diff options
author | Anna (navi) Figueiredo Gomes <navi@vlhl.dev> | 2024-02-11 20:39:22 +0100 |
---|---|---|
committer | Anna (navi) Figueiredo Gomes <navi@vlhl.dev> | 2024-02-11 20:39:22 +0100 |
commit | 4ecdaa7cd08f4f3ee04cd49f8f2271636ac81e64 (patch) | |
tree | 96c95877250d63ca2d688ad472bd6a46bdc3fbb3 /src/render | |
parent | 35a70d71f62e41d78d68247075ce174f2b6d997a (diff) |
Signed-off-by: Anna (navi) Figueiredo Gomes <navi@vlhl.dev>
Diffstat (limited to 'src/render')
-rw-r--r-- | src/render/renderer.c | 318 |
1 files changed, 299 insertions, 19 deletions
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; |