fake frames (and cleaning up swapchain code)
This commit is contained in:
parent
8803034a60
commit
2c3da15a4d
4
Makefile
4
Makefile
@ -90,8 +90,8 @@ ifneq (,$(findstring ffx:sdk,$(REQ_DEPS)))
|
||||
ifneq (,$(findstring vulkan,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_FFX_SDK=3
|
||||
#INCS += -I./dep/include/ffx_fsr2/
|
||||
#DEPS += -lffx_fsr3_x64drel -lffx_fsr2_x64drel -lffx_fsr3upscaler_x64drel -lffx_frameinterpolation_x64drel -lffx_opticalflow_x64drel -lffx_backend_vk_x64drel -lamd_fidelityfx_vkdrel
|
||||
DEPS += -lffx_fsr3_x64 -lffx_fsr2_x64 -lffx_fsr3upscaler_x64 -lffx_frameinterpolation_x64 -lffx_opticalflow_x64 -lffx_backend_vk_x64 -lamd_fidelityfx_vk
|
||||
DEPS += -lffx_fsr3_x64drel -lffx_fsr2_x64drel -lffx_fsr3upscaler_x64drel -lffx_frameinterpolation_x64drel -lffx_opticalflow_x64drel -lffx_backend_vk_x64drel -lamd_fidelityfx_vkdrel
|
||||
#DEPS += -lffx_fsr3_x64 -lffx_fsr2_x64 -lffx_fsr3upscaler_x64 -lffx_frameinterpolation_x64 -lffx_opticalflow_x64 -lffx_backend_vk_x64 -lamd_fidelityfx_vk
|
||||
endif
|
||||
endif
|
||||
ifneq (,$(findstring vulkan,$(REQ_DEPS)))
|
||||
|
||||
@ -29,8 +29,8 @@
|
||||
}
|
||||
},
|
||||
"vxgi": {
|
||||
"limiter": 0,
|
||||
// "limiter": 0.0125,
|
||||
// "limiter": 0,
|
||||
"limiter": 0.0125,
|
||||
"size": 256,
|
||||
"dispatch": 16,
|
||||
"cascades": 3,
|
||||
@ -101,7 +101,7 @@
|
||||
"experimental": {
|
||||
"rebuild on tick begin": false,
|
||||
"batch queue submissions": true,
|
||||
"dedicated thread": false, // mostly works
|
||||
"dedicated thread": true, // mostly works
|
||||
"memory budget": false,
|
||||
"register render modes": true,
|
||||
"skip render on rebuild": false
|
||||
@ -122,7 +122,7 @@
|
||||
"bloom": true,
|
||||
"dof": true,
|
||||
"rt": false,
|
||||
"fsr": true,
|
||||
"fsr": false,
|
||||
"postProcess": false // "postProcess.chromab" // false
|
||||
},
|
||||
"formats": {
|
||||
@ -228,7 +228,8 @@
|
||||
"descriptorBindingVariableDescriptorCount",
|
||||
|
||||
"shaderOutputViewportIndex",
|
||||
"shaderOutputLayer"
|
||||
"shaderOutputLayer",
|
||||
"timelineSemaphore"
|
||||
],
|
||||
"featureChain": [
|
||||
"physicalDeviceVulkan12"
|
||||
@ -303,7 +304,7 @@
|
||||
"fsr": {
|
||||
"enabled": true,
|
||||
"upscale": true,
|
||||
"interpolation": false, // it works but it's naively using the interpolated frame
|
||||
"interpolation": true, // it works but i don't think it's presenting the frame
|
||||
"sharpness": 0,
|
||||
"jitter scale": 0.0625,
|
||||
"preset": "native" // native (1x), quality (1.5x), balanced (1.7x), performance (2.0x), ultra (3.0x)
|
||||
|
||||
24
bin/data/shaders/display/compositor/comp.glsl
Normal file
24
bin/data/shaders/display/compositor/comp.glsl
Normal file
@ -0,0 +1,24 @@
|
||||
#version 450
|
||||
#pragma shader_stage(compute)
|
||||
|
||||
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
|
||||
|
||||
layout(binding = 0) uniform sampler2D samplerA;
|
||||
layout(binding = 1) uniform sampler2D samplerB;
|
||||
layout(binding = 2, rgba16f) uniform writeonly image2D imageOutput;
|
||||
|
||||
void main() {
|
||||
ivec2 texCoords = ivec2(gl_GlobalInvocationID.xy);
|
||||
ivec2 size = imageSize(imageOutput);
|
||||
|
||||
if(texCoords.x >= size.x || texCoords.y >= size.y) return;
|
||||
|
||||
vec2 uv = (vec2(texCoords) + vec2(0.5)) / vec2(size);
|
||||
|
||||
vec4 colorA = texture(samplerA, uv);
|
||||
vec4 colorB = texture(samplerB, uv);
|
||||
|
||||
vec4 finalColor = vec4(mix(colorA.rgb, colorB.rgb, colorB.a), 1.0);
|
||||
|
||||
imageStore(imageOutput, texCoords, finalColor);
|
||||
}
|
||||
@ -21,10 +21,18 @@ namespace ext {
|
||||
void UF_API initialize();
|
||||
void UF_API tick();
|
||||
void UF_API render();
|
||||
void UF_API render( VkCommandBuffer );
|
||||
void UF_API terminate();
|
||||
|
||||
uf::renderer::Texture& getRenderTarget();
|
||||
|
||||
VkResult acquireNextImage( uint32_t*, VkSemaphore, VkFence = VK_NULL_HANDLE );
|
||||
VkResult queuePresent( VkQueue, uint32_t, VkSemaphore = VK_NULL_HANDLE );
|
||||
|
||||
VkResult createSwapchain( VkDevice, VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain );
|
||||
void destroySwapchain( VkDevice, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator );
|
||||
VkResult getSwapchainImages( VkDevice, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages );
|
||||
VkSwapchainKHR getSwapchain( VkSwapchainKHR swapchain );
|
||||
|
||||
uf::renderer::Texture& getRenderTarget();
|
||||
pod::Matrix4f UF_API getJitterMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@ namespace ext {
|
||||
PRESENT,
|
||||
COMPUTE,
|
||||
TRANSFER,
|
||||
ACQUIRE,
|
||||
};
|
||||
struct CommandBuffer {
|
||||
bool immediate{true};
|
||||
@ -76,6 +77,7 @@ namespace ext {
|
||||
uf::ThreadUnique<VkQueue> present;
|
||||
uf::ThreadUnique<VkQueue> compute;
|
||||
uf::ThreadUnique<VkQueue> transfer;
|
||||
uf::ThreadUnique<VkQueue> acquire;
|
||||
} queues;
|
||||
|
||||
struct {
|
||||
@ -104,7 +106,8 @@ namespace ext {
|
||||
uint32_t present;
|
||||
uint32_t compute;
|
||||
uint32_t transfer;
|
||||
} queueFamilyIndices;
|
||||
uint32_t acquire;
|
||||
} queueFamilyIndices, queueIndices;
|
||||
operator VkDevice() { return this->logicalDevice; };
|
||||
|
||||
// helpers
|
||||
|
||||
@ -14,9 +14,10 @@ namespace ext {
|
||||
uint32_t buffers = {};
|
||||
|
||||
uf::stl::vector<VkSemaphore> presentCompleteSemaphores;
|
||||
uf::stl::vector<VkImage> images;
|
||||
|
||||
// helpers
|
||||
VkResult acquireNextImage( uint32_t* imageIndex, VkSemaphore, VkFence = nullptr );
|
||||
VkResult acquireNextImage( uint32_t* imageIndex, VkSemaphore, VkFence = VK_NULL_HANDLE );
|
||||
VkResult queuePresent( VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE );
|
||||
|
||||
// RAII
|
||||
|
||||
@ -286,6 +286,14 @@ void UF_API uf::load( ext::json::Value& json ) {
|
||||
|
||||
ext::fsr::frameUpscale = json["engine"]["ext"]["fsr"]["upscale"].as(ext::fsr::frameUpscale);
|
||||
ext::fsr::frameInterpolation = json["engine"]["ext"]["fsr"]["interpolation"].as(ext::fsr::frameInterpolation);
|
||||
|
||||
{
|
||||
bool enabled = json["engine"]["ext"]["fsr"]["enabled"].as(true);
|
||||
if ( !enabled ) {
|
||||
ext::fsr::frameUpscale = false;
|
||||
ext::fsr::frameInterpolation = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( uf::renderer::hasRenderMode("", true) ) {
|
||||
|
||||
@ -190,6 +190,11 @@ namespace {
|
||||
FfxContextDescription contextDescription;
|
||||
|
||||
#if UF_USE_FFX_SDR_FRAME_INTERP && UF_USE_FFX_SDK == FFX_SDK_3_1
|
||||
FfxSwapchain ffxSwapchain = nullptr;
|
||||
FfxSwapchainReplacementFunctions ffxSwapchainFuncs = {};
|
||||
|
||||
uf::renderer::Graphic compositor;
|
||||
|
||||
uf::stl::vector<uint8_t> scratchBufferFG;
|
||||
uf::stl::vector<uint8_t> scratchBufferOF;
|
||||
|
||||
@ -203,7 +208,7 @@ namespace {
|
||||
uf::renderer::Texture empty;
|
||||
uf::renderer::Texture output;
|
||||
#if UF_USE_FFX_SDK == FFX_SDK_3_1
|
||||
uf::renderer::Texture outputFG;
|
||||
uf::renderer::Texture outputComposited;
|
||||
uf::renderer::Texture dilatedMotionVectors;
|
||||
uf::renderer::Texture dilatedDepth;
|
||||
uf::renderer::Texture reconstructedPrevNearestDepth;
|
||||
@ -224,7 +229,7 @@ namespace {
|
||||
width, height,
|
||||
1,
|
||||
1,
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | usage,
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | usage,
|
||||
layout
|
||||
);
|
||||
}
|
||||
@ -399,6 +404,12 @@ namespace {
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
auto& projection = camera.getProjection();
|
||||
|
||||
// composite GUI onto output
|
||||
{
|
||||
::compositor.record( commandBuffer );
|
||||
barrier(commandBuffer, ::resources.outputComposited.image);
|
||||
}
|
||||
|
||||
#if UF_USE_FFX_SDK == FFX_SDK_3
|
||||
FfxFsr3DispatchFrameGenerationPrepareDescription dispatchParameters = {};
|
||||
dispatchParameters.commandList = ffxGetCommandListVK(commandBuffer);
|
||||
@ -407,6 +418,16 @@ namespace {
|
||||
|
||||
FFX_ERROR_CHECK(ffxFsr3ContextDispatchFrameGenerationPrepare(&::context, &dispatchParameters));
|
||||
#elif UF_USE_FFX_SDK == FFX_SDK_3_1
|
||||
FfxFrameGenerationConfig fgConfig = {};
|
||||
fgConfig.swapChain = ffxGetSwapchainVK(uf::renderer::swapchain.swapChain);
|
||||
fgConfig.frameGenerationEnabled = true;
|
||||
fgConfig.allowAsyncWorkloads = true;
|
||||
|
||||
FFX_ERROR_CHECK(ffxSetFrameGenerationConfigToSwapchainVK(&fgConfig));
|
||||
|
||||
FfxCommandList interpolationCommandList;
|
||||
ffxGetFrameinterpolationCommandlistVK(fgConfig.swapChain, interpolationCommandList);
|
||||
|
||||
FfxFrameInterpolationDispatchDescription dispatchParameters = {};
|
||||
dispatchParameters.commandList = ffxGetCommandListVK(commandBuffer);
|
||||
|
||||
@ -416,15 +437,17 @@ namespace {
|
||||
dispatchParameters.renderSize.height = displaySize.y;
|
||||
|
||||
// use output from rendermode
|
||||
if ( ext::fsr::frameUpscale ) {
|
||||
if ( !ext::fsr::frameUpscale ) {
|
||||
if ( !renderMode.hasAttachment("output") && !renderMode.hasAttachment("color") ) return;
|
||||
auto& attachmentColor = renderMode.hasAttachment("output") ? renderMode.getAttachment("output") : renderMode.getAttachment("color");
|
||||
dispatchParameters.currentBackBuffer = createFfxResource(attachmentColor, L"FSR3_InterpolationSource");
|
||||
dispatchParameters.currentBackBuffer_HUDLess = createFfxResource(attachmentColor, L"FSR3_InterpolationSource_HUDLess");
|
||||
} else {
|
||||
dispatchParameters.currentBackBuffer = createFfxResource(::resources.output, L"FSR3_InterpolationSource");
|
||||
|
||||
dispatchParameters.currentBackBuffer_HUDLess = createFfxResource(::resources.output, L"FSR3_InterpolationSource_HUDLess");
|
||||
}
|
||||
dispatchParameters.output = createFfxResource(::resources.outputFG, L"FSR3_InterpolatedOutput");
|
||||
// attach HUD'd image
|
||||
dispatchParameters.currentBackBuffer = createFfxResource(::resources.outputComposited, L"FSR3_InterpolationSource");
|
||||
|
||||
dispatchParameters.output = ffxGetFrameinterpolationTextureVK( ffxGetSwapchainVK(uf::renderer::swapchain.swapChain) );
|
||||
|
||||
dispatchParameters.cameraNear = projection(2,3);
|
||||
dispatchParameters.cameraFar = FLT_MAX;
|
||||
@ -450,9 +473,9 @@ namespace {
|
||||
dispatchParameters.opticalFlowScale.x = 1.0f;
|
||||
dispatchParameters.opticalFlowScale.y = 1.0f;
|
||||
dispatchParameters.opticalFlowBlockSize = FFX_FSR_BLOCK_SIZE;
|
||||
dispatchParameters.commandList = interpolationCommandList;
|
||||
|
||||
FFX_ERROR_CHECK(ffxFrameInterpolationDispatch(&::contextFG, &dispatchParameters));
|
||||
barrier(commandBuffer, ::resources.outputFG.image);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@ -577,6 +600,8 @@ void ext::fsr::initialize() {
|
||||
|
||||
FFX_ERROR_CHECK(ffxGetInterfaceVK( &::contextDescriptionFG.backendInterface, ffxDevice, ::scratchBufferFG.data(), ::scratchBufferFG.size(), 1 ));
|
||||
FFX_ERROR_CHECK(ffxFrameInterpolationContextCreate( &::contextFG, &::contextDescriptionFG ));
|
||||
|
||||
FFX_ERROR_CHECK(ffxGetSwapchainReplacementFunctionsVK(ffxDevice, &::ffxSwapchainFuncs));
|
||||
}
|
||||
|
||||
// setup optical flow context
|
||||
@ -594,9 +619,7 @@ void ext::fsr::initialize() {
|
||||
::resources.output.format = uf::renderer::settings::pipelines::hdr ? uf::renderer::enums::Format::HDR : uf::renderer::enums::Format::SDR;
|
||||
::initializeResource( ::resources.output );
|
||||
#if UF_USE_FFX_SDK == FFX_SDK_3_1
|
||||
::resources.outputFG.viewComponentMapping.a = VK_COMPONENT_SWIZZLE_ONE; // for some reason framegen has the alpha set to 1 (or never writes it)
|
||||
|
||||
::resources.outputFG.format = uf::renderer::settings::pipelines::hdr ? uf::renderer::enums::Format::HDR : uf::renderer::enums::Format::SDR;
|
||||
::resources.outputComposited.format = uf::renderer::settings::pipelines::hdr ? uf::renderer::enums::Format::HDR : uf::renderer::enums::Format::SDR;
|
||||
::resources.dilatedMotionVectors.format = uf::renderer::enums::Format::R16G16_SFLOAT;
|
||||
::resources.dilatedDepth.format = uf::renderer::enums::Format::R32_SFLOAT;
|
||||
::resources.reconstructedPrevNearestDepth.format = uf::renderer::enums::Format::R32_UINT;
|
||||
@ -607,7 +630,7 @@ void ext::fsr::initialize() {
|
||||
uint32_t ofWidth = (uf::renderer::settings::width + block_size) / block_size;
|
||||
uint32_t ofHeight = (uf::renderer::settings::height + block_size) / block_size;
|
||||
|
||||
::initializeResource( ::resources.outputFG );
|
||||
::initializeResource( ::resources.outputComposited );
|
||||
::initializeResource( ::resources.dilatedMotionVectors );
|
||||
::initializeResource( ::resources.dilatedDepth );
|
||||
::initializeResource( ::resources.reconstructedPrevNearestDepth );
|
||||
@ -616,6 +639,37 @@ void ext::fsr::initialize() {
|
||||
#endif
|
||||
}
|
||||
|
||||
// setup compositor
|
||||
{
|
||||
uf::Mesh mesh;
|
||||
mesh.vertex.count = 3;
|
||||
|
||||
auto& blitter = ::compositor;
|
||||
blitter.device = &uf::renderer::device;
|
||||
blitter.material.device = &uf::renderer::device;
|
||||
blitter.descriptor.renderMode = "Swapchain";
|
||||
blitter.descriptor.subpass = -1;
|
||||
|
||||
blitter.initializeMesh( mesh );
|
||||
|
||||
blitter.material.attachShader(uf::io::resolveURI(uf::io::root+"/shaders/display/compositor/comp.spv"), ext::vulkan::enums::Shader::COMPUTE);
|
||||
|
||||
blitter.material.textures.clear();
|
||||
blitter.material.textures.emplace_back().aliasTexture(::resources.output);
|
||||
blitter.material.textures.emplace_back().aliasTexture(uf::renderer::Texture2D::empty);
|
||||
blitter.material.textures.emplace_back().aliasTexture(::resources.outputComposited);
|
||||
|
||||
blitter.descriptor.bind.width = uf::renderer::settings::width;
|
||||
blitter.descriptor.bind.height = uf::renderer::settings::height;
|
||||
blitter.descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
|
||||
|
||||
if ( !blitter.hasPipeline( blitter.descriptor ) ) {
|
||||
blitter.initializePipeline( blitter.descriptor );
|
||||
} else if ( blitter.hasPipeline( blitter.descriptor ) ){
|
||||
blitter.getPipeline( blitter.descriptor ).update( blitter, blitter.descriptor );
|
||||
}
|
||||
}
|
||||
|
||||
ext::fsr::initialized = true;
|
||||
}
|
||||
void ext::fsr::tick() {
|
||||
@ -684,7 +738,7 @@ void ext::fsr::tick() {
|
||||
uint32_t ofWidth = (displaySize.x + block_size) / block_size;
|
||||
uint32_t ofHeight = (displaySize.y + block_size) / block_size;
|
||||
|
||||
::initializeResource( ::resources.outputFG, displaySize.x, displaySize.y );
|
||||
::initializeResource( ::resources.outputComposited, displaySize.x, displaySize.y );
|
||||
::initializeResource( ::resources.dilatedMotionVectors, displaySize.x, displaySize.y );
|
||||
::initializeResource( ::resources.dilatedDepth, displaySize.x, displaySize.y );
|
||||
::initializeResource( ::resources.reconstructedPrevNearestDepth, displaySize.x, displaySize.y );
|
||||
@ -692,6 +746,29 @@ void ext::fsr::tick() {
|
||||
::initializeResource( ::resources.opticalFlowSceneChangeDetection, ofWidth, ofHeight );
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
auto& blitter = ::compositor;
|
||||
blitter.material.textures.clear();
|
||||
blitter.material.textures.emplace_back().aliasTexture(::resources.output);
|
||||
if ( uf::renderer::hasRenderMode("Gui", true) ) {
|
||||
auto& renderMode = uf::renderer::getRenderMode("Gui", true);
|
||||
auto& attachment = renderMode.getAttachment("color");
|
||||
blitter.material.textures.emplace_back().aliasAttachment( attachment );
|
||||
} else {
|
||||
blitter.material.textures.emplace_back().aliasTexture( uf::renderer::Texture2D::empty );
|
||||
}
|
||||
blitter.material.textures.emplace_back().aliasTexture(::resources.outputComposited);
|
||||
|
||||
blitter.descriptor.bind.width = displaySize.x;
|
||||
blitter.descriptor.bind.height = displaySize.y;
|
||||
|
||||
if ( !blitter.hasPipeline( blitter.descriptor ) ) {
|
||||
blitter.initializePipeline( blitter.descriptor );
|
||||
} else if ( blitter.hasPipeline( blitter.descriptor ) ){
|
||||
blitter.getPipeline( blitter.descriptor ).update( blitter, blitter.descriptor );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update jitter
|
||||
@ -713,8 +790,12 @@ void ext::fsr::tick() {
|
||||
}
|
||||
void ext::fsr::render() {
|
||||
if ( !ext::fsr::initialized ) return;
|
||||
|
||||
auto commandBuffer = uf::renderer::device.fetchCommandBuffer(uf::renderer::QueueEnum::GRAPHICS, true); // immediately flush
|
||||
render( commandBuffer );
|
||||
uf::renderer::device.flushCommandBuffer(commandBuffer);
|
||||
}
|
||||
void ext::fsr::render( VkCommandBuffer commandBuffer ) {
|
||||
if ( !ext::fsr::initialized ) return;
|
||||
if ( ext::fsr::frameUpscale ) {
|
||||
upscale( commandBuffer );
|
||||
}
|
||||
@ -726,7 +807,6 @@ void ext::fsr::render() {
|
||||
framegen( commandBuffer );
|
||||
#endif
|
||||
}
|
||||
uf::renderer::device.flushCommandBuffer(commandBuffer);
|
||||
}
|
||||
void ext::fsr::terminate() {
|
||||
if ( !ext::fsr::initialized ) return;
|
||||
@ -746,7 +826,7 @@ void ext::fsr::terminate() {
|
||||
{
|
||||
::resources.output.destroy();
|
||||
#if UF_USE_FFX_SDK == FFX_SDK_3_1
|
||||
::resources.outputFG.destroy();
|
||||
::resources.outputComposited.destroy();
|
||||
::resources.dilatedMotionVectors.destroy();
|
||||
::resources.dilatedDepth.destroy();
|
||||
::resources.reconstructedPrevNearestDepth.destroy();
|
||||
@ -754,6 +834,99 @@ void ext::fsr::terminate() {
|
||||
::resources.opticalFlowSceneChangeDetection.destroy();
|
||||
#endif
|
||||
}
|
||||
|
||||
// destroy compositor
|
||||
{
|
||||
::compositor.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
VkResult ext::fsr::acquireNextImage( uint32_t* imageIndex, VkSemaphore presentCompleteSemaphore, VkFence acquireFence ) {
|
||||
#if UF_USE_FFX_SDR_FRAME_INTERP && UF_USE_FFX_SDK == FFX_SDK_3_1
|
||||
if ( ext::fsr::frameInterpolation && ::ffxSwapchainFuncs.acquireNextImageKHR ) {
|
||||
return ::ffxSwapchainFuncs.acquireNextImageKHR( uf::renderer::device, uf::renderer::swapchain.swapChain, VK_DEFAULT_FENCE_TIMEOUT, presentCompleteSemaphore, acquireFence, imageIndex );
|
||||
}
|
||||
#endif
|
||||
return vkAcquireNextImageKHR( uf::renderer::device, uf::renderer::swapchain.swapChain, VK_DEFAULT_FENCE_TIMEOUT, presentCompleteSemaphore, acquireFence, imageIndex );
|
||||
}
|
||||
VkResult ext::fsr::queuePresent( VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore ) {
|
||||
VkPresentInfoKHR presentInfo = {};
|
||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
presentInfo.pNext = NULL;
|
||||
presentInfo.swapchainCount = 1;
|
||||
presentInfo.pSwapchains = &uf::renderer::swapchain.swapChain;
|
||||
presentInfo.pImageIndices = &imageIndex;
|
||||
|
||||
if ( waitSemaphore != VK_NULL_HANDLE ) {
|
||||
presentInfo.pWaitSemaphores = &waitSemaphore;
|
||||
presentInfo.waitSemaphoreCount = 1;
|
||||
}
|
||||
|
||||
#if UF_USE_FFX_SDR_FRAME_INTERP && UF_USE_FFX_SDK == FFX_SDK_3_1
|
||||
if ( ext::fsr::frameInterpolation && ::ffxSwapchainFuncs.queuePresentKHR ) {
|
||||
return ::ffxSwapchainFuncs.queuePresentKHR(queue, &presentInfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
return vkQueuePresentKHR(queue, &presentInfo);
|
||||
}
|
||||
|
||||
VkResult ext::fsr::createSwapchain( VkDevice device, VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain ) {
|
||||
#if UF_USE_FFX_SDR_FRAME_INTERP && UF_USE_FFX_SDK == FFX_SDK_3_1
|
||||
if ( ext::fsr::frameInterpolation && !::ffxSwapchainFuncs.createSwapchainFFX ) {
|
||||
VkDeviceContext deviceContextVK = {};
|
||||
deviceContextVK.vkDevice = device;
|
||||
deviceContextVK.vkPhysicalDevice = uf::renderer::device.physicalDevice;
|
||||
deviceContextVK.vkDeviceProcAddr = vkGetDeviceProcAddr;
|
||||
FfxDevice ffxDevice = ffxGetDeviceVK(&deviceContextVK);
|
||||
|
||||
FFX_ERROR_CHECK(ffxGetSwapchainReplacementFunctionsVK(ffxDevice, &::ffxSwapchainFuncs));
|
||||
}
|
||||
if ( ext::fsr::frameInterpolation && ::ffxSwapchainFuncs.createSwapchainFFX ) {
|
||||
VkFrameInterpolationInfoFFX fiInfo = {};
|
||||
fiInfo.device = device;
|
||||
fiInfo.physicalDevice = uf::renderer::device.physicalDevice;
|
||||
fiInfo.pAllocator = pAllocator;
|
||||
fiInfo.compositionMode = VK_COMPOSITION_MODE_GAME_QUEUE_FFX; // Standard mode
|
||||
|
||||
fiInfo.gameQueue.queue = uf::renderer::device.getQueue( uf::renderer::QueueEnum::GRAPHICS );
|
||||
fiInfo.gameQueue.familyIndex = uf::renderer::device.queueFamilyIndices.graphics;
|
||||
fiInfo.gameQueue.submitFunc = nullptr;
|
||||
|
||||
fiInfo.presentQueue.queue = uf::renderer::device.getQueue( uf::renderer::QueueEnum::PRESENT );
|
||||
fiInfo.presentQueue.familyIndex = uf::renderer::device.queueFamilyIndices.present;
|
||||
fiInfo.presentQueue.submitFunc = nullptr;
|
||||
|
||||
fiInfo.asyncComputeQueue.queue = uf::renderer::device.getQueue( uf::renderer::QueueEnum::COMPUTE );
|
||||
fiInfo.asyncComputeQueue.familyIndex = uf::renderer::device.queueFamilyIndices.compute;
|
||||
fiInfo.asyncComputeQueue.submitFunc = nullptr;
|
||||
|
||||
fiInfo.imageAcquireQueue.queue = uf::renderer::device.getQueue( uf::renderer::QueueEnum::ACQUIRE );
|
||||
fiInfo.imageAcquireQueue.familyIndex = uf::renderer::device.queueFamilyIndices.acquire;
|
||||
fiInfo.imageAcquireQueue.submitFunc = nullptr;
|
||||
|
||||
return ::ffxSwapchainFuncs.createSwapchainFFX( device, pCreateInfo, pAllocator, pSwapchain, &fiInfo );
|
||||
}
|
||||
#endif
|
||||
return vkCreateSwapchainKHR( device, pCreateInfo, pAllocator, pSwapchain );
|
||||
}
|
||||
void ext::fsr::destroySwapchain( VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator ) {
|
||||
#if UF_USE_FFX_SDR_FRAME_INTERP && UF_USE_FFX_SDK == FFX_SDK_3_1
|
||||
if ( ext::fsr::frameInterpolation && ::ffxSwapchainFuncs.destroySwapchainKHR ) {
|
||||
::ffxSwapchainFuncs.destroySwapchainKHR(device, swapchain, pAllocator);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
vkDestroySwapchainKHR( device, swapchain, pAllocator );
|
||||
}
|
||||
VkResult ext::fsr::getSwapchainImages( VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages ) {
|
||||
#if UF_USE_FFX_SDR_FRAME_INTERP && UF_USE_FFX_SDK == FFX_SDK_3_1
|
||||
if ( ext::fsr::frameInterpolation && ::ffxSwapchainFuncs.getSwapchainImagesKHR ) {
|
||||
return ::ffxSwapchainFuncs.getSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
|
||||
}
|
||||
#endif
|
||||
|
||||
return vkGetSwapchainImagesKHR( device, swapchain, pSwapchainImageCount, pSwapchainImages );
|
||||
}
|
||||
|
||||
pod::Matrix4f ext::fsr::getJitterMatrix() {
|
||||
@ -761,12 +934,7 @@ pod::Matrix4f ext::fsr::getJitterMatrix() {
|
||||
}
|
||||
|
||||
uf::renderer::Texture& ext::fsr::getRenderTarget() {
|
||||
#if UF_USE_FFX_SDR_FRAME_INTERP
|
||||
if ( ext::fsr::frameInterpolation ) return ::resources.outputFG;
|
||||
#endif
|
||||
return ::resources.output;
|
||||
}
|
||||
|
||||
// to-do: add functions to get framegen swapchain functions
|
||||
|
||||
#endif
|
||||
@ -787,24 +787,34 @@ VkCommandPool ext::vulkan::Device::getCommandPool( ext::vulkan::QueueEnum queueE
|
||||
VkQueue ext::vulkan::Device::getQueue( ext::vulkan::QueueEnum queueEnum, std::thread::id id ) {
|
||||
auto& device = *this;
|
||||
|
||||
uint32_t familyIndex = 0;
|
||||
uint32_t index = 0;
|
||||
uf::ThreadUnique<VkQueue>* commandPool{NULL};
|
||||
switch ( queueEnum ) {
|
||||
case QueueEnum::GRAPHICS:
|
||||
index = device.queueFamilyIndices.graphics;
|
||||
familyIndex = device.queueFamilyIndices.graphics;
|
||||
commandPool = &queues.graphics;
|
||||
index = device.queueIndices.graphics;
|
||||
break;
|
||||
case QueueEnum::PRESENT:
|
||||
index = device.queueFamilyIndices.present;
|
||||
familyIndex = device.queueFamilyIndices.present;
|
||||
commandPool = &queues.present;
|
||||
index = device.queueIndices.present;
|
||||
break;
|
||||
case QueueEnum::COMPUTE:
|
||||
index = device.queueFamilyIndices.compute;
|
||||
familyIndex = device.queueFamilyIndices.compute;
|
||||
commandPool = &queues.compute;
|
||||
index = device.queueIndices.compute;
|
||||
break;
|
||||
case QueueEnum::TRANSFER:
|
||||
index = device.queueFamilyIndices.transfer;
|
||||
familyIndex = device.queueFamilyIndices.transfer;
|
||||
commandPool = &queues.transfer;
|
||||
index = device.queueIndices.transfer;
|
||||
break;
|
||||
case QueueEnum::ACQUIRE:
|
||||
familyIndex = device.queueFamilyIndices.acquire;
|
||||
commandPool = &queues.acquire;
|
||||
index = device.queueIndices.acquire;
|
||||
break;
|
||||
}
|
||||
UF_ASSERT( commandPool );
|
||||
@ -812,7 +822,7 @@ VkQueue ext::vulkan::Device::getQueue( ext::vulkan::QueueEnum queueEnum, std::th
|
||||
bool exists = commandPool->has(id);
|
||||
VkQueue& queue = commandPool->get(id);
|
||||
if ( !exists ) {
|
||||
vkGetDeviceQueue( device, index, 0, &queue );
|
||||
vkGetDeviceQueue( device, familyIndex, index, &queue );
|
||||
}
|
||||
return queue;
|
||||
}
|
||||
@ -1070,37 +1080,24 @@ void ext::vulkan::Device::initialize() {
|
||||
extensions.enabled.device[s] = true;
|
||||
}
|
||||
|
||||
|
||||
// Desired queues need to be requested upon logical device creation
|
||||
// Due to differing queue family configurations of Vulkan implementations this can be a bit tricky, especially if the application
|
||||
// requests different queue types
|
||||
uf::stl::vector<VkDeviceQueueCreateInfo> queueCreateInfos{};
|
||||
// Get queue family indices for the requested queue family types
|
||||
// Note that the indices may overlap depending on the implementation
|
||||
const float defaultQueuePriority(0.0f);
|
||||
std::vector<std::vector<float>> queuePriorities;
|
||||
|
||||
// Graphics queue
|
||||
if ( requestedQueueTypes & VK_QUEUE_GRAPHICS_BIT ) {
|
||||
queueFamilyIndices.graphics = getQueueFamilyIndex(VK_QUEUE_GRAPHICS_BIT);
|
||||
VkDeviceQueueCreateInfo queueInfo{};
|
||||
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queueInfo.queueFamilyIndex = queueFamilyIndices.graphics;
|
||||
queueInfo.queueCount = 1;
|
||||
queueInfo.pQueuePriorities = &defaultQueuePriority;
|
||||
queueCreateInfos.push_back(queueInfo);
|
||||
} else {
|
||||
queueFamilyIndices.graphics = 0; // VK_NULL_HANDLE;
|
||||
}
|
||||
// Dedicated compute queue
|
||||
if ( requestedQueueTypes & VK_QUEUE_COMPUTE_BIT ) {
|
||||
queueFamilyIndices.compute = getQueueFamilyIndex(VK_QUEUE_COMPUTE_BIT);
|
||||
if ( queueFamilyIndices.compute != queueFamilyIndices.graphics ) {
|
||||
// If compute family index differs, we need an additional queue create info for the compute queue
|
||||
VkDeviceQueueCreateInfo queueInfo{};
|
||||
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queueInfo.queueFamilyIndex = queueFamilyIndices.compute;
|
||||
queueInfo.queueCount = 1;
|
||||
queueInfo.pQueuePriorities = &defaultQueuePriority;
|
||||
queueCreateInfos.push_back(queueInfo);
|
||||
}
|
||||
} else {
|
||||
// Else we use the same queue
|
||||
queueFamilyIndices.compute = queueFamilyIndices.graphics;
|
||||
@ -1108,19 +1105,50 @@ void ext::vulkan::Device::initialize() {
|
||||
// Dedicated transfer queue
|
||||
if ( requestedQueueTypes & VK_QUEUE_TRANSFER_BIT ) {
|
||||
queueFamilyIndices.transfer = getQueueFamilyIndex(VK_QUEUE_TRANSFER_BIT);
|
||||
if ((queueFamilyIndices.transfer != queueFamilyIndices.graphics) && (queueFamilyIndices.transfer != queueFamilyIndices.compute)) {
|
||||
// If compute family index differs, we need an additional queue create info for the compute queue
|
||||
VkDeviceQueueCreateInfo queueInfo{};
|
||||
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queueInfo.queueFamilyIndex = queueFamilyIndices.transfer;
|
||||
queueInfo.queueCount = 1;
|
||||
queueInfo.pQueuePriorities = &defaultQueuePriority;
|
||||
queueCreateInfos.emplace_back(queueInfo);
|
||||
}
|
||||
} else {
|
||||
// Else we use the same queue
|
||||
queueFamilyIndices.transfer = queueFamilyIndices.graphics;
|
||||
}
|
||||
// Dedicated acquire queue
|
||||
{
|
||||
queueFamilyIndices.acquire = queueFamilyIndices.present;
|
||||
}
|
||||
|
||||
// tally up how many queues we need
|
||||
std::map<uint32_t, uint32_t> requestedQueuesPerFamily;
|
||||
requestedQueuesPerFamily[queueFamilyIndices.graphics]++;
|
||||
requestedQueuesPerFamily[queueFamilyIndices.compute]++;
|
||||
requestedQueuesPerFamily[queueFamilyIndices.transfer]++;
|
||||
requestedQueuesPerFamily[queueFamilyIndices.present]++;
|
||||
requestedQueuesPerFamily[queueFamilyIndices.acquire]++;
|
||||
|
||||
for ( const auto& [ familyIndex, requestedCount ] : requestedQueuesPerFamily ) {
|
||||
uint32_t maxSupported = queueFamilyProperties[familyIndex].queueCount;
|
||||
uint32_t actualCount = std::min( requestedCount, maxSupported );
|
||||
|
||||
queuePriorities.emplace_back(std::vector<float>(actualCount, 1.0f));
|
||||
|
||||
VkDeviceQueueCreateInfo queueInfo{};
|
||||
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queueInfo.queueFamilyIndex = familyIndex;
|
||||
queueInfo.queueCount = actualCount;
|
||||
queueInfo.pQueuePriorities = queuePriorities.back().data();
|
||||
|
||||
queueCreateInfos.emplace_back(queueInfo);
|
||||
}
|
||||
|
||||
{
|
||||
std::map<uint32_t, uint32_t> familyIndexCounters;
|
||||
auto assignQueueIndex = [&](uint32_t family) -> uint32_t {
|
||||
return familyIndexCounters[family]++;
|
||||
};
|
||||
|
||||
device.queueIndices.graphics = assignQueueIndex( device.queueFamilyIndices.graphics );
|
||||
device.queueIndices.compute = assignQueueIndex( device.queueFamilyIndices.compute );
|
||||
device.queueIndices.transfer = assignQueueIndex( device.queueFamilyIndices.transfer );
|
||||
device.queueIndices.present = assignQueueIndex( device.queueFamilyIndices.present );
|
||||
device.queueIndices.acquire = assignQueueIndex( device.queueFamilyIndices.acquire );
|
||||
}
|
||||
|
||||
// Create the logical device representation
|
||||
if ( useSwapChain ) {
|
||||
@ -1311,35 +1339,41 @@ void ext::vulkan::Device::initialize() {
|
||||
|
||||
int i = 0;
|
||||
for (const auto& queueFamily : queueFamilyProperties) {
|
||||
if ( queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT )
|
||||
if ( queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT ) {
|
||||
graphicsQueueNodeIndex = i;
|
||||
}
|
||||
|
||||
if ( queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT )
|
||||
if ( queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT ) {
|
||||
computeQueueNodeIndex = i;
|
||||
}
|
||||
|
||||
if ( queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT )
|
||||
if ( queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT ) {
|
||||
transferQueueNodeIndex = i;
|
||||
}
|
||||
|
||||
VkBool32 presentSupport = false;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR( this->physicalDevice, i, surface, &presentSupport );
|
||||
if ( queueFamily.queueCount > 0 && presentSupport )
|
||||
if ( queueFamily.queueCount > 0 && presentSupport ) {
|
||||
presentQueueNodeIndex = i;
|
||||
}
|
||||
|
||||
if ( graphicsQueueNodeIndex != UINT32_MAX && presentQueueNodeIndex != UINT32_MAX && computeQueueNodeIndex != UINT32_MAX ) break;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
VK_VALIDATION_MESSAGE("Graphics queue: {}", device.queueFamilyIndices.graphics);
|
||||
VK_VALIDATION_MESSAGE("Compute queue: {}", device.queueFamilyIndices.compute);
|
||||
VK_VALIDATION_MESSAGE("Transfer queue: {}", device.queueFamilyIndices.transfer);
|
||||
VK_VALIDATION_MESSAGE("Present queue: {}", device.queueFamilyIndices.present);
|
||||
VK_VALIDATION_MESSAGE("Graphics queue: family={}, index={}", device.queueFamilyIndices.graphics, device.queueIndices.graphics );
|
||||
VK_VALIDATION_MESSAGE("Compute queue: family={}, index={}", device.queueFamilyIndices.compute, device.queueIndices.compute );
|
||||
VK_VALIDATION_MESSAGE("Transfer queue: family={}, index={}", device.queueFamilyIndices.transfer, device.queueIndices.transfer );
|
||||
VK_VALIDATION_MESSAGE("Present queue: family={}, index={}", device.queueFamilyIndices.present, device.queueIndices.present );
|
||||
VK_VALIDATION_MESSAGE("Acquire queue: family={}, index={}", device.queueFamilyIndices.acquire, device.queueIndices.acquire );
|
||||
|
||||
device.queueFamilyIndices.present = presentQueueNodeIndex;
|
||||
getQueue( QueueEnum::GRAPHICS );
|
||||
getQueue( QueueEnum::PRESENT );
|
||||
getQueue( QueueEnum::COMPUTE );
|
||||
getQueue( QueueEnum::TRANSFER );
|
||||
getQueue( QueueEnum::ACQUIRE );
|
||||
}
|
||||
// Set formats
|
||||
{
|
||||
|
||||
@ -454,8 +454,7 @@ void ext::vulkan::Pipeline::record( const Graphic& graphic, const GraphicDescrip
|
||||
|
||||
// no matching bind point for shaders, skip
|
||||
if ( !bound ) {
|
||||
UF_MSG_DEBUG("No shaders found to bind...");
|
||||
return;
|
||||
UF_MSG_DEBUG("No shaders found to bind...: {} | {}", shaders.size(), descriptor.pipeline);
|
||||
}
|
||||
|
||||
// Bind descriptor sets describing shader binding points
|
||||
|
||||
@ -9,13 +9,173 @@
|
||||
#include <uf/utils/graphic/graphic.h>
|
||||
#include <uf/utils/io/fmt.h>
|
||||
|
||||
namespace {
|
||||
uf::stl::vector<VkImage> images;
|
||||
}
|
||||
|
||||
const uf::stl::string ext::vulkan::BaseRenderMode::getType() const {
|
||||
return "Swapchain";
|
||||
}
|
||||
|
||||
|
||||
void ext::vulkan::BaseRenderMode::build( bool resized ) {
|
||||
|
||||
}
|
||||
|
||||
void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
|
||||
this->metadata.name = "Swapchain";
|
||||
auto windowSize = device.window->getSize();
|
||||
this->width = windowSize.x;
|
||||
this->height = windowSize.y;
|
||||
renderTarget.width = this->width;
|
||||
renderTarget.height = this->height;
|
||||
|
||||
ext::vulkan::RenderMode::initialize( device );
|
||||
swapchain.initialize( device );
|
||||
renderTarget.device = &device;
|
||||
renderTarget.passes.clear();
|
||||
renderTarget.attachments.clear();
|
||||
|
||||
struct {
|
||||
size_t color, depth;
|
||||
} attachments = {};
|
||||
|
||||
attachments.color = renderTarget.attach(RenderTarget::Attachment::Descriptor{
|
||||
/*.format = */ext::vulkan::settings::formats::color,
|
||||
/*.layout = */VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||
/*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||
/*.blend = */false,
|
||||
/*.samples = */1,
|
||||
});
|
||||
|
||||
attachments.depth = renderTarget.attach(RenderTarget::Attachment::Descriptor{
|
||||
/*.format = */ext::vulkan::settings::formats::depth,
|
||||
/*.layout = */VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
/*.usage = */VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
|
||||
/*.blend = */false,
|
||||
/*.samples = */1,
|
||||
});
|
||||
|
||||
metadata.attachments["color"] = attachments.color;
|
||||
metadata.attachments["depth"] = attachments.depth;
|
||||
|
||||
renderTarget.addPass(
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
{ attachments.color }, {}, {}, attachments.depth, 0, true
|
||||
);
|
||||
|
||||
renderTarget.initialize( device );
|
||||
|
||||
// set sync objects
|
||||
for ( auto i = 0; i < ext::vulkan::swapchain.buffers; ++i ) {
|
||||
auto& presentCompleteSemaphore = swapchain.presentCompleteSemaphores.emplace_back();
|
||||
VkSemaphoreCreateInfo semaphoreCreateInfo = {};
|
||||
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
semaphoreCreateInfo.pNext = nullptr;
|
||||
|
||||
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &presentCompleteSemaphore));
|
||||
VK_REGISTER_HANDLE(presentCompleteSemaphore);
|
||||
}
|
||||
}
|
||||
|
||||
void ext::vulkan::BaseRenderMode::tick() {
|
||||
ext::vulkan::RenderMode::tick();
|
||||
|
||||
bool resized = (this->width == 0 && this->height == 0) || ext::vulkan::states::resized || this->resized;
|
||||
bool rebuild = resized || ext::vulkan::states::rebuild || this->rebuild;
|
||||
|
||||
auto windowSize = device->window->getSize();
|
||||
|
||||
if ( windowSize.x == this->width && windowSize.y == this->height ) {
|
||||
resized = false;
|
||||
}
|
||||
|
||||
// rebuild rendertarget
|
||||
if ( resized ) {
|
||||
this->destroy();
|
||||
this->initialize( *this->device );
|
||||
/*
|
||||
this->width = windowSize.x;
|
||||
this->height = windowSize.y;
|
||||
this->resized = false;
|
||||
rebuild = true;
|
||||
renderTarget.width = this->width;
|
||||
renderTarget.height = this->height;
|
||||
|
||||
|
||||
swapchain.initialize( *swapchain.device );
|
||||
renderTarget.initialize( *renderTarget.device );
|
||||
*/
|
||||
}
|
||||
|
||||
// update blitter descriptor set
|
||||
if ( rebuild && blitter.initialized ) {
|
||||
this->build( resized );
|
||||
}
|
||||
}
|
||||
void ext::vulkan::BaseRenderMode::render() {
|
||||
// if ( ext::vulkan::states::frameSkip ) return;
|
||||
// if ( ext::vulkan::renderModes.size() > 1 ) return;
|
||||
// if ( ext::vulkan::renderModes.back() != this ) return;
|
||||
|
||||
if ( this->commands.container().empty() ) return;
|
||||
|
||||
//lockMutex( this->mostRecentCommandPoolId );
|
||||
auto& commands = getCommands( this->mostRecentCommandPoolId );
|
||||
|
||||
VK_CHECK_RESULT(swapchain.acquireNextImage(&states::currentBuffer, swapchain.presentCompleteSemaphores[0]));
|
||||
|
||||
VK_CHECK_RESULT(vkWaitForFences(*device, 1, &fences[states::currentBuffer], VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT));
|
||||
VK_CHECK_RESULT(vkResetFences(*device, 1, &fences[states::currentBuffer]));
|
||||
|
||||
VkPipelineStageFlags waitStageMask[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
||||
|
||||
VkSubmitInfo submitInfo = {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.pWaitDstStageMask = waitStageMask;
|
||||
submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphores[0];
|
||||
submitInfo.waitSemaphoreCount = 1;
|
||||
submitInfo.pSignalSemaphores = &renderCompleteSemaphores[states::currentBuffer];
|
||||
submitInfo.signalSemaphoreCount = 1;
|
||||
submitInfo.pCommandBuffers = &commands[states::currentBuffer];
|
||||
submitInfo.commandBufferCount = 1;
|
||||
|
||||
{
|
||||
VkQueue queue = device->getQueue( QueueEnum::GRAPHICS );
|
||||
VkResult res = vkQueueSubmit( queue, 1, &submitInfo, fences[states::currentBuffer]);
|
||||
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
|
||||
}
|
||||
|
||||
VK_CHECK_RESULT(swapchain.queuePresent(device->getQueue( QueueEnum::PRESENT ), states::currentBuffer, renderCompleteSemaphores[states::currentBuffer]));
|
||||
|
||||
#if 0
|
||||
{
|
||||
VkQueue queue = device->getQueue( QueueEnum::PRESENT );
|
||||
VkResult res = vkQueueWaitIdle(device->getQueue( QueueEnum::PRESENT ));
|
||||
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
|
||||
}
|
||||
#endif
|
||||
|
||||
this->executed = true;
|
||||
|
||||
//unlockMutex( this->mostRecentCommandPoolId );
|
||||
}
|
||||
|
||||
void ext::vulkan::BaseRenderMode::destroy() {
|
||||
|
||||
ext::vulkan::RenderMode::destroy();
|
||||
|
||||
for ( auto& presentCompleteSemaphore : swapchain.presentCompleteSemaphores ) {
|
||||
vkDestroySemaphore( *device, presentCompleteSemaphore, nullptr);
|
||||
VK_UNREGISTER_HANDLE( presentCompleteSemaphore );
|
||||
}
|
||||
swapchain.presentCompleteSemaphores.clear();
|
||||
}
|
||||
|
||||
ext::vulkan::GraphicDescriptor ext::vulkan::BaseRenderMode::bindGraphicDescriptor( const ext::vulkan::GraphicDescriptor& reference, size_t pass ) {
|
||||
ext::vulkan::GraphicDescriptor descriptor = ext::vulkan::RenderMode::bindGraphicDescriptor(reference, pass);
|
||||
|
||||
descriptor.depth.test = false;
|
||||
descriptor.depth.write = false;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vector<ext::vulkan::Graphic*>& graphics ) {
|
||||
// if ( ext::vulkan::renderModes.size() > 1 ) return;
|
||||
|
||||
@ -94,40 +254,11 @@ void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vector<ex
|
||||
|
||||
auto& commandBuffer = commands[frame];
|
||||
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[frame];
|
||||
|
||||
|
||||
VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &cmdBufInfo));
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::BEGIN, "begin" );
|
||||
{
|
||||
size_t currentSubpass = 0;
|
||||
|
||||
{
|
||||
VkImageMemoryBarrier imageMemoryBarrier = {};
|
||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
imageMemoryBarrier.srcAccessMask = 0;
|
||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
imageMemoryBarrier.oldLayout = renderTarget.attachments[frame].descriptor.layout;
|
||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
// explicitly transfer queue-ownership
|
||||
if ( ext::vulkan::device.queueFamilyIndices.graphics != ext::vulkan::device.queueFamilyIndices.present ) {
|
||||
imageMemoryBarrier.srcQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.present;
|
||||
imageMemoryBarrier.dstQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.graphics;
|
||||
} else {
|
||||
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.present;
|
||||
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics;
|
||||
}
|
||||
imageMemoryBarrier.image = renderTarget.attachments[frame].image;
|
||||
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
|
||||
imageMemoryBarrier.subresourceRange.levelCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
|
||||
imageMemoryBarrier.subresourceRange.layerCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
renderTarget.attachments[frame].descriptor.layout = imageMemoryBarrier.newLayout;
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" );
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
||||
}
|
||||
|
||||
// pre-renderpass commands
|
||||
VK_COMMAND_BUFFER_CALLBACK( CALLBACK_BEGIN, commandBuffer, frame, {
|
||||
@ -160,29 +291,6 @@ void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vector<ex
|
||||
VK_COMMAND_BUFFER_CALLBACK( CALLBACK_END, commandBuffer, frame, {
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "callback[end]" );
|
||||
} );
|
||||
|
||||
// need to transfer it back, if they differ
|
||||
if ( ext::vulkan::device.queueFamilyIndices.graphics != ext::vulkan::device.queueFamilyIndices.present ) {
|
||||
VkImageMemoryBarrier imageMemoryBarrier = {};
|
||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
imageMemoryBarrier.oldLayout = renderTarget.attachments[frame].descriptor.layout;
|
||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
imageMemoryBarrier.srcQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.graphics;
|
||||
imageMemoryBarrier.dstQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.present;
|
||||
imageMemoryBarrier.image = renderTarget.attachments[frame].image;
|
||||
|
||||
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
|
||||
imageMemoryBarrier.subresourceRange.levelCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
|
||||
imageMemoryBarrier.subresourceRange.layerCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
renderTarget.attachments[frame].descriptor.layout = imageMemoryBarrier.newLayout;
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" );
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
||||
}
|
||||
}
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "end" );
|
||||
@ -190,501 +298,4 @@ void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vector<ex
|
||||
}
|
||||
}
|
||||
|
||||
void ext::vulkan::BaseRenderMode::build( bool resized ) {
|
||||
|
||||
}
|
||||
void ext::vulkan::BaseRenderMode::tick() {
|
||||
ext::vulkan::RenderMode::tick();
|
||||
|
||||
if ( ext::vulkan::states::resized ) {
|
||||
this->destroy();
|
||||
this->initialize( *this->device );
|
||||
}
|
||||
}
|
||||
void ext::vulkan::BaseRenderMode::render() {
|
||||
// if ( ext::vulkan::states::frameSkip ) return;
|
||||
// if ( ext::vulkan::renderModes.size() > 1 ) return;
|
||||
// if ( ext::vulkan::renderModes.back() != this ) return;
|
||||
|
||||
if ( this->commands.container().empty() ) return;
|
||||
|
||||
//lockMutex( this->mostRecentCommandPoolId );
|
||||
auto& commands = getCommands( this->mostRecentCommandPoolId );
|
||||
|
||||
// Get next image in the swap chain (back/front buffer)
|
||||
VK_CHECK_RESULT(swapchain.acquireNextImage(&states::currentBuffer, swapchain.presentCompleteSemaphores[0]));
|
||||
|
||||
// Use a fence to wait until the command buffer has finished execution before using it again
|
||||
VK_CHECK_RESULT(vkWaitForFences(*device, 1, &fences[states::currentBuffer], VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT));
|
||||
VK_CHECK_RESULT(vkResetFences(*device, 1, &fences[states::currentBuffer]));
|
||||
|
||||
// Pipeline stage at which the queue submission will wait (via pWaitSemaphores)
|
||||
VkPipelineStageFlags waitStageMask[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
||||
// The submit info structure specifices a command buffer queue submission batch
|
||||
VkSubmitInfo submitInfo = {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.pWaitDstStageMask = waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at
|
||||
submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphores[0]; // Semaphore(s) to wait upon before the submitted command buffer starts executing
|
||||
submitInfo.waitSemaphoreCount = 1; // One wait semaphore
|
||||
submitInfo.pSignalSemaphores = &renderCompleteSemaphores[states::currentBuffer]; // Semaphore(s) to be signaled when command buffers have completed
|
||||
submitInfo.signalSemaphoreCount = 1; // One signal semaphore
|
||||
submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission)
|
||||
submitInfo.commandBufferCount = 1;
|
||||
|
||||
// Submit to the graphics queue passing a wait fence
|
||||
#if 1
|
||||
VK_CHECK_RESULT(vkQueueSubmit( device->getQueue( QueueEnum::GRAPHICS ), 1, &submitInfo, fences[states::currentBuffer]));
|
||||
#else
|
||||
{
|
||||
VkQueue queue = device->getQueue( QueueEnum::GRAPHICS );
|
||||
VkResult res = vkQueueSubmit( queue, 1, &submitInfo, fences[states::currentBuffer]);
|
||||
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
|
||||
}
|
||||
#endif
|
||||
|
||||
// Present the current buffer to the swap chain
|
||||
// Pass the semaphore signaled by the command buffer submission from the submit info as the wait semaphore for swap chain presentation
|
||||
// This ensures that the image is not presented to the windowing system until all commands have been submitted
|
||||
VK_CHECK_RESULT(swapchain.queuePresent(device->getQueue( QueueEnum::PRESENT ), states::currentBuffer, renderCompleteSemaphores[states::currentBuffer]));
|
||||
|
||||
#if 1
|
||||
//VK_CHECK_RESULT(vkQueueWaitIdle(device->getQueue( QueueEnum::PRESENT )));
|
||||
#else
|
||||
{
|
||||
VkQueue queue = device->getQueue( QueueEnum::PRESENT );
|
||||
VkResult res = vkQueueWaitIdle(device->getQueue( QueueEnum::PRESENT ));
|
||||
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
|
||||
}
|
||||
#endif
|
||||
|
||||
this->executed = true;
|
||||
|
||||
//unlockMutex( this->mostRecentCommandPoolId );
|
||||
}
|
||||
|
||||
void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
|
||||
this->metadata.name = "Swapchain";
|
||||
auto windowSize = device.window->getSize();
|
||||
this->width = windowSize.x;
|
||||
this->height = windowSize.y;
|
||||
|
||||
ext::vulkan::RenderMode::initialize( device );
|
||||
// manual initialization
|
||||
// recreate swapchain
|
||||
// destroy any existing imageviews
|
||||
// attachments marked as aliased are actually from the swapchain
|
||||
// swapchain.destroy();
|
||||
swapchain.initialize( device );
|
||||
// bind swapchain images
|
||||
::images.resize( ext::vulkan::swapchain.buffers );
|
||||
VK_CHECK_RESULT(vkGetSwapchainImagesKHR( device, swapchain.swapChain, &swapchain.buffers, ::images.data()));
|
||||
// create image views for swapchain images
|
||||
|
||||
renderTarget.attachments.clear();
|
||||
renderTarget.attachments.resize( ext::vulkan::swapchain.buffers );
|
||||
|
||||
// uint32_t width = windowSize.x; //this->width > 0 ? this->width : windowSize.x;
|
||||
// uint32_t height = windowSize.y; //this->height > 0 ? this->height : windowSize.y;
|
||||
|
||||
size_t attachmentIndex = 0;
|
||||
for ( size_t frame = 0; frame < ext::vulkan::swapchain.buffers; ++frame ) {
|
||||
VkImageViewCreateInfo colorAttachmentView = {};
|
||||
colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
colorAttachmentView.pNext = NULL;
|
||||
colorAttachmentView.format = ext::vulkan::settings::formats::color;
|
||||
colorAttachmentView.components = {
|
||||
VK_COMPONENT_SWIZZLE_R,
|
||||
VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_B,
|
||||
VK_COMPONENT_SWIZZLE_A
|
||||
};
|
||||
colorAttachmentView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
colorAttachmentView.subresourceRange.baseMipLevel = 0;
|
||||
colorAttachmentView.subresourceRange.levelCount = 1;
|
||||
colorAttachmentView.subresourceRange.baseArrayLayer = 0;
|
||||
colorAttachmentView.subresourceRange.layerCount = 1;
|
||||
colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
colorAttachmentView.flags = 0;
|
||||
colorAttachmentView.image = ::images[frame];
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImageView( device, &colorAttachmentView, nullptr, &renderTarget.attachments[frame].view));
|
||||
VK_REGISTER_HANDLE( renderTarget.attachments[frame].view );
|
||||
|
||||
renderTarget.attachments[frame].descriptor.format = ext::vulkan::settings::formats::color;
|
||||
// renderTarget.attachments[frame].descriptor.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
renderTarget.attachments[frame].descriptor.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
renderTarget.attachments[frame].descriptor.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
renderTarget.attachments[frame].descriptor.aliased = true;
|
||||
renderTarget.attachments[frame].image = ::images[frame];
|
||||
renderTarget.attachments[frame].mem = VK_NULL_HANDLE;
|
||||
|
||||
metadata.attachments["color["+std::to_string((int) frame)+"]"] = attachmentIndex++;
|
||||
}
|
||||
{
|
||||
// Create depth
|
||||
auto& attachment = renderTarget.attachments.emplace_back();
|
||||
metadata.attachments["depth"] = attachmentIndex++;
|
||||
|
||||
// Create an optimal image used as the depth stencil attachment
|
||||
VkImageCreateInfo imageCreateInfo = {};
|
||||
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageCreateInfo.format = ext::vulkan::settings::formats::depth;
|
||||
// Use example's height and width
|
||||
imageCreateInfo.extent = { width, height, 1 };
|
||||
imageCreateInfo.mipLevels = 1;
|
||||
imageCreateInfo.arrayLayers = 1;
|
||||
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
VmaAllocationCreateInfo allocInfo = {};
|
||||
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
|
||||
VK_CHECK_RESULT(vmaCreateImage(allocator, &imageCreateInfo, &allocInfo, &attachment.image, &attachment.allocation, &attachment.allocationInfo));
|
||||
VK_REGISTER_HANDLE( attachment.image );
|
||||
|
||||
|
||||
attachment.descriptor.format = ext::vulkan::settings::formats::depth;
|
||||
// attachment.descriptor.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
attachment.descriptor.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachment.descriptor.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
// attachment.descriptor.aliased = true;
|
||||
attachment.mem = attachment.allocationInfo.deviceMemory;
|
||||
|
||||
VkImageViewCreateInfo depthStencilView = {};
|
||||
depthStencilView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
depthStencilView.format = ext::vulkan::settings::formats::depth;
|
||||
depthStencilView.subresourceRange = {};
|
||||
depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
depthStencilView.subresourceRange.baseMipLevel = 0;
|
||||
depthStencilView.subresourceRange.levelCount = 1;
|
||||
depthStencilView.subresourceRange.baseArrayLayer = 0;
|
||||
depthStencilView.subresourceRange.layerCount = 1;
|
||||
depthStencilView.image = attachment.image;
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &attachment.view));
|
||||
VK_REGISTER_HANDLE(attachment.view);
|
||||
}
|
||||
|
||||
#if 1
|
||||
auto commandBuffer = device.fetchCommandBuffer(uf::renderer::QueueEnum::GRAPHICS);
|
||||
for ( auto& attachment : renderTarget.attachments ) {
|
||||
bool isDepth = attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
if ( isDepth ) {
|
||||
// transition attachments to general attachments for imageStore
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.levelCount = 1;
|
||||
subresourceRange.baseArrayLayer = 0;
|
||||
subresourceRange.layerCount = 1;
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
subresourceRange.layerCount = 1;
|
||||
|
||||
uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, subresourceRange );
|
||||
} else {
|
||||
// transition attachments to general attachments for imageStore
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.levelCount = 1;
|
||||
subresourceRange.baseArrayLayer = 0;
|
||||
subresourceRange.layerCount = 1;
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subresourceRange.layerCount = 1;
|
||||
|
||||
uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, subresourceRange );
|
||||
}
|
||||
}
|
||||
device.flushCommandBuffer(commandBuffer, uf::renderer::QueueEnum::GRAPHICS);
|
||||
#endif
|
||||
|
||||
// Create FSR dump
|
||||
/*
|
||||
if ( settings::pipelines::fsr ) {
|
||||
auto& attachment = renderTarget.attachments.emplace_back();
|
||||
|
||||
VkImageCreateInfo imageCreateInfo = {};
|
||||
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageCreateInfo.format = ext::vulkan::settings::pipelines::hdr ? enums::Format::HDR : enums::Format::SDR;
|
||||
|
||||
imageCreateInfo.extent = { width, height, 1 };
|
||||
imageCreateInfo.mipLevels = 1;
|
||||
imageCreateInfo.arrayLayers = 1;
|
||||
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageCreateInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
VmaAllocationCreateInfo allocInfo = {};
|
||||
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
|
||||
VK_CHECK_RESULT(vmaCreateImage(allocator, &imageCreateInfo, &allocInfo, &attachment.image, &attachment.allocation, &attachment.allocationInfo));
|
||||
VK_REGISTER_HANDLE( attachment.image );
|
||||
attachment.mem = attachment.allocationInfo.deviceMemory;
|
||||
|
||||
VkImageViewCreateInfo imageViewCreateInfo = {};
|
||||
imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
imageViewCreateInfo.format = ext::vulkan::settings::pipelines::hdr ? enums::Format::HDR : enums::Format::SDR;
|
||||
imageViewCreateInfo.subresourceRange = {};
|
||||
imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
imageViewCreateInfo.subresourceRange.baseMipLevel = 0;
|
||||
imageViewCreateInfo.subresourceRange.levelCount = 1;
|
||||
imageViewCreateInfo.subresourceRange.baseArrayLayer = 0;
|
||||
imageViewCreateInfo.subresourceRange.layerCount = 1;
|
||||
imageViewCreateInfo.image = attachment.image;
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImageView(device, &imageViewCreateInfo, nullptr, &attachment.view));
|
||||
VK_REGISTER_HANDLE(attachment.view);
|
||||
metadata.attachments["fsr"] = attachmentIndex++;
|
||||
}
|
||||
*/
|
||||
// Create renderpass
|
||||
if ( !renderTarget.renderPass ) {// Create render pass
|
||||
// This example will use a single render pass with one subpass
|
||||
|
||||
// Descriptors for the attachments used by this renderpass
|
||||
std::array<VkAttachmentDescription, 2> attachments = {};
|
||||
|
||||
// Color attachment
|
||||
attachments[0].format = ext::vulkan::settings::formats::color; // Use the color format selected by the swapchain
|
||||
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; // We don't use multi sampling in this example
|
||||
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // Clear this attachment at the start of the render pass
|
||||
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; // Keep it's contents after the render pass is finished (for displaying it)
|
||||
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // We don't use stencil, so don't care for load
|
||||
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // Same for store
|
||||
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Layout at render pass start. Initial doesn't matter, so we use undefined
|
||||
attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; // Layout to which the attachment is transitioned when the render pass is finished
|
||||
// As we want to present the color buffer to the swapchain, we transition to PRESENT_KHR
|
||||
// Depth attachment
|
||||
attachments[1].format = ext::vulkan::settings::formats::depth; // A proper depth format is selected in the example base
|
||||
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // Clear depth at start of first subpass
|
||||
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // We don't need depth after render pass has finished (DONT_CARE may result in better performance)
|
||||
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // No stencil
|
||||
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // No Stencil
|
||||
attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Layout at render pass start. Initial doesn't matter, so we use undefined
|
||||
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // Transition to depth/stencil attachment
|
||||
|
||||
// Setup attachment references
|
||||
VkAttachmentReference colorReference = {};
|
||||
colorReference.attachment = 0; // Attachment 0 is color
|
||||
colorReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // Attachment layout used as color during the subpass
|
||||
|
||||
VkAttachmentReference depthReference = {};
|
||||
depthReference.attachment = 1; // Attachment 1 is color
|
||||
depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // Attachment used as depth/stemcil used during the subpass
|
||||
|
||||
// Setup a single subpass reference
|
||||
VkSubpassDescription subpassDescription = {};
|
||||
subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpassDescription.colorAttachmentCount = 1; // Subpass uses one color attachment
|
||||
subpassDescription.pColorAttachments = &colorReference; // Reference to the color attachment in slot 0
|
||||
subpassDescription.pDepthStencilAttachment = &depthReference; // Reference to the depth attachment in slot 1
|
||||
subpassDescription.inputAttachmentCount = 0; // Input attachments can be used to sample from contents of a previous subpass
|
||||
subpassDescription.pInputAttachments = nullptr; // (Input attachments not used by this example)
|
||||
subpassDescription.preserveAttachmentCount = 0; // Preserved attachments can be used to loop (and preserve) attachments through subpasses
|
||||
subpassDescription.pPreserveAttachments = nullptr; // (Preserve attachments not used by this example)
|
||||
subpassDescription.pResolveAttachments = nullptr; // Resolve attachments are resolved at the end of a sub pass and can be used for e.g. multi sampling
|
||||
|
||||
// Setup subpass dependencies
|
||||
// These will add the implicit ttachment layout transitionss specified by the attachment descriptions
|
||||
// The actual usage layout is preserved through the layout specified in the attachment reference
|
||||
// Each subpass dependency will introduce a memory and execution dependency between the source and dest subpass described by
|
||||
// srcStageMask, dstStageMask, srcAccessMask, dstAccessMask (and dependencyFlags is set)
|
||||
// Note: VK_SUBPASS_EXTERNAL is a special constant that refers to all commands executed outside of the actual renderpass)
|
||||
std::array<VkSubpassDependency, 2> dependencies;
|
||||
|
||||
// First dependency at the start of the renderpass
|
||||
// Does the transition from final to initial layout
|
||||
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; // Producer of the dependency
|
||||
dependencies[0].dstSubpass = 0; // Consumer is our single subpass that will wait for the execution depdendency
|
||||
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
||||
|
||||
// Second dependency at the end the renderpass
|
||||
// Does the transition from the initial to the final layout
|
||||
dependencies[1].srcSubpass = 0; // Producer of the dependency is our single subpass
|
||||
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; // Consumer are all commands outside of the renderpass
|
||||
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
||||
|
||||
// Create the actual renderpass
|
||||
VkRenderPassCreateInfo renderPassInfo = {};
|
||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size()); // Number of attachments used by this render pass
|
||||
renderPassInfo.pAttachments = attachments.data(); // Descriptions of the attachments used by the render pass
|
||||
renderPassInfo.subpassCount = 1; // We only use one subpass in this example
|
||||
renderPassInfo.pSubpasses = &subpassDescription; // Description of that subpass
|
||||
renderPassInfo.dependencyCount = static_cast<uint32_t>(dependencies.size()); // Number of subpass dependencies
|
||||
renderPassInfo.pDependencies = dependencies.data(); // Subpass dependencies used by the render pass
|
||||
|
||||
VK_CHECK_RESULT(vkCreateRenderPass( device, &renderPassInfo, nullptr, &renderTarget.renderPass));
|
||||
VK_REGISTER_HANDLE(renderTarget.renderPass);
|
||||
}
|
||||
// Create framebuffer
|
||||
{
|
||||
// Create a frame buffer for every image in the swapchain
|
||||
renderTarget.framebuffers.resize(::images.size());
|
||||
for (size_t frame = 0; frame < renderTarget.framebuffers.size(); frame++)
|
||||
{
|
||||
std::array<VkImageView, 2> attachments;
|
||||
attachments[0] = renderTarget.attachments[frame].view; // Color attachment is the view of the swapchain image
|
||||
attachments[1] = renderTarget.attachments[metadata.attachments["depth"]].view; // Depth/Stencil attachment is the same for all frame buffers
|
||||
|
||||
VkFramebufferCreateInfo frameBufferCreateInfo = {};
|
||||
frameBufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
// All frame buffers use the same renderpass setup
|
||||
frameBufferCreateInfo.renderPass = renderTarget.renderPass;
|
||||
frameBufferCreateInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
|
||||
frameBufferCreateInfo.pAttachments = attachments.data();
|
||||
frameBufferCreateInfo.width = width;
|
||||
frameBufferCreateInfo.height = height;
|
||||
frameBufferCreateInfo.layers = 1;
|
||||
// Create the framebuffer
|
||||
VK_CHECK_RESULT(vkCreateFramebuffer( device, &frameBufferCreateInfo, nullptr, &renderTarget.framebuffers[frame]));
|
||||
VK_REGISTER_HANDLE(renderTarget.framebuffers[frame]);
|
||||
}
|
||||
|
||||
}
|
||||
#if 0
|
||||
if ( true ) {
|
||||
auto commandBuffer = device.fetchCommandBuffer(uf::renderer::QueueEnum::TRANSFER);
|
||||
for ( size_t frame = 0; frame < ::images.size(); ++frame ) {
|
||||
VkImageMemoryBarrier imageMemoryBarrier = {};
|
||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
imageMemoryBarrier.srcAccessMask = 0;
|
||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
imageMemoryBarrier.oldLayout = renderTarget.attachments[frame].descriptor.layout;
|
||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.present;
|
||||
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics;
|
||||
|
||||
imageMemoryBarrier.image = renderTarget.attachments[frame].image;
|
||||
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
|
||||
imageMemoryBarrier.subresourceRange.levelCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
|
||||
imageMemoryBarrier.subresourceRange.layerCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
renderTarget.attachments[frame].descriptor.layout = imageMemoryBarrier.newLayout;
|
||||
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
||||
}
|
||||
device.flushCommandBuffer(uf::renderer::QueueEnum::TRANSFER);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
{
|
||||
renderTarget.device = &device;
|
||||
// attach targets
|
||||
struct {
|
||||
size_t color, depth;
|
||||
} attachments;
|
||||
|
||||
attachments.color = 0; {
|
||||
|
||||
}
|
||||
attachments.depth = renderTarget.attach( ext::vulkan::settings::formats::depth, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ); // depth
|
||||
|
||||
// First pass: fill the G-Buffer
|
||||
{
|
||||
renderTarget.addPass(
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
{ attachments.color },
|
||||
{},
|
||||
attachments.depth
|
||||
);
|
||||
}
|
||||
}
|
||||
renderTarget.initialize( device );
|
||||
*/
|
||||
// Set sync objects
|
||||
for ( auto i = 0; i < ext::vulkan::swapchain.buffers; ++i ) {
|
||||
auto& presentCompleteSemaphore = swapchain.presentCompleteSemaphores.emplace_back();
|
||||
// Semaphores (Used for correct command ordering)
|
||||
VkSemaphoreCreateInfo semaphoreCreateInfo = {};
|
||||
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
semaphoreCreateInfo.pNext = nullptr;
|
||||
|
||||
// Semaphore used to ensures that image presentation is complete before starting to submit again
|
||||
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &presentCompleteSemaphore));
|
||||
VK_REGISTER_HANDLE(presentCompleteSemaphore);
|
||||
}
|
||||
}
|
||||
|
||||
void ext::vulkan::BaseRenderMode::destroy() {
|
||||
if ( renderTarget.renderPass != VK_NULL_HANDLE ) {
|
||||
vkDestroyRenderPass( *device, renderTarget.renderPass, nullptr );
|
||||
VK_UNREGISTER_HANDLE( renderTarget.renderPass );
|
||||
renderTarget.renderPass = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
for ( uint32_t frame = 0; frame < renderTarget.framebuffers.size(); frame++ ) {
|
||||
if ( renderTarget.framebuffers[frame] != VK_NULL_HANDLE ) {
|
||||
vkDestroyFramebuffer( *device, renderTarget.framebuffers[frame], nullptr );
|
||||
VK_UNREGISTER_HANDLE( renderTarget.framebuffers[frame] );
|
||||
renderTarget.framebuffers[frame] = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
for ( auto& attachment : renderTarget.attachments ) {
|
||||
if ( attachment.view != VK_NULL_HANDLE ) {
|
||||
vkDestroyImageView( *device, attachment.view, nullptr);
|
||||
VK_UNREGISTER_HANDLE( attachment.view );
|
||||
attachment.view = VK_NULL_HANDLE;
|
||||
}
|
||||
if ( attachment.descriptor.aliased ) continue;
|
||||
if ( attachment.image != VK_NULL_HANDLE ) {
|
||||
// vkDestroyImage( *device, attachment.image, nullptr );
|
||||
vmaDestroyImage( allocator, attachment.image, attachment.allocation );
|
||||
VK_UNREGISTER_HANDLE( attachment.image );
|
||||
attachment.image = VK_NULL_HANDLE;
|
||||
}
|
||||
if ( attachment.mem != VK_NULL_HANDLE ) {
|
||||
// vkFreeMemory( *device, attachment.mem, nullptr );
|
||||
attachment.mem = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
for ( auto& image : ::images ) {
|
||||
// vkDestroyImage( *device, image, nullptr ); // destroyed via vkDestroySwapchainKHR
|
||||
VK_UNREGISTER_HANDLE( image );
|
||||
image = VK_NULL_HANDLE;
|
||||
}
|
||||
::images.clear();
|
||||
|
||||
ext::vulkan::RenderMode::destroy();
|
||||
|
||||
for ( auto& presentCompleteSemaphore : swapchain.presentCompleteSemaphores ) {
|
||||
vkDestroySemaphore( *device, presentCompleteSemaphore, nullptr);
|
||||
VK_UNREGISTER_HANDLE( presentCompleteSemaphore );
|
||||
}
|
||||
swapchain.presentCompleteSemaphores.clear();
|
||||
}
|
||||
|
||||
ext::vulkan::GraphicDescriptor ext::vulkan::BaseRenderMode::bindGraphicDescriptor( const ext::vulkan::GraphicDescriptor& reference, size_t pass ) {
|
||||
ext::vulkan::GraphicDescriptor descriptor = ext::vulkan::RenderMode::bindGraphicDescriptor(reference, pass);
|
||||
/*
|
||||
descriptor.parse(metadata.json["descriptor"]);
|
||||
// invalidate
|
||||
if ( metadata.target != "" && descriptor.renderMode != this->getName() && descriptor.renderMode != metadata.target ) {
|
||||
descriptor.invalidated = true;
|
||||
} else {
|
||||
descriptor.renderMode = this->getName();
|
||||
}
|
||||
*/
|
||||
|
||||
descriptor.depth.test = false;
|
||||
descriptor.depth.write = false;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -280,7 +280,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
});
|
||||
|
||||
auto& shader = blitter.material.getShader("fragment");
|
||||
if ( !settings::pipelines::fsr ) {
|
||||
if ( !settings::pipelines::fsr || !ext::fsr::frameUpscale ) {
|
||||
shader.aliasAttachment("output", this);
|
||||
}
|
||||
}
|
||||
@ -456,7 +456,7 @@ void ext::vulkan::DeferredRenderMode::build( bool resized ) {
|
||||
// if resized (or initialized)
|
||||
if ( resized ) {
|
||||
#if UF_USE_FFX_FSR || UF_USE_FFX_SDK
|
||||
if ( settings::pipelines::fsr ) {
|
||||
if ( settings::pipelines::fsr && ext::fsr::frameUpscale ) {
|
||||
auto& shader = blitter.material.getShader("fragment");
|
||||
shader.textures.clear();
|
||||
shader.textures.emplace_back().aliasTexture( ext::fsr::getRenderTarget() );
|
||||
@ -1109,6 +1109,16 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
#if UF_USE_FFX_FSR || UF_USE_FFX_SDK
|
||||
{
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "fsr:start" );
|
||||
ext::fsr::render( commandBuffer );
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "fsr:end" );
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "end" );
|
||||
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
|
||||
}
|
||||
|
||||
@ -211,10 +211,10 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
|
||||
} else {
|
||||
for ( size_t currentPass = 0; currentPass < metadata.subpasses; ++currentPass ) {
|
||||
struct {
|
||||
size_t albedo, depth;
|
||||
size_t color, depth;
|
||||
} attachments = {};
|
||||
|
||||
attachments.albedo = renderTarget.attach(RenderTarget::Attachment::Descriptor{
|
||||
attachments.color = renderTarget.attach(RenderTarget::Attachment::Descriptor{
|
||||
/*.format = */VK_FORMAT_R8G8B8A8_UNORM,
|
||||
/*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
/*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
|
||||
@ -230,7 +230,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
|
||||
});
|
||||
renderTarget.addPass(
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
{ attachments.albedo },
|
||||
{ attachments.color },
|
||||
{},
|
||||
{},
|
||||
attachments.depth,
|
||||
@ -238,7 +238,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
|
||||
true
|
||||
);
|
||||
|
||||
metadata.attachments["albedo"] = attachments.albedo;
|
||||
metadata.attachments["color"] = attachments.color;
|
||||
metadata.attachments["depth"] = attachments.depth;
|
||||
}
|
||||
}
|
||||
@ -537,7 +537,7 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
|
||||
// VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
|
||||
// VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
for ( auto& attachment : renderTarget.attachments ) {
|
||||
// transition attachments to general attachments for imageStore
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
|
||||
@ -34,7 +34,7 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript
|
||||
VK_UNREGISTER_HANDLE( view );
|
||||
}
|
||||
attachment->views.clear();
|
||||
if ( attachment->image ) {
|
||||
if ( attachment->image && attachment->descriptor.layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) {
|
||||
vmaDestroyImage( allocator, attachment->image, attachment->allocation );
|
||||
attachment->image = VK_NULL_HANDLE;
|
||||
}
|
||||
@ -73,8 +73,51 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript
|
||||
}
|
||||
attachment->views.resize(this->views * attachment->descriptor.mips);
|
||||
|
||||
bool isSwapchain = attachment->descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
bool isDepth = attachment->descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
// swapchain specialization
|
||||
if ( isSwapchain ) {
|
||||
attachment->descriptor.aliased = true;
|
||||
attachment->views.resize(ext::vulkan::swapchain.buffers);
|
||||
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.levelCount = 1;
|
||||
subresourceRange.baseArrayLayer = 0;
|
||||
subresourceRange.layerCount = 1;
|
||||
subresourceRange.aspectMask = isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subresourceRange.layerCount = 1;
|
||||
|
||||
auto commandBuffer = device->fetchCommandBuffer(uf::renderer::QueueEnum::GRAPHICS);
|
||||
for ( size_t i = 0; i < ext::vulkan::swapchain.buffers; ++i ) {
|
||||
auto& image = ext::vulkan::swapchain.images[i];
|
||||
|
||||
VkImageViewCreateInfo imageView = {};
|
||||
imageView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
imageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
imageView.format = attachment->descriptor.format;
|
||||
imageView.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
|
||||
imageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
imageView.subresourceRange.baseMipLevel = 0;
|
||||
imageView.subresourceRange.levelCount = 1;
|
||||
imageView.subresourceRange.baseArrayLayer = 0;
|
||||
imageView.subresourceRange.layerCount = 1;
|
||||
imageView.image = image;
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImageView(*device, &imageView, nullptr, &attachment->views[i]));
|
||||
VK_REGISTER_HANDLE( attachment->views[i] );
|
||||
uf::renderer::Texture::setImageLayout( commandBuffer, image, VK_IMAGE_LAYOUT_UNDEFINED, attachment->descriptor.layout, subresourceRange );
|
||||
}
|
||||
device->flushCommandBuffer(commandBuffer, uf::renderer::QueueEnum::GRAPHICS);
|
||||
|
||||
attachment->image = ext::vulkan::swapchain.images[0];
|
||||
attachment->view = attachment->views[0];
|
||||
attachment->mem = VK_NULL_HANDLE;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
VkImageCreateInfo imageCreateInfo = {};
|
||||
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
@ -158,27 +201,13 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript
|
||||
|
||||
if ( false ) {
|
||||
auto commandBuffer = device->fetchCommandBuffer(uf::renderer::QueueEnum::GRAPHICS);
|
||||
if ( isDepth ) {
|
||||
// transition attachments to general attachments for imageStore
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.baseArrayLayer = 0;
|
||||
subresourceRange.levelCount = attachment->descriptor.mips;
|
||||
subresourceRange.layerCount = this->views;
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
|
||||
uf::renderer::Texture::setImageLayout( commandBuffer, attachment->image, VK_IMAGE_LAYOUT_UNDEFINED, attachment->descriptor.layout, subresourceRange );
|
||||
} else {
|
||||
// transition attachments to general attachments for imageStore
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.baseArrayLayer = 0;
|
||||
subresourceRange.levelCount = attachment->descriptor.mips;
|
||||
subresourceRange.layerCount = this->views;
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
|
||||
uf::renderer::Texture::setImageLayout( commandBuffer, attachment->image, VK_IMAGE_LAYOUT_UNDEFINED, attachment->descriptor.layout, subresourceRange );
|
||||
}
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.baseArrayLayer = 0;
|
||||
subresourceRange.levelCount = attachment->descriptor.mips;
|
||||
subresourceRange.layerCount = this->views;
|
||||
subresourceRange.aspectMask = isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
uf::renderer::Texture::setImageLayout( commandBuffer, attachment->image, VK_IMAGE_LAYOUT_UNDEFINED, attachment->descriptor.layout, subresourceRange );
|
||||
device->flushCommandBuffer(commandBuffer, uf::renderer::QueueEnum::GRAPHICS);
|
||||
}
|
||||
|
||||
@ -201,6 +230,11 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
|
||||
assert( this->attachments.size() > 0 );
|
||||
|
||||
// Create render pass
|
||||
bool isSwapchain = false;
|
||||
for ( auto& attachment : this->attachments ) {
|
||||
if ( attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) isSwapchain = true;
|
||||
}
|
||||
|
||||
if ( !renderPass ) {
|
||||
uf::stl::vector<VkAttachmentDescription> attachments; attachments.reserve( this->attachments.size() );
|
||||
for ( size_t i = 0; i < this->views; ++i ) {
|
||||
@ -212,7 +246,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
|
||||
description.storeOp = attachment.descriptor.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
|
||||
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
description.initialLayout = attachment.descriptor.layout; // VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // isSwapchain ? VK_IMAGE_LAYOUT_UNDEFINED : attachment.descriptor.layout; // VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
description.finalLayout = ext::vulkan::Texture::remapRenderpassLayout( attachment.descriptor.layout );
|
||||
description.flags = 0;
|
||||
|
||||
@ -220,7 +254,6 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ensure that the subpasses are already described
|
||||
auto passes = this->passes;
|
||||
assert( passes.size() > 0 );
|
||||
@ -316,6 +349,26 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
|
||||
|
||||
dependencies.emplace_back(dependency);
|
||||
}
|
||||
|
||||
// crunge
|
||||
if ( isSwapchain ) {
|
||||
dependencies.resize(2);
|
||||
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||
dependencies[0].dstSubpass = 0;
|
||||
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
||||
|
||||
dependencies[1].srcSubpass = 0;
|
||||
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
|
||||
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
||||
}
|
||||
|
||||
VkRenderPassCreateInfo renderPassInfo = {};
|
||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
@ -336,30 +389,20 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
|
||||
vkDestroyFramebuffer( device, framebuffer, nullptr );
|
||||
VK_UNREGISTER_HANDLE( framebuffer );
|
||||
}
|
||||
|
||||
RenderMode& base = ext::vulkan::getRenderMode( "Swapchain", false );
|
||||
framebuffers.clear();
|
||||
framebuffers.resize(ext::vulkan::swapchain.buffers);
|
||||
for ( size_t i = 0; i < framebuffers.size(); ++i ) {
|
||||
for ( size_t frame = 0; frame < framebuffers.size(); ++frame ) {
|
||||
uf::stl::vector<VkImageView> attachmentViews;
|
||||
|
||||
for ( size_t view = 0; view < this->views; ++view ) {
|
||||
for ( auto view = 0; view < this->views; ++view ) {
|
||||
for ( auto& attachment : this->attachments ) {
|
||||
if ( attachment.descriptor.aliased && attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) {
|
||||
attachmentViews.emplace_back(base.renderTarget.attachments[i].view);
|
||||
continue;
|
||||
if ( attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) {
|
||||
attachmentViews.emplace_back(attachment.views[frame]);
|
||||
} else {
|
||||
attachmentViews.emplace_back(attachment.views[view * attachment.descriptor.mips]);
|
||||
}
|
||||
attachmentViews.emplace_back(attachment.views[view * attachment.descriptor.mips]);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
for ( size_t j = 0; j < this->views; ++j ) {
|
||||
for ( auto& attachment : this->attachments ) {
|
||||
if ( attachment.descriptor.aliased && attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) {
|
||||
attachmentViews.emplace_back(base.renderTarget.attachments[i].view);
|
||||
} else attachmentViews.emplace_back(attachment.views[j]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
VkFramebufferCreateInfo frameBufferCreateInfo = {};
|
||||
frameBufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
@ -371,45 +414,11 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
|
||||
frameBufferCreateInfo.height = height;
|
||||
frameBufferCreateInfo.layers = 1;
|
||||
// Create the framebuffer
|
||||
VK_CHECK_RESULT(vkCreateFramebuffer( device, &frameBufferCreateInfo, nullptr, &framebuffers[i]));
|
||||
VK_REGISTER_HANDLE( framebuffers[i] );
|
||||
VK_CHECK_RESULT(vkCreateFramebuffer( device, &frameBufferCreateInfo, nullptr, &framebuffers[frame]));
|
||||
VK_REGISTER_HANDLE( framebuffers[frame] );
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
{
|
||||
auto commandBuffer = device.fetchCommandBuffer(uf::renderer::QueueEnum::TRANSFER);
|
||||
for ( auto& attachment : attachments ) {
|
||||
bool isDepth = attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
if ( isDepth ) {
|
||||
// transition attachments to general attachments for imageStore
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.levelCount = 1;
|
||||
subresourceRange.baseArrayLayer = 0;
|
||||
subresourceRange.layerCount = 1;
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
subresourceRange.layerCount = 1;
|
||||
|
||||
uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, subresourceRange );
|
||||
} else {
|
||||
// transition attachments to general attachments for imageStore
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.levelCount = 1;
|
||||
subresourceRange.baseArrayLayer = 0;
|
||||
subresourceRange.layerCount = 1;
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subresourceRange.layerCount = 1;
|
||||
|
||||
uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_UNDEFINED, attachment.descriptor.layout, subresourceRange );
|
||||
}
|
||||
}
|
||||
device.flushCommandBuffer(commandBuffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@ -421,6 +430,7 @@ void ext::vulkan::RenderTarget::destroy() {
|
||||
vkDestroyFramebuffer( *device, framebuffer, nullptr );
|
||||
VK_UNREGISTER_HANDLE( framebuffer );
|
||||
}
|
||||
framebuffers.clear();
|
||||
|
||||
for ( auto& attachment : attachments ) {
|
||||
if ( attachment.descriptor.aliased ) continue;
|
||||
|
||||
@ -4,14 +4,24 @@
|
||||
#include <uf/ext/vulkan/swapchain.h>
|
||||
#include <uf/ext/vulkan/initializers.h>
|
||||
#include <uf/utils/window/window.h>
|
||||
#include <uf/ext/ffx/fsr.h>
|
||||
|
||||
VkResult ext::vulkan::Swapchain::acquireNextImage( uint32_t* imageIndex, VkSemaphore presentCompleteSemaphore, VkFence acquireFence ) {
|
||||
// By setting timeout to UINT64_MAX we will always wait until the next image has been acquired or an actual error is thrown
|
||||
// With that we don't have to handle VK_NOT_READY
|
||||
#if UF_USE_FFX_SDK
|
||||
if ( ext::fsr::frameInterpolation ) {
|
||||
return ext::fsr::acquireNextImage( imageIndex, presentCompleteSemaphore, acquireFence );
|
||||
}
|
||||
#endif
|
||||
|
||||
return vkAcquireNextImageKHR( *device, swapChain, VK_DEFAULT_FENCE_TIMEOUT, presentCompleteSemaphore, acquireFence, imageIndex );
|
||||
}
|
||||
|
||||
VkResult ext::vulkan::Swapchain::queuePresent( VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore ) {
|
||||
#if UF_USE_FFX_SDK
|
||||
if ( ext::fsr::frameInterpolation ) {
|
||||
return ext::fsr::queuePresent( queue, imageIndex, waitSemaphore );
|
||||
}
|
||||
#endif
|
||||
VkPresentInfoKHR presentInfo = {};
|
||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
presentInfo.pNext = NULL;
|
||||
@ -168,24 +178,55 @@ void ext::vulkan::Swapchain::initialize( Device& device ) {
|
||||
swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
}
|
||||
|
||||
VK_CHECK_RESULT(vkCreateSwapchainKHR( device.logicalDevice, &swapchainCI, nullptr, &swapChain));
|
||||
#if UF_USE_FFX_SDK
|
||||
VK_CHECK_RESULT(ext::fsr::createSwapchain( device.logicalDevice, &swapchainCI, nullptr, &swapChain ));
|
||||
#else
|
||||
VK_CHECK_RESULT(vkCreateSwapchainKHR( device.logicalDevice, &swapchainCI, nullptr, &swapChain ));
|
||||
#endif
|
||||
// VK_REGISTER_HANDLE( swapchainCI );
|
||||
|
||||
// If an existing swap chain is re-created, destroy the old swap chain
|
||||
// This also cleans up all the presentable images
|
||||
if (oldSwapchain != VK_NULL_HANDLE) {
|
||||
vkDestroySwapchainKHR( device.logicalDevice, oldSwapchain, nullptr);
|
||||
if ( oldSwapchain != VK_NULL_HANDLE ) {
|
||||
#if UF_USE_FFX_SDK
|
||||
ext::fsr::destroySwapchain( device.logicalDevice, oldSwapchain, nullptr);
|
||||
#else
|
||||
vkDestroySwapchainKHR( device.logicalDevice, oldSwapchain, nullptr);
|
||||
#endif
|
||||
// VK_UNREGISTER_HANDLE( oldSwapchain );
|
||||
}
|
||||
#if UF_USE_FFX_SDK
|
||||
VK_CHECK_RESULT(ext::fsr::getSwapchainImages( device.logicalDevice, swapChain, &buffers, NULL));
|
||||
#else
|
||||
VK_CHECK_RESULT(vkGetSwapchainImagesKHR( device.logicalDevice, swapChain, &buffers, NULL));
|
||||
#endif
|
||||
}
|
||||
// Bind images
|
||||
{
|
||||
images.resize( buffers );
|
||||
#if UF_USE_FFX_SDK
|
||||
VK_CHECK_RESULT(ext::fsr::getSwapchainImages( device, swapChain, &buffers, images.data()));
|
||||
#else
|
||||
VK_CHECK_RESULT(vkGetSwapchainImagesKHR( device, swapChain, &buffers, images.data()));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void ext::vulkan::Swapchain::destroy() {
|
||||
if ( !device ) return;
|
||||
|
||||
for ( auto& image : swapchain.images ) {
|
||||
// vkDestroyImage( *device, image, nullptr ); // destroyed via vkDestroySwapchainKHR
|
||||
//VK_UNREGISTER_HANDLE( image );
|
||||
image = VK_NULL_HANDLE;
|
||||
}
|
||||
swapchain.images.clear();
|
||||
if ( swapChain != VK_NULL_HANDLE ) {
|
||||
#if UF_USE_FFX_SDK
|
||||
ext::fsr::destroySwapchain( *device, swapChain, nullptr );
|
||||
#else
|
||||
vkDestroySwapchainKHR( *device, swapChain, nullptr);
|
||||
#endif
|
||||
// VK_UNREGISTER_HANDLE( swapChain )
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user