From 62b61fb88306158bb8ef7a733a0c5ce2e75a2497 Mon Sep 17 00:00:00 2001 From: Matthew Date: Sun, 14 Jun 2026 07:56:10 +1000 Subject: [PATCH] use swapchain image per framebuffer, remove built in descriptor set --- vulkan/convert.comp.glsl | 22 ++-- vulkan/vulkan.d | 262 ++++++++++++++------------------------- 2 files changed, 103 insertions(+), 181 deletions(-) diff --git a/vulkan/convert.comp.glsl b/vulkan/convert.comp.glsl index e041ad0..5811268 100644 --- a/vulkan/convert.comp.glsl +++ b/vulkan/convert.comp.glsl @@ -2,23 +2,23 @@ #extension GL_EXT_shader_8bit_storage : require -layout (constant_id = 0) const int CHANNELS = 3; - layout (local_size_x = 32, local_size_y = 32) in; -layout (push_constant) uniform Constants { +layout (constant_id = 0) const int CHANNELS = 3; + +layout (push_constant) uniform Constants +{ uint x; uint y; } PC; -layout (set = 1, binding = 0, rgba32f) uniform image2D dst; +layout (set = 0, binding = 0, rgba32f) uniform image2D dst; -layout (set = 1, binding = 1) buffer input_array +layout (set = 0, binding = 1) buffer input_array { uint8_t src[]; }; - void main() { uint x = gl_GlobalInvocationID.x; @@ -33,23 +33,23 @@ void main() { uint index = x + y * PC.x; - vec4 col = vec4(vec3(uint(src[index]) / 255.0), 1.0); + vec4 col = vec4(vec3(uint(src[index]) / 255.0), 1.0); imageStore(dst, ivec2(x, y), col); } else if(CHANNELS == 2) { uint index = (x + y * PC.x) * 2; - float f = uint(src[index]) / 255.0; - float a = uint(src[index+1]) / 255.0; - vec4 col = vec4(f, f, f, a); + float f = uint(src[index]) / 255.0; + float a = uint(src[index+1]) / 255.0; + vec4 col = vec4(f, f, f, a); imageStore(dst, ivec2(x, y), col); } else if(CHANNELS == 3) { uint index = (x + y * PC.x) * 3; - vec4 col = vec4(uint(src[index]) / 255.0, uint(src[index+1]) / 255.0, uint(src[index+2]) / 255.0, 1.0); + vec4 col = vec4(uint(src[index]) / 255.0, uint(src[index+1]) / 255.0, uint(src[index+2]) / 255.0, 1.0); imageStore(dst, ivec2(x, y), col); } } diff --git a/vulkan/vulkan.d b/vulkan/vulkan.d index 588c5ec..de85623 100644 --- a/vulkan/vulkan.d +++ b/vulkan/vulkan.d @@ -493,12 +493,12 @@ struct Vulkan bool recreate_swapchain; VkRenderPass render_pass; - VkFramebuffer framebuffer; + VkFramebuffer[] framebuffers; + u32 image_index; Descriptor[] present_images; - u32 image_index; + Descriptor depth_image; + Format present_image_format; - Descriptor draw_image; - Descriptor depth_image; VkCommandPool[FRAME_OVERLAP] cmd_pools; VkCommandBuffer[FRAME_OVERLAP] cmds; @@ -541,77 +541,19 @@ struct Vulkan f32[4] color_clear; f32[4] depth_clear; - @property VkCommandPool - cmd_pool() - { - return this.cmd_pools[this.frame_index]; - } - - @property VkCommandBuffer - cmd() - { - return this.cmds[this.frame_index]; - } - - @property VkSemaphore - acquire_sem() - { - return this.acquire_sems[this.frame_index]; - } - - @property VkSemaphore* - acquire_sem_ptr() - { - return this.acquire_sems.ptr + this.frame_index; - } - - @property VkFence - render_fence() - { - return this.render_fences[this.frame_index]; - } - - @property VkFence* - render_fence_ptr() - { - return this.render_fences.ptr + this.frame_index; - } - - @property VkPipeline - last_pipeline() - { - return this.last_pipelines[this.frame_index]; - } - - @property VkPipeline - last_pipeline(VkPipeline pipeline) - { - return this.last_pipelines[this.frame_index] = pipeline; - } - - @property VkSemaphore - submit_sem() - { - return this.submit_sems[this.image_index]; - } - - @property ref Descriptor - present_image() - { - return this.present_images[this.image_index]; - } - - @property Descriptor* - present_image_ptr() - { - return this.present_images.ptr + this.image_index; - } - - Arena* - FrameArena() - { - return &this.frame_arenas[this.frame_index]; - } + @property VkCommandPool cmd_pool() => this.cmd_pools[this.frame_index]; + @property VkCommandBuffer cmd() => this.cmds[this.frame_index]; + @property VkSemaphore acquire_sem() => this.acquire_sems[this.frame_index]; + @property VkSemaphore* acquire_sem_ptr() => this.acquire_sems.ptr + this.frame_index; + @property VkFence render_fence() => this.render_fences[this.frame_index]; + @property VkFence* render_fence_ptr() => this.render_fences.ptr + this.frame_index; + @property VkPipeline last_pipeline() => this.last_pipelines[this.frame_index]; + @property VkPipeline last_pipeline(VkPipeline pipeline) => this.last_pipelines[this.frame_index] = pipeline; + @property VkSemaphore submit_sem() => this.submit_sems[this.image_index]; + @property ref Descriptor present_image() => this.present_images[this.image_index]; + @property Descriptor* present_image_ptr() => this.present_images.ptr + this.image_index; + @property VkFramebuffer framebuffer() => this.framebuffers[this.image_index]; + @property Arena* frame_arena() => &this.frame_arenas[this.frame_index]; alias queues this; } @@ -693,23 +635,17 @@ CreatePipelineLayout(T)(T layouts, u32 push_const_size, bool compute = false) if { VkShaderStageFlagBits stage = (compute ? VK_SHADER_STAGE_COMPUTE_BIT : VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); - DescSetLayout[] desc_layouts; + u32 desc_layouts_length = 1; + DescSetLayout* desc_layouts; static if(is(T: DescSetLayout)) { - desc_layouts = Alloc!(DescSetLayout)(g_vk.FrameArena(), 2); - desc_layouts[0] = g_vk.global_set_layout; - desc_layouts[1] = layouts; + desc_layouts = &layouts; } else static if(is(T: DescSetLayout[])) { - desc_layouts = Alloc!(DescSetLayout)(g_vk.FrameArena(), layouts.length + 1); - desc_layouts[0] = g_vk.global_set_layout; - - foreach(i; 0 .. layouts.length) - { - desc_layouts[i+1] = layouts[i]; - } + desc_layouts_length = cast(u32)layouts.length; + desc_layouts = layouts.ptr; } VkPushConstantRange const_range = { @@ -720,8 +656,8 @@ CreatePipelineLayout(T)(T layouts, u32 push_const_size, bool compute = false) if VkPipelineLayoutCreateInfo layout_info = { sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - setLayoutCount: cast(u32)desc_layouts.length, - pSetLayouts: desc_layouts.ptr, + setLayoutCount: desc_layouts_length, + pSetLayouts: desc_layouts, pushConstantRangeCount: (push_const_size > 0 ? 1 : 0), pPushConstantRanges: (push_const_size > 0 ? &const_range : null), }; @@ -831,7 +767,7 @@ BeginFrame() result = vkResetFences(g_vk.device, 1, g_vk.render_fence_ptr); VkCheckA("BeginFrame failure: vkResetFences error", result); - Reset(g_vk.FrameArena()); + Reset(g_vk.frame_arena); // ?? dont know why this is 3 (should have commented it) for(u64 i = 0; i < 3; i += 1) @@ -880,11 +816,9 @@ SetClearColors(f32[4] color_clear, f32[4] depth_clear) void BeginRendering() { - Transition(g_vk.cmd, &g_vk.draw_image, IL.ColorAttach); + Transition(g_vk.cmd, g_vk.present_image_ptr, IL.ColorAttach); Transition(g_vk.cmd, &g_vk.depth_image, IL.DepthAttach); - Transition(g_vk.cmd, g_vk.present_image_ptr, IL.TransferDst); - VkClearValue[2] clear_color = [ { color: { float32: g_vk.color_clear } }, { color: { float32: g_vk.depth_clear } }, @@ -922,9 +856,21 @@ GetAspect() } void -PrepComputeDrawImage() +PrepComputeImage(Descriptor* descriptor) { - Transition(g_vk.cmd, &g_vk.draw_image, IL.General); + Transition(g_vk.cmd, descriptor, IL.General); +} + +void +CopyToPresentImage(Descriptor* descriptor, UVec2 extent) +{ + Transition(g_vk.cmd, descriptor, IL.TransferSrc); + Transition(g_vk.cmd, g_vk.present_image_ptr, IL.TransferDst); + + VkExtent2D src_extent = { width: extent.x, height: extent.y }; + VkExtent2D dst_extent = { width: g_vk.swapchain_extent.width, height: g_vk.swapchain_extent.height }; + + Copy(g_vk.cmd, descriptor, g_vk.present_image_ptr, src_extent, dst_extent); } void @@ -936,27 +882,10 @@ FinishRendering() void SubmitAndPresent() { - scope(exit) - { - g_vk.last_pipeline = null; - g_vk.frame_index = (g_vk.frame_index + 1) % FRAME_OVERLAP; - } - - VkImage image = g_vk.present_image.image.image; VkSemaphore acquire_sem = g_vk.acquire_sem; VkSemaphore submit_sem = g_vk.submit_sem; - Transition(g_vk.cmd, &g_vk.draw_image, IL.TransferSrc); - - VkExtent2D extent = { - width: g_vk.swapchain_extent.width, - height: g_vk.swapchain_extent.height, - }; - - // TODO: Find out how to copy from same dimension images (pretty sure its not blitting) - Copy(g_vk.cmd, &g_vk.draw_image, image, IL.TransferDst, extent, extent); - - Transition(g_vk.cmd, image, IL.TransferDst, IL.PresentSrc); + Transition(g_vk.cmd, g_vk.present_image_ptr, IL.PresentSrc); VkResult result = vkEndCommandBuffer(g_vk.cmd); VkCheckA("FinishFrame failure: vkEndCommandBuffer error", result); @@ -1016,6 +945,9 @@ SubmitAndPresent() { g_vk.frame_started = false; } + + g_vk.last_pipeline = null; + g_vk.frame_index = (g_vk.frame_index + 1) % FRAME_OVERLAP; } void @@ -1585,7 +1517,7 @@ Bind(Pipeline pipeline_handle, DescSet[] sets, bool compute = false) u32[] offsets; if(g_vk.global_set.dynamic_count > 0) { - offsets = Alloc!(u32)(g_vk.FrameArena(), g_vk.global_set.dynamic_count); + offsets = Alloc!(u32)(g_vk.frame_arena, g_vk.global_set.dynamic_count); } vkCmdBindDescriptorSets( @@ -1600,7 +1532,7 @@ Bind(Pipeline pipeline_handle, DescSet[] sets, bool compute = false) ); u32 offset_count; - VkDescriptorSet[] handles = Alloc!(VkDescriptorSet)(g_vk.FrameArena(), sets.length); + VkDescriptorSet[] handles = Alloc!(VkDescriptorSet)(g_vk.frame_arena, sets.length); foreach(i, set; sets) { @@ -1610,7 +1542,7 @@ Bind(Pipeline pipeline_handle, DescSet[] sets, bool compute = false) if(offset_count > 0) { - offsets = Alloc!(u32)(g_vk.FrameArena(), offset_count); + offsets = Alloc!(u32)(g_vk.frame_arena, offset_count); } vkCmdBindDescriptorSets( @@ -1647,7 +1579,7 @@ Bind(Pipeline pipeline_handle, DescSet set, bool compute = false) u32[] offsets; if(g_vk.global_set.dynamic_count > 0) { - offsets = Alloc!(u32)(g_vk.FrameArena(), g_vk.global_set.dynamic_count); + offsets = Alloc!(u32)(g_vk.frame_arena, g_vk.global_set.dynamic_count); } vkCmdBindDescriptorSets( @@ -1663,7 +1595,7 @@ Bind(Pipeline pipeline_handle, DescSet set, bool compute = false) if(set.dynamic_count > 0) { - offsets = Alloc!(u32)(g_vk.FrameArena(), set.dynamic_count); + offsets = Alloc!(u32)(g_vk.frame_arena, set.dynamic_count); } vkCmdBindDescriptorSets( @@ -1856,7 +1788,7 @@ CreateGraphicsPipeline(Pipeline* pipeline_handle, GfxPipelineInfo* build_info) VkPipelineRenderingCreateInfo rendering_info = { sType: VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, colorAttachmentCount: 1, - pColorAttachmentFormats: cast(VkFormat*)&g_vk.draw_image.image.format, + pColorAttachmentFormats: cast(VkFormat*)&g_vk.present_image_format, depthAttachmentFormat: g_vk.depth_image.image.format, }; @@ -2054,8 +1986,8 @@ ClearDepth(f32[4] color = [0.0, 0.0, 0.0, 0.0]) void ClearColor(f32[4] color) { - Transition(g_vk.cmd, &g_vk.draw_image, IL.TransferDst); - ClearColor(&g_vk.draw_image, color); + Transition(g_vk.cmd, g_vk.present_image_ptr, IL.TransferDst); + ClearColor(g_vk.present_image_ptr, color); } void @@ -2153,7 +2085,7 @@ PushDescriptorPool() void PrepareWrite(VkWriteDescriptorSet* write, DescSet set, Descriptor* desc) { - Arena* arena = g_vk.FrameArena(); + Arena* arena = g_vk.frame_arena; write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write.descriptorType = desc.type; @@ -2199,7 +2131,7 @@ PrepareWrite(VkWriteDescriptorSet* write, DescSet set, Descriptor* desc) void Write(DescSet set, Descriptor[] descs) { - Arena* arena = g_vk.FrameArena(); + Arena* arena = g_vk.frame_arena; VkWriteDescriptorSet[] writes = Alloc!(VkWriteDescriptorSet)(arena, descs.length); @@ -2419,13 +2351,12 @@ CreateSampler(Descriptor* desc, DescInfo* info) void CreateDrawImages() { - Format draw_format = cast(Format)GetDrawImageFormat(); - Format depth_format = cast(Format)VK_FORMAT_D32_SFLOAT; + g_vk.present_image_format = cast(Format)GetDrawImageFormat(); + Format depth_format = cast(Format)VK_FORMAT_D32_SFLOAT; u32 w = g_vk.swapchain_extent.width; u32 h = g_vk.swapchain_extent.height; - CreateDescriptor(&g_vk.draw_image, DescInfo(type: DT.StorageImage, format: draw_format, usage: IU.Draw, w: w, h: h, binding: 0)); CreateDescriptor(&g_vk.depth_image, DescInfo(type: DT.Image, format: depth_format, usage: IU.Depth, w: w, h: h, binding: 0)); } @@ -2433,7 +2364,7 @@ bool CreateSwapchain() { bool success = true; - Arena* arena = g_vk.FrameArena(); + Arena* arena = g_vk.frame_arena; VkSurfaceCapabilitiesKHR cap; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_vk.physical_device, g_vk.surface, &cap); @@ -2527,33 +2458,37 @@ RecreateSwapchain() vkDeviceWaitIdle(g_vk.device); Destroy(g_vk.swapchain, g_vk.present_images, g_vk.device); - Destroy(&g_vk.draw_image); Destroy(&g_vk.depth_image); - vkDestroyFramebuffer(g_vk.device, g_vk.framebuffer, null); + foreach(i; 0 .. g_vk.framebuffers.length) + { + vkDestroyFramebuffer(g_vk.device, g_vk.framebuffers[i], null); + } CreateSwapchain(); CreateDrawImages(); - Write(g_vk.global_set, &g_vk.draw_image); - CreateFramebuffer(); + CreateFramebuffers(); g_vk.recreate_swapchain = false; } void -CreateFramebuffer() +CreateFramebuffers() { - VkFramebufferCreateInfo framebuffer_info = { - sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - renderPass: g_vk.render_pass, - attachmentCount: 2, - pAttachments: [g_vk.draw_image.image.view, g_vk.depth_image.image.view], - width: g_vk.swapchain_extent.width, - height: g_vk.swapchain_extent.height, - layers: 1, - }; + foreach(i; 0 .. g_vk.framebuffers.length) + { + VkFramebufferCreateInfo framebuffer_info = { + sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + renderPass: g_vk.render_pass, + attachmentCount: 2, + pAttachments: [g_vk.present_images[i].image.view, g_vk.depth_image.image.view], + width: g_vk.swapchain_extent.width, + height: g_vk.swapchain_extent.height, + layers: 1, + }; - VkResult result = vkCreateFramebuffer(g_vk.device, &framebuffer_info, null, &g_vk.framebuffer); - VkCheckA("vkCreateFramebuffer failure", result); + VkResult result = vkCreateFramebuffer(g_vk.device, &framebuffer_info, null, &g_vk.framebuffers[i]); + VkCheckA("vkCreateFramebuffer failure", result); + } } void @@ -2681,7 +2616,7 @@ PrintShaderDisassembly(Pipeline pipeline_id, VkShaderStageFlagBits stage) VkResult result = vkGetShaderInfoAMD(g_vk.device, pipeline.handle, stage, VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD, &size, null); if(result == VK_SUCCESS) { - u8[] buf = Alloc!(u8)(g_vk.FrameArena(), size); + u8[] buf = Alloc!(u8)(g_vk.frame_arena, size); vkGetShaderInfoAMD(g_vk.device, pipeline.handle, stage, VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD, &size, buf.ptr); Logf("DISASSEMBLY:\n%r", buf); } @@ -3353,24 +3288,8 @@ Init(VulkanBuildInfo build_info, u64 permanent_mem, u64 frame_mem) if(success) { - PushDescriptorPool(); + PushDescriptorPool(); - if(success) - { - DescLayoutBinding[2] layout_bindings = [ - { binding: 0, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, - { binding: 1, descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, - ]; - - g_vk.global_set_layout = CreateDescSetLayout(layout_bindings); - g_vk.global_set = AllocDescSet(g_vk.global_set_layout); - - Write(g_vk.global_set, [g_vk.draw_image]); - } - } - - if(success) - { g_vk.pipeline_handles = Alloc!(PipelineHandles)(&g_vk.arena, 128); g_vk.pipeline_count += 1; @@ -3378,15 +3297,15 @@ Init(VulkanBuildInfo build_info, u64 permanent_mem, u64 frame_mem) g_vk.transfer_buf = CreateMappedBuffer!(u8)(BT.Staging, transfer_size); VkDescriptorSetLayoutBinding[2] layout_bindings = [ - { binding: 0, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_COMPUTE_BIT }, + { binding: 0, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_COMPUTE_BIT }, { binding: 1, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_COMPUTE_BIT }, ]; - g_vk.conv_desc_layout = CreateDescSetLayout(layout_bindings); - g_vk.conv_desc_set = AllocDescSet(g_vk.conv_desc_layout); + g_vk.conv_desc_layout = CreateDescSetLayout(layout_bindings); + g_vk.conv_desc_set = AllocDescSet(g_vk.conv_desc_layout); g_vk.conv_pipeline_layout = CreatePipelineLayout(g_vk.conv_desc_layout, ConvPushConst.sizeof, true); - u32 channels = 1; + u32 channels; SpecEntry[1] entries = [ { constantID: 0, @@ -3405,18 +3324,19 @@ Init(VulkanBuildInfo build_info, u64 permanent_mem, u64 frame_mem) }, }; - g_vk.r_to_rgba_pipeline = CreateComputePipeline(&conv_info); + channels = 1; + g_vk.r_to_rgba_pipeline = CreateComputePipeline(&conv_info); - channels = 2; - g_vk.rg_to_rgba_pipeline = CreateComputePipeline(&conv_info); + channels = 2; + g_vk.rg_to_rgba_pipeline = CreateComputePipeline(&conv_info); - channels = 3; + channels = 3; g_vk.rgb_to_rgba_pipeline = CreateComputePipeline(&conv_info); VkAttachmentDescription[2] attach_descriptions = [ { - format: g_vk.draw_image.image.format, + format: g_vk.present_image_format, samples: VK_SAMPLE_COUNT_1_BIT, loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR, storeOp: VK_ATTACHMENT_STORE_OP_STORE, @@ -3475,7 +3395,9 @@ Init(VulkanBuildInfo build_info, u64 permanent_mem, u64 frame_mem) VkResult result = vkCreateRenderPass(g_vk.device, &pass_info, null, &g_vk.render_pass); VkCheckA("vkCreateRenderPass failure", result); - CreateFramebuffer(); + g_vk.framebuffers = Alloc!(VkFramebuffer)(&g_vk.arena, g_vk.present_images.length); + + CreateFramebuffers(); } assert(success, "Error initializing vulkan");