static VkViewport viewport;
static VkRect2D scissor;
-static bool enable_layers = true;
+static VkPipelineCache pipeline_cache;
+
+/* when I extend the program to use more than one buffers
+ * I might need to store them in this list and access it
+ * using multiple threads
+ *
+ * man realloc
+ */
+#if 0
+static VkCommandBuffer *command_buffers;
+static uint32_t num_command_buffers;
+#endif
/* static functions */
/* VkApplicationInfo */
memset(&app_info, 0, sizeof app_info);
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
- app_info.pApplicationName = "vktest";
+ app_info.pApplicationName = "hikikornd";
app_info.apiVersion = VK_API_VERSION_1_1;
/* VkInstanceCreateInfo */
{
VkCommandPoolCreateInfo cmd_pool_info;
VkCommandPool cmd_pool;
- VkDevice dev = ctx->dev;
memset(&cmd_pool_info, 0, sizeof cmd_pool_info);
cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmd_pool_info.queueFamilyIndex = ctx->qfam_idx;
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- if (vkCreateCommandPool(dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS)
+ if (vkCreateCommandPool(ctx->dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS)
return 0;
return cmd_pool;
}
-static VkRenderPass
-create_renderpass(struct vk_ctx *ctx,
- struct vk_image_props *color_img_props,
- struct vk_image_props *depth_img_props)
+static VkPipelineCache
+create_pipeline_cache(struct vk_ctx *ctx)
{
- uint32_t num_attachments = 2;
- VkAttachmentDescription att_dsc[2];
- VkAttachmentReference att_rfc[2];
- VkSubpassDescription subpass_dsc[1];
- VkRenderPassCreateInfo rpass_info;
-
- /* VkAttachmentDescription */
- memset(att_dsc, 0, num_attachments * sizeof att_dsc[0]);
-
- att_dsc[0].samples = get_num_samples(color_img_props->num_samples);
- att_dsc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- att_dsc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
- att_dsc[0].initialLayout = color_img_props->in_layout;
- att_dsc[0].finalLayout = color_img_props->end_layout;
- att_dsc[0].format = color_img_props->format;
- att_dsc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- att_dsc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ VkPipelineCacheCreateInfo pc_info;
+ VkPipelineCache pcache;
- att_dsc[1].samples = get_num_samples(depth_img_props->num_samples);
+ memset(&pc_info, 0, sizeof pc_info);
+ pc_info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
- /* We might want to reuse a depth buffer */
- if (depth_img_props->in_layout != VK_IMAGE_LAYOUT_UNDEFINED) {
- att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
- att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
- }
- else {
- att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ if (vkCreatePipelineCache(ctx->dev, &pc_info, 0, &pcache) != VK_SUCCESS) {
+ fprintf(stderr, "Failed to create a pipeline cache.\n");
+ return VK_NULL_HANDLE;
}
- att_dsc[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
- att_dsc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
- att_dsc[1].initialLayout = depth_img_props->in_layout;
- att_dsc[1].finalLayout = depth_img_props->end_layout;
- att_dsc[1].format = depth_img_props->format;
+ return pcache;
+}
- /* VkAttachmentReference */
- memset(att_rfc, 0, num_attachments * sizeof att_rfc[0]);
+bool
+vk_create_renderpass(struct vk_ctx *ctx,
+ uint32_t num_color_atts,
+ struct vk_att_props *color_props,
+ struct vk_att_props *depth_props,
+ VkRenderPass *renderpass)
+{
+ VkAttachmentDescription *att_dsc;
+ VkAttachmentReference *att_rfc;
- att_rfc[0].layout = color_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
- att_rfc[0].attachment = 0;
+ /* one subpass for the moment: */
+ VkSubpassDescription subpass_dsc[1];
+ VkSubpassDependency subpass_dep;
+
+ VkRenderPassCreateInfo rpass_info;
- att_rfc[1].layout = depth_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
- att_rfc[1].attachment = 1;
+ int i;
+ uint32_t num_atts = num_color_atts + 1;
+ bool has_layout = depth_props->in_layout != VK_IMAGE_LAYOUT_UNDEFINED;
+
+ att_dsc = malloc(num_atts * sizeof att_dsc[0]);
+ att_rfc = malloc(num_atts * sizeof att_rfc[0]);
+
+ memset(att_dsc, 0, num_atts * sizeof att_dsc[0]);
+ memset(att_rfc, 0, num_atts * sizeof att_rfc[0]);
+
+ /* color attachments description (we can have many) */
+ for (i = 0; i < num_color_atts; i++) {
+ att_dsc[i].samples = get_num_samples(color_props[i].num_samples);
+ att_dsc[i].initialLayout = color_props[i].in_layout;
+ att_dsc[i].finalLayout = color_props[i].end_layout;
+ att_dsc[i].format = color_props[i].format;
+
+ att_dsc[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ att_dsc[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ att_dsc[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ att_dsc[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+
+ att_rfc[i].attachment = i;
+ att_rfc[i].layout = color_props[i].tiling != VK_IMAGE_TILING_OPTIMAL ?
+ VK_IMAGE_LAYOUT_GENERAL :
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ }
+
+ /* depth attachment description (we can have only one) */
+ att_dsc[num_color_atts].samples = get_num_samples(depth_props->num_samples);
+ att_dsc[num_color_atts].initialLayout = depth_props->in_layout;
+ att_dsc[num_color_atts].finalLayout = depth_props->end_layout;
+ att_dsc[num_color_atts].format = depth_props->format;
+ /* we might want to reuse the depth buffer when it's filled */
+ att_dsc[num_color_atts].loadOp = has_layout ?
+ VK_ATTACHMENT_LOAD_OP_LOAD :
+ VK_ATTACHMENT_LOAD_OP_CLEAR;
+ att_dsc[num_color_atts].stencilLoadOp = has_layout ?
+ VK_ATTACHMENT_LOAD_OP_LOAD :
+ VK_ATTACHMENT_LOAD_OP_CLEAR;
+ att_dsc[num_color_atts].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+ att_rfc[num_color_atts].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ att_rfc[num_color_atts].attachment = num_color_atts;
/* VkSubpassDescription */
memset(&subpass_dsc, 0, sizeof subpass_dsc);
subpass_dsc[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
- subpass_dsc[0].colorAttachmentCount = 1;
+ subpass_dsc[0].colorAttachmentCount = num_color_atts;
subpass_dsc[0].pColorAttachments = &att_rfc[0];
- subpass_dsc[0].pDepthStencilAttachment = &att_rfc[1];
+ subpass_dsc[0].pDepthStencilAttachment = &att_rfc[num_color_atts];
+
+ /* The subpasses in a render pass automatically take care of
+ * image layout transitions. These transitions are controlled
+ * by subpass dependencies, which specify memory and execution
+ * dependencies between subpasses. We have only a single subpass
+ * right now, but the operations right before and right after
+ * this subpass also count as implicit "subpasses". There are two
+ * built-in dependencies that take care of the transition at the
+ * start of the render pass and at the end of the render pass,
+ * but the former does not occur at the right time. It assumes
+ * that the transition occurs at the start of the pipeline,
+ * but we haven't acquired the image yet at that point! There are
+ * two ways to deal with this problem.
+ *
+ * We could change the waitStages for the frame_ready semaphore
+ * to VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT to ensure that the render
+ * passes don't begin until the image is available, or we can make
+ * the render pass wait for the
+ * VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT stage.
+ */
+
+ /* VkSubpassDependency */
+ memset(&subpass_dep, 0, sizeof subpass_dep);
+ subpass_dep.srcSubpass = VK_SUBPASS_EXTERNAL;
+ subpass_dep.dstSubpass = 0;
+ subpass_dep.srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ subpass_dep.srcAccessMask = 0;
+ subpass_dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ subpass_dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
/* VkRenderPassCreateInfo */
memset(&rpass_info, 0, sizeof rpass_info);
rpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- rpass_info.attachmentCount = num_attachments;
+ rpass_info.attachmentCount = num_atts;
rpass_info.pAttachments = att_dsc;
rpass_info.subpassCount = 1;
rpass_info.pSubpasses = subpass_dsc;
+ rpass_info.dependencyCount = 1;
+ rpass_info.pDependencies = &subpass_dep;
- VkRenderPass rpass;
- if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, &rpass) != VK_SUCCESS) {
+ if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, renderpass) != VK_SUCCESS) {
fprintf(stderr, "Failed to create renderpass.\n");
- rpass = VK_NULL_HANDLE;
+ *renderpass = VK_NULL_HANDLE;
+
+ free(att_dsc);
+ free(att_rfc);
+
+ return false;
}
- return rpass;
+ free(att_dsc);
+ free(att_rfc);
+
+ return true;
}
static inline VkImageType
return VK_IMAGE_TYPE_2D;
}
+#if 0
static VkImageViewType
-get_image_view_type(struct vk_image_props *props)
+get_image_view_type(struct vk_att_props *props)
{
VkImageType type = get_image_type(props->h, props->depth);
switch(type) {
return VK_IMAGE_VIEW_TYPE_2D;
}
}
+#endif
static VkImageAspectFlagBits
get_aspect_from_depth_format(VkFormat depth_format)
return 0;
}
+#if 0
static bool
-create_image_view(struct vk_ctx *ctx,
- VkImage image,
- VkImageViewType view_type,
- VkFormat format,
- VkImageSubresourceRange sr,
- bool is_swapchain,
- VkImageView *image_view)
+create_attachment_views(struct vk_ctx *ctx, int num_color_att,
+ struct vk_attachment *color_att,
+ struct vk_attachment *depth_att)
{
- VkImageViewCreateInfo info;
-
- memset(&info, 0, sizeof info);
- info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- info.image = image;
- info.viewType = view_type;
- info.viewType = VK_IMAGE_VIEW_TYPE_2D;
- info.format = format;
- info.subresourceRange = sr;
+ VkImageSubresourceRange sr;
+ int i;
- if (is_swapchain) {
- info.components.r = VK_COMPONENT_SWIZZLE_R;
- info.components.g = VK_COMPONENT_SWIZZLE_G;
- info.components.b = VK_COMPONENT_SWIZZLE_B;
- info.components.a = VK_COMPONENT_SWIZZLE_A;
- }
+ vk_create_image_view(ctx, depth_att->obj.img, VK_IMAGE_VIEW_TYPE_2D,
+ depth_att->props.format, false,
+ &depth_att->obj.img_view);
- if (vkCreateImageView(ctx->dev, &info, 0, image_view) != VK_SUCCESS) {
- fprintf(stderr, "Failed to create image view.\n");
- image_view = VK_NULL_HANDLE;
+ memset(&sr, 0, sizeof sr);
+ sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- return false;
+ for (i = 0; i < num_color_att; i++) {
+ vk_create_image_view(ctx, color_att[i].obj.img, VK_IMAGE_VIEW_TYPE_2D,
+ color_att[i].props.format,
+ color_att[i].props.is_swapchain,
+ &color_att[i].obj.img_view);
}
return true;
}
-static void
-create_framebuffer(struct vk_ctx *ctx,
- struct vk_image_att *color_att,
- struct vk_image_att *depth_att,
- struct vk_renderer *renderer)
+static bool
+create_framebuffer_from_attachments(struct vk_ctx *ctx,
+ int width, int height,
+ int num_color_atts,
+ struct vk_attachment *color_att,
+ struct vk_attachment *depth_att,
+ struct vk_renderer *renderer)
{
- VkImageSubresourceRange sr;
VkFramebufferCreateInfo fb_info;
- VkImageView atts[2];
- VkImageViewType view_type = get_image_view_type(&color_att->props);
-
- if (!color_att->obj.img || !depth_att->obj.img) {
- fprintf(stderr, "Invalid framebuffer attachment image.\n");
- goto fail;
- }
-
- /* create image views */
+ VkImageView *atts;
+ int i;
+ int num_atts = num_color_atts + 1;
- /* VKImageSubresourceRange */
- memset(&sr, 0, sizeof sr);
- sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- /* If an application wants to use all mip levels
- * or layers in an image after the baseMipLevel
- * or baseArrayLayer, it can set levelCount and
- * layerCount to the special values
- * VK_REMAINING_MIP_LEVELS and
- * VK_REMAINING_ARRAY_LAYERS without knowing the
- * exact number of mip levels or layers.
- */
- sr.baseMipLevel = 0;
- sr.levelCount = color_att->props.num_levels;
- sr.baseArrayLayer = 0;
- sr.layerCount = color_att->props.num_layers;
-
- /* color view */
- if (!create_image_view(ctx, color_att->obj.img, view_type, color_att->props.format, sr, false, &color_att->obj.img_view)) {
- fprintf(stderr, "Failed to create color image view for framebuffer.\n");
- vk_destroy_image(ctx, &color_att->obj);
- goto fail;
- }
+ atts = malloc(num_atts * sizeof atts[0]);
- /* depth view */
- memset(&sr, 0, sizeof sr);
- sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format);
- sr.baseMipLevel = 0;
- sr.levelCount = depth_att->props.num_levels ? depth_att->props.num_levels : 1;
- sr.baseArrayLayer = 0;
- sr.layerCount = depth_att->props.num_layers ? depth_att->props.num_layers : 1;
-
- if (!create_image_view(ctx, depth_att->obj.img,
- depth_att->props.num_layers > 1 ?
- VK_IMAGE_VIEW_TYPE_2D_ARRAY :
- VK_IMAGE_VIEW_TYPE_2D,
- depth_att->props.format,
- sr,
- false,
- &depth_att->obj.img_view)) {
- fprintf(stderr, "Failed to create depth image view for framebuffer.\n");
- vk_destroy_image(ctx, &depth_att->obj);
- goto fail;
+ for (i = 0; i < num_color_atts; i++) {
+ atts[i] = color_att[i].obj.img_view;
}
-
- atts[0] = color_att->obj.img_view;
- atts[1] = depth_att->obj.img_view;
+ atts[num_color_atts] = depth_att->obj.img_view;
memset(&fb_info, 0, sizeof fb_info);
fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fb_info.renderPass = renderer->renderpass;
- fb_info.width = color_att->props.w;
- fb_info.height = color_att->props.h;
- fb_info.layers = color_att->props.num_layers ? color_att->props.num_layers : 1;
- fb_info.attachmentCount = 2;
+ fb_info.width = width;
+ fb_info.height = height;
+ fb_info.layers = 1;
+ fb_info.attachmentCount = num_atts;
fb_info.pAttachments = atts;
- if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS)
- goto fail;
+ if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS) {
+ fprintf(stderr, "Failed to create framebuffer.\n");
+ free(atts);
+ renderer->fb = VK_NULL_HANDLE;
- return;
+ return false;
+ }
-fail:
- fprintf(stderr, "Failed to create framebuffer.\n");
- renderer->fb = VK_NULL_HANDLE;
+ free(atts);
+ return true;
}
+#endif
static VkShaderModule
create_shader_module(struct vk_ctx *ctx,
- const char *src,
- unsigned int size)
+ const char *src,
+ unsigned int size)
{
VkShaderModuleCreateInfo sm_info;
VkShaderModule sm;
}
static void
-create_pipeline(struct vk_ctx *ctx,
- uint32_t width,
- uint32_t height,
- uint32_t num_samples,
- bool enable_depth,
- bool enable_stencil,
- struct vk_renderer *renderer)
+create_vertex_descriptions(struct vk_ctx *ctx,
+ struct vk_geometry *geometry,
+ int num_bind_dsc,
+ VkVertexInputBindingDescription *bind_dsc,
+ int num_att_dsc,
+ VkVertexInputAttributeDescription *att_dsc)
{
- VkVertexInputBindingDescription vert_bind_dsc[1];
- VkVertexInputAttributeDescription vert_att_dsc[1];
+ VkFormat format;
+ VkFormatProperties fmt_props;
+ uint32_t stride;
+
+ assert(num_bind_dsc == num_att_dsc);
+
+ memset(bind_dsc, 0, num_bind_dsc * sizeof bind_dsc[0]);
+ memset(att_dsc, 0, num_att_dsc * sizeof att_dsc[0]);
+
+ /* FIXME!!! format and stride!!
+ * We have 3D Vectors so we need an RGB format:
+ * R for x, G for y, B for z
+ * If we need to set the w we need an RGBA format!
+ * the stride (distance between 2 consecutive elements
+ * must be 8 as we use 32bits floats and 32bits = 8bytes
+ */
+ format = VK_FORMAT_R32G32B32_SFLOAT;
+ vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props);
+ assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
+ stride = 8;
+
+ /* Assumming that:
+ * 0 = vertices
+ * 1 = indices
+ * 2 = normals
+ * 3 = tangets
+ */
+
+ if (geometry->vertices.num_vertices) {
+ att_dsc[0].location = VERTEX_LOC;
+ att_dsc[0].binding = VERTEX_BIND;
+ att_dsc[0].format = format;
+ att_dsc[0].offset = 0;
+
+ bind_dsc[0].binding = VERTEX_BIND;
+ bind_dsc[0].stride = stride;
+ bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+ }
+
+ if (geometry->indices.num_vertices) {
+ }
+
+ if (geometry->normals.num_vertices) {
+ }
+
+ if (geometry->tangents.num_vertices) {
+ }
+}
- VkPipelineColorBlendAttachmentState cb_att_state[1];
+static bool
+create_graphics_pipeline(struct vk_ctx *ctx,
+ uint32_t width,
+ uint32_t height,
+ uint32_t num_samples,
+ uint32_t num_color_atts,
+ bool enable_depth,
+ bool enable_stencil,
+ struct vk_renderer *renderer)
+{
+ VkVertexInputBindingDescription vert_bind_dsc[4];
+ VkVertexInputAttributeDescription vert_att_dsc[4];
+
+ VkPipelineColorBlendAttachmentState *cb_att_state;
VkPipelineVertexInputStateCreateInfo vert_input_info;
VkPipelineInputAssemblyStateCreateInfo asm_info;
VkPipelineViewportStateCreateInfo viewport_info;
VkPipelineLayout pipeline_layout;
uint32_t stride;
+ /* FIXME */
/* format of vertex attributes:
* we have 2D vectors so we need a RG format:
* R for x, G for y
assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
stride = 8;
+ // create_vertex_descriptions(ctx, renderer->geometry, 1, vert_bind_dsc, 1, vert_att_dsc);
+ memset(vert_att_dsc, 0, 4 * sizeof vert_att_dsc[0]);
+ memset(vert_bind_dsc, 0, 4 * sizeof vert_bind_dsc[0]);
+
/* VkVertexInputAttributeDescription */
- memset(&vert_att_dsc, 0, sizeof vert_att_dsc);
vert_att_dsc[0].location = 0;
vert_att_dsc[0].binding = 0;
vert_att_dsc[0].format = format; /* see comment */
vert_att_dsc[0].offset = 0;
/* VkVertexInputBindingDescription */
- memset(&vert_bind_dsc, 0, sizeof vert_bind_dsc);
vert_bind_dsc[0].binding = 0;
vert_bind_dsc[0].stride = stride;
vert_bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
/* If using vbo, we have setup vertex_info in the renderer. */
- bool use_vbo = renderer->vertex_info.num_verts > 0;
+ bool has_geometry = renderer->geometry;
/* VkPipelineVertexInputStateCreateInfo */
memset(&vert_input_info, 0, sizeof vert_input_info);
vert_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
- vert_input_info.vertexBindingDescriptionCount = use_vbo ? 1 : 0;
+ vert_input_info.vertexBindingDescriptionCount = renderer->geometry ? 1 : 0;
vert_input_info.pVertexBindingDescriptions = vert_bind_dsc;
- vert_input_info.vertexAttributeDescriptionCount = use_vbo ? 1 : 0;
+ vert_input_info.vertexAttributeDescriptionCount = renderer->geometry ? 1 : 0;
vert_input_info.pVertexAttributeDescriptions = vert_att_dsc;
/* VkPipelineInputAssemblyStateCreateInfo */
memset(&asm_info, 0, sizeof asm_info);
asm_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
- asm_info.topology = renderer->vertex_info.topology ?
- renderer->vertex_info.topology
+ asm_info.topology = has_geometry ?
+ renderer->geometry->topo
: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
asm_info.primitiveRestartEnable = false;
/* VkPipelineMultisampleStateCreateInfo */
memset(&ms_info, 0, sizeof ms_info);
ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
- ms_info.rasterizationSamples = num_samples;
+ ms_info.rasterizationSamples = get_num_samples(num_samples);
/* VkStencilOpState */
/* The default values for ES are taken by Topi Pohjolainen's code */
ds_info.front = ds_info.back;
/* VkPipelineColorBlendAttachmentState */
- memset(&cb_att_state[0], 0, sizeof cb_att_state[0]);
- cb_att_state[0].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT |
- VK_COLOR_COMPONENT_G_BIT |
- VK_COLOR_COMPONENT_B_BIT |
- VK_COLOR_COMPONENT_A_BIT);
+ cb_att_state = malloc(num_color_atts * sizeof cb_att_state[0]);
+ if (!cb_att_state) {
+ fprintf(stderr, "Failed to allocate color blend attachment state for each attachment.\n");
+ goto fail;
+ }
+ memset(cb_att_state, 0, num_color_atts * sizeof cb_att_state[0]);
+ for (i = 0; i < num_color_atts; i++) {
+ cb_att_state[i].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT |
+ VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT |
+ VK_COLOR_COMPONENT_A_BIT);
+ }
/* VkPipelineColorBlendStateCreateInfo */
memset(&cb_info, 0, sizeof cb_info);
cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
- cb_info.attachmentCount = 1;
+ cb_info.attachmentCount = num_color_atts;
cb_info.pAttachments = cb_att_state;
/* default in ES 3.1 */
for (i = 0; i < 4; i++) {
layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = pc_range;
- if (vkCreatePipelineLayout(ctx->dev, &layout_info, 0, &pipeline_layout) != VK_SUCCESS) {
+ if (vkCreatePipelineLayout(ctx->dev, &layout_info,
+ 0, &pipeline_layout) != VK_SUCCESS) {
fprintf(stderr, "Failed to create pipeline layout\n");
renderer->pipeline = VK_NULL_HANDLE;
- return;
+ goto fail;
}
renderer->pipeline_layout = pipeline_layout;
&renderer->pipeline) != VK_SUCCESS) {
fprintf(stderr, "Failed to create graphics pipeline.\n");
renderer->pipeline = VK_NULL_HANDLE;
+ goto fail;
}
-}
-
-static VkCommandBuffer
-create_cmd_buf(VkDevice dev, VkCommandPool cmd_pool)
-{
- 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 = cmd_pool;
- if (vkAllocateCommandBuffers(dev, &alloc_info, &cmd_buf) != VK_SUCCESS)
- return 0;
+ free(cb_att_state);
+ return true;
- return cmd_buf;
+fail:
+ free(cb_att_state);
+ return false;
}
static uint32_t
memset(&mem_alloc_info, 0, sizeof mem_alloc_info);
mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
- mem_alloc_info.pNext = &exp_mem_info;
+ mem_alloc_info.pNext = is_external ? &exp_mem_info : VK_NULL_HANDLE;
mem_alloc_info.allocationSize = mem_reqs->size;
- mem_alloc_info.memoryTypeIndex =
- get_memory_type_idx(ctx->pdev, mem_reqs, prop_flags);
+ mem_alloc_info.memoryTypeIndex = get_memory_type_idx(ctx->pdev,
+ mem_reqs,
+ prop_flags);
if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) {
fprintf(stderr, "No suitable memory type index found.\n");
}
static bool
-alloc_image_memory(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
+alloc_image_memory(struct vk_ctx *ctx,
+ bool is_external,
+ struct vk_image_obj *img_obj)
{
VkMemoryDedicatedRequirements ded_reqs;
VkImageMemoryRequirementsInfo2 req_info2;
vkGetImageMemoryRequirements2(ctx->dev, &req_info2, &mem_reqs2);
img_obj->mobj.mem = alloc_memory(ctx,
- true, /* is_external = FIXME */
+ is_external,
&mem_reqs2.memoryRequirements,
ded_reqs.requiresDedicatedAllocation ?
img_obj->img : VK_NULL_HANDLE,
VK_NULL_HANDLE,
mem_reqs2.memoryRequirements.memoryTypeBits &
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
img_obj->mobj.mem_sz = mem_reqs2.memoryRequirements.size;
img_obj->mobj.dedicated = ded_reqs.requiresDedicatedAllocation;
}
static bool
-are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props)
+are_props_supported(struct vk_ctx *ctx, struct vk_att_props *props)
{
VkPhysicalDeviceExternalImageFormatInfo ext_img_fmt_info;
VkExternalImageFormatProperties ext_img_fmt_props;
int i;
VkPhysicalDeviceImageFormatInfo2 img_fmt_info;
VkImageFormatProperties2 img_fmt_props;
+
VkImageUsageFlagBits all_flags[] = {
VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
VK_IMAGE_USAGE_TRANSFER_DST_BIT,
};
VkImageUsageFlagBits flags = 0;
- VkExternalMemoryFeatureFlagBits export_feature_flags =
- VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
- VkExternalMemoryHandleTypeFlagBits handle_type =
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+ VkExternalMemoryFeatureFlagBits export_feature_flags = props->need_export ?
+ VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT : 0;
+ VkExternalMemoryHandleTypeFlagBits handle_type = props->need_export ?
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR : 0;
- memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info);
- ext_img_fmt_info.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
- ext_img_fmt_info.handleType = handle_type;
+ if (props->need_export) {
+ memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info);
+ ext_img_fmt_info.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
+ ext_img_fmt_info.handleType = handle_type;
- memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props);
- ext_img_fmt_props.sType =
- VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
+ memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props);
+ ext_img_fmt_props.sType =
+ VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
+ }
memset(&img_fmt_props, 0, sizeof img_fmt_props);
img_fmt_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
- img_fmt_props.pNext = &ext_img_fmt_props;
+ img_fmt_props.pNext = props->need_export ? &ext_img_fmt_props : 0;
memset(&img_fmt_info, 0, sizeof img_fmt_info);
img_fmt_info.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
- img_fmt_info.pNext = &ext_img_fmt_info;
+ img_fmt_info.pNext = props->need_export ? &ext_img_fmt_info : 0;
img_fmt_info.format = props->format;
- img_fmt_info.type = get_image_type(props->h, props->depth);
+ img_fmt_info.type = VK_IMAGE_TYPE_2D;
img_fmt_info.tiling = props->tiling;
for (i = 0; i < ARRAY_SIZE(all_flags); i++) {
img_fmt_info.usage = all_flags[i];
if (vkGetPhysicalDeviceImageFormatProperties2(ctx->pdev,
- &img_fmt_info,
- &img_fmt_props) == VK_SUCCESS) {
+ &img_fmt_info,
+ &img_fmt_props) == VK_SUCCESS) {
flags |= all_flags[i];
}
}
/* usage can't be null */
if (flags) {
img_fmt_info.usage = flags;
- }
- else {
- fprintf(stderr, "Unsupported Vulkan format properties: usage.\n");
- return false;
+ } else {
+ if (!props->is_swapchain) {
+ fprintf(stderr, "Unsupported Vulkan format properties: usage.\n");
+ return false;
+ }
+ img_fmt_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
if (vkGetPhysicalDeviceImageFormatProperties2
static bool
sc_validate_surface(struct vk_ctx *ctx,
- VkSurfaceKHR surf)
+ VkSurfaceKHR surf)
{
VkBool32 supported;
if (!surf) {
return false;
}
- if(vkGetPhysicalDeviceSurfaceSupportKHR(ctx->pdev, ctx->qfam_idx, surf, &supported) != VK_SUCCESS) {
+ if(vkGetPhysicalDeviceSurfaceSupportKHR(ctx->pdev, ctx->qfam_idx,
+ surf, &supported) != VK_SUCCESS) {
fprintf(stderr, "Failed to validate surface.\n");
return false;
}
VkSurfaceFormatKHR *formats;
uint32_t num_formats;
- if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, 0) != VK_SUCCESS) {
+ if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev,
+ surf,
+ &num_formats, 0) != VK_SUCCESS) {
fprintf(stderr, "Failed to get the number of surface formats.\n");
return false;
}
formats = malloc(num_formats * sizeof *formats);
- if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, formats) != VK_SUCCESS) {
+ if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats,
+ formats) != VK_SUCCESS) {
fprintf(stderr, "Failed to get the supported surface formats.\n");
return false;
}
{
VkPresentModeKHR *present_modes;
uint32_t num_present_modes;
- int i;
/* find supported present modes */
- if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, 0) != VK_SUCCESS || !num_present_modes) {
+ if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf,
+ &num_present_modes, 0) != VK_SUCCESS || !num_present_modes) {
fprintf(stderr, "Failed to get the number of the supported presentation modes.\n");
return false;
}
present_modes = malloc(num_present_modes * sizeof *present_modes);
- if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, present_modes) != VK_SUCCESS) {
+ if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf,
+ &num_present_modes,
+ present_modes) != VK_SUCCESS) {
fprintf(stderr, "Failed to get the number of supported presentation modes.\n");
return false;
}
- if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes,
+ if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf,
+ &num_present_modes,
present_modes) != VK_SUCCESS) {
fprintf(stderr, "Failed to get the supported presentation modes.\n");
return false;
}
s_info->presentMode = VK_PRESENT_MODE_FIFO_KHR;
+#if 0
if (!has_vsync) {
for (i = 0; i < num_present_modes; i++) {
if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
s_info->presentMode = present_modes[i];
- goto success;
+ break;
}
if (present_modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) {
s_info->presentMode = present_modes[i];
- goto success;
+ break;
}
}
}
+#endif
-success:
free(present_modes);
return true;
}
/* exposed Vulkan functions */
bool
-vk_init_ctx(struct vk_ctx *ctx)
+vk_init_ctx(struct vk_ctx *ctx,
+ bool enable_layers)
{
if ((ctx->inst = create_instance(enable_layers)) == VK_NULL_HANDLE) {
fprintf(stderr, "Failed to create Vulkan instance.\n");
}
bool
-vk_init_ctx_for_rendering(struct vk_ctx *ctx)
+vk_init_ctx_for_rendering(struct vk_ctx *ctx,
+ bool enable_cache,
+ bool enable_layers)
{
- if (!vk_init_ctx(ctx)) {
+ if (!vk_init_ctx(ctx, enable_layers)) {
fprintf(stderr, "Failed to initialize Vulkan.\n");
return false;
}
goto fail;
}
- if ((ctx->cmd_buf = create_cmd_buf(ctx->dev, ctx->cmd_pool)) ==
- VK_NULL_HANDLE) {
- fprintf(stderr, "Failed to create command buffer.\n");
- goto fail;
- }
-
vkGetDeviceQueue(ctx->dev, ctx->qfam_idx, 0, &ctx->queue);
if (!ctx->queue) {
fprintf(stderr, "Failed to get command queue.\n");
goto fail;
}
+ if (enable_cache) {
+ if (!(pipeline_cache = create_pipeline_cache(ctx))) {
+ fprintf(stderr, "Failed to create pipeline cache.\n");
+ goto fail;
+ }
+ }
+
return true;
fail:
}
void
-vk_cleanup_ctx(struct vk_ctx *ctx)
+vk_destroy_cmd_buffers(struct vk_ctx *ctx,
+ uint32_t num_buffers,
+ VkCommandBuffer *buffers)
{
- if (enable_layers) {
- return;
- }
-
- if (ctx->cmd_buf != VK_NULL_HANDLE) {
- vkResetCommandBuffer(ctx->cmd_buf,
+ int i;
+ for (i = 0; i < num_buffers; i++) {
+ vkResetCommandBuffer(buffers[i],
VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
- vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, 1, &ctx->cmd_buf);
- ctx->cmd_buf = VK_NULL_HANDLE;
}
+ vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, num_buffers, buffers);
+}
+void
+vk_cleanup_ctx(struct vk_ctx *ctx)
+{
if (ctx->cmd_pool != VK_NULL_HANDLE) {
vkResetCommandPool(ctx->dev, ctx->cmd_pool,
VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
ctx->cmd_pool = VK_NULL_HANDLE;
}
+ if (pipeline_cache != VK_NULL_HANDLE) {
+ vkDestroyPipelineCache(ctx->dev, pipeline_cache, 0);
+ pipeline_cache = VK_NULL_HANDLE;
+ }
+
if (ctx->dev != VK_NULL_HANDLE) {
vkDestroyDevice(ctx->dev, 0);
ctx->dev = VK_NULL_HANDLE;
}
bool
-vk_create_image(struct vk_ctx *ctx,
- struct vk_image_props *props,
- struct vk_image_obj *img)
+vk_create_ext_image(struct vk_ctx *ctx,
+ struct vk_att_props *props,
+ struct vk_image_obj *img)
{
+ VkExternalMemoryImageCreateInfo ext_img_info;
VkImageCreateInfo img_info;
+ memset(&ext_img_info, 0, sizeof ext_img_info);
+ ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
+ ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+
memset(&img_info, 0, sizeof img_info);
img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- img_info.pNext = 0; /* do something if external */
+ img_info.pNext = &ext_img_info;
img_info.imageType = get_image_type(props->h, props->depth);
img_info.format = props->format;
img_info.extent.width = props->w;
props->num_layers : VK_SAMPLE_COUNT_1_BIT;
img_info.samples = get_num_samples(props->num_samples);
img_info.tiling = props->tiling;
- img_info.usage = props->usage ?
- props->usage : VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ img_info.usage = props->usage;
img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ /* issue 17 of EXT_external_objects
+ * Required in OpenGL implementations that support
+ * ARB_texture_view, OES_texture_view, EXT_texture_view,
+ * or OpenGL 4.3 and above.
+ */
+ img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
goto fail;
- if(!alloc_image_memory(ctx, img))
+ if(!alloc_image_memory(ctx, true, img))
goto fail;
return true;
return false;
}
-void
-vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
-{
- if (img_obj->img != VK_NULL_HANDLE) {
- vkDestroyImage(ctx->dev, img_obj->img, 0);
- img_obj->img = VK_NULL_HANDLE;
- }
-
- if (img_obj->mobj.mem != VK_NULL_HANDLE) {
- vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0);
- img_obj->mobj.mem = VK_NULL_HANDLE;
- }
-}
-
bool
-vk_create_ext_image(struct vk_ctx *ctx,
- struct vk_image_props *props, struct vk_image_obj *img)
+vk_create_image(struct vk_ctx *ctx,
+ struct vk_att_props *props,
+ struct vk_image_obj *img)
{
- VkExternalMemoryImageCreateInfo ext_img_info;
VkImageCreateInfo img_info;
- memset(&ext_img_info, 0, sizeof ext_img_info);
- ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
- ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
-
memset(&img_info, 0, sizeof img_info);
img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- img_info.pNext = &ext_img_info;
+ img_info.pNext = 0; /* do something if external */
img_info.imageType = get_image_type(props->h, props->depth);
img_info.format = props->format;
img_info.extent.width = props->w;
img_info.extent.height = props->h;
img_info.extent.depth = props->depth;
img_info.mipLevels = props->num_levels ? props->num_levels : 1;
- img_info.arrayLayers = props->num_layers ? props->num_layers : VK_SAMPLE_COUNT_1_BIT;
+ img_info.arrayLayers = props->num_layers ?
+ props->num_layers : VK_SAMPLE_COUNT_1_BIT;
img_info.samples = get_num_samples(props->num_samples);
img_info.tiling = props->tiling;
- img_info.usage = props->usage;
- img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ img_info.usage = props->usage ?
+ props->usage : VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ img_info.initialLayout = props->in_layout;
img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- /* issue 17 of EXT_external_objects
- * Required in OpenGL implementations that support
- * ARB_texture_view, OES_texture_view, EXT_texture_view,
- * or OpenGL 4.3 and above.
- */
- img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
goto fail;
- if(!alloc_image_memory(ctx, img))
+ if(!alloc_image_memory(ctx, props->need_export, img))
goto fail;
return true;
}
bool
-vk_fill_ext_image_props(struct vk_ctx *ctx,
- uint32_t w,
- uint32_t h,
- uint32_t d,
- uint32_t num_samples,
- uint32_t num_levels,
- uint32_t num_layers,
- VkFormat format,
- VkImageTiling tiling,
- VkImageLayout in_layout,
- VkImageLayout end_layout,
- bool need_export,
- struct vk_image_props *props)
+vk_create_image_view(struct vk_ctx *ctx,
+ VkImage image,
+ VkImageViewType view_type,
+ VkFormat format,
+ bool is_swapchain,
+ VkImageView *image_view)
+{
+ VkImageViewCreateInfo info;
+ VkImageSubresourceRange sr;
+ VkImageAspectFlagBits aspect = get_aspect_from_depth_format(format);
+
+ /* VkSubresourceRange */
+ memset(&sr, 0, sizeof sr);
+ sr.aspectMask = aspect ? aspect : VK_IMAGE_ASPECT_COLOR_BIT;
+ sr.levelCount = 1;
+ sr.layerCount = 1;
+
+ memset(&info, 0, sizeof info);
+ info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ info.image = image;
+ info.viewType = view_type;
+ info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ info.format = format;
+ info.subresourceRange = sr;
+
+ if (is_swapchain) {
+ info.components.r = VK_COMPONENT_SWIZZLE_R;
+ info.components.g = VK_COMPONENT_SWIZZLE_G;
+ info.components.b = VK_COMPONENT_SWIZZLE_B;
+ info.components.a = VK_COMPONENT_SWIZZLE_A;
+ }
+
+ if (vkCreateImageView(ctx->dev, &info, 0, image_view) != VK_SUCCESS) {
+ fprintf(stderr, "Failed to create image view.\n");
+ image_view = VK_NULL_HANDLE;
+
+ return false;
+ }
+
+ return true;
+}
+
+void
+vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
+{
+ if (img_obj->img != VK_NULL_HANDLE) {
+ vkDestroyImage(ctx->dev, img_obj->img, 0);
+ img_obj->img = VK_NULL_HANDLE;
+ }
+
+ if (img_obj->mobj.mem != VK_NULL_HANDLE) {
+ vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0);
+ img_obj->mobj.mem = VK_NULL_HANDLE;
+ }
+}
+
+bool
+vk_fill_image_props(struct vk_ctx *ctx,
+ uint32_t w,
+ uint32_t h,
+ uint32_t d,
+ uint32_t num_samples,
+ uint32_t num_levels,
+ uint32_t num_layers,
+ VkFormat format,
+ VkImageTiling tiling,
+ VkImageLayout in_layout,
+ VkImageLayout end_layout,
+ bool is_swapchain,
+ bool is_depth,
+ bool need_export,
+ struct vk_att_props *props)
{
props->w = w;
props->h = h;
props->in_layout = in_layout;
props->end_layout = end_layout;
+
+ props->is_swapchain = is_swapchain;
+ props->is_depth = is_depth;
props->need_export = need_export;
if (!are_props_supported(ctx, props))
return true;
}
+struct vk_attachment
+vk_create_attachment_from_obj(struct vk_image_obj *obj,
+ struct vk_att_props *props)
+{
+ struct vk_attachment att;
+
+ att.obj = *obj;
+ att.props = *props;
+
+ return att;
+}
+
+struct vk_attachment
+vk_create_attachment(VkImage image,
+ VkImageView view,
+ struct vk_att_props *props)
+{
+ struct vk_attachment att;
+
+ att.obj.img = image;
+ att.obj.img_view = view;
+ att.props = *props;
+
+ memset(&att.obj.mobj, 0, sizeof att.obj.mobj);
+
+ return att;
+}
+
+bool
+vk_create_framebuffer(struct vk_ctx *ctx,
+ int width, int height,
+ int num_color_atts,
+ VkImageView *color_views,
+ VkImageView *depth_view,
+ VkRenderPass rpass,
+ VkFramebuffer *fb)
+{
+ VkFramebufferCreateInfo fb_info;
+ VkImageView *atts;
+ int i;
+ int num_atts = num_color_atts + 1;
+
+ atts = malloc(num_atts * sizeof atts[0]);
+ for (i = 0; i < num_color_atts; i++) {
+ atts[i] = color_views[i];
+ }
+ atts[num_color_atts] = *depth_view;
+
+ memset(&fb_info, 0, sizeof fb_info);
+ fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ fb_info.renderPass = rpass;
+ fb_info.width = width;
+ fb_info.height = height;
+ fb_info.layers = 1;
+ fb_info.attachmentCount = num_atts;
+ fb_info.pAttachments = atts;
+
+ if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, fb) != VK_SUCCESS) {
+ fprintf(stderr, "Failed to create framebuffer.\n");
+
+ fb = VK_NULL_HANDLE;
+ free(atts);
+
+ return false;
+ }
+
+ free(atts);
+ return true;
+}
+
bool
vk_create_renderer(struct vk_ctx *ctx,
const char *vs_src,
unsigned int vs_size,
const char *fs_src,
unsigned int fs_size,
+ int w, int h,
+ uint32_t num_samples,
bool enable_depth,
bool enable_stencil,
- struct vk_image_att *color_att,
- struct vk_image_att *depth_att,
- struct vk_vertex_info *vert_info,
+ int num_color_att,
+ struct vk_att_props *color_props,
+ struct vk_att_props *depth_props,
+ struct vk_geometry *geometry,
struct vk_renderer *renderer)
{
- memset(&renderer->vertex_info, 0, sizeof renderer->vertex_info);
- if (vert_info)
- renderer->vertex_info = *vert_info;
-
- if (!color_att || depth_att) {
- fprintf(stderr, "Empty attachment.\n");
+ /* create image views for each attachment */
+#if 0
+ if (!create_attachment_views(ctx, num_color_att, color_att, depth_att))
goto fail;
- }
+#endif
- renderer->renderpass = create_renderpass(ctx, &color_att->props,
- &depth_att->props);
- if (renderer->renderpass == VK_NULL_HANDLE)
- goto fail;
-
- create_framebuffer(ctx, color_att, depth_att, renderer);
- if (renderer->fb == VK_NULL_HANDLE)
+ VkRenderPass rpass;
+ if (!vk_create_renderpass(ctx, num_color_att, color_props, depth_props,
+ &rpass)) {
goto fail;
+ }
+ renderer->renderpass = rpass;
- renderer->vs = create_shader_module(ctx, vs_src, vs_size);
- if (renderer->vs == VK_NULL_HANDLE)
+ VkShaderModule vs = create_shader_module(ctx, vs_src, vs_size);
+ if (vs == VK_NULL_HANDLE)
goto fail;
+ renderer->vs = vs;
- renderer->fs = create_shader_module(ctx, fs_src, fs_size);
- if (renderer->fs == VK_NULL_HANDLE)
+ VkShaderModule fs = create_shader_module(ctx, fs_src, fs_size);
+ if (fs == VK_NULL_HANDLE)
goto fail;
+ renderer->fs = fs;
- create_pipeline(ctx, color_att->props.w, color_att->props.h,
- color_att->props.num_samples, enable_depth,
- enable_stencil, renderer);
+ if (geometry)
+ renderer->geometry = geometry;
- if (renderer->pipeline == VK_NULL_HANDLE)
+ /* FIXME this is only for graphics atm */
+ if(!create_graphics_pipeline(ctx, w, h,
+ num_samples,
+ num_color_att,
+ enable_depth,
+ enable_stencil, renderer))
goto fail;
return true;
fail:
- fprintf(stderr, "Failed to create graphics pipeline.\n");
+ fprintf(stderr, "Failed to create renderer.\n");
vk_destroy_renderer(ctx, renderer);
return false;
}
renderer->fs = VK_NULL_HANDLE;
}
- if (renderer->fb != VK_NULL_HANDLE) {
- vkDestroyFramebuffer(ctx->dev, renderer->fb, 0);
- renderer->fb = VK_NULL_HANDLE;
- }
-
if (renderer->pipeline != VK_NULL_HANDLE) {
vkDestroyPipeline(ctx->dev, renderer->pipeline, 0);
renderer->pipeline = VK_NULL_HANDLE;
void
vk_destroy_buffer(struct vk_ctx *ctx,
- struct vk_buf *bo)
+ struct vk_buf *bo)
{
if (bo->buf != VK_NULL_HANDLE)
vkDestroyBuffer(ctx->dev, bo->buf, 0);
bo->mobj.mem = VK_NULL_HANDLE;
}
-void
-vk_draw(struct vk_ctx *ctx,
- struct vk_buf *vbo,
- struct vk_renderer *renderer,
- float *vk_fb_color,
- uint32_t vk_fb_color_count,
- struct vk_semaphores *semaphores,
- struct vk_image_att *attachments,
- uint32_t n_attachments,
- float x, float y,
- float w, float h)
+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;
+
+ 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,
+ uint32_t vk_fb_color_count,
+ float *vk_fb_color,
+ VkFramebuffer fb,
+ 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[2];
- VkSubmitInfo submit_info;
+ VkClearValue *clear_values; int i;
VkDeviceSize offsets[] = {0};
- VkPipelineStageFlagBits stage_flags;
+ int num_vertices = 0;
struct vk_dims img_size;
+ bool create_cmd_buf = false;
+ bool has_geometry = renderer->geometry != 0;
assert(vk_fb_color_count == 4);
+ if (!cmd_buf) {
+ fprintf(stderr, "Can't record an empty command buffer.\n");
+ return false;
+ }
+
/* VkCommandBufferBeginInfo */
memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
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 */
+ clear_values = malloc(num_atts * sizeof clear_values[0]);
+ memset(clear_values, 0, num_atts * sizeof clear_values[0]);
- memset(&clear_values[1], 0, sizeof clear_values[1]);
- clear_values[1].depthStencil.depth = 1.0;
- clear_values[1].depthStencil.stencil = 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.framebuffer = fb;
rp_begin_info.renderArea = rp_area;
- rp_begin_info.clearValueCount = 2;
+ rp_begin_info.clearValueCount = num_atts;
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);
+ vkBeginCommandBuffer(cmd_buf, &cmd_begin_info);
+ vkCmdBeginRenderPass(cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
viewport.x = x;
viewport.y = y;
scissor.extent.width = w;
scissor.extent.height = h;
- vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
- vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
+ vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
+ vkCmdSetScissor(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);
+ vkCmdPushConstants(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);
+ if (has_geometry && renderer->geometry->vertices.num_vertices > 0) {
+ num_vertices = renderer->geometry->vertices.num_vertices;
+ vkCmdBindVertexBuffers(cmd_buf, 0, 1, &renderer->geometry->vertices.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);
- vkCmdEndRenderPass(ctx->cmd_buf);
- if (attachments) {
+ vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS,
+ renderer->pipeline);
+
+ /* FIXME: temporal hack because I hard code 4 vertices in the
+ * vertex shader until I properly support VBOs */
+ if (!num_vertices)
+ num_vertices = 4;
+
+ vkCmdDraw(cmd_buf, num_vertices, 1, 0, 0);
+ vkCmdEndRenderPass(cmd_buf);
+
+ free(clear_values);
+#if 0
+ if (atts) {
VkImageMemoryBarrier *barriers =
- calloc(n_attachments, sizeof(VkImageMemoryBarrier));
+ calloc(num_atts, sizeof(VkImageMemoryBarrier));
VkImageMemoryBarrier *barrier = barriers;
- for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
- struct vk_image_att *att = &attachments[n];
+ 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);
barrier->subresourceRange.layerCount = 1;
}
- vkCmdPipelineBarrier(ctx->cmd_buf,
+ vkCmdPipelineBarrier(cmd_buf,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
0,
0, NULL,
0, NULL,
- n_attachments, barriers);
+ num_atts, barriers);
free(barriers);
}
+#endif
- vkEndCommandBuffer(ctx->cmd_buf);
+ vkEndCommandBuffer(cmd_buf);
+ if (create_cmd_buf) {
+ vk_destroy_cmd_buffers(ctx, 1, &cmd_buf);
+ }
+ return true;
+}
- if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
+void
+vk_draw(struct vk_ctx *ctx,
+ struct vk_semaphores *semaphores,
+ uint32_t num_buffers,
+ VkCommandBuffer *cmd_buf)
+{
+ VkSubmitInfo submit_info;
+ VkPipelineStageFlagBits stage_flags;
+
+ /* VkSubmitInfo */
+ memset(&submit_info, 0, sizeof submit_info);
+ submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submit_info.commandBufferCount = num_buffers;
+ submit_info.pCommandBuffers = cmd_buf;
+
+ /* semaphores */
+ if (semaphores) {
+ assert(semaphores->frame_ready);
+ assert(semaphores->frame_done);
+
+ /* The subpasses in a render pass automatically take care of
+ * image layout transitions. These transitions are controlled
+ * by subpass dependencies, which specify memory and execution
+ * dependencies between subpasses. We have only a single subpass
+ * right now, but the operations right before and right after
+ * this subpass also count as implicit "subpasses". There are two
+ * built-in dependencies that take care of the transition at the
+ * start of the render pass and at the end of the render pass,
+ * but the former does not occur at the right time. It assumes
+ * that the transition occurs at the start of the pipeline,
+ * but we haven't acquired the image yet at that point! There are
+ * two ways to deal with this problem.
+ *
+ * We could change the waitStages for the frame_ready semaphore
+ * to VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT to ensure that the render
+ * passes don't begin until the image is available, or we can make
+ * the render pass wait for the
+ * VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT stage.
+ */
+ stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
+
+ 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;
+ }
+
+
+ if (vkQueueSubmit(ctx->queue, 1, &submit_info,
+ VK_NULL_HANDLE) != VK_SUCCESS) {
fprintf(stderr, "Failed to submit queue.\n");
+ abort();
}
- if (!semaphores)
- vkQueueWaitIdle(ctx->queue);
+ if (vkQueueWaitIdle(ctx->queue) != VK_SUCCESS) {
+ fprintf(stderr, "Failed to wait idle.\n");
+ abort();
+ }
}
void
vk_clear_color(struct vk_ctx *ctx,
+ VkCommandBuffer cmd_buf,
struct vk_buf *vbo,
struct vk_renderer *renderer,
float *vk_fb_color,
uint32_t vk_fb_color_count,
+ VkFramebuffer fb,
struct vk_semaphores *semaphores,
bool has_wait, bool has_signal,
- struct vk_image_att *attachments,
+ struct vk_attachment *attachments,
uint32_t n_attachments,
float x, float y,
float w, float h)
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.framebuffer = fb;
rp_begin_info.renderArea = rp_area;
rp_begin_info.clearValueCount = 2;
rp_begin_info.pClearValues = clear_values;
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;
+ submit_info.pCommandBuffers = &cmd_buf;
/* FIXME */
if (has_wait) {
img_range.baseArrayLayer = 0;
img_range.layerCount = 1;
- vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
+ vkBeginCommandBuffer(cmd_buf, &cmd_begin_info);
vk_transition_image_layout(&attachments[0],
- ctx->cmd_buf,
+ cmd_buf,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_GENERAL,
VK_QUEUE_FAMILY_EXTERNAL,
ctx->qfam_idx);
- vkCmdClearColorImage(ctx->cmd_buf,
+ vkCmdClearColorImage(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);
+ vkCmdBeginRenderPass(cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
viewport.x = x;
viewport.y = y;
scissor.extent.width = w;
scissor.extent.height = h;
- vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
- vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
+ vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
+ vkCmdSetScissor(cmd_buf, 0, 1, &scissor);
- vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
+ vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS,
+ renderer->pipeline);
- vkCmdEndRenderPass(ctx->cmd_buf);
+ vkCmdEndRenderPass(cmd_buf);
if (attachments) {
VkImageMemoryBarrier *barriers =
VkImageMemoryBarrier *barrier = barriers;
for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
- struct vk_image_att *att = &attachments[n];
+ struct vk_attachment *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;
+ get_aspect_from_depth_format(att->props.format) != 0;
barrier->oldLayout = is_depth ?
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
barrier->subresourceRange.layerCount = 1;
}
- vkCmdPipelineBarrier(ctx->cmd_buf,
+ vkCmdPipelineBarrier(cmd_buf,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
0,
free(barriers);
}
- vkEndCommandBuffer(ctx->cmd_buf);
+ vkEndCommandBuffer(cmd_buf);
- if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
+ if (vkQueueSubmit(ctx->queue, 1, &submit_info,
+ VK_NULL_HANDLE) != VK_SUCCESS) {
fprintf(stderr, "Failed to submit queue.\n");
}
vkQueueWaitIdle(ctx->queue);
}
+void
+vk_set_viewport(struct vk_ctx *ctx,
+ VkCommandBuffer cmd_buf,
+ float x, float y,
+ float w, float h,
+ float near, float far)
+{
+ VkCommandBufferBeginInfo binfo;
+ VkViewport viewport;
+
+ memset(&viewport, 0, sizeof viewport);
+ viewport.x = x;
+ viewport.y = y;
+ viewport.width = w;
+ viewport.height = h;
+ viewport.minDepth = near;
+ viewport.maxDepth = far;
+
+ memset(&binfo, 0, sizeof binfo);
+ binfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ binfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
+
+ vkBeginCommandBuffer(cmd_buf, &binfo);
+ vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
+ vkEndCommandBuffer(cmd_buf);
+}
+
bool
vk_create_swapchain(struct vk_ctx *ctx,
int width, int height,
VkSurfaceCapabilitiesKHR surf_cap;
VkSwapchainCreateInfoKHR s_info;
VkExtent2D extent;
- VkImageSubresourceRange sr;
- VkImage *s_images;
- int i;
+ int i, j;
if (!sc_validate_surface(ctx, surf)) {
fprintf(stderr, "Failed to validate surface!\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;
}
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)
/* 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;
+ 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) {
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);
+ if (!swapchain->swapchain) {
+ fprintf(stderr, "The swapchain seems null\n");
+ return false;
}
/* 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);
+ 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);
+ /* get the images */
+ swapchain->images = (VkImage*)alloca(swapchain->num_images * sizeof(VkImage));
+ vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain,
+ &swapchain->num_images,
+ swapchain->images);
+ /* create attributes from those 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;
+ vk_fill_image_props(ctx, width, height, 1,
+ 1, 1, 1,
+ s_info.imageFormat,
+ 0,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+ true, false, false,
+ &swapchain->img_props);
+
+ swapchain->img_props.usage = s_info.imageUsage;
+ swapchain->views = malloc(swapchain->num_images * sizeof(VkImageView));
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;
+ if (!vk_create_image_view(ctx, swapchain->images[i],
+ VK_IMAGE_VIEW_TYPE_2D,
+ s_info.imageFormat, true,
+ &swapchain->views[i])) {
+ fprintf(stderr, "Failed to create image view for image: %d\n", i);
+ goto fail;
}
}
- free(s_images);
return true;
+
+fail:
+ for (j = 0; j < i; j++) {
+ vkDestroyImageView(ctx->dev, swapchain->views[j], 0);
+ }
+ return false;
}
void
vk_destroy_swapchain(struct vk_ctx *ctx,
struct vk_swapchain *swapchain)
{
+ int i;
+ for (i = 0; i < swapchain->num_images; i++) {
+ vkDestroyImageView(ctx->dev, swapchain->views[i], 0);
+ }
vkDestroySwapchainKHR(ctx->dev, swapchain->swapchain, 0);
- vkDestroySurfaceKHR(ctx->inst, swapchain->surface, 0);
+}
+
+bool
+vk_queue_present(struct vk_swapchain *swapchain,
+ VkQueue queue,
+ uint32_t image_idx,
+ VkSemaphore wait_sema)
+{
+ VkPresentInfoKHR pinfo;
+
+ memset(&pinfo, 0, sizeof pinfo);
+ pinfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
+ pinfo.swapchainCount = 1;
+ pinfo.pSwapchains = &swapchain->swapchain;
+ pinfo.pImageIndices = &image_idx;
+
+ pinfo.pWaitSemaphores = &wait_sema;
+ pinfo.waitSemaphoreCount = 1;
+
+ /* FIXME: add code for VK_KHR_incremental_present_enabled!! */
- free(swapchain);
- swapchain = 0;
+ if (vkQueuePresentKHR(queue, &pinfo) != VK_SUCCESS) {
+ fprintf(stderr, "Failed to present queue.\n");
+ return false;
+ }
+
+ return true;
}
void
vk_copy_image_to_buffer(struct vk_ctx *ctx,
- struct vk_image_att *src_img,
+ VkCommandBuffer cmd_buf,
+ struct vk_attachment *src_img,
struct vk_buf *dst_bo,
float w, float h)
{
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;
+ submit_info.pCommandBuffers = &cmd_buf;
- vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
+ vkBeginCommandBuffer(cmd_buf, &cmd_begin_info);
if (src_img->props.end_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && dst_bo) {
vk_transition_image_layout(src_img,
- ctx->cmd_buf,
+ cmd_buf,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_QUEUE_FAMILY_EXTERNAL,
.imageExtent = { w, h, 1 }
};
- vkCmdCopyImageToBuffer(ctx->cmd_buf,
+ vkCmdCopyImageToBuffer(cmd_buf,
src_img->obj.img,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
dst_bo->buf, 1, ©_region);
vk_transition_image_layout(src_img,
- ctx->cmd_buf,
+ cmd_buf,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_QUEUE_FAMILY_EXTERNAL,
.size = VK_WHOLE_SIZE
};
- vkCmdPipelineBarrier(ctx->cmd_buf,
+ vkCmdPipelineBarrier(cmd_buf,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_HOST_BIT,
(VkDependencyFlags) 0, 0, NULL,
1, &write_finish_buffer_memory_barrier,
0, NULL);
}
- vkEndCommandBuffer(ctx->cmd_buf);
+ vkEndCommandBuffer(cmd_buf);
if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
fprintf(stderr, "Failed to submit queue.\n");
vkQueueWaitIdle(ctx->queue);
}
-// FIXME: external
bool
vk_create_semaphores(struct vk_ctx *ctx,
bool is_external,
vk_destroy_semaphores(struct vk_ctx *ctx,
struct vk_semaphores *semaphores)
{
- if (semaphores->frame_ready)
- vkDestroySemaphore(ctx->dev, semaphores->frame_ready, 0);
- if (semaphores->frame_done)
- vkDestroySemaphore(ctx->dev, semaphores->frame_done, 0);
+ vkDestroySemaphore(ctx->dev, semaphores->frame_ready, 0);
+ semaphores->frame_ready = VK_NULL_HANDLE;
+
+ vkDestroySemaphore(ctx->dev, semaphores->frame_done, 0);
+ semaphores->frame_done = VK_NULL_HANDLE;
+}
+
+bool
+vk_create_fences(struct vk_ctx *ctx,
+ int num_cmd_buf,
+ VkFenceCreateFlagBits flags,
+ VkFence *fences)
+{
+ VkFenceCreateInfo f_info;
+ int i, j = -1;
+
+ memset(&f_info, 0, sizeof f_info);
+ f_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+ f_info.flags = flags ? flags : VK_FENCE_CREATE_SIGNALED_BIT;
+
+
+ fences = malloc(num_cmd_buf * sizeof(VkFence));
+ for (i = 0; i < num_cmd_buf; i++) {
+ if (vkCreateFence(ctx->dev, &f_info, 0, &fences[i]) != VK_SUCCESS) {
+ fprintf(stderr, "Failed to create fence number: %d\n", (i + 1));
+ j = i;
+ break;
+ }
+ }
+
+ if (j == i) {
+ for (i = 0; i < j; i++) {
+ vkDestroyFence(ctx->dev, fences[i], 0);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+void
+vk_destroy_fences(struct vk_ctx *ctx,
+ int num_fences,
+ VkFence *fences)
+{
+ int i;
+ for (i = 0; i < num_fences; i++) {
+ vkDestroyFence(ctx->dev, fences[i], 0);
+ }
}
void
-vk_transition_image_layout(struct vk_image_att *img_att,
- VkCommandBuffer cmd_buf,
- VkImageLayout old_layout,
- VkImageLayout new_layout,
- uint32_t src_queue_fam_idx,
- uint32_t dst_queue_fam_idx)
+vk_transition_image_layout(struct vk_attachment *img_att,
+ VkCommandBuffer cmd_buf,
+ VkImageLayout old_layout,
+ VkImageLayout new_layout,
+ uint32_t src_queue_fam_idx,
+ uint32_t dst_queue_fam_idx)
{
VkImageMemoryBarrier barrier;
- struct vk_image_props props = img_att->props;
+ struct vk_att_props props = img_att->props;
VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(props.format);
memset(&barrier, 0, sizeof barrier);