# HG changeset patch # User Sam # Date 1681237253 -25200 # Node ID 5871acc2977ecf67fb8c938bd8ed4563c6b5ab3c # Parent 81a8e62215db579462ca243ab8299b7ccce25297 did: big refactoring diff -r 81a8e62215db -r 5871acc2977e src/semicongine.nim --- a/src/semicongine.nim Tue Apr 11 01:06:37 2023 +0700 +++ b/src/semicongine.nim Wed Apr 12 01:20:53 2023 +0700 @@ -1,5 +1,6 @@ import semicongine/color import semicongine/config +import semicongine/engine import semicongine/entity import semicongine/events import semicongine/gpu_data @@ -11,6 +12,7 @@ export color export config +export engine export entity export events export gpu_data diff -r 81a8e62215db -r 5871acc2977e src/semicongine/config.nim --- a/src/semicongine/config.nim Tue Apr 11 01:06:37 2023 +0700 +++ b/src/semicongine/config.nim Wed Apr 12 01:20:53 2023 +0700 @@ -17,7 +17,7 @@ # root of where config files will be searched # must be relative (to the directory of the binary) -const DEBUG = not defined(release) +const DEBUG* = not defined(release) const CONFIGROOT {.strdefine.}: string = "." assert not isAbsolute(CONFIGROOT) diff -r 81a8e62215db -r 5871acc2977e src/semicongine/engine.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/engine.nim Wed Apr 12 01:20:53 2023 +0700 @@ -0,0 +1,49 @@ +import ./platform/window + +import ./vulkan/api +import ./vulkan/instance +import ./vulkan/device +import ./vulkan/physicaldevice + +import ./config + +type + Engine* = object + device: Device + debugger: Debugger + instance: Instance + window: NativeWindow + +func gpuDevice*(engine: Engine): Device = + engine.device + +proc initEngine*(applicationName: string, debug=DEBUG): Engine = + result.window = createWindow(applicationName) + var + instanceExtensions: seq[string] + enabledLayers: seq[string] + + if debug: + instanceExtensions.add "VK_EXT_debug_utils" + enabledLayers.add @["VK_LAYER_KHRONOS_validation", "VK_LAYER_MESA_overlay"] + result.instance = result.window.createInstance( + vulkanVersion=VK_MAKE_API_VERSION(0, 1, 3, 0), + instanceExtensions=instanceExtensions, + layers=enabledLayers, + ) + if debug: + result.debugger = result.instance.createDebugMessenger() + # create devices + let selectedPhysicalDevice = result.instance.getPhysicalDevices().filterBestGraphics() + result.device = result.instance.createDevice( + selectedPhysicalDevice, + enabledLayers = @[], + enabledExtensions = @[], + selectedPhysicalDevice.filterForGraphicsPresentationQueues() + ) + +proc destroy*(engine: var Engine) = + engine.device.destroy() + engine.debugger.destroy() + engine.instance.destroy() + engine.window.destroy() diff -r 81a8e62215db -r 5871acc2977e src/semicongine/entity.nim --- a/src/semicongine/entity.nim Tue Apr 11 01:06:37 2023 +0700 +++ b/src/semicongine/entity.nim Wed Apr 12 01:20:53 2023 +0700 @@ -2,6 +2,7 @@ import std/typetraits import ./math/matrix +import ./gpu_data type Component* = ref object of RootObj @@ -14,6 +15,18 @@ children*: seq[Entity] components*: seq[Component] + ShaderGlobal* = ref object of Component + name*: string + value*: DataValue + +func `$`*(global: ShaderGlobal): string = + &"ShaderGlobal(name: {global.name}, {global.value})" + +func initShaderGlobal*[T](name: string, data: T): ShaderGlobal = + var value = DataValue(thetype: getDataType[T]()) + value.setValue(data) + ShaderGlobal(name: name, value: value) + method `$`*(entity: Entity): string {.base.} = entity.name method `$`*(component: Component): string {.base.} = diff -r 81a8e62215db -r 5871acc2977e src/semicongine/mesh.nim --- a/src/semicongine/mesh.nim Tue Apr 11 01:06:37 2023 +0700 +++ b/src/semicongine/mesh.nim Wed Apr 12 01:20:53 2023 +0700 @@ -169,7 +169,6 @@ var pos = @[newVec3f(0, 0), newVec3f(0, half_h)] col = @[c, c] - index: seq[array[3, uint16]] = @[] for i in 0'u16 .. nSegments: pos.add newVec3f(cos(float32(i) * step) * half_w, sin(float32(i) * step) * half_h) col.add c diff -r 81a8e62215db -r 5871acc2977e src/semicongine/renderer.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/renderer.nim Wed Apr 12 01:20:53 2023 +0700 @@ -0,0 +1,27 @@ +import std/options + +import ./vulkan/api +import ./vulkan/device +import ./vulkan/physicaldevice +import ./vulkan/renderpass +import ./vulkan/swapchain + +type + Renderer = object + surfaceFormat: VkSurfaceFormatKHR + renderPasses: seq[RenderPass] + swapchain: Swapchain + + +proc initRenderer(device: Device, renderPasses: seq[RenderPass]): Renderer = + assert device.vk.valid + assert renderPasses.len > 0 + for renderPass in renderPasses: + assert renderPass.vk.valid + + result.renderPasses = renderPasses + result.surfaceFormat = device.physicalDevice.getSurfaceFormats().filterSurfaceFormat() + let (swapchain, res) = device.createSwapchain(renderPasses[^1], result.surfaceFormat, device.firstGraphicsQueue().get().family, 2) + if res != VK_SUCCESS: + raise newException(Exception, "Unable to create swapchain") + result.swapchain = swapchain diff -r 81a8e62215db -r 5871acc2977e src/semicongine/scene.nim --- a/src/semicongine/scene.nim Tue Apr 11 01:06:37 2023 +0700 +++ b/src/semicongine/scene.nim Wed Apr 12 01:20:53 2023 +0700 @@ -3,71 +3,27 @@ import ./vulkan/api import ./vulkan/buffer -import ./vulkan/pipeline -import ./vulkan/renderpass +import ./vulkan/device +import ./vulkan/drawable + import ./gpu_data import ./entity import ./mesh type - Drawable* = object - elementCount*: uint32 # number of vertices or indices - bufferOffsets*: Table[MemoryLocation, seq[uint64]] # list of buffers and list of offset for each attribute in that buffer - instanceCount*: uint32 # number of instance - case indexed*: bool - of true: - indexType*: VkIndexType - indexBufferOffset*: uint64 - of false: - discard - - ShaderGlobal* = ref object of Component - name*: string - value*: DataValue - Scene* = object name*: string root*: Entity - drawables: Table[VkPipeline, seq[Drawable]] + drawables*: seq[Drawable] vertexBuffers*: Table[MemoryLocation, Buffer] indexBuffer*: Buffer -func `$`*(drawable: Drawable): string = - if drawable.indexed: - &"Drawable(elementCount: {drawable.elementCount}, instanceCount: {drawable.instanceCount}, bufferOffsets: {drawable.bufferOffsets}, indexType: {drawable.indexType}, indexBufferOffset: {drawable.indexBufferOffset})" - else: - &"Drawable(elementCount: {drawable.elementCount}, instanceCount: {drawable.instanceCount}, bufferOffsets: {drawable.bufferOffsets})" - -func `$`*(global: ShaderGlobal): string = - &"ShaderGlobal(name: {global.name}, {global.value})" - -func initShaderGlobal*[T](name: string, data: T): ShaderGlobal = - var value = DataValue(thetype: getDataType[T]()) - value.setValue(data) - ShaderGlobal(name: name, value: value) - -proc destroy*(scene: var Scene, pipeline: VkPipeline) = - for buffer in scene.vertexBuffers.mvalues: - buffer.destroy() - if scene.indexBuffer.vk.valid: - scene.indexBuffer.destroy - -proc destroy*(scene: var Scene) = - for pipeline in scene.drawables.keys: - scene.destroy(pipeline) - -proc setupDrawables(scene: var Scene, pipeline: Pipeline) = - assert pipeline.device.vk.valid - - if pipeline.vk in scene.drawables: - for drawable in scene.drawables[pipeline.vk].mitems: - scene.destroy(pipeline.vk) - scene.drawables[pipeline.vk] = @[] - +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 pipeline.inputs: + for inputAttr in inputs: assert mesh.hasDataFor(inputAttr.name), &"{mesh} missing data for {inputAttr}" var indicesBufferSize = 0'u64 @@ -83,7 +39,7 @@ indicesBufferSize += indexAlignment - (indicesBufferSize mod indexAlignment) indicesBufferSize += mesh.indexDataSize if indicesBufferSize > 0: - scene.indexBuffer = pipeline.device.createBuffer( + scene.indexBuffer = device.createBuffer( size=indicesBufferSize, usage=[VK_BUFFER_USAGE_INDEX_BUFFER_BIT], useVRAM=true, @@ -92,14 +48,14 @@ # one vertex data buffer per memory location var perLocationOffsets: Table[MemoryLocation, uint64] - for location, attributes in pipeline.inputs.groupByMemoryLocation().pairs: + 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] = pipeline.device.createBuffer( + scene.vertexBuffers[location] = device.createBuffer( size=bufferSize, usage=[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT], useVRAM=location in [VRAM, VRAMVisible], @@ -110,7 +66,7 @@ var indexBufferOffset = 0'u64 for mesh in allMeshes: var offsets: Table[MemoryLocation, seq[uint64]] - for location, attributes in pipeline.inputs.groupByMemoryLocation().pairs: + for location, attributes in inputs.groupByMemoryLocation().pairs: for attribute in attributes: if not (location in offsets): offsets[location] = @[] @@ -140,12 +96,11 @@ var (pdata, size) = mesh.getRawIndexData() scene.indexBuffer.setData(pdata, size, indexBufferOffset) indexBufferOffset += size - scene.drawables[pipeline.vk].add drawable + scene.drawables.add drawable -proc setupDrawables*(scene: var Scene, renderPass: RenderPass) = - for subpass in renderPass.subpasses: - for pipeline in subpass.pipelines: - scene.setupDrawables(pipeline) +proc destroy*(scene: var Scene) = + for buffer in scene.vertexBuffers.mvalues: + buffer.destroy() + if scene.indexBuffer.vk.valid: + scene.indexBuffer.destroy -func getDrawables*(scene: Scene, pipeline: Pipeline): seq[Drawable] = - scene.drawables.getOrDefault(pipeline.vk, @[]) diff -r 81a8e62215db -r 5871acc2977e src/semicongine/vulkan/drawable.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/vulkan/drawable.nim Wed Apr 12 01:20:53 2023 +0700 @@ -0,0 +1,61 @@ +import std/tables +import std/strformat +import std/logging + +import ./api +import ./utils +import ./buffer + +import ../gpu_data + +type + Drawable* = object + elementCount*: uint32 # number of vertices or indices + bufferOffsets*: Table[MemoryLocation, seq[uint64]] # list of buffers and list of offset for each attribute in that buffer + instanceCount*: uint32 # number of instance + case indexed*: bool + of true: + indexType*: VkIndexType + indexBufferOffset*: uint64 + of false: + discard + +func `$`*(drawable: Drawable): string = + if drawable.indexed: + &"Drawable(elementCount: {drawable.elementCount}, instanceCount: {drawable.instanceCount}, bufferOffsets: {drawable.bufferOffsets}, indexType: {drawable.indexType}, indexBufferOffset: {drawable.indexBufferOffset})" + else: + &"Drawable(elementCount: {drawable.elementCount}, instanceCount: {drawable.instanceCount}, bufferOffsets: {drawable.bufferOffsets})" + +proc draw*(commandBuffer: VkCommandBuffer, drawable: Drawable, vertexBuffers: Table[MemoryLocation, Buffer], indexBuffer: BUffer) = + debug "Draw ", drawable + + var buffers: seq[VkBuffer] + var offsets: seq[VkDeviceSize] + + for (location, bufferOffsets) in drawable.bufferOffsets.pairs: + for offset in bufferOffsets: + buffers.add vertexBuffers[location].vk + offsets.add VkDeviceSize(offset) + + commandBuffer.vkCmdBindVertexBuffers( + firstBinding=0'u32, + bindingCount=uint32(buffers.len), + pBuffers=buffers.toCPointer(), + pOffsets=offsets.toCPointer() + ) + if drawable.indexed: + commandBuffer.vkCmdBindIndexBuffer(indexBuffer.vk, VkDeviceSize(drawable.indexBufferOffset), drawable.indexType) + commandBuffer.vkCmdDrawIndexed( + indexCount=drawable.elementCount, + instanceCount=drawable.instanceCount, + firstIndex=0, + vertexOffset=0, + firstInstance=0 + ) + else: + commandBuffer.vkCmdDraw( + vertexCount=drawable.elementCount, + instanceCount=drawable.instanceCount, + firstVertex=0, + firstInstance=0 + ) diff -r 81a8e62215db -r 5871acc2977e src/semicongine/vulkan/framebuffer.nim --- a/src/semicongine/vulkan/framebuffer.nim Tue Apr 11 01:06:37 2023 +0700 +++ b/src/semicongine/vulkan/framebuffer.nim Wed Apr 12 01:20:53 2023 +0700 @@ -2,7 +2,6 @@ import ./device import ./utils import ./image -import ./renderpass import ../math @@ -12,9 +11,9 @@ vk*: VkFramebuffer dimension*: Vec2I -proc createFramebuffer*(device: Device, renderPass: RenderPass, attachments: openArray[ImageView], dimension: Vec2I): Framebuffer = +proc createFramebuffer*(device: Device, renderpass: VkRenderPass, attachments: openArray[ImageView], dimension: Vec2I): Framebuffer = assert device.vk.valid - assert renderpass.vk.valid + assert renderpass.valid result.device = device result.dimension = dimension @@ -25,7 +24,7 @@ theattachments.add a.vk var framebufferInfo = VkFramebufferCreateInfo( sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - renderPass: renderPass.vk, + renderPass: renderpass, attachmentCount: uint32(theattachments.len), pAttachments: theattachments.toCPointer, width: dimension[0], diff -r 81a8e62215db -r 5871acc2977e src/semicongine/vulkan/pipeline.nim --- a/src/semicongine/vulkan/pipeline.nim Tue Apr 11 01:06:37 2023 +0700 +++ b/src/semicongine/vulkan/pipeline.nim Wed Apr 12 01:20:53 2023 +0700 @@ -5,8 +5,10 @@ import ./device import ./descriptor import ./shader +import ./buffer import ./utils +import ../entity import ../gpu_data type @@ -18,6 +20,7 @@ descriptorSetLayout*: DescriptorSetLayout descriptorPool*: DescriptorPool descriptorSets*: seq[DescriptorSet] + uniformBuffers: seq[Buffer] func inputs*(pipeline: Pipeline): seq[ShaderAttribute] = for shader in pipeline.shaders: @@ -34,6 +37,23 @@ uniformList[attribute.name] = attribute result = uniformList.values.toSeq +proc setupUniforms(pipeline: var Pipeline, inFlightFrames: int) = + assert pipeline.vk.valid + + var uniformBufferSize = 0'u64 + for uniform in pipeline.uniforms: + uniformBufferSize += uniform.thetype.size + + for i in 0 ..< inFlightFrames: + var buffer = pipeline.device.createBuffer( + size=uniformBufferSize, + usage=[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT], + useVRAM=true, + mappable=true, + ) + 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 = assert renderPass.valid assert device.vk.valid @@ -45,7 +65,6 @@ result.device = device result.shaders = @[vertexShader, fragmentShader] - # TODO: correct descriptors over all shaders var descriptors = @[ Descriptor( thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, @@ -161,12 +180,33 @@ result.descriptorPool = result.device.createDescriptorSetPool(@[(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1'u32)]) result.descriptorSets = result.descriptorPool.allocateDescriptorSet(result.descriptorSetLayout, inFlightFrames) discard result.uniforms # just for assertion + result.setupUniforms(inFlightFrames=inFlightFrames) + +proc updateUniforms*(pipeline: Pipeline, rootEntity: Entity, currentInFlight: int) = + assert pipeline.vk.valid + assert pipeline.uniformBuffers[currentInFlight].vk.valid + + var globalsByName: Table[string, DataValue] + for component in allComponentsOfType[ShaderGlobal](rootEntity): + globalsByName[component.name] = component.value + + var offset = 0'u64 + for uniform in pipeline.uniforms: + assert uniform.thetype == globalsByName[uniform.name].thetype + let (pdata, size) = globalsByName[uniform.name].getRawData() + pipeline.uniformBuffers[currentInFlight].setData(pdata, size, offset) + offset += size + proc destroy*(pipeline: var Pipeline) = assert pipeline.device.vk.valid assert pipeline.vk.valid assert pipeline.layout.valid assert pipeline.descriptorSetLayout.vk.valid + + for buffer in pipeline.uniformBuffers.mitems: + assert buffer.vk.valid + buffer.destroy() if pipeline.descriptorPool.vk.valid: pipeline.descriptorPool.destroy() diff -r 81a8e62215db -r 5871acc2977e src/semicongine/vulkan/renderpass.nim --- a/src/semicongine/vulkan/renderpass.nim Tue Apr 11 01:06:37 2023 +0700 +++ b/src/semicongine/vulkan/renderpass.nim Wed Apr 12 01:20:53 2023 +0700 @@ -1,12 +1,19 @@ import std/options +import std/tables +import std/logging import ./api import ./utils import ./device import ./pipeline import ./shader +import ./drawable +import ./buffer +import ./framebuffer import ../math +import ../entity +import ../gpu_data type Subpass* = object @@ -22,7 +29,6 @@ RenderPass* = object vk*: VkRenderPass device*: Device - inFlightFrames*: int subpasses*: seq[Subpass] proc createRenderPass*( @@ -30,7 +36,6 @@ attachments: seq[VkAttachmentDescription], subpasses: seq[Subpass], dependencies: seq[VkSubpassDependency], - inFlightFrames: int, ): RenderPass = assert device.vk.valid var pAttachments = attachments @@ -62,7 +67,6 @@ pDependencies: pDependencies.toCPointer, ) result.device = device - result.inFlightFrames = inFlightFrames result.subpasses = pSubpasses checkVkResult device.vk.vkCreateRenderPass(addr(createInfo), nil, addr(result.vk)) @@ -95,9 +99,89 @@ dstStageMask: toBits [VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT], dstAccessMask: toBits [VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT], )] - result = device.createRenderPass(attachments=attachments, subpasses=subpasses, dependencies=dependencies, inFlightFrames=inFlightFrames) + result = device.createRenderPass(attachments=attachments, subpasses=subpasses, dependencies=dependencies) result.subpasses[0].pipelines.add device.createPipeline(result.vk, vertexShader, fragmentShader, inFlightFrames, 0) +proc beginRenderCommands*(commandBuffer: VkCommandBuffer, renderpass: RenderPass, framebuffer: Framebuffer) = + assert commandBuffer.valid + assert renderpass.vk.valid + assert framebuffer.vk.valid + let + w = framebuffer.dimension.x + h = framebuffer.dimension.y + + var clearColors: seq[VkClearValue] + for subpass in renderpass.subpasses: + clearColors.add(VkClearValue(color: VkClearColorValue(float32: subpass.clearColor))) + var + beginInfo = VkCommandBufferBeginInfo( + sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + pInheritanceInfo: nil, + ) + renderPassInfo = VkRenderPassBeginInfo( + sType: VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + renderPass: renderPass.vk, + framebuffer: framebuffer.vk, + renderArea: VkRect2D( + offset: VkOffset2D(x: 0, y: 0), + extent: VkExtent2D(width: w, height: h), + ), + clearValueCount: uint32(clearColors.len), + pClearValues: clearColors.toCPointer(), + ) + viewport = VkViewport( + x: 0.0, + y: 0.0, + width: (float)w, + height: (float)h, + minDepth: 0.0, + maxDepth: 1.0, + ) + scissor = VkRect2D( + offset: VkOffset2D(x: 0, y: 0), + extent: VkExtent2D(width: w, height: h) + ) + checkVkResult commandBuffer.vkResetCommandBuffer(VkCommandBufferResetFlags(0)) + checkVkResult commandBuffer.vkBeginCommandBuffer(addr(beginInfo)) + commandBuffer.vkCmdBeginRenderPass(addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE) + commandBuffer.vkCmdSetViewport(firstViewport=0, viewportCount=1, addr(viewport)) + commandBuffer.vkCmdSetScissor(firstScissor=0, scissorCount=1, addr(scissor)) + +proc endRenderCommands*(commandBuffer: VkCommandBuffer) = + 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 assert renderPass.vk.valid diff -r 81a8e62215db -r 5871acc2977e src/semicongine/vulkan/shader.nim --- a/src/semicongine/vulkan/shader.nim Tue Apr 11 01:06:37 2023 +0700 +++ b/src/semicongine/vulkan/shader.nim Wed Apr 12 01:20:53 2023 +0700 @@ -91,14 +91,14 @@ outputs: seq[ShaderAttribute]= @[], version=DEFAULT_SHADER_VERSION , entrypoint=DEFAULT_SHADER_ENTRYPOINT , - body: seq[string] + main: seq[string] ): ShaderCode {.compileTime.} = var code = @[&"#version {version}", ""] & (if inputs.len > 0: inputs.glslInput() & @[""] else: @[]) & (if uniforms.len > 0: uniforms.glslUniforms() & @[""] else: @[]) & (if outputs.len > 0: outputs.glslOutput() & @[""] else: @[]) & @[&"void {entrypoint}(){{"] & - body & + main & @[&"}}"] result.inputs = inputs result.uniforms = uniforms @@ -115,9 +115,9 @@ outputs: seq[ShaderAttribute]= @[], version=DEFAULT_SHADER_VERSION , entrypoint=DEFAULT_SHADER_ENTRYPOINT , - body: string + main: string ): ShaderCode {.compileTime.} = - return compileGlslShader(stage, inputs, uniforms, outputs, version, entrypoint, @[body]) + return compileGlslShader(stage, inputs, uniforms, outputs, version, entrypoint, @[main]) proc createShaderModule*( diff -r 81a8e62215db -r 5871acc2977e src/semicongine/vulkan/swapchain.nim --- a/src/semicongine/vulkan/swapchain.nim Tue Apr 11 01:06:37 2023 +0700 +++ b/src/semicongine/vulkan/swapchain.nim Wed Apr 12 01:20:53 2023 +0700 @@ -1,4 +1,3 @@ -import std/tables import std/options import std/logging @@ -7,21 +6,16 @@ import ./device import ./physicaldevice import ./image -import ./buffer import ./renderpass -import ./descriptor import ./framebuffer import ./commandbuffer -import ./pipeline import ./syncing import ../scene -import ../entity -import ../gpu_data import ../math type - Swapchain = object + Swapchain* = object device*: Device vk*: VkSwapchainKHR format*: VkFormat @@ -36,7 +30,7 @@ imageAvailableSemaphore*: seq[Semaphore] renderFinishedSemaphore*: seq[Semaphore] commandBufferPool: CommandBufferPool - uniformBuffers: Table[VkPipeline, seq[Buffer]] + inFlightFrames: int proc createSwapchain*( @@ -45,12 +39,13 @@ surfaceFormat: VkSurfaceFormatKHR, queueFamily: QueueFamily, desiredNumberOfImages=3'u32, - presentationMode: VkPresentModeKHR=VK_PRESENT_MODE_MAILBOX_KHR + presentationMode: VkPresentModeKHR=VK_PRESENT_MODE_MAILBOX_KHR, + inFlightFrames=2 ): (Swapchain, VkResult) = assert device.vk.valid assert device.physicalDevice.vk.valid assert renderPass.vk.valid - assert renderPass.inFlightFrames > 0 + assert inFlightFrames > 0 var capabilities = device.physicalDevice.getSurfaceCapabilities() @@ -85,6 +80,7 @@ format: surfaceFormat.format, dimension: TVec2[uint32]([capabilities.currentExtent.width, capabilities.currentExtent.height]), renderPass: renderPass, + inFlightFrames: inFlightFrames ) createResult = device.vk.vkCreateSwapchainKHR(addr(createInfo), nil, addr(swapchain.vk)) @@ -98,150 +94,15 @@ let image = Image(vk: vkimage, format: surfaceFormat.format, device: device) let imageview = image.createImageView() swapChain.imageviews.add imageview - swapChain.framebuffers.add swapchain.device.createFramebuffer(renderPass, [imageview], swapchain.dimension) - for i in 0 ..< swapchain.renderPass.inFlightFrames: + swapChain.framebuffers.add swapchain.device.createFramebuffer(renderPass.vk, [imageview], swapchain.dimension) + for i in 0 ..< swapchain.inFlightFrames: swapchain.queueFinishedFence.add device.createFence() swapchain.imageAvailableSemaphore.add device.createSemaphore() swapchain.renderFinishedSemaphore.add device.createSemaphore() - swapchain.commandBufferPool = device.createCommandBufferPool(queueFamily, swapchain.renderPass.inFlightFrames) + swapchain.commandBufferPool = device.createCommandBufferPool(queueFamily, swapchain.inFlightFrames) return (swapchain, createResult) -proc setupUniforms(swapChain: var Swapchain, scene: var Scene, pipeline: var Pipeline) = - assert pipeline.vk.valid - assert not (pipeline.vk in swapChain.uniformBuffers) - - swapChain.uniformBuffers[pipeline.vk] = @[] - - var uniformBufferSize = 0'u64 - for uniform in pipeline.uniforms: - uniformBufferSize += uniform.thetype.size - - for i in 0 ..< swapChain.renderPass.inFlightFrames: - var buffer = pipeline.device.createBuffer( - size=uniformBufferSize, - usage=[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT], - useVRAM=true, - mappable=true, - ) - swapChain.uniformBuffers[pipeline.vk].add buffer - pipeline.descriptorSets[i].setDescriptorSet(buffer) - -proc setupUniforms*(swapChain: var Swapchain, scene: var Scene) = - for subpass in swapChain.renderPass.subpasses.mitems: - for pipeline in subpass.pipelines.mitems: - swapChain.setupUniforms(scene, pipeline) - -proc updateUniforms*(swapChain: var Swapchain, scene: Scene, pipeline: Pipeline) = - assert pipeline.vk.valid - assert swapChain.uniformBuffers[pipeline.vk][swapChain.currentInFlight].vk.valid - - var globalsByName: Table[string, DataValue] - for component in allComponentsOfType[ShaderGlobal](scene.root): - globalsByName[component.name] = component.value - - var offset = 0'u64 - for uniform in pipeline.uniforms: - assert uniform.thetype == globalsByName[uniform.name].thetype - let (pdata, size) = globalsByName[uniform.name].getRawData() - swapChain.uniformBuffers[pipeline.vk][swapChain.currentInFlight].setData(pdata, size, offset) - offset += size - - -proc beginRenderCommands*(commandBuffer: VkCommandBuffer, renderpass: RenderPass, framebuffer: Framebuffer) = - assert commandBuffer.valid - assert renderpass.vk.valid - assert framebuffer.vk.valid - let - w = framebuffer.dimension.x - h = framebuffer.dimension.y - - var clearColors: seq[VkClearValue] - for subpass in renderpass.subpasses: - clearColors.add(VkClearValue(color: VkClearColorValue(float32: subpass.clearColor))) - var - beginInfo = VkCommandBufferBeginInfo( - sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - pInheritanceInfo: nil, - ) - renderPassInfo = VkRenderPassBeginInfo( - sType: VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - renderPass: renderPass.vk, - framebuffer: framebuffer.vk, - renderArea: VkRect2D( - offset: VkOffset2D(x: 0, y: 0), - extent: VkExtent2D(width: w, height: h), - ), - clearValueCount: uint32(clearColors.len), - pClearValues: clearColors.toCPointer(), - ) - viewport = VkViewport( - x: 0.0, - y: 0.0, - width: (float)w, - height: (float)h, - minDepth: 0.0, - maxDepth: 1.0, - ) - scissor = VkRect2D( - offset: VkOffset2D(x: 0, y: 0), - extent: VkExtent2D(width: w, height: h) - ) - checkVkResult commandBuffer.vkResetCommandBuffer(VkCommandBufferResetFlags(0)) - checkVkResult commandBuffer.vkBeginCommandBuffer(addr(beginInfo)) - commandBuffer.vkCmdBeginRenderPass(addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE) - commandBuffer.vkCmdSetViewport(firstViewport=0, viewportCount=1, addr(viewport)) - commandBuffer.vkCmdSetScissor(firstScissor=0, scissorCount=1, addr(scissor)) - -proc endRenderCommands*(commandBuffer: VkCommandBuffer) = - commandBuffer.vkCmdEndRenderPass() - checkVkResult commandBuffer.vkEndCommandBuffer() - -template renderCommands*(commandBuffer: VkCommandBuffer, renderpass: RenderPass, framebuffer: Framebuffer, body: untyped) = - commandBuffer.beginRenderCommands(renderpass, framebuffer) - body - commandBuffer.endRenderCommands() - -proc draw*(commandBuffer: VkCommandBuffer, drawables: seq[Drawable], scene: Scene) = - - debug "Scene buffers:" - for (location, buffer) in scene.vertexBuffers.pairs: - echo " ", location, ": ", buffer - echo " Index buffer: ", scene.indexBuffer - - for drawable in drawables: - debug "Draw ", drawable - - var buffers: seq[VkBuffer] - var offsets: seq[VkDeviceSize] - - for (location, bufferOffsets) in drawable.bufferOffsets.pairs: - for offset in bufferOffsets: - buffers.add scene.vertexBuffers[location].vk - offsets.add VkDeviceSize(offset) - - commandBuffer.vkCmdBindVertexBuffers( - firstBinding=0'u32, - bindingCount=uint32(buffers.len), - pBuffers=buffers.toCPointer(), - pOffsets=offsets.toCPointer() - ) - if drawable.indexed: - commandBuffer.vkCmdBindIndexBuffer(scene.indexBuffer.vk, VkDeviceSize(drawable.indexBufferOffset), drawable.indexType) - commandBuffer.vkCmdDrawIndexed( - indexCount=drawable.elementCount, - instanceCount=drawable.instanceCount, - firstIndex=0, - vertexOffset=0, - firstInstance=0 - ) - else: - commandBuffer.vkCmdDraw( - vertexCount=drawable.elementCount, - instanceCount=drawable.instanceCount, - firstVertex=0, - firstInstance=0 - ) proc drawScene*(swapchain: var Swapchain, scene: Scene): bool = assert swapchain.device.vk.valid @@ -249,7 +110,7 @@ assert swapchain.device.firstGraphicsQueue().isSome assert swapchain.device.firstPresentationQueue().isSome - swapchain.currentInFlight = (swapchain.currentInFlight + 1) mod swapchain.renderPass.inFlightFrames + swapchain.currentInFlight = (swapchain.currentInFlight + 1) mod swapchain.inFlightFrames swapchain.queueFinishedFence[swapchain.currentInFlight].wait() var currentFramebufferIndex: uint32 @@ -267,20 +128,7 @@ swapchain.queueFinishedFence[swapchain.currentInFlight].reset() var commandBuffer = swapchain.commandBufferPool.buffers[swapchain.currentInFlight] - - renderCommands( - commandBuffer, - swapchain.renderpass, - swapchain.framebuffers[currentFramebufferIndex] - ): - for i in 0 ..< swapchain.renderpass.subpasses.len: - for pipeline in swapchain.renderpass.subpasses[i].pipelines.mitems: - commandBuffer.vkCmdBindPipeline(swapchain.renderpass.subpasses[i].pipelineBindPoint, pipeline.vk) - commandBuffer.vkCmdBindDescriptorSets(swapchain.renderpass.subpasses[i].pipelineBindPoint, pipeline.layout, 0, 1, addr(pipeline.descriptorSets[swapchain.currentInFlight].vk), 0, nil) - swapchain.updateUniforms(scene, pipeline) - commandBuffer.draw(scene.getDrawables(pipeline), scene) - if i < swapchain.renderpass.subpasses.len - 1: - commandBuffer.vkCmdNextSubpass(VK_SUBPASS_CONTENTS_INLINE) + commandBuffer.draw(renderPass=swapchain.renderPass, framebuffer=swapchain.framebuffers[currentFramebufferIndex], rootEntity=scene.root, drawables=scene.drawables, vertexBuffers=scene.vertexBuffers, indexBuffer=scene.indexBuffer, currentInFlight=swapchain.currentInFlight) var waitSemaphores = [swapchain.imageAvailableSemaphore[swapchain.currentInFlight].vk] @@ -331,16 +179,13 @@ assert framebuffer.vk.valid framebuffer.destroy() swapchain.commandBufferPool.destroy() - for i in 0 ..< swapchain.renderPass.inFlightFrames: + for i in 0 ..< swapchain.inFlightFrames: assert swapchain.queueFinishedFence[i].vk.valid assert swapchain.imageAvailableSemaphore[i].vk.valid assert swapchain.renderFinishedSemaphore[i].vk.valid swapchain.queueFinishedFence[i].destroy() swapchain.imageAvailableSemaphore[i].destroy() swapchain.renderFinishedSemaphore[i].destroy() - for buffers in swapchain.uniformBuffers.mvalues: - for buffer in buffers.mitems: - buffer.destroy() swapchain.device.vk.vkDestroySwapchainKHR(swapchain.vk, nil) swapchain.vk.reset() diff -r 81a8e62215db -r 5871acc2977e tests/test_vulkan_wrapper.nim --- a/tests/test_vulkan_wrapper.nim Tue Apr 11 01:06:37 2023 +0700 +++ b/tests/test_vulkan_wrapper.nim Wed Apr 12 01:20:53 2023 +0700 @@ -113,23 +113,7 @@ ) when isMainModule: - # INIT ENGINE: - # create instance - var thewindow = createWindow("Test") - var instance = thewindow.createInstance( - vulkanVersion=VK_MAKE_API_VERSION(0, 1, 3, 0), - instanceExtensions= @["VK_EXT_debug_utils"], - layers= @["VK_LAYER_KHRONOS_validation", "VK_LAYER_MESA_overlay"] - ) - var debugger = instance.createDebugMessenger() - # create devices - let selectedPhysicalDevice = instance.getPhysicalDevices().filterBestGraphics() - var device = instance.createDevice( - selectedPhysicalDevice, - @[], - @["VK_EXT_index_type_uint8"], - selectedPhysicalDevice.filterForGraphicsPresentationQueues() - ) + var engine = initEngine("Test") # INIT RENDERER: const @@ -146,33 +130,32 @@ inputs=vertexInput, uniforms=uniforms, outputs=vertexOutput, - body="""gl_Position = vec4(position + translate, 1.0); outcolor = color;""" + main="""gl_Position = vec4(position + translate, 1.0); outcolor = color;""" ) fragmentCode = compileGlslShader( stage=VK_SHADER_STAGE_FRAGMENT_BIT, inputs=vertexOutput, uniforms=uniforms, outputs=fragOutput, - body="color = vec4(outcolor, 1);" + main="color = vec4(outcolor, 1);" ) var - vertexshader = device.createShaderModule(vertexCode) - fragmentshader = device.createShaderModule(fragmentCode) - surfaceFormat = device.physicalDevice.getSurfaceFormats().filterSurfaceFormat() - renderPass = device.simpleForwardRenderPass(surfaceFormat.format, vertexshader, fragmentshader, 2) - (swapchain, res) = device.createSwapchain(renderPass, surfaceFormat, device.firstGraphicsQueue().get().family, 2) + 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") # INIT SCENE - var time = initShaderGlobal("time", 0.0'f32) # var thescene = scene_simple() # var thescene = scene_different_mesh_types() var thescene = scene_primitives() + var time = initShaderGlobal("time", 0.0'f32) thescene.root.components.add time - thescene.setupDrawables(renderPass) - swapchain.setupUniforms(thescene) + thescene.setupDrawableBuffers(engine.gpuDevice, vertexInput) # MAINLOOP echo "Setup successfull, start rendering" @@ -180,10 +163,10 @@ setValue[float32](time.value, get[float32](time.value) + 0.0005) discard swapchain.drawScene(thescene) echo "Rendered ", swapchain.framesRendered, " frames" - checkVkResult device.vk.vkDeviceWaitIdle() # cleanup echo "Start cleanup" + checkVkResult engine.gpuDevice.vk.vkDeviceWaitIdle() # destroy scene thescene.destroy() @@ -195,7 +178,4 @@ swapchain.destroy() # destroy engine - device.destroy() - debugger.destroy() - instance.destroy() - thewindow.destroy() + engine.destroy()