# HG changeset patch # User Sam # Date 1680284402 -25200 # Node ID 0c5a74885796bd3700141236233026e803635e33 # Parent 6fd10b7e2d6af23f461fcc5d1ccfb847aef4e146 did: real implementation of buffer and memory, getting closer to collect shit for drawing per pipeline diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/entity.nim --- a/src/semicongine/entity.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/entity.nim Sat Apr 01 00:40:02 2023 +0700 @@ -15,12 +15,9 @@ components*: seq[Component] -func `$`*(entity: Entity): string = entity.name +method `$`*(entity: Entity): string {.base.} = entity.name method `$`*(part: Component): string {.base.} = - if part.entity != nil: - &"{part.entity} -> Component" - else: - &"Standalone Component" + "Unknown Component" proc add*(entity: Entity, child: Entity) = child.parent = entity @@ -44,8 +41,7 @@ if result.name == "": result.name = &"Entity[{$(cast[ByteAddress](result))}]" -func newEntity*(name: string, firstChild: Entity, children: varargs[ - Entity]): Entity = +func newEntity*(name: string, firstChild: Entity, children: varargs[Entity]): Entity = result = new Entity result.add firstChild for child in children: diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/gpu_data.nim --- a/src/semicongine/gpu_data.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/gpu_data.nim Sat Apr 01 00:40:02 2023 +0700 @@ -22,6 +22,7 @@ components*: CountType # how many components the vectors has (1 means scalar) rows*: CountType # used to split matrices into rows of vectors perInstance*: bool + useGPULocalMemory*: bool AttributeGroup* = object attributes*: seq[Attribute] diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/legacy/buffer.nim --- a/src/semicongine/legacy/buffer.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/legacy/buffer.nim Sat Apr 01 00:40:02 2023 +0700 @@ -54,8 +54,7 @@ bufferTypes: set[BufferType], properties: MemoryProperties, ): Buffer = - result = Buffer(device: device, size: size, bufferTypes: bufferTypes, - memoryProperties: properties) + result = Buffer(device: device, size: size, bufferTypes: bufferTypes, memoryProperties: properties) var usageFlags = 0 for usage in bufferTypes: usageFlags = ord(usageFlags) or ord(usage) @@ -65,10 +64,8 @@ usage: VkBufferUsageFlags(usageFlags), sharingMode: VK_SHARING_MODE_EXCLUSIVE, ) - checkVkResult vkCreateBuffer(result.device, addr(bufferInfo), nil, addr( - result.vkBuffer)) - vkGetBufferMemoryRequirements(result.device, result.vkBuffer, addr( - result.memoryRequirements)) + checkVkResult vkCreateBuffer(result.device, addr(bufferInfo), nil, addr(result.vkBuffer)) + vkGetBufferMemoryRequirements(result.device, result.vkBuffer, addr(result.memoryRequirements)) var allocInfo = VkMemoryAllocateInfo( sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, @@ -77,8 +74,7 @@ ) if result.size > 0: checkVkResult result.device.vkAllocateMemory(addr(allocInfo), nil, addr(result.memory)) - checkVkResult result.device.vkBindBufferMemory(result.vkBuffer, result.memory, - VkDeviceSize(0)) + checkVkResult result.device.vkBindBufferMemory(result.vkBuffer, result.memory, VkDeviceSize(0)) checkVkResult vkMapMemory( result.device, result.memory, @@ -89,8 +85,7 @@ ) -proc transferBuffer*(commandPool: VkCommandPool, queue: VkQueue, src, - dst: Buffer, size: uint64) = +proc transferBuffer*(commandPool: VkCommandPool, queue: VkQueue, src, dst: Buffer, size: uint64) = assert uint64(src.device) == uint64(dst.device) assert TransferSrc in src.bufferTypes assert TransferDst in dst.bufferTypes diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/math/vector.nim --- a/src/semicongine/math/vector.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/math/vector.nim Sat Apr 01 00:40:02 2023 +0700 @@ -36,6 +36,13 @@ func ConstG[T: SomeNumber](): auto {.compiletime.} = TVec3[T]([T(0), T(1), T(0)]) func ConstB[T: SomeNumber](): auto {.compiletime.} = TVec3[T]([T(0), T(0), T(1)]) +func newVec2*(x=0'f32, y=0'f32): auto = + Vec2([x, y]) +func newVec3*(x=0'f32, y=0'f32, z=0'f32): auto = + Vec3([x, y, z]) +func newVec4*(x=0'f32, y=0'f32, z=0'f32, a=0'f32): auto = + Vec4([x, y, z, a]) + # generates constants: Xf, Xf32, Xf64, Xi, Xi8, Xi16, Xi32, Xi64 # Also for Y, Z, R, G, B and One # not sure if this is necessary or even a good idea... diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/mesh.nim --- a/src/semicongine/mesh.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/mesh.nim Sat Apr 01 00:40:02 2023 +0700 @@ -1,20 +1,50 @@ -import std/math -import std/options -import std/typetraits +import std/enumerate +import std/strformat +import std/sequtils -import ./vulkan -import ./thing -import ./buffer -import ./math/vector +import ./entity +import ./math type - Mesh*[T: object, U: uint16|uint32] = ref object of Part - vertexData*: T - case indexed*: bool - of true: - indices*: seq[array[3, U]] - of false: + MeshIndexType* = enum + None + Small # up to 2^16 vertices + Big # up to 2^32 vertices + Mesh* = ref object of Component + vertices: seq[Vec3] + case indexType*: MeshIndexType + of None: discard + of Small: + smallIndices*: seq[array[3, uint16]] + of Big: + bigIndices*: seq[array[3, uint32]] + +method `$`*(mesh: Mesh): string = + &"Mesh ({mesh.vertices.len})" + +func newMesh*(vertices: openArray[Vec3]): auto = + Mesh(vertices: vertices.toSeq, indexType: None) + +func newMesh*(vertices: openArray[Vec3], indices: openArray[array[3, uint32|int32]]): auto = + if uint16(vertices.len) < high(uint16): + var smallIndices = newSeq[array[3, uint16]](indices.len) + for i, tri in enumerate(indices): + smallIndices[i] = [uint16(tri[0]), uint16(tri[1]), uint16(tri[3])] + Mesh(vertices: vertices.toSeq, indexType: Small, smallIndices: smallIndices) + else: + var bigIndices = newSeq[array[3, uint32]](indices.len) + for i, tri in enumerate(indices): + bigIndices[i] = [uint32(tri[0]), uint32(tri[1]), uint32(tri[3])] + Mesh(vertices: vertices.toSeq, indexType: Big, bigIndices: bigIndices) + +func newMesh*(vertices: openArray[Vec3], indices: openArray[array[3, uint16|int16]]): auto = + var smallIndices = newSeq[array[3, uint16]](indices.len) + for i, tri in enumerate(indices): + smallIndices[i] = [uint16(tri[0]), uint16(tri[1]), uint16(tri[3])] + Mesh(vertices: vertices.toSeq, indexType: Small, smallIndices: smallIndices) + +#[ func createUberMesh*[T: object, U: uint16|uint32](meshes: openArray[Mesh[ T, U]]): Mesh[T, U] = @@ -136,3 +166,4 @@ when typeof(value) is PositionAttribute: value.data = data value.useOnDeviceMemory = true +]# diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/scene.nim --- a/src/semicongine/scene.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/scene.nim Sat Apr 01 00:40:02 2023 +0700 @@ -1,16 +1,17 @@ import std/tables import ./vulkan/api -import ./entity import ./vulkan/buffer import ./vulkan/pipeline import ./vulkan/renderpass +import ./entity +import ./mesh type Drawable* = object buffers*: seq[(Buffer, int)] # buffer + offset from buffer - elementCount*: uint32 # vertices or indices - instanceCount*: uint32 + elementCount*: uint32 # number of vertices or indices + instanceCount*: uint32 # number of instance case indexed*: bool of true: indexBuffer*: Buffer @@ -19,16 +20,54 @@ discard Scene* = object + name*: string root*: Entity drawables: Table[VkPipeline, seq[Drawable]] proc setupDrawables(scene: var Scene, pipeline: Pipeline) = - # echo pipeline.descriptorSetLayout.descriptors - # thetype*: VkDescriptorType - # count*: uint32 - # itemsize*: uint32 + var meshes: seq[Mesh] + var smallIMeshes: seq[Mesh] + var bigIMeshes: seq[Mesh] + for mesh in allPartsOfType[Mesh](scene.root): + case mesh.indexType: + of None: meshes.add mesh + of Small: smallIMeshes.add mesh + of Big: bigIMeshes.add mesh + echo pipeline.inputs + + # one drawable per mesh list + # one buffer per pipeline.input + # how to find data for pipeline.inputs attribute-buffer? + # position: get from mesh, mark attribute + # color/UVs: material component? scene.drawables[pipeline.vk] = @[] +#[ +proc createVertexBuffers*[M: Mesh]( + mesh: M, + device: VkDevice, + physicalDevice: VkPhysicalDevice, + commandPool: VkCommandPool, + queue: VkQueue, +): (seq[Buffer], uint32) = + result[1] = mesh.vertexData.VertexCount + for name, value in mesh.vertexData.fieldPairs: + assert value.data.len > 0 + var flags = if value.useOnDeviceMemory: {TransferSrc} else: {VertexBuffer} + var stagingBuffer = device.InitBuffer(physicalDevice, value.datasize, flags, {HostVisible, HostCoherent}) + copyMem(stagingBuffer.data, addr(value.data[0]), value.datasize) + + if value.useOnDeviceMemory: + var finalBuffer = device.InitBuffer(physicalDevice, value.datasize, {TransferDst, VertexBuffer}, {DeviceLocal}) + transferBuffer(commandPool, queue, stagingBuffer, finalBuffer, value.datasize) + stagingBuffer.trash() + result[0].add(finalBuffer) + value.buffer = finalBuffer + else: + result[0].add(stagingBuffer) + value.buffer = stagingBuffer +]# + proc setupDrawables*(scene: var Scene, renderPass: var RenderPass) = for subpass in renderPass.subpasses.mitems: for pipeline in subpass.pipelines.mitems: diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/vulkan/buffer.nim --- a/src/semicongine/vulkan/buffer.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/vulkan/buffer.nim Sat Apr 01 00:40:02 2023 +0700 @@ -1,17 +1,48 @@ +import std/sequtils +import std/tables + import ./api import ./device +import ./memory +import ./physicaldevice +import ./commandbuffer type Buffer* = object device*: Device vk*: VkBuffer size*: uint64 + usage*: seq[VkBufferUsageFlagBits] + case hasMemory*: bool + of false: discard + of true: + memory*: DeviceMemory + data*: pointer + +proc allocateMemory(buffer: var Buffer, flags: openArray[VkMemoryPropertyFlagBits]) = + assert buffer.device.vk.valid + assert buffer.hasMemory == false + + buffer.hasMemory = true + buffer.memory = buffer.device.allocate(buffer.size, flags) + checkVkResult buffer.device.vk.vkBindBufferMemory(buffer.vk, buffer.memory.vk, VkDeviceSize(0)) + buffer.data = buffer.memory.map() # currently no support for extended structure and concurrent/shared use # (shardingMode = VK_SHARING_MODE_CONCURRENT not supported) -proc createBuffer(device: Device, size: uint64, flags: openArray[VkBufferCreateFlagBits], usage: openArray[VkBufferUsageFlagBits]): Buffer = +proc createBuffer*( + device: Device, + size: uint64, + flags: openArray[VkBufferCreateFlagBits], + usage: openArray[VkBufferUsageFlagBits], + memoryFlags: openArray[VkMemoryPropertyFlagBits], +): Buffer = + assert device.vk.valid + assert size > 0 + result.device = device result.size = size + result.usage = usage.toSeq var createInfo = VkBufferCreateInfo( sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, flags: toBits(flags), @@ -26,9 +57,51 @@ pAllocator=nil, pBuffer=addr result.vk ) + result.allocateMemory(memoryFlags) -proc destroy(buffer: var Buffer) = + +proc copy*(src, dst: Buffer) = + assert src.device.vk.valid + assert dst.device.vk.valid + assert src.device == dst.device + assert src.size == dst.size + assert VK_BUFFER_USAGE_TRANSFER_SRC_BIT in src.usage + assert VK_BUFFER_USAGE_TRANSFER_DST_BIT in dst.usage + + var queue: Queue + for q in src.device.queues.values: + if q.family.canDoTransfer: + queue = q + if not queue.vk.valid: + raise newException(Exception, "No queue that supports buffer transfer") + + var + commandBufferPool = src.device.createCommandBufferPool(family=queue.family, nBuffers=1) + commandBuffer = commandBufferPool.buffers[0] + + beginInfo = VkCommandBufferBeginInfo( + sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + flags: VkCommandBufferUsageFlags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT), + ) + copyRegion = VkBufferCopy(size: VkDeviceSize(src.size)) + checkVkResult commandBuffer.vkBeginCommandBuffer(addr(beginInfo)) + commandBuffer.vkCmdCopyBuffer(src.vk, dst.vk, 1, addr(copyRegion)) + checkVkResult commandBuffer.vkEndCommandBuffer() + + var submitInfo = VkSubmitInfo( + sType: VK_STRUCTURE_TYPE_SUBMIT_INFO, + commandBufferCount: 1, + pCommandBuffers: addr(commandBuffer), + ) + checkVkResult queue.vk.vkQueueSubmit(1, addr(submitInfo), VkFence(0)) + checkVkResult queue.vk.vkQueueWaitIdle() + commandBufferPool.destroy() + +proc destroy*(buffer: var Buffer) = assert buffer.device.vk.valid assert buffer.vk.valid + if buffer.hasMemory: + assert buffer.memory.vk.valid + buffer.memory.free buffer.device.vk.vkDestroyBuffer(buffer.vk, nil) buffer.vk.reset() diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/vulkan/commandbuffer.nim --- a/src/semicongine/vulkan/commandbuffer.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/vulkan/commandbuffer.nim Sat Apr 01 00:40:02 2023 +0700 @@ -1,18 +1,14 @@ import ./api import ./device import ./physicaldevice -import ./renderpass -import ./framebuffer import ./utils -import ../math - type CommandBufferPool* = object + device: Device vk*: VkCommandPool family*: QueueFamily buffers*: seq[VkCommandBuffer] - device: Device proc createCommandBufferPool*(device: Device, family: QueueFamily, nBuffers: int): CommandBufferPool = assert device.vk.valid @@ -34,61 +30,6 @@ result.buffers = newSeq[VkCommandBuffer](nBuffers) checkVkResult device.vk.vkAllocateCommandBuffers(addr(allocInfo), result.buffers.toCPointer) -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 destroy*(commandpool: var CommandBufferPool) = assert commandpool.device.vk.valid diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/vulkan/device.nim --- a/src/semicongine/vulkan/device.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/vulkan/device.nim Sat Apr 01 00:40:02 2023 +0700 @@ -72,7 +72,7 @@ for family in deviceQueues.keys: var queue: VkQueue vkGetDeviceQueue(result.vk, family.index, 0, addr queue) - result.queues[family] = Queue(vk: queue, family: family, presentation: family.hasPresentation(physicalDevice.surface), graphics: family.hasGraphics()) + result.queues[family] = Queue(vk: queue, family: family, presentation: family.canDoPresentation(physicalDevice.surface), graphics: family.canDoGraphics()) func firstGraphicsQueue*(device: Device): Option[Queue] = assert device.vk.valid diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/vulkan/memory.nim --- a/src/semicongine/vulkan/memory.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/vulkan/memory.nim Sat Apr 01 00:40:02 2023 +0700 @@ -1,4 +1,7 @@ +import std/strformat + import ./api +import ./device type MemoryHeap = object @@ -12,10 +15,10 @@ PhyscialDeviceMemoryProperties = object heaps*: seq[MemoryHeap] types*: seq[MemoryType] - DeviceMemory = object - device*: VkDevice + DeviceMemory* = object + device*: Device + vk*: VkDeviceMemory size*: uint64 - vk*: VkDeviceMemory proc getPhysicalDeviceMemoryProperties(physicalDevice: VkPhysicalDevice): PhyscialDeviceMemoryProperties = var physicalProperties: VkPhysicalDeviceMemoryProperties @@ -33,19 +36,59 @@ index: i, ) -proc allocateMemory(device: VkDevice, size: uint64, memoryType: MemoryType): DeviceMemory = +proc allocate*(device: Device, size: uint64, flags: openArray[VkMemoryPropertyFlagBits]): DeviceMemory = + assert device.vk.valid + result.device = device result.size = size + var + memtype: MemoryType + hasAllFlags: bool + for mtype in device.physicalDevice.vk.getPhysicalDeviceMemoryProperties.types: + hasAllFlags = true + for flag in flags: + if not (flag in mtype.flags): + hasAllFlags = false + break + if hasAllFlags: + memtype = mtype + break + if not hasAllFlags: + raise newException(Exception, &"No memory with support for {flags}") + var allocationInfo = VkMemoryAllocateInfo( sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, allocationSize: size, - memoryTypeIndex: memoryType.index, + memoryTypeIndex: memtype.index, ) checkVkResult vkAllocateMemory( - device, + device.vk, addr allocationInfo, nil, addr result.vk ) + +proc map*(memory: DeviceMemory, offset=0'u64, size=0'u64): pointer = + assert memory.device.vk.valid + assert memory.vk.valid + + var thesize = size + if thesize == 0: + thesize = memory.size + + checkVkResult memory.device.vk.vkMapMemory( + memory=memory.vk, + offset=VkDeviceSize(offset), + size=VkDeviceSize(thesize), + flags=VkMemoryMapFlags(0), # unused up to Vulkan 1.3 + ppData=addr(result) + ) + +proc free*(memory: var DeviceMemory) = + assert memory.device.vk.valid + assert memory.vk.valid + + memory.device.vk.vkFreeMemory(memory.vk, nil) + memory.vk.reset diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/vulkan/physicaldevice.nim --- a/src/semicongine/vulkan/physicaldevice.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/vulkan/physicaldevice.nim Sat Apr 01 00:40:02 2023 +0700 @@ -99,37 +99,41 @@ flags: queuFamilies[i].queueFlags.toEnums, ) -proc hasGraphics*(family: QueueFamily): bool = +proc canDoGraphics*(family: QueueFamily): bool = VK_QUEUE_GRAPHICS_BIT in family.flags -proc hasPresentation*(family: QueueFamily, surface: VkSurfaceKHR): bool = + +proc canDoPresentation*(family: QueueFamily, surface: VkSurfaceKHR): bool = assert surface.valid var presentation = VkBool32(false) checkVkResult vkGetPhysicalDeviceSurfaceSupportKHR(family.device.vk, family.index, surface, addr presentation) return presentation +proc canDoTransfer*(family: QueueFamily): bool = + VK_QUEUE_TRANSFER_BIT in family.flags + proc filterForGraphicsPresentationQueues*(device: PhysicalDevice): seq[QueueFamily] = - var hasGraphics = false - var hasPresentation = false + var canDoGraphics = false + var canDoPresentation = false var queues: Table[uint32, QueueFamily] for family in device.getQueueFamilies(): - if family.hasGraphics: + if family.canDoGraphics: queues[family.index] = family - hasGraphics = true - if family.hasPresentation(device.surface): + canDoGraphics = true + if family.canDoPresentation(device.surface): queues[family.index] = family - hasPresentation = true - if hasGraphics and hasPresentation: + canDoPresentation = true + if canDoGraphics and canDoPresentation: return queues.values.toSeq proc filterGraphics(families: seq[QueueFamily]): seq[QueueFamily] = for family in families: - if family.hasGraphics: + if family.canDoGraphics: result.add family proc filterPresentation(families: seq[QueueFamily], surface: VkSurfaceKHR): seq[QueueFamily] = assert surface.valid for family in families: - if family.hasPresentation(surface): + if family.canDoPresentation(surface): result.add family proc rateGraphics*(device: PhysicalDevice): float = diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/vulkan/pipeline.nim --- a/src/semicongine/vulkan/pipeline.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/vulkan/pipeline.nim Sat Apr 01 00:40:02 2023 +0700 @@ -1,16 +1,24 @@ import ./api import ./device import ./descriptor +import ./shader + +import ../gpu_data type Pipeline* = object device*: Device vk*: VkPipeline layout*: VkPipelineLayout + shaders*: seq[Shader] descriptorSetLayout*: DescriptorSetLayout descriptorPool*: DescriptorPool descriptorSets*: seq[DescriptorSet] +func inputs*(pipeline: Pipeline): AttributeGroup = + for shader in pipeline.shaders: + if shader.stage == VK_SHADER_STAGE_VERTEX_BIT: + return shader.inputs proc destroy*(pipeline: var Pipeline) = assert pipeline.device.vk.valid diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/vulkan/renderpass.nim --- a/src/semicongine/vulkan/renderpass.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/vulkan/renderpass.nim Sat Apr 01 00:40:02 2023 +0700 @@ -74,7 +74,7 @@ assert vertexShader.stage == VK_SHADER_STAGE_VERTEX_BIT assert fragmentShader.stage == VK_SHADER_STAGE_FRAGMENT_BIT - var pipeline = Pipeline(device: renderPass.device) + var pipeline = Pipeline(device: renderPass.device, shaders: @[vertexShader, fragmentShader]) var descriptors = @[Descriptor( thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/vulkan/shader.nim --- a/src/semicongine/vulkan/shader.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/vulkan/shader.nim Sat Apr 01 00:40:02 2023 +0700 @@ -1,5 +1,4 @@ import std/typetraits -import std/macros import std/os import std/enumerate import std/logging @@ -8,10 +7,8 @@ import std/strutils import std/compilesettings -import ../math import ./api import ./device -import ./vertex import ./utils import ../gpu_data diff -r 6fd10b7e2d6a -r 0c5a74885796 src/semicongine/vulkan/swapchain.nim --- a/src/semicongine/vulkan/swapchain.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/src/semicongine/vulkan/swapchain.nim Sat Apr 01 00:40:02 2023 +0700 @@ -100,6 +100,60 @@ return (swapchain, createResult) +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) = for drawable in drawables: var buffers: seq[VkBuffer] diff -r 6fd10b7e2d6a -r 0c5a74885796 tests/test_vulkan_wrapper.nim --- a/tests/test_vulkan_wrapper.nim Fri Mar 31 16:00:16 2023 +0700 +++ b/tests/test_vulkan_wrapper.nim Sat Apr 01 00:40:02 2023 +0700 @@ -1,4 +1,3 @@ -import std/os import std/options import semicongine/vulkan @@ -7,16 +6,7 @@ import semicongine/entity import semicongine/scene import semicongine/gpu_data - -type - Vertex = object - pos: Vec3 - FragmentInput = object - fragpos: Vec3 - Uniforms = object - time: float32 - Pixel = object - color: Vec4 +import semicongine/mesh proc diagnostics(instance: Instance) = # diagnostic output @@ -83,11 +73,11 @@ if res != VK_SUCCESS: raise newException(Exception, "Unable to create swapchain") - var thescene = Scene(root: newEntity("scene")) + var thescene = Scene(name: "main", root: newEntity("triangle", newMesh([newVec3(-1, -1), newVec3(0, 1), newVec3(1, -1)]))) thescene.setupDrawables(renderPass) echo "Setup successfull, start rendering" - for i in 0 ..< 10: + for i in 0 ..< 1: discard swapchain.drawScene(thescene) echo "Rendered ", swapchain.framesRendered, " frames" echo "Start cleanup"