/* * Copyright © 2019 Raspberry Pi Ltd * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include "v3dv_private.h" static uint32_t num_subpass_attachments(const VkSubpassDescription2 *desc) { return desc->inputAttachmentCount + desc->colorAttachmentCount + (desc->pResolveAttachments ? desc->colorAttachmentCount : 0) + (desc->pDepthStencilAttachment != NULL); } static void set_try_tlb_resolve(struct v3dv_device *device, struct v3dv_render_pass_attachment *att) { const struct v3dv_format *format = v3dv_X(device, get_format)(att->desc.format); att->try_tlb_resolve = v3dv_X(device, format_supports_tlb_resolve)(format); } static void pass_find_subpass_range_for_attachments(struct v3dv_device *device, struct v3dv_render_pass *pass) { for (uint32_t i = 0; i < pass->attachment_count; i++) { pass->attachments[i].first_subpass = pass->subpass_count - 1; pass->attachments[i].last_subpass = 0; if (pass->multiview_enabled) { for (uint32_t j = 0; j < MAX_MULTIVIEW_VIEW_COUNT; j++) { pass->attachments[i].views[j].first_subpass = pass->subpass_count - 1; pass->attachments[i].views[j].last_subpass = 0; } } } for (uint32_t i = 0; i < pass->subpass_count; i++) { const struct v3dv_subpass *subpass = &pass->subpasses[i]; for (uint32_t j = 0; j < subpass->color_count; j++) { uint32_t attachment_idx = subpass->color_attachments[j].attachment; if (attachment_idx == VK_ATTACHMENT_UNUSED) continue; struct v3dv_render_pass_attachment *att = &pass->attachments[attachment_idx]; if (i < att->first_subpass) att->first_subpass = i; if (i > att->last_subpass) att->last_subpass = i; uint32_t view_mask = subpass->view_mask; while (view_mask) { uint32_t view_index = u_bit_scan(&view_mask); if (i < att->views[view_index].first_subpass) att->views[view_index].first_subpass = i; if (i > att->views[view_index].last_subpass) att->views[view_index].last_subpass = i; } if (subpass->resolve_attachments && subpass->resolve_attachments[j].attachment != VK_ATTACHMENT_UNUSED) { set_try_tlb_resolve(device, att); } } uint32_t ds_attachment_idx = subpass->ds_attachment.attachment; if (ds_attachment_idx != VK_ATTACHMENT_UNUSED) { if (i < pass->attachments[ds_attachment_idx].first_subpass) pass->attachments[ds_attachment_idx].first_subpass = i; if (i > pass->attachments[ds_attachment_idx].last_subpass) pass->attachments[ds_attachment_idx].last_subpass = i; if (subpass->ds_resolve_attachment.attachment != VK_ATTACHMENT_UNUSED) set_try_tlb_resolve(device, &pass->attachments[ds_attachment_idx]); } for (uint32_t j = 0; j < subpass->input_count; j++) { uint32_t input_attachment_idx = subpass->input_attachments[j].attachment; if (input_attachment_idx == VK_ATTACHMENT_UNUSED) continue; if (i < pass->attachments[input_attachment_idx].first_subpass) pass->attachments[input_attachment_idx].first_subpass = i; if (i > pass->attachments[input_attachment_idx].last_subpass) pass->attachments[input_attachment_idx].last_subpass = i; } if (subpass->resolve_attachments) { for (uint32_t j = 0; j < subpass->color_count; j++) { uint32_t attachment_idx = subpass->resolve_attachments[j].attachment; if (attachment_idx == VK_ATTACHMENT_UNUSED) continue; if (i < pass->attachments[attachment_idx].first_subpass) pass->attachments[attachment_idx].first_subpass = i; if (i > pass->attachments[attachment_idx].last_subpass) pass->attachments[attachment_idx].last_subpass = i; } } } } /* GFXH-1461: if depth is cleared but stencil is loaded (or vice versa), * the clear might get lost. If a subpass has this then we can't emit * the clear using the TLB and we have to do it as a draw call. This * issue is fixed since V3D 4.3.18. * * FIXME: separate stencil. */ static void check_do_depth_stencil_clear_with_draw(struct v3dv_device *device, struct v3dv_render_pass *pass, struct v3dv_subpass *subpass) { if (device->devinfo.ver > 42 || subpass->ds_attachment.attachment == VK_ATTACHMENT_UNUSED) { return; } struct v3dv_render_pass_attachment *att = &pass->attachments[subpass->ds_attachment.attachment]; if (att->desc.format != VK_FORMAT_D24_UNORM_S8_UINT) return; if (att->desc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR && att->desc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD) { subpass->do_depth_clear_with_draw = true; } else if (att->desc.loadOp == VK_ATTACHMENT_LOAD_OP_LOAD && att->desc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) { subpass->do_stencil_clear_with_draw = true; } } VKAPI_ATTR VkResult VKAPI_CALL v3dv_CreateRenderPass2(VkDevice _device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) { V3DV_FROM_HANDLE(v3dv_device, device, _device); struct v3dv_render_pass *pass; assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2); /* From the VK_KHR_multiview spec: * * When a subpass uses a non-zero view mask, multiview functionality is * considered to be enabled. Multiview is all-or-nothing for a render * pass - that is, either all subpasses must have a non-zero view mask * (though some subpasses may have only one view) or all must be zero. */ bool multiview_enabled = pCreateInfo->subpassCount && pCreateInfo->pSubpasses[0].viewMask; size_t size = sizeof(*pass); size_t subpasses_offset = size; size += pCreateInfo->subpassCount * sizeof(pass->subpasses[0]); size_t attachments_offset = size; size += pCreateInfo->attachmentCount * sizeof(pass->attachments[0]); pass = vk_object_zalloc(&device->vk, pAllocator, size, VK_OBJECT_TYPE_RENDER_PASS); if (pass == NULL) return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); pass->multiview_enabled = multiview_enabled; pass->attachment_count = pCreateInfo->attachmentCount; pass->attachments = (void *) pass + attachments_offset; pass->subpass_count = pCreateInfo->subpassCount; pass->subpasses = (void *) pass + subpasses_offset; for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) pass->attachments[i].desc = pCreateInfo->pAttachments[i]; uint32_t subpass_attachment_count = 0; for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { const VkSubpassDescription2 *desc = &pCreateInfo->pSubpasses[i]; subpass_attachment_count += num_subpass_attachments(desc); } if (subpass_attachment_count) { const size_t subpass_attachment_bytes = subpass_attachment_count * sizeof(struct v3dv_subpass_attachment); pass->subpass_attachments = vk_alloc2(&device->vk.alloc, pAllocator, subpass_attachment_bytes, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (pass->subpass_attachments == NULL) { vk_object_free(&device->vk, pAllocator, pass); return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); } } else { pass->subpass_attachments = NULL; } struct v3dv_subpass_attachment *p = pass->subpass_attachments; for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { const VkSubpassDescription2 *desc = &pCreateInfo->pSubpasses[i]; struct v3dv_subpass *subpass = &pass->subpasses[i]; subpass->input_count = desc->inputAttachmentCount; subpass->color_count = desc->colorAttachmentCount; subpass->view_mask = desc->viewMask; if (desc->inputAttachmentCount > 0) { subpass->input_attachments = p; p += desc->inputAttachmentCount; for (uint32_t j = 0; j < desc->inputAttachmentCount; j++) { subpass->input_attachments[j] = (struct v3dv_subpass_attachment) { .attachment = desc->pInputAttachments[j].attachment, .layout = desc->pInputAttachments[j].layout, }; } } if (desc->colorAttachmentCount > 0) { subpass->color_attachments = p; p += desc->colorAttachmentCount; for (uint32_t j = 0; j < desc->colorAttachmentCount; j++) { subpass->color_attachments[j] = (struct v3dv_subpass_attachment) { .attachment = desc->pColorAttachments[j].attachment, .layout = desc->pColorAttachments[j].layout, }; } } if (desc->pResolveAttachments) { subpass->resolve_attachments = p; p += desc->colorAttachmentCount; for (uint32_t j = 0; j < desc->colorAttachmentCount; j++) { subpass->resolve_attachments[j] = (struct v3dv_subpass_attachment) { .attachment = desc->pResolveAttachments[j].attachment, .layout = desc->pResolveAttachments[j].layout, }; } } if (desc->pDepthStencilAttachment) { subpass->ds_attachment = (struct v3dv_subpass_attachment) { .attachment = desc->pDepthStencilAttachment->attachment, .layout = desc->pDepthStencilAttachment->layout, }; check_do_depth_stencil_clear_with_draw(device, pass, subpass); /* VK_KHR_depth_stencil_resolve */ const VkSubpassDescriptionDepthStencilResolve *resolve_desc = vk_find_struct_const(desc->pNext, SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE); const VkAttachmentReference2 *resolve_att = resolve_desc && resolve_desc->pDepthStencilResolveAttachment && resolve_desc->pDepthStencilResolveAttachment->attachment != VK_ATTACHMENT_UNUSED ? resolve_desc->pDepthStencilResolveAttachment : NULL; if (resolve_att) { subpass->ds_resolve_attachment = (struct v3dv_subpass_attachment) { .attachment = resolve_att->attachment, .layout = resolve_att->layout, }; assert(resolve_desc->depthResolveMode == VK_RESOLVE_MODE_SAMPLE_ZERO_BIT || resolve_desc->stencilResolveMode == VK_RESOLVE_MODE_SAMPLE_ZERO_BIT); subpass->resolve_depth = resolve_desc->depthResolveMode != VK_RESOLVE_MODE_NONE && resolve_att->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT; subpass->resolve_stencil = resolve_desc->stencilResolveMode != VK_RESOLVE_MODE_NONE && resolve_att->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT; } else { subpass->ds_resolve_attachment.attachment = VK_ATTACHMENT_UNUSED; subpass->resolve_depth = false; subpass->resolve_stencil = false; } } else { subpass->ds_attachment.attachment = VK_ATTACHMENT_UNUSED; subpass->ds_resolve_attachment.attachment = VK_ATTACHMENT_UNUSED; subpass->resolve_depth = false; subpass->resolve_stencil = false; } } pass_find_subpass_range_for_attachments(device, pass); /* FIXME: handle subpass dependencies */ *pRenderPass = v3dv_render_pass_to_handle(pass); return VK_SUCCESS; } VKAPI_ATTR void VKAPI_CALL v3dv_DestroyRenderPass(VkDevice _device, VkRenderPass _pass, const VkAllocationCallbacks *pAllocator) { V3DV_FROM_HANDLE(v3dv_device, device, _device); V3DV_FROM_HANDLE(v3dv_render_pass, pass, _pass); if (!_pass) return; vk_free2(&device->vk.alloc, pAllocator, pass->subpass_attachments); vk_object_free(&device->vk, pAllocator, pass); } static void get_granularity(struct v3dv_device *device, uint32_t count, const VkFormat *formats, bool msaa, VkExtent2D *granularity) { uint32_t max_internal_bpp = 0; uint32_t total_color_bpp = 0; for (int i = 0; i < count; i++) { const struct v3dv_format *format = v3dv_X(device, get_format)(formats[i]); assert(format); /* We don't support rendering to YCbCr images */ assert(format->plane_count == 1); uint32_t internal_type, internal_bpp; v3dv_X(device, get_internal_type_bpp_for_output_format) (format->planes[0].rt_type, &internal_type, &internal_bpp); max_internal_bpp = MAX2(max_internal_bpp, internal_bpp); total_color_bpp += 4 * v3d_internal_bpp_words(internal_bpp); } /* If requested, double-buffer may or may not be enabled depending on * heuristics so we choose a conservative granularity here, with it disabled. */ uint32_t width, height; v3d_choose_tile_size(&device->devinfo, count, max_internal_bpp, total_color_bpp, msaa, false /* double-buffer */, &width, &height); *granularity = (VkExtent2D) { .width = width, .height = height }; } static void subpass_get_granularity(struct v3dv_device *device, struct v3dv_render_pass *pass, uint32_t subpass_idx, VkExtent2D *granularity) { /* Granularity is defined by the tile size */ assert(subpass_idx < pass->subpass_count); struct v3dv_subpass *subpass = &pass->subpasses[subpass_idx]; const uint32_t subpass_color_count = subpass->color_count; assert(subpass_color_count <= V3D_MAX_DRAW_BUFFERS); VkFormat formats[V3D_MAX_DRAW_BUFFERS]; bool msaa = false; uint32_t color_count = 0; for (uint32_t i = 0; i < subpass_color_count; i++) { uint32_t attachment_idx = subpass->color_attachments[i].attachment; if (attachment_idx == VK_ATTACHMENT_UNUSED) continue; const VkAttachmentDescription2 *desc = &pass->attachments[attachment_idx].desc; formats[color_count++] = desc->format; if (desc->samples > VK_SAMPLE_COUNT_1_BIT) msaa = true; } get_granularity(device, color_count, formats, msaa, granularity); } VKAPI_ATTR void VKAPI_CALL v3dv_GetRenderAreaGranularity(VkDevice _device, VkRenderPass renderPass, VkExtent2D *pGranularity) { V3DV_FROM_HANDLE(v3dv_render_pass, pass, renderPass); V3DV_FROM_HANDLE(v3dv_device, device, _device); *pGranularity = (VkExtent2D) { .width = 64, .height = 64, }; for (uint32_t i = 0; i < pass->subpass_count; i++) { VkExtent2D sg; subpass_get_granularity(device, pass, i, &sg); pGranularity->width = MIN2(pGranularity->width, sg.width); pGranularity->height = MIN2(pGranularity->height, sg.height); } } /* This is for dynamic rendering, introduced with VK_KHR_maintenance5 */ VKAPI_ATTR void VKAPI_CALL v3dv_GetRenderingAreaGranularityKHR(VkDevice _device, const VkRenderingAreaInfoKHR *pRenderingAreaInfo, VkExtent2D *pGranularity) { V3DV_FROM_HANDLE(v3dv_device, device, _device); /* Since VkRenderingAreaInfoKHR doesn't include information about MSAA we * choose to compute granularity as if it was disabled which would give us * the largest granularity (worst case). */ get_granularity(device, pRenderingAreaInfo->colorAttachmentCount, pRenderingAreaInfo->pColorAttachmentFormats, false /* msaa */, pGranularity); } /* Checks whether the render area rectangle covers a region that is aligned to * tile boundaries. This means that we are writing to all pixels covered by * all tiles in that area (except for pixels on edge tiles that are outside * the framebuffer dimensions). * * When our framebuffer is aligned to tile boundaries we know we are writing * valid data to all all pixels in each tile and we can apply certain * optimizations, like avoiding tile loads, since we know that none of the * original pixel values in each tile for that area need to be preserved. * We also use this to decide if we can use TLB clears, as these clear whole * tiles so we can't use them if the render area is not aligned. * * Note that when an image is created it will possibly include padding blocks * depending on its tiling layout. When the framebuffer dimensions are not * aligned to tile boundaries then edge tiles are only partially covered by the * framebuffer pixels, but tile stores still seem to store full tiles * writing to the padded sections. This is important when the framebuffer * is aliasing a smaller section of a larger image, as in that case the edge * tiles of the framebuffer would overwrite valid pixels in the larger image. * In that case, we can't flag the area as being aligned. */ bool v3dv_subpass_area_is_tile_aligned(struct v3dv_device *device, const VkRect2D *area, struct v3dv_framebuffer *fb, struct v3dv_render_pass *pass, uint32_t subpass_idx) { assert(subpass_idx < pass->subpass_count); VkExtent2D granularity; subpass_get_granularity(device, pass, subpass_idx, &granularity); return area->offset.x % granularity.width == 0 && area->offset.y % granularity.height == 0 && (area->extent.width % granularity.width == 0 || (fb->has_edge_padding && area->offset.x + area->extent.width >= fb->width)) && (area->extent.height % granularity.height == 0 || (fb->has_edge_padding && area->offset.y + area->extent.height >= fb->height)); } static void setup_dynamic_attachment(struct v3dv_device *device, struct v3dv_render_pass_attachment *att, const VkRenderingAttachmentInfo *info, bool is_stencil, bool is_resolve) { struct v3dv_image_view *view = v3dv_image_view_from_handle(info->imageView); VkAttachmentLoadOp load_op, stencil_load_op; VkAttachmentStoreOp store_op, stencil_store_op; if (!is_stencil) { stencil_load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE; stencil_store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE; if (!is_resolve) { load_op = info->loadOp; store_op = info->storeOp; } else { load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE; store_op = VK_ATTACHMENT_STORE_OP_STORE; } } else { load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE; store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE; if (!is_resolve) { stencil_load_op = info->loadOp; stencil_store_op = info->storeOp; } else { stencil_load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE; stencil_store_op = VK_ATTACHMENT_STORE_OP_STORE; } } att->desc = (VkAttachmentDescription2) { .sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, .flags = 0, .format = view->vk.format, .samples = view->vk.image->samples, .loadOp = load_op, .storeOp = store_op, .stencilLoadOp = stencil_load_op, .stencilStoreOp = stencil_store_op, .initialLayout = info->imageLayout, .finalLayout = info->imageLayout, }; if (is_resolve) set_try_tlb_resolve(device, att); } void v3dv_setup_dynamic_render_pass(struct v3dv_cmd_buffer *cmd_buffer, const VkRenderingInfoKHR *info) { struct v3dv_device *device = cmd_buffer->device; struct v3dv_cmd_buffer_state *state = &cmd_buffer->state; struct v3dv_render_pass *pass = &state->dynamic_pass; struct v3dv_subpass *subpass = &state->dynamic_subpass; struct v3dv_render_pass_attachment *pass_attachments = &state->dynamic_attachments[0]; struct v3dv_subpass_attachment *subpass_attachments = &state->dynamic_subpass_attachments[0]; memset(pass, 0, sizeof(*pass)); memset(subpass, 0, sizeof(*subpass)); memset(pass_attachments, 0, sizeof(state->dynamic_subpass_attachments)); memset(subpass_attachments, 0, sizeof(state->dynamic_subpass_attachments)); vk_object_base_init(&device->vk, (struct vk_object_base *) pass, VK_OBJECT_TYPE_RENDER_PASS); pass->attachments = pass_attachments; pass->subpass_attachments = subpass_attachments; subpass->view_mask = info->viewMask; subpass->color_count = info->colorAttachmentCount; subpass->color_attachments = &subpass_attachments[0]; subpass->resolve_attachments = &subpass_attachments[subpass->color_count]; pass->multiview_enabled = info->viewMask != 0; pass->subpass_count = 1; pass->subpasses = subpass; int a = 0; for (int i = 0; i < info->colorAttachmentCount; i++) { struct v3dv_render_pass_attachment *att = &pass->attachments[a]; const VkRenderingAttachmentInfo *att_info = &info->pColorAttachments[i]; if (att_info->imageView == VK_NULL_HANDLE) { subpass->color_attachments[i].attachment = VK_ATTACHMENT_UNUSED; subpass->resolve_attachments[i].attachment = VK_ATTACHMENT_UNUSED; continue; } setup_dynamic_attachment(device, att, att_info, false, false); subpass->color_attachments[i].attachment = a++; subpass->color_attachments[i].layout = att_info->imageLayout; if (att_info->resolveMode != VK_RESOLVE_MODE_NONE) { struct v3dv_render_pass_attachment *resolve_att = &pass->attachments[a]; setup_dynamic_attachment(device, resolve_att, att_info, false, true); subpass->resolve_attachments[i].attachment = a++; subpass->resolve_attachments[i].layout = att_info->resolveImageLayout; } else { subpass->resolve_attachments[i].attachment = VK_ATTACHMENT_UNUSED; } } bool has_depth = info->pDepthAttachment && info->pDepthAttachment->imageView != VK_NULL_HANDLE; bool has_stencil = info->pStencilAttachment && info->pStencilAttachment->imageView != VK_NULL_HANDLE; if (has_depth || has_stencil) { struct v3dv_render_pass_attachment *att = &pass->attachments[a]; subpass->ds_attachment.attachment = a++; bool has_depth_resolve = false; bool has_stencil_resolve = false; if (has_depth) { setup_dynamic_attachment(device, att, info->pDepthAttachment, false, false); subpass->ds_attachment.layout = info->pDepthAttachment->imageLayout; has_depth_resolve = info->pDepthAttachment->resolveMode != VK_RESOLVE_MODE_NONE; } if (has_stencil) { if (has_depth) { att->desc.stencilLoadOp = info->pStencilAttachment->loadOp; att->desc.stencilStoreOp = info->pStencilAttachment->storeOp; } else { setup_dynamic_attachment(device, att, info->pStencilAttachment, true, false); subpass->ds_attachment.layout = info->pStencilAttachment->imageLayout; } has_stencil_resolve = info->pStencilAttachment->resolveMode != VK_RESOLVE_MODE_NONE; } if (has_depth_resolve || has_stencil_resolve) { struct v3dv_render_pass_attachment *att = &pass->attachments[a]; subpass->ds_resolve_attachment.attachment = a++; if (has_depth_resolve) { setup_dynamic_attachment(device, att, info->pDepthAttachment, false, true); subpass->ds_resolve_attachment.layout = info->pDepthAttachment->resolveImageLayout; subpass->resolve_depth = true; } if (has_stencil_resolve) { if (has_depth_resolve) { att->desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; att->desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; } else { setup_dynamic_attachment(device, att, info->pStencilAttachment, true, true); subpass->ds_resolve_attachment.layout = info->pStencilAttachment->resolveImageLayout; } subpass->resolve_stencil = true; } } else { subpass->ds_resolve_attachment.attachment = VK_ATTACHMENT_UNUSED; } } else { subpass->ds_attachment.attachment = VK_ATTACHMENT_UNUSED; } check_do_depth_stencil_clear_with_draw(device, pass, subpass); pass->attachment_count = a; } void v3dv_setup_dynamic_render_pass_inheritance(struct v3dv_cmd_buffer *cmd_buffer, const VkCommandBufferInheritanceRenderingInfo *info) { struct v3dv_device *device = cmd_buffer->device; struct v3dv_cmd_buffer_state *state = &cmd_buffer->state; struct v3dv_render_pass *pass = &state->dynamic_pass; struct v3dv_subpass *subpass = &state->dynamic_subpass; struct v3dv_render_pass_attachment *pass_attachments = &state->dynamic_attachments[0]; struct v3dv_subpass_attachment *subpass_attachments = &state->dynamic_subpass_attachments[0]; memset(pass, 0, sizeof(*pass)); memset(subpass, 0, sizeof(*subpass)); memset(pass_attachments, 0, sizeof(state->dynamic_subpass_attachments)); memset(subpass_attachments, 0, sizeof(state->dynamic_subpass_attachments)); vk_object_base_init(&device->vk, (struct vk_object_base *) pass, VK_OBJECT_TYPE_RENDER_PASS); pass->attachments = pass_attachments; pass->subpass_attachments = subpass_attachments; subpass->view_mask = info->viewMask; subpass->color_count = info->colorAttachmentCount; subpass->color_attachments = &subpass_attachments[0]; subpass->resolve_attachments = NULL; pass->multiview_enabled = info->viewMask != 0; pass->subpass_count = 1; pass->subpasses = subpass; int a = 0; for (int i = 0; i < info->colorAttachmentCount; i++) { struct v3dv_render_pass_attachment *att = &pass->attachments[a]; const VkFormat format = info->pColorAttachmentFormats[i]; if (format == VK_FORMAT_UNDEFINED) { subpass->color_attachments[i].attachment = VK_ATTACHMENT_UNUSED; continue; } /* We don't have info about load/store, so we assume we load and we * store. */ att->desc.format = format; att->desc.samples = info->rasterizationSamples; att->desc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; att->desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; att->desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; att->desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; subpass->color_attachments[i].attachment = a++; } if (info->depthAttachmentFormat != VK_FORMAT_UNDEFINED || info->stencilAttachmentFormat != VK_FORMAT_UNDEFINED) { struct v3dv_render_pass_attachment *att = &pass->attachments[a]; att->desc.format = info->depthAttachmentFormat != VK_FORMAT_UNDEFINED ? info->depthAttachmentFormat : info->stencilAttachmentFormat; att->desc.samples = info->rasterizationSamples; if (vk_format_has_depth(att->desc.format)) { att->desc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; att->desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; } else { att->desc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; att->desc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; } if (vk_format_has_stencil(att->desc.format)) { att->desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; att->desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; } else { att->desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; att->desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; } subpass->ds_attachment.attachment = a++; } else { subpass->ds_attachment.attachment = VK_ATTACHMENT_UNUSED; } pass->attachment_count = a; }