changeset 1240:42eeb59f3a43

add: more tests, line and point rendering
author sam <sam@basx.dev>
date Mon, 22 Jul 2024 12:42:35 +0700
parents 69489a678141
children a0ed1a918fda
files semiconginev2/rendering.nim semiconginev2/rendering/renderer.nim semiconginev2/rendering/shaders.nim semiconginev2/text/textbox.nim tests/test_rendering.nim tests/test_text.nim
diffstat 6 files changed, 113 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/semiconginev2/rendering.nim	Mon Jul 22 00:46:10 2024 +0700
+++ b/semiconginev2/rendering.nim	Mon Jul 22 12:42:35 2024 +0700
@@ -302,6 +302,11 @@
     )
     deviceExtensionsC = allocCStringArray(deviceExtensions)
   defer: deallocCStringArray(deviceExtensionsC)
+  let enabledFeatures = VkPhysicalDeviceFeatures(
+   fillModeNonSolid: true,
+   wideLines: true,
+   largePoints: true,
+  )
   var createDeviceInfo = VkDeviceCreateInfo(
     sType: VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
     queueCreateInfoCount: 1,
@@ -310,7 +315,7 @@
     ppEnabledLayerNames: nil,
     enabledExtensionCount: uint32(deviceExtensions.len),
     ppEnabledExtensionNames: deviceExtensionsC,
-    pEnabledFeatures: nil,
+    pEnabledFeatures: addr(enabledFeatures),
   )
   checkVkResult vkCreateDevice(
     physicalDevice = vulkan.physicalDevice,
--- a/semiconginev2/rendering/renderer.nim	Mon Jul 22 00:46:10 2024 +0700
+++ b/semiconginev2/rendering/renderer.nim	Mon Jul 22 12:42:35 2024 +0700
@@ -304,7 +304,6 @@
   renderdata: var RenderData,
   bufferType: BufferType,
   size: uint64,
-  needsFrameInFlight = -1
 ): (Buffer, uint64) =
 
   # find buffer that has space
@@ -312,9 +311,8 @@
 
   for i in 0 ..< renderData.buffers[bufferType].len:
     let buffer = renderData.buffers[bufferType][i]
-    if needsFrameInFlight == -1 or buffer.useForFrameInFlight == needsFrameInFlight:
-      if buffer.size - alignedTo(buffer.offsetNextFree, BUFFER_ALIGNMENT) >= size:
-        selectedBufferI = i
+    if buffer.size - alignedTo(buffer.offsetNextFree, BUFFER_ALIGNMENT) >= size:
+      selectedBufferI = i
 
   # otherwise create new buffer
   if selectedBufferI < 0:
@@ -323,8 +321,6 @@
       size = max(size, BUFFER_ALLOCATION_SIZE),
       bufferType = bufferType,
     )
-    if needsFrameInFlight >= 0:
-      renderdata.buffers[bufferType][selectedBufferI].useForFrameInFlight = needsFrameInFlight
 
   # assigne value
   let selectedBuffer = renderdata.buffers[bufferType][selectedBufferI]
--- a/semiconginev2/rendering/shaders.nim	Mon Jul 22 00:46:10 2024 +0700
+++ b/semiconginev2/rendering/shaders.nim	Mon Jul 22 12:42:35 2024 +0700
@@ -349,7 +349,7 @@
   polygonMode: VkPolygonMode = VK_POLYGON_MODE_FILL,
   cullMode: openArray[VkCullModeFlagBits] = [VK_CULL_MODE_BACK_BIT],
   frontFace: VkFrontFace = VK_FRONT_FACE_CLOCKWISE,
-  descriptorPoolLimit = 1024,
+  lineWidth = 1'f32,
 ): Pipeline[TShader] =
   # create pipeline
 
@@ -427,7 +427,7 @@
       depthClampEnable: VK_FALSE,
       rasterizerDiscardEnable: VK_FALSE,
       polygonMode: polygonMode,
-      lineWidth: 1.0,
+      lineWidth: lineWidth,
       cullMode: toBits cullMode,
       frontFace: frontFace,
       depthBiasEnable: VK_FALSE,
