# HG changeset patch # User sam # Date 1721321337 -25200 # Node ID 70f6c1cfe005a4bd2ee9f3cd428334166484046b # Parent 51221494caeb30b3cb48633c5659f7e48ba5d453 add: incomplete cube demo diff -r 51221494caeb -r 70f6c1cfe005 semiconginev2/rendering.nim --- a/semiconginev2/rendering.nim Fri Jul 19 04:49:18 2024 +0700 +++ b/semiconginev2/rendering.nim Thu Jul 18 23:48:57 2024 +0700 @@ -116,6 +116,8 @@ size: uint64 rawPointer: pointer # if not nil, buffer is using mapped memory offsetNextFree: uint64 + memoryOffset: uint64 + memory: VkDeviceMemory Image*[T: PixelType] = object width*: uint32 height*: uint32 @@ -132,7 +134,7 @@ offset*: uint64 GPUValue*[T: object, TBuffer: static BufferType] = object data*: T - buffer: Buffer + buffer*: Buffer offset: uint64 GPUData = GPUArray | GPUValue diff -r 51221494caeb -r 70f6c1cfe005 semiconginev2/rendering/renderer.nim --- a/semiconginev2/rendering/renderer.nim Fri Jul 19 04:49:18 2024 +0700 +++ b/semiconginev2/rendering/renderer.nim Thu Jul 18 23:48:57 2024 +0700 @@ -216,6 +216,15 @@ ppData = addr(result.rawPointer) ) +proc FlushBuffer*(buffer: Buffer) = + var flushRegion = VkMappedMemoryRange( + sType: VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + memory: buffer.memory, + offset: buffer.memoryOffset, + size: buffer.size, + ) + checkVkResult vkFlushMappedMemoryRanges(vulkan.device, 1, addr(flushRegion)) + proc FlushAllMemory*(renderData: RenderData) = var flushRegions = newSeq[VkMappedMemoryRange]() for memoryBlocks in renderData.memory: @@ -265,14 +274,18 @@ selectedBlock.vk, selectedBlock.offsetNextFree, ) + result.memory = selectedBlock.vk + result.memoryOffset = selectedBlock.offsetNextFree result.rawPointer = selectedBlock.rawPointer.pointerAddOffset(selectedBlock.offsetNextFree) renderData.memory[memoryType][selectedBlockI].offsetNextFree += memoryRequirements.size -proc UpdateGPUBuffer*(gpuData: GPUData) = +proc UpdateGPUBuffer*(gpuData: GPUData, flush = false) = if gpuData.size == 0: return when NeedsMapping(gpuData): copyMem(pointerAddOffset(gpuData.buffer.rawPointer, gpuData.offset), gpuData.rawPointer, gpuData.size) + if flush: + FlushBuffer(gpuData.buffer) else: WithStagingBuffer((gpuData.buffer.vk, gpuData.offset), gpuData.size, stagingPtr): copyMem(stagingPtr, gpuData.rawPointer, gpuData.size) diff -r 51221494caeb -r 70f6c1cfe005 semiconginev2/rendering/shaders.nim --- a/semiconginev2/rendering/shaders.nim Fri Jul 19 04:49:18 2024 +0700 +++ b/semiconginev2/rendering/shaders.nim Thu Jul 18 23:48:57 2024 +0700 @@ -347,7 +347,7 @@ renderPass: RenderPass, topology: VkPrimitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, polygonMode: VkPolygonMode = VK_POLYGON_MODE_FILL, - cullMode: VkCullModeFlagBits = VK_CULL_MODE_BACK_BIT, + cullMode: openArray[VkCullModeFlagBits] = [VK_CULL_MODE_BACK_BIT], frontFace: VkFrontFace = VK_FRONT_FACE_CLOCKWISE, descriptorPoolLimit = 1024, ): Pipeline[TShader] = @@ -428,7 +428,7 @@ rasterizerDiscardEnable: VK_FALSE, polygonMode: polygonMode, lineWidth: 1.0, - cullMode: toBits [cullMode], + cullMode: toBits cullMode, frontFace: frontFace, depthBiasEnable: VK_FALSE, depthBiasConstantFactor: 0.0, diff -r 51221494caeb -r 70f6c1cfe005 tests/test_rendering.nim --- a/tests/test_rendering.nim Fri Jul 19 04:49:18 2024 +0700 +++ b/tests/test_rendering.nim Thu Jul 18 23:48:57 2024 +0700 @@ -1,3 +1,4 @@ +import std/sequtils import std/options import std/random @@ -311,7 +312,122 @@ DestroyPipeline(pipeline) DestroyRenderData(renderdata) -proc test_05_triangle_2pass(nFrames: int, depthBuffer: bool, samples: VkSampleCountFlagBits) = +proc test_05_cube(nFrames: int, swapchain: var Swapchain) = + type + + UniformData = object + m: Mat4 + Uniforms = object + data: GPUValue[UniformData, UniformBufferMapped] + CubeShader = object + position {.VertexAttribute.}: Vec3f + color {.VertexAttribute.}: Vec4f + fragmentColor {.Pass.}: Vec4f + outColor {.ShaderOutput.}: Vec4f + descriptorSets {.DescriptorSets.}: (Uniforms, ) + # code + vertexCode = """void main() { + fragmentColor = color; + gl_Position = data.m * vec4(position, 1); +}""" + fragmentCode = """void main() { + outColor = fragmentColor; +}""" + Mesh = object + position: GPUArray[Vec3f, VertexBuffer] + normals: GPUArray[Vec3f, VertexBuffer] + color: GPUArray[Vec4f, VertexBuffer] + + let quad = @[ + NewVec3f(-0.5, -0.5), NewVec3f(-0.5, +0.5), NewVec3f(+0.5, +0.5), + NewVec3f(+0.5, +0.5), NewVec3f(+0.5, -0.5), NewVec3f(-0.5, -0.5), + ] + proc transf(data: seq[Vec3f], m: Mat4): seq[Vec3f] = + for v in data: + result.add m * v + + var + vertices: seq[Vec3f] + colors: seq[Vec4f] + normals: seq[Vec3f] + + # front, red + vertices.add quad.transf(Translate(0, 0, -0.5)) + colors.add newSeqWith(6, NewVec4f(1, 0, 0, 1)) + normals.add newSeqWith(6, NewVec3f(0, 0, -1)) + + # back, cyan + vertices.add quad.transf(Rotate(PI, Y) * Translate(0, 0, -0.5)) + colors.add newSeqWith(6, NewVec4f(0, 1, 1, 1)) + normals.add newSeqWith(6, NewVec3f(0, 0, 1)) + + # right, green + vertices.add quad.transf(Rotate(PI / 2, Y) * Translate(0, 0, -0.5)) + colors.add newSeqWith(6, NewVec4f(0, 1, 0, 1)) + normals.add newSeqWith(6, NewVec3f(-1, 0, 0)) + + # left, magenta + vertices.add quad.transf(Rotate(-PI / 2, Y) * Translate(0, 0, -0.5)) + colors.add newSeqWith(6, NewVec4f(1, 0, 1, 1)) + normals.add newSeqWith(6, NewVec3f(1, 0, 0)) + + # bottom, blue + vertices.add quad.transf(Rotate(PI / 2, X) * Translate(0, 0, -0.5)) + colors.add newSeqWith(6, NewVec4f(0, 0, 1, 1)) + normals.add newSeqWith(6, NewVec3f(0, -1, 0)) + + # top, yellow + vertices.add quad.transf(Rotate(-PI / 2, X) * Translate(0, 0, -0.5)) + colors.add newSeqWith(6, NewVec4f(1, 1, 0, 1)) + normals.add newSeqWith(6, NewVec3f(0, 1, 0)) + + var renderdata = InitRenderData() + + var mesh = Mesh( + position: asGPUArray(vertices, VertexBuffer), + color: asGPUArray(colors, VertexBuffer), + normals: asGPUArray(normals, VertexBuffer), + ) + AssignBuffers(renderdata, mesh) + + var floor = Mesh( + position: asGPUArray(quad.transf(Scale(10, 10, 10) * Rotate(-PI / 2, X) * Translate(0, 0, 0.05)), VertexBuffer), + color: asGPUArray(newSeqWith(6, NewVec4f(0.1, 0.1, 0.1, 1)), VertexBuffer), + normals: asGPUArray(newSeqWith(6, Y), VertexBuffer), + ) + AssignBuffers(renderdata, floor) + + var uniforms1 = asDescriptorSet( + Uniforms( + data: asGPUValue(UniformData(m: Unit4), UniformBufferMapped) + ) + ) + AssignBuffers(renderdata, uniforms1) + + renderdata.FlushAllMemory() + + var pipeline = CreatePipeline[CubeShader](renderPass = swapchain.renderPass) + InitDescriptorSet(renderdata, pipeline.descriptorSetLayouts[0], uniforms1) + + var c = 0 + while UpdateInputs() and c < nFrames: + + uniforms1.data.data.data.m = Translate(0, 0, -2) * Rotate(PI * 2 * c.float32 / nFrames.float32, Y) * Rotate(-PI / 4, X) * Perspective(-PI / 2, GetAspectRatio(swapchain), 0.01, 100) + UpdateGPUBuffer(uniforms1.data.data, flush = true) + WithNextFrame(swapchain, framebuffer, commandbuffer): + WithRenderPass(swapchain.renderPass, framebuffer, commandbuffer, swapchain.width, swapchain.height, NewVec4f(0, 0, 0, 0)): + WithPipeline(commandbuffer, pipeline): + WithBind(commandbuffer, (uniforms1, ), pipeline, swapchain.currentFiF): + Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = mesh) + Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = floor) + inc c + + # cleanup + checkVkResult vkDeviceWaitIdle(vulkan.device) + DestroyPipeline(pipeline) + DestroyRenderData(renderdata) + +proc test_06_triangle_2pass(nFrames: int, depthBuffer: bool, samples: VkSampleCountFlagBits) = var (offscreenRP, presentRP) = CreateIndirectPresentationRenderPass(depthBuffer = depthBuffer, samples = samples) swapchain = InitSwapchain(renderpass = presentRP).get() @@ -493,15 +609,15 @@ DestroySwapchain(swapchain) when isMainModule: - var nFrames = 1000 + var nFrames = 3000 InitVulkan() var mainRenderpass: RenderPass var renderPasses = [ - (depthBuffer: false, samples: VK_SAMPLE_COUNT_1_BIT), - (depthBuffer: false, samples: VK_SAMPLE_COUNT_4_BIT), + # (depthBuffer: false, samples: VK_SAMPLE_COUNT_1_BIT), + # (depthBuffer: false, samples: VK_SAMPLE_COUNT_4_BIT), (depthBuffer: true, samples: VK_SAMPLE_COUNT_1_BIT), - (depthBuffer: true, samples: VK_SAMPLE_COUNT_4_BIT), + # (depthBuffer: true, samples: VK_SAMPLE_COUNT_4_BIT), ] # test normal @@ -509,6 +625,7 @@ var renderpass = CreateDirectPresentationRenderPass(depthBuffer = depthBuffer, samples = samples) var swapchain = InitSwapchain(renderpass = renderpass).get() + #[ # tests a simple triangle with minimalistic shader and vertex format test_01_triangle(nFrames, swapchain) @@ -520,13 +637,18 @@ # tests multiple descriptor sets and arrays test_04_multiple_descriptorsets(nFrames, swapchain) + ]# + + # rotating cube + while true: + test_05_cube(nFrames, swapchain) checkVkResult vkDeviceWaitIdle(vulkan.device) vkDestroyRenderPass(vulkan.device, renderpass.vk, nil) DestroySwapchain(swapchain) # test multiple render passes - for i, (depthBuffer, samples) in renderPasses: - test_05_triangle_2pass(nFrames, depthBuffer, samples) + # for i, (depthBuffer, samples) in renderPasses: + # test_06_triangle_2pass(nFrames, depthBuffer, samples) DestroyVulkan()