# HG changeset patch # User sam # Date 1720873563 -25200 # Node ID 96a094cd0c783a2bb69f83da65cf522ea566c510 # Parent f6a0dc7ad0521e745c2f35c8c43f7b182b00a742 sync to notebook in bedroom diff -r f6a0dc7ad052 -r 96a094cd0c78 semicongine/rendering.nim --- a/semicongine/rendering.nim Fri Jul 12 23:06:29 2024 +0700 +++ b/semicongine/rendering.nim Sat Jul 13 19:26:03 2024 +0700 @@ -49,11 +49,14 @@ msaaImageView: VkImageView framebuffers: seq[VkFramebuffer] framebufferViews: seq[VkImageView] + currentFramebufferIndex: uint32 + commandBufferPool: VkCommandPool + # frame-in-flight handling + currentFiF: range[0 .. (INFLIGHTFRAMES - 1).int] queueFinishedFence*: array[INFLIGHTFRAMES.int, VkFence] imageAvailableSemaphore*: array[INFLIGHTFRAMES.int, VkSemaphore] renderFinishedSemaphore*: array[INFLIGHTFRAMES.int, VkSemaphore] - currentFiF: range[0 .. (INFLIGHTFRAMES - 1).int] - currentFramebufferIndex: uint32 + commandBuffers: array[INFLIGHTFRAMES.int, VkCommandBuffer] var vulkan*: VulkanGlobals @@ -167,10 +170,12 @@ include ./platform/vulkan_extensions # for REQUIRED_PLATFORM_EXTENSIONS # instance creation - # + + # enagle all kind of debug stuff when not defined(release): let requiredExtensions = REQUIRED_PLATFORM_EXTENSIONS & @["VK_KHR_surface", "VK_EXT_debug_utils"] let layers: seq[string] = if hasValidationLayer(): @["VK_LAYER_KHRONOS_validation"] else: @[] + putEnv("VK_LAYER_ENABLES", "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD,VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXTVK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT") else: let requiredExtensions = REQUIRED_PLATFORM_EXTENSIONS & @["VK_KHR_surface"] let layers: seq[string] diff -r f6a0dc7ad052 -r 96a094cd0c78 semicongine/rendering/swapchain.nim --- a/semicongine/rendering/swapchain.nim Fri Jul 12 23:06:29 2024 +0700 +++ b/semicongine/rendering/swapchain.nim Sat Jul 13 19:26:03 2024 +0700 @@ -4,7 +4,6 @@ renderPass: VkRenderPass, vSync: bool = false, samples = VK_SAMPLE_COUNT_1_BIT, - nFramebuffers = N_FRAMEBUFFERS, oldSwapchain = VkSwapchainKHR(0), ): Option[Swapchain] = assert vulkan.instance.Valid @@ -27,7 +26,7 @@ # create swapchain let hasTripleBuffering = VK_PRESENT_MODE_MAILBOX_KHR in svkGetPhysicalDeviceSurfacePresentModesKHR() - var createInfo = VkSwapchainCreateInfoKHR( + var swapchainCreateInfo = VkSwapchainCreateInfoKHR( sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, surface: vulkan.surface, minImageCount: minFramebufferCount, @@ -44,7 +43,7 @@ oldSwapchain: oldSwapchain, ) var swapchain: Swapchain - if vkCreateSwapchainKHR(vulkan.device, addr(createInfo), nil, addr(swapchain.vk)) != VK_SUCCESS: + if vkCreateSwapchainKHR(vulkan.device, addr(swapchainCreateInfo), nil, addr(swapchain.vk)) != VK_SUCCESS: return none(Swapchain) swapchain.renderPass = renderPass @@ -90,9 +89,25 @@ swapchain.queueFinishedFence[i] = svkCreateFence(signaled = true) swapchain.imageAvailableSemaphore[i] = svkCreateSemaphore() swapchain.renderFinishedSemaphore[i] = svkCreateSemaphore() + + # command buffers + var commandPoolCreateInfo = VkCommandPoolCreateInfo( + sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + flags: toBits [VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT], + queueFamilyIndex: vulkan.graphicsQueueFamily, + ) + checkVkResult vkCreateCommandPool(vulkan.device, addr(commandPoolCreateInfo), nil, addr(swapchain.commandBufferPool)) + var allocInfo = VkCommandBufferAllocateInfo( + sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + commandPool: swapchain.commandBufferPool, + level: VK_COMMAND_BUFFER_LEVEL_PRIMARY, + commandBufferCount: INFLIGHTFRAMES, + ) + checkVkResult vkAllocateCommandBuffers(vulkan.device, addr(allocInfo), swapchain.commandBuffers.ToCPointer) + return some(swapchain) -proc TryAcquireNextImage*(swapchain: var Swapchain): Option[VkFramebuffer] = +proc TryAcquireNextImage(swapchain: var Swapchain): Option[VkFramebuffer] = swapchain.queueFinishedFence[swapchain.currentFiF].Await() let nextImageResult = vkAcquireNextImageKHR( @@ -110,7 +125,7 @@ return none(VkFramebuffer) return some(swapchain.framebuffers[swapchain.currentFramebufferIndex]) -proc Swap*(swapchain: var Swapchain, queue: VkQueue, commandBuffer: VkCommandBuffer): bool = +proc Swap(swapchain: var Swapchain, commandBuffer: VkCommandBuffer): bool = var waitStage = VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT) submitInfo = VkSubmitInfo( @@ -124,7 +139,7 @@ pSignalSemaphores: addr(swapchain.renderFinishedSemaphore[swapchain.currentFiF]), ) checkVkResult vkQueueSubmit( - queue = queue, + queue = vulkan.graphicsQueue, submitCount = 1, pSubmits = addr(submitInfo), fence = swapchain.queueFinishedFence[swapchain.currentFiF] @@ -143,13 +158,47 @@ if presentResult != VK_SUCCESS: return false + swapchain.currentFiF = (uint32(swapchain.currentFiF) + 1) mod INFLIGHTFRAMES return true -proc Recreate*(swapchain: Swapchain): Option[Swapchain] = +proc Recreate(swapchain: Swapchain): Option[Swapchain] = InitSwapchain( renderPass = swapchain.renderPass, vSync = swapchain.vSync, samples = swapchain.samples, - nFramebuffers = swapchain.framebuffers.len.uint32, oldSwapchain = swapchain.vk, ) + +template RecordRenderingCommands*(swapchain: var Swapchain, framebufferName, commandBufferName, body: untyped): untyped = + var nextFrameReady = true + + var maybeFramebuffer = TryAcquireNextImage(swapchain) + if not maybeFramebuffer.isSome: + let maybeNewSwapchain = Recreate(swapchain) + # unable to recreate swapchain + if not maybeNewSwapchain.isSome: + nextFrameReady = false + else: + swapchain = maybeNewSwapchain.get + maybeFramebuffer = TryAcquireNextImage(swapchain) + if not maybeFramebuffer.isSome: + nextFrameReady = false + + if nextFrameReady: + block: + let `framebufferName` {.inject.} = maybeFramebuffer.get + let `commandBufferName` {.inject.} = swapchain.commandBuffers[swapchain.currentFiF] + let beginInfo = VkCommandBufferBeginInfo( + sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + flags: VkCommandBufferUsageFlags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT), + ) + checkVkResult vkResetCommandBuffer(`commandBufferName`, VkCommandBufferResetFlags(0)) + checkVkResult vkBeginCommandBuffer(`commandBufferName`, addr(beginInfo)) + + body + + checkVkResult vkEndCommandBuffer(`commandBufferName`) + if not Swap(swapchain = swapchain, commandBuffer = `commandBufferName`): + let maybeNewSwapchain = Recreate(swapchain) + if maybeNewSwapchain.isSome: + swapchain = maybeNewSwapchain.get diff -r f6a0dc7ad052 -r 96a094cd0c78 semicongine/rendering/vulkan_wrappers.nim --- a/semicongine/rendering/vulkan_wrappers.nim Fri Jul 12 23:06:29 2024 +0700 +++ b/semicongine/rendering/vulkan_wrappers.nim Sat Jul 13 19:26:03 2024 +0700 @@ -235,7 +235,7 @@ commandBufferPool: VkCommandPool createInfo = VkCommandPoolCreateInfo( sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - flags: toBits [VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT], + flags: VkCommandPoolCreateFlags(0), queueFamilyIndex: vulkan.graphicsQueueFamily, ) checkVkResult vkCreateCommandPool(vulkan.device, addr createInfo, nil, addr(commandBufferPool)) diff -r f6a0dc7ad052 -r 96a094cd0c78 test1.nim --- a/test1.nim Fri Jul 12 23:06:29 2024 +0700 +++ b/test1.nim Sat Jul 13 19:26:03 2024 +0700 @@ -41,8 +41,6 @@ vertexCode: string = "void main() {}" fragmentCode: string = "void main() {}" -putEnv("VK_LAYER_ENABLES", "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD,VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXTVK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT") - let frameWidth = 100'u32 let frameHeight = 100'u32 @@ -76,7 +74,7 @@ ) let renderpass = CreatePresentationRenderPass() -var swapchainResult = InitSwapchain(renderpass) +var swapchainResult = InitSwapchain(renderpass = renderpass) assert swapchainResult.isSome() var swapchain = swapchainResult.get() @@ -104,59 +102,21 @@ UpdateAllGPUBuffers(myGlobals) renderdata.FlushAllMemory() - # descriptors echo "Writing descriptors" InitDescriptorSet(renderdata, pipeline1.GetLayoutFor(GlobalSet), myGlobals) InitDescriptorSet(renderdata, pipeline1.GetLayoutFor(MaterialSet), uniforms1) - - - - -# command buffer -var - commandBufferPool: VkCommandPool - createInfo = VkCommandPoolCreateInfo( - sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - flags: toBits [VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT], - queueFamilyIndex: vulkan.graphicsQueueFamily, - ) -checkVkResult vkCreateCommandPool(vulkan.device, addr createInfo, nil, addr commandBufferPool) -var - cmdBuffers: array[INFLIGHTFRAMES.int, VkCommandBuffer] - allocInfo = VkCommandBufferAllocateInfo( - sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - commandPool: commandBufferPool, - level: VK_COMMAND_BUFFER_LEVEL_PRIMARY, - commandBufferCount: INFLIGHTFRAMES, - ) -checkVkResult vkAllocateCommandBuffers(vulkan.device, addr allocInfo, cmdBuffers.ToCPointer) - - - # start command buffer -block: - let - currentFramebuffer = VkFramebuffer(0) # TODO - currentFrameInFlight = 1 - cmd = cmdBuffers[currentFrameInFlight] - beginInfo = VkCommandBufferBeginInfo( - sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - flags: VkCommandBufferUsageFlags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT), - ) - checkVkResult cmd.vkResetCommandBuffer(VkCommandBufferResetFlags(0)) - checkVkResult cmd.vkBeginCommandBuffer(addr(beginInfo)) - - # start renderpass - block: +while true: + RecordRenderingCommands(swapchain, framebuffer, commandbuffer): var clearColors = [VkClearValue(color: VkClearColorValue(float32: [0, 0, 0, 0]))] renderPassInfo = VkRenderPassBeginInfo( sType: VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, renderPass: renderpass, - framebuffer: currentFramebuffer, # TODO + framebuffer: framebuffer, renderArea: VkRect2D( offset: VkOffset2D(x: 0, y: 0), extent: VkExtent2D(width: frameWidth, height: frameHeight), @@ -176,19 +136,18 @@ offset: VkOffset2D(x: 0, y: 0), extent: VkExtent2D(width: frameWidth, height: frameHeight) ) - vkCmdBeginRenderPass(cmd, addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE) + vkCmdBeginRenderPass(commandbuffer, addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE) # setup viewport - vkCmdSetViewport(cmd, firstViewport = 0, viewportCount = 1, addr(viewport)) - vkCmdSetScissor(cmd, firstScissor = 0, scissorCount = 1, addr(scissor)) + vkCmdSetViewport(commandbuffer, firstViewport = 0, viewportCount = 1, addr(viewport)) + vkCmdSetScissor(commandbuffer, firstScissor = 0, scissorCount = 1, addr(scissor)) # bind pipeline, will be loop # block: - # Bind(pipeline1, cmd, currentFrameInFlight = currentFrameInFlight) + # Bind(pipeline1, commandbuffer, currentFrameInFlight = currentFrameInFlight) # render object, will be loop # block: - # Render(cmd, pipeline1, myGlobals, uniforms1, myMesh1, instances1) + # Render(commandbuffer, pipeline1, myGlobals, uniforms1, myMesh1, instances1) - vkCmdEndRenderPass(cmd) - checkVkResult cmd.vkEndCommandBuffer() + vkCmdEndRenderPass(commandbuffer)