Mercurial > games > semicongine
changeset 1252:01e9f41d35b1
add:support for push constants
author | sam <sam@basx.dev> |
---|---|
date | Fri, 26 Jul 2024 23:04:01 +0700 |
parents | 3f98ad20a9d3 |
children | c4f98eb4bb05 |
files | semiconginev2.nim semiconginev2/contrib/settings.nim semiconginev2/gltf.nim semiconginev2/image.nim semiconginev2/rendering.nim semiconginev2/rendering/renderer.nim semiconginev2/rendering/shaders.nim tests/test_rendering.nim |
diffstat | 8 files changed, 86 insertions(+), 34 deletions(-) [+] |
line wrap: on
line diff
--- a/semiconginev2.nim Fri Jul 26 20:34:02 2024 +0700 +++ b/semiconginev2.nim Fri Jul 26 23:04:01 2024 +0700 @@ -55,3 +55,8 @@ include ./semiconginev2/contrib/settings include ./semiconginev2/contrib/algorithms/collision include ./semiconginev2/contrib/algorithms/noise + +if not defined(release): + setLogFilter(lvlAll) +else: + setLogFilter(lvlWarn)
--- a/semiconginev2/contrib/settings.nim Fri Jul 26 20:34:02 2024 +0700 +++ b/semiconginev2/contrib/settings.nim Fri Jul 26 23:04:01 2024 +0700 @@ -1,9 +1,8 @@ -const CONFIGROOT: string = "." -const CONFIGEXTENSION: string = "ini" -# by default enable hot-reload of runtime-configuration only in debug builds -const CONFIGHOTRELOAD: bool = not defined(release) -# milliseconds to wait between checks for settings hotreload -const CONFIGHOTRELOADINTERVAL: int = 1000 +const CONFIGHOTRELOAD {.booldefine.}: bool = not defined(release) +const CONFIGHOTRELOADINTERVAL {.intdefine.}: int = 1000 +const CONFIGROOT {.strdefine.}: string = "." +const CONFIGEXTENSION {.strdefine.}: string = "ini" + when CONFIGHOTRELOAD: var @@ -77,8 +76,6 @@ allsettings = loadAllConfig() when CONFIGHOTRELOAD == true: - import std/times - proc configFileWatchdog() {.thread.} = var configModTimes: Table[string, times.Time] while true: @@ -93,8 +90,3 @@ sleep CONFIGHOTRELOADINTERVAL var thethread: Thread[void] createThread(thethread, configFileWatchdog) - -if not defined(release): - setLogFilter(lvlAll) -else: - setLogFilter(lvlWarn)
--- a/semiconginev2/gltf.nim Fri Jul 26 20:34:02 2024 +0700 +++ b/semiconginev2/gltf.nim Fri Jul 26 23:04:01 2024 +0700 @@ -145,7 +145,7 @@ assert imageType == "image/png", "glTF loader currently only supports PNG" let bufferView = root["bufferViews"][root["images"][imageIndex]["bufferView"].getInt()] - result = LoadImage[BGRA](getBufferViewData(bufferView, mainBuffer)) + result = LoadImageData[BGRA](getBufferViewData(bufferView, mainBuffer)) if textureNode.hasKey("sampler"): let sampler = root["samplers"][textureNode["sampler"].getInt()]
--- a/semiconginev2/image.nim Fri Jul 26 20:34:02 2024 +0700 +++ b/semiconginev2/image.nim Fri Jul 26 23:04:01 2024 +0700 @@ -16,7 +16,7 @@ isRenderTarget*: bool = false samples*: VkSampleCountFlagBits = VK_SAMPLE_COUNT_1_BIT -proc LoadImage*[T: PixelType](pngData: seq[uint8]): Image[T] = +proc LoadImageData*[T: PixelType](pngData: string|seq[uint8]): Image[T] = when T is Gray: let pngType = 0.cint elif T is BGRA: @@ -38,13 +38,13 @@ swap(result.data[i][0], result.data[i][2]) proc LoadImage*[T: PixelType](path: string, package = DEFAULT_PACKAGE): Image[T] = - assert path.splitFile().ext.toLowerAscii == ".png" + assert path.splitFile().ext.toLowerAscii == ".png", "Unsupported image type: " & path.splitFile().ext.toLowerAscii when T is Gray: let pngType = 0.cint elif T is BGRA: let pngType = 6.cint - result = LoadImage[T](loadResource_intern(path, package = package).readAll()) + result = LoadImageData[T](loadResource_intern(path, package = package).readAll()) proc toPNG[T: PixelType](image: Image[T]): seq[uint8] =
--- a/semiconginev2/rendering.nim Fri Jul 26 20:34:02 2024 +0700 +++ b/semiconginev2/rendering.nim Fri Jul 26 23:04:01 2024 +0700 @@ -18,6 +18,7 @@ # custom pragmas to classify shader attributes template VertexAttribute* {.pragma.} template InstanceAttribute* {.pragma.} +template PushConstantAttribute* {.pragma.} template Pass* {.pragma.} template PassFlat* {.pragma.} template ShaderOutput* {.pragma.}
--- a/semiconginev2/rendering/renderer.nim Fri Jul 26 20:34:02 2024 +0700 +++ b/semiconginev2/rendering/renderer.nim Fri Jul 26 23:04:01 2024 +0700 @@ -670,6 +670,38 @@ ) = Render(commandBuffer, pipeline, mesh, EMPTY()) +proc RenderWithPushConstant*[TShader, TMesh, TInstance, TPushConstant]( + commandBuffer: VkCommandBuffer, + pipeline: Pipeline[TShader], + mesh: TMesh, + instances: TInstance, + pushConstant: TPushConstant, +) = + vkCmdPushConstants( + commandBuffer = commandBuffer, + layout = pipeline.layout, + stageFlags = VkShaderStageFlags(VK_SHADER_STAGE_ALL_GRAPHICS), + offset = 0, + size = 128, + pValues = addr(pushConstant) + ); + Render(commandBuffer, pipeline, mesh, instances) +proc RenderWithPushConstant*[TShader, TMesh, TPushConstant]( + commandBuffer: VkCommandBuffer, + pipeline: Pipeline[TShader], + mesh: TMesh, + pushConstant: TPushConstant, +) = + vkCmdPushConstants( + commandBuffer = commandBuffer, + layout = pipeline.layout, + stageFlags = VkShaderStageFlags(VK_SHADER_STAGE_ALL_GRAPHICS), + offset = 0, + size = 128, + pValues = addr(pushConstant) + ); + Render(commandBuffer, pipeline, mesh, EMPTY()) + proc asGPUArray*[T](data: openArray[T], bufferType: static BufferType): auto = GPUArray[T, bufferType](data: @data)
--- a/semiconginev2/rendering/shaders.nim Fri Jul 26 20:34:02 2024 +0700 +++ b/semiconginev2/rendering/shaders.nim Fri Jul 26 23:04:01 2024 +0700 @@ -131,6 +131,7 @@ var fsInput: seq[string] var fsOutput: seq[string] var uniforms: seq[string] + var pushConstants: seq[string] var samplers: seq[string] var vsInputLocation = 0'u32 var passLocation = 0 @@ -213,12 +214,22 @@ descriptorSetIndex.inc elif fieldname in ["vertexCode", "fragmentCode"]: discard + elif hasCustomPragma(value, PushConstantAttribute): + assert pushConstants.len == 0, "Only one push constant value allowed" + assert value is object, "push constants need to be objects" + pushConstants.add "layout( push_constant ) uniform constants" + pushConstants.add "{" + for constFieldName, constFieldValue in value.fieldPairs(): + assert typeof(constFieldValue) is SupportedGPUType, "push constant field '" & constFieldName & "' is not a SupportedGPUType" + pushConstants.add " " & GlslType(constFieldValue) & " " & constFieldName & ";" + pushConstants.add "} " & fieldname & ";" else: {.error: "Unsupported shader field '" & typetraits.name(TShader) & "." & fieldname & "' of type " & typetraits.name(typeof(value)).} result[0] = (@[&"#version {GLSL_VERSION}", "#extension GL_EXT_scalar_block_layout : require", ""] & vsInput & uniforms & + pushConstants & samplers & vsOutput & @[shader.vertexCode]).join("\n") @@ -226,6 +237,7 @@ result[1] = (@[&"#version {GLSL_VERSION}", "#extension GL_EXT_scalar_block_layout : require", ""] & fsInput & uniforms & + pushConstants & samplers & fsOutput & @[shader.fragmentCode]).join("\n") @@ -360,12 +372,19 @@ var nSets = GetDescriptorSetCount[TShader]() result.descriptorSetLayouts = CreateDescriptorSetLayouts[TShader]() + + let pushConstant = VkPushConstantRange( + stageFlags: VkShaderStageFlags(VK_SHADER_STAGE_ALL_GRAPHICS), + offset: 0, + size: 128, # currently supported everywhere, places for two mat4 + ) + let pipelineLayoutInfo = VkPipelineLayoutCreateInfo( sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, setLayoutCount: nSets, pSetLayouts: if nSets == 0: nil else: result.descriptorSetLayouts.ToCPointer, - # pushConstantRangeCount: uint32(pushConstants.len), - # pPushConstantRanges: pushConstants.ToCPointer, + pushConstantRangeCount: 1, + pPushConstantRanges: addr(pushConstant), ) checkVkResult vkCreatePipelineLayout(vulkan.device, addr(pipelineLayoutInfo), nil, addr(result.layout))
--- a/tests/test_rendering.nim Fri Jul 26 20:34:02 2024 +0700 +++ b/tests/test_rendering.nim Fri Jul 26 23:04:01 2024 +0700 @@ -11,15 +11,18 @@ var renderdata = InitRenderData() type + PushConstant = object + scale: float32 Shader = object position {.VertexAttribute.}: Vec3f color {.VertexAttribute.}: Vec3f + pushConstant {.PushConstantAttribute.}: PushConstant fragmentColor {.Pass.}: Vec3f outColor {.ShaderOutput.}: Vec4f # code vertexCode: string = """void main() { fragmentColor = color; - gl_Position = vec4(position, 1);}""" + gl_Position = vec4(position * pushConstant.scale, 1);}""" fragmentCode: string = """void main() { outColor = vec4(fragmentColor, 1);}""" TriangleMesh = object @@ -43,7 +46,7 @@ WithPipeline(commandbuffer, pipeline): - Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = mesh) + RenderWithPushConstant(commandbuffer = commandbuffer, pipeline = pipeline, mesh = mesh, pushConstant = PushConstant(scale: 0.3 + ((getMonoTime() - start).inMilliseconds().int / 1000))) # cleanup checkVkResult vkDeviceWaitIdle(vulkan.device) @@ -133,7 +136,7 @@ Uniforms = object material: GPUValue[Material, UniformBuffer] - texture1: Image[RGBA] + texture1: Image[BGRA] QuadShader = object position {.VertexAttribute.}: Vec3f @@ -154,10 +157,10 @@ position: GPUArray[Vec3f, VertexBuffer] indices: GPUArray[uint16, IndexBuffer] - let R = RGBA([255'u8, 0'u8, 0'u8, 255'u8]) - let G = RGBA([0'u8, 255'u8, 0'u8, 255'u8]) - let B = RGBA([0'u8, 0'u8, 255'u8, 255'u8]) - let W = RGBA([255'u8, 255'u8, 255'u8, 255'u8]) + let R = BGRA([255'u8, 0'u8, 0'u8, 255'u8]) + let G = BGRA([0'u8, 255'u8, 0'u8, 255'u8]) + let B = BGRA([0'u8, 0'u8, 255'u8, 255'u8]) + let W = BGRA([255'u8, 255'u8, 255'u8, 255'u8]) var quad = QuadMesh( position: asGPUArray([NewVec3f(-0.5, -0.5), NewVec3f(-0.5, 0.5), NewVec3f(0.5, 0.5), NewVec3f(0.5, -0.5)], VertexBuffer), @@ -166,13 +169,13 @@ uniforms1 = asDescriptorSet( Uniforms( material: asGPUValue(Material(baseColor: NewVec3f(1, 1, 1)), UniformBuffer), - texture1: Image[RGBA](width: 3, height: 3, data: @[R, G, B, G, B, R, B, R, G], interpolation: VK_FILTER_NEAREST), + texture1: Image[BGRA](width: 3, height: 3, data: @[R, G, B, G, B, R, B, R, G], minInterpolation: VK_FILTER_NEAREST, magInterpolation: VK_FILTER_NEAREST), ) ) uniforms2 = asDescriptorSet( Uniforms( material: asGPUValue(Material(baseColor: NewVec3f(0.5, 0.5, 0.5)), UniformBuffer), - texture1: Image[RGBA](width: 2, height: 2, data: @[R, G, B, W]), + texture1: Image[BGRA](width: 2, height: 2, data: @[R, G, B, W]), ) ) @@ -271,8 +274,8 @@ asGPUValue(Material(baseColor: NewVec3f(1, 0, 1)), UniformBuffer), ], texture1: [ - Image[Gray](width: 2, height: 2, data: @[W, G, G, W], interpolation: VK_FILTER_NEAREST), - Image[Gray](width: 3, height: 3, data: @[W, G, W, G, W, G, W, G, W], interpolation: VK_FILTER_NEAREST), + Image[Gray](width: 2, height: 2, data: @[W, G, G, W], minInterpolation: VK_FILTER_NEAREST, magInterpolation: VK_FILTER_NEAREST), + Image[Gray](width: 3, height: 3, data: @[W, G, W, G, W, G, W, G, W], minInterpolation: VK_FILTER_NEAREST, magInterpolation: VK_FILTER_NEAREST), ], ), ) @@ -522,7 +525,7 @@ type Uniforms = object - texture1: Image[RGBA] + texture1: Image[BGRA] Shader = object position {.VertexAttribute.}: Vec3f uv {.VertexAttribute.}: Vec2f @@ -558,7 +561,7 @@ var pipeline = CreatePipeline[Shader](renderPass = vulkan.swapchain.renderPass) var uniforms1 = asDescriptorSet( Uniforms( - texture1: LoadImage[RGBA]("art.png"), + texture1: LoadImage[BGRA]("art.png"), ) ) UploadImages(renderdata, uniforms1) @@ -590,7 +593,7 @@ type Uniforms = object - frameTexture: Image[RGBA] + frameTexture: Image[BGRA] TriangleShader = object position {.VertexAttribute.}: Vec3f color {.VertexAttribute.}: Vec3f @@ -639,7 +642,7 @@ ) var uniforms1 = asDescriptorSet( Uniforms( - frameTexture: Image[RGBA](width: vulkan.swapchain.width, height: vulkan.swapchain.height, isRenderTarget: true), + frameTexture: Image[BGRA](width: vulkan.swapchain.width, height: vulkan.swapchain.height, isRenderTarget: true), ) ) AssignBuffers(renderdata, mesh)