diff --git a/src/imagination/vulkan/pvr_blit.c b/src/imagination/vulkan/pvr_blit.c index 36d4683ec82..9db22a38bdd 100644 --- a/src/imagination/vulkan/pvr_blit.c +++ b/src/imagination/vulkan/pvr_blit.c @@ -35,9 +35,10 @@ #include "pvr_shader_factory.h" #include "pvr_static_shaders.h" #include "pvr_types.h" +#include "util/bitscan.h" #include "util/list.h" #include "util/macros.h" -#include "util/bitscan.h" +#include "util/u_math.h" #include "vk_alloc.h" #include "vk_command_buffer.h" #include "vk_command_pool.h" @@ -1620,6 +1621,126 @@ static VkResult pvr_clear_color_attachment_static( return VK_SUCCESS; } +/** + * \brief Record a deferred clear operation into the command buffer. + * + * Devices which don't have gs_rta_support require extra handling for RTA + * clears. We setup a list of deferred clear transfer commands which will be + * processed at the end of the graphics sub command to account for the missing + * feature. + */ +static VkResult pvr_add_deferred_rta_clear(struct pvr_cmd_buffer *cmd_buffer, + const VkClearAttachment *attachment, + const VkClearRect *rect) +{ + struct pvr_render_pass_info *pass_info = &cmd_buffer->state.render_pass_info; + struct pvr_sub_cmd_gfx *sub_cmd = &cmd_buffer->state.current_sub_cmd->gfx; + const struct pvr_renderpass_hwsetup_render *hw_render = + &pass_info->pass->hw_setup->renders[sub_cmd->hw_render_idx]; + struct pvr_transfer_cmd *transfer_cmd_list; + const struct pvr_image_view *image_view; + const struct pvr_image *image; + uint32_t base_layer; + + const VkOffset3D offset = { + .x = rect->rect.offset.x, + .y = rect->rect.offset.y, + .z = 1, + }; + const VkExtent3D extent = { + .width = rect->rect.extent.width, + .height = rect->rect.extent.height, + .depth = 1, + }; + + assert( + !PVR_HAS_FEATURE(&cmd_buffer->device->pdevice->dev_info, gs_rta_support)); + + transfer_cmd_list = util_dynarray_grow(&cmd_buffer->deferred_clears, + struct pvr_transfer_cmd, + rect->layerCount); + if (!transfer_cmd_list) { + cmd_buffer->state.status = + vk_error(cmd_buffer, VK_ERROR_OUT_OF_HOST_MEMORY); + return cmd_buffer->state.status; + } + + /* From the Vulkan 1.3.229 spec VUID-VkClearAttachment-aspectMask-00019: + * + * "If aspectMask includes VK_IMAGE_ASPECT_COLOR_BIT, it must not + * include VK_IMAGE_ASPECT_DEPTH_BIT or VK_IMAGE_ASPECT_STENCIL_BIT" + * + */ + if (attachment->aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) { + assert(attachment->aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT || + attachment->aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT || + attachment->aspectMask == + (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)); + + image_view = pass_info->attachments[hw_render->ds_attach_idx]; + } else { + const struct pvr_renderpass_hwsetup_subpass *hw_pass = + pvr_get_hw_subpass(pass_info->pass, pass_info->subpass_idx); + const struct pvr_render_subpass *sub_pass = + &pass_info->pass->subpasses[hw_pass->index]; + const uint32_t attachment_idx = + sub_pass->color_attachments[attachment->colorAttachment]; + + assert(attachment->colorAttachment < sub_pass->color_count); + + image_view = pass_info->attachments[attachment_idx]; + } + + base_layer = image_view->vk.base_array_layer + rect->baseArrayLayer; + image = vk_to_pvr_image(image_view->vk.image); + + for (uint32_t i = 0; i < rect->layerCount; i++) { + struct pvr_transfer_cmd *transfer_cmd = &transfer_cmd_list[i]; + + /* TODO: Add an init function for when we don't want to use + * pvr_transfer_cmd_alloc()? And use it here. + */ + *transfer_cmd = (struct pvr_transfer_cmd){ + .flags = PVR_TRANSFER_CMD_FLAGS_FILL, + .source_count = 1, + .sources = { + [0] = { + .filter = PVR_FILTER_POINT, + .resolve_op = PVR_RESOLVE_BLEND, + .addr_mode = PVRX(TEXSTATE_ADDRMODE_CLAMP_TO_EDGE), + }, + }, + .cmd_buffer = cmd_buffer, + }; + + if (attachment->aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) { + for (uint32_t i = 0; i < ARRAY_SIZE(transfer_cmd->clear_color); i++) { + transfer_cmd->clear_color[i].ui = + attachment->clearValue.color.uint32[i]; + } + } else { + transfer_cmd->clear_color[0].f = + attachment->clearValue.depthStencil.depth; + transfer_cmd->clear_color[1].ui = + attachment->clearValue.depthStencil.stencil; + } + + pvr_setup_transfer_surface(cmd_buffer->device, + &transfer_cmd->sources[0].surface, + &transfer_cmd->scissor, + image, + base_layer + i, + 0, + &offset, + &extent, + 0.0f, + image->vk.format, + attachment->aspectMask); + } + + return VK_SUCCESS; +} + static void pvr_clear_attachments(struct pvr_cmd_buffer *cmd_buffer, uint32_t attachment_count, const VkClearAttachment *attachments, @@ -1811,7 +1932,10 @@ static void pvr_clear_attachments(struct pvr_cmd_buffer *cmd_buffer, if (!PVR_HAS_FEATURE(dev_info, gs_rta_support) && (clear_rect->baseArrayLayer != 0 || clear_rect->layerCount > 1)) { - pvr_finishme("Add deferred RTA clear."); + result = + pvr_add_deferred_rta_clear(cmd_buffer, attachment, clear_rect); + if (result != VK_SUCCESS) + return; if (clear_rect->baseArrayLayer != 0) continue; diff --git a/src/imagination/vulkan/pvr_cmd_buffer.c b/src/imagination/vulkan/pvr_cmd_buffer.c index c7444ad673f..7ca8393a5ae 100644 --- a/src/imagination/vulkan/pvr_cmd_buffer.c +++ b/src/imagination/vulkan/pvr_cmd_buffer.c @@ -155,6 +155,7 @@ static void pvr_cmd_buffer_free_resources(struct pvr_cmd_buffer *cmd_buffer) pvr_bo_free(cmd_buffer->device, bo); } + util_dynarray_fini(&cmd_buffer->deferred_clears); util_dynarray_fini(&cmd_buffer->deferred_csb_commands); util_dynarray_fini(&cmd_buffer->scissor_array); util_dynarray_fini(&cmd_buffer->depth_bias_array); @@ -222,6 +223,7 @@ static VkResult pvr_cmd_buffer_create(struct pvr_device *device, util_dynarray_init(&cmd_buffer->depth_bias_array, NULL); util_dynarray_init(&cmd_buffer->scissor_array, NULL); util_dynarray_init(&cmd_buffer->deferred_csb_commands, NULL); + util_dynarray_init(&cmd_buffer->deferred_clears, NULL); cmd_buffer->state.status = VK_SUCCESS; @@ -1681,6 +1683,24 @@ void pvr_compute_generate_fence(struct pvr_cmd_buffer *cmd_buffer, pvr_compute_generate_control_stream(csb, sub_cmd, &info); } +static VkResult +pvr_cmd_buffer_process_deferred_clears(struct pvr_cmd_buffer *cmd_buffer) +{ + util_dynarray_foreach (&cmd_buffer->deferred_clears, + struct pvr_transfer_cmd, + transfer_cmd) { + VkResult result; + + result = pvr_cmd_buffer_add_transfer_cmd(cmd_buffer, transfer_cmd); + if (result != VK_SUCCESS) + return result; + + cmd_buffer->state.current_sub_cmd->transfer.serialize_with_frag = true; + } + + return VK_SUCCESS; +} + VkResult pvr_cmd_buffer_end_sub_cmd(struct pvr_cmd_buffer *cmd_buffer) { struct pvr_cmd_buffer_state *state = &cmd_buffer->state; @@ -1755,6 +1775,10 @@ VkResult pvr_cmd_buffer_end_sub_cmd(struct pvr_cmd_buffer *cmd_buffer) * sub_cmd->gfx.empty_cmd flag. */ + /* TODO: Set the state in the functions called with the command buffer + * instead of here. + */ + result = pvr_cmd_buffer_upload_tables(device, cmd_buffer, gfx_sub_cmd); if (result != VK_SUCCESS) { state->status = result; @@ -1792,6 +1816,12 @@ VkResult pvr_cmd_buffer_end_sub_cmd(struct pvr_cmd_buffer *cmd_buffer) return result; } + result = pvr_cmd_buffer_process_deferred_clears(cmd_buffer); + if (result != VK_SUCCESS) { + state->status = result; + return result; + } + break; } @@ -6812,8 +6842,10 @@ pvr_execute_graphics_cmd_buffer(struct pvr_cmd_buffer *cmd_buffer, primary_sub_cmd->gfx.empty_cmd = false; } - if (!PVR_HAS_FEATURE(dev_info, gs_rta_support)) - pvr_finishme("Unimplemented path."); + if (!PVR_HAS_FEATURE(dev_info, gs_rta_support)) { + util_dynarray_append_dynarray(&cmd_buffer->deferred_clears, + &sec_cmd_buffer->deferred_clears); + } } return VK_SUCCESS; diff --git a/src/imagination/vulkan/pvr_private.h b/src/imagination/vulkan/pvr_private.h index 772f4100f19..e2ec38be5cc 100644 --- a/src/imagination/vulkan/pvr_private.h +++ b/src/imagination/vulkan/pvr_private.h @@ -851,6 +851,10 @@ struct pvr_cmd_buffer { * execute in secondary command buffer. */ struct util_dynarray deferred_csb_commands; + /* List of struct pvr_transfer_cmd used to emulate RTA clears on non RTA + * capable cores. + */ + struct util_dynarray deferred_clears; /* List of pvr_bo structs associated with this cmd buffer. */ struct list_head bo_list;