Mercurial > games > semicongine
changeset 122:506090173619
did: implement uniforms, some refactoring
author | Sam <sam@basx.dev> |
---|---|
date | Sun, 09 Apr 2023 01:04:54 +0700 |
parents | dfaddaf96f09 |
children | 55be3579dc30 |
files | src/semicongine/entity.nim src/semicongine/gpu_data.nim src/semicongine/mesh.nim src/semicongine/platform/linux/xlib.nim src/semicongine/platform/windows/win32.nim src/semicongine/scene.nim src/semicongine/vulkan/instance.nim src/semicongine/vulkan/pipeline.nim src/semicongine/vulkan/shader.nim src/semicongine/vulkan/swapchain.nim tests/test_vulkan_wrapper.nim |
diffstat | 11 files changed, 318 insertions(+), 145 deletions(-) [+] |
line wrap: on
line diff
--- a/src/semicongine/entity.nim Fri Apr 07 00:32:07 2023 +0700 +++ b/src/semicongine/entity.nim Sun Apr 09 01:04:54 2023 +0700 @@ -16,23 +16,23 @@ method `$`*(entity: Entity): string {.base.} = entity.name -method `$`*(part: Component): string {.base.} = +method `$`*(component: Component): string {.base.} = "Unknown Component" proc add*(entity: Entity, child: Entity) = child.parent = entity entity.children.add child -proc add*(entity: Entity, part: Component) = - part.entity = entity - entity.components.add part +proc add*(entity: Entity, component: Component) = + component.entity = entity + entity.components.add component proc add*(entity: Entity, children: seq[Entity]) = for child in children: child.parent = entity entity.children.add child proc add*(entity: Entity, components: seq[Component]) = - for part in components: - part.entity = entity - entity.components.add part + for component in components: + component.entity = entity + entity.components.add component func newEntity*(name: string = ""): Entity = result = new Entity @@ -51,12 +51,12 @@ if result.name == "": result.name = &"Entity[{$(cast[ByteAddress](result))}]" -proc newEntity*(name: string, firstPart: Component, components: varargs[Component]): Entity = +proc newEntity*(name: string, firstComponent: Component, components: varargs[Component]): Entity = result = new Entity result.name = name - result.add firstPart - for part in components: - result.add part + result.add firstComponent + for component in components: + result.add component if result.name == "": result.name = &"Entity[{$(cast[ByteAddress](result))}]" result.transform = Unit4 @@ -68,13 +68,13 @@ result = currentEntity.transform * result currentEntity = currentEntity.parent -iterator allPartsOfType*[T: Component](root: Entity): T = +iterator allComponentsOfType*[T: Component](root: Entity): T = var queue = @[root] while queue.len > 0: let entity = queue.pop - for part in entity.components: - if part of T: - yield T(part) + for component in entity.components: + if component of T: + yield T(component) for i in countdown(entity.children.len - 1, 0): queue.add entity.children[i] @@ -87,15 +87,15 @@ return child queue.add child -func firstPartWithName*[T: Component](root: Entity, name: string): T = +func firstComponentWithName*[T: Component](root: Entity, name: string): T = var queue = @[root] while queue.len > 0: let next = queue.pop for child in next.children: if child.name == name: - for part in child.components: - if part of T: - return T(part) + for component in child.components: + if component of T: + return T(component) queue.add child func allWithName*(root: Entity, name: string): seq[Entity] = @@ -107,15 +107,15 @@ result.add child queue.add child -func allPartsWithName*[T: Component](root: Entity, name: string): seq[T] = +func allComponentsWithName*[T: Component](root: Entity, name: string): seq[T] = var queue = @[root] while queue.len > 0: let next = queue.pop for child in next.children: if child.name == name: - for part in child.components: - if part of T: - result.add T(part) + for component in child.components: + if component of T: + result.add T(component) queue.add child iterator allEntities*(root: Entity): Entity =
--- a/src/semicongine/gpu_data.nim Fri Apr 07 00:32:07 2023 +0700 +++ b/src/semicongine/gpu_data.nim Sun Apr 09 01:04:54 2023 +0700 @@ -1,4 +1,3 @@ -import std/sequtils import std/typetraits import std/strformat import std/tables @@ -99,24 +98,19 @@ of Mat4F64: mat4f64: TMat4[float64] MemoryLocation* = enum VRAM, VRAMVisible, RAM # VRAM is fastest, VRAMVisible allows updating memory directly, may be slower - VertexAttribute* = object + ShaderAttribute* = object name*: string thetype*: DataType perInstance*: bool memoryLocation*: MemoryLocation - AttributeGroup* = object - attributes*: seq[VertexAttribute] -func initAttributeGroup*(attrs: varargs[VertexAttribute]): auto = - AttributeGroup(attributes: attrs.toSeq) - -func vertexInputs*(group: AttributeGroup): seq[VertexAttribute] = - for attr in group.attributes: +func vertexInputs*(attributes: seq[ShaderAttribute]): seq[ShaderAttribute] = + for attr in attributes: if attr.perInstance == false: result.add attr -func instanceInputs*(group: AttributeGroup): seq[VertexAttribute] = - for attr in group.attributes: +func instanceInputs*(attributes: seq[ShaderAttribute]): seq[ShaderAttribute] = + for attr in attributes: if attr.perInstance == false: result.add attr @@ -173,12 +167,12 @@ of Mat4F32: 64 of Mat4F64: 128 -func size*(attribute: VertexAttribute, perDescriptor=false): uint32 = +func size*(attribute: ShaderAttribute, perDescriptor=false): uint32 = if perDescriptor: attribute.thetype.size div attribute.thetype.numberOfVertexInputAttributeDescriptors else: attribute.thetype.size -func size*(thetype: AttributeGroup): uint32 = - for attribute in thetype.attributes: +func size*(thetype: seq[ShaderAttribute]): uint32 = + for attribute in thetype: result += attribute.size func getDataType*[T: GPUType|int|uint|float](): DataType = @@ -239,7 +233,7 @@ perInstance=false, memoryLocation=VRAMVisible, ): auto = - VertexAttribute( + ShaderAttribute( name: name, thetype: getDataType[T](), perInstance: perInstance, @@ -247,49 +241,150 @@ ) func get*[T: GPUType|int|uint|float](value: DataValue): T = + when T is float32: value.float32 + elif T is float64: value.float64 + elif T is int8: value.int8 + elif T is int16: value.int16 + elif T is int32: value.int32 + elif T is int64: value.int64 + elif T is uint8: value.uint8 + elif T is uint16: value.uint16 + elif T is uint32: value.uint32 + elif T is uint64: value.uint64 + elif T is int and sizeof(int) == sizeof(int32): value.int32 + elif T is int and sizeof(int) == sizeof(int64): value.int64 + elif T is uint and sizeof(uint) == sizeof(uint32): value.uint32 + elif T is uint and sizeof(uint) == sizeof(uint64): value.uint64 + elif T is float and sizeof(float) == sizeof(float32): value.float32 + elif T is float and sizeof(float) == sizeof(float64): value.float64 + elif T is TVec2[int32]: value.vec2i32 + elif T is TVec2[int64]: value.vec2i64 + elif T is TVec3[int32]: value.vec3i32 + elif T is TVec3[int64]: value.vec3i64 + elif T is TVec4[int32]: value.vec4i32 + elif T is TVec4[int64]: value.vec4i64 + elif T is TVec2[uint32]: value.vec2u32 + elif T is TVec2[uint64]: value.vec2u64 + elif T is TVec3[uint32]: value.vec3u32 + elif T is TVec3[uint64]: value.vec3u64 + elif T is TVec4[uint32]: value.vec4u32 + elif T is TVec4[uint64]: value.vec4u64 + elif T is TVec2[float32]: value.vec2f32 + elif T is TVec2[float64]: value.vec2f64 + elif T is TVec3[float32]: value.vec3f32 + elif T is TVec3[float64]: value.vec3f64 + elif T is TVec4[float32]: value.vec4f32 + elif T is TVec4[float64]: value.vec4f64 + elif T is TMat2[float32]: value.mat2f32 + elif T is TMat2[float64]: value.mat2f64 + elif T is TMat23[float32]: value.mat23f + elif T is TMat23[float64]: value.mat23f64 + elif T is TMat32[float32]: value.mat32f32 + elif T is TMat32[float64]: value.mat32f64 + elif T is TMat3[float32]: value.mat3f32 + elif T is TMat3[float64]: value.mat3f64 + elif T is TMat34[float32]: value.mat34f32 + elif T is TMat34[float64]: value.mat34f64 + elif T is TMat43[float32]: value.mat43f32 + elif T is TMat43[float64]: value.mat43f64 + elif T is TMat4[float32]: value.mat4f32 + elif T is TMat4[float64]: value.mat4f64 + +proc getRawData*(value: var DataValue): (pointer, uint64) = + result[1] = value.thetype.size case value.thetype - of Float32: value.float32 - of Float64: value.float64 - of Int8: value.int8 - of Int16: value.int16 - of Int32: value.int32 - of Int64: value.int64 - of UInt8: value.uint8 - of UInt16: value.uint16 - of UInt32: value.uint32 - of UInt64: value.uint64 - of Vec2I32: value.vec2i32 - of Vec2I64: value.vec2i64 - of Vec3I32: value.vec3i32 - of Vec3I64: value.vec3i64 - of Vec4I32: value.vec4i32 - of Vec4I64: value.vec4i64 - of Vec2U32: value.vec2u32 - of Vec2U64: value.vec2u64 - of Vec3U32: value.vec3u32 - of Vec3U64: value.vec3u64 - of Vec4U32: value.vec4u32 - of Vec4U64: value.vec4u64 - of Vec2F32: value.vec2f32 - of Vec2F64: value.vec2f64 - of Vec3F32: value.vec3f32 - of Vec3F64: value.vec3f64 - of Vec4F32: value.vec4f32 - of Vec4F64: value.vec4f64 - of Mat2F32: value.mat2f32 - of Mat2F64: value.mat2f64 - of Mat23F32: value.mat23f32 - of Mat23F64: value.mat23f64 - of Mat32F32: value.mat32f32 - of Mat32F64: value.mat32f64 - of Mat3F32: value.mat3f32 - of Mat3F64: value.mat3f64 - of Mat34F32: value.mat34f32 - of Mat34F64: value.mat34f64 - of Mat43F32: value.mat43f32 - of Mat43F64: value.mat43f64 - of Mat4F32: value.mat4f32 - of Mat4F64: value.mat4f64 + of Float32: result[0] = addr value.float32 + of Float64: result[0] = addr value.float64 + of Int8: result[0] = addr value.int8 + of Int16: result[0] = addr value.int16 + of Int32: result[0] = addr value.int32 + of Int64: result[0] = addr value.int64 + of UInt8: result[0] = addr value.uint8 + of UInt16: result[0] = addr value.uint16 + of UInt32: result[0] = addr value.uint32 + of UInt64: result[0] = addr value.uint64 + of Vec2I32: result[0] = addr value.vec2i32 + of Vec2I64: result[0] = addr value.vec2i64 + of Vec3I32: result[0] = addr value.vec3i32 + of Vec3I64: result[0] = addr value.vec3i64 + of Vec4I32: result[0] = addr value.vec4i32 + of Vec4I64: result[0] = addr value.vec4i64 + of Vec2U32: result[0] = addr value.vec2u32 + of Vec2U64: result[0] = addr value.vec2u64 + of Vec3U32: result[0] = addr value.vec3u32 + of Vec3U64: result[0] = addr value.vec3u64 + of Vec4U32: result[0] = addr value.vec4u32 + of Vec4U64: result[0] = addr value.vec4u64 + of Vec2F32: result[0] = addr value.vec2f32 + of Vec2F64: result[0] = addr value.vec2f64 + of Vec3F32: result[0] = addr value.vec3f32 + of Vec3F64: result[0] = addr value.vec3f64 + of Vec4F32: result[0] = addr value.vec4f32 + of Vec4F64: result[0] = addr value.vec4f64 + of Mat2F32: result[0] = addr value.mat2f32 + of Mat2F64: result[0] = addr value.mat2f64 + of Mat23F32: result[0] = addr value.mat23f32 + of Mat23F64: result[0] = addr value.mat23f64 + of Mat32F32: result[0] = addr value.mat32f32 + of Mat32F64: result[0] = addr value.mat32f64 + of Mat3F32: result[0] = addr value.mat3f32 + of Mat3F64: result[0] = addr value.mat3f64 + of Mat34F32: result[0] = addr value.mat34f32 + of Mat34F64: result[0] = addr value.mat34f64 + of Mat43F32: result[0] = addr value.mat43f32 + of Mat43F64: result[0] = addr value.mat43f64 + of Mat4F32: result[0] = addr value.mat4f32 + of Mat4F64: result[0] = addr value.mat4f64 + +func setValue*[T: GPUType|int|uint|float](value: var DataValue, data: T) = + when T is float32: value.float32 = data + elif T is float64: value.float64 = data + elif T is int8: value.int8 = data + elif T is int16: value.int16 = data + elif T is int32: value.int32 = data + elif T is int64: value.int64 = data + elif T is uint8: value.uint8 = data + elif T is uint16: value.uint16 = data + elif T is uint32: value.uint32 = data + elif T is uint64: value.uint64 = data + elif T is int and sizeof(int) == sizeof(int32): value.int32 = data + elif T is int and sizeof(int) == sizeof(int64): value.int64 = data + elif T is uint and sizeof(uint) == sizeof(uint32): value.uint32 = data + elif T is uint and sizeof(uint) == sizeof(uint64): value.uint64 = data + elif T is float and sizeof(float) == sizeof(float32): value.float32 = data + elif T is float and sizeof(float) == sizeof(float64): value.float64 = data + elif T is TVec2[int32]: value.vec2i32 = data + elif T is TVec2[int64]: value.vec2i64 = data + elif T is TVec3[int32]: value.vec3i32 = data + elif T is TVec3[int64]: value.vec3i64 = data + elif T is TVec4[int32]: value.vec4i32 = data + elif T is TVec4[int64]: value.vec4i64 = data + elif T is TVec2[uint32]: value.vec2u32 = data + elif T is TVec2[uint64]: value.vec2u64 = data + elif T is TVec3[uint32]: value.vec3u32 = data + elif T is TVec3[uint64]: value.vec3u64 = data + elif T is TVec4[uint32]: value.vec4u32 = data + elif T is TVec4[uint64]: value.vec4u64 = data + elif T is TVec2[float32]: value.vec2f32 = data + elif T is TVec2[float64]: value.vec2f64 = data + elif T is TVec3[float32]: value.vec3f32 = data + elif T is TVec3[float64]: value.vec3f64 = data + elif T is TVec4[float32]: value.vec4f32 = data + elif T is TVec4[float64]: value.vec4f64 = data + elif T is TMat2[float32]: value.mat2f32 = data + elif T is TMat2[float64]: value.mat2f64 = data + elif T is TMat23[float32]: value.mat23f32 = data + elif T is TMat23[float64]: value.mat23f64 = data + elif T is TMat32[float32]: value.mat32f32 = data + elif T is TMat32[float64]: value.mat32f64 = data + elif T is TMat3[float32]: value.mat3f32 = data + elif T is TMat3[float64]: value.mat3f64 = data + elif T is TMat34[float32]: value.mat34f32 = data + elif T is TMat34[float64]: value.mat34f64 = data + elif T is TMat43[float32]: value.mat43f32 = data + elif T is TMat43[float64]: value.mat43f64 = data + elif T is TMat4[float32]: value.mat4f32 = data + elif T is TMat4[float64]: value.mat4f64 = data const TYPEMAP = { Float32: VK_FORMAT_R32_SFLOAT, @@ -436,33 +531,33 @@ of Mat4F32: "mat4" of Mat4F64: "dmat4" -func glslInput*(group: AttributeGroup): seq[string] = - if group.attributes.len == 0: +func glslInput*(group: seq[ShaderAttribute]): seq[string] = + if group.len == 0: return @[] var i = 0'u32 - for attribute in group.attributes: + for attribute in group: result.add &"layout(location = {i}) in {attribute.thetype.glslType} {attribute.name};" for j in 0 ..< attribute.thetype.numberOfVertexInputAttributeDescriptors: i += attribute.thetype.nLocationSlots -func glslUniforms*(group: AttributeGroup, blockName="Uniforms", binding=0): seq[string] = - if group.attributes.len == 0: +func glslUniforms*(group: seq[ShaderAttribute], blockName="Uniforms", binding=0): seq[string] = + if group.len == 0: return @[] # currently only a single uniform block supported, therefore binding = 0 result.add(&"layout(binding = {binding}) uniform T{blockName} {{") - for attribute in group.attributes: + for attribute in group: result.add(&" {attribute.thetype.glslType} {attribute.name};") result.add(&"}} {blockName};") -func glslOutput*(group: AttributeGroup): seq[string] = - if group.attributes.len == 0: +func glslOutput*(group: seq[ShaderAttribute]): seq[string] = + if group.len == 0: return @[] var i = 0'u32 - for attribute in group.attributes: + for attribute in group: result.add &"layout(location = {i}) out {attribute.thetype.glslType} {attribute.name};" i += 1 -func groupByMemoryLocation*(attributes: openArray[VertexAttribute]): Table[MemoryLocation, seq[VertexAttribute]] = +func groupByMemoryLocation*(attributes: openArray[ShaderAttribute]): Table[MemoryLocation, seq[ShaderAttribute]] = for attr in attributes: if not (attr.memoryLocation in result): result[attr.memoryLocation] = @[]
--- a/src/semicongine/mesh.nim Fri Apr 07 00:32:07 2023 +0700 +++ b/src/semicongine/mesh.nim Sun Apr 09 01:04:54 2023 +0700 @@ -28,7 +28,7 @@ of TextureCoordinate: texturecoord: seq[Vec2f] Mesh* = ref object of Component vertexCount*: uint32 - data: Table[VertexAttribute, MeshData] + data: Table[ShaderAttribute, MeshData] case indexType*: MeshIndexType of None: discard of Tiny: tinyIndices*: seq[array[3, uint8]] @@ -134,7 +134,7 @@ of BiTangent: meshdata.bitangent.size of TextureCoordinate: meshdata.texturecoord.size -func attributeSize*(mesh: Mesh, attribute: VertexAttribute): uint64 = +func attributeSize*(mesh: Mesh, attribute: ShaderAttribute): uint64 = mesh.data[attribute].meshDataSize func vertexDataSize*(mesh: Mesh): uint64 = @@ -167,14 +167,14 @@ of Small: rawData(mesh.smallIndices) of Big: rawData(mesh.bigIndices) -proc hasDataFor*(mesh: Mesh, attribute: VertexAttribute): bool = +proc hasDataFor*(mesh: Mesh, attribute: ShaderAttribute): bool = assert attribute.perInstance == false, "Mesh data cannot handle per-instance attributes" attribute in mesh.data -proc getRawData*(mesh: Mesh, attribute: VertexAttribute): (pointer, uint64) = +proc getRawData*(mesh: Mesh, attribute: ShaderAttribute): (pointer, uint64) = assert attribute.perInstance == false, "Mesh data cannot handle per-instance attributes" mesh.data[attribute].getRawData() -proc getData*(mesh: Mesh, attribute: VertexAttribute): MeshData = +proc getData*(mesh: Mesh, attribute: ShaderAttribute): MeshData = assert attribute.perInstance == false, "Mesh data cannot handle per-instance attributes" mesh.data[attribute]
--- a/src/semicongine/platform/linux/xlib.nim Fri Apr 07 00:32:07 2023 +0700 +++ b/src/semicongine/platform/linux/xlib.nim Sun Apr 09 01:04:54 2023 +0700 @@ -62,7 +62,7 @@ return NativeWindow(display: display, window: window, emptyCursor: empty_cursor) -proc trash*(window: NativeWindow) = +proc destroy*(window: NativeWindow) = checkXlibResult window.display.XFreeCursor(window.emptyCursor) checkXlibResult window.display.XDestroyWindow(window.window) discard window.display.XCloseDisplay() # always returns 0
--- a/src/semicongine/platform/windows/win32.nim Fri Apr 07 00:32:07 2023 +0700 +++ b/src/semicongine/platform/windows/win32.nim Sun Apr 09 01:04:54 2023 +0700 @@ -88,7 +88,7 @@ discard ShowWindow(result.hwnd, SW_SHOW) discard ShowCursor(false) -proc trash*(window: NativeWindow) = +proc destroy*(window: NativeWindow) = discard proc size*(window: NativeWindow): (int, int) = @@ -106,9 +106,9 @@ DispatchMessage(addr(msg)) return currentEvents -proc getMousePosition*(window: NativeWindow): Option[Vec2] = +proc getMousePosition*(window: NativeWindow): Option[Vec2f] = var p: POINT let res = GetCursorPos(addr(p)) if res: - return some(Vec2([float32(p.x), float32(p.y)])) - return none(Vec2) + return some(Vec2f([float32(p.x), float32(p.y)])) + return none(Vec2f)
--- a/src/semicongine/scene.nim Fri Apr 07 00:32:07 2023 +0700 +++ b/src/semicongine/scene.nim Sun Apr 09 01:04:54 2023 +0700 @@ -38,14 +38,22 @@ else: &"Drawable(elementCount: {drawable.elementCount}, instanceCount: {drawable.instanceCount}, buffer: {drawable.buffer}, offsets: {drawable.offsets})" +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 getBuffers*(scene: Scene, pipeline: VkPipeline): seq[Buffer] = var counted: seq[VkBuffer] for drawable in scene.drawables[pipeline]: if not (drawable.buffer.vk in counted): - result.add(drawable.buffer) + result.add drawable.buffer counted.add drawable.buffer.vk if drawable.indexed and not (drawable.indexBuffer.vk in counted): - result.add(drawable.indexBuffer) + result.add drawable.indexBuffer counted.add drawable.indexBuffer.vk proc destroy*(scene: var Scene, pipeline: VkPipeline) = @@ -70,7 +78,7 @@ smallIndexedMeshes: seq[Mesh] bigIndexedMeshes: seq[Mesh] allIndexedMeshes: seq[Mesh] - for mesh in allPartsOfType[Mesh](scene.root): + for mesh in allComponentsOfType[Mesh](scene.root): for inputAttr in pipeline.inputs.vertexInputs: assert mesh.hasDataFor(inputAttr), &"{mesh} missing data for {inputAttr}" case mesh.indexType: @@ -148,11 +156,10 @@ buffer.setData(pdata, size, bufferOffset) bufferOffset += size scene.drawables[pipeline.vk].add drawable - echo scene.getBuffers(pipeline.vk) -proc setupDrawables*(scene: var Scene, renderPass: var RenderPass) = - for subpass in renderPass.subpasses.mitems: - for pipeline in subpass.pipelines.mitems: +proc setupDrawables*(scene: var Scene, renderPass: RenderPass) = + for subpass in renderPass.subpasses: + for pipeline in subpass.pipelines: scene.setupDrawables(pipeline) proc getDrawables*(scene: Scene, pipeline: Pipeline): seq[Drawable] =
--- a/src/semicongine/vulkan/instance.nim Fri Apr 07 00:32:07 2023 +0700 +++ b/src/semicongine/vulkan/instance.nim Sun Apr 09 01:04:54 2023 +0700 @@ -108,6 +108,7 @@ log LEVEL_MAPPING[messageSeverity], &"{toEnums messageTypes}: {pCallbackData.pMessage}" if messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: echo getStackTrace() + quit() return false proc createDebugMessenger*(
--- a/src/semicongine/vulkan/pipeline.nim Fri Apr 07 00:32:07 2023 +0700 +++ b/src/semicongine/vulkan/pipeline.nim Sun Apr 09 01:04:54 2023 +0700 @@ -1,3 +1,6 @@ +import std/tables +import std/sequtils + import ./api import ./device import ./descriptor @@ -16,35 +19,41 @@ descriptorPool*: DescriptorPool descriptorSets*: seq[DescriptorSet] -func inputs*(pipeline: Pipeline): AttributeGroup = +func inputs*(pipeline: Pipeline): seq[ShaderAttribute] = for shader in pipeline.shaders: if shader.stage == VK_SHADER_STAGE_VERTEX_BIT: return shader.inputs +func uniforms*(pipeline: Pipeline): seq[ShaderAttribute] = + var uniformList: Table[string, ShaderAttribute] + for shader in pipeline.shaders: + for attribute in shader.uniforms: + if attribute.name in uniformList: + assert uniformList[attribute.name] == attribute + else: + uniformList[attribute.name] = attribute + result = uniformList.values.toSeq + proc createPipeline*(device: Device, renderPass: VkRenderPass, vertexShader: Shader, fragmentShader: Shader, inFlightFrames: int, subpass = 0'u32): Pipeline = assert renderPass.valid assert device.vk.valid assert vertexShader.stage == VK_SHADER_STAGE_VERTEX_BIT assert fragmentShader.stage == VK_SHADER_STAGE_FRAGMENT_BIT + assert vertexShader.outputs == fragmentShader.inputs + assert vertexShader.uniforms == fragmentShader.uniforms result.device = device result.shaders = @[vertexShader, fragmentShader] - var descriptors = @[Descriptor( - thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - count: 1, - stages: @[VK_SHADER_STAGE_VERTEX_BIT], - itemsize: vertexShader.uniforms.size(), - )] - if vertexShader.uniforms == fragmentShader.uniforms: - descriptors[0].stages.add VK_SHADER_STAGE_FRAGMENT_BIT - else: - descriptors.add Descriptor( + # TODO: correct descriptors over all shaders + var descriptors = @[ + Descriptor( thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, count: 1, - stages: @[VK_SHADER_STAGE_FRAGMENT_BIT], - itemsize: fragmentShader.uniforms.size(), - ) + stages: @[VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT], + itemsize: vertexShader.uniforms.size(), + ), + ] result.descriptorSetLayout = device.createDescriptorSetLayout(descriptors) # TODO: Push constants @@ -151,6 +160,7 @@ ) 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 proc destroy*(pipeline: var Pipeline) = assert pipeline.device.vk.valid
--- a/src/semicongine/vulkan/shader.nim Fri Apr 07 00:32:07 2023 +0700 +++ b/src/semicongine/vulkan/shader.nim Sun Apr 09 01:04:54 2023 +0700 @@ -24,17 +24,17 @@ stage: VkShaderStageFlagBits entrypoint: string binary: seq[uint32] - inputs: AttributeGroup - uniforms: AttributeGroup - outputs: AttributeGroup + inputs: seq[ShaderAttribute] + uniforms: seq[ShaderAttribute] + outputs: seq[ShaderAttribute] Shader* = object device: Device vk*: VkShaderModule stage*: VkShaderStageFlagBits entrypoint*: string - inputs*: AttributeGroup - uniforms*: AttributeGroup - outputs*: AttributeGroup + inputs*: seq[ShaderAttribute] + uniforms*: seq[ShaderAttribute] + outputs*: seq[ShaderAttribute] proc compileGlslToSPIRV(stage: VkShaderStageFlagBits, shaderSource: string, entrypoint: string): seq[uint32] {.compileTime.} = @@ -86,17 +86,17 @@ proc compileGlslShader*( stage: VkShaderStageFlagBits, - inputs=AttributeGroup(), - uniforms=AttributeGroup(), - outputs=AttributeGroup(), + inputs: seq[ShaderAttribute]= @[], + uniforms: seq[ShaderAttribute]= @[], + outputs: seq[ShaderAttribute]= @[], version=DEFAULT_SHADER_VERSION , entrypoint=DEFAULT_SHADER_ENTRYPOINT , body: seq[string] ): ShaderCode {.compileTime.} = var code = @[&"#version {version}", ""] & - (if inputs.attributes.len > 0: inputs.glslInput() & @[""] else: @[]) & - (if uniforms.attributes.len > 0: uniforms.glslUniforms() & @[""] else: @[]) & - (if outputs.attributes.len > 0: outputs.glslOutput() & @[""] else: @[]) & + (if inputs.len > 0: inputs.glslInput() & @[""] else: @[]) & + (if uniforms.len > 0: uniforms.glslUniforms() & @[""] else: @[]) & + (if outputs.len > 0: outputs.glslOutput() & @[""] else: @[]) & @[&"void {entrypoint}(){{"] & body & @[&"}}"] @@ -110,9 +110,9 @@ proc compileGlslShader*( stage: VkShaderStageFlagBits, - inputs: AttributeGroup=AttributeGroup(), - uniforms: AttributeGroup=AttributeGroup(), - outputs: AttributeGroup=AttributeGroup(), + inputs: seq[ShaderAttribute]= @[], + uniforms: seq[ShaderAttribute]= @[], + outputs: seq[ShaderAttribute]= @[], version=DEFAULT_SHADER_VERSION , entrypoint=DEFAULT_SHADER_ENTRYPOINT , body: string @@ -150,7 +150,7 @@ var location = 0'u32 var binding = baseBinding - for attribute in shader.inputs.attributes: + for attribute in shader.inputs.vertexInputs: bindings.add VkVertexInputBindingDescription( binding: binding, stride: attribute.size,
--- a/src/semicongine/vulkan/swapchain.nim Fri Apr 07 00:32:07 2023 +0700 +++ b/src/semicongine/vulkan/swapchain.nim Sun Apr 09 01:04:54 2023 +0700 @@ -1,3 +1,4 @@ +import std/tables import std/options import std/logging @@ -6,13 +7,17 @@ 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 @@ -31,6 +36,7 @@ imageAvailableSemaphore*: seq[Semaphore] renderFinishedSemaphore*: seq[Semaphore] commandBufferPool: CommandBufferPool + uniformBuffers: Table[VkPipeline, seq[Buffer]] proc createSwapchain*( @@ -101,6 +107,47 @@ 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 @@ -220,6 +267,7 @@ 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) @@ -280,6 +328,9 @@ 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() -
--- a/tests/test_vulkan_wrapper.nim Fri Apr 07 00:32:07 2023 +0700 +++ b/tests/test_vulkan_wrapper.nim Sun Apr 09 01:04:54 2023 +0700 @@ -1,4 +1,3 @@ -import std/os import std/options import semicongine @@ -55,21 +54,25 @@ # INIT RENDERER: const - vertexInput = initAttributeGroup( + vertexInput = @[ attr[Vec3f]("position"), attr[Vec3f]("color"), - ) - vertexOutput = initAttributeGroup(attr[Vec3f]("outcolor")) - fragOutput = initAttributeGroup(attr[Vec4f]("color")) + attr[Mat4]("transform", perInstance=true) + ] + vertexOutput = @[attr[Vec3f]("outcolor")] + uniforms = @[attr[float32]("time")] + fragOutput = @[attr[Vec4f]("color")] vertexCode = compileGlslShader( stage=VK_SHADER_STAGE_VERTEX_BIT, inputs=vertexInput, + uniforms=uniforms, outputs=vertexOutput, - body="""gl_Position = vec4(position, 1.0); outcolor = color;""" + body="""gl_Position = vec4(position, 1.0); outcolor = color * sin(Uniforms.time) * 0.5 + 0.5;""" ) fragmentCode = compileGlslShader( stage=VK_SHADER_STAGE_FRAGMENT_BIT, inputs=vertexOutput, + uniforms=uniforms, outputs=fragOutput, body="color = vec4(outcolor, 1);" ) @@ -83,9 +86,11 @@ raise newException(Exception, "Unable to create swapchain") # INIT SCENE + var time = initShaderGlobal("time", 0.0'f32) var thescene = Scene( name: "main", root: newEntity("root", + newEntity("stuff", time), 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)], @@ -119,10 +124,13 @@ ) ) thescene.setupDrawables(renderPass) + swapchain.setupUniforms(thescene) # MAINLOOP echo "Setup successfull, start rendering" - for i in 0 ..< 10000: + for i in 0 ..< 1: + setValue[float32](time.value, get[float32](time.value) + 0.0005) + echo get[float32](time.value) discard swapchain.drawScene(thescene) echo "Rendered ", swapchain.framesRendered, " frames" checkVkResult device.vk.vkDeviceWaitIdle() @@ -143,3 +151,4 @@ device.destroy() debugger.destroy() instance.destroy() + thewindow.destroy()