diff options
| -rw-r--r-- | include/render/mesh.h | 1 | ||||
| -rw-r--r-- | include/render/renderer.h | 15 | ||||
| -rw-r--r-- | meson.build | 18 | ||||
| -rw-r--r-- | shaders/combine.frag | 65 | ||||
| -rw-r--r-- | shaders/combine.vert | 11 | ||||
| -rw-r--r-- | shaders/shader.frag | 25 | ||||
| -rw-r--r-- | shaders/shader.vert | 5 | ||||
| -rw-r--r-- | src/main.c | 72 | ||||
| -rw-r--r-- | src/render/renderer.c | 318 | 
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;  } @@ -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; | 
