X-Git-Url: http://git.mutantstargoat.com?a=blobdiff_plain;f=src%2Fvk.c;h=546f283c74078e07292ebf6d3de8bfea7fd61894;hb=7f569457adb3b12e9f067f16bd96451a9b00831f;hp=bde9972c5a31b98ef98ac04ee705d421cea02724;hpb=63c91ee81f2e7d6218a424d5856132b3e8c5d8ac;p=vkrt diff --git a/src/vk.c b/src/vk.c index bde9972..546f283 100644 --- a/src/vk.c +++ b/src/vk.c @@ -148,7 +148,7 @@ create_instance(bool enable_layers) /* 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 */ @@ -291,23 +291,25 @@ create_pipeline_cache(struct vk_ctx *ctx) return pcache; } -static VkRenderPass -create_renderpass(struct vk_ctx *ctx, - uint32_t num_color_atts, - struct vk_attachment *color_atts, - struct vk_attachment *depth_att) +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; /* one subpass for the moment: */ VkSubpassDescription subpass_dsc[1]; + VkSubpassDependency subpass_dep; + VkRenderPassCreateInfo rpass_info; int i; uint32_t num_atts = num_color_atts + 1; - bool has_layout = depth_att->props.in_layout != - VK_IMAGE_LAYOUT_UNDEFINED; + 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]); @@ -317,10 +319,10 @@ create_renderpass(struct vk_ctx *ctx, /* color attachments description (we can have many) */ for (i = 0; i < num_color_atts; i++) { - att_dsc[i].samples = get_num_samples(color_atts[i].props.num_samples); - att_dsc[i].initialLayout = color_atts[i].props.in_layout; - att_dsc[i].finalLayout = color_atts[i].props.end_layout; - att_dsc[i].format = color_atts[i].props.format; + 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; @@ -328,17 +330,17 @@ create_renderpass(struct vk_ctx *ctx, att_dsc[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; att_rfc[i].attachment = i; - att_rfc[i].layout = color_atts[i].props.tiling != VK_IMAGE_TILING_OPTIMAL ? - VK_IMAGE_LAYOUT_GENERAL : - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + 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_att->props.num_samples); - att_dsc[num_color_atts].initialLayout = depth_att->props.in_layout; - att_dsc[num_color_atts].finalLayout = depth_att->props.end_layout; - att_dsc[num_color_atts].format = depth_att->props.format; + 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 : @@ -357,6 +359,35 @@ create_renderpass(struct vk_ctx *ctx, subpass_dsc[0].pColorAttachments = &att_rfc[0]; 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; @@ -364,17 +395,23 @@ create_renderpass(struct vk_ctx *ctx, 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; } free(att_dsc); free(att_rfc); - return rpass; + return true; } static inline VkImageType @@ -469,42 +506,7 @@ get_pipeline_stage_flags(const VkImageLayout layout) return 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) -{ - 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; - - 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; -} - +#if 0 static bool create_attachment_views(struct vk_ctx *ctx, int num_color_att, struct vk_attachment *color_att, @@ -513,43 +515,30 @@ create_attachment_views(struct vk_ctx *ctx, int num_color_att, VkImageSubresourceRange sr; int i; - /* depth attachments */ - memset(&sr, 0, sizeof sr); - sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format); - sr.baseMipLevel = 0; - sr.levelCount = 1; - sr.baseArrayLayer = 0; - sr.layerCount = 1; - - create_image_view(ctx, depth_att->obj.img, VK_IMAGE_VIEW_TYPE_2D, - depth_att->props.format, sr, false, - &depth_att->obj.img_view); + vk_create_image_view(ctx, depth_att->obj.img, VK_IMAGE_VIEW_TYPE_2D, + depth_att->props.format, false, + &depth_att->obj.img_view); memset(&sr, 0, sizeof sr); sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; for (i = 0; i < num_color_att; i++) { - /* FIXME: in case of mipmaps */ - sr.baseMipLevel = 0; - sr.levelCount = color_att[i].props.num_levels; - sr.baseArrayLayer = 0; - sr.layerCount = color_att[i].props.num_layers; - - create_image_view(ctx, color_att[i].obj.img, VK_IMAGE_VIEW_TYPE_2D, - color_att[i].props.format, sr, color_att[i].props.is_swapchain, - &color_att[i].obj.img_view); + 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, - int width, int height, - int num_color_atts, - struct vk_attachment *color_att, - struct vk_attachment *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) { VkFramebufferCreateInfo fb_info; VkImageView *atts; @@ -572,22 +561,23 @@ create_framebuffer(struct vk_ctx *ctx, 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; - free(atts); - return; + return false; + } -fail: - fprintf(stderr, "Failed to create framebuffer.\n"); free(atts); - renderer->fb = VK_NULL_HANDLE; + 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; @@ -606,6 +596,63 @@ create_shader_module(struct vk_ctx *ctx, return sm; } +static void +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) +{ + 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) { + } +} + static bool create_graphics_pipeline(struct vk_ctx *ctx, uint32_t width, @@ -616,8 +663,8 @@ create_graphics_pipeline(struct vk_ctx *ctx, bool enable_stencil, struct vk_renderer *renderer) { - VkVertexInputBindingDescription vert_bind_dsc[1]; - VkVertexInputAttributeDescription vert_att_dsc[1]; + VkVertexInputBindingDescription vert_bind_dsc[4]; + VkVertexInputAttributeDescription vert_att_dsc[4]; VkPipelineColorBlendAttachmentState *cb_att_state; VkPipelineVertexInputStateCreateInfo vert_input_info; @@ -640,6 +687,7 @@ create_graphics_pipeline(struct vk_ctx *ctx, 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 @@ -651,35 +699,37 @@ create_graphics_pipeline(struct vk_ctx *ctx, 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; @@ -807,7 +857,8 @@ create_graphics_pipeline(struct vk_ctx *ctx, 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; goto fail; @@ -892,8 +943,9 @@ alloc_memory(struct vk_ctx *ctx, mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_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"); @@ -917,7 +969,9 @@ alloc_memory(struct vk_ctx *ctx, } static bool -alloc_image_memory(struct vk_ctx *ctx, bool is_external, 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; @@ -1018,7 +1072,7 @@ are_props_supported(struct vk_ctx *ctx, struct vk_att_props *props) VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; 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++) { @@ -1033,8 +1087,7 @@ are_props_supported(struct vk_ctx *ctx, struct vk_att_props *props) /* usage can't be null */ if (flags) { img_fmt_info.usage = flags; - } - else { + } else { if (!props->is_swapchain) { fprintf(stderr, "Unsupported Vulkan format properties: usage.\n"); return false; @@ -1072,7 +1125,8 @@ sc_validate_surface(struct vk_ctx *ctx, 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; } @@ -1093,7 +1147,9 @@ sc_select_format(struct vk_ctx *ctx, 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; } @@ -1105,7 +1161,8 @@ sc_select_format(struct vk_ctx *ctx, 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; } @@ -1130,40 +1187,44 @@ sc_select_supported_present_modes(struct vk_ctx *ctx, { 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; } @@ -1195,7 +1256,7 @@ vk_init_ctx(struct vk_ctx *ctx, return true; fail: - vk_cleanup_ctx(ctx, enable_layers); + vk_cleanup_ctx(ctx); return false; } @@ -1230,31 +1291,26 @@ vk_init_ctx_for_rendering(struct vk_ctx *ctx, return true; fail: - vk_cleanup_ctx(ctx, enable_layers); + vk_cleanup_ctx(ctx); return false; } void -vk_destroy_cmd_bufs(struct vk_ctx *ctx, - uint32_t num_buffers, - VkCommandBuffer *buffers) +vk_destroy_cmd_buffers(struct vk_ctx *ctx, + uint32_t num_buffers, + VkCommandBuffer *buffers) { 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, num_buffers, &buffers[i]); + vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, num_buffers, buffers); } void -vk_cleanup_ctx(struct vk_ctx *ctx, - bool enable_layers) +vk_cleanup_ctx(struct vk_ctx *ctx) { - if (enable_layers) { - return; - } - if (ctx->cmd_pool != VK_NULL_HANDLE) { vkResetCommandPool(ctx->dev, ctx->cmd_pool, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT); @@ -1279,15 +1335,20 @@ vk_cleanup_ctx(struct vk_ctx *ctx, } bool -vk_create_image(struct vk_ctx *ctx, - struct vk_att_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; @@ -1298,15 +1359,20 @@ vk_create_image(struct vk_ctx *ctx, 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, props->need_export, img)) + if(!alloc_image_memory(ctx, true, img)) goto fail; return true; @@ -1319,57 +1385,35 @@ fail: 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_att_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, true, img)) + if(!alloc_image_memory(ctx, props->need_export, img)) goto fail; return true; @@ -1383,6 +1427,63 @@ fail: } bool +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, @@ -1423,6 +1524,76 @@ vk_fill_image_props(struct vk_ctx *ctx, 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, @@ -1434,41 +1605,36 @@ vk_create_renderer(struct vk_ctx *ctx, bool enable_depth, bool enable_stencil, int num_color_att, - struct vk_attachment *color_att, - struct vk_attachment *depth_att, - struct vk_vertex_info *vert_info, + 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; - /* 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, - num_color_att, - color_att, - depth_att); - - if (renderer->renderpass == VK_NULL_HANDLE) + VkRenderPass rpass; + if (!vk_create_renderpass(ctx, num_color_att, color_props, depth_props, + &rpass)) { goto fail; + } + renderer->renderpass = rpass; - create_framebuffer(ctx, - w, h, - num_color_att, color_att, - depth_att, renderer); - if (renderer->fb == VK_NULL_HANDLE) + VkShaderModule vs = create_shader_module(ctx, vs_src, vs_size); + if (vs == VK_NULL_HANDLE) goto fail; + renderer->vs = vs; - renderer->vs = create_shader_module(ctx, vs_src, vs_size); - if (renderer->vs == VK_NULL_HANDLE) + VkShaderModule fs = create_shader_module(ctx, fs_src, fs_size); + if (fs == VK_NULL_HANDLE) goto fail; + renderer->fs = fs; - renderer->fs = create_shader_module(ctx, fs_src, fs_size); - if (renderer->fs == VK_NULL_HANDLE) - goto fail; + if (geometry) + renderer->geometry = geometry; /* FIXME this is only for graphics atm */ if(!create_graphics_pipeline(ctx, w, h, @@ -1478,9 +1644,6 @@ vk_create_renderer(struct vk_ctx *ctx, enable_stencil, renderer)) goto fail; - if (renderer->pipeline == VK_NULL_HANDLE) - goto fail; - return true; fail: @@ -1508,11 +1671,6 @@ vk_destroy_renderer(struct vk_ctx *ctx, 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; @@ -1626,7 +1784,7 @@ fail: 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); @@ -1639,6 +1797,24 @@ vk_destroy_buffer(struct vk_ctx *ctx, 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; + + 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) { @@ -1651,7 +1827,8 @@ vk_create_cmd_buffer(struct vk_ctx *ctx) alloc_info.commandBufferCount = 1; alloc_info.commandPool = ctx->cmd_pool; - if (vkAllocateCommandBuffers(ctx->dev, &alloc_info, &cmd_buf) != VK_SUCCESS) + if (vkAllocateCommandBuffers(ctx->dev, &alloc_info, + &cmd_buf) != VK_SUCCESS) return 0; return cmd_buf; @@ -1661,9 +1838,9 @@ 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, + VkFramebuffer fb, uint32_t num_atts, struct vk_attachment *atts, float x, float y, @@ -1674,18 +1851,16 @@ vk_record_cmd_buffer(struct vk_ctx *ctx, VkRect2D rp_area; VkClearValue *clear_values; int i; VkDeviceSize offsets[] = {0}; - int num_vertices; + 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 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; - } + fprintf(stderr, "Can't record an empty command buffer.\n"); + return false; } /* VkCommandBufferBeginInfo */ @@ -1717,7 +1892,7 @@ vk_record_cmd_buffer(struct vk_ctx *ctx, 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 = num_atts; rp_begin_info.pClearValues = clear_values; @@ -1746,13 +1921,19 @@ vk_record_cmd_buffer(struct vk_ctx *ctx, 0, sizeof (struct vk_dims), &img_size); - if (vbo) { - vkCmdBindVertexBuffers(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(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline); + 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; - num_vertices = vbo ? renderer->vertex_info.num_verts : 4; vkCmdDraw(cmd_buf, num_vertices, 1, 0, 0); vkCmdEndRenderPass(cmd_buf); @@ -1800,6 +1981,9 @@ vk_record_cmd_buffer(struct vk_ctx *ctx, #endif vkEndCommandBuffer(cmd_buf); + if (create_cmd_buf) { + vk_destroy_cmd_buffers(ctx, 1, &cmd_buf); + } return true; } @@ -1812,8 +1996,6 @@ vk_draw(struct vk_ctx *ctx, VkSubmitInfo submit_info; VkPipelineStageFlagBits stage_flags; - stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - /* VkSubmitInfo */ memset(&submit_info, 0, sizeof submit_info); submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; @@ -1825,6 +2007,27 @@ vk_draw(struct vk_ctx *ctx, 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; @@ -1834,11 +2037,16 @@ vk_draw(struct vk_ctx *ctx, } - 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"); + abort(); } - vkQueueWaitIdle(ctx->queue); + if (vkQueueWaitIdle(ctx->queue) != VK_SUCCESS) { + fprintf(stderr, "Failed to wait idle.\n"); + abort(); + } } void @@ -1848,6 +2056,7 @@ vk_clear_color(struct vk_ctx *ctx, 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_attachment *attachments, @@ -1892,7 +2101,7 @@ vk_clear_color(struct vk_ctx *ctx, 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; @@ -1952,7 +2161,8 @@ vk_clear_color(struct vk_ctx *ctx, vkCmdSetViewport(cmd_buf, 0, 1, &viewport); vkCmdSetScissor(cmd_buf, 0, 1, &scissor); - vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline); + vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, + renderer->pipeline); vkCmdEndRenderPass(cmd_buf); @@ -1968,7 +2178,7 @@ vk_clear_color(struct vk_ctx *ctx, 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 : @@ -2000,7 +2210,8 @@ vk_clear_color(struct vk_ctx *ctx, 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"); } @@ -2008,6 +2219,33 @@ vk_clear_color(struct vk_ctx *ctx, 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, @@ -2019,9 +2257,7 @@ vk_create_swapchain(struct vk_ctx *ctx, 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"); @@ -2092,62 +2328,47 @@ vk_create_swapchain(struct vk_ctx *ctx, /* get the number of swapchain images and the swapchain images * and store the new swapchain images */ - vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_atts, 0); - printf("number of swapchain images: %d\n", swapchain->num_atts); - - /* create images */ - s_images = malloc(swapchain->num_atts * sizeof(VkImage)); - if (!s_images) { - fprintf(stderr, "Failed to allocate swapchain images.\n"); - return false; - } + vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, + &swapchain->num_images, 0); + printf("number of swapchain images: %d\n", swapchain->num_images); - vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_atts, 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->atts = malloc(swapchain->num_atts * sizeof swapchain->atts[0]); - if (!swapchain->atts) { - fprintf(stderr, "Failed to allocate swapchain images.\n"); - goto fail; - } - memset(swapchain->atts, 0, sizeof swapchain->atts[0]); - memset(&sr, 0, sizeof sr); - sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - sr.levelCount = 1; - sr.layerCount = 1; - - for (i = 0; i < swapchain->num_atts; i++) { - /* we store the image */ - swapchain->atts[i].obj.img = s_images[i]; - - /* filling attachment properties here where that info - * is available */ - - 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->atts[i].props); - swapchain->atts[i].props.usage = s_info.imageUsage; - - if (!create_image_view(ctx, s_images[i], - VK_IMAGE_VIEW_TYPE_2D, - s_info.imageFormat, sr, true, - &swapchain->atts[i].obj.img_view)) { + 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++) { + 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: - free(s_images); + for (j = 0; j < i; j++) { + vkDestroyImageView(ctx->dev, swapchain->views[j], 0); + } return false; } @@ -2155,12 +2376,15 @@ 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); - swapchain = 0; } bool -vk_present_queue(struct vk_swapchain *swapchain, +vk_queue_present(struct vk_swapchain *swapchain, VkQueue queue, uint32_t image_idx, VkSemaphore wait_sema) @@ -2170,12 +2394,13 @@ vk_present_queue(struct vk_swapchain *swapchain, memset(&pinfo, 0, sizeof pinfo); pinfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; pinfo.swapchainCount = 1; + pinfo.pSwapchains = &swapchain->swapchain; pinfo.pImageIndices = &image_idx; - if (wait_sema != VK_NULL_HANDLE) { - pinfo.pWaitSemaphores = &wait_sema; - pinfo.waitSemaphoreCount = 1; - } + pinfo.pWaitSemaphores = &wait_sema; + pinfo.waitSemaphoreCount = 1; + + /* FIXME: add code for VK_KHR_incremental_present_enabled!! */ if (vkQueuePresentKHR(queue, &pinfo) != VK_SUCCESS) { fprintf(stderr, "Failed to present queue.\n"); @@ -2306,10 +2531,11 @@ void 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