From 2c3da15a4deb67e1d43e19a48a47a9df4eaf1664 Mon Sep 17 00:00:00 2001 From: ecker Date: Sat, 25 Apr 2026 00:37:19 -0500 Subject: [PATCH] fake frames (and cleaning up swapchain code) --- Makefile | 4 +- bin/data/config.json | 13 +- bin/data/shaders/display/compositor/comp.glsl | 24 + engine/inc/uf/ext/ffx/fsr.h | 12 +- engine/inc/uf/ext/vulkan/device.h | 5 +- engine/inc/uf/ext/vulkan/swapchain.h | 3 +- engine/src/engine/ext/ext.cpp | 8 + engine/src/ext/ffx/fsr.cpp | 210 ++++- engine/src/ext/vulkan/device.cpp | 110 ++- engine/src/ext/vulkan/graphic.cpp | 3 +- engine/src/ext/vulkan/rendermodes/base.cpp | 717 ++++-------------- .../src/ext/vulkan/rendermodes/deferred.cpp | 14 +- .../ext/vulkan/rendermodes/rendertarget.cpp | 10 +- engine/src/ext/vulkan/rendertarget.cpp | 164 ++-- engine/src/ext/vulkan/swapchain.cpp | 51 +- 15 files changed, 633 insertions(+), 715 deletions(-) create mode 100644 bin/data/shaders/display/compositor/comp.glsl diff --git a/Makefile b/Makefile index f22dd4a5..186f6608 100644 --- a/Makefile +++ b/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))) diff --git a/bin/data/config.json b/bin/data/config.json index bdbedbcf..1ae30133 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -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) diff --git a/bin/data/shaders/display/compositor/comp.glsl b/bin/data/shaders/display/compositor/comp.glsl new file mode 100644 index 00000000..1c18818c --- /dev/null +++ b/bin/data/shaders/display/compositor/comp.glsl @@ -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); +} \ No newline at end of file diff --git a/engine/inc/uf/ext/ffx/fsr.h b/engine/inc/uf/ext/ffx/fsr.h index aa840703..c7f12522 100644 --- a/engine/inc/uf/ext/ffx/fsr.h +++ b/engine/inc/uf/ext/ffx/fsr.h @@ -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(); } } diff --git a/engine/inc/uf/ext/vulkan/device.h b/engine/inc/uf/ext/vulkan/device.h index 9dfd40eb..42083858 100644 --- a/engine/inc/uf/ext/vulkan/device.h +++ b/engine/inc/uf/ext/vulkan/device.h @@ -15,6 +15,7 @@ namespace ext { PRESENT, COMPUTE, TRANSFER, + ACQUIRE, }; struct CommandBuffer { bool immediate{true}; @@ -76,6 +77,7 @@ namespace ext { uf::ThreadUnique present; uf::ThreadUnique compute; uf::ThreadUnique transfer; + uf::ThreadUnique 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 diff --git a/engine/inc/uf/ext/vulkan/swapchain.h b/engine/inc/uf/ext/vulkan/swapchain.h index a8d8e215..5611959b 100644 --- a/engine/inc/uf/ext/vulkan/swapchain.h +++ b/engine/inc/uf/ext/vulkan/swapchain.h @@ -14,9 +14,10 @@ namespace ext { uint32_t buffers = {}; uf::stl::vector presentCompleteSemaphores; + uf::stl::vector 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 diff --git a/engine/src/engine/ext/ext.cpp b/engine/src/engine/ext/ext.cpp index bd59aefd..d79b2c89 100644 --- a/engine/src/engine/ext/ext.cpp +++ b/engine/src/engine/ext/ext.cpp @@ -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) ) { diff --git a/engine/src/ext/ffx/fsr.cpp b/engine/src/ext/ffx/fsr.cpp index 9f54e93e..fd71a266 100644 --- a/engine/src/ext/ffx/fsr.cpp +++ b/engine/src/ext/ffx/fsr.cpp @@ -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 scratchBufferFG; uf::stl::vector 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(); 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 \ No newline at end of file diff --git a/engine/src/ext/vulkan/device.cpp b/engine/src/ext/vulkan/device.cpp index 96bafe88..2b029bd8 100644 --- a/engine/src/ext/vulkan/device.cpp +++ b/engine/src/ext/vulkan/device.cpp @@ -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* 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 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> 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 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(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 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 { diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index 13abd678..f296772a 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -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 diff --git a/engine/src/ext/vulkan/rendermodes/base.cpp b/engine/src/ext/vulkan/rendermodes/base.cpp index c17c67dd..afc6cfa4 100644 --- a/engine/src/ext/vulkan/rendermodes/base.cpp +++ b/engine/src/ext/vulkan/rendermodes/base.cpp @@ -9,13 +9,173 @@ #include #include -namespace { - uf::stl::vector 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& graphics ) { // if ( ext::vulkan::renderModes.size() > 1 ) return; @@ -94,40 +254,11 @@ void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vectorUF_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::vectorUF_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::vectordestroy(); - 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 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 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(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(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 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(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 \ No newline at end of file diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index 82e75060..5e7850ce 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -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)); } diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index 6bf34536..5dccccb3 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -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; diff --git a/engine/src/ext/vulkan/rendertarget.cpp b/engine/src/ext/vulkan/rendertarget.cpp index 25f0d184..4ce1743a 100644 --- a/engine/src/ext/vulkan/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendertarget.cpp @@ -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 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 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; diff --git a/engine/src/ext/vulkan/swapchain.cpp b/engine/src/ext/vulkan/swapchain.cpp index 4e1bc19c..0339fa4b 100644 --- a/engine/src/ext/vulkan/swapchain.cpp +++ b/engine/src/ext/vulkan/swapchain.cpp @@ -4,14 +4,24 @@ #include #include #include +#include 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 ) }