From 4ecdaa7cd08f4f3ee04cd49f8f2271636ac81e64 Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Sun, 11 Feb 2024 20:39:22 +0100 Subject: transparency Signed-off-by: Anna (navi) Figueiredo Gomes --- include/render/mesh.h | 1 + include/render/renderer.h | 15 ++- meson.build | 18 ++- shaders/combine.frag | 65 ++++++++++ shaders/combine.vert | 11 ++ shaders/shader.frag | 25 +++- shaders/shader.vert | 5 +- src/main.c | 72 +++++------ src/render/renderer.c | 318 +++++++++++++++++++++++++++++++++++++++++++--- 9 files changed, 463 insertions(+), 67 deletions(-) create mode 100644 shaders/combine.frag create mode 100644 shaders/combine.vert diff --git a/include/render/mesh.h b/include/render/mesh.h index aed4836..bf8c1ee 100644 --- a/include/render/mesh.h +++ b/include/render/mesh.h @@ -21,6 +21,7 @@ struct ubo { mat4x4 model; mat4x4 view; mat4x4 proj; + uint32_t max_frags; }; struct vertex { diff --git a/include/render/renderer.h b/include/render/renderer.h index bae799d..2c764ca 100644 --- a/include/render/renderer.h +++ b/include/render/renderer.h @@ -62,8 +62,6 @@ struct renderer { } images; } swapchain; - VkRenderPass render_pass; - struct { VkCommandPool pool; VkCommandBuffer buffers[MAX_FRAMES]; @@ -72,6 +70,7 @@ struct renderer { struct { VkPipelineLayout layout; VkPipeline gfx; + VkPipeline blend; } pipeline; struct { @@ -92,10 +91,16 @@ struct renderer { void *data; } uniform[MAX_FRAMES]; - VkSampler sampler; - VkSampleCountFlagBits msaa_samples; + VkRenderPass render_pass; + VkRenderPass blend_pass; + VkFramebuffer blend_framebuffer[MAX_FRAMES]; + + struct buffer node[MAX_FRAMES]; + struct buffer count[MAX_FRAMES]; + struct image head[MAX_FRAMES]; + VkImageView head_view[MAX_FRAMES]; + uint32_t max_count; - uint32_t mip_levels; uint32_t current_frame; }; diff --git a/meson.build b/meson.build index 4c0c163..d43414f 100644 --- a/meson.build +++ b/meson.build @@ -64,10 +64,24 @@ frag_shader = custom_target( command: [find_program('glslc'), '@INPUT@', '-o', '@OUTPUT@'] ) -c_files += [ vert_shader, frag_shader ] +combine_vert = custom_target( + input: 'shaders/combine.vert', + output: '@PLAINNAME@', + command: [find_program('glslc'), '@INPUT@', '-o', '@OUTPUT@'] +) + +combine_frag = custom_target( + input: 'shaders/combine.frag', + output: '@PLAINNAME@', + command: [find_program('glslc'), '@INPUT@', '-o', '@OUTPUT@'] +) + +c_files += [ vert_shader, frag_shader, combine_vert, combine_frag ] executable('vk', c_files, dependencies: libs, include_directories: ['include/'], c_args: [ '-DVERTEX_SHADER="@0@"'.format(vert_shader.full_path()), - '-DFRAGMENT_SHADER="@0@"'.format(frag_shader.full_path()) + '-DFRAGMENT_SHADER="@0@"'.format(frag_shader.full_path()), + '-DBLEND_VERT="@0@"'.format(combine_vert.full_path()), + '-DBLEND_FRAG="@0@"'.format(combine_frag.full_path()) ]) diff --git a/shaders/combine.frag b/shaders/combine.frag new file mode 100644 index 0000000..4240528 --- /dev/null +++ b/shaders/combine.frag @@ -0,0 +1,65 @@ +#version 450 + +#define LIST_END ~0x0 +#define SORT_MAX 32 + +layout (location = 0) out vec4 color; + +layout(binding = 0) uniform mvp { + mat4 model; + mat4 view; + mat4 proj; + uint count; +} ubo; + +layout(binding = 1) buffer fragment_buffer { + uvec3 fragments[]; +}; +layout(binding = 2, r32ui) uniform uimage2D head; +layout(binding = 3) buffer counter { + int data; +}; + +vec4 blend_colors(uint packed_color, vec4 dst_color) { + const vec4 src_color = unpackUnorm4x8(packed_color); + return vec4(mix(dst_color.rgb, src_color.rgb, src_color.a), dst_color.a * (1.0f - src_color.a)); +} + +void main() { + color = vec4(0, 0, 0, 1); + uint idx = imageLoad(head, ivec2(gl_FragCoord.xy)).r; + imageStore(head, ivec2(gl_FragCoord.xy), ivec4(LIST_END, 0, 0, 0)); + + uvec2 sorted[SORT_MAX]; + uint sorted_count = 0; + + // TODO: use a proper struct + while (idx != LIST_END) { + const uvec3 fragment = fragments[idx]; + idx = fragment.x; + + if (sorted_count < SORT_MAX) { + uint i = sorted_count; + for(; i > 0 && fragment.z > sorted[i - 1].y; i--) { + sorted[i] = sorted[i - 1]; + } + sorted[i] = fragment.yz; + sorted_count++; + } else if (fragment.z > sorted[0].y) { + color = blend_colors(sorted[0].x, color); + uint i = 0; + for (; i < SORT_MAX - 1 && fragment.z < sorted[i + 1].y; i++) { + sorted[i] = sorted[i + 1]; + } + sorted[i] = fragment.yz; + } else { + color = blend_colors(fragment.y, color); + } + } + + for (int i = 0; i < sorted_count; i++) { + color = blend_colors(sorted[i].x, color); + } + + color.a = 1.0f - color.a; +} diff --git a/shaders/combine.vert b/shaders/combine.vert new file mode 100644 index 0000000..b9b349e --- /dev/null +++ b/shaders/combine.vert @@ -0,0 +1,11 @@ +#version 450 + +const vec2 vertices[] = { + vec2(-1.0f, 3.0f), + vec2(-1.0f, -1.0f), + vec2(3.0f, -1.0f) +}; + +void main() { + gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0f, 1.0f); +} diff --git a/shaders/shader.frag b/shaders/shader.frag index a4ce603..eb255e3 100644 --- a/shaders/shader.frag +++ b/shaders/shader.frag @@ -1,8 +1,27 @@ #version 450 -layout(location = 0) in vec4 fragColor; -layout(location = 0) out vec4 outColor; +layout(location = 0) in vec4 color; + +layout(set = 0, binding = 0) uniform mvp { + mat4 model; + mat4 view; + mat4 proj; + uint count; +} ubo; + +layout(binding = 1) buffer fragment_buffer { + uvec3 fragments[]; +}; +layout(binding = 2, r32ui) uniform uimage2D head; +layout(binding = 3) buffer counter { + uint data; +}; void main() { - outColor = fragColor; + const uint idx = atomicAdd(data, 1); + if (idx >= ubo.count) { + discard; + } + const uint prev_idx = imageAtomicExchange(head, ivec2(gl_FragCoord.xy), idx); + fragments[idx] = uvec3(prev_idx, packUnorm4x8(color), floatBitsToUint(gl_FragCoord.z)); } diff --git a/shaders/shader.vert b/shaders/shader.vert index 48f67d6..181d1bd 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -10,6 +10,7 @@ layout(set = 0, binding = 0) uniform mvp { mat4 model; mat4 view; mat4 proj; + uint count; } ubo; layout(push_constant) uniform mesh_data { @@ -17,6 +18,6 @@ layout(push_constant) uniform mesh_data { } mesh; void main() { - gl_Position = ubo.proj * ubo.view * ubo.model * mesh.transform * ubo.model * vec4(in_position, 1.0); - frag_color = gl_Position; + gl_Position = ubo.proj * ubo.view * ubo.model * mesh.transform * vec4(in_position, 1.0); + frag_color = in_color; } diff --git a/src/main.c b/src/main.c index 763bd4e..da3adf4 100644 --- a/src/main.c +++ b/src/main.c @@ -17,42 +17,42 @@ int main() { } struct vertex vertices[] = { - { .position = { -0.25, -0.25, -0.25 }, .color = { 0.f, 0.f, 0.f} }, - { .position = { 0.25, -0.25, -0.25,}, .color = { 1.f, 0.f, 0.f} }, - { .position = { -0.25, 0.25, -0.25,}, .color = { 0.f, 1.f, 0.f} }, - { .position = { -0.25, 0.25, -0.25,}, .color = { 0.f, 1.f, 0.f} }, - { .position = { 0.25, -0.25, -0.25,}, .color = { 1.f, 0.f, 0.f} }, - { .position = { 0.25, 0.25, -0.25,}, .color = { 1.f, 1.f, 0.f} }, - { .position = { -0.25, -0.25, 0.25,}, .color = { 0.f, 0.f, 1.f} }, - { .position = { -0.25, 0.25, 0.25,}, .color = { 0.f, 1.f, 1.f} }, - { .position = { 0.25, -0.25, 0.25,}, .color = { 1.f, 0.f, 1.f} }, - { .position = { 0.25, -0.25, 0.25,}, .color = { 1.f, 0.f, 1.f} }, - { .position = { -0.25, 0.25, 0.25,}, .color = { 0.f, 1.f, 1.f} }, - { .position = { 0.25, 0.25, 0.25,}, .color = { 1.f, 1.f, 1.f} }, - { .position = { 0.25, 0.25, 0.25,}, .color = { 1.f, 1.f, 1.f} }, - { .position = { 0.25, 0.25, -0.25,}, .color = { 1.f, 1.f, 0.f} }, - { .position = { 0.25, -0.25, 0.25,}, .color = { 1.f, 0.f, 1.f} }, - { .position = { 0.25, -0.25, 0.25,}, .color = { 1.f, 0.f, 1.f} }, - { .position = { 0.25, 0.25, -0.25,}, .color = { 1.f, 1.f, 0.f} }, - { .position = { 0.25, -0.25, -0.25,}, .color = { 1.f, 0.f, 0.f} }, - { .position = { -0.25, 0.25, 0.25,}, .color = { 0.f, 1.f, 1.f} }, - { .position = { -0.25, -0.25, 0.25,}, .color = { 0.f, 0.f, 1.f} }, - { .position = { -0.25, 0.25, -0.25,}, .color = { 0.f, 1.f, 0.f} }, - { .position = { -0.25, 0.25, -0.25,}, .color = { 0.f, 1.f, 0.f} }, - { .position = { -0.25, -0.25, 0.25,}, .color = { 0.f, 0.f, 1.f} }, - { .position = { -0.25, -0.25, -0.25,}, .color = { 0.f, 0.f, 0.f} }, - { .position = { 0.25, 0.25, 0.25,}, .color = { 1.f, 1.f, 1.f} }, - { .position = { -0.25, 0.25, 0.25,}, .color = { 0.f, 1.f, 1.f} }, - { .position = { 0.25, 0.25, -0.25,}, .color = { 1.f, 1.f, 0.f} }, - { .position = { 0.25, 0.25, -0.25,}, .color = { 1.f, 1.f, 0.f} }, - { .position = { -0.25, 0.25, 0.25,}, .color = { 0.f, 1.f, 1.f} }, - { .position = { -0.25, 0.25, -0.25,}, .color = { 0.f, 1.f, 0.f} }, - { .position = { 0.25, -0.25, 0.25,}, .color = { 1.f, 0.f, 1.f} }, - { .position = { 0.25, -0.25, -0.25,}, .color = { 1.f, 0.f, 0.f} }, - { .position = { -0.25, -0.25, 0.25,}, .color = { 0.f, 0.f, 1.f} }, - { .position = { -0.25, -0.25, 0.25,}, .color = { 0.f, 0.f, 1.f} }, - { .position = { 0.25, -0.25, -0.25,}, .color = { 1.f, 0.f, 0.f} }, - { .position = { -0.25, -0.25, -0.25,}, .color = { 0.f, 0.f, 0.f} }, + { .position = { -0.25, -0.25, -0.25 }, .color = { 0.f, 0.f, 0.f, 0.5f } }, + { .position = { 0.25, -0.25, -0.25,}, .color = { 1.f, 0.f, 0.f, 0.5f } }, + { .position = { -0.25, 0.25, -0.25,}, .color = { 0.f, 1.f, 0.f, 0.5f } }, + { .position = { -0.25, 0.25, -0.25,}, .color = { 0.f, 1.f, 0.f, 0.5f } }, + { .position = { 0.25, -0.25, -0.25,}, .color = { 1.f, 0.f, 0.f, 0.5f } }, + { .position = { 0.25, 0.25, -0.25,}, .color = { 1.f, 1.f, 0.f, 0.5f } }, + { .position = { -0.25, -0.25, 0.25,}, .color = { 0.f, 0.f, 1.f, 0.5f } }, + { .position = { -0.25, 0.25, 0.25,}, .color = { 0.f, 1.f, 1.f, 0.5f } }, + { .position = { 0.25, -0.25, 0.25,}, .color = { 1.f, 0.f, 1.f, 0.5f } }, + { .position = { 0.25, -0.25, 0.25,}, .color = { 1.f, 0.f, 1.f, 0.5f } }, + { .position = { -0.25, 0.25, 0.25,}, .color = { 0.f, 1.f, 1.f, 0.5f } }, + { .position = { 0.25, 0.25, 0.25,}, .color = { 1.f, 1.f, 1.f, 0.5f } }, + { .position = { 0.25, 0.25, 0.25,}, .color = { 1.f, 1.f, 1.f, 0.5f } }, + { .position = { 0.25, 0.25, -0.25,}, .color = { 1.f, 1.f, 0.f, 0.5f } }, + { .position = { 0.25, -0.25, 0.25,}, .color = { 1.f, 0.f, 1.f, 0.5f } }, + { .position = { 0.25, -0.25, 0.25,}, .color = { 1.f, 0.f, 1.f, 0.5f } }, + { .position = { 0.25, 0.25, -0.25,}, .color = { 1.f, 1.f, 0.f, 0.5f } }, + { .position = { 0.25, -0.25, -0.25,}, .color = { 1.f, 0.f, 0.f, 0.5f } }, + { .position = { -0.25, 0.25, 0.25,}, .color = { 0.f, 1.f, 1.f, 0.5f } }, + { .position = { -0.25, -0.25, 0.25,}, .color = { 0.f, 0.f, 1.f, 0.5f } }, + { .position = { -0.25, 0.25, -0.25,}, .color = { 0.f, 1.f, 0.f, 0.5f } }, + { .position = { -0.25, 0.25, -0.25,}, .color = { 0.f, 1.f, 0.f, 0.5f } }, + { .position = { -0.25, -0.25, 0.25,}, .color = { 0.f, 0.f, 1.f, 0.5f } }, + { .position = { -0.25, -0.25, -0.25,}, .color = { 0.f, 0.f, 0.f, 0.5f } }, + { .position = { 0.25, 0.25, 0.25,}, .color = { 1.f, 1.f, 1.f, 0.5f } }, + { .position = { -0.25, 0.25, 0.25,}, .color = { 0.f, 1.f, 1.f, 0.5f } }, + { .position = { 0.25, 0.25, -0.25,}, .color = { 1.f, 1.f, 0.f, 0.5f } }, + { .position = { 0.25, 0.25, -0.25,}, .color = { 1.f, 1.f, 0.f, 0.5f } }, + { .position = { -0.25, 0.25, 0.25,}, .color = { 0.f, 1.f, 1.f, 0.5f } }, + { .position = { -0.25, 0.25, -0.25,}, .color = { 0.f, 1.f, 0.f, 0.5f } }, + { .position = { 0.25, -0.25, 0.25,}, .color = { 1.f, 0.f, 1.f, 0.5f } }, + { .position = { 0.25, -0.25, -0.25,}, .color = { 1.f, 0.f, 0.f, 0.5f } }, + { .position = { -0.25, -0.25, 0.25,}, .color = { 0.f, 0.f, 1.f, 0.5f } }, + { .position = { -0.25, -0.25, 0.25,}, .color = { 0.f, 0.f, 1.f, 0.5f } }, + { .position = { 0.25, -0.25, -0.25,}, .color = { 1.f, 0.f, 0.f, 0.5f } }, + { .position = { -0.25, -0.25, -0.25,}, .color = { 0.f, 0.f, 0.f, 0.5f } }, }; uint32_t indices[len(vertices)]; diff --git a/src/render/renderer.c b/src/render/renderer.c index 1c1b23c..4373999 100644 --- a/src/render/renderer.c +++ b/src/render/renderer.c @@ -16,12 +16,26 @@ #define FRAGMENT_SHADER "" #endif +#ifndef BLEND_VERT +#error "no blend" +#define BLEND_VERT "" +#endif + +#ifndef BLEND_FRAG +#error "no blend" +#define BLEND_FRAG "" +#endif + // TODO: add asserts #define len(X) sizeof(X) / sizeof(*X) #define min(X, Y) X < Y ? X : Y #define max(X, Y) X > Y ? X : Y +struct node { + uint32_t fragment[3]; +}; + static VkDebugUtilsMessengerEXT debug_messenger; static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, @@ -46,6 +60,13 @@ static bool enumarate_phygpus(struct renderer *ren) { VkExtensionProperties ext_props[count]; vkEnumerateDeviceExtensionProperties(gpus[i], NULL, &count, ext_props); + VkPhysicalDeviceFeatures feats; + vkGetPhysicalDeviceFeatures(gpus[i], &feats); + if (!feats.fragmentStoresAndAtomics) { + printf("no atomic store\n"); + continue; + } + bool swapchain = false; for (size_t i = 0; i < count; i++) if (strcmp(ext_props[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) { @@ -63,9 +84,8 @@ static bool enumarate_phygpus(struct renderer *ren) { ssize_t gfx_queue = -1, present_queue = -1; for (size_t q = 0; q < count; q++) { - if ((queue_props[q].queueFlags & VK_QUEUE_GRAPHICS_BIT)) { + if ((queue_props[q].queueFlags & VK_QUEUE_GRAPHICS_BIT)) gfx_queue = q; - } VkBool32 present_support = false; vkGetPhysicalDeviceSurfaceSupportKHR(gpus[i], q, ren->surface, &present_support); @@ -135,12 +155,20 @@ static bool create_device(struct renderer *ren) { const char * const ext = VK_KHR_SWAPCHAIN_EXTENSION_NAME; + VkPhysicalDeviceFeatures feats = { .fragmentStoresAndAtomics = VK_TRUE }; + VkPhysicalDeviceVulkan12Features feats12 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, + .runtimeDescriptorArray = VK_TRUE + }; + VkDeviceCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pNext = &feats12, .pQueueCreateInfos = queue_infos, .queueCreateInfoCount = len(queue_infos), .enabledExtensionCount = 1, - .ppEnabledExtensionNames = &ext + .ppEnabledExtensionNames = &ext, + .pEnabledFeatures = &feats }; if (vkCreateDevice(ren->phy_gpus.chosen->gpu, &create_info, NULL, &ren->gpu.device) != VK_SUCCESS) @@ -233,6 +261,18 @@ static VkResult create_renderpass(struct renderer *ren) { .pDependencies = &dep }; + vkCreateRenderPass(ren->gpu.device, &create_info, NULL, &ren->blend_pass); + + subpass = (VkSubpassDescription) { + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS + }; + + create_info = (VkRenderPassCreateInfo) { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .subpassCount = 1, + .pSubpasses = &subpass + }; + return vkCreateRenderPass(ren->gpu.device, &create_info, NULL, &ren->render_pass); } @@ -304,7 +344,7 @@ static bool create_swapchain(struct renderer *ren) { VkImageView attachs[] = { ren->swapchain.images.data[i].view, ren->depth.view }; VkFramebufferCreateInfo fb_info = { .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - .renderPass = ren->render_pass, + .renderPass = ren->blend_pass, .attachmentCount = len(attachs), .pAttachments = attachs, .width = ren->swapchain.extent.width, @@ -316,6 +356,17 @@ static bool create_swapchain(struct renderer *ren) { return false; } + VkFramebufferCreateInfo fb_create_info = { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .renderPass = ren->render_pass, + .width = ren->swapchain.extent.width, + .height = ren->swapchain.extent.height, + .layers = 1 + }; + + for (size_t i = 0; i < MAX_FRAMES; i++) + vkCreateFramebuffer(ren->gpu.device, &fb_create_info, NULL, &ren->blend_framebuffer[i]); + return true; } @@ -447,9 +498,60 @@ static bool create_pipeline(struct renderer *ren, size_t shader_count, if (vkCreateGraphicsPipelines(ren->gpu.device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &ren->pipeline.gfx) != VK_SUCCESS) return false; + vertex_input_info = (VkPipelineVertexInputStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + }; + + struct shader shaders_blend[2]; + if (!shader_load(BLEND_VERT, &shaders_blend[0])) { + fputs("failed to load " BLEND_VERT "\n", stderr); + return false; + } + if (!shader_load(BLEND_FRAG, &shaders_blend[1])) { + fputs("failed to load " BLEND_FRAG "\n", stderr); + return false; + } + + VkShaderModule shader_blend_modules[2]; + shader_create_module(ren, shaders_blend[0].len, shaders_blend[0].code, &shader_blend_modules[0]); + shader_create_module(ren, shaders_blend[1].len, shaders_blend[1].code, &shader_blend_modules[1]); + + VkPipelineShaderStageCreateInfo shader_blend_info[2] = { + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = shader_blend_modules[0], + .pName = "main" + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = shader_blend_modules[1], + .pName = "main" + } + }; + + pipeline_info.stageCount = 2; + pipeline_info.pStages = shader_blend_info; + pipeline_info.renderPass = ren->blend_pass; + + color_state.blendEnable = VK_TRUE; + color_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_state.colorBlendOp = VK_BLEND_OP_ADD; + color_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + color_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_state.alphaBlendOp = VK_BLEND_OP_ADD; + + if (vkCreateGraphicsPipelines(ren->gpu.device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &ren->pipeline.blend) != VK_SUCCESS) + return false; + for (size_t i = 0; i < shader_count; i++) vkDestroyShaderModule(ren->gpu.device, modules[i], NULL); + vkDestroyShaderModule(ren->gpu.device, shader_blend_modules[0], NULL); + vkDestroyShaderModule(ren->gpu.device, shader_blend_modules[1], NULL); + return true; } @@ -493,17 +595,25 @@ static bool create_sync_objects(struct renderer *ren) { static bool create_descriptor_sets(struct renderer *ren) { VkDescriptorPoolCreateInfo pool_info = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - .maxSets = MAX_FRAMES + 15, - .poolSizeCount = 2, + .maxSets = MAX_FRAMES, + .poolSizeCount = 4, .pPoolSizes = (VkDescriptorPoolSize[]) { { .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = MAX_FRAMES }, { - .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .descriptorCount = 15 - } + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = MAX_FRAMES + }, + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = MAX_FRAMES + }, + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = MAX_FRAMES + }, } }; @@ -515,7 +625,25 @@ static bool create_descriptor_sets(struct renderer *ren) { .binding = 0, .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = 1, - .stageFlags = VK_SHADER_STAGE_VERTEX_BIT + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT + }, + { + .binding = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT + }, + { + .binding = 2, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT + }, + { + .binding = 3, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT } }; @@ -546,19 +674,53 @@ static bool create_descriptor_sets(struct renderer *ren) { for (size_t i = 0; i < MAX_FRAMES; i++) { VkDescriptorBufferInfo buffer_info = { .buffer = ren->uniform[i].buffer.buffer, - .offset = 0, .range = sizeof(struct ubo) }; + VkDescriptorBufferInfo node_info = { + .buffer = ren->node[i].buffer, + .range = sizeof(struct node) * ren->max_count + }; + VkDescriptorImageInfo head_info = { + .imageLayout = VK_IMAGE_LAYOUT_GENERAL, + .imageView = ren->head_view[i] + }; + VkDescriptorBufferInfo count_info = { + .buffer = ren->count[i].buffer, + .range = sizeof(uint32_t) + }; VkWriteDescriptorSet desc_write[] = { { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .dstSet = ren->descriptor.sets[i], .dstBinding = 0, - .dstArrayElement = 0, .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = 1, .pBufferInfo = &buffer_info, }, + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = ren->descriptor.sets[i], + .dstBinding = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .pBufferInfo = &node_info, + }, + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = ren->descriptor.sets[i], + .dstBinding = 2, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = 1, + .pImageInfo = &head_info + }, + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = ren->descriptor.sets[i], + .dstBinding = 3, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .pBufferInfo = &count_info, + }, }; vkUpdateDescriptorSets(ren->gpu.device, len(desc_write), desc_write, 0, NULL); @@ -567,6 +729,43 @@ static bool create_descriptor_sets(struct renderer *ren) { return true; } +// FIXME: repeated from mesh.c +static VkCommandBuffer begin_single_command(struct renderer *ren) { + VkCommandBufferAllocateInfo alloc_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandPool = ren->command.pool, + .commandBufferCount = 1 + }; + + VkCommandBuffer buffer; + vkAllocateCommandBuffers(ren->gpu.device, &alloc_info, &buffer); + + VkCommandBufferBeginInfo begin_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT + }; + + vkBeginCommandBuffer(buffer, &begin_info); + + return buffer; +} + +static void end_single_command(struct renderer *ren, VkCommandBuffer buffer) { + vkEndCommandBuffer(buffer); + + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .commandBufferCount = 1, + .pCommandBuffers = &buffer + }; + + vkQueueSubmit(ren->gpu.gfx_queue, 1, &submit_info, VK_NULL_HANDLE); + vkQueueWaitIdle(ren->gpu.gfx_queue); + + vkFreeCommandBuffers(ren->gpu.device, ren->command.pool, 1, &buffer); +} + struct renderer *renderer_init(struct window *win) { struct renderer *ren = calloc(1, sizeof(*ren)); ren->win = win; @@ -576,14 +775,14 @@ struct renderer *renderer_init(struct window *win) { .applicationVersion = VK_MAKE_VERSION(1, 0, 0), .pEngineName = "void", .engineVersion = VK_MAKE_VERSION(1, 0, 0), - .apiVersion = VK_API_VERSION_1_0 + .apiVersion = VK_API_VERSION_1_3 }; // TODO: query window const char *exts[] = { VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, - VK_EXT_DEBUG_UTILS_EXTENSION_NAME + VK_EXT_DEBUG_UTILS_EXTENSION_NAME, }; const char *validation_layers[] = { "VK_LAYER_KHRONOS_validation" }; @@ -674,10 +873,61 @@ struct renderer *renderer_init(struct window *win) { } }; + ren->max_count = ren->swapchain.extent.width * ren->swapchain.extent.height * 16; + for (size_t i = 0; i < MAX_FRAMES; i++) { + // ubo buffer_create(ren, sizeof(struct ubo), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &ren->uniform[i].buffer); vkMapMemory(ren->gpu.device, ren->uniform[i].buffer.memory, 0, sizeof(struct ubo), 0, &ren->uniform[i].data); + + VkDeviceSize size = sizeof(struct node) * ren->max_count; + buffer_create(ren, size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &ren->node[i]); + buffer_create(ren, sizeof(uint32_t), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &ren->count[i]); + create_image(ren, ren->swapchain.extent, 1, VK_FORMAT_R32_UINT, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &ren->head[i].image, &ren->head[i].memory); + + // TODO: utilities to transition images + VkCommandBuffer cmd = begin_single_command(ren); + + VkImageSubresourceRange subresource_range = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .layerCount = 1, + .levelCount = 1 + }; + VkImageMemoryBarrier barrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .image = ren->head[i].image, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .subresourceRange = subresource_range + }; + vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); + vkCmdFillBuffer(cmd, ren->count[i].buffer, 0, sizeof(uint32_t), 0); + VkClearColorValue clear_value = { + .uint32 = { ~0x0, ~0x0, ~0x0 } + }; + vkCmdClearColorImage(cmd, ren->head[i].image, VK_IMAGE_LAYOUT_GENERAL, &clear_value, 1, &subresource_range); + end_single_command(ren, cmd); + + VkImageViewCreateInfo iv = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = ren->head[i].image, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = VK_FORMAT_R32_UINT, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = 1, + .layerCount = 1 + } + }; + + vkCreateImageView(ren->gpu.device, &iv, NULL, &ren->head_view[i]); } if (!create_descriptor_sets(ren)) @@ -720,22 +970,26 @@ void renderer_destroy(struct renderer *ren) { vkDestroySemaphore(ren->gpu.device, ren->locks.render_finished[i], NULL); vkDestroyFence(ren->gpu.device, ren->locks.in_flight[i], NULL); buffer_destroy(ren, &ren->uniform[i].buffer); + buffer_destroy(ren, &ren->node[i]); + buffer_destroy(ren, &ren->count[i]); + image_destroy(ren, &ren->head[i]); + vkDestroyImageView(ren->gpu.device, ren->head_view[i], NULL); + vkDestroyFramebuffer(ren->gpu.device, ren->blend_framebuffer[i], NULL); } swapchain_destroy(ren); - - vkDestroySampler(ren->gpu.device, ren->sampler, NULL); - vkDestroyDescriptorPool(ren->gpu.device, ren->descriptor.pool, NULL); vkDestroyDescriptorSetLayout(ren->gpu.device, ren->descriptor.layout, NULL); vkDestroyCommandPool(ren->gpu.device, ren->command.pool, NULL); vkDestroyPipeline(ren->gpu.device, ren->pipeline.gfx, NULL); + vkDestroyPipeline(ren->gpu.device, ren->pipeline.blend, NULL); vkDestroyPipelineLayout(ren->gpu.device, ren->pipeline.layout, NULL); vkDestroyRenderPass(ren->gpu.device, ren->render_pass, NULL); + vkDestroyRenderPass(ren->gpu.device, ren->blend_pass, NULL); vkDestroyDevice(ren->gpu.device, NULL); } @@ -762,6 +1016,7 @@ static void update_ubo(struct renderer *ren, uint32_t frame) { mat4x4_perspective(ubo.proj, 45, ren->swapchain.extent.width / (float) ren->swapchain.extent.height, 0.1f, 10.0f); ubo.proj[1][1] *= -1; + ubo.max_frags = ren->max_count; memcpy(ren->uniform[frame].data, &ubo, sizeof(ubo)); rotate += 0.0001; } @@ -788,7 +1043,6 @@ void renderer_draw(struct renderer *ren, size_t mesh_count, struct mesh meshes[m vkResetCommandBuffer(ren->command.buffers[frame], 0); // record cmd buffer - if (vkBeginCommandBuffer(ren->command.buffers[frame], &(VkCommandBufferBeginInfo) { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }) != VK_SUCCESS) return; @@ -801,7 +1055,7 @@ void renderer_draw(struct renderer *ren, size_t mesh_count, struct mesh meshes[m VkRenderPassBeginInfo render_pass_info = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .renderPass = ren->render_pass, - .framebuffer = ren->swapchain.images.data[image_index].framebuffer, + .framebuffer = ren->blend_framebuffer[frame], .renderArea = { .extent = ren->swapchain.extent, .offset = {0, 0} @@ -847,6 +1101,32 @@ void renderer_draw(struct renderer *ren, size_t mesh_count, struct mesh meshes[m vkCmdEndRenderPass(ren->command.buffers[frame]); + render_pass_info = (VkRenderPassBeginInfo) { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = ren->blend_pass, + .framebuffer = ren->swapchain.images.data[image_index].framebuffer, + .renderArea = { + .extent = ren->swapchain.extent, + .offset = {0, 0} + }, + .clearValueCount = len(clear_color), + .pClearValues = clear_color + }; + vkCmdBeginRenderPass(ren->command.buffers[frame], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); + + vkCmdSetViewport(ren->command.buffers[frame], 0, 1, &viewport); + vkCmdSetScissor(ren->command.buffers[frame], 0, 1, &scissor); + + vkCmdBindDescriptorSets(ren->command.buffers[frame], VK_PIPELINE_BIND_POINT_GRAPHICS, + ren->pipeline.layout, 0, 1, &ren->descriptor.sets[frame], 0, NULL); + + vkCmdBindPipeline(ren->command.buffers[frame], VK_PIPELINE_BIND_POINT_GRAPHICS, ren->pipeline.blend); + vkCmdDraw(ren->command.buffers[frame], 3, 1, 0, 0); + + vkCmdEndRenderPass(ren->command.buffers[frame]); + + vkCmdFillBuffer(ren->command.buffers[frame], ren->count[frame].buffer, 0, sizeof(uint32_t), 0); + if (vkEndCommandBuffer(ren->command.buffers[frame]) != VK_SUCCESS) return; -- cgit v1.2.3