@@ -457,7 +457,7 @@
     )
     colorBlendAttachment = VkPipelineColorBlendAttachmentState(
       colorWriteMask: toBits [VK_COLOR_COMPONENT_R_BIT, VK_COLOR_COMPONENT_G_BIT, VK_COLOR_COMPONENT_B_BIT, VK_COLOR_COMPONENT_A_BIT],
-      blendEnable: VK_TRUE,
+      blendEnable: true,
       srcColorBlendFactor: VK_BLEND_FACTOR_SRC_ALPHA,
       dstColorBlendFactor: VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
       colorBlendOp: VK_BLEND_OP_ADD,
@@ -468,8 +468,10 @@
     colorBlending = VkPipelineColorBlendStateCreateInfo(
       sType: VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
       logicOpEnable: false,
+      logicOp: VK_LOGIC_OP_COPY,
       attachmentCount: 1,
       pAttachments: addr(colorBlendAttachment),
+      blendConstants: [0'f32, 0'f32, 0'f32, 0'f32]
     )
     dynamicStates = [VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR]
     dynamicState = VkPipelineDynamicStateCreateInfo(
--- a/semiconginev2/text/textbox.nim	Mon Jul 22 00:46:10 2024 +0700
+++ b/semiconginev2/text/textbox.nim	Mon Jul 22 12:42:35 2024 +0700
@@ -47,7 +47,7 @@
     of Top: 0'f32
     of Center: -height / 2
     of Bottom: -height
-  ) - textbox.font.capHeight
+  ) + textbox.font.capHeight
 
   var
     offsetX = 0'f32
--- a/tests/test_rendering.nim	Mon Jul 22 00:46:10 2024 +0700
+++ b/tests/test_rendering.nim	Mon Jul 22 12:42:35 2024 +0700
@@ -433,7 +433,6 @@
     let looptime = tEndLoop - tStartLoop
     let waitTime = 16_666 - looptime.inMicroseconds
     if waitTime > 0:
-      echo "sleep ", waitTime / 1000
       sleep((waitTime / 1000).int)
 
   # cleanup
@@ -441,7 +440,64 @@
   DestroyPipeline(pipeline)
   DestroyRenderData(renderdata)
 
