Mercurial > games > semicongine
changeset 956:cca6f1a675db
fix: again, I think, I have now a correct syncing of vertex buffers updates and drawing of multiple frames in flight XD
author | sam <sam@basx.dev> |
---|---|
date | Mon, 01 Apr 2024 22:42:50 +0700 |
parents | 53249d9bb7a3 |
children | d27c8dbfef1c |
files | examples/E01_hello_triangle.nim semicongine/engine.nim semicongine/renderer.nim semicongine/vulkan/buffer.nim semicongine/vulkan/commandbuffer.nim semicongine/vulkan/image.nim semicongine/vulkan/swapchain.nim |
diffstat | 7 files changed, 45 insertions(+), 37 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/E01_hello_triangle.nim Mon Apr 01 01:06:22 2024 +0700 +++ b/examples/E01_hello_triangle.nim Mon Apr 01 22:42:50 2024 +0700 @@ -26,7 +26,7 @@ ) myengine = initEngine("Hello triangle", showFps = true) -myengine.initRenderer({VERTEX_COLORED_MATERIAL: shaderConfiguration}, vSync = false, inFlightFrames = 2) +myengine.initRenderer({VERTEX_COLORED_MATERIAL: shaderConfiguration}, inFlightFrames = 1) myengine.loadScene(scene) while myengine.updateInputs() == Running and not myengine.keyWasPressed(Escape):
--- a/semicongine/engine.nim Mon Apr 01 01:06:22 2024 +0700 +++ b/semicongine/engine.nim Mon Apr 01 22:42:50 2024 +0700 @@ -22,7 +22,7 @@ import ./text import ./panel -const COUNT_N_RENDERTIMES = 99 +const COUNT_N_RENDERTIMES = 199 type EngineState* = enum @@ -149,18 +149,24 @@ )) proc initRenderer*(engine: var Engine, clearColor = newVec4f(0, 0, 0, 0), vSync = false) = + checkVkResult engine.device.vk.vkDeviceWaitIdle() engine.initRenderer(@[], clearColor, vSync = vSync) + checkVkResult engine.device.vk.vkDeviceWaitIdle() proc loadScene*(engine: var Engine, scene: var Scene) = assert engine.renderer.isSome assert not scene.loaded + checkVkResult engine.device.vk.vkDeviceWaitIdle() scene.addShaderGlobal(ASPECT_RATIO_ATTRIBUTE, engine.getAspectRatio) engine.renderer.get.setupDrawableBuffers(scene) engine.renderer.get.updateMeshData(scene, forceAll = true) engine.renderer.get.updateUniformData(scene, forceAll = true) + checkVkResult engine.device.vk.vkDeviceWaitIdle() proc unloadScene*(engine: var Engine, scene: Scene) = + checkVkResult engine.device.vk.vkDeviceWaitIdle() engine.renderer.get.destroy(scene) + checkVkResult engine.device.vk.vkDeviceWaitIdle() proc renderScene*(engine: var Engine, scene: var Scene) = assert engine.state == Running
--- a/semicongine/renderer.nim Mon Apr 01 01:06:22 2024 +0700 +++ b/semicongine/renderer.nim Mon Apr 01 22:42:50 2024 +0700 @@ -330,30 +330,41 @@ renderer.scenedata[scene] = scenedata -proc refreshMeshAttributeData(renderer: Renderer, scene: var Scene, drawable: Drawable, mesh: Mesh, attribute: string) = - debug &"Refreshing data on mesh mesh for {attribute}" - # ignore attributes that are not used in this shader - if not (attribute in renderer.scenedata[scene].attributeLocation): - return - - let memoryPerformanceHint = renderer.scenedata[scene].attributeLocation[attribute] - renderer.scenedata[scene].vertexBuffers[memoryPerformanceHint].setData( - renderer.queue, - mesh[].getPointer(attribute), - mesh[].attributeSize(attribute), - renderer.scenedata[scene].vertexBufferOffsets[(mesh, attribute)] - ) - proc updateMeshData*(renderer: var Renderer, scene: var Scene, forceAll = false) = assert scene in renderer.scenedata + var addedBarrier = false; for (drawable, mesh) in renderer.scenedata[scene].drawables.mitems: if mesh[].attributes.contains(TRANSFORM_ATTRIB): mesh[].updateInstanceTransforms(TRANSFORM_ATTRIB) let attrs = (if forceAll: mesh[].attributes else: mesh[].dirtyAttributes) for attribute in attrs: - renderer.refreshMeshAttributeData(scene, drawable, mesh, attribute) - debug &"Update mesh attribute {attribute}" + # ignore attributes that are not used in this scene + if attribute in renderer.scenedata[scene].attributeLocation: + debug &"Update mesh attribute {attribute}" + let memoryPerformanceHint = renderer.scenedata[scene].attributeLocation[attribute] + # if we have to do a vkCmdCopyBuffer (not buffer.canMap), then we want to added a barrier to + # not infer with the current frame that is being renderer (relevant when we have multiple frames in flight) + # (remark: ...I think..., I am pretty new to this sync stuff) + if not renderer.scenedata[scene].vertexBuffers[memoryPerformanceHint].canMap and not addedBarrier: + withSingleUseCommandBuffer(renderer.device, renderer.queue, commandBuffer): + let barrier = VkMemoryBarrier( + sType: VK_STRUCTURE_TYPE_MEMORY_BARRIER, + srcAccessMask: [VK_ACCESS_MEMORY_READ_BIT].toBits, + dstAccessMask: [VK_ACCESS_MEMORY_WRITE_BIT].toBits, + ) + commandBuffer.pipelineBarrier( + srcStages = [VK_PIPELINE_STAGE_VERTEX_INPUT_BIT], + dstStages = [VK_PIPELINE_STAGE_TRANSFER_BIT], + memoryBarriers = [barrier] + ) + addedBarrier = true + renderer.scenedata[scene].vertexBuffers[memoryPerformanceHint].setData( + renderer.queue, + mesh[].getPointer(attribute), + mesh[].attributeSize(attribute), + renderer.scenedata[scene].vertexBufferOffsets[(mesh, attribute)] + ) mesh[].clearDirtyAttributes() proc updateUniformData*(renderer: var Renderer, scene: var Scene, forceAll = false) = @@ -413,7 +424,7 @@ scene.clearDirtyShaderGlobals() proc startNewFrame*(renderer: var Renderer) = - # TODO: chance for an infinity-loop + # TODO: chance for an infinity-loop? while not renderer.swapchain.acquireNextFrame(): checkVkResult renderer.device.vk.vkDeviceWaitIdle() let res = renderer.swapchain.recreate() @@ -458,6 +469,7 @@ renderer.swapchain = res.get() checkVkResult renderer.device.vk.vkDeviceWaitIdle() oldSwapchain.destroy() + renderer.swapchain.currentInFlight = (renderer.swapchain.currentInFlight + 1) mod renderer.swapchain.inFlightFrames renderer.nextFrameReady = false func valid*(renderer: Renderer): bool =
--- a/semicongine/vulkan/buffer.nim Mon Apr 01 01:06:22 2024 +0700 +++ b/semicongine/vulkan/buffer.nim Mon Apr 01 22:42:50 2024 +0700 @@ -9,7 +9,6 @@ import ./memory import ./physicaldevice import ./commandbuffer -import ./syncing type Buffer* = object @@ -108,17 +107,7 @@ assert VK_BUFFER_USAGE_TRANSFER_DST_BIT in dst.usage var copyRegion = VkBufferCopy(size: VkDeviceSize(src.size), dstOffset: VkDeviceSize(dstOffset)) - withSingleUseCommandBuffer(src.device, queue, true, commandBuffer): - let barrier = VkMemoryBarrier( - sType: VK_STRUCTURE_TYPE_MEMORY_BARRIER, - srcAccessMask: [VK_ACCESS_MEMORY_WRITE_BIT].toBits, - dstAccessMask: [VK_ACCESS_MEMORY_READ_BIT].toBits, - ) - commandBuffer.pipelineBarrier( - srcStages = [VK_PIPELINE_STAGE_TRANSFER_BIT], - dstStages = [VK_PIPELINE_STAGE_VERTEX_INPUT_BIT], - memoryBarriers = [barrier] - ) + withSingleUseCommandBuffer(src.device, queue, commandBuffer): commandBuffer.vkCmdCopyBuffer(src.vk, dst.vk, 1, addr(copyRegion)) proc destroy*(buffer: var Buffer) = @@ -137,9 +126,12 @@ ) buffer.vk.reset +template canMap*(buffer: Buffer): bool = + buffer.memory.canMap + proc setData*(dst: Buffer, queue: Queue, src: pointer, size: int, bufferOffset = 0) = assert bufferOffset + size <= dst.size - if dst.memory.canMap: + if dst.canMap: copyMem(cast[pointer](cast[int](dst.memory.data) + bufferOffset), src, size) if dst.memory.needsFlushing: dst.memory.flush()
--- a/semicongine/vulkan/commandbuffer.nim Mon Apr 01 01:06:22 2024 +0700 +++ b/semicongine/vulkan/commandbuffer.nim Mon Apr 01 22:42:50 2024 +0700 @@ -53,7 +53,7 @@ ) -template withSingleUseCommandBuffer*(device: Device, queue: Queue, needsTransfer: bool, commandBuffer, body: untyped): untyped = +template withSingleUseCommandBuffer*(device: Device, queue: Queue, commandBuffer, body: untyped): untyped = # TODO? This is super slow, because we call vkQueueWaitIdle block: assert device.vk.valid
--- a/semicongine/vulkan/image.nim Mon Apr 01 01:06:22 2024 +0700 +++ b/semicongine/vulkan/image.nim Mon Apr 01 22:42:50 2024 +0700 @@ -8,7 +8,6 @@ import ./buffer import ./memory import ./commandbuffer -import ./syncing type PixelDepth = 1 .. 4 @@ -112,7 +111,7 @@ else: raise newException(Exception, "Unsupported layout transition!") - withSingleUseCommandBuffer(image.device, queue, false, commandBuffer): + withSingleUseCommandBuffer(image.device, queue, commandBuffer): commandBuffer.pipelineBarrier([srcStage], [dstStage], imageBarriers = [barrier]) proc copy*(src: Buffer, dst: VulkanImage, queue: Queue) = @@ -135,7 +134,7 @@ imageOffset: VkOffset3D(x: 0, y: 0, z: 0), imageExtent: VkExtent3D(width: uint32(dst.width), height: uint32(dst.height), depth: 1) ) - withSingleUseCommandBuffer(src.device, queue, true, commandBuffer): + withSingleUseCommandBuffer(src.device, queue, commandBuffer): commandBuffer.vkCmdCopyBufferToImage( src.vk, dst.vk,
--- a/semicongine/vulkan/swapchain.nim Mon Apr 01 01:06:22 2024 +0700 +++ b/semicongine/vulkan/swapchain.nim Mon Apr 01 22:42:50 2024 +0700 @@ -110,7 +110,6 @@ assert swapchain.device.vk.valid assert swapchain.vk.valid - swapchain.currentInFlight = (swapchain.currentInFlight + 1) mod swapchain.inFlightFrames swapchain.queueFinishedFence[swapchain.currentInFlight].await() let nextImageResult = swapchain.device.vk.vkAcquireNextImageKHR(