+ bo->mobj.mem_sz = 0;
+ bo->buf = VK_NULL_HANDLE;
+ bo->mobj.mem = VK_NULL_HANDLE;
+}
+
+bool
+vk_create_fence(struct vk_ctx *ctx,
+ VkFence *fence)
+{
+ VkFenceCreateInfo finfo;
+
+ memset(&finfo, 0, sizeof finfo);
+ finfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+ finfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
+
+ if (vkCreateFence(ctx->dev, &finfo, 0, fence) != VK_SUCCESS) {
+ fprintf(stderr, "Failed to create fence.\n");
+ fence = 0;
+ return false;
+ }
+
+ return true;
+}
+
+VkCommandBuffer
+vk_create_cmd_buffer(struct vk_ctx *ctx)
+{
+ VkCommandBuffer cmd_buf;
+ VkCommandBufferAllocateInfo alloc_info;
+
+ memset(&alloc_info, 0, sizeof alloc_info);
+ alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ alloc_info.commandBufferCount = 1;
+ alloc_info.commandPool = ctx->cmd_pool;
+
+ if (vkAllocateCommandBuffers(ctx->dev, &alloc_info, &cmd_buf) != VK_SUCCESS)
+ return 0;
+
+ return cmd_buf;
+}
+
+bool
+vk_record_cmd_buffer(struct vk_ctx *ctx,
+ VkCommandBuffer cmd_buf,
+ struct vk_renderer *renderer,
+ struct vk_buf *vbo,
+ uint32_t vk_fb_color_count,
+ float *vk_fb_color,
+ uint32_t num_atts,
+ struct vk_attachment *atts,
+ float x, float y,
+ float w, float h)
+{
+ VkCommandBufferBeginInfo cmd_begin_info;
+ VkRenderPassBeginInfo rp_begin_info;
+ VkRect2D rp_area;
+ VkClearValue *clear_values; int i;
+ VkDeviceSize offsets[] = {0};
+ int num_vertices;
+ struct vk_dims img_size;
+ bool create_cmd_buf = false;
+
+ assert(vk_fb_color_count == 4);
+
+ /* if cmd_buf is null create it */
+ if (!cmd_buf) {
+ if ((cmd_buf = vk_create_cmd_buffer(ctx)) ==
+ VK_NULL_HANDLE) {
+ fprintf(stderr, "Failed to create command buffer.\n");
+ return false;
+ }
+ create_cmd_buf = true;
+ }
+
+ /* VkCommandBufferBeginInfo */
+ memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
+ cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
+
+ /* VkRect2D render area */
+ memset(&rp_area, 0, sizeof rp_area);
+ rp_area.extent.width = (uint32_t)w;
+ rp_area.extent.height = (uint32_t)h;
+ rp_area.offset.x = x;
+ rp_area.offset.y = y;
+
+ /* VkClearValue */
+ clear_values = malloc(num_atts * sizeof clear_values[0]);
+ memset(clear_values, 0, num_atts * sizeof clear_values[0]);
+
+ for (i = 0; i < num_atts - 1; i++) {
+ clear_values[i].color.float32[0] = vk_fb_color[0];
+ clear_values[i].color.float32[1] = vk_fb_color[1];
+ clear_values[i].color.float32[2] = vk_fb_color[2];
+ clear_values[i].color.float32[3] = vk_fb_color[3];
+ }
+ clear_values[num_atts - 1].depthStencil.depth = 1.0f;
+ clear_values[num_atts - 1].depthStencil.stencil = 0;
+
+ /* VkRenderPassBeginInfo */
+ memset(&rp_begin_info, 0, sizeof rp_begin_info);
+ rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ rp_begin_info.renderPass = renderer->renderpass;
+ rp_begin_info.framebuffer = renderer->fb;
+ rp_begin_info.renderArea = rp_area;
+ rp_begin_info.clearValueCount = num_atts;
+ rp_begin_info.pClearValues = clear_values;
+
+ vkBeginCommandBuffer(cmd_buf, &cmd_begin_info);
+ vkCmdBeginRenderPass(cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
+
+ viewport.x = x;
+ viewport.y = y;
+ viewport.width = w;
+ viewport.height = h;
+
+ scissor.offset.x = x;
+ scissor.offset.y = y;
+ scissor.extent.width = w;
+ scissor.extent.height = h;
+
+ vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
+ vkCmdSetScissor(cmd_buf, 0, 1, &scissor);
+
+ img_size.w = (float)w;
+ img_size.h = (float)h;
+ vkCmdPushConstants(cmd_buf,
+ renderer->pipeline_layout,
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ 0, sizeof (struct vk_dims),
+ &img_size);
+
+ if (vbo) {
+ vkCmdBindVertexBuffers(cmd_buf, 0, 1, &vbo->buf, offsets);
+ }
+
+ vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
+
+ num_vertices = vbo ? renderer->vertex_info.num_verts : 4;
+ vkCmdDraw(cmd_buf, num_vertices, 1, 0, 0);
+ vkCmdEndRenderPass(cmd_buf);
+
+ free(clear_values);
+#if 0
+ if (atts) {
+ VkImageMemoryBarrier *barriers =
+ calloc(num_atts, sizeof(VkImageMemoryBarrier));
+ VkImageMemoryBarrier *barrier = barriers;
+ for (uint32_t n = 0; n < num_atts; n++, barrier++) {
+ struct vk_attachment *att = &atts[n];
+ VkImageAspectFlagBits depth_stencil_flags =
+ get_aspect_from_depth_format(att->props.format);
+ bool is_depth = (depth_stencil_flags != 0);
+
+ /* Insert barrier to mark ownership transfer. */
+ barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ barrier->oldLayout = is_depth ?
+ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
+ barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
+ barrier->dstAccessMask = get_access_mask(barrier->newLayout);
+ barrier->srcQueueFamilyIndex = ctx->qfam_idx;
+ barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
+ barrier->image = att->obj.img;
+ barrier->subresourceRange.aspectMask = is_depth ?
+ depth_stencil_flags :
+ VK_IMAGE_ASPECT_COLOR_BIT;
+ barrier->subresourceRange.baseMipLevel = 0;
+ barrier->subresourceRange.levelCount = 1;
+ barrier->subresourceRange.baseArrayLayer = 0;
+ barrier->subresourceRange.layerCount = 1;
+ }
+
+ vkCmdPipelineBarrier(cmd_buf,
+ VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
+ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+ 0,
+ 0, NULL,
+ 0, NULL,
+ num_atts, barriers);
+ free(barriers);
+ }
+#endif
+
+ vkEndCommandBuffer(cmd_buf);
+ if (create_cmd_buf) {
+ vk_destroy_cmd_buffers(ctx, 1, &cmd_buf);
+ }
+ return true;