summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna (navi) Figueiredo Gomes <navi@vlhl.dev>2024-02-11 20:39:22 +0100
committerAnna (navi) Figueiredo Gomes <navi@vlhl.dev>2024-02-11 20:39:22 +0100
commit4ecdaa7cd08f4f3ee04cd49f8f2271636ac81e64 (patch)
tree96c95877250d63ca2d688ad472bd6a46bdc3fbb3
parent35a70d71f62e41d78d68247075ce174f2b6d997a (diff)
transparencyHEADmain
Signed-off-by: Anna (navi) Figueiredo Gomes <navi@vlhl.dev>
-rw-r--r--include/render/mesh.h1
-rw-r--r--include/render/renderer.h15
-rw-r--r--meson.build18
-rw-r--r--shaders/combine.frag65
-rw-r--r--shaders/combine.vert11
-rw-r--r--shaders/shader.frag25
-rw-r--r--shaders/shader.vert5
-rw-r--r--src/main.c72
-rw-r--r--src/render/renderer.c318
9 files changed, 463 insertions, 67 deletions
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;