# HG changeset patch # User Sam # Date 1681729339 -25200 # Node ID b434feaf2b67361d109d5aa2c45edfa332b02cc2 # Parent 008592db044227a16dd35d4cdfeb4b1b8746696d did: finish refactoring of render pipeline, yipi! :) diff -r 008592db0442 -r b434feaf2b67 src/semicongine.nim --- a/src/semicongine.nim Wed Apr 12 01:20:53 2023 +0700 +++ b/src/semicongine.nim Mon Apr 17 18:02:19 2023 +0700 @@ -6,8 +6,8 @@ import semicongine/gpu_data import semicongine/math import semicongine/mesh +import semicongine/renderer import semicongine/platform/window -import semicongine/scene import semicongine/vulkan export color @@ -18,6 +18,6 @@ export gpu_data export math export mesh +export renderer export window -export scene export vulkan diff -r 008592db0442 -r b434feaf2b67 src/semicongine/entity.nim --- a/src/semicongine/entity.nim Wed Apr 12 01:20:53 2023 +0700 +++ b/src/semicongine/entity.nim Mon Apr 17 18:02:19 2023 +0700 @@ -1,4 +1,5 @@ import std/strformat +import std/hashes import std/typetraits import ./math/matrix @@ -27,6 +28,8 @@ value.setValue(data) ShaderGlobal(name: name, value: value) +func hash*(entity: Entity): Hash = + hash(cast[pointer](entity)) method `$`*(entity: Entity): string {.base.} = entity.name method `$`*(component: Component): string {.base.} = @@ -81,11 +84,11 @@ result = currentEntity.transform * result currentEntity = currentEntity.parent -iterator allComponentsOfType*[T: Component](root: Entity): T = +iterator allComponentsOfType*[T: Component](root: Entity): var T = var queue = @[root] while queue.len > 0: let entity = queue.pop - for component in entity.components: + for component in entity.components.mitems: if component of T: yield T(component) for i in countdown(entity.children.len - 1, 0): diff -r 008592db0442 -r b434feaf2b67 src/semicongine/renderer.nim --- a/src/semicongine/renderer.nim Wed Apr 12 01:20:53 2023 +0700 +++ b/src/semicongine/renderer.nim Mon Apr 17 18:02:19 2023 +0700 @@ -1,27 +1,171 @@ import std/options +import std/sequtils +import std/tables +import std/strformat +import std/logging import ./vulkan/api +import ./vulkan/buffer import ./vulkan/device +import ./vulkan/drawable +import ./vulkan/framebuffer +import ./vulkan/pipeline import ./vulkan/physicaldevice import ./vulkan/renderpass import ./vulkan/swapchain +import ./entity +import ./mesh +import ./gpu_data + type - Renderer = object + SceneData = object + drawables*: seq[Drawable] + vertexBuffers*: Table[MemoryLocation, Buffer] + indexBuffer*: Buffer + Renderer* = object + device: Device surfaceFormat: VkSurfaceFormatKHR renderPasses: seq[RenderPass] swapchain: Swapchain + scenedata: Table[Entity, SceneData] -proc initRenderer(device: Device, renderPasses: seq[RenderPass]): Renderer = +proc initRenderer*(device: Device, renderPasses: openArray[RenderPass]): Renderer = assert device.vk.valid assert renderPasses.len > 0 for renderPass in renderPasses: assert renderPass.vk.valid - result.renderPasses = renderPasses + result.device = device + result.renderPasses = renderPasses.toSeq result.surfaceFormat = device.physicalDevice.getSurfaceFormats().filterSurfaceFormat() - let (swapchain, res) = device.createSwapchain(renderPasses[^1], result.surfaceFormat, device.firstGraphicsQueue().get().family, 2) + let (swapchain, res) = device.createSwapchain(result.renderPasses[^1], result.surfaceFormat, device.firstGraphicsQueue().get().family, 2) if res != VK_SUCCESS: raise newException(Exception, "Unable to create swapchain") result.swapchain = swapchain + +proc setupDrawableBuffers*(renderer: var Renderer, tree: Entity, inputs: seq[ShaderAttribute]) = + assert not (tree in renderer.scenedata) + var data = SceneData() + + var allMeshes: seq[Mesh] + for mesh in allComponentsOfType[Mesh](tree): + allMeshes.add mesh + for inputAttr in inputs: + assert mesh.hasDataFor(inputAttr.name), &"{mesh} missing data for {inputAttr}" + + var indicesBufferSize = 0'u64 + for mesh in allMeshes: + if mesh.indexType != None: + let indexAlignment = case mesh.indexType + of None: 0'u64 + of Tiny: 1'u64 + of Small: 2'u64 + of Big: 4'u64 + # index value alignment required by Vulkan + if indicesBufferSize mod indexAlignment != 0: + indicesBufferSize += indexAlignment - (indicesBufferSize mod indexAlignment) + indicesBufferSize += mesh.indexDataSize + if indicesBufferSize > 0: + data.indexBuffer = renderer.device.createBuffer( + size=indicesBufferSize, + usage=[VK_BUFFER_USAGE_INDEX_BUFFER_BIT], + useVRAM=true, + mappable=false, + ) + + # one vertex data buffer per memory location + var perLocationOffsets: Table[MemoryLocation, uint64] + for location, attributes in inputs.groupByMemoryLocation().pairs: + # setup one buffer per attribute-location-type + var bufferSize = 0'u64 + for mesh in allMeshes: + for attribute in attributes: + bufferSize += mesh.dataSize(attribute.name) + if bufferSize > 0: + data.vertexBuffers[location] = renderer.device.createBuffer( + size=bufferSize, + usage=[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT], + useVRAM=location in [VRAM, VRAMVisible], + mappable=location in [VRAMVisible, RAM], + ) + perLocationOffsets[location] = 0 + + var indexBufferOffset = 0'u64 + for mesh in allMeshes: + var offsets: Table[MemoryLocation, seq[uint64]] + for location, attributes in inputs.groupByMemoryLocation().pairs: + for attribute in attributes: + if not (location in offsets): + offsets[location] = @[] + offsets[location].add perLocationOffsets[location] + var (pdata, size) = mesh.getRawData(attribute.name) + data.vertexBuffers[location].setData(pdata, size, perLocationOffsets[location]) + perLocationOffsets[location] += size + + let indexed = mesh.indexType != None + var drawable = Drawable( + elementCount: if indexed: mesh.indicesCount else: mesh.vertexCount, + bufferOffsets: offsets, + instanceCount: mesh.instanceCount, + indexed: indexed, + ) + if indexed: + let indexAlignment = case mesh.indexType + of None: 0'u64 + of Tiny: 1'u64 + of Small: 2'u64 + of Big: 4'u64 + # index value alignment required by Vulkan + if indexBufferOffset mod indexAlignment != 0: + indexBufferOffset += indexAlignment - (indexBufferOffset mod indexAlignment) + drawable.indexBufferOffset = indexBufferOffset + drawable.indexType = mesh.indexType + var (pdata, size) = mesh.getRawIndexData() + data.indexBuffer.setData(pdata, size, indexBufferOffset) + indexBufferOffset += size + data.drawables.add drawable + + renderer.scenedata[tree] = data + +proc render*(renderer: var Renderer, entity: Entity): bool = + var commandBuffer = renderer.swapchain.nextFrame() + + commandBuffer.beginRenderCommands(renderer.swapchain.renderPass, renderer.swapchain.currentFramebuffer()) + + for i in 0 ..< renderer.swapchain.renderPass.subpasses.len: + let subpass = renderer.swapchain.renderPass.subpasses[i] + for pipeline in subpass.pipelines: + var mpipeline = pipeline + commandBuffer.vkCmdBindPipeline(subpass.pipelineBindPoint, mpipeline.vk) + commandBuffer.vkCmdBindDescriptorSets(subpass.pipelineBindPoint, mpipeline.layout, 0, 1, addr(mpipeline.descriptorSets[renderer.swapchain.currentInFlight].vk), 0, nil) + mpipeline.updateUniforms(entity, renderer.swapchain.currentInFlight) + + debug "Scene buffers:" + for (location, buffer) in renderer.scenedata[entity].vertexBuffers.pairs: + echo " ", location, ": ", buffer + echo " Index buffer: ", renderer.scenedata[entity].indexBuffer + + for drawable in renderer.scenedata[entity].drawables: + commandBuffer.draw(drawable, vertexBuffers=renderer.scenedata[entity].vertexBuffers, indexBuffer=renderer.scenedata[entity].indexBuffer) + + if i < renderer.swapchain.renderPass.subpasses.len - 1: + commandBuffer.vkCmdNextSubpass(VK_SUBPASS_CONTENTS_INLINE) + + commandBuffer.endRenderCommands() + + return renderer.swapchain.swap() + +func framesRendered*(renderer: Renderer): uint64 = + renderer.swapchain.framesRendered + +proc destroy*(renderer: var Renderer) = + for data in renderer.scenedata.mvalues: + for buffer in data.vertexBuffers.mvalues: + buffer.destroy() + if data.indexBuffer.vk.valid: + data.indexBuffer.destroy() + for renderpass in renderer.renderPasses.mitems: + renderpass.destroy() + renderer.swapchain.destroy() diff -r 008592db0442 -r b434feaf2b67 src/semicongine/scene.nim --- a/src/semicongine/scene.nim Wed Apr 12 01:20:53 2023 +0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -import std/tables -import std/strformat - -import ./vulkan/api -import ./vulkan/buffer -import ./vulkan/device -import ./vulkan/drawable - -import ./gpu_data -import ./entity -import ./mesh - -type - Scene* = object - name*: string - root*: Entity - drawables*: seq[Drawable] - vertexBuffers*: Table[MemoryLocation, Buffer] - indexBuffer*: Buffer - -proc setupDrawableBuffers*(scene: var Scene, device: Device, inputs: seq[ShaderAttribute]) = - assert scene.drawables.len == 0 - var allMeshes: seq[Mesh] - for mesh in allComponentsOfType[Mesh](scene.root): - allMeshes.add mesh - for inputAttr in inputs: - assert mesh.hasDataFor(inputAttr.name), &"{mesh} missing data for {inputAttr}" - - var indicesBufferSize = 0'u64 - for mesh in allMeshes: - if mesh.indexType != None: - let indexAlignment = case mesh.indexType - of None: 0'u64 - of Tiny: 1'u64 - of Small: 2'u64 - of Big: 4'u64 - # index value alignment required by Vulkan - if indicesBufferSize mod indexAlignment != 0: - indicesBufferSize += indexAlignment - (indicesBufferSize mod indexAlignment) - indicesBufferSize += mesh.indexDataSize - if indicesBufferSize > 0: - scene.indexBuffer = device.createBuffer( - size=indicesBufferSize, - usage=[VK_BUFFER_USAGE_INDEX_BUFFER_BIT], - useVRAM=true, - mappable=false, - ) - - # one vertex data buffer per memory location - var perLocationOffsets: Table[MemoryLocation, uint64] - for location, attributes in inputs.groupByMemoryLocation().pairs: - # setup one buffer per attribute-location-type - var bufferSize = 0'u64 - for mesh in allMeshes: - for attribute in attributes: - bufferSize += mesh.dataSize(attribute.name) - if bufferSize > 0: - scene.vertexBuffers[location] = device.createBuffer( - size=bufferSize, - usage=[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT], - useVRAM=location in [VRAM, VRAMVisible], - mappable=location in [VRAMVisible, RAM], - ) - perLocationOffsets[location] = 0 - - var indexBufferOffset = 0'u64 - for mesh in allMeshes: - var offsets: Table[MemoryLocation, seq[uint64]] - for location, attributes in inputs.groupByMemoryLocation().pairs: - for attribute in attributes: - if not (location in offsets): - offsets[location] = @[] - offsets[location].add perLocationOffsets[location] - var (pdata, size) = mesh.getRawData(attribute.name) - scene.vertexBuffers[location].setData(pdata, size, perLocationOffsets[location]) - perLocationOffsets[location] += size - - let indexed = mesh.indexType != None - var drawable = Drawable( - elementCount: if indexed: mesh.indicesCount else: mesh.vertexCount, - bufferOffsets: offsets, - instanceCount: mesh.instanceCount, - indexed: indexed, - ) - if indexed: - let indexAlignment = case mesh.indexType - of None: 0'u64 - of Tiny: 1'u64 - of Small: 2'u64 - of Big: 4'u64 - # index value alignment required by Vulkan - if indexBufferOffset mod indexAlignment != 0: - indexBufferOffset += indexAlignment - (indexBufferOffset mod indexAlignment) - drawable.indexBufferOffset = indexBufferOffset - drawable.indexType = mesh.indexType - var (pdata, size) = mesh.getRawIndexData() - scene.indexBuffer.setData(pdata, size, indexBufferOffset) - indexBufferOffset += size - scene.drawables.add drawable - -proc destroy*(scene: var Scene) = - for buffer in scene.vertexBuffers.mvalues: - buffer.destroy() - if scene.indexBuffer.vk.valid: - scene.indexBuffer.destroy - diff -r 008592db0442 -r b434feaf2b67 src/semicongine/vulkan/pipeline.nim --- a/src/semicongine/vulkan/pipeline.nim Wed Apr 12 01:20:53 2023 +0700 +++ b/src/semicongine/vulkan/pipeline.nim Mon Apr 17 18:02:19 2023 +0700 @@ -54,9 +54,13 @@ pipeline.uniformBuffers.add buffer pipeline.descriptorSets[i].setDescriptorSet(buffer) -proc createPipeline*(device: Device, renderPass: VkRenderPass, vertexShader: Shader, fragmentShader: Shader, inFlightFrames: int, subpass = 0'u32): Pipeline = +proc createPipeline*(device: Device, renderPass: VkRenderPass, vertexCode: ShaderCode, fragmentCode: ShaderCode, inFlightFrames: int, subpass = 0'u32): Pipeline = assert renderPass.valid assert device.vk.valid + + var + vertexShader = device.createShaderModule(vertexCode) + fragmentShader = device.createShaderModule(fragmentCode) assert vertexShader.stage == VK_SHADER_STAGE_VERTEX_BIT assert fragmentShader.stage == VK_SHADER_STAGE_FRAGMENT_BIT assert vertexShader.outputs == fragmentShader.inputs @@ -210,6 +214,9 @@ if pipeline.descriptorPool.vk.valid: pipeline.descriptorPool.destroy() + + for shader in pipeline.shaders.mitems: + shader.destroy() pipeline.descriptorSetLayout.destroy() pipeline.device.vk.vkDestroyPipelineLayout(pipeline.layout, nil) pipeline.device.vk.vkDestroyPipeline(pipeline.vk, nil) diff -r 008592db0442 -r b434feaf2b67 src/semicongine/vulkan/renderpass.nim --- a/src/semicongine/vulkan/renderpass.nim Wed Apr 12 01:20:53 2023 +0700 +++ b/src/semicongine/vulkan/renderpass.nim Mon Apr 17 18:02:19 2023 +0700 @@ -1,5 +1,4 @@ import std/options -import std/tables import std/logging import ./api @@ -7,13 +6,9 @@ import ./device import ./pipeline import ./shader -import ./drawable -import ./buffer import ./framebuffer import ../math -import ../entity -import ../gpu_data type Subpass* = object @@ -70,7 +65,7 @@ result.subpasses = pSubpasses checkVkResult device.vk.vkCreateRenderPass(addr(createInfo), nil, addr(result.vk)) -proc simpleForwardRenderPass*(device: Device, format: VkFormat, vertexShader: Shader, fragmentShader: Shader, inFlightFrames: int, clearColor=Vec4f([0.8'f32, 0.8'f32, 0.8'f32, 1'f32])): RenderPass = +proc simpleForwardRenderPass*(device: Device, format: VkFormat, vertexCode: ShaderCode, fragmentCode: ShaderCode, inFlightFrames: int, clearColor=Vec4f([0.8'f32, 0.8'f32, 0.8'f32, 1'f32])): RenderPass = assert device.vk.valid var attachments = @[VkAttachmentDescription( @@ -100,7 +95,7 @@ dstAccessMask: toBits [VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT], )] result = device.createRenderPass(attachments=attachments, subpasses=subpasses, dependencies=dependencies) - result.subpasses[0].pipelines.add device.createPipeline(result.vk, vertexShader, fragmentShader, inFlightFrames, 0) + result.subpasses[0].pipelines.add device.createPipeline(result.vk, vertexCode, fragmentCode, inFlightFrames, 0) proc beginRenderCommands*(commandBuffer: VkCommandBuffer, renderpass: RenderPass, framebuffer: Framebuffer) = assert commandBuffer.valid @@ -151,36 +146,6 @@ commandBuffer.vkCmdEndRenderPass() checkVkResult commandBuffer.vkEndCommandBuffer() -proc draw*( - commandBuffer: VkCommandBuffer, - renderPass: var RenderPass, - framebuffer: Framebuffer, - rootEntity: Entity, - drawables: seq[Drawable], - vertexBuffers: Table[MemoryLocation, Buffer], - indexBuffer: Buffer, - currentInFlight: int -) = - commandBuffer.beginRenderCommands(renderpass, framebuffer) - for i in 0 ..< renderpass.subpasses.len: - let subpass = renderpass.subpasses[i] - for pipeline in subpass.pipelines: - var mpipeline = pipeline - commandBuffer.vkCmdBindPipeline(subpass.pipelineBindPoint, mpipeline.vk) - commandBuffer.vkCmdBindDescriptorSets(subpass.pipelineBindPoint, mpipeline.layout, 0, 1, addr(mpipeline.descriptorSets[currentInFlight].vk), 0, nil) - mpipeline.updateUniforms(rootEntity, currentInFlight) - - debug "Scene buffers:" - for (location, buffer) in vertexBuffers.pairs: - echo " ", location, ": ", buffer - echo " Index buffer: ", indexBuffer - - for drawable in drawables: - commandBuffer.draw(drawable, vertexBuffers=vertexBuffers, indexBuffer=indexBuffer) - - if i < renderpass.subpasses.len - 1: - commandBuffer.vkCmdNextSubpass(VK_SUBPASS_CONTENTS_INLINE) - commandBuffer.endRenderCommands() proc destroy*(renderPass: var RenderPass) = assert renderPass.device.vk.valid diff -r 008592db0442 -r b434feaf2b67 src/semicongine/vulkan/shader.nim --- a/src/semicongine/vulkan/shader.nim Wed Apr 12 01:20:53 2023 +0700 +++ b/src/semicongine/vulkan/shader.nim Mon Apr 17 18:02:19 2023 +0700 @@ -20,7 +20,7 @@ addHandler(logger) type - ShaderCode = object + ShaderCode* = object # compiled shader code with some meta data stage: VkShaderStageFlagBits entrypoint: string binary: seq[uint32] diff -r 008592db0442 -r b434feaf2b67 src/semicongine/vulkan/swapchain.nim --- a/src/semicongine/vulkan/swapchain.nim Wed Apr 12 01:20:53 2023 +0700 +++ b/src/semicongine/vulkan/swapchain.nim Mon Apr 17 18:02:19 2023 +0700 @@ -11,7 +11,6 @@ import ./commandbuffer import ./syncing -import ../scene import ../math type @@ -25,7 +24,8 @@ imageviews*: seq[ImageView] framebuffers*: seq[Framebuffer] currentInFlight*: int - framesRendered*: int + currentFramebufferIndex: uint32 + framesRendered*: uint64 queueFinishedFence: seq[Fence] imageAvailableSemaphore*: seq[Semaphore] renderFinishedSemaphore*: seq[Semaphore] @@ -103,8 +103,10 @@ return (swapchain, createResult) +proc currentFramebuffer*(swapchain: Swapchain): Framebuffer = + swapchain.framebuffers[swapchain.currentFramebufferIndex] -proc drawScene*(swapchain: var Swapchain, scene: Scene): bool = +proc nextFrame*(swapchain: var Swapchain): VkCommandBuffer = assert swapchain.device.vk.valid assert swapchain.vk.valid assert swapchain.device.firstGraphicsQueue().isSome @@ -113,24 +115,23 @@ swapchain.currentInFlight = (swapchain.currentInFlight + 1) mod swapchain.inFlightFrames swapchain.queueFinishedFence[swapchain.currentInFlight].wait() - var currentFramebufferIndex: uint32 - let nextImageResult = swapchain.device.vk.vkAcquireNextImageKHR( swapchain.vk, high(uint64), swapchain.imageAvailableSemaphore[swapchain.currentInFlight].vk, VkFence(0), - addr(currentFramebufferIndex) + addr(swapchain.currentFramebufferIndex) ) if not (nextImageResult in [VK_SUCCESS, VK_TIMEOUT, VK_NOT_READY, VK_SUBOPTIMAL_KHR]): - return false + return swapchain.queueFinishedFence[swapchain.currentInFlight].reset() - var commandBuffer = swapchain.commandBufferPool.buffers[swapchain.currentInFlight] - commandBuffer.draw(renderPass=swapchain.renderPass, framebuffer=swapchain.framebuffers[currentFramebufferIndex], rootEntity=scene.root, drawables=scene.drawables, vertexBuffers=scene.vertexBuffers, indexBuffer=scene.indexBuffer, currentInFlight=swapchain.currentInFlight) + return swapchain.commandBufferPool.buffers[swapchain.currentInFlight] +proc swap*(swapchain: var Swapchain): bool = var + commandBuffer = swapchain.commandBufferPool.buffers[swapchain.currentInFlight] waitSemaphores = [swapchain.imageAvailableSemaphore[swapchain.currentInFlight].vk] waitStages = [VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)] submitInfo = VkSubmitInfo( @@ -156,7 +157,7 @@ pWaitSemaphores: addr(swapchain.renderFinishedSemaphore[swapchain.currentInFlight].vk), swapchainCount: 1, pSwapchains: addr(swapchain.vk), - pImageIndices: addr(currentFramebufferIndex), + pImageIndices: addr(swapchain.currentFramebufferIndex), pResults: nil, ) let presentResult = vkQueuePresentKHR(swapchain.device.firstPresentationQueue().get().vk, addr(presentInfo)) @@ -164,7 +165,6 @@ return false inc swapchain.framesRendered - return true diff -r 008592db0442 -r b434feaf2b67 tests/test_vulkan_wrapper.nim --- a/tests/test_vulkan_wrapper.nim Wed Apr 12 01:20:53 2023 +0700 +++ b/tests/test_vulkan_wrapper.nim Mon Apr 17 18:02:19 2023 +0700 @@ -33,44 +33,43 @@ for format in device.getSurfaceFormats(): echo " " & $format -proc scene_different_mesh_types(): Scene = - result = Scene( - name: "main", - root: newEntity("root", - newEntity("triangle1", newMesh( - positions=[newVec3f(0.0, -0.5), newVec3f(0.5, 0.5), newVec3f(-0.5, 0.5)], - colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)], - )), - newEntity("triangle1b", newMesh( - positions=[newVec3f(0.0, -0.4), newVec3f(0.4, 0.4), newVec3f(-0.4, 0.5)], - colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)], - )), - newEntity("triangle2a", newMesh( - positions=[newVec3f(0.0, 0.5), newVec3f(0.5, -0.5), newVec3f(-0.5, -0.5)], - colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)], - indices=[[0'u16, 2'u16, 1'u16]] - )), - newEntity("triangle2b", newMesh( - positions=[newVec3f(0.0, 0.4), newVec3f(0.4, -0.4), newVec3f(-0.4, -0.4)], - colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)], - indices=[[0'u16, 2'u16, 1'u16]] - )), - newEntity("triangle3a", newMesh( - positions=[newVec3f(0.4, 0.5), newVec3f(0.9, -0.3), newVec3f(0.0, -0.3)], - colors=[newVec3f(1.0, 1.0, 0.0), newVec3f(1.0, 1.0, 0.0), newVec3f(1.0, 1.0, 0.0)], - indices=[[0'u32, 2'u32, 1'u32]], - autoResize=false - )), - newEntity("triangle3b", newMesh( - positions=[newVec3f(0.4, 0.5), newVec3f(0.9, -0.3), newVec3f(0.0, -0.3)], - colors=[newVec3f(1.0, 1.0, 0.0), newVec3f(1.0, 1.0, 0.0), newVec3f(1.0, 1.0, 0.0)], - indices=[[0'u32, 2'u32, 1'u32]], - autoResize=false - )), - ) +proc scene_different_mesh_types(): Entity = + result = newEntity("root", + newEntity("triangle1", newMesh( + positions=[newVec3f(0.0, -0.5), newVec3f(0.5, 0.5), newVec3f(-0.5, 0.5)], + colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)], + )), + newEntity("triangle1b", newMesh( + positions=[newVec3f(0.0, -0.4), newVec3f(0.4, 0.4), newVec3f(-0.4, 0.5)], + colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)], + )), + newEntity("triangle2a", newMesh( + positions=[newVec3f(0.0, 0.5), newVec3f(0.5, -0.5), newVec3f(-0.5, -0.5)], + colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)], + indices=[[0'u16, 2'u16, 1'u16]] + )), + newEntity("triangle2b", newMesh( + positions=[newVec3f(0.0, 0.4), newVec3f(0.4, -0.4), newVec3f(-0.4, -0.4)], + colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)], + indices=[[0'u16, 2'u16, 1'u16]] + )), + newEntity("triangle3a", newMesh( + positions=[newVec3f(0.4, 0.5), newVec3f(0.9, -0.3), newVec3f(0.0, -0.3)], + colors=[newVec3f(1.0, 1.0, 0.0), newVec3f(1.0, 1.0, 0.0), newVec3f(1.0, 1.0, 0.0)], + indices=[[0'u32, 2'u32, 1'u32]], + autoResize=false + )), + newEntity("triangle3b", newMesh( + positions=[newVec3f(0.4, 0.5), newVec3f(0.9, -0.3), newVec3f(0.0, -0.3)], + colors=[newVec3f(1.0, 1.0, 0.0), newVec3f(1.0, 1.0, 0.0), newVec3f(1.0, 1.0, 0.0)], + indices=[[0'u32, 2'u32, 1'u32]], + autoResize=false + )), ) + for mesh in allComponentsOfType[Mesh](result): + mesh.setInstanceData("translate", @[newVec3f()]) -proc scene_simple(): Scene = +proc scene_simple(): Entity = var mymesh1 = newMesh( positions=[newVec3f(0.0, -0.3), newVec3f(0.3, 0.3), newVec3f(-0.3, 0.3)], colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)], @@ -95,22 +94,16 @@ mymesh2.setInstanceData("translate", @[newVec3f(0.0, 0.3)]) mymesh3.setInstanceData("translate", @[newVec3f(-0.3, 0.0)]) mymesh4.setInstanceData("translate", @[newVec3f(0.0, -0.3), newVec3f(0.0, 0.5)]) - result = Scene( - name: "main", - root: newEntity("root", newEntity("triangle", mymesh4, mymesh3, mymesh2, mymesh1)) - ) + result = newEntity("root", newEntity("triangle", mymesh4, mymesh3, mymesh2, mymesh1)) -proc scene_primitives(): Scene = +proc scene_primitives(): Entity = var r = rect(color="ff0000") var t = tri(color="0000ff") var c = circle(color="00ff00") setInstanceData[Vec3f](r, "translate", @[newVec3f(0.5, -0.3)]) setInstanceData[Vec3f](t, "translate", @[newVec3f(0.3, 0.3)]) setInstanceData[Vec3f](c, "translate", @[newVec3f(-0.3, 0.1)]) - result = Scene( - name: "main", - root: newEntity("root", t, r, c) - ) + result = newEntity("root", t, r, c) when isMainModule: var engine = initEngine("Test") @@ -140,42 +133,29 @@ main="color = vec4(outcolor, 1);" ) var - vertexshader = engine.gpuDevice.createShaderModule(vertexCode) - fragmentshader = engine.gpuDevice.createShaderModule(fragmentCode) surfaceFormat = engine.gpuDevice.physicalDevice.getSurfaceFormats().filterSurfaceFormat() - renderPass = engine.gpuDevice.simpleForwardRenderPass(surfaceFormat.format, vertexshader, fragmentshader, 2) - (swapchain, res) = engine.gpuDevice.createSwapchain(renderPass, surfaceFormat, engine.gpuDevice.firstGraphicsQueue().get().family, 2) - if res != VK_SUCCESS: - raise newException(Exception, "Unable to create swapchain") + renderPass = engine.gpuDevice.simpleForwardRenderPass(surfaceFormat.format, vertexCode, fragmentCode, 2) + renderer = engine.gpuDevice.initRenderer([renderPass]) # INIT SCENE - # var thescene = scene_simple() - # var thescene = scene_different_mesh_types() - var thescene = scene_primitives() + var scenes = [scene_simple(), scene_different_mesh_types(), scene_primitives()] var time = initShaderGlobal("time", 0.0'f32) - thescene.root.components.add time - thescene.setupDrawableBuffers(engine.gpuDevice, vertexInput) + for scene in scenes.mitems: + scene.components.add time + renderer.setupDrawableBuffers(scene, vertexInput) # MAINLOOP echo "Setup successfull, start rendering" - for i in 0 ..< 10000: - setValue[float32](time.value, get[float32](time.value) + 0.0005) - discard swapchain.drawScene(thescene) - echo "Rendered ", swapchain.framesRendered, " frames" + for i in 0 ..< 3: + for scene in scenes: + for i in 0 ..< 1000: + setValue[float32](time.value, get[float32](time.value) + 0.0005) + discard renderer.render(scene) + echo "Rendered ", renderer.framesRendered, " frames" # cleanup echo "Start cleanup" checkVkResult engine.gpuDevice.vk.vkDeviceWaitIdle() - - # destroy scene - thescene.destroy() - - # destroy renderer - vertexshader.destroy() - fragmentshader.destroy() - renderPass.destroy() - swapchain.destroy() - - # destroy engine + renderer.destroy() engine.destroy()