X-Git-Url: https://eleni.mutantstargoat.com/git/?p=vkrt;a=blobdiff_plain;f=src%2Fvk.c;h=56d4c6e21262b76b9dbe77793b11015741478064;hp=a62fc18b570063dc8580bc400f2a10e3fb88cd12;hb=739a8266145a78fdc015ac74c890474f023b1fd1;hpb=35f7d10bf03cc666b551490bcae87ac389d63cb7 diff --git a/src/vk.c b/src/vk.c index a62fc18..56d4c6e 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; @@ -807,7 +797,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; @@ -1074,7 +1065,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; } @@ -1095,7 +1087,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; } @@ -1107,7 +1101,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; } @@ -1134,17 +1129,21 @@ sc_select_supported_present_modes(struct vk_ctx *ctx, uint32_t num_present_modes; /* 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; @@ -1276,15 +1275,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; @@ -1295,15 +1299,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.initialLayout = props->in_layout; + 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; @@ -1316,57 +1325,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; @@ -1380,6 +1367,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, @@ -1420,6 +1464,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, @@ -1431,41 +1545,37 @@ 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_att_props *color_props, + struct vk_att_props *depth_props, struct vk_vertex_info *vert_info, 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; + + if (vert_info) + renderer->vertex_info = *vert_info; - renderer->fs = create_shader_module(ctx, fs_src, fs_size); - if (renderer->fs == VK_NULL_HANDLE) - goto fail; /* FIXME this is only for graphics atm */ if(!create_graphics_pipeline(ctx, w, h, @@ -1475,9 +1585,6 @@ vk_create_renderer(struct vk_ctx *ctx, enable_stencil, renderer)) goto fail; - if (renderer->pipeline == VK_NULL_HANDLE) - goto fail; - return true; fail: @@ -1505,11 +1612,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; @@ -1644,7 +1746,6 @@ vk_create_fence(struct vk_ctx *ctx, memset(&finfo, 0, sizeof finfo); finfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - finfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; if (vkCreateFence(ctx->dev, &finfo, 0, fence) != VK_SUCCESS) { fprintf(stderr, "Failed to create fence.\n"); @@ -1667,7 +1768,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; @@ -1680,6 +1782,7 @@ vk_record_cmd_buffer(struct vk_ctx *ctx, 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, @@ -1696,14 +1799,9 @@ vk_record_cmd_buffer(struct vk_ctx *ctx, assert(vk_fb_color_count == 4); - /* if cmd_buf is null create it */ if (!cmd_buf) { - if ((cmd_buf = vk_create_cmd_buffer(ctx)) == - VK_NULL_HANDLE) { - fprintf(stderr, "Failed to create command buffer.\n"); - return false; - } - create_cmd_buf = true; + fprintf(stderr, "Can't record an empty command buffer.\n"); + return false; } /* VkCommandBufferBeginInfo */ @@ -1735,7 +1833,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; @@ -1768,7 +1866,8 @@ vk_record_cmd_buffer(struct vk_ctx *ctx, vkCmdBindVertexBuffers(cmd_buf, 0, 1, &vbo->buf, offsets); } - vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline); + vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, + renderer->pipeline); num_vertices = vbo ? renderer->vertex_info.num_verts : 4; vkCmdDraw(cmd_buf, num_vertices, 1, 0, 0); @@ -1833,8 +1932,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; @@ -1846,6 +1943,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; @@ -1855,7 +1973,8 @@ 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(); } @@ -1873,6 +1992,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, @@ -1917,7 +2037,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; @@ -1977,7 +2097,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); @@ -1993,7 +2114,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 : @@ -2025,7 +2146,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"); } @@ -2071,9 +2193,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"); @@ -2144,62 +2264,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); + 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_atts * sizeof(VkImage)); - if (!s_images) { - fprintf(stderr, "Failed to allocate swapchain images.\n"); - return false; - } - - 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; } @@ -2207,6 +2312,10 @@ 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); } @@ -2227,6 +2336,8 @@ vk_queue_present(struct vk_swapchain *swapchain, 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"); return false; @@ -2356,10 +2467,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