changeset 1231:70f6c1cfe005

add: incomplete cube demo
author sam <sam@basx.dev>
date Thu, 18 Jul 2024 23:48:57 +0700
parents 51221494caeb
children 32a977c71ba5
files semiconginev2/rendering.nim semiconginev2/rendering/renderer.nim semiconginev2/rendering/shaders.nim tests/test_rendering.nim
diffstat 4 files changed, 148 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- 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
 
--- 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)
--- 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,
--- 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()