# HG changeset patch # User sam # Date 1711897910 -25200 # Node ID 9c364af8d3f0bb7f742e723d472fee905cce06af # Parent 7a0d5fc00f4fd028badbd01a7932c5f00e1473c7 did: tons of small improvments, on the way to make GPU sync (more) correct I guess diff -r 7a0d5fc00f4f -r 9c364af8d3f0 config.nims --- a/config.nims Sun Mar 31 18:13:46 2024 +0700 +++ b/config.nims Sun Mar 31 22:11:50 2024 +0700 @@ -2,61 +2,26 @@ import std/strutils import std/os -const BUILDBASE = "build" -const DEBUG = "debug" -const RELEASE = "release" -const LINUX = "linux" -const WINDOWS = "windows" +import semicongine/build -const PACKAGETYPE* {.strdefine.}: string = "dir" # dir, zip, exe -const RESOURCEROOT* {.strdefine.}: string = "resources" +# TODO: totally update this file!! -switch("d", "nimPreviewHashRef") -switch("experimental", "strictEffects") -switch("experimental", "strictFuncs") switch("nimblePath", "nimbledeps/pkgs2") -task build, "build": - switch("d", "PACKAGETYPE=" & PACKAGETYPE) - switch("d", "RESOURCEROOT=" & RESOURCEROOT) - var buildType = DEBUG - var platformDir = "" - if defined(linux): - switch("define", "VK_USE_PLATFORM_XLIB_KHR") - platformDir = LINUX - if defined(windows): - switch("define", "VK_USE_PLATFORM_WIN32_KHR") - platformDir = WINDOWS - if defined(release): - switch("app", "gui") - buildType = RELEASE - else: - switch("debugger", "native") - - var outdir = getCurrentDir() / BUILDBASE / buildType / platformDir / projectName() - switch("outdir", outdir) +task build_dev, "build dev": + semicongine_build_switches(buildname = "dev") setCommand "c" - rmDir(outdir) - mkDir(outdir) - let resourcedir = joinPath(projectDir(), RESOURCEROOT) - if dirExists(resourcedir): - let outdir_resources = joinPath(outdir, RESOURCEROOT) - if PACKAGETYPE == "dir": - cpDir(resourcedir, outdir_resources) - elif PACKAGETYPE == "zip": - mkDir(outdir_resources) - for resource in listDirs(resourcedir): - let - oldcwd = getCurrentDir() - outputfile = joinPath(outdir_resources, resource.splitPath().tail & ".zip") - inputfile = resource.splitPath().tail - cd(resource) - if defined(linux): - exec &"zip -r {outputfile} ." - elif defined(windows): - # TODO: test this - exec &"powershell Compress-Archive * {outputfile}" - cd(oldcwd) + let outdir = semicongine_builddir(buildname = "dev") + semicongine_pack(outdir, bundleType = "exe", resourceRoot = "resources") + +task build_release, "build release": + switch "define", "release" + switch "app", "gui" + semicongine_build_switches(buildname = "release") + setCommand "c" + let outdir = semicongine_builddir(buildname = "release") + semicongine_pack(outdir, bundleType = "exe", resourceRoot = "resources") + task build_all_debug, "build all examples for debug": for file in listFiles("examples"): @@ -77,9 +42,6 @@ exec("nim build -d:BUILD_RESOURCEROOT=tests/resources -d:PACKAGETYPE=zip --run tests/test_resources.nim") exec("nim build -d:BUILD_RESOURCEROOT=tests/resources -d:PACKAGETYPE=exe --run tests/test_resources.nim") -task clean, "remove all build files": - exec(&"rm -rf {BUILDBASE}") - task publish, "publish all build": for file in listDirs("build/debug/linux"): exec(&"scp -r {file} sam@mail.basx.dev:/var/www/public.basx.dev/semicongine/debug/linux/") diff -r 7a0d5fc00f4f -r 9c364af8d3f0 examples/E01_hello_triangle.nim --- a/examples/E01_hello_triangle.nim Sun Mar 31 18:13:46 2024 +0700 +++ b/examples/E01_hello_triangle.nim Sun Mar 31 22:11:50 2024 +0700 @@ -1,35 +1,37 @@ import std/tables -import ../src/semicongine +import ../semicongine # shader setup const shaderConfiguration = createShaderConfiguration( - inputs=[ + inputs = [ attr[Vec3f]("position"), attr[Vec4f]("color"), ], - intermediates=[attr[Vec4f]("outcolor")], - outputs=[attr[Vec4f]("color")], - vertexCode="gl_Position = vec4(position, 1.0); outcolor = color;", - fragmentCode="color = outcolor;", + intermediates = [attr[Vec4f]("outcolor")], + outputs = [attr[Vec4f]("color")], + vertexCode = "gl_Position = vec4(position, 1.0); outcolor = color;", + fragmentCode = "color = outcolor;", ) # scene setup var - triangle = Scene(name: "scene", + scene = Scene(name: "scene", meshes: @[newMesh( - [newVec3f(-0.5, 0.5), newVec3f(0, -0.5), newVec3f(0.5, 0.5)], - [newVec4f(1, 0, 0, 1), newVec4f(0, 1, 0, 1), newVec4f(0, 0, 1, 1)], - material=Material(name: "default") + positions = [newVec3f(-0.5, 0.5), newVec3f(0, -0.5), newVec3f(0.5, 0.5)], + colors = [newVec4f(1, 0, 0, 1), newVec4f(0, 1, 0, 1), newVec4f(0, 0, 1, 1)], + material = VERTEX_COLORED_MATERIAL.initMaterialData() )] ) - myengine = initEngine("Hello triangle") + myengine = initEngine("Hello triangle", showFps = true) -myengine.initRenderer({"default": shaderConfiguration}.toTable) -myengine.addScene(triangle) +myengine.initRenderer({VERTEX_COLORED_MATERIAL: shaderConfiguration}, vSync = false, inFlightFrames = 1) +myengine.loadScene(scene) while myengine.updateInputs() == Running and not myengine.keyWasPressed(Escape): - myengine.renderScene(triangle) + echo "" + transform[Vec3f](scene.meshes[0][], "position", scale(1.001, 1.001)) + myengine.renderScene(scene) myengine.destroy() diff -r 7a0d5fc00f4f -r 9c364af8d3f0 semicongine/core/dynamic_arrays.nim --- a/semicongine/core/dynamic_arrays.nim Sun Mar 31 18:13:46 2024 +0700 +++ b/semicongine/core/dynamic_arrays.nim Sun Mar 31 22:11:50 2024 +0700 @@ -473,6 +473,8 @@ getValue[t](list, i) # since we use this often with tables, add this for an easy assignment +template `[]`*(table: Table[string, DataList], key: string, t: typedesc): ref seq[t] = + getValues[t](table[key]) template `[]=`*[T](table: var Table[string, DataList], key: string, values: openArray[T]) = if table.contains(key): table[key].setValues(values) diff -r 7a0d5fc00f4f -r 9c364af8d3f0 semicongine/engine.nim --- a/semicongine/engine.nim Sun Mar 31 18:13:46 2024 +0700 +++ b/semicongine/engine.nim Sun Mar 31 22:11:50 2024 +0700 @@ -1,4 +1,7 @@ +import std/algorithm +import std/monotimes import std/options +import std/strformat import std/sequtils import std/logging import std/os @@ -19,6 +22,8 @@ import ./text import ./panel +const COUNT_N_RENDERTIMES = 99 + type EngineState* = enum Starting @@ -37,6 +42,9 @@ windowWasResized: bool mouseWheel: float32 Engine* = object + applicationName: string + debug: bool + showFps: bool state*: EngineState device: Device debugger: Debugger @@ -48,6 +56,8 @@ resizeHandler: proc(engine: var Engine) eventHandler: proc(engine: var Engine, event: Event) fullscreen: bool + lastNRenderTimes: array[COUNT_N_RENDERTIMES, int64] + currentRenderTimeI: int = 0 # forward declarations func getAspectRatio*(engine: Engine): float32 @@ -66,6 +76,7 @@ proc initEngine*( applicationName: string, debug = DEBUG, + showFps = DEBUG, exitHandler: proc(engine: var Engine) = nil, resizeHandler: proc(engine: var Engine) = nil, eventHandler: proc(engine: var Engine, event: Event) = nil, @@ -79,34 +90,34 @@ result.exitHandler = exitHandler result.resizeHandler = resizeHandler result.eventHandler = eventHandler - result.window = createWindow(applicationName) + result.applicationName = applicationName + result.debug = debug + result.showFps = showFps + result.window = createWindow(result.applicationName) var layers = @vulkanLayers instanceExtensions: seq[string] - if debug: + if result.debug: instanceExtensions.add "VK_EXT_debug_utils" layers.add "VK_LAYER_KHRONOS_validation" # This stuff might be usefull if we one day to smart GPU memory allocation, - # but right now it just clobbers up the console log + # but right now it just clobbers up the console log: # putEnv("VK_LAYER_ENABLES", "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT") putEnv("VK_LAYER_ENABLES", "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD,VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXTVK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT") - if defined(linux) and DEBUG: - layers.add "VK_LAYER_MESA_overlay" result.instance = result.window.createInstance( vulkanVersion = vulkanVersion, instanceExtensions = instanceExtensions, - layers = layers, + layers = layers.deduplicate(), ) - if debug: + if result.debug: result.debugger = result.instance.createDebugMessenger() # create devices let selectedPhysicalDevice = result.instance.getPhysicalDevices().filterBestGraphics() result.device = result.instance.createDevice( selectedPhysicalDevice, - enabledLayers = @[], enabledExtensions = @[], selectedPhysicalDevice.filterForGraphicsPresentationQueues() ) @@ -154,11 +165,26 @@ proc renderScene*(engine: var Engine, scene: var Scene) = assert engine.state == Running assert engine.renderer.isSome + let t0 = getMonoTime() scene.setShaderGlobal(ASPECT_RATIO_ATTRIBUTE, engine.getAspectRatio) engine.renderer.get.updateMeshData(scene) engine.renderer.get.updateUniformData(scene) engine.renderer.get.render(scene) + if engine.showFps: + let nanoSecs = getMonoTime().ticks - t0.ticks + engine.lastNRenderTimes[engine.currentRenderTimeI] = nanoSecs + inc engine.currentRenderTimeI + if engine.currentRenderTimeI >= engine.lastNRenderTimes.len: + engine.currentRenderTimeI = 0 + engine.lastNRenderTimes.sort + let + min = float(engine.lastNRenderTimes[0]) / 1_000_000 + median = float(engine.lastNRenderTimes[engine.lastNRenderTimes.len div 2]) / 1_000_000 + max = float(engine.lastNRenderTimes[^1]) / 1_000_000 + engine.window.setTitle(&"{engine.applicationName} ({min:.2}, {median:.2}, {max:.2})") + + proc updateInputs*(engine: var Engine): EngineState = assert engine.state in [Starting, Running] diff -r 7a0d5fc00f4f -r 9c364af8d3f0 semicongine/mesh.nim --- a/semicongine/mesh.nim Sun Mar 31 18:13:46 2024 +0700 +++ b/semicongine/mesh.nim Sun Mar 31 22:11:50 2024 +0700 @@ -384,6 +384,7 @@ mesh.instanceData[attribute][i] = transform * mesh.vertexData[attribute][i, T] else: raise newException(Exception, &"Attribute {attribute} is not defined for mesh {mesh}") + mesh.dirtyAttributes.add attribute proc applyTransformToVertices*(mesh: var MeshObject, positionAttribute = DEFAULT_POSITION_ATTRIBUTE) = for i in 0 ..< mesh.vertexData[positionAttribute].len: diff -r 7a0d5fc00f4f -r 9c364af8d3f0 semicongine/platform/linux/window.nim --- a/semicongine/platform/linux/window.nim Sun Mar 31 18:13:46 2024 +0700 +++ b/semicongine/platform/linux/window.nim Sun Mar 31 22:11:50 2024 +0700 @@ -77,6 +77,9 @@ checkXlibResult display.XFreePixmap(pixmap) return NativeWindow(display: display, window: window, emptyCursor: empty_cursor) +proc setTitle*(window: NativeWindow, title: string) = + checkXlibResult XSetStandardProperties(window.display, window.window, title, "window", 0, nil, 0, nil) + proc fullscreen*(window: var NativeWindow, enable: bool) = var wm_state = window.display.XInternAtom("_NET_WM_STATE", 0) @@ -94,8 +97,8 @@ 0, 0, 0 - ] - ) + ] + ) ) xev.theType = ClientMessage diff -r 7a0d5fc00f4f -r 9c364af8d3f0 semicongine/platform/windows/window.nim --- a/semicongine/platform/windows/window.nim Sun Mar 31 18:13:46 2024 +0700 +++ b/semicongine/platform/windows/window.nim Sun Mar 31 22:11:50 2024 +0700 @@ -100,6 +100,9 @@ result.g_wpPrev.length = UINT(sizeof(WINDOWPLACEMENT)) discard result.hwnd.ShowWindow(SW_SHOW) +proc setTitle*(window: NativeWindow, title: string) + window.hwnd.SetWindowText(T(title)) + # inspired by the one and only, Raymond Chen # https://devblogs.microsoft.com/oldnewthing/20100412-00/?p=14353 proc fullscreen*(window: var NativeWindow, enable: bool) = diff -r 7a0d5fc00f4f -r 9c364af8d3f0 semicongine/renderer.nim --- a/semicongine/renderer.nim Sun Mar 31 18:13:46 2024 +0700 +++ b/semicongine/renderer.nim Sun Mar 31 22:11:50 2024 +0700 @@ -362,7 +362,7 @@ if forceAll: debug "Update uniforms because 'forceAll' was given" - else: + elif dirty.len > 0: debug &"Update uniforms because of dirty scene globals: {dirty}" # loop over all used shaders/pipelines @@ -411,25 +411,31 @@ offset += uniform.size scene.clearDirtyShaderGlobals() +proc startNewFrame(renderer: var Renderer) = + # this is kinda important as we will wait for the queue finished fence from the swapchain + if not renderer.swapchain.nextFrame(): + let res = renderer.swapchain.recreate() + if not res.isSome: + raise newException(Exception, "Unable to recreate swapchain") + var oldSwapchain = renderer.swapchain + renderer.swapchain = res.get() + checkVkResult renderer.device.vk.vkDeviceWaitIdle() + oldSwapchain.destroy() + proc render*(renderer: var Renderer, scene: Scene) = assert scene in renderer.scenedata - if not renderer.swapchain.nextFrame(): - let res = renderer.swapchain.recreate() - if res.isSome: - var oldSwapchain = renderer.swapchain - renderer.swapchain = res.get() - checkVkResult renderer.device.vk.vkDeviceWaitIdle() - oldSwapchain.destroy() - return - + # preparation + renderer.startNewFrame() renderer.currentFrameCommandBuffer.beginRenderCommands(renderer.renderPass, renderer.swapchain.currentFramebuffer(), oneTimeSubmit = true) + # debug output debug "Scene buffers:" for (location, buffer) in renderer.scenedata[scene].vertexBuffers.pairs: debug " ", location, ": ", buffer debug " Index buffer: ", renderer.scenedata[scene].indexBuffer + # draw all meshes for (materialType, shaderPipeline) in renderer.renderPass.shaderPipelines: if scene.usesMaterial(materialType): debug &"Start shaderPipeline for '{materialType}'" @@ -438,8 +444,10 @@ for (drawable, mesh) in renderer.scenedata[scene].drawables.filterIt(it[1].visible and it[1].material.theType == materialType): drawable.draw(renderer.currentFrameCommandBuffer, vertexBuffers = renderer.scenedata[scene].vertexBuffers, indexBuffer = renderer.scenedata[scene].indexBuffer, shaderPipeline.vk) + # done rendering renderer.currentFrameCommandBuffer.endRenderCommands() + # swap framebuffer if not renderer.swapchain.swap(renderer.queue, renderer.currentFrameCommandBuffer): let res = renderer.swapchain.recreate() if res.isSome: diff -r 7a0d5fc00f4f -r 9c364af8d3f0 semicongine/scene.nim --- a/semicongine/scene.nim Sun Mar 31 18:13:46 2024 +0700 +++ b/semicongine/scene.nim Sun Mar 31 22:11:50 2024 +0700 @@ -58,6 +58,8 @@ scene.getShaderGlobalArray(name)[][0] proc setShaderGlobalArray*[T](scene: var Scene, name: string, value: openArray[T]) = + if scene.shaderGlobals[name, T][] == @value: + return scene.shaderGlobals[name] = value if not scene.dirtyShaderGlobals.contains(name): scene.dirtyShaderGlobals.add name diff -r 7a0d5fc00f4f -r 9c364af8d3f0 semicongine/vulkan/buffer.nim --- a/semicongine/vulkan/buffer.nim Sun Mar 31 18:13:46 2024 +0700 +++ b/semicongine/vulkan/buffer.nim Sun Mar 31 22:11:50 2024 +0700 @@ -99,6 +99,7 @@ proc copy*(src, dst: Buffer, queue: Queue, dstOffset = 0) = + # TODO? This is super slow, because withSingleUseCommandBuffer uses vkQueueWaitIdle assert src.device.vk.valid assert dst.device.vk.valid assert src.device == dst.device @@ -108,14 +109,16 @@ var copyRegion = VkBufferCopy(size: VkDeviceSize(src.size), dstOffset: VkDeviceSize(dstOffset)) withSingleUseCommandBuffer(src.device, queue, true, commandBuffer): + # TODO: This barrier is somehow "reversed" + # I think we need to check for the queue-finished fence before we + # do any buffer updates, otherwise will append buffer updates after the draw calls let barrier = VkMemoryBarrier( sType: VK_STRUCTURE_TYPE_MEMORY_BARRIER, - srcAccessMask: [VK_ACCESS_MEMORY_WRITE_BIT].toBits, - dstAccessMask: [VK_ACCESS_MEMORY_READ_BIT].toBits, + dstAccessMask: [VK_ACCESS_MEMORY_WRITE_BIT].toBits, ) commandBuffer.pipelineBarrier( + [VK_PIPELINE_STAGE_VERTEX_INPUT_BIT], [VK_PIPELINE_STAGE_TRANSFER_BIT], - [VK_PIPELINE_STAGE_VERTEX_INPUT_BIT], memoryBarriers = [barrier] ) commandBuffer.vkCmdCopyBuffer(src.vk, dst.vk, 1, addr(copyRegion)) diff -r 7a0d5fc00f4f -r 9c364af8d3f0 semicongine/vulkan/commandbuffer.nim --- a/semicongine/vulkan/commandbuffer.nim Sun Mar 31 18:13:46 2024 +0700 +++ b/semicongine/vulkan/commandbuffer.nim Sun Mar 31 22:11:50 2024 +0700 @@ -55,10 +55,10 @@ template withSingleUseCommandBuffer*(device: Device, queue: Queue, needsTransfer: bool, commandBuffer, body: untyped): untyped = + # TODO? This is super slow, because we call vkQueueWaitIdle assert device.vk.valid assert queue.vk.valid - checkVkResult queue.vk.vkQueueWaitIdle() var commandBufferPool = createCommandBufferPool(device, queue.family, 1) commandBuffer = commandBufferPool.buffers[0] diff -r 7a0d5fc00f4f -r 9c364af8d3f0 semicongine/vulkan/device.nim --- a/semicongine/vulkan/device.nim Sun Mar 31 18:13:46 2024 +0700 +++ b/semicongine/vulkan/device.nim Sun Mar 31 22:11:50 2024 +0700 @@ -24,7 +24,6 @@ proc createDevice*( instance: Instance, physicalDevice: PhysicalDevice, - enabledLayers: seq[string], enabledExtensions: seq[string], queueFamilies: seq[QueueFamily], ): Device = @@ -37,7 +36,6 @@ for extension in allExtensions: instance.vk.loadExtension(extension) var - enabledLayersC = allocCStringArray(enabledLayers) enabledExtensionsC = allocCStringArray(allExtensions) priority = 1'f32 var deviceQueues: Table[QueueFamily, VkDeviceQueueCreateInfo] @@ -58,8 +56,8 @@ sType: VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, queueCreateInfoCount: uint32(queueList.len), pQueueCreateInfos: queueList.toCPointer, - enabledLayerCount: uint32(enabledLayers.len), - ppEnabledLayerNames: enabledLayersC, + enabledLayerCount: 0, + ppEnabledLayerNames: nil, enabledExtensionCount: uint32(allExtensions.len), ppEnabledExtensionNames: enabledExtensionsC, pEnabledFeatures: nil, @@ -72,7 +70,6 @@ pAllocator = nil, pDevice = addr result.vk ) - deallocCStringArray(enabledLayersC) deallocCStringArray(enabledExtensionsC) for family in deviceQueues.keys: var queue: VkQueue diff -r 7a0d5fc00f4f -r 9c364af8d3f0 semicongine/vulkan/swapchain.nim --- a/semicongine/vulkan/swapchain.nim Sun Mar 31 18:13:46 2024 +0700 +++ b/semicongine/vulkan/swapchain.nim Sun Mar 31 22:11:50 2024 +0700 @@ -14,18 +14,17 @@ device*: Device vk*: VkSwapchainKHR dimension*: TVec2[uint32] - nImages*: uint32 - imageviews*: seq[ImageView] - framebuffers*: seq[Framebuffer] + nFramebuffers*: uint32 currentInFlight*: int currentFramebufferIndex: uint32 + framebufferViews*: seq[ImageView] + framebuffers*: seq[Framebuffer] queueFinishedFence*: seq[Fence] imageAvailableSemaphore*: seq[Semaphore] renderFinishedSemaphore*: seq[Semaphore] # required for recreation: renderPass: VkRenderPass surfaceFormat: VkSurfaceFormatKHR - imageCount: uint32 inFlightFrames*: int presentQueue: Queue vSync: bool @@ -36,7 +35,7 @@ renderPass: VkRenderPass, surfaceFormat: VkSurfaceFormatKHR, inFlightFrames: int, - desiredNumberOfImages = 3'u32, + desiredFramebufferCount = 3'u32, oldSwapchain = VkSwapchainKHR(0), vSync = false ): Option[Swapchain] = @@ -49,17 +48,17 @@ if capabilities.currentExtent.width == 0 or capabilities.currentExtent.height == 0: return none(Swapchain) - var imageCount = desiredNumberOfImages + var minFramebufferCount = desiredFramebufferCount # following is according to vulkan specs - imageCount = max(imageCount, capabilities.minImageCount) + minFramebufferCount = max(minFramebufferCount, capabilities.minImageCount) if capabilities.maxImageCount != 0: - imageCount = min(imageCount, capabilities.maxImageCount) + minFramebufferCount = min(minFramebufferCount, capabilities.maxImageCount) let hasTripleBuffering = VK_PRESENT_MODE_MAILBOX_KHR in device.physicalDevice.getSurfacePresentModes() var createInfo = VkSwapchainCreateInfoKHR( sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, surface: device.physicalDevice.surface, - minImageCount: imageCount, + minImageCount: minFramebufferCount, imageFormat: surfaceFormat.format, imageColorSpace: surfaceFormat.colorSpace, imageExtent: capabilities.currentExtent, @@ -83,22 +82,19 @@ vSync: vSync ) - if device.vk.vkCreateSwapchainKHR(addr(createInfo), nil, addr(swapchain.vk)) == VK_SUCCESS: - var nImages: uint32 - checkVkResult device.vk.vkGetSwapchainImagesKHR(swapChain.vk, addr(nImages), nil) - swapchain.nImages = nImages - var images = newSeq[VkImage](nImages) - checkVkResult device.vk.vkGetSwapchainImagesKHR(swapChain.vk, addr(nImages), images.toCPointer) - for vkimage in images: - let image = VulkanImage(vk: vkimage, format: surfaceFormat.format, device: device) - let imageview = image.createImageView() - swapChain.imageviews.add imageview - swapChain.framebuffers.add device.createFramebuffer(renderPass, [imageview], swapchain.dimension) + if device.vk.vkCreateSwapchainKHR(addr createInfo, nil, addr swapchain.vk) == VK_SUCCESS: + checkVkResult device.vk.vkGetSwapchainImagesKHR(swapchain.vk, addr swapchain.nFramebuffers, nil) + var framebuffers = newSeq[VkImage](swapchain.nFramebuffers) + checkVkResult device.vk.vkGetSwapchainImagesKHR(swapchain.vk, addr swapchain.nFramebuffers, framebuffers.toCPointer) + for framebuffer in framebuffers: + let framebufferView = VulkanImage(vk: framebuffer, format: surfaceFormat.format, device: device).createImageView() + swapchain.framebufferViews.add framebufferView + swapchain.framebuffers.add device.createFramebuffer(renderPass, [framebufferView], swapchain.dimension) for i in 0 ..< swapchain.inFlightFrames: swapchain.queueFinishedFence.add device.createFence() swapchain.imageAvailableSemaphore.add device.createSemaphore() swapchain.renderFinishedSemaphore.add device.createSemaphore() - debug &"Created swapchain with: {nImages} framebuffers, {inFlightFrames} in-flight frames, {swapchain.dimension.x}x{swapchain.dimension.y}" + debug &"Created swapchain with: {swapchain.nFramebuffers} framebuffers, {inFlightFrames} in-flight frames, {swapchain.dimension.x}x{swapchain.dimension.y}" assert device.firstPresentationQueue().isSome, "No present queue found" swapchain.presentQueue = device.firstPresentationQueue().get result = some(swapchain) @@ -122,7 +118,7 @@ high(uint64), swapchain.imageAvailableSemaphore[swapchain.currentInFlight].vk, VkFence(0), - addr(swapchain.currentFramebufferIndex) + addr swapchain.currentFramebufferIndex, ) if nextImageResult == VK_SUCCESS: @@ -142,29 +138,29 @@ submitInfo = VkSubmitInfo( sType: VK_STRUCTURE_TYPE_SUBMIT_INFO, waitSemaphoreCount: 1, - pWaitSemaphores: addr(waitSemaphores[0]), - pWaitDstStageMask: addr(waitStages[0]), + pWaitSemaphores: waitSemaphores.toCPointer, + pWaitDstStageMask: waitStages.toCPointer, commandBufferCount: 1, - pCommandBuffers: addr(commandBuffer), + pCommandBuffers: addr commandBuffer, signalSemaphoreCount: 1, - pSignalSemaphores: addr(swapchain.renderFinishedSemaphore[swapchain.currentInFlight].vk), + pSignalSemaphores: addr swapchain.renderFinishedSemaphore[swapchain.currentInFlight].vk, ) checkVkResult queue.vk.vkQueueSubmit( - 1, - addr(submitInfo), - swapchain.queueFinishedFence[swapchain.currentInFlight].vk + submitCount = 1, + pSubmits = addr submitInfo, + fence = swapchain.queueFinishedFence[swapchain.currentInFlight].vk ) var presentInfo = VkPresentInfoKHR( sType: VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, waitSemaphoreCount: 1, - pWaitSemaphores: addr(swapchain.renderFinishedSemaphore[swapchain.currentInFlight].vk), + pWaitSemaphores: addr swapchain.renderFinishedSemaphore[swapchain.currentInFlight].vk, swapchainCount: 1, - pSwapchains: addr(swapchain.vk), - pImageIndices: addr(swapchain.currentFramebufferIndex), + pSwapchains: addr swapchain.vk, + pImageIndices: addr swapchain.currentFramebufferIndex, pResults: nil, ) - let presentResult = vkQueuePresentKHR(swapchain.presentQueue.vk, addr(presentInfo)) + let presentResult = vkQueuePresentKHR(swapchain.presentQueue.vk, addr presentInfo) if presentResult != VK_SUCCESS: return false @@ -174,7 +170,7 @@ proc destroy*(swapchain: var Swapchain) = assert swapchain.vk.valid - for imageview in swapchain.imageviews.mitems: + for imageview in swapchain.framebufferViews.mitems: assert imageview.vk.valid imageview.destroy() for framebuffer in swapchain.framebuffers.mitems: @@ -198,7 +194,7 @@ device = swapchain.device, renderPass = swapchain.renderPass, surfaceFormat = swapchain.surfaceFormat, - desiredNumberOfImages = swapchain.imageCount, + desiredFramebufferCount = swapchain.nFramebuffers, inFlightFrames = swapchain.inFlightFrames, oldSwapchain = swapchain.vk, vSync = swapchain.vSync