summaryrefslogtreecommitdiff
path: root/src/render
diff options
context:
space:
mode:
Diffstat (limited to 'src/render')
-rw-r--r--src/render/renderer.c318
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;