-proc test_06_triangle_2pass(time: float32, depthBuffer: bool, samples: VkSampleCountFlagBits) =
+proc test_06_different_draw_modes(time: float32) =
+  var renderdata = InitRenderData()
+
+  type
+    Shader = object
+      position {.VertexAttribute.}: Vec3f
+      color {.VertexAttribute.}: Vec3f
+      fragmentColor {.Pass.}: Vec3f
+      outColor {.ShaderOutput.}: Vec4f
+      # code
+      vertexCode: string = """void main() {
+      gl_PointSize = 100;
+      fragmentColor = color;
+      gl_Position = vec4(position, 1);}"""
+      fragmentCode: string = """void main() {
+      outColor = vec4(fragmentColor, 1);}"""
+    TriangleMesh = object
+      position: GPUArray[Vec3f, VertexBuffer]
+      color: GPUArray[Vec3f, VertexBuffer]
+  var triangle = TriangleMesh(
+    position: asGPUArray([NewVec3f(-0.5, -0.5), NewVec3f(0, 0.5), NewVec3f(0.5, -0.5)], VertexBuffer),
+    color: asGPUArray([NewVec3f(0, 0, 1), NewVec3f(0, 1, 0), NewVec3f(1, 0, 0)], VertexBuffer),
+  )
+  var lines = TriangleMesh(
+    position: asGPUArray([NewVec3f(-0.9, 0), NewVec3f(-0.05, -0.9), NewVec3f(0.05, -0.9), NewVec3f(0.9, 0)], VertexBuffer),
+    color: asGPUArray([NewVec3f(1, 1, 0), NewVec3f(1, 1, 0), NewVec3f(0, 1, 0), NewVec3f(0, 1, 0)], VertexBuffer),
+  )
+  AssignBuffers(renderdata, triangle)
+  AssignBuffers(renderdata, lines)
+  renderdata.FlushAllMemory()
+
+  var pipeline1 = CreatePipeline[Shader](renderPass = vulkan.swapchain.renderPass, polygonMode = VK_POLYGON_MODE_LINE, lineWidth = 20'f32)
+  var pipeline2 = CreatePipeline[Shader](renderPass = vulkan.swapchain.renderPass, polygonMode = VK_POLYGON_MODE_POINT)
+  var pipeline3 = CreatePipeline[Shader](renderPass = vulkan.swapchain.renderPass, topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST, lineWidth = 5)
+  var pipeline4 = CreatePipeline[Shader](renderPass = vulkan.swapchain.renderPass, topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
+
+  var start = getMonoTime()
+  while ((getMonoTime() - start).inMilliseconds().int / 1000) < time:
+    WithNextFrame(framebuffer, commandbuffer):
+      WithRenderPass(vulkan.swapchain.renderPass, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, NewVec4f(0, 0, 0, 0)):
+        WithPipeline(commandbuffer, pipeline1):
+          Render(commandbuffer = commandbuffer, pipeline = pipeline1, mesh = triangle)
+        WithPipeline(commandbuffer, pipeline2):
+          Render(commandbuffer = commandbuffer, pipeline = pipeline2, mesh = triangle)
+        WithPipeline(commandbuffer, pipeline3):
+          Render(commandbuffer = commandbuffer, pipeline = pipeline3, mesh = lines)
+        WithPipeline(commandbuffer, pipeline4):
+          Render(commandbuffer = commandbuffer, pipeline = pipeline4, mesh = lines)
+
+  # cleanup
+  checkVkResult vkDeviceWaitIdle(vulkan.device)
+  DestroyPipeline(pipeline1)
+  DestroyPipeline(pipeline2)
+  DestroyPipeline(pipeline3)
+  DestroyPipeline(pipeline4)
+  DestroyRenderData(renderdata)
+
+proc test_07_triangle_2pass(time: float32, depthBuffer: bool, samples: VkSampleCountFlagBits) =
   var (offscreenRP, presentRP) = CreateIndirectPresentationRenderPass(depthBuffer = depthBuffer, samples = samples)
 
   SetupSwapchain(renderpass = presentRP)
@@ -580,7 +636,6 @@
       attachments = @[msaaImageView, depthImageView, uniforms1.data.frameTexture.imageview]
     else:
       attachments = @[msaaImageView, uniforms1.data.frameTexture.imageview]
-  echo attachments
   var offscreenFB = svkCreateFramebuffer(
     offscreenRP.vk,
     vulkan.swapchain.width,
@@ -633,6 +688,7 @@
      (depthBuffer: true, samples: VK_SAMPLE_COUNT_4_BIT),
   ]
 
+
   # test normal
   for i, (depthBuffer, samples) in renderPasses:
     var renderpass = CreateDirectPresentationRenderPass(depthBuffer = depthBuffer, samples = samples)
@@ -653,12 +709,15 @@
     # rotating cube
     test_05_cube(time)
 
+    # different draw modes (lines, points, and topologies)
+    test_06_different_draw_modes(time)
+
     checkVkResult vkDeviceWaitIdle(vulkan.device)
     vkDestroyRenderPass(vulkan.device, renderpass.vk, nil)
     ClearSwapchain()
 
   # test multiple render passes
   for i, (depthBuffer, samples) in renderPasses:
-    test_06_triangle_2pass(time, depthBuffer, samples)
+    test_07_triangle_2pass(time, depthBuffer, samples)
 
   DestroyVulkan()
--- a/tests/test_text.nim	Mon Jul 22 00:46:10 2024 +0700
+++ b/tests/test_text.nim	Mon Jul 22 12:42:35 2024 +0700
@@ -1,4 +1,5 @@
 import std/os
+import std/algorithm
 import std/strutils
 import std/sequtils
 import std/monotimes
@@ -160,10 +161,41 @@
   DestroyRenderData(renderdata)
 
 proc test_04_lots_of_texts(time: float32) =
-  discard # TODO
+  var renderdata = InitRenderData()
+
+  var pipeline = CreatePipeline[DefaultFontShader](renderPass = vulkan.swapchain.renderPass)
+
+  var font = LoadFont("DejaVuSans.ttf", lineHeightPixels = 160)
+  var labels: seq[Textbox]
+  for i in 0 ..< 100:
+    labels.add InitTextbox(
+      renderdata,
+      pipeline.descriptorSetLayouts[0],
+      font,
+      $i,
+      color = NewVec4f(rand(0.5 .. 1.0), rand(0.5 .. 1.0), rand(0.5 .. 1.0), rand(0.5 .. 1.0)),
+      scale = rand(0.0002 .. 0.002),
+      position = NewVec3f(rand(-0.5 .. 0.5), rand(-0.5 .. 0.5), rand(-0.1 .. 0.1))
+    )
+  labels = labels.sortedByIt(-it.Position.z)
+
+  var start = getMonoTime()
+  while ((getMonoTime() - start).inMilliseconds().int / 1000) < time:
+    for l in labels.mitems:
+      l.Refresh()
+    WithNextFrame(framebuffer, commandbuffer):
+      WithRenderPass(vulkan.swapchain.renderPass, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, NewVec4f(0, 0, 0, 0)):
+        WithPipeline(commandbuffer, pipeline):
+          for l in labels:
+            Render(l, commandbuffer, pipeline)
+
+        # cleanup
+  checkVkResult vkDeviceWaitIdle(vulkan.device)
+  DestroyPipeline(pipeline)
+  DestroyRenderData(renderdata)
 
 when isMainModule:
-  var time = 10'f32
+  var time = 1000'f32
   InitVulkan()
 
   var renderpass = CreateDirectPresentationRenderPass(depthBuffer = true)
@@ -172,7 +204,8 @@
   # tests a simple triangle with minimalistic shader and vertex format
   # test_01_static_label(time, swapchain)
   # test_02_multiple_animated(time)
-  test_03_layouting(time)
+  # test_03_layouting(time)
+  test_04_lots_of_texts(time)
 
 
   checkVkResult vkDeviceWaitIdle(vulkan.device)