diff --git a/assets/shaders/gradient.comp.spv b/assets/shaders/gradient.comp.spv index f0d9fd6..7ca2085 100644 Binary files a/assets/shaders/gradient.comp.spv and b/assets/shaders/gradient.comp.spv differ diff --git a/assets/shaders/gui.frag.spv b/assets/shaders/gui.frag.spv index d9f1e3d..6568e89 100644 Binary files a/assets/shaders/gui.frag.spv and b/assets/shaders/gui.frag.spv differ diff --git a/assets/shaders/gui.vert.spv b/assets/shaders/gui.vert.spv index 42d46a6..df1c78b 100644 Binary files a/assets/shaders/gui.vert.spv and b/assets/shaders/gui.vert.spv differ diff --git a/assets/shaders/pbr.frag.spv b/assets/shaders/pbr.frag.spv index 23992e9..33e0b49 100644 Binary files a/assets/shaders/pbr.frag.spv and b/assets/shaders/pbr.frag.spv differ diff --git a/src/gears/game.d b/src/gears/game.d index 2bed3a9..d5de655 100644 --- a/src/gears/game.d +++ b/src/gears/game.d @@ -61,33 +61,18 @@ struct Game PlatformWindow* window; - Pipeline pbr_pipeline; - Pipeline triangle_pipeline; - Pipeline compute_pipeline; Pipeline ui_pipeline; - Pipeline oit_pipeline; UIVertex[] ui_vertex_buf; u32[] ui_index_buf; u32 ui_count; ImageView draw_image, depth_image; - ImageView aux_image; GlobalUniforms globals; PushConst pc; Timer timer; - - Camera camera; - - Model tree; - Model rock; - Model magic_rock; - Model log; - Model stump; - - SLList!(Model) models; } Game @@ -109,11 +94,6 @@ InitGame(PlatformWindow* window) UVec2 ext = GetExtent(&g.rd); CreateImageView(&g.rd, &g.aux_image, ext.x, ext.y, FMT.R_U32, IU.Storage); - - GfxPipelineInfo triangle_info = { - vertex_shader: "shaders/triangle.vert.spv", - frag_shader: "shaders/triangle.frag.spv", - }; GfxPipelineInfo ui_info = { vertex_shader: "shaders/gui.vert.spv", @@ -128,39 +108,7 @@ InitGame(PlatformWindow* window) ], }; - GfxPipelineInfo pbr_info = { - vertex_shader: "shaders/pbr.vert.spv", - frag_shader: "shaders/pbr.frag.spv", - input_rate_stride: Vertex.sizeof, - vertex_attributes: [ - { binding: 0, location: 0, format: FMT.RGBA_F32, offset: 0 }, - { binding: 0, location: 1, format: FMT.RGBA_F32, offset: Vertex.tangent.offsetof }, - { binding: 0, location: 2, format: FMT.RGB_F32, offset: Vertex.pos.offsetof }, - { binding: 0, location: 3, format: FMT.RGB_F32, offset: Vertex.normal.offsetof }, - { binding: 0, location: 4, format: FMT.RG_F32, offset: Vertex.uv.offsetof }, - ] - }; - - GfxPipelineInfo oit_info = { - vertex_shader: "shaders/full_screen_triangle.vert.spv", - frag_shader: "shaders/oit.frag.spv", - }; - - CompPipelineInfo gradient_info = { - shader: "shaders/gradient.comp.spv", - }; - - g.pbr_pipeline = CreateGraphicsPipeline(&g.rd, &pbr_info); - g.triangle_pipeline = CreateGraphicsPipeline(&g.rd, &triangle_info); g.ui_pipeline = CreateGraphicsPipeline(&g.rd, &ui_info); - g.oit_pipeline = CreateGraphicsPipeline(&g.rd, &oit_info); - g.compute_pipeline = CreateComputePipeline(&g.rd, &gradient_info); - - g.rock = LoadModel(&g, "models/BigRock01.m3d"); - g.tree = LoadModel(&g, "models/Tree01.m3d"); - g.magic_rock = LoadModel(&g, "models/MagicRock01.m3d"); - g.log = LoadModel(&g, "models/Log01.m3d"); - g.stump = LoadModel(&g, "models/Stump01.m3d"); assert(g.aux_image.view != null); @@ -184,50 +132,6 @@ Copy(Model* dst, Model* src) void ProcessInputs(Game* g, Camera* cam) { - foreach(i; 0 .. g.window.inputs.count) - { - InputEvent event = g.window.inputs.events[i]; - switch(event.key) - { - case Input.One: - { - Node!(Model)* node = Alloc!(Node!(Model)); - Copy(&node.value, &g.tree); - node.value.pos = cam.pos; - PushFront(&g.models, node, null); - } break; - case Input.Two: - { - Node!(Model)* node = Alloc!(Node!(Model)); - Copy(&node.value, &g.rock); - node.value.pos = cam.pos; - PushFront(&g.models, node, null); - } break; - case Input.Three: - { - Node!(Model)* node = Alloc!(Node!(Model)); - Copy(&node.value, &g.magic_rock); - node.value.pos = cam.pos; - PushFront(&g.models, node, null); - } break; - case Input.Four: - { - Node!(Model)* node = Alloc!(Node!(Model)); - Copy(&node.value, &g.log); - node.value.pos = cam.pos; - PushFront(&g.models, node, null); - } break; - case Input.Five: - { - Node!(Model)* node = Alloc!(Node!(Model)); - Copy(&node.value, &g.stump); - node.value.pos = cam.pos; - PushFront(&g.models, node, null); - } break; - default: break; - } - } - HandleInputs(cam, &g.window.inputs); } @@ -276,30 +180,6 @@ Cycle(Game* g) BindUIBuffers(&g.rd); - Bind(&g.rd, &g.triangle_pipeline); - - Bind(&g.rd, &g.pbr_pipeline); - - g.pc.model_matrix = Mat4Identity(); - - Node!(Model)* model = g.models.first; - for(;;) - { - if (model == null) - { - break; - } - - DrawModel(g, &model.value); - model = model.next; - } - - ImageBarrier(&g.rd); - - Bind(&g.rd, &g.oit_pipeline); - - Draw(&g.rd, 3, 1); - FinishRendering(&g.rd); //ImageBarrier(&g.rd); @@ -330,17 +210,8 @@ void Destroy(Game* g) { WaitIdle(&g.rd); - Destroy(&g.rd, &g.pbr_pipeline); - Destroy(&g.rd, &g.triangle_pipeline); + Destroy(&g.rd, &g.ui_pipeline); - Destroy(&g.rd, &g.compute_pipeline); - - Destroy(&g.rd, &g.rock); - Destroy(&g.rd, &g.tree); - Destroy(&g.rd, &g.magic_rock); - Destroy(&g.rd, &g.log); - Destroy(&g.rd, &g.stump); - Destroy(&g.rd); } diff --git a/src/gears/vulkan.d b/src/gears/vulkan.d index a9f7275..0239e4c 100644 --- a/src/gears/vulkan.d +++ b/src/gears/vulkan.d @@ -17,15 +17,26 @@ import math; alias InitRenderer = Init; alias Renderer = Vulkan; alias Shader = VkShaderModule; -alias Pipeline = PipelineHandle; +alias Pipeline = u32; alias Attribute = VkVertexInputAttributeDescription; alias SpecEntry = VkSpecializationMapEntry; alias RenderPass = VkRenderPass; +alias DescSet = VkDescriptorSet; +alias DescSetLayout = VkDescriptorSetLayout; +alias PipelineLayout = VkPipelineLayout; + +struct DescLayoutBinding +{ + VkDescriptorSetLayoutBinding binding; + bool dynamic; +} bool g_VLAYER_SUPPORT = false; bool g_DEBUG_PRINTF = false; const FRAME_OVERLAP = 2; +const MAX_SETS = 1000; +const DESC_ARRAY_SIZE = 256; version(linux) { @@ -189,6 +200,7 @@ struct Buffer VkBuffer buffer; VmaAllocation alloc; u64 size; + bool dynamic; } struct ShaderUniforms @@ -225,9 +237,9 @@ struct GfxPipelineInfo struct CompPipelineInfo { - string shader; - Specialization spec; - VkPipelineLayout *layout; + string shader; + Specialization spec; + PipelineLayout layout; } struct PushConst @@ -248,7 +260,7 @@ enum StepInitialized : u32 FrameStructures, Swapchain, DrawImages, - Descriptors, + DescriptorPools, Pipelines, } @@ -328,16 +340,15 @@ struct Vulkan VkCommandBuffer imm_cmd; VkFence imm_fence; - VkDescriptorPool desc_pool; - VkDescriptorSet[DT.max] desc_sets; - VkDescriptorSetLayout[DT.max] desc_layouts; - DescBindings[DT.max] desc_bindings; + VkDescriptorPool active_pool; + SLList!(VkDescriptorPool) full_pools; VkSampler nearest_sampler; VkSampler oit_sampler; - VkPipeline[FRAME_OVERLAP] last_pipeline; - VkPipelineLayout pipeline_layout; + PipelineHandles[] pipeline_handles; + u32 pipeline_count; + Pipeline[FRAME_OVERLAP] last_pipeline; MappedBuffer!(u8) transfer_buf; MappedBuffer!(UIVertex) ui_vert_buf; @@ -347,9 +358,9 @@ struct Vulkan QueueInfo queues; - PipelineHandle r_to_rgba_pipeline; - PipelineHandle rg_to_rgba_pipeline; - PipelineHandle rgb_to_rgba_pipeline; + Pipeline r_to_rgba_pipeline; + Pipeline rg_to_rgba_pipeline; + Pipeline rgb_to_rgba_pipeline; VkDescriptorSet conv_desc_set; VkDescriptorSetLayout conv_desc_layout; VkPipelineLayout conv_pipeline_layout; @@ -369,10 +380,11 @@ struct ConvPushConst u32 y; } -struct PipelineHandle +struct PipelineHandles { VkPipeline handle; VkPipelineBindPoint type; + VkPipelineLayout layout; } struct QueueInfo @@ -415,6 +427,7 @@ Init(PlatformWindow* window, u64 permanent_mem, u64 frame_mem) if (success) success = CreateDrawImages(&vk); if (success) success = InitFrameStructures(&vk); if (success) success = InitDescriptors(&vk); + if (success) InitPipelines(&vk); if (success) InitBuffers(&vk); if (success) success = InitConversionPipeline(&vk); if (success) InitFramebufferAndRenderPass(&vk); @@ -424,110 +437,133 @@ Init(PlatformWindow* window, u64 permanent_mem, u64 frame_mem) return vk; } +void +InitPipelines(Vulkan* vk) +{ + vk.pipeline_handles = AllocArray!(PipelineHandles)(&vk.arena, 128); + vk.pipeline_count += 1; +} + +DescSetLayout +CreateDescSetLayout(Vulkan* vk, DescLayoutBinding[] bindings) +{ + VkDescriptorSetLayoutCreateInfo layout_info = { + sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + bindingCount: cast(u32)bindings.length, + pBindings: bindings.ptr, + }; + + DescSetLayout layout; + VkResult result = vkCreateDescriptorSetLayout(vk.device, &layout_info, null, &layout); + VkCheckA("vkCreateDescriptorSetLayout failure", result); + + return layout; +} + +DescSet +AllocDescSet(Vulkan* vk, DescSetLayout layout) +{ + VkDescriptorSetAllocateInfo alloc_info = { + sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + descriptorSetCount: 1, + pSetLayouts: &layout, + descriptorPool: vk.active_pool, + }; + + DescSet set; + VkResult result = vkAllocateDescriptorSets(vk.device, &alloc_info, &set); + if (result == VK_ERROR_OUT_OF_POOL_MEMORY || result == VK_ERROR_FRAGMENTED_POOL) + { + PushDescriptorPool(vk); + + alloc_info = vk.active_pool; + + result = vkAllocateDescriptorSets(vk.device, &alloc_info, &set); + VkCheckA("vkAllocateDescriptorSets failure", result); // TODO: look more into how to handle this + } + + return set; +} + +PipelineLayout +CreatePipelineLayout(Vulkan* vk, DescSetLayout[] layouts, u64 push_const_size, bool compute = false) +{ + VkShaderStageFlagBits stage = (compute ? VK_SHADER_STAGE_COMPUTE_BIT : VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); + + VkPushConstantRange const_range = { + offset: 0, + size: cast(VkDeviceSize)push_const_size, + stageFlags: stage, + }; + + VkPipelineLayoutCreateInfo layout_info = { + sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + setLayoutCount: cast(u32)layouts.length, + pSetLayouts: layouts.ptr, + pushConstantRangeCount: (push_const_size > 0 ? 1 : 0), + pPushConstantRanges: (push_const_size > 0 ? &const_range : null), + }; + + PipelineLayout layout; + VkResult result = vkCreatePipelineLayout(vk.device, &layout_info, null, &layout); + VkCheckA("CreatePipelineLayout failure", result); + + return layout; +} + bool InitConversionPipeline(Vulkan* vk) { Push(vk, SI.Pipelines); - VkDescriptorBindingFlags[] binding_flags; - binding_flags[] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT; - - VkDescriptorSetLayoutBindingFlagsCreateInfo flag_info = { - sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, - bindingCount: cast(u32)binding_flags.length, - pBindingFlags: binding_flags.ptr, - }; - VkDescriptorSetLayoutBinding[] layout_bindings = [ { 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 }, ]; - VkDescriptorSetLayoutCreateInfo set_info = { - sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - pNext: &flag_info, - bindingCount: cast(u32)layout_bindings.length, - pBindings: layout_bindings.ptr, - flags: VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, + vk.conv_desc_layout = CreateDescSetLayout(vk, layout_bindings); + vk.conv_desc_set = AllocDescSet(vk, vk.conv_desc_layout); + vk.conv_pipeline_layout = CreatePipelineLayout(vk, [vk.conv_desc_layout], ConvPushConst.sizeof, true); + + u32 channels = 1; + CompPipelineInfo conv_info = { + shader: "shaders/convert.comp.spv", + layout: vk.conv_pipeline_layout, + spec: { + data: &channels, + size: u32.sizeof, + entries: [ + { + constantID: 0, + size: u32.sizeof, + offset: 0, + } + ], + }, }; - VkResult result = vkCreateDescriptorSetLayout(vk.device, &set_info, null, &vk.conv_desc_layout); - bool success = VkCheck("InitConversionPipeline failure: vkCreateDescriptorSetLayout error", result); + vk.r_to_rgba_pipeline = CreateComputePipeline(vk, &conv_info); - if (success) - { - VkDescriptorSetAllocateInfo alloc_info = { - sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - descriptorSetCount: 1, - pSetLayouts: &vk.conv_desc_layout, - descriptorPool: vk.desc_pool, - }; + channels = 2; + vk.rg_to_rgba_pipeline = CreateComputePipeline(vk, &conv_info); - result = vkAllocateDescriptorSets(vk.device, &alloc_info, &vk.conv_desc_set); - success = VkCheck("InitConversionPipeline failure: vkAllocateDescriptorSets error", result); - } - - if (success) - { - VkPushConstantRange const_range = { - offset: 0, - size: cast(VkDeviceSize)ConvPushConst.sizeof, - stageFlags: VK_SHADER_STAGE_COMPUTE_BIT, - }; - - VkPipelineLayoutCreateInfo layout_info = { - sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - setLayoutCount: 1, - pSetLayouts: &vk.conv_desc_layout, - pushConstantRangeCount: 1, - pPushConstantRanges: &const_range, - }; - - result = vkCreatePipelineLayout(vk.device, &layout_info, null, &vk.conv_pipeline_layout); - success = VkCheck("InitConversionPipeline failure: vkCreatePipelineLayout error", result); - } - - if (success) - { - u32 channels = 1; - - CompPipelineInfo conv_info = { - shader: "shaders/convert.comp.spv", - layout: &vk.conv_pipeline_layout, - spec: { - data: &channels, - size: u32.sizeof, - entries: [ - { - constantID: 0, - size: u32.sizeof, - offset: 0, - } - ], - }, - }; - - vk.r_to_rgba_pipeline = CreateComputePipeline(vk, &conv_info); - - channels = 2; - vk.rg_to_rgba_pipeline = CreateComputePipeline(vk, &conv_info); - - channels = 3; - vk.rgb_to_rgba_pipeline = CreateComputePipeline(vk, &conv_info); - } + channels = 3; + vk.rgb_to_rgba_pipeline = CreateComputePipeline(vk, &conv_info); return success; } void -CreateBuffer(Vulkan* vk, Buffer* buf, BufferType type, u64 size, bool host_visible) +CreateBuffer(Vulkan* vk, Buffer* buf, BufferType type, u64 size, bool host_visible, bool dynamic = false) { assert(type != BT.None, "CreateBuffer failure: type is None"); + u64 buffer_size = (dynamic ? size * FRAME_OVERLAP : size); + VkBufferCreateInfo buffer_info = { sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, usage: type, - size: size, + size: buffer_size, }; VmaAllocationCreateInfo alloc_info = { @@ -558,7 +594,8 @@ CreateBuffer(Vulkan* vk, Buffer* buf, BufferType type, u64 size, bool host_visib // TODO: handle errors here then reallocate buffer assert(VkCheck("CreateBuffer failure: vmaCreateBuffer error", result), "CreateBuffer failure"); - buf.size = size; + buf.size = buffer_size; + buf.dynamic = dynamic; } void @@ -932,22 +969,11 @@ CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, u32 ch, u8[] data) BeginComputePass(vk); - vkCmdBindDescriptorSets( - vk.comp_cmd, - VK_PIPELINE_BIND_POINT_COMPUTE, - vk.conv_pipeline_layout, - 0, - 1, - &vk.conv_desc_set, - 0, - null - ); + Pipeline pipeline = ch == 1 ? vk.r_to_rgba_pipeline : + ch == 2 ? vk.rg_to_rgba_pipeline : + vk.rgb_to_rgba_pipeline; - VkPipeline pipeline = ch == 1 ? vk.r_to_rgba_pipeline.handle : - ch == 2 ? vk.rg_to_rgba_pipeline.handle : - vk.rgb_to_rgba_pipeline.handle; - - vkCmdBindPipeline(vk.comp_cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); + Bind(vk, pipeline, vk.conv_desc_set); ConvPushConst pc = { x: w, @@ -1106,68 +1132,12 @@ CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, Format format, ImageU view.usage = usage; } -u32 -Pop(Vulkan* vk, DescType type) -{ - DescBindings* bindings = vk.desc_bindings.ptr + type; - - assert(bindings.count > 0, "Pop failure: no free bindings remaining"); - bindings.count -= 1; - - return bindings.free[bindings.count]; -} - void -Push(Vulkan* vk, u32 index, DescType type) -{ - DescBindings* bindings = vk.desc_bindings.ptr + type; - - bindings.free[bindings.count] = index; - bindings.count += 1; -} - -u32 -Pop(Vulkan* vk, string name, DescType type) -{ - DescBindings* bindings = vk.desc_bindings.ptr + type; - - u32 index; - auto result = bindings.lookup_table[name]; - if (!result.ok) - { - // TODO: handle unbinding assets (maybe) - assert(bindings.count > 0, "Pop failure: no free bindings remaining"); - bindings.count -= 1; - index = bindings.free[bindings.count]; - } - else - { - index = result.value; - } - - return index; -} - -void -Push(Vulkan* vk, string name, DescType type) -{ - DescBindings* bindings = vk.desc_bindings.ptr + type; - auto result = Delete(&bindings.lookup_table, name); - if (result.ok) - { - assert(bindings.count < bindings.free.length, "Push failure: attempt to push a binding into a full stack"); - - bindings.free[bindings.count] = result.value; - bindings.count += 1; - } -} - -void -PushConstants(Vulkan* vk, PushConst* pc) +PushConstants(Vulkan* vk, PipelineLayout layout, PushConst* pc) { vkCmdPushConstants( vk.cmds[vk.frame_index], - vk.pipeline_layout, + layout, VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT|VK_SHADER_STAGE_COMPUTE_BIT, 0, PushConst.sizeof, @@ -1383,44 +1353,71 @@ Copy(VkCommandBuffer cmd, VkImage src, VkImage dst, VkImageLayout src_layout, Vk } void -Bind(Vulkan* vk, PipelineHandle* pipeline) +Bind(Vulkan* vk, Pipeline pipeline_handle, DescSet[] sets) { - if (vk.last_pipeline[vk.frame_index] == null || vk.last_pipeline[vk.frame_index] != pipeline.handle) - { - vkCmdBindPipeline(vk.cmds[vk.frame_index], pipeline.type, pipeline.handle); - vk.last_pipeline[vk.frame_index] = pipeline.handle; - } + assert(pipeline_handle > 0, "Bind failure: pipeline is 0"); + PipelineHandles* pipeline = vk.pipeline_handles.ptr + pipeline_handle; + BindPipeline(vk, pipeline); vkCmdBindDescriptorSets( vk.cmds[vk.frame_index], pipeline.type, - vk.pipeline_layout, + pipeline.layout, 0, - cast(u32)vk.desc_sets.length, - vk.desc_sets.ptr, + cast(u32)sets.length, + sets.ptr, 0, null ); +} - VkViewport viewport = { - x: 0.0, - y: 0.0, - width: cast(f32)vk.swapchain_extent.width, - height: cast(f32)vk.swapchain_extent.height, - minDepth: 0.0, - maxDepth: 1.0, - }; +void +Bind(Vulkan* vk, Pipeline pipeline_handle, DescSet set) +{ + assert(pipeline_handle > 0, "Bind failure: pipeline is 0"); + PipelineHandles* pipeline = vk.pipeline_handles.ptr + pipeline_handle; + BindPipeline(vk, pipeline); + + vkCmdBindDescriptorSets( + vk.cmds[vk.frame_index], + pipeline.type, + pipeline.layout, + 0, + 1, + &set, + 0, + null + ); +} - vkCmdSetViewport(vk.cmds[vk.frame_index], 0, 1, &viewport); +pragma(inline): void +BindPipeline(Vulkan* vk, PipelineHandles* pipeline) +{ + if (vk.last_pipeline[vk.frame_index] == 0 || vk.last_pipeline[vk.frame_index] != pipeline_handle) + { + vkCmdBindPipeline(vk.cmds[vk.frame_index], pipeline.type, pipeline.handle); + vk.last_pipeline[vk.frame_index] = pipeline_handle; - VkRect2D scissor = { - extent: { - width: vk.swapchain_extent.width, - height: vk.swapchain_extent.height, - }, - }; + VkViewport viewport = { + x: 0.0, + y: 0.0, + width: cast(f32)vk.swapchain_extent.width, + height: cast(f32)vk.swapchain_extent.height, + minDepth: 0.0, + maxDepth: 1.0, + }; - vkCmdSetScissor(vk.cmds[vk.frame_index], 0, 1, &scissor); + vkCmdSetViewport(vk.cmds[vk.frame_index], 0, 1, &viewport); + + VkRect2D scissor = { + extent: { + width: vk.swapchain_extent.width, + height: vk.swapchain_extent.height, + }, + }; + + vkCmdSetScissor(vk.cmds[vk.frame_index], 0, 1, &scissor); + } } pragma(inline): void @@ -1725,7 +1722,6 @@ CreateGraphicsPipeline(Vulkan* vk, GfxPipelineInfo* build_info) pDynamicState: &dyn_info, stageCount: cast(u32)shader_info.length, pStages: shader_info.ptr, - layout: vk.pipeline_layout, renderPass: vk.render_pass, }; @@ -1740,7 +1736,7 @@ CreateComputePipeline(Vulkan* vk, CompPipelineInfo* comp_info) { VkComputePipelineCreateInfo info = { sType: VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, - layout: comp_info.layout ? *comp_info.layout : vk.pipeline_layout, + layout: comp_info.layout, stage: { sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, stage: VK_SHADER_STAGE_COMPUTE_BIT, @@ -1769,11 +1765,17 @@ CreateComputePipeline(Vulkan* vk, CompPipelineInfo* comp_info) info.stage.pSpecializationInfo = &spec_info; } - PipelineHandle pipeline = { type: VK_PIPELINE_BIND_POINT_COMPUTE }; + PipelineHandles* pipeline = vk.pipeline_handles.ptr + vk.pipeline_count; + pipeline.type = VK_PIPELINE_BIND_POINT_COMPUTE; + pipeline.layout = comp_info.layout; + + Pipeline pipeline_handle = vk.pipeline_count; + vk.pipeline_count += 1; + VkResult result = vkCreateComputePipelines(vk.device, null, 1, &info, null, &pipeline.handle); assert(VkCheck("CreateComputePipeline failure", result), "Unable to build pipeline"); - return pipeline; + return pipeline_handle; } void @@ -1809,7 +1811,7 @@ SetUniform(Vulkan* vk, GlobalUniforms* globals) sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, dstSet: vk.desc_sets[DT.Shared], dstBinding: 0, - descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, descriptorCount: 1, pBufferInfo: &buffer_info, }; @@ -1874,8 +1876,8 @@ Destroy(Vulkan* vk) Destroy(vk, &vk.draw_image); Destroy(vk, &vk.depth_image); break; - case SI.Descriptors: - Destroy(vk.desc_pool, vk.desc_layouts, vk.pipeline_layout, vk.nearest_sampler, vk.device); + case SI.DescriptorPools: + DestroyDescriptorPools(vk); break; case SI.Buffers: Destroy(vk, &vk.transfer_buf); @@ -1893,6 +1895,25 @@ Destroy(Vulkan* vk) } } +void +DestroyDescriptorPools(Vulkan* vk) +{ + vkDestroyDescriptorPool(vk.device, vk.active_pool, null); + + Node!(VkDescriptorPool)* node = vk.full_pools.first; + for(;;) + { + if (node == null) + { + break; + } + + vkDestroyDescriptorPool(vk.device, node.value, null); + + node = node.next; + } +} + void DestroyPipelines(Vulkan* vk) { @@ -1916,7 +1937,7 @@ DestroyPipelines(Vulkan* vk) vkDestroyPipeline(vk.device, vk.rg_to_rgba_pipeline.handle, null); } - if (vk.rgb_to_rgba_pipeline.handle) + if (vk.rgb_to_rgba_pipeline.handle) { vkDestroyPipeline(vk.device, vk.rgb_to_rgba_pipeline.handle, null); } @@ -1938,15 +1959,21 @@ Destroy(Vulkan* vk, Buffer* buf) bool InitDescriptors(Vulkan* vk) { - Push(vk, SI.Descriptors); + Push(vk, SI.DescriptorPools); bool success = true; + PushDescriptorPool(vk); +} + +void +PushDescriptorPool(Vulkan* vk) +{ VkDescriptorPoolSize[] pool_sizes = [ { type: VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, descriptorCount: 4096 }, { type: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descriptorCount: 4096 }, - { type: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, descriptorCount: 4096 }, - { type: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 4096 }, + { type: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, descriptorCount: 4096 }, + { type: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, descriptorCount: 4096 }, { type: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 4096 }, { type: VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, descriptorCount: 4096 }, ]; @@ -1955,18 +1982,36 @@ InitDescriptors(Vulkan* vk) sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, poolSizeCount: cast(u32)pool_sizes.length, pPoolSizes: pool_sizes.ptr, - maxSets: 12, - flags: VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT, + maxSets: MAX_SETS, }; - VkResult result = vkCreateDescriptorPool(vk.device, &pool_info, null, &vk.desc_pool); + VkDescriptorPool pool; + VkResult result = vkCreateDescriptorPool(vk.device, &pool_info, null, &pool); success = VkCheck("vkCreateDescriptorPool failure", result); + assert(success, "vkCreateDescriptorPool error"); + + if (vk.active_pool == null || vk.active_pool == VK_NULL_HANDLE) + { + Node!(VkDescriptorPool)* node = Alloc!(Node!(VkDescriptorPool)); + node.value = vk.active_pool; + PushFront(&g.full_pools, node, null); + } + + vk.active_pool = pool; +} + + + +bool +InitDescriptors(Vulkan* vk) +{ + if (success) { VkDescriptorSetLayoutBinding[] shared_bindings = [ - { binding: 0, descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, - { binding: 1, descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, + { binding: 0, descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, + { binding: 1, descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, { binding: 2, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, { binding: 3, descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, { binding: 4, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, @@ -2069,26 +2114,6 @@ InitDescriptors(Vulkan* vk) success = VkCheck("vkCreatePipelineLayout failure", result); } - if (success) - { - foreach(i; cast(u64)DT.min .. cast(u64)DT.max) - { - vk.desc_bindings[i].lookup_table = CreateHashTable!(string, u32)(8); - - u32 DESC_MAX_BINDINGS = 512; - vk.desc_bindings[i].free = AllocArray!(u32)(&vk.arena, DESC_MAX_BINDINGS); - - u32 free_count = 0; - for(i32 j = DESC_MAX_BINDINGS-1; j >= 0; j -= 1) - { - vk.desc_bindings[i].free[j] = cast(u32)free_count; - free_count += 1; - } - - vk.desc_bindings[i].count = free_count; - } - } - if (success) { VkPhysicalDeviceProperties props; diff --git a/src/shaders/gui.frag.glsl b/src/shaders/gui.frag.glsl index 5907081..93b5149 100644 --- a/src/shaders/gui.frag.glsl +++ b/src/shaders/gui.frag.glsl @@ -1,17 +1,19 @@ #version 460 #extension GL_GOOGLE_include_directive : require -#extension GL_EXT_nonuniform_qualifier : require #include "structures.layout" +#include "gui.layout" -layout (location = 0) in vec4 in_color; -layout (location = 1) in vec2 in_uv; -layout (location = 2) flat in uint in_image; +layout (location = 0) in struct FragDataIn { + vec4 color; + vec2 uv; +} FragData; -layout (location = 0) out vec4 out_frag_col; +layout (location = 0) out vec4 FragColor; void main() { - out_frag_col = in_color; + vec4 tex_color = texture(sampler2D(SpriteAtlas, SamplerNearest), FragData.uv); + FragColor = FragData.color * tex_color; } diff --git a/src/shaders/gui.layout b/src/shaders/gui.layout new file mode 100644 index 0000000..3c38182 --- /dev/null +++ b/src/shaders/gui.layout @@ -0,0 +1,5 @@ +layout (set = 1, binding = 0) uniform texture2D SpriteAtlas; + +layout (push_constant) uniform Constants { + vec2 res; +} PC; diff --git a/src/shaders/gui.vert.glsl b/src/shaders/gui.vert.glsl index 8a1828b..5fe8e20 100644 --- a/src/shaders/gui.vert.glsl +++ b/src/shaders/gui.vert.glsl @@ -1,25 +1,27 @@ #version 460 #extension GL_GOOGLE_include_directive : require -#extension GL_EXT_nonuniform_qualifier : require #include "structures.layout" +#include "gui.layout" -layout (location = 0) in vec2 in_gui_pos_0; -layout (location = 1) in vec2 in_gui_pos_1; -layout (location = 2) in vec4 in_col; -layout (location = 3) in uint in_image; +layout (location = 0) in vec2 in_dst_start; +layout (location = 1) in vec2 in_dst_end; +layout (location = 2) in vec2 in_src_start; +layout (location = 3) in vec2 in_src_end; +layout (location = 4) in vec4 in_col; -layout (location = 0) out vec4 out_color; -layout (location = 1) out vec2 out_uv; -layout (location = 2) out uint out_image; +layout (location = 0) out struct FragDataOut { + vec4 color; + vec2 uv; +} FragData; -vec2 uvs[] = { - vec2(0.0, 1.0), - vec2(0.0, 0.0), - vec2(1.0, 1.0), - vec2(1.0, 0.0) -}; +vec2 Vertices[4] = vec2[4]( + vec2(-1.0, -1.0), + vec2(-1.0, +1.0), + vec2(+1.0, -1.0), + vec2(+1.0, +1.0) +); vec2 rotate(vec2 coords, float theta) { @@ -28,18 +30,24 @@ vec2 rotate(vec2 coords, float theta) void main() { - // Draw with 6 indices, gl_VertexIndex will use the appropriate index, iterates through 0-3 and not 0-5 - vec2 dst_pos = gl_VertexIndex == 0 ? vec2(in_gui_pos_0.x, in_gui_pos_1.y) : - gl_VertexIndex == 1 ? vec2(in_gui_pos_0.x, in_gui_pos_0.y) : - gl_VertexIndex == 2 ? vec2(in_gui_pos_1.x, in_gui_pos_1.y) : - gl_VertexIndex == 3 ? vec2(in_gui_pos_1.x, in_gui_pos_0.y) : vec2(0.0, 0.0); + ivec2 tex_size = textureSize(sampler2D(SpriteAtlas, SamplerNearest), 0); - out_uv = uvs[gl_VertexIndex]; - out_color = in_col; - out_image = in_image; + vec2 dst_half_size = (in_dst_end - in_dst_start) / 2; + vec2 dst_center = (in_dst_end + in_dst_start) / 2; + vec2 dst_pos = (Vertices[gl_VertexIndex] * dst_half_size + dst_center); - gl_Position = vec4(2 * dst_pos.x / G.res.x - 1, - 2 * dst_pos.y / G.res.y - 1, + vec2 src_half_size = (in_src_end - in_src_start) / 2; + vec2 src_center = (in_src_end + in_src_start) / 2; + vec2 src_pos = (Vertices[gl_VertexIndex] * src_half_size + src_center); + + FragData.color = in_col; + FragData.uv = vec2( + in_src_start.x / tex_size.x, + in_src_start + ); + + gl_Position = vec4(2 * dst_pos.x / PC.res.x - 1, + 2 * dst_pos.y / PC.res.y - 1, 0, 1); } diff --git a/src/shaders/pbr.frag.glsl b/src/shaders/pbr.frag.glsl index 2964c89..44b92d9 100644 --- a/src/shaders/pbr.frag.glsl +++ b/src/shaders/pbr.frag.glsl @@ -58,9 +58,8 @@ void main() out_col.a = alpha_col.a; } - FragColor = out_col; + //FragColor = out_col; - /* //TODO: set up OIT again vec4 srgb_col = out_col;// UnPreMultLinearToSRGB(out_col); @@ -75,7 +74,6 @@ void main() } else { - FragColor = vec4(out_col.rgb * out_col.a, out_col.a); // Change to vec4(0.0) to disable tail blending + FragColor = vec4(0.0); //vec4(out_col.rgb * out_col.a, out_col.a); // Change to vec4(0.0) to disable tail blending } - */ } diff --git a/src/shaders/pbr.vert.glsl b/src/shaders/pbr.vert.glsl index b5551b4..4fcf203 100644 --- a/src/shaders/pbr.vert.glsl +++ b/src/shaders/pbr.vert.glsl @@ -5,6 +5,31 @@ #include "structures.layout" +layout (set = 1, binding = 0) uniform texture2D AlbedoTexture; + +layout (set = 1, binding = 1) uniform texture2D AmbientTexture; + +layout (set = 1, binding = 2) uniform texture2D SpecularTexture; + +layout (set = 1, binding = 3) uniform texture2D AlphaTexture; + +layout (set = 1, binding = 4) uniform Material { + vec4 ambient; + vec4 diffuse; + vec4 specular; + bool albedo_has_texture; + bool ambient_has_texture; + bool specular_has_texture; + bool alpha_has_texture; + float shininess; + float alpha; +} Materials[]; + +layout (push_constant) uniform Constants { + mat4 model_matrix; + uint mat_id; +} PC; + layout (location = 0) in vec4 in_col; layout (location = 1) in vec4 in_tangent; layout (location = 2) in vec3 in_pos; diff --git a/src/shaders/structures.layout b/src/shaders/structures.layout index 537d48d..216e707 100644 --- a/src/shaders/structures.layout +++ b/src/shaders/structures.layout @@ -1,60 +1,4 @@ -// **************************************************************************** -// **** STRUCTS MUST BE PACKED IN OPTIMAL PACKING ORDER TO MATCH D STRUCTS **** -// **************************************************************************** +layout (rgba16f, set = 0, binding = 0) uniform image2D DrawImage; -#define OIT_LAYERS 8 +layout (set = 0, binding = 1) uniform sampler SamplerNearest; -layout (set = 0, binding = 0) uniform GlobalUniforms { - mat4 view_matrix; - mat4 projection_matrix; - mat4 projection_view; - vec4 light_color; - vec4 ambient_color; - vec3 light_direction; - vec2 res; -} G; - -layout (set = 0, binding = 1) uniform ShaderUniforms { - float placeholder; -} S; - -layout (rgba16f, set = 0, binding = 2) uniform image2D DrawImage; - -layout (set = 0, binding = 3) uniform sampler SamplerNearest; - -#ifdef COMPOSITE_PASS - -layout (set = 0, binding = 4, rg32ui) uniform restrict readonly uimageBuffer ImageABuffer; - -layout (set = 0, binding = 5, r32ui) uniform restrict readonly uimage2D ImageAux; - -#else - -layout (set = 0, binding = 4, rg32ui) uniform coherent uimageBuffer ImageABuffer; - -layout (set = 0, binding = 5, r32ui) uniform coherent uimage2D ImageAux; - -#endif - -layout (set = 1, binding = 0) uniform texture2D Textures[]; - -layout (set = 2, binding = 0) uniform Material { - vec4 ambient; - vec4 diffuse; - vec4 specular; - uint albedo_texture; - uint ambient_texture; - uint specular_texture; - uint alpha_texture; - bool albedo_has_texture; - bool ambient_has_texture; - bool specular_has_texture; - bool alpha_has_texture; - float shininess; - float alpha; -} Materials[]; - -layout (push_constant) uniform Constants { - mat4 model_matrix; - uint mat_id; -} PC; diff --git a/src/shared/util.d b/src/shared/util.d index ecbb50a..e6e8377 100644 --- a/src/shared/util.d +++ b/src/shared/util.d @@ -8,6 +8,23 @@ import core.simd; import std.conv; import std.string; +struct TrackedSlice(T) +{ + T[] slice; + u32 free_index; +} + +alias TSlice = TrackedSlice; + +TSlice!(T) +InitTrackedSlice(T)(u32 length) +{ + TSlice!(T) tslice; + tslice.slice = AllocArray!(T[])(length); + + return tslice; +} + void Logf(Args...)(string fmt, Args args) {