# HG changeset patch # User sam # Date 1720959343 -25200 # Node ID 5c6491f28dcd467817f8f2ecb8b8964b0d7bb05b # Parent ba1af13233ee88b7701a3fdceb5f50ef3b9768f5 did: simplify some swapchain stuff, add many destructor calls diff -r ba1af13233ee -r 5c6491f28dcd semicongine/rendering.nim --- a/semicongine/rendering.nim Sat Jul 13 23:27:12 2024 +0700 +++ b/semicongine/rendering.nim Sun Jul 14 19:15:43 2024 +0700 @@ -60,6 +60,8 @@ imageAvailableSemaphore*: array[INFLIGHTFRAMES.int, VkSemaphore] renderFinishedSemaphore*: array[INFLIGHTFRAMES.int, VkSemaphore] commandBuffers: array[INFLIGHTFRAMES.int, VkCommandBuffer] + oldSwapchain: ref Swapchain + oldSwapchainCounter: int # swaps until old swapchain will be destroyed var vulkan*: VulkanGlobals @@ -80,6 +82,8 @@ vk: array[INFLIGHTFRAMES.int, VkDescriptorSet] Pipeline*[TShader] = object vk: VkPipeline + vertexShaderModule: VkShaderModule + fragmentShaderModule: VkShaderModule layout: VkPipelineLayout descriptorSetLayouts: array[DescriptorSetType, VkDescriptorSetLayout] @@ -122,6 +126,8 @@ descriptorPool: VkDescriptorPool memory: array[VK_MAX_MEMORY_TYPES.int, seq[MemoryBlock]] buffers: array[BufferType, seq[Buffer]] + images: seq[VkImage] + imageViews: seq[VkImageView] template ForDescriptorFields(shader: typed, fieldname, valuename, typename, countname, bindingNumber, body: untyped): untyped = var `bindingNumber` {.inject.} = 1'u32 @@ -295,4 +301,8 @@ ) result.graphicsQueue = svkGetDeviceQueue(result.device, result.graphicsQueueFamily, VK_QUEUE_GRAPHICS_BIT) +proc DestroyVulkan*() = + vkDestroyDevice(vulkan.device, nil) + vkDestroyInstance(vulkan.instance, nil) + vulkan = InitVulkan() diff -r ba1af13233ee -r 5c6491f28dcd semicongine/rendering/renderer.nim --- a/semicongine/rendering/renderer.nim Sat Jul 13 23:27:12 2024 +0700 +++ b/semicongine/rendering/renderer.nim Sun Jul 14 19:15:43 2024 +0700 @@ -321,6 +321,23 @@ ) checkVkResult vkCreateDescriptorPool(vulkan.device, addr(poolInfo), nil, addr(result.descriptorPool)) +proc DestroyRenderData*(renderData: RenderData) = + vkDestroyDescriptorPool(vulkan.device, renderData.descriptorPool, nil) + + for buffers in renderData.buffers: + for buffer in buffers: + vkDestroyBuffer(vulkan.device, buffer.vk, nil) + + for imageView in renderData.imageViews: + vkDestroyImageView(vulkan.device, imageView, nil) + + for image in renderData.images: + vkDestroyImage(vulkan.device, image, nil) + + for memoryBlocks in renderData.memory: + for memory in memoryBlocks: + vkFreeMemory(vulkan.device, memory.vk, nil) + proc TransitionImageLayout(image: VkImage, oldLayout, newLayout: VkImageLayout) = var barrier = VkImageMemoryBarrier( @@ -401,6 +418,7 @@ let format = GetVkFormat(texture.depth, usage = usage) texture.vk = svkCreate2DImage(texture.width, texture.height, format, usage) + renderData.images.add texture.vk texture.sampler = createSampler() let memoryRequirements = texture.vk.svkGetImageMemoryRequirements() @@ -435,6 +453,7 @@ # imageview can only be created after memory is bound texture.imageview = svkCreate2DImageView(texture.vk, format) + renderData.imageViews.add texture.imageview # data transfer and layout transition TransitionImageLayout(texture.vk, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) @@ -471,20 +490,6 @@ let `fieldvalue` {.inject.} = value body -#[ -proc Bind[T](pipeline: Pipeline[T], commandBuffer: VkCommandBuffer, currentFrameInFlight: int) = - commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.vk) - commandBuffer.vkCmdBindDescriptorSets( - VK_PIPELINE_BIND_POINT_GRAPHICS, - pipeline.layout, - 0, - 1, - addr pipeline.descriptorSets[currentFrameInFlight], - 0, - nil, - ) - ]# - proc AssertCompatible(TShader, TMesh, TInstance, TGlobals, TMaterial: typedesc) = var descriptorSetCount = 0 diff -r ba1af13233ee -r 5c6491f28dcd semicongine/rendering/shaders.nim --- a/semicongine/rendering/shaders.nim Sat Jul 13 23:27:12 2024 +0700 +++ b/semicongine/rendering/shaders.nim Sun Jul 14 19:15:43 2024 +0700 @@ -1,8 +1,3 @@ -type - ShaderObject[TShader] = object - vertexShaderModule: VkShaderModule - fragmentShaderModule: VkShaderModule - func GlslType[T: SupportedGPUType|Texture](value: T): string = when T is float32: "float" elif T is float64: "double" @@ -263,7 +258,7 @@ i += 4 -proc CompileShader[TShader](shader: static TShader): ShaderObject[TShader] = +proc CompileShader[TShader](shader: static TShader): (VkShaderModule, VkShaderModule) = const (vertexShaderSource, fragmentShaderSource) = generateShaderSource(shader) let vertexBinary = compileGlslToSPIRV(VK_SHADER_STAGE_VERTEX_BIT, vertexShaderSource) @@ -274,13 +269,13 @@ codeSize: csize_t(vertexBinary.len * sizeof(uint32)), pCode: vertexBinary.ToCPointer, ) - checkVkResult vulkan.device.vkCreateShaderModule(addr(createInfoVertex), nil, addr(result.vertexShaderModule)) + checkVkResult vulkan.device.vkCreateShaderModule(addr(createInfoVertex), nil, addr(result[0])) var createInfoFragment = VkShaderModuleCreateInfo( sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, codeSize: csize_t(fragmentBinary.len * sizeof(uint32)), pCode: fragmentBinary.ToCPointer, ) - checkVkResult vulkan.device.vkCreateShaderModule(addr(createInfoFragment), nil, addr(result.fragmentShaderModule)) + checkVkResult vulkan.device.vkCreateShaderModule(addr(createInfoFragment), nil, addr(result[1])) template ForVertexDataFields(shader: typed, fieldname, valuename, isinstancename, body: untyped): untyped = for theFieldname, value in fieldPairs(shader): @@ -306,7 +301,7 @@ # create pipeline const shader = default(TShader) - let shaderObject = CompileShader(shader) + (result.vertexShaderModule, result.fragmentShaderModule) = CompileShader(shader) for theFieldname, value in fieldPairs(default(TShader)): when typeof(value) is DescriptorSet: @@ -343,13 +338,13 @@ VkPipelineShaderStageCreateInfo( sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, stage: VK_SHADER_STAGE_VERTEX_BIT, - module: shaderObject.vertexShaderModule, + module: result.vertexShaderModule, pName: "main", ), VkPipelineShaderStageCreateInfo( sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, stage: VK_SHADER_STAGE_FRAGMENT_BIT, - module: shaderObject.fragmentShaderModule, + module: result.fragmentShaderModule, pName: "main", ), ] @@ -465,3 +460,6 @@ addr(result.vk) ) +proc DestroyPipeline*(pipeline: Pipeline) = + vkDestroyShaderModule(vulkan.device, pipeline.vertexShaderModule, nil) + vkDestroyShaderModule(vulkan.device, pipeline.fragmentShaderModule, nil) diff -r ba1af13233ee -r 5c6491f28dcd semicongine/rendering/swapchain.nim --- a/semicongine/rendering/swapchain.nim Sat Jul 13 23:27:12 2024 +0700 +++ b/semicongine/rendering/swapchain.nim Sun Jul 14 19:15:43 2024 +0700 @@ -4,7 +4,7 @@ renderPass: VkRenderPass, vSync: bool = false, samples = VK_SAMPLE_COUNT_1_BIT, - oldSwapchain = VkSwapchainKHR(0), + oldSwapchain: ref Swapchain = nil, ): Option[Swapchain] = assert vulkan.instance.Valid @@ -40,7 +40,7 @@ compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, # only used for blending with other windows, can be opaque presentMode: if (vSync or not hasTripleBuffering): VK_PRESENT_MODE_FIFO_KHR else: VK_PRESENT_MODE_MAILBOX_KHR, clipped: true, - oldSwapchain: oldSwapchain, + oldSwapchain: if oldSwapchain != nil: oldSwapchain.vk else: VkSwapchainKHR(0), ) var swapchain: Swapchain if vkCreateSwapchainKHR(vulkan.device, addr(swapchainCreateInfo), nil, addr(swapchain.vk)) != VK_SUCCESS: @@ -51,6 +51,9 @@ swapchain.renderPass = renderPass swapchain.vSync = vSync swapchain.samples = samples + swapchain.oldSwapchain = oldSwapchain + if swapchain.oldSwapchain != nil: + swapchain.oldSwapchainCounter = INFLIGHTFRAMES.int * 2 # create msaa image+view if desired if samples != VK_SAMPLE_COUNT_1_BIT: @@ -109,8 +112,24 @@ return some(swapchain) +proc DestroySwapchain*(swapchain: Swapchain) = + + for fence in swapchain.queueFinishedFence: + vkDestroyFence(vulkan.device, fence, nil) + + for semaphore in swapchain.imageAvailableSemaphore: + vkDestroySemaphore(vulkan.device, semaphore, nil) + + for semaphore in swapchain.renderFinishedSemaphore: + vkDestroySemaphore(vulkan.device, semaphore, nil) + + for imageView in swapchain.framebufferViews: + vkDestroyImageView(vulkan.device, imageView, nil) + + vkDestroyCommandPool(vulkan.device, swapchain.commandBufferPool, nil) + proc TryAcquireNextImage(swapchain: var Swapchain): Option[VkFramebuffer] = - if not swapchain.queueFinishedFence[swapchain.currentFiF].Await(1_000_000_000): + if not swapchain.queueFinishedFence[swapchain.currentFiF].Await(100_000_000): return none(VkFramebuffer) let nextImageResult = vkAcquireNextImageKHR( @@ -158,6 +177,14 @@ pResults: nil, ) let presentResult = vkQueuePresentKHR(vulkan.graphicsQueue, addr(presentInfo)) + + if swapchain.oldSwapchain != nil: + dec swapchain.oldSwapchainCounter + if swapchain.oldSwapchainCounter <= 0: + DestroySwapchain(swapchain.oldSwapchain[]) + swapchain.oldSwapchain = nil + + if presentResult != VK_SUCCESS: return false @@ -165,31 +192,18 @@ return true proc Recreate(swapchain: Swapchain): Option[Swapchain] = - echo "Recreating swapchain" + var oldSwapchain = new Swapchain + oldSwapchain[] = swapchain InitSwapchain( renderPass = swapchain.renderPass, vSync = swapchain.vSync, samples = swapchain.samples, - oldSwapchain = swapchain.vk, + oldSwapchain = oldSwapchain, ) template WithNextFrame*(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: + if maybeFramebuffer.isSome: block: let `framebufferName` {.inject.} = maybeFramebuffer.get let `commandBufferName` {.inject.} = swapchain.commandBuffers[swapchain.currentFiF] @@ -203,7 +217,9 @@ body checkVkResult vkEndCommandBuffer(`commandBufferName`) - if not Swap(swapchain = swapchain, commandBuffer = `commandBufferName`): - let maybeNewSwapchain = Recreate(swapchain) - if maybeNewSwapchain.isSome: - swapchain = maybeNewSwapchain.get + discard Swap(swapchain = swapchain, commandBuffer = `commandBufferName`) + else: + let maybeNewSwapchain = Recreate(swapchain) + if maybeNewSwapchain.isSome: + swapchain = maybeNewSwapchain.get + diff -r ba1af13233ee -r 5c6491f28dcd semicongine/rendering/vulkan_wrappers.nim --- a/semicongine/rendering/vulkan_wrappers.nim Sat Jul 13 23:27:12 2024 +0700 +++ b/semicongine/rendering/vulkan_wrappers.nim Sun Jul 14 19:15:43 2024 +0700 @@ -270,6 +270,7 @@ var fence = svkCreateFence() checkVkResult vkQueueSubmit(vulkan.graphicsQueue, 1, addr(submitInfo), fence) discard fence.Await() + vkDestroyFence(vulkan.device, fence, nil) vkDestroyCommandPool(vulkan.device, commandBufferPool, nil) template WithStagingBuffer*[T: (VkBuffer, uint64)|(VkImage, uint32, uint32)]( diff -r ba1af13233ee -r 5c6491f28dcd test1.nim --- a/test1.nim Sat Jul 13 23:27:12 2024 +0700 +++ b/test1.nim Sun Jul 14 19:15:43 2024 +0700 @@ -116,5 +116,13 @@ while UpdateInputs(): WithNextFrame(swapchain, framebuffer, commandbuffer): WithRenderPass(mainRenderpass, framebuffer, commandbuffer, swapchain.width, swapchain.height, NewVec4f(1, 0, 0, 0)): - # echo (getMonoTime() - t).inMicroseconds.float / 1000.0 + vkCmdBindPipeline(commandbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline1.vk) + echo (getMonoTime() - t).inMicroseconds.float / 1000.0 t = getMonoTime() + +DestroyPipeline(pipeline1) + +DestroyRenderData(renderdata) +checkVkResult vkDeviceWaitIdle(vulkan.device) +DestroySwapchain(swapchain) +DestroyVulkan()