diff --git a/assets/shaders/full_screen_triangle.vert.spv b/assets/shaders/full_screen_triangle.vert.spv new file mode 100644 index 0000000..c353e8c Binary files /dev/null and b/assets/shaders/full_screen_triangle.vert.spv differ diff --git a/assets/shaders/gradient.comp.spv b/assets/shaders/gradient.comp.spv index 18575bc..035a46b 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 8a6d970..4f894f9 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 5e968bf..a899b9b 100644 Binary files a/assets/shaders/gui.vert.spv and b/assets/shaders/gui.vert.spv differ diff --git a/assets/shaders/oit.frag.spv b/assets/shaders/oit.frag.spv new file mode 100644 index 0000000..c0ecd82 Binary files /dev/null and b/assets/shaders/oit.frag.spv differ diff --git a/assets/shaders/pbr.frag.spv b/assets/shaders/pbr.frag.spv index 4f0dc63..36729ed 100644 Binary files a/assets/shaders/pbr.frag.spv and b/assets/shaders/pbr.frag.spv differ diff --git a/assets/shaders/pbr.vert.spv b/assets/shaders/pbr.vert.spv index 09f5990..c0ddc20 100644 Binary files a/assets/shaders/pbr.vert.spv and b/assets/shaders/pbr.vert.spv differ diff --git a/assets/shaders/triangle.frag.spv b/assets/shaders/triangle.frag.spv index 821a69b..ca7b677 100644 Binary files a/assets/shaders/triangle.frag.spv and b/assets/shaders/triangle.frag.spv differ diff --git a/assets/shaders/triangle.vert.spv b/assets/shaders/triangle.vert.spv index 1524706..7ce0591 100644 Binary files a/assets/shaders/triangle.vert.spv and b/assets/shaders/triangle.vert.spv differ diff --git a/src/gears/game.d b/src/gears/game.d index 21e2a74..12f6c34 100644 --- a/src/gears/game.d +++ b/src/gears/game.d @@ -3,15 +3,18 @@ import includes; import renderer : Destroy; import renderer; import util; +import alloc; import platform; import math; import core.stdc.math : cosf, sinf; +import std.algorithm.sorting; f32 g_DELTA; struct Game { Renderer rd; + Arena frame_arena; PlatformWindow* window; @@ -19,6 +22,7 @@ struct Game Pipeline triangle_pipeline; Pipeline compute_pipeline; Pipeline ui_pipeline; + Pipeline oit_pipeline; GlobalUniforms globals; PushConst pc; @@ -36,6 +40,7 @@ InitGame(PlatformWindow* window) { Game g = { rd: InitRenderer(window), + frame_arena: CreateArena(MB(16)), window: window, timer: CreateTimer(), globals: { @@ -76,13 +81,23 @@ InitGame(PlatformWindow* window) ] }; + 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", }; + Logf("pbr"); g.pbr_pipeline = BuildGfxPipeline(&g.rd, &pbr_info); + Logf("triangle"); g.triangle_pipeline = BuildGfxPipeline(&g.rd, &triangle_info); + Logf("ui"); g.ui_pipeline = BuildGfxPipeline(&g.rd, &ui_info); + Logf("oit"); + g.oit_pipeline = BuildGfxPipeline(&g.rd, &oit_info); g.compute_pipeline = BuildCompPipeline(&g.rd, &gradient_info); PrintShader(&g.rd, &g.pbr_pipeline, VK_SHADER_STAGE_VERTEX_BIT); @@ -107,8 +122,12 @@ Cycle(Game* g) { g_DELTA = DeltaTime(&g.timer); + Reset(&g.frame_arena); + ProcessInputs(g, &g.camera); + //Sort(g, g.camera.pos, &g.model); + //Update(g, &g.camera); Update(&g.camera); @@ -234,3 +253,28 @@ Update(Camera* cam) Vec4 pos = rotation * Vec4(cam.velocity * 0.5 * g_DELTA, 0.0); cam.pos += pos.xyz; } + +void +Sort(Game* g, Vec3 pos, Model* model) +{ + f32[] lengths = AllocArray!(f32)(&g.frame_arena, model.positions.length); + + foreach(i; 0 .. lengths.length) + { + model.pos_indices[i] = cast(u32)i; + lengths.ptr[i] = fabs(Norm(&pos) - Norm(model.positions.ptr + i)); + } + + makeIndex!("a < b")(lengths, model.pos_indices); + + Logf("%s", model.positions.length); + + foreach(i, v; model.pos_indices) + { + model.indices[i+0] = cast(u32)((3*v)+0); + model.indices[i+1] = cast(u32)((3*v)+1); + model.indices[i+2] = cast(u32)((3*v)+2); + } + + UpdateIndexBuffer(&g.rd, model); +} diff --git a/src/gears/main.d b/src/gears/main.d index c2edf1e..0683ddc 100644 --- a/src/gears/main.d +++ b/src/gears/main.d @@ -14,6 +14,7 @@ import core.stdc.string : memcpy; // 2. Set up VK_AMD_shader_info // 3. Determine how to better handle inputs // 4. Make assets loaded from the disk in debug mode +// 5. Set up multisampling void main(string[] argv) { diff --git a/src/gears/renderer.d b/src/gears/renderer.d index e089c93..aa476e9 100644 --- a/src/gears/renderer.d +++ b/src/gears/renderer.d @@ -4,7 +4,7 @@ import assets; import util; import alloc; import vulkan; -import vulkan : Destroy, Init, Draw, DrawIndexed, Bind, BindUIBuffers, BeginRender, SetUniform, PrepComputeDrawImage, Dispatch, FinishFrame, BeginFrame, WaitIdle, PushConstants, BindBuffers, SetClearColor; +import vulkan : Destroy, Init, Draw, DrawIndexed, Bind, BindUIBuffers, BeginRender, SetUniform, PrepComputeDrawImage, Dispatch, FinishFrame, BeginFrame, WaitIdle, PushConstants, BindBuffers, SetClearColor, ImageBarrier; import assets; import std.math.traits : isNaN; import util : Logf; @@ -33,6 +33,8 @@ enum Format : VkFormat RGB_F32 = VK_FORMAT_R32G32B32_SFLOAT, RGBA_F32 = VK_FORMAT_R32G32B32A32_SFLOAT, RGBA_UINT = VK_FORMAT_B8G8R8A8_UINT, + R_U32 = VK_FORMAT_R32_UINT, + RG_U32 = VK_FORMAT_R32G32_UINT, RGBA_UNORM = VK_FORMAT_R8G8B8A8_UNORM, RGBA_SRGB = VK_FORMAT_R8G8B8A8_SRGB, } @@ -47,6 +49,7 @@ enum BufferType : int Uniform = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, Storage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, Staging = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + BufferView = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, } alias BT = BufferType; @@ -161,6 +164,10 @@ struct Model Buffer[] materials; ImageView[] textures; + + Vec3[] positions; + u32[] pos_indices; + u32[] indices; } Renderer @@ -260,6 +267,12 @@ Bind(Renderer* rd, Pipeline* pipeline) Bind(&rd.vk, pipeline); } +void +UpdateIndexBuffer(Renderer* rd, Model* model) +{ + assert(Transfer(&rd.vk, &model.index_buffer, model.indices), "UpdateIndexBuffer failure"); +} + void DrawRect(Renderer* rd, f32 p0_x, f32 p0_y, f32 p1_x, f32 p1_y, Vec4 col) { @@ -345,7 +358,6 @@ LoadModel(Renderer* rd, string name) u32[] tex_lookup = AllocArray!(u32)(&rd.temp_arena, m3d.numtexture); model.textures = AllocArray!(ImageView)(&rd.arena, m3d.numtexture); - Logf("numtexture %s", m3d.numtexture); foreach(i; 0 .. m3d.numtexture) { u32 w = m3d.texture[i].w; u32 h = m3d.texture[i].h; u32 ch = m3d.texture[i].f; @@ -360,7 +372,6 @@ LoadModel(Renderer* rd, string name) Material[] mats = AllocArray!(Material)(&rd.temp_arena, m3d.nummaterial); u32[] mat_lookup = AllocArray!(u32)(&rd.temp_arena, m3d.nummaterial); model.materials = AllocArray!(Buffer)(&rd.arena, m3d.nummaterial); - Logf("nummaterial %s", m3d.nummaterial); foreach(i; 0 .. m3d.nummaterial) { const(char)[] mat_name = m3d.material[i].name[0 .. strlen(m3d.material[i].name)]; @@ -391,7 +402,6 @@ LoadModel(Renderer* rd, string name) } break; case m3dp_map_D: { - Logf("alpha %s", i); mats[i].alpha_texture = tex_lookup[m3d.material[i].prop[j].value.textureid]; mats[i].alpha_has_texture = true; } break; @@ -447,8 +457,10 @@ LoadModel(Renderer* rd, string name) m3dv_t* vertex; - u32[] indices = AllocArray!(u32)(&rd.temp_arena, m3d.numface * 3); + u32[] indices = AllocArray!(u32)(&rd.arena, m3d.numface * 3); Vertex[] vertices = AllocArray!(Vertex)(&rd.temp_arena, m3d.numface * 3); + Vec3[] positions = AllocArray!(Vec3)(&rd.arena, m3d.numface); + u32[] pos_indices = AllocArray!(u32)(&rd.arena, m3d.numface); foreach(i; 0 .. m3d.numface) { @@ -484,6 +496,11 @@ LoadModel(Renderer* rd, string name) indices[i0] = i0; indices[i1] = i1; indices[i2] = i2; + + Vec3 center = (vertices[i0].pos + vertices[i1].pos + vertices[i2].pos) / 3.0; + + positions[i] = center; + pos_indices[i] = i; } for(u64 i = 0; i < indices.length; i += 3) @@ -529,6 +546,10 @@ LoadModel(Renderer* rd, string name) WriteDescriptors(&rd.vk, DT.Material, model.materials, mat_lookup); WriteDescriptors(&rd.vk, DT.SampledImage, model.textures, tex_lookup); + model.positions = positions; + model.indices = indices; + model.pos_indices = pos_indices; + Reset(&rd.temp_arena); return model; @@ -618,6 +639,12 @@ ClearColorEnabled(Renderer* rd, bool enabled) rd.vk.enable_clear_color = enabled; } +void +ImageBarrier(Renderer* rd) +{ + ImageBarrier(&rd.vk); +} + void Destroy(Renderer* rd, Model* model) { diff --git a/src/gears/vulkan.d b/src/gears/vulkan.d index 9d673bc..be4026b 100644 --- a/src/gears/vulkan.d +++ b/src/gears/vulkan.d @@ -80,6 +80,10 @@ const VkImageUsageFlags VK_DRAW_IMAGE_USAGE_FLAGS = VK_IMAGE_USAGE_TRANSFER_SRC_ VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; +const VkImageUsageFlags TEXTURE_IMAGE_USAGE = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; +const VkImageUsageFlags CONVERT_IMAGE_USAGE = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; +const VkImageUsageFlags OIT_IMAGE_USAGE = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + enum StepInitialized : u32 { Renderer = 1, @@ -117,6 +121,14 @@ struct Image VkImageLayout layout; } +struct BufferView +{ + Buffer base; + VkBufferView view; + + alias base this; +} + struct ImageView { Image base; @@ -199,6 +211,7 @@ struct Vulkan DescBindings[DT.max] desc_bindings; VkSampler nearest_sampler; + VkSampler oit_sampler; VkPipeline[FRAME_OVERLAP] last_pipeline; VkPipelineLayout pipeline_layout; @@ -224,6 +237,9 @@ struct Vulkan bool enable_clear_color; VkClearColorValue clear_color; + BufferView a_buffer_view; + ImageView aux_image; + alias queues this; } @@ -755,7 +771,7 @@ TransferAssets(Vulkan* vk) pragma(inline): void CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, u32 ch, u8[] data) { - CreateImageView(vk, view, w, h); + CreateImageView(vk, view, w, h, FMT.RGBA_UNORM, TEXTURE_IMAGE_USAGE); if (ch == 4) { @@ -768,7 +784,7 @@ CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, u32 ch, u8[] data) assert(Transfer(vk, &buf, data), "CreateImageView failure: Buffer Transfer error"); ImageView conv_view; - CreateImageView(vk, &conv_view, w, h, FMT.RGBA_F32); + CreateImageView(vk, &conv_view, w, h, FMT.RGBA_F32, CONVERT_IMAGE_USAGE); WriteConvDescriptor(vk, &buf); WriteConvDescriptor(vk, &conv_view); @@ -872,7 +888,25 @@ FinishComputePass(Vulkan* vk) } pragma(inline): void -CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, Format format = FMT.RGBA_UNORM) +CreateBufferView(Vulkan* vk, BufferView* view, u64 size, Format format) +{ + CreateBuffer(vk, &view.base, BT.BufferView, size, false); + + VkBufferViewCreateInfo info = { + sType: VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, + buffer: view.buffer, + format: format, + range: size, + }; + + VkResult result = vkCreateBufferView(vk.device, &info, null, &view.view); + VkCheckA("CreateBufferView failure: vkCreateBufferView failed", result); + + view.size = size; +} + +pragma(inline): void +CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, Format format = FMT.RGBA_UNORM, VkImageUsageFlags usage) { VmaAllocationCreateInfo alloc_info = { usage: VMA_MEMORY_USAGE_GPU_ONLY, @@ -887,7 +921,7 @@ CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, Format format = FMT.R format: format, tiling: VK_IMAGE_TILING_OPTIMAL, initialLayout: VK_IMAGE_LAYOUT_UNDEFINED, - usage: format == FMT.RGBA_F32 ? (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT) : (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), + usage: usage, samples: VK_SAMPLE_COUNT_1_BIT, extent: { width: w, @@ -996,6 +1030,27 @@ PushConstants(Vulkan* vk, PushConst* pc) ); } +void +ImageBarrier(Vulkan* vk) +{ + VkMemoryBarrier2 barrier = { + sType: VK_STRUCTURE_TYPE_MEMORY_BARRIER_2, + srcStageMask: VK_PIPELINE_STAGE_2_TRANSFER_BIT, + srcAccessMask: VK_ACCESS_2_TRANSFER_WRITE_BIT, + dstStageMask: VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, + dstAccessMask: VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT, + }; + + VkDependencyInfo dependency = { + sType: VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + dependencyFlags: VK_DEPENDENCY_BY_REGION_BIT, + memoryBarrierCount: 1, + pMemoryBarriers: &barrier, + }; + + vkCmdPipelineBarrier2(vk.cmds[vk.frame_index], &dependency); +} + bool Transfer(T)(Vulkan* vk, Buffer* buf, T[] data) { @@ -1323,7 +1378,7 @@ CreateGraphicsPipeline(Vulkan* vk, GfxPipelineInfo* build_info) VkPipelineDepthStencilStateCreateInfo depth_info = { sType: VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, depthTestEnable: VK_TRUE, - depthWriteEnable: VK_TRUE, + depthWriteEnable: VK_FALSE, depthCompareOp: VK_COMPARE_OP_GREATER_OR_EQUAL, depthBoundsTestEnable: VK_FALSE, stencilTestEnable: VK_FALSE, @@ -1380,36 +1435,36 @@ CreateGraphicsPipeline(Vulkan* vk, GfxPipelineInfo* build_info) VkPipelineShaderStageCreateInfo[] shader_info = [ { sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - stage: VK_SHADER_STAGE_VERTEX_BIT, - pName: "main", + stage: VK_SHADER_STAGE_FRAGMENT_BIT, + pName: "main", }, { sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - stage: VK_SHADER_STAGE_FRAGMENT_BIT, + stage: VK_SHADER_STAGE_VERTEX_BIT, pName: "main", }, ]; Arena* arena = &vk.frame_arenas[0]; - u8[] vert_bytes = LoadAssetData(arena, build_info.vertex_shader); u8[] frag_bytes = LoadAssetData(arena, build_info.frag_shader); + u8[] vert_bytes = LoadAssetData(arena, build_info.vertex_shader); assert(vert_bytes && frag_bytes, "Unable to load shaders"); - Result!(Shader) vert_module = BuildShader(vk, vert_bytes); Result!(Shader) frag_module = BuildShader(vk, frag_bytes); + Result!(Shader) vert_module = BuildShader(vk, vert_bytes); assert(vert_module.ok && frag_module.ok, "Unable to build vulkan shaders"); scope(exit) { - Destroy(vk, vert_module.value); Destroy(vk, frag_module.value); + Destroy(vk, vert_module.value); } - __traits(getMember, shader_info.ptr + 0, "module") = vert_module.value; - __traits(getMember, shader_info.ptr + 1, "module") = frag_module.value; + __traits(getMember, shader_info.ptr + 0, "module") = frag_module.value; + __traits(getMember, shader_info.ptr + 1, "module") = vert_module.value; VkSpecializationInfo vert_spec_info = { dataSize: build_info.vert_spec.size, @@ -1652,6 +1707,7 @@ InitDescriptors(Vulkan* vk) { type: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, descriptorCount: 4096 }, { type: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 4096 }, { type: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 4096 }, + { type: VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, descriptorCount: 4096 }, ]; VkDescriptorPoolCreateInfo pool_info = { @@ -1667,7 +1723,17 @@ InitDescriptors(Vulkan* vk) if (success) { - VkDescriptorBindingFlags[4] shared_binding_flags; + 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: 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 }, + { binding: 5, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, + { binding: 6, descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL }, + ]; + + VkDescriptorBindingFlags[] shared_binding_flags = AllocArray!(VkDescriptorBindingFlags)(&vk.frame_arenas[0], shared_bindings.length); shared_binding_flags[] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT; VkDescriptorSetLayoutBindingFlagsCreateInfo shared_flag_info = { @@ -1676,13 +1742,6 @@ InitDescriptors(Vulkan* vk) pBindingFlags: shared_binding_flags.ptr, }; - 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: 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 }, - ]; - VkDescriptorSetLayoutCreateInfo shared_set_info = { sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, pNext: &shared_flag_info, @@ -1814,20 +1873,89 @@ InitDescriptors(Vulkan* vk) if (success) { + VkSamplerCreateInfo sampler_info = { + sType: VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + magFilter: VK_FILTER_LINEAR, + minFilter: VK_FILTER_LINEAR, + addressModeU: VK_SAMPLER_ADDRESS_MODE_REPEAT, + addressModeV: VK_SAMPLER_ADDRESS_MODE_REPEAT, + addressModeW: VK_SAMPLER_ADDRESS_MODE_REPEAT, + anisotropyEnable: VK_FALSE, + compareEnable: VK_FALSE, + borderColor: VK_BORDER_COLOR_INT_OPAQUE_BLACK, + mipmapMode: VK_SAMPLER_MIPMAP_MODE_NEAREST, + unnormalizedCoordinates: VK_FALSE, + }; + + result = vkCreateSampler(vk.device, &sampler_info, null, &vk.oit_sampler); + success = VkCheck("vkCreateSampler failure", result); + } + + if (success) + { + // TODO: move this elsewhere later + // Also add samples/supersampling scaling + + CreateBufferView(vk, &vk.a_buffer_view, (u32.sizeof * 2) * vk.swapchain_extent.width * vk.swapchain_extent.height, FMT.RG_U32); + CreateImageView(vk, &vk.aux_image, vk.swapchain_extent.width, vk.swapchain_extent.height, FMT.R_U32, OIT_IMAGE_USAGE); + + VkDescriptorBufferInfo a_buffer_info = { + buffer: vk.a_buffer_view.buffer, + offset: 0, + range: VK_WHOLE_SIZE, + }; + + VkDescriptorImageInfo aux_info = { + sampler: vk.oit_sampler, + imageView: vk.aux_image.view, + imageLayout: VK_IMAGE_LAYOUT_GENERAL, + }; + VkDescriptorImageInfo sampler_info = { sampler: vk.nearest_sampler, }; - VkWriteDescriptorSet write = { - sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - dstSet: vk.desc_sets[DT.Shared], - dstBinding: 3, - descriptorCount: 1, - descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, - pImageInfo: &sampler_info, + VkDescriptorImageInfo oit_sample_info = { + sampler: vk.oit_sampler, }; - vkUpdateDescriptorSets(vk.device, 1, &write, 0, null); + VkWriteDescriptorSet[] writes = [ + { + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: vk.desc_sets[DT.Shared], + dstBinding: 3, + descriptorCount: 1, + descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, + pImageInfo: &sampler_info, + }, + { + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: vk.desc_sets[DT.Shared], + dstBinding: 4, + descriptorCount: 1, + descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, + pBufferInfo: &a_buffer_info, + pTexelBufferView: &vk.a_buffer_view.view, + }, + { + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: vk.desc_sets[DT.Shared], + dstBinding: 5, + descriptorCount: 1, + descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + pImageInfo: &aux_info, + }, + { + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: vk.desc_sets[DT.Shared], + dstBinding: 6, + descriptorCount: 1, + descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, + pImageInfo: &oit_sample_info, + }, + ]; + + vkUpdateDescriptorSets(vk.device, cast(u32)writes.length, writes.ptr, 0, null); WriteDrawImageDesc(vk); } @@ -2467,6 +2595,7 @@ InitDevice(Vulkan* vk) descriptorBindingSampledImageUpdateAfterBind: VK_TRUE, descriptorBindingStorageImageUpdateAfterBind: VK_TRUE, descriptorBindingStorageBufferUpdateAfterBind: VK_TRUE, + descriptorBindingStorageTexelBufferUpdateAfterBind: VK_TRUE, descriptorBindingPartiallyBound: VK_TRUE, shaderSampledImageArrayNonUniformIndexing: VK_TRUE, shaderUniformBufferArrayNonUniformIndexing: VK_TRUE, @@ -2488,6 +2617,7 @@ InitDevice(Vulkan* vk) shaderStorageBufferArrayDynamicIndexing: VK_TRUE, shaderStorageImageArrayDynamicIndexing: VK_TRUE, samplerAnisotropy: VK_TRUE, + fragmentStoresAndAtomics: VK_TRUE, }, }; @@ -2557,6 +2687,7 @@ CheckDeviceFeatures(VkPhysicalDevice device) VkPhysicalDeviceFeatures features = features2.features; bool result = true; + result &= cast(bool)features.fragmentStoresAndAtomics; result &= cast(bool)features.shaderUniformBufferArrayDynamicIndexing; result &= cast(bool)features.shaderSampledImageArrayDynamicIndexing; result &= cast(bool)features.shaderStorageBufferArrayDynamicIndexing; @@ -2566,6 +2697,7 @@ CheckDeviceFeatures(VkPhysicalDevice device) result &= cast(bool)features_12.descriptorIndexing; result &= cast(bool)features_12.bufferDeviceAddress; result &= cast(bool)features_12.descriptorBindingUniformBufferUpdateAfterBind; + result &= cast(bool)features_12.descriptorBindingStorageTexelBufferUpdateAfterBind; result &= cast(bool)features_12.descriptorBindingSampledImageUpdateAfterBind; result &= cast(bool)features_12.descriptorBindingStorageImageUpdateAfterBind; result &= cast(bool)features_12.descriptorBindingStorageBufferUpdateAfterBind; diff --git a/src/gears/vulkan_funcs.d b/src/gears/vulkan_funcs.d index 282195e..af4be1e 100644 --- a/src/gears/vulkan_funcs.d +++ b/src/gears/vulkan_funcs.d @@ -58,6 +58,7 @@ version(AMD_GPU) PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR = null; PFN_vkCreateImage vkCreateImage = null; PFN_vkCreateImageView vkCreateImageView = null; +PFN_vkCreateBufferView vkCreateBufferView = null; PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR = null; PFN_vkGetDeviceQueue vkGetDeviceQueue = null; PFN_vkCreateSemaphore vkCreateSemaphore = null; @@ -154,6 +155,7 @@ LoadDeviceFunctions(Vulkan* vk) vkCreateSwapchainKHR = cast(PFN_vkCreateSwapchainKHR)vkGetDeviceProcAddr(vk.device, "vkCreateSwapchainKHR"); vkCreateImage = cast(PFN_vkCreateImage)vkGetDeviceProcAddr(vk.device, "vkCreateImage"); vkCreateImageView = cast(PFN_vkCreateImageView)vkGetDeviceProcAddr(vk.device, "vkCreateImageView"); + vkCreateBufferView = cast(PFN_vkCreateBufferView)vkGetDeviceProcAddr(vk.device, "vkCreateBufferView"); vkGetSwapchainImagesKHR = cast(PFN_vkGetSwapchainImagesKHR)vkGetDeviceProcAddr(vk.device, "vkGetSwapchainImagesKHR"); vkGetDeviceQueue = cast(PFN_vkGetDeviceQueue)vkGetDeviceProcAddr(vk.device, "vkGetDeviceQueue"); vkCreateSemaphore = cast(PFN_vkCreateSemaphore)vkGetDeviceProcAddr(vk.device, "vkCreateSemaphore"); diff --git a/src/shaders/full_screen_triangle.vert.glsl b/src/shaders/full_screen_triangle.vert.glsl new file mode 100644 index 0000000..001d5b1 --- /dev/null +++ b/src/shaders/full_screen_triangle.vert.glsl @@ -0,0 +1,7 @@ +#version 460 + +void main() +{ + vec4 pos = vec4((float((gl_VertexIndex >> 1U) & 1U)) * 4.0 - 1.0, (float(gl_VertexIndex & 1U)) * 4.0 - 1.0, 0, 1.0); + gl_Position = pos; +} diff --git a/src/shaders/oit.frag.glsl b/src/shaders/oit.frag.glsl new file mode 100644 index 0000000..d9b84d5 --- /dev/null +++ b/src/shaders/oit.frag.glsl @@ -0,0 +1,84 @@ +#version 460 + +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_nonuniform_qualifier : require + +#define COMPOSITE_PASS + +#include "structures.layout" + +layout (location = 0) out vec4 FragColor; + +void BubbleSort(inout uvec2 array[OIT_LAYERS], int n) +{ + for(int i = (n - 2); i >= 0; --i) + { + for(int j = 0; j <= i; ++j) + { + if(uintBitsToFloat(array[j].g) >= uintBitsToFloat(array[j+1].g)) + { + uvec2 temp = array[j+1]; + array[j+1] = array[j]; + array[j] = temp; + } + } + } +} + +float UnPreMultSRGBToLinear(float col) +{ + return col < 0.04045f ? col / 12.92f : pow((col + 0.055f) / 1.055f, 2.4f); +} + +vec4 UnPreMultSRGBToLinear(vec4 col) +{ + col.r = UnPreMultSRGBToLinear(col.r); + col.g = UnPreMultSRGBToLinear(col.g); + col.b = UnPreMultSRGBToLinear(col.b); + return col; +} + +void DoBlend(inout vec4 color, vec4 base_color) +{ + color.rgb += (1 - color.a) * base_color.rgb; + color.a += (1 - color.a) * base_color.a; +} + +void DoBlendPacked(inout vec4 color, uint fragment) +{ + vec4 unpacked_color = unpackUnorm4x8(fragment); + unpacked_color = UnPreMultSRGBToLinear(unpacked_color); + unpacked_color.rgb *= unpacked_color.a; + DoBlend(color, unpacked_color); +} + +void main() +{ + ivec2 coord = ivec2(gl_FragCoord.xy); + int store_mask = 0; + int view_size = int(G.res.x) * int(G.res.y); + int sample_id = 0; + int list_pos = view_size * OIT_LAYERS * sample_id + coord.y * int(G.res.x) + coord.x; + uvec2 array[OIT_LAYERS]; + + vec4 color = vec4(0.0); + + int fragments = int(imageLoad(ImageAux, coord).r); + fragments = min(OIT_LAYERS, fragments); + + for (int i = 0; i < fragments; i++) + { + array[i] = imageLoad(ImageABuffer, list_pos + i * view_size).rg; + } + + BubbleSort(array, fragments); + + vec4 color_sum = vec4(0.0); + + for(int i = 0; i < fragments; i++) + { + DoBlendPacked(color_sum, array[i].x); + } + + FragColor = color_sum; +} diff --git a/src/shaders/pbr.frag.glsl b/src/shaders/pbr.frag.glsl index d1170ed..e47f671 100644 --- a/src/shaders/pbr.frag.glsl +++ b/src/shaders/pbr.frag.glsl @@ -10,7 +10,7 @@ layout (location = 0) in struct FragDataIn { vec2 uv; } FragData; -layout (location = 0) out vec4 FragColor; +layout (location = 0, index = 0) out vec4 FragColor; vec4 CalculateDirectionalLight(vec4 diff_col, vec4 diff_samp, vec4 light_col, vec3 dir, vec3 normal) { @@ -25,8 +25,27 @@ vec4 CalculateDirectionalLight(vec4 diff_col, vec4 diff_samp, vec4 light_col, ve return (ambient + diffuse); } +float UnPreMultLinearToSRGB(float col) +{ + return col < 0.0031308f ? col * 12.92f : (pow(col, 1.0f / 2.4f) * 1.055f) - 0.055f; +} + +vec4 UnPreMultLinearToSRGB(vec4 col) +{ + col.r = UnPreMultLinearToSRGB(col.x); + col.g = UnPreMultLinearToSRGB(col.x); + col.b = UnPreMultLinearToSRGB(col.x); + return col; +} + void main() { + ivec2 coord = ivec2(gl_FragCoord.xy); + int store_mask = 0; + int view_size = int(G.res.x) * int(G.res.y); + int sample_id = 0; + int list_pos = view_size * OIT_LAYERS * sample_id + coord.y * int(G.res.x) + coord.x; + vec4 col = Materials[nonuniformEXT(PC.mat_id)].diffuse; vec4 tex_col = texture(sampler2D(Textures[nonuniformEXT(Materials[nonuniformEXT(PC.mat_id)].albedo_texture)], SamplerNearest), FragData.uv); @@ -39,5 +58,19 @@ void main() out_col.a = alpha_col.a; } - FragColor = out_col; + vec4 srgb_col = UnPreMultLinearToSRGB(out_col); + + uvec4 store_value = uvec4(packUnorm4x8(srgb_col), floatBitsToUint(gl_FragCoord.z), store_mask, 0); + + uint old_counter = imageAtomicAdd(ImageAux, coord, 1u); + if (old_counter < OIT_LAYERS) + { + imageStore(ImageABuffer, list_pos + int(old_counter) * view_size, store_value); + + FragColor = vec4(0.0); + } + else + { + FragColor = vec4(out_col.rgb * out_col.a, out_col.a); // Change to vec4(0.0) to disable tail blending + } } diff --git a/src/shaders/structures.layout b/src/shaders/structures.layout index ca31899..b150455 100644 --- a/src/shaders/structures.layout +++ b/src/shaders/structures.layout @@ -2,6 +2,8 @@ // **** STRUCTS MUST BE PACKED IN OPTIMAL PACKING ORDER TO MATCH D STRUCTS **** // **************************************************************************** +#define OIT_LAYERS 64 + layout (set = 0, binding = 0) uniform GlobalUniforms { mat4 view_matrix; mat4 projection_matrix; @@ -20,6 +22,20 @@ 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 {