- VkCommandBufferBeginInfo cmd_begin_info;
- VkRenderPassBeginInfo rp_begin_info;
- VkRect2D rp_area;
- VkClearValue clear_values[2];
- VkSubmitInfo submit_info;
- VkDeviceSize offsets[] = {0};
- VkPipelineStageFlagBits stage_flags;
- struct vk_dims img_size;
-
- assert(vk_fb_color_count == 4);
-
- /* 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 */
- memset(&clear_values[0], 0, sizeof clear_values[0]);
- clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
- clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
- clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
- clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
-
- memset(&clear_values[1], 0, sizeof clear_values[1]);
- clear_values[1].depthStencil.depth = 1.0;
- clear_values[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 = 2;
- rp_begin_info.pClearValues = clear_values;
-
- /* VkSubmitInfo */
- stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
-
- memset(&submit_info, 0, sizeof submit_info);
- submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submit_info.commandBufferCount = 1;
- submit_info.pCommandBuffers = &ctx->cmd_buf;
-
- /* semaphores */
- if (semaphores) {
- assert(semaphores->frame_ready);
- assert(semaphores->frame_done);
-
- submit_info.pWaitDstStageMask = &stage_flags;
- submit_info.waitSemaphoreCount = 1;
- submit_info.pWaitSemaphores = &semaphores->frame_done;
-
- submit_info.signalSemaphoreCount = 1;
- submit_info.pSignalSemaphores = &semaphores->frame_ready;
- }
-
- vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
- vkCmdBeginRenderPass(ctx->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(ctx->cmd_buf, 0, 1, &viewport);
- vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
-
- img_size.w = (float)w;
- img_size.h = (float)h;
- vkCmdPushConstants(ctx->cmd_buf,
- renderer->pipeline_layout,
- VK_SHADER_STAGE_FRAGMENT_BIT,
- 0, sizeof (struct vk_dims),
- &img_size);
-
- if (vbo) {
- vkCmdBindVertexBuffers(ctx->cmd_buf, 0, 1, &vbo->buf, offsets);
- }
- vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
-
- int num_vertices = vbo ? renderer->vertex_info.num_verts : 4;
- vkCmdDraw(ctx->cmd_buf, num_vertices, 1, 0, 0);
-
- if (attachments) {
- VkImageMemoryBarrier *barriers =
- calloc(n_attachments, sizeof(VkImageMemoryBarrier));
- VkImageMemoryBarrier *barrier = barriers;
- for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
- struct vk_image_att *att = &attachments[n];
-
- /* Insert barrier to mark ownership transfer. */
- barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-
- bool is_depth =
- get_aspect_from_depth_format(att->props.format) != VK_NULL_HANDLE;
-
- barrier->oldLayout = is_depth ?
- VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
- barrier->srcQueueFamilyIndex = ctx->qfam_idx;
- barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
- barrier->image = att->obj.img;
- barrier->subresourceRange.aspectMask = is_depth ?
- VK_IMAGE_ASPECT_DEPTH_BIT :
- VK_IMAGE_ASPECT_COLOR_BIT;
- barrier->subresourceRange.baseMipLevel = 0;
- barrier->subresourceRange.levelCount = 1;
- barrier->subresourceRange.baseArrayLayer = 0;
- barrier->subresourceRange.layerCount = 1;
- }
-
- vkCmdPipelineBarrier(ctx->cmd_buf,
- VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
- VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
- 0,
- 0, NULL,
- 0, NULL,
- n_attachments, barriers);
- free(barriers);
- }
-
- vkCmdEndRenderPass(ctx->cmd_buf);
- vkEndCommandBuffer(ctx->cmd_buf);
-
- if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
- fprintf(stderr, "Failed to submit queue.\n");
- }
-
- if (!semaphores)
- vkQueueWaitIdle(ctx->queue);
+ VkCommandBufferBeginInfo cmd_begin_info;
+ VkRenderPassBeginInfo rp_begin_info;
+ VkRect2D rp_area;
+ VkClearValue clear_values[2];
+ VkSubmitInfo submit_info;
+ VkPipelineStageFlagBits stage_flags;
+ VkImageSubresourceRange img_range;
+
+ assert(vk_fb_color_count == 4);
+
+ /* 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_ONE_TIME_SUBMIT_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 */
+ memset(&clear_values[0], 0, sizeof clear_values[0]);
+ clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
+ clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
+ clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
+ clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
+
+ memset(&clear_values[1], 0, sizeof clear_values[1]);
+ clear_values[1].depthStencil.depth = 1.0;
+ clear_values[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 = 2;
+ rp_begin_info.pClearValues = clear_values;
+
+ /* VkSubmitInfo */
+ stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
+
+ memset(&submit_info, 0, sizeof submit_info);
+ submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submit_info.commandBufferCount = 1;
+ submit_info.pCommandBuffers = &ctx->cmd_buf;
+
+ /* FIXME */
+ if (has_wait) {
+ submit_info.pWaitDstStageMask = &stage_flags;
+ submit_info.waitSemaphoreCount = 1;
+ submit_info.pWaitSemaphores = &semaphores->frame_done;
+ }
+
+ if (has_signal) {
+ submit_info.signalSemaphoreCount = 1;
+ submit_info.pSignalSemaphores = &semaphores->frame_ready;
+ }
+
+ img_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ img_range.baseMipLevel = 0;
+ img_range.levelCount = 1;
+ img_range.baseArrayLayer = 0;
+ img_range.layerCount = 1;
+
+ vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
+ vk_transition_image_layout(&attachments[0],
+ ctx->cmd_buf,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_GENERAL,
+ VK_QUEUE_FAMILY_EXTERNAL,
+ ctx->qfam_idx);
+ vkCmdClearColorImage(ctx->cmd_buf,
+ attachments[0].obj.img,
+ VK_IMAGE_LAYOUT_GENERAL,
+ &clear_values[0].color,
+ 1,
+ &img_range);
+
+ vkCmdBeginRenderPass(ctx->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(ctx->cmd_buf, 0, 1, &viewport);
+ vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
+
+ vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
+
+ vkCmdEndRenderPass(ctx->cmd_buf);
+
+ if (attachments) {
+ VkImageMemoryBarrier *barriers =
+ calloc(n_attachments, sizeof(VkImageMemoryBarrier));
+ VkImageMemoryBarrier *barrier = barriers;
+
+ for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
+ struct vk_image_att *att = &attachments[n];
+
+ /* Insert barrier to mark ownership transfer. */
+ barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+
+ bool is_depth =
+ get_aspect_from_depth_format(att->props.format) != VK_NULL_HANDLE;
+
+ 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 ?
+ VK_IMAGE_ASPECT_DEPTH_BIT :
+ VK_IMAGE_ASPECT_COLOR_BIT;
+ barrier->subresourceRange.baseMipLevel = 0;
+ barrier->subresourceRange.levelCount = 1;
+ barrier->subresourceRange.baseArrayLayer = 0;
+ barrier->subresourceRange.layerCount = 1;
+ }
+
+ vkCmdPipelineBarrier(ctx->cmd_buf,
+ VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
+ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+ 0,
+ 0, NULL,
+ 0, NULL,
+ n_attachments, barriers);
+ free(barriers);
+ }
+
+ vkEndCommandBuffer(ctx->cmd_buf);
+
+ if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
+ fprintf(stderr, "Failed to submit queue.\n");
+ }
+
+ if (!semaphores && !has_wait && !has_signal)
+ vkQueueWaitIdle(ctx->queue);
+}
+
+bool
+vk_create_swapchain(struct vk_ctx *ctx,
+ int width, int height,
+ bool has_vsync,
+ VkSurfaceKHR surf,
+ struct vk_swapchain *old_swapchain,
+ struct vk_swapchain *swapchain)
+{
+ VkSurfaceCapabilitiesKHR surf_cap;
+ VkSwapchainCreateInfoKHR s_info;
+ VkExtent2D extent;
+ VkImageSubresourceRange sr;
+ VkImage *s_images;
+ int i;
+
+ if (!sc_validate_surface(ctx, surf)) {
+ fprintf(stderr, "Failed to validate surface!\n");
+ return false;
+ }
+
+ /* get pdevice capabilities
+ * will need that to determine the swapchain number of images
+ */
+ if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(ctx->pdev, surf, &surf_cap) != VK_SUCCESS) {
+ fprintf(stderr, "Failed to query surface capabilities.\n");
+ return false;
+ }
+
+ /* allocate and init an empty struct vk_swapchain */
+ swapchain = malloc(sizeof *swapchain);
+ memset(swapchain, 0, sizeof *swapchain);
+
+ swapchain->surface = surf;
+
+ memset(&s_info, 0, sizeof s_info);
+ s_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+ s_info.flags = 0;
+ /* surface format */
+ if (!sc_select_format(ctx, surf, &s_info)) {
+ fprintf(stderr, "Failed to determine the surface format.\n");
+ return false;
+ }
+ s_info.surface = surf;
+
+ /* number of images */
+ s_info.minImageCount = surf_cap.minImageCount;
+ /* swapchain images dims */
+ {
+ extent.width = width;
+ extent.height = height;
+ }
+ if (!sc_select_supported_present_modes(ctx, surf, has_vsync, &s_info)) {
+ s_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
+ }
+ s_info.imageExtent = extent;
+ s_info.imageArrayLayers = 1;
+ /* enable color attachment bit and transfer src and transfer dst bits
+ * too if they are supported */
+ {
+ s_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
+ s_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
+ s_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ }
+ s_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ s_info.queueFamilyIndexCount = ctx->qfam_idx;
+
+ /* we might want to use this function when we recreate the swapchain too */
+ s_info.preTransform = surf_cap.supportedTransforms &
+ VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ?
+ VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
+ surf_cap.currentTransform;
+
+ /* we could also write a sc_select_supported_composite_alpha
+ * later but VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR is universally
+ * supported */
+ s_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+ s_info.clipped = VK_TRUE;
+ s_info.oldSwapchain = old_swapchain ? old_swapchain->swapchain : 0;
+
+ if (vkCreateSwapchainKHR(ctx->dev, &s_info, 0,
+ &swapchain->swapchain) != VK_SUCCESS) {
+ fprintf(stderr, "Failed to create a swapchain.\n");
+ return false;
+ }
+
+ /* if an existing swapchain is recreated we need to destroy
+ * the old swapchain and clean up the images */
+ if (old_swapchain) {
+ for (i = 0; i < old_swapchain->num_images; i++) {
+ vkDestroyImageView(ctx->dev, old_swapchain->images[i].image_view, 0);
+ }
+ vk_destroy_swapchain(ctx, old_swapchain);
+ }
+
+ /* get the number of swapchain images and the swapchain images
+ * and store the new swapchain images
+ */
+ vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_images, 0);
+ printf("number of swapchain images: %d\n", swapchain->num_images);
+
+ /* create images */
+ s_images = malloc(swapchain->num_images * sizeof(VkImage));
+ vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_images, s_images);
+
+ swapchain->image_fmt = s_info.imageFormat;
+ swapchain->images = malloc(swapchain->num_images * sizeof(struct vk_swap_image_obj));
+
+ memset(&sr, 0, sizeof sr);
+ sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ sr.levelCount = 1;
+ sr.layerCount = 1;
+
+ for (i = 0; i < swapchain->num_images; i++) {
+ swapchain->images[i].image = s_images[i];
+ if (!(create_image_view(ctx,
+ swapchain->images[i].image,
+ VK_IMAGE_VIEW_TYPE_2D,
+ swapchain->image_fmt,
+ sr,
+ true,
+ &swapchain->images[i].image_view))) {
+ fprintf(stderr, "Fail to create an image view from the swapchain image: i=%d\n", i);
+ break;
+ }
+ if (i < swapchain->num_images - 1) {
+ int j;
+ for (j = 0; j < i; j++) {
+ vkDestroyImageView(ctx->dev, swapchain->images[i].image_view, 0);
+ }
+ return false;
+ }
+ }
+
+ free(s_images);
+ return true;
+}
+
+void
+vk_destroy_swapchain(struct vk_ctx *ctx,
+ struct vk_swapchain *swapchain)
+{
+ vkDestroySwapchainKHR(ctx->dev, swapchain->swapchain, 0);
+ vkDestroySurfaceKHR(ctx->inst, swapchain->surface, 0);
+
+ free(swapchain);
+ swapchain = 0;