Mercurial > games > semicongine
changeset 1239:69489a678141
add: better syncing, better swapchain access, correct font offset, two font-rendering tests
author | sam <sam@basx.dev> |
---|---|
date | Mon, 22 Jul 2024 00:46:10 +0700 |
parents | 03634915bbdb |
children | 42eeb59f3a43 |
files | semiconginev2/rendering.nim semiconginev2/rendering/renderer.nim semiconginev2/rendering/swapchain.nim semiconginev2/rendering/vulkan_wrappers.nim semiconginev2/text/textbox.nim tests/test_rendering.nim tests/test_text.nim |
diffstat | 7 files changed, 247 insertions(+), 146 deletions(-) [+] |
line wrap: on
line diff
--- a/semiconginev2/rendering.nim Sun Jul 21 11:31:11 2024 +0700 +++ b/semiconginev2/rendering.nim Mon Jul 22 00:46:10 2024 +0700 @@ -42,6 +42,8 @@ graphicsQueueFamily*: uint32 graphicsQueue*: VkQueue debugMessenger: VkDebugUtilsMessengerEXT + # populated through the InitSwapchain proc + swapchain*: Swapchain # unclear as of yet anisotropy*: float32 = 0 # needs to be enable during device creation Renderpass* = ref object @@ -80,8 +82,6 @@ var vulkan*: VulkanGlobals var fullscreen: bool -func currentFiF*(swapchain: Swapchain): int = swapchain.currentFiF - type # type aliases SupportedGPUType = float32 | float64 | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | TVec2[int32] | TVec2[int64] | TVec3[int32] | TVec3[int64] | TVec4[int32] | TVec4[int64] | TVec2[uint32] | TVec2[uint64] | TVec3[uint32] | TVec3[uint64] | TVec4[uint32] | TVec4[uint64] | TVec2[float32] | TVec2[float64] | TVec3[float32] | TVec3[float64] | TVec4[float32] | TVec4[float64] | TMat2[float32] | TMat2[float64] | TMat23[float32] | TMat23[float64] | TMat32[float32] | TMat32[float64] | TMat3[float32] | TMat3[float64] | TMat34[float32] | TMat34[float64] | TMat43[float32] | TMat43[float64] | TMat4[float32] | TMat4[float64] @@ -320,7 +320,18 @@ ) vulkan.graphicsQueue = svkGetDeviceQueue(vulkan.device, vulkan.graphicsQueueFamily, VK_QUEUE_GRAPHICS_BIT) +proc ClearSwapchain*() = + assert vulkan.swapchain != nil, "Swapchain has not been initialized yet" + DestroySwapchain(vulkan.swapchain) + vulkan.swapchain = nil + +proc SetupSwapchain*(renderPass: RenderPass, vSync: bool = false) = + assert vulkan.swapchain == nil, "Swapchain has already been initialized yet" + vulkan.swapchain = InitSwapchain(renderPass, vSync = vSync) + proc DestroyVulkan*() = + if vulkan.swapchain != nil: + DestroySwapchain(vulkan.swapchain) vkDestroyDevice(vulkan.device, nil) vkDestroySurfaceKHR(vulkan.instance, vulkan.surface, nil) vkDestroyDebugUtilsMessengerEXT(vulkan.instance, vulkan.debugMessenger, nil) @@ -334,7 +345,13 @@ fullscreen = enable vulkan.window.Fullscreen(fullscreen) -func GetAspectRatio*(swapchain: Swapchain): float32 = swapchain.width.float32 / swapchain.height.float32 +proc GetAspectRatio*(): float32 = + assert vulkan.swapchain != nil, "Swapchain has not been initialized yet" + vulkan.swapchain.width.float32 / vulkan.swapchain.height.float32 + +proc currentFiF*(): int = + assert vulkan.swapchain != nil, "Swapchain has not been initialized yet" + vulkan.swapchain.currentFiF proc MaxFramebufferSampleCount*(maxSamples = VK_SAMPLE_COUNT_8_BIT): VkSampleCountFlagBits = let limits = svkGetPhysicalDeviceProperties().limits
--- a/semiconginev2/rendering/renderer.nim Sun Jul 21 11:31:11 2024 +0700 +++ b/semiconginev2/rendering/renderer.nim Mon Jul 22 00:46:10 2024 +0700 @@ -4,11 +4,11 @@ func usage(bType: BufferType): seq[VkBufferUsageFlagBits] = case bType: of VertexBuffer: @[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] - of VertexBufferMapped: @[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] + of VertexBufferMapped: @[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT] of IndexBuffer: @[VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] - of IndexBufferMapped: @[VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] + of IndexBufferMapped: @[VK_BUFFER_USAGE_INDEX_BUFFER_BIT] of UniformBuffer: @[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] - of UniformBufferMapped: @[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] + of UniformBufferMapped: @[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT] proc GetVkFormat(grayscale: bool, usage: openArray[VkImageUsageFlagBits]): VkFormat = let formats = if grayscale: [VK_FORMAT_R8_SRGB, VK_FORMAT_R8_UNORM] @@ -279,9 +279,10 @@ result.rawPointer = selectedBlock.rawPointer.pointerAddOffset(selectedBlock.offsetNextFree) renderData.memory[memoryType][selectedBlockI].offsetNextFree += memoryRequirements.size -proc UpdateGPUBuffer*(gpuData: GPUData, flush = false) = +proc UpdateGPUBuffer*(gpuData: GPUData, flush = false, allFrames = false) = if gpuData.size == 0: return + when NeedsMapping(gpuData): copyMem(pointerAddOffset(gpuData.buffer.rawPointer, gpuData.offset), gpuData.rawPointer, gpuData.size) if flush: @@ -290,47 +291,57 @@ WithStagingBuffer((gpuData.buffer.vk, gpuData.offset), gpuData.size, stagingPtr): copyMem(stagingPtr, gpuData.rawPointer, gpuData.size) -proc UpdateAllGPUBuffers*[T](value: T, flush = false) = +proc UpdateAllGPUBuffers*[T](value: T, flush = false, allFrames = false) = for name, fieldvalue in value.fieldPairs(): when typeof(fieldvalue) is GPUData: - UpdateGPUBuffer(fieldvalue, flush = flush) + UpdateGPUBuffer(fieldvalue, flush = flush, allFrames = allFrames) when typeof(fieldvalue) is array: when elementType(fieldvalue) is GPUData: for entry in fieldvalue: - UpdateGPUBuffer(entry, flush = flush) + UpdateGPUBuffer(entry, flush = flush, allFrames = allFrames) -proc AssignGPUData(renderdata: var RenderData, value: var GPUData) = +proc AllocateGPUData( + renderdata: var RenderData, + bufferType: BufferType, + size: uint64, + needsFrameInFlight = -1 +): (Buffer, uint64) = + # find buffer that has space var selectedBufferI = -1 - for i in 0 ..< renderData.buffers[value.bufferType].len: - let buffer = renderData.buffers[value.bufferType][i] - if buffer.size - alignedTo(buffer.offsetNextFree, BUFFER_ALIGNMENT) >= value.size: - selectedBufferI = i + 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 # otherwise create new buffer if selectedBufferI < 0: - selectedBufferI = renderdata.buffers[value.bufferType].len - renderdata.buffers[value.bufferType].add renderdata.AllocateNewBuffer( - size = max(value.size, BUFFER_ALLOCATION_SIZE), - bufferType = value.bufferType, + selectedBufferI = renderdata.buffers[bufferType].len + renderdata.buffers[bufferType].add renderdata.AllocateNewBuffer( + size = max(size, BUFFER_ALLOCATION_SIZE), + bufferType = bufferType, ) + if needsFrameInFlight >= 0: + renderdata.buffers[bufferType][selectedBufferI].useForFrameInFlight = needsFrameInFlight # assigne value - let selectedBuffer = renderdata.buffers[value.bufferType][selectedBufferI] - renderdata.buffers[value.bufferType][selectedBufferI].offsetNextFree = alignedTo( + let selectedBuffer = renderdata.buffers[bufferType][selectedBufferI] + renderdata.buffers[bufferType][selectedBufferI].offsetNextFree = alignedTo( selectedBuffer.offsetNextFree, BUFFER_ALIGNMENT ) - value.buffer = selectedBuffer - value.offset = renderdata.buffers[value.bufferType][selectedBufferI].offsetNextFree - renderdata.buffers[value.bufferType][selectedBufferI].offsetNextFree += value.size + + result[0] = selectedBuffer + result[1] = renderdata.buffers[bufferType][selectedBufferI].offsetNextFree + renderdata.buffers[bufferType][selectedBufferI].offsetNextFree += size proc AssignBuffers*[T](renderdata: var RenderData, data: var T, uploadData = true) = for name, value in fieldPairs(data): when typeof(value) is GPUData: - AssignGPUData(renderdata, value) + (value.buffer, value.offset) = AllocateGPUData(renderdata, value.bufferType, value.size) elif typeof(value) is DescriptorSet: AssignBuffers(renderdata, value.data, uploadData = uploadData) @@ -338,10 +349,10 @@ elif typeof(value) is array: when elementType(value) is GPUValue: for v in value.mitems: - AssignGPUData(renderdata, v) + (v.buffer, v.offset) = AllocateGPUData(renderdata, v.bufferType, v.size) if uploadData: - UpdateAllGPUBuffers(data) + UpdateAllGPUBuffers(data, flush = true, allFrames = true) proc AssignBuffers*(renderdata: var RenderData, descriptorSet: var DescriptorSet, uploadData = true) = AssignBuffers(renderdata, descriptorSet.data, uploadData = uploadData) @@ -534,36 +545,36 @@ let `fieldvalue` {.inject.} = value body -template WithBind*[A, B, C, D](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], DescriptorSet[B], DescriptorSet[C], DescriptorSet[D]), pipeline: Pipeline, currentFiF: int, body: untyped): untyped = +template WithBind*[A, B, C, D](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], DescriptorSet[B], DescriptorSet[C], DescriptorSet[D]), pipeline: Pipeline, body: untyped): untyped = block: var descriptorSets: seq[VkDescriptorSet] for dSet in sets.fields: - assert dSet.vk[currentFiF].Valid, "DescriptorSet not initialized, maybe forgot to call InitDescriptorSet" - descriptorSets.add dSet.vk[currentFiF] + assert dSet.vk[currentFiF()].Valid, "DescriptorSet not initialized, maybe forgot to call InitDescriptorSet" + descriptorSets.add dSet.vk[currentFiF()] svkCmdBindDescriptorSets(commandBuffer, descriptorSets, pipeline.layout) body -template WithBind*[A, B, C](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], DescriptorSet[B], DescriptorSet[C]), pipeline: Pipeline, currentFiF: int, body: untyped): untyped = +template WithBind*[A, B, C](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], DescriptorSet[B], DescriptorSet[C]), pipeline: Pipeline, body: untyped): untyped = block: var descriptorSets: seq[VkDescriptorSet] for dSet in sets.fields: - assert dSet.vk[currentFiF].Valid, "DescriptorSet not initialized, maybe forgot to call InitDescriptorSet" - descriptorSets.add dSet.vk[currentFiF] + assert dSet.vk[currentFiF()].Valid, "DescriptorSet not initialized, maybe forgot to call InitDescriptorSet" + descriptorSets.add dSet.vk[currentFiF()] svkCmdBindDescriptorSets(commandBuffer, descriptorSets, pipeline.layout) body -template WithBind*[A, B](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], DescriptorSet[B]), pipeline: Pipeline, currentFiF: int, body: untyped): untyped = +template WithBind*[A, B](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], DescriptorSet[B]), pipeline: Pipeline, body: untyped): untyped = block: var descriptorSets: seq[VkDescriptorSet] for dSet in sets.fields: - assert dSet.vk[currentFiF].Valid, "DescriptorSet not initialized, maybe forgot to call InitDescriptorSet" - descriptorSets.add dSet.vk[currentFiF] + assert dSet.vk[currentFiF()].Valid, "DescriptorSet not initialized, maybe forgot to call InitDescriptorSet" + descriptorSets.add dSet.vk[currentFiF()] svkCmdBindDescriptorSets(commandBuffer, descriptorSets, pipeline.layout) body -template WithBind*[A](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], ), pipeline: Pipeline, currentFiF: int, body: untyped): untyped = +template WithBind*[A](commandBuffer: VkCommandBuffer, sets: (DescriptorSet[A], ), pipeline: Pipeline, body: untyped): untyped = block: var descriptorSets: seq[VkDescriptorSet] for dSet in sets.fields: - assert dSet.vk[currentFiF].Valid, "DescriptorSet not initialized, maybe forgot to call InitDescriptorSet" - descriptorSets.add dSet.vk[currentFiF] + assert dSet.vk[currentFiF()].Valid, "DescriptorSet not initialized, maybe forgot to call InitDescriptorSet" + descriptorSets.add dSet.vk[currentFiF()] svkCmdBindDescriptorSets(commandBuffer, descriptorSets, pipeline.layout) body
--- a/semiconginev2/rendering/swapchain.nim Sun Jul 21 11:31:11 2024 +0700 +++ b/semiconginev2/rendering/swapchain.nim Mon Jul 22 00:46:10 2024 +0700 @@ -1,10 +1,10 @@ const N_FRAMEBUFFERS = 3'u32 -proc InitSwapchain*( +proc InitSwapchain( renderPass: RenderPass, vSync: bool = false, oldSwapchain: Swapchain = nil, -): Option[Swapchain] = +): Swapchain = assert vulkan.instance.Valid, "Vulkan not initialized" var capabilities: VkSurfaceCapabilitiesKHR @@ -14,7 +14,7 @@ height = capabilities.currentExtent.height if width == 0 or height == 0: - return none(Swapchain) + return nil # following "count" is established according to vulkan specs var minFramebufferCount = N_FRAMEBUFFERS @@ -49,7 +49,7 @@ ) if vkCreateSwapchainKHR(vulkan.device, addr(swapchainCreateInfo), nil, addr(swapchain.vk)) != VK_SUCCESS: - return none(Swapchain) + return nil if swapchain.oldSwapchain != nil: swapchain.oldSwapchainCounter = INFLIGHTFRAMES.int * 2 @@ -150,9 +150,11 @@ ) checkVkResult vkAllocateCommandBuffers(vulkan.device, addr(allocInfo), swapchain.commandBuffers.ToCPointer) - return some(swapchain) + return swapchain proc DestroySwapchain*(swapchain: Swapchain) = + if swapchain.oldSwapchain != nil: + DestroySwapchain(swapchain.oldSwapchain) if swapchain.msaaImage.Valid: vkDestroyImageView(vulkan.device, swapchain.msaaImageView, nil) @@ -245,19 +247,20 @@ swapchain.currentFiF = (uint32(swapchain.currentFiF) + 1) mod INFLIGHTFRAMES return true -proc Recreate(swapchain: Swapchain): Option[Swapchain] = +proc Recreate(swapchain: Swapchain): Swapchain = InitSwapchain( renderPass = swapchain.renderPass, vSync = swapchain.vSync, oldSwapchain = swapchain, ) -template WithNextFrame*(theSwapchain: var Swapchain, framebufferName, commandBufferName, body: untyped): untyped = - var maybeFramebuffer = TryAcquireNextImage(theSwapchain) +template WithNextFrame*(framebufferName, commandBufferName, body: untyped): untyped = + assert vulkan.swapchain != nil, "Swapchain has not been initialized yet" + var maybeFramebuffer = TryAcquireNextImage(vulkan.swapchain) if maybeFramebuffer.isSome: block: let `framebufferName` {.inject.} = maybeFramebuffer.get - let `commandBufferName` {.inject.} = theSwapchain.commandBuffers[theSwapchain.currentFiF] + let `commandBufferName` {.inject.} = vulkan.swapchain.commandBuffers[vulkan.swapchain.currentFiF] let beginInfo = VkCommandBufferBeginInfo( sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, flags: VkCommandBufferUsageFlags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT), @@ -268,9 +271,8 @@ body checkVkResult vkEndCommandBuffer(`commandBufferName`) - discard Swap(swapchain = theSwapchain, commandBuffer = `commandBufferName`) + discard Swap(swapchain = vulkan.swapchain, commandBuffer = `commandBufferName`) else: - let maybeNewSwapchain = Recreate(theSwapchain) - if maybeNewSwapchain.isSome: - theSwapchain = maybeNewSwapchain.get - + let newSwapchain = Recreate(vulkan.swapchain) + if newSwapchain != nil: + vulkan.swapchain = newSwapchain
--- a/semiconginev2/rendering/vulkan_wrappers.nim Sun Jul 21 11:31:11 2024 +0700 +++ b/semiconginev2/rendering/vulkan_wrappers.nim Mon Jul 22 00:46:10 2024 +0700 @@ -347,6 +347,22 @@ WithSingleUseCommandBuffer(commandBuffer): when T is (VkBuffer, uint64): + # first make sure memory has been made available with a memory barrier + # we are just waiting for the vertex input stage, but I think that is fine for most buffer copies (for now at least) + let memoryBarrier = VkMemoryBarrier(sType: VK_STRUCTURE_TYPE_MEMORY_BARRIER) + vkCmdPipelineBarrier( + commandBuffer = commandBuffer, + srcStageMask = toBits [VK_PIPELINE_STAGE_VERTEX_INPUT_BIT], + dstStageMask = toBits [VK_PIPELINE_STAGE_TRANSFER_BIT], + dependencyFlags = VkDependencyFlags(0), + memoryBarrierCount = 1, + pMemoryBarriers = addr(memoryBarrier), + bufferMemoryBarrierCount = 0, + pBufferMemoryBarriers = nil, + imageMemoryBarrierCount = 0, + pImageMemoryBarriers = nil, + ) + # now copy stuff let copyRegion = VkBufferCopy( size: bufferSize, dstOffset: target[1],
--- a/semiconginev2/text/textbox.nim Sun Jul 21 11:31:11 2024 +0700 +++ b/semiconginev2/text/textbox.nim Mon Jul 22 00:46:10 2024 +0700 @@ -23,7 +23,7 @@ "\"" & $textbox.text[0 ..< min(textbox.text.len, 16)] & "\"" proc RefreshShaderdata(textbox: Textbox) = - textbox.shaderdata.data.textbox.UpdateGPUBuffer() + textbox.shaderdata.data.textbox.UpdateGPUBuffer(flush = true) proc RefreshGeometry(textbox: var Textbox) = # pre-calculate text-width @@ -45,8 +45,9 @@ let anchorY = (case textbox.verticalAlignment of Top: 0'f32 - of Center: height / 2 - of Bottom: height) - textbox.font.capHeight + of Center: -height / 2 + of Bottom: -height + ) - textbox.font.capHeight var offsetX = 0'f32 @@ -61,7 +62,7 @@ if i < textbox.processedText.len: if textbox.processedText[i] == Rune('\n'): offsetX = 0 - offsetY += textbox.font.lineAdvance + offsetY -= textbox.font.lineAdvance textbox.position.data[vertexOffset + 0] = NewVec3f() textbox.position.data[vertexOffset + 1] = NewVec3f() textbox.position.data[vertexOffset + 2] = NewVec3f() @@ -76,13 +77,13 @@ glyph = textbox.font.glyphs[textbox.processedText[i]] left = offsetX + glyph.leftOffset right = offsetX + glyph.leftOffset + glyph.dimension.x - top = offsetY + glyph.topOffset - bottom = offsetY + glyph.topOffset + glyph.dimension.y + top = offsetY - glyph.topOffset + bottom = offsetY - glyph.topOffset - glyph.dimension.y - textbox.position.data[vertexOffset + 1] = NewVec3f(left - anchorX, bottom - anchorY) - textbox.position.data[vertexOffset + 0] = NewVec3f(left - anchorX, top - anchorY) - textbox.position.data[vertexOffset + 3] = NewVec3f(right - anchorX, top - anchorY) - textbox.position.data[vertexOffset + 2] = NewVec3f(right - anchorX, bottom - anchorY) + textbox.position.data[vertexOffset + 0] = NewVec3f(left - anchorX, bottom - anchorY) + textbox.position.data[vertexOffset + 1] = NewVec3f(left - anchorX, top - anchorY) + textbox.position.data[vertexOffset + 2] = NewVec3f(right - anchorX, top - anchorY) + textbox.position.data[vertexOffset + 3] = NewVec3f(right - anchorX, bottom - anchorY) textbox.uv.data[vertexOffset + 0] = glyph.uvs[0] textbox.uv.data[vertexOffset + 1] = glyph.uvs[1] @@ -97,8 +98,8 @@ textbox.position.data[vertexOffset + 1] = NewVec3f() textbox.position.data[vertexOffset + 2] = NewVec3f() textbox.position.data[vertexOffset + 3] = NewVec3f() - UpdateGPUBuffer(textbox.position, flush = true) - UpdateGPUBuffer(textbox.uv, flush = true) + UpdateGPUBuffer(textbox.position) + UpdateGPUBuffer(textbox.uv) textbox.lastRenderedText = textbox.processedText func text*(textbox: Textbox): seq[Rune] = @@ -137,14 +138,6 @@ textbox.dirtyShaderdata = true textbox.shaderdata.data.textbox.data.scale = value -proc AspectRatio*(textbox: Textbox): float32 = - textbox.shaderdata.data.textbox.data.aspectratio - -proc `AspectRatio=`*(textbox: var Textbox, value: float32) = - if textbox.shaderdata.data.textbox.data.aspectratio != value: - textbox.dirtyShaderdata = true - textbox.shaderdata.data.textbox.data.aspectratio = value - proc Position*(textbox: Textbox): Vec3f = textbox.shaderdata.data.textbox.data.position @@ -167,8 +160,10 @@ textbox.verticalAlignment = value textbox.dirtyGeometry = true -proc Refresh*(textbox: var Textbox, aspectratio: float32) = - `AspectRatio=`(textbox, aspectratio) +proc Refresh*(textbox: var Textbox) = + if textbox.shaderdata.data.textbox.data.aspectratio != GetAspectRatio(): + textbox.dirtyShaderdata = true + textbox.shaderdata.data.textbox.data.aspectratio = GetAspectRatio() if textbox.dirtyShaderdata: textbox.RefreshShaderdata() @@ -178,8 +173,8 @@ textbox.RefreshGeometry() textbox.dirtyGeometry = false -proc Render*(textbox: Textbox, commandbuffer: VkCommandBuffer, pipeline: Pipeline, currentFiF: int) = - WithBind(commandbuffer, (textbox.shaderdata, ), pipeline, currentFiF): +proc Render*(textbox: Textbox, commandbuffer: VkCommandBuffer, pipeline: Pipeline) = + WithBind(commandbuffer, (textbox.shaderdata, ), pipeline): Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = textbox) proc InitTextbox*[T: string | seq[Rune]]( @@ -238,6 +233,6 @@ UploadImages(renderdata, result.shaderdata) InitDescriptorSet(renderdata, descriptorSetLayout, result.shaderdata) - result.Refresh(1) - UpdateAllGPUBuffers(result, flush = true) + result.Refresh() + UpdateAllGPUBuffers(result, flush = true, allFrames = true) UpdateAllGPUBuffers(result.shaderdata.data, flush = true)
--- a/tests/test_rendering.nim Sun Jul 21 11:31:11 2024 +0700 +++ b/tests/test_rendering.nim Mon Jul 22 00:46:10 2024 +0700 @@ -7,7 +7,7 @@ import ../semiconginev2 -proc test_01_triangle(time: float32, swapchain: var Swapchain) = +proc test_01_triangle(time: float32) = var renderdata = InitRenderData() type @@ -33,12 +33,12 @@ renderdata.FlushAllMemory() var - pipeline = CreatePipeline[TrianglShader](renderPass = swapchain.renderPass) + pipeline = CreatePipeline[TrianglShader](renderPass = vulkan.swapchain.renderPass) var start = getMonoTime() while ((getMonoTime() - start).inMilliseconds().int / 1000) < time: - WithNextFrame(swapchain, framebuffer, commandbuffer): - WithRenderPass(swapchain.renderPass, framebuffer, commandbuffer, swapchain.width, swapchain.height, NewVec4f(0, 0, 0, 0)): + WithNextFrame(framebuffer, commandbuffer): + WithRenderPass(vulkan.swapchain.renderPass, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, NewVec4f(0, 0, 0, 0)): WithPipeline(commandbuffer, pipeline): Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = mesh) @@ -48,7 +48,7 @@ DestroyRenderData(renderdata) -proc test_02_triangle_quad_instanced(time: float32, swapchain: var Swapchain) = +proc test_02_triangle_quad_instanced(time: float32) = var renderdata = InitRenderData() type @@ -100,12 +100,12 @@ AssignBuffers(renderdata, instancesB) renderdata.FlushAllMemory() - var pipeline = CreatePipeline[SomeShader](renderPass = swapchain.renderPass) + var pipeline = CreatePipeline[SomeShader](renderPass = vulkan.swapchain.renderPass) var start = getMonoTime() while ((getMonoTime() - start).inMilliseconds().int / 1000) < time: - WithNextFrame(swapchain, framebuffer, commandbuffer): - WithRenderPass(swapchain.renderPass, framebuffer, commandbuffer, swapchain.width, swapchain.height, NewVec4f(0, 0, 0, 0)): + WithNextFrame(framebuffer, commandbuffer): + WithRenderPass(vulkan.swapchain.renderPass, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, NewVec4f(0, 0, 0, 0)): WithPipeline(commandbuffer, pipeline): Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad, instances = instancesA) Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad, instances = instancesB) @@ -117,7 +117,7 @@ DestroyPipeline(pipeline) DestroyRenderData(renderdata) -proc test_03_simple_descriptorset(time: float32, swapchain: var Swapchain) = +proc test_03_simple_descriptorset(time: float32) = var renderdata = InitRenderData() type @@ -176,19 +176,19 @@ UploadImages(renderdata, uniforms2) renderdata.FlushAllMemory() - var pipeline = CreatePipeline[QuadShader](renderPass = swapchain.renderPass) + var pipeline = CreatePipeline[QuadShader](renderPass = vulkan.swapchain.renderPass) InitDescriptorSet(renderdata, pipeline.descriptorSetLayouts[0], uniforms1) InitDescriptorSet(renderdata, pipeline.descriptorSetLayouts[0], uniforms2) var start = getMonoTime() while ((getMonoTime() - start).inMilliseconds().int / 1000) < time: - WithNextFrame(swapchain, framebuffer, commandbuffer): - WithRenderPass(swapchain.renderPass, framebuffer, commandbuffer, swapchain.width, swapchain.height, NewVec4f(0, 0, 0, 0)): + WithNextFrame(framebuffer, commandbuffer): + WithRenderPass(vulkan.swapchain.renderPass, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, NewVec4f(0, 0, 0, 0)): WithPipeline(commandbuffer, pipeline): - WithBind(commandbuffer, (uniforms1, ), pipeline, swapchain.currentFiF): + WithBind(commandbuffer, (uniforms1, ), pipeline): Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) - WithBind(commandbuffer, (uniforms2, ), pipeline, swapchain.currentFiF): + WithBind(commandbuffer, (uniforms2, ), pipeline): Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) # cleanup @@ -196,7 +196,7 @@ DestroyPipeline(pipeline) DestroyRenderData(renderdata) -proc test_04_multiple_descriptorsets(time: float32, swapchain: var Swapchain) = +proc test_04_multiple_descriptorsets(time: float32) = var renderdata = InitRenderData() type @@ -283,7 +283,7 @@ UploadImages(renderdata, mainset) renderdata.FlushAllMemory() - var pipeline = CreatePipeline[QuadShader](renderPass = swapchain.renderPass) + var pipeline = CreatePipeline[QuadShader](renderPass = vulkan.swapchain.renderPass) InitDescriptorSet(renderdata, pipeline.descriptorSetLayouts[0], constset) InitDescriptorSet(renderdata, pipeline.descriptorSetLayouts[1], mainset) @@ -293,12 +293,12 @@ var start = getMonoTime() while ((getMonoTime() - start).inMilliseconds().int / 1000) < time: TimeAndLog: - WithNextFrame(swapchain, framebuffer, commandbuffer): - WithRenderPass(swapchain.renderPass, framebuffer, commandbuffer, swapchain.width, swapchain.height, NewVec4f(0, 0, 0, 0)): + WithNextFrame(framebuffer, commandbuffer): + WithRenderPass(vulkan.swapchain.renderPass, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, NewVec4f(0, 0, 0, 0)): WithPipeline(commandbuffer, pipeline): - WithBind(commandbuffer, (constset, mainset, otherset1), pipeline, swapchain.currentFiF): + WithBind(commandbuffer, (constset, mainset, otherset1), pipeline): Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) - WithBind(commandbuffer, (constset, mainset, otherset2), pipeline, swapchain.currentFiF): + WithBind(commandbuffer, (constset, mainset, otherset2), pipeline): Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = quad) mainset.data.renderSettings.data.brigthness = ((getMonoTime() - start).inMilliseconds().int / 1000) / time otherset1.data.objectSettings.data.scale = 0.5 + ((getMonoTime() - start).inMilliseconds().int / 1000) / time @@ -311,7 +311,7 @@ DestroyPipeline(pipeline) DestroyRenderData(renderdata) -proc test_05_cube(time: float32, swapchain: var Swapchain) = +proc test_05_cube(time: float32) = type UniformData = object @@ -405,7 +405,7 @@ renderdata.FlushAllMemory() - var pipeline = CreatePipeline[CubeShader](renderPass = swapchain.renderPass) + var pipeline = CreatePipeline[CubeShader](renderPass = vulkan.swapchain.renderPass) InitDescriptorSet(renderdata, pipeline.descriptorSetLayouts[0], uniforms1) var tStart = getMonoTime() @@ -416,16 +416,16 @@ let tStartLoop = getMonoTime() - tStart uniforms1.data.data.data.mvp = ( - Perspective(-PI / 2, GetAspectRatio(swapchain), 0.01, 100) * + Perspective(-PI / 2, GetAspectRatio(), 0.01, 100) * Translate(0, 0, 2) * Rotate(PI / 4, X) * Rotate(PI * 0.1 * (tStartLoop.inMicroseconds() / 1_000_000), Y) ) UpdateGPUBuffer(uniforms1.data.data, flush = true) - WithNextFrame(swapchain, framebuffer, commandbuffer): - WithRenderPass(swapchain.renderPass, framebuffer, commandbuffer, swapchain.width, swapchain.height, NewVec4f(0, 0, 0, 0)): + WithNextFrame(framebuffer, commandbuffer): + WithRenderPass(vulkan.swapchain.renderPass, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, NewVec4f(0, 0, 0, 0)): WithPipeline(commandbuffer, pipeline): - WithBind(commandbuffer, (uniforms1, ), pipeline, swapchain.currentFiF): + WithBind(commandbuffer, (uniforms1, ), pipeline): Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = mesh) Render(commandbuffer = commandbuffer, pipeline = pipeline, mesh = floor) @@ -442,9 +442,9 @@ DestroyRenderData(renderdata) proc test_06_triangle_2pass(time: float32, depthBuffer: bool, samples: VkSampleCountFlagBits) = - var - (offscreenRP, presentRP) = CreateIndirectPresentationRenderPass(depthBuffer = depthBuffer, samples = samples) - swapchain = InitSwapchain(renderpass = presentRP).get() + var (offscreenRP, presentRP) = CreateIndirectPresentationRenderPass(depthBuffer = depthBuffer, samples = samples) + + SetupSwapchain(renderpass = presentRP) var renderdata = InitRenderData() @@ -499,7 +499,7 @@ ) var uniforms1 = asDescriptorSet( Uniforms( - frameTexture: Image[TVec4[uint8]](width: swapchain.width, height: swapchain.height, isRenderTarget: true), + frameTexture: Image[TVec4[uint8]](width: vulkan.swapchain.width, height: vulkan.swapchain.height, isRenderTarget: true), ) ) AssignBuffers(renderdata, mesh) @@ -520,8 +520,8 @@ depthMemory: VkDeviceMemory if offscreenRP.depthBuffer: depthImage = svkCreate2DImage( - width = swapchain.width, - height = swapchain.height, + width = vulkan.swapchain.width, + height = vulkan.swapchain.height, format = DEPTH_FORMAT, usage = [VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT], samples = offscreenRP.samples, @@ -550,8 +550,8 @@ msaaMemory: VkDeviceMemory if offscreenRP.samples != VK_SAMPLE_COUNT_1_BIT: msaaImage = svkCreate2DImage( - width = swapchain.width, - height = swapchain.height, + width = vulkan.swapchain.width, + height = vulkan.swapchain.height, format = SURFACE_FORMAT, usage = [VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT], samples = offscreenRP.samples, @@ -583,8 +583,8 @@ echo attachments var offscreenFB = svkCreateFramebuffer( offscreenRP.vk, - swapchain.width, - swapchain.height, + vulkan.swapchain.width, + vulkan.swapchain.height, attachments ) @@ -592,15 +592,15 @@ while ((getMonoTime() - start).inMilliseconds().int / 1000) < time: TimeAndLog: - WithNextFrame(swapchain, framebuffer, commandbuffer): + WithNextFrame(framebuffer, commandbuffer): - WithRenderPass(offscreenRP, offscreenFB, commandbuffer, swapchain.width, swapchain.height, NewVec4f(0, 0, 0, 0)): + WithRenderPass(offscreenRP, offscreenFB, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, NewVec4f(0, 0, 0, 0)): WithPipeline(commandbuffer, drawPipeline): Render(commandbuffer = commandbuffer, pipeline = drawPipeline, mesh = mesh) - WithRenderPass(presentRP, framebuffer, commandbuffer, swapchain.width, swapchain.height, NewVec4f(0, 0, 0, 0)): + WithRenderPass(presentRP, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, NewVec4f(0, 0, 0, 0)): WithPipeline(commandbuffer, presentPipeline): - WithBind(commandbuffer, (uniforms1, ), presentPipeline, swapchain.currentFiF): + WithBind(commandbuffer, (uniforms1, ), presentPipeline): Render(commandbuffer = commandbuffer, pipeline = presentPipeline, mesh = quad) # cleanup @@ -619,7 +619,7 @@ vkDestroyRenderPass(vulkan.device, offscreenRP.vk, nil) vkDestroyRenderPass(vulkan.device, presentRP.vk, nil) vkDestroyFramebuffer(vulkan.device, offscreenFB, nil) - DestroySwapchain(swapchain) + ClearSwapchain() when isMainModule: var time = 1'f32 @@ -636,26 +636,26 @@ # test normal for i, (depthBuffer, samples) in renderPasses: var renderpass = CreateDirectPresentationRenderPass(depthBuffer = depthBuffer, samples = samples) - var swapchain = InitSwapchain(renderpass = renderpass).get() + SetupSwapchain(renderpass = renderpass) # tests a simple triangle with minimalistic shader and vertex format - test_01_triangle(time, swapchain) + test_01_triangle(time) # tests instanced triangles and quads, mixing meshes and instances - test_02_triangle_quad_instanced(time, swapchain) + test_02_triangle_quad_instanced(time) # teste descriptor sets - test_03_simple_descriptorset(time, swapchain) + test_03_simple_descriptorset(time) # tests multiple descriptor sets and arrays - test_04_multiple_descriptorsets(time, swapchain) + test_04_multiple_descriptorsets(time) # rotating cube - test_05_cube(time, swapchain) + test_05_cube(time) checkVkResult vkDeviceWaitIdle(vulkan.device) vkDestroyRenderPass(vulkan.device, renderpass.vk, nil) - DestroySwapchain(swapchain) + ClearSwapchain() # test multiple render passes for i, (depthBuffer, samples) in renderPasses:
--- a/tests/test_text.nim Sun Jul 21 11:31:11 2024 +0700 +++ b/tests/test_text.nim Mon Jul 22 00:46:10 2024 +0700 @@ -8,10 +8,10 @@ import ../semiconginev2 -proc test_01_static_label(time: float32, swapchain: var Swapchain) = +proc test_01_static_label(time: float32) = var renderdata = InitRenderData() - var pipeline = CreatePipeline[DefaultFontShader](renderPass = swapchain.renderPass) + var pipeline = CreatePipeline[DefaultFontShader](renderPass = vulkan.swapchain.renderPass) var font = LoadFont("Overhaul.ttf", lineHeightPixels = 160) var label1 = InitTextbox( @@ -25,21 +25,21 @@ var start = getMonoTime() while ((getMonoTime() - start).inMilliseconds().int / 1000) < time: - label1.Refresh(swapchain.GetAspectRatio()) - WithNextFrame(swapchain, framebuffer, commandbuffer): - WithRenderPass(swapchain.renderPass, framebuffer, commandbuffer, swapchain.width, swapchain.height, NewVec4f(0, 0, 0, 0)): + label1.Refresh() + WithNextFrame(framebuffer, commandbuffer): + WithRenderPass(vulkan.swapchain.renderPass, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, NewVec4f(0, 0, 0, 0)): WithPipeline(commandbuffer, pipeline): - Render(label1, commandbuffer, pipeline, swapchain.currentFiF) + Render(label1, commandbuffer, pipeline) # cleanup checkVkResult vkDeviceWaitIdle(vulkan.device) DestroyPipeline(pipeline) DestroyRenderData(renderdata) -proc test_02_multiple_animated(time: float32, swapchain: var Swapchain) = +proc test_02_multiple_animated(time: float32) = var renderdata = InitRenderData() - var pipeline = CreatePipeline[DefaultFontShader](renderPass = swapchain.renderPass) + var pipeline = CreatePipeline[DefaultFontShader](renderPass = vulkan.swapchain.renderPass) var font1 = LoadFont("Overhaul.ttf", lineHeightPixels = 40) var font2 = LoadFont("Overhaul.ttf", lineHeightPixels = 160) @@ -85,22 +85,81 @@ labels[i].Scale = labels[i].Scale * (1.0 + (i + 1).float * 0.001) labels[i].Position = labels[i].Position + NewVec3f(0.001 * (i.float - 1'f)) labels[i].text = $(p + i) - labels[i].Refresh(swapchain.GetAspectRatio()) + labels[i].Refresh() inc p - WithNextFrame(swapchain, framebuffer, commandbuffer): - WithRenderPass(swapchain.renderPass, framebuffer, commandbuffer, swapchain.width, swapchain.height, NewVec4f(0, 0, 0, 0)): + WithNextFrame(framebuffer, commandbuffer): + WithRenderPass(vulkan.swapchain.renderPass, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, NewVec4f(0, 0, 0, 0)): WithPipeline(commandbuffer, pipeline): for label in labels: - Render(label, commandbuffer, pipeline, swapchain.currentFiF) + Render(label, commandbuffer, pipeline) - # cleanup + # cleanup checkVkResult vkDeviceWaitIdle(vulkan.device) DestroyPipeline(pipeline) DestroyRenderData(renderdata) -proc test_03_layouting(time: float32, swapchain: var Swapchain) = - discard # TODO -proc test_04_lots_of_texts(time: float32, swapchain: var Swapchain) = +proc test_03_layouting(time: float32) = + var renderdata = InitRenderData() + + var pipeline = CreatePipeline[DefaultFontShader](renderPass = vulkan.swapchain.renderPass) + + var font = LoadFont("DejaVuSans.ttf", lineHeightPixels = 40) + var labels: seq[Textbox] + + for horizontal in HorizontalAlignment: + labels.add InitTextbox( + renderdata, + pipeline.descriptorSetLayouts[0], + font, + $horizontal & " aligned", + color = NewVec4f(1, 1, 1, 1), + scale = 0.001, + position = NewVec3f(0, 0.9 - (horizontal.float * 0.15)), + horizontalAlignment = horizontal, + ) + for vertical in VerticalAlignment: + labels.add InitTextbox( + renderdata, + pipeline.descriptorSetLayouts[0], + font, + $vertical & " aligned", + color = NewVec4f(1, 1, 1, 1), + scale = 0.001, + position = NewVec3f(-0.35 + (vertical.float * 0.35), 0.3), + verticalAlignment = vertical, + ) + labels.add InitTextbox( + renderdata, + pipeline.descriptorSetLayouts[0], + font, + """Paragraph +This is a somewhat longer paragraph with a few newlines and a maximum width of 0.2. + +It should display with some space above and have a pleasing appearance overall! :)""", + maxWidth = 0.6, + color = NewVec4f(1, 1, 1, 1), + scale = 0.001, + position = NewVec3f(-0.9, 0.1), + verticalAlignment = Top, + horizontalAlignment = Left, + ) + + + var start = getMonoTime() + while ((getMonoTime() - start).inMilliseconds().int / 1000) < time: + let progress = ((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, pipeline): + for label in labels: + Render(label, commandbuffer, pipeline) + + # cleanup + checkVkResult vkDeviceWaitIdle(vulkan.device) + DestroyPipeline(pipeline) + DestroyRenderData(renderdata) + +proc test_04_lots_of_texts(time: float32) = discard # TODO when isMainModule: @@ -108,14 +167,15 @@ InitVulkan() var renderpass = CreateDirectPresentationRenderPass(depthBuffer = true) - var swapchain = InitSwapchain(renderpass = renderpass).get() + SetupSwapchain(renderpass = renderpass) # tests a simple triangle with minimalistic shader and vertex format # test_01_static_label(time, swapchain) - test_02_multiple_animated(time, swapchain) + # test_02_multiple_animated(time) + test_03_layouting(time) + checkVkResult vkDeviceWaitIdle(vulkan.device) vkDestroyRenderPass(vulkan.device, renderpass.vk, nil) - DestroySwapchain(swapchain) DestroyVulkan()