summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIago Toral Quiroga <itoral@igalia.com>2020-03-31 12:59:44 +0200
committerMarge Bot <eric+marge@anholt.net>2020-10-13 21:21:29 +0000
commit7a39e5e9022958b68af55d06ae0e48ae20a93b17 (patch)
treea65cfa18bdc4acdebbcf208a7f0598e880ccd82c
parent152a64185b2a3e9b92478e22a164851e661c1c08 (diff)
v3dv: implement partial color attachment clears
This is achieved by rendering a quad in the clear color for each layer of each attachment being cleared. Right now we emit each clear in a separate job with a single attachment framebuffer, but in the future we may be able to extend the solution to using multiple render targets and clear multiple attachments with a single job. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>
-rw-r--r--src/broadcom/vulkan/v3dv_cmd_buffer.c78
-rw-r--r--src/broadcom/vulkan/v3dv_device.c2
-rw-r--r--src/broadcom/vulkan/v3dv_meta_clear.c494
-rw-r--r--src/broadcom/vulkan/v3dv_pipeline.c6
-rw-r--r--src/broadcom/vulkan/v3dv_private.h31
5 files changed, 587 insertions, 24 deletions
diff --git a/src/broadcom/vulkan/v3dv_cmd_buffer.c b/src/broadcom/vulkan/v3dv_cmd_buffer.c
index c32b5c4c8c2..d6175936b59 100644
--- a/src/broadcom/vulkan/v3dv_cmd_buffer.c
+++ b/src/broadcom/vulkan/v3dv_cmd_buffer.c
@@ -72,12 +72,6 @@ v3dv_job_add_extra_bo(struct v3dv_job *job, struct v3dv_bo *bo)
_mesa_set_add(job->extra_bos, bo);
}
-static struct v3dv_job *
-subpass_start(struct v3dv_cmd_buffer *cmd_buffer, uint32_t subpass_idx);
-
-static void
-subpass_finish(struct v3dv_cmd_buffer *cmd_buffer);
-
static void
cmd_buffer_emit_render_pass_rcl(struct v3dv_cmd_buffer *cmd_buffer);
@@ -133,6 +127,9 @@ cmd_buffer_init(struct v3dv_cmd_buffer *cmd_buffer,
assert(pool);
list_addtail(&cmd_buffer->pool_link, &pool->cmd_buffers);
+ cmd_buffer->state.subpass_idx = -1;
+ cmd_buffer->state.meta.subpass_idx = -1;
+
cmd_buffer->status = V3DV_CMD_BUFFER_STATUS_INITIALIZED;
}
@@ -887,7 +884,7 @@ v3dv_CmdBeginRenderPass(VkCommandBuffer commandBuffer,
state->render_area = pRenderPassBegin->renderArea;
/* Setup for first subpass */
- subpass_start(cmd_buffer, 0);
+ v3dv_cmd_buffer_subpass_start(cmd_buffer, 0);
}
void
@@ -899,10 +896,10 @@ v3dv_CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents)
assert(state->subpass_idx < state->pass->subpass_count - 1);
/* Finish the previous subpass */
- subpass_finish(cmd_buffer);
+ v3dv_cmd_buffer_subpass_finish(cmd_buffer);
/* Start the next subpass */
- subpass_start(cmd_buffer, state->subpass_idx + 1);
+ v3dv_cmd_buffer_subpass_start(cmd_buffer, state->subpass_idx + 1);
}
void
@@ -1517,8 +1514,9 @@ cmd_buffer_emit_render_pass_rcl(struct v3dv_cmd_buffer *cmd_buffer)
cl_emit(rcl, END_OF_RENDERING, end);
}
-static struct v3dv_job *
-subpass_start(struct v3dv_cmd_buffer *cmd_buffer, uint32_t subpass_idx)
+struct v3dv_job *
+v3dv_cmd_buffer_subpass_start(struct v3dv_cmd_buffer *cmd_buffer,
+ uint32_t subpass_idx)
{
struct v3dv_cmd_buffer_state *state = &cmd_buffer->state;
assert(subpass_idx < state->pass->subpass_count);
@@ -1568,8 +1566,8 @@ subpass_start(struct v3dv_cmd_buffer *cmd_buffer, uint32_t subpass_idx)
return job;
}
-static void
-subpass_finish(struct v3dv_cmd_buffer *cmd_buffer)
+void
+v3dv_cmd_buffer_subpass_finish(struct v3dv_cmd_buffer *cmd_buffer)
{
struct v3dv_job *job = cmd_buffer->state.job;
assert(job);
@@ -1584,7 +1582,7 @@ v3dv_CmdEndRenderPass(VkCommandBuffer commandBuffer)
/* Emit last subpass */
struct v3dv_cmd_buffer_state *state = &cmd_buffer->state;
assert(state->subpass_idx == state->pass->subpass_count - 1);
- subpass_finish(cmd_buffer);
+ v3dv_cmd_buffer_subpass_finish(cmd_buffer);
v3dv_cmd_buffer_finish_job(cmd_buffer);
/* We are no longer inside a render pass */
@@ -2507,6 +2505,55 @@ emit_gl_shader_state(struct v3dv_cmd_buffer *cmd_buffer)
V3DV_CMD_DIRTY_PUSH_CONSTANTS);
}
+/* This stores command buffer state for the current subpass that we are
+ * about to interrupt to emit a meta pass.
+ */
+void
+v3dv_cmd_buffer_meta_state_push(struct v3dv_cmd_buffer *cmd_buffer)
+{
+ struct v3dv_cmd_buffer_state *state = &cmd_buffer->state;
+ assert(state->subpass_idx != -1);
+
+ state->meta.pipeline = v3dv_pipeline_to_handle(state->pipeline);
+ state->meta.framebuffer = v3dv_framebuffer_to_handle(state->framebuffer);
+ state->meta.pass = v3dv_render_pass_to_handle(state->pass);
+ state->meta.subpass_idx = state->subpass_idx;
+}
+
+/* This resstores command buffer state for a subpass that we interrupted to
+ * emit a meta pass.
+ */
+void
+v3dv_cmd_buffer_meta_state_pop(struct v3dv_cmd_buffer *cmd_buffer)
+{
+ struct v3dv_cmd_buffer_state *state = &cmd_buffer->state;
+ assert(state->meta.subpass_idx != -1);
+
+ state->pass = v3dv_render_pass_from_handle(state->meta.pass);
+ state->framebuffer = v3dv_framebuffer_from_handle(state->meta.framebuffer);
+
+ struct v3dv_job *job =
+ v3dv_cmd_buffer_subpass_start(cmd_buffer, state->meta.subpass_idx);
+ if (job) {
+ job->is_subpass_continue = true;
+ if (state->meta.pipeline != VK_NULL_HANDLE) {
+ v3dv_CmdBindPipeline(v3dv_cmd_buffer_to_handle(cmd_buffer),
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ state->meta.pipeline);
+ } else {
+ state->pipeline = VK_NULL_HANDLE;
+ }
+ } else {
+ state->pipeline = VK_NULL_HANDLE;
+ state->subpass_idx = -1;
+ }
+
+ state->meta.pipeline = VK_NULL_HANDLE;
+ state->meta.framebuffer = VK_NULL_HANDLE;
+ state->meta.pass = VK_NULL_HANDLE;
+ state->meta.subpass_idx = -1;
+}
+
/* FIXME: C&P from v3dx_draw. Refactor to common place? */
static uint32_t
v3d_hw_prim_type(enum pipe_prim_type prim_type)
@@ -2583,7 +2630,8 @@ cmd_buffer_pre_draw_split_job(struct v3dv_cmd_buffer *cmd_buffer)
/* Now start a new job in the same subpass and flag it as continuing
* the current subpass.
*/
- job = subpass_start(cmd_buffer, cmd_buffer->state.subpass_idx);
+ job = v3dv_cmd_buffer_subpass_start(cmd_buffer,
+ cmd_buffer->state.subpass_idx);
assert(job->draw_count == 0);
job->is_subpass_continue = true;
diff --git a/src/broadcom/vulkan/v3dv_device.c b/src/broadcom/vulkan/v3dv_device.c
index 0374f70ee1b..d7814b0829f 100644
--- a/src/broadcom/vulkan/v3dv_device.c
+++ b/src/broadcom/vulkan/v3dv_device.c
@@ -1111,7 +1111,7 @@ v3dv_CreateDevice(VkPhysicalDevice physicalDevice,
return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED);
}
- device = vk_alloc2(&physical_device->instance->alloc, pAllocator,
+ device = vk_zalloc2(&physical_device->instance->alloc, pAllocator,
sizeof(*device), 8,
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
if (!device)
diff --git a/src/broadcom/vulkan/v3dv_meta_clear.c b/src/broadcom/vulkan/v3dv_meta_clear.c
index 03c88678ed1..3aba40461e3 100644
--- a/src/broadcom/vulkan/v3dv_meta_clear.c
+++ b/src/broadcom/vulkan/v3dv_meta_clear.c
@@ -24,21 +24,503 @@
#include "v3dv_private.h"
#include "broadcom/cle/v3dx_pack.h"
+#include "compiler/nir/nir_builder.h"
#include "vk_format_info.h"
+static nir_ssa_def *
+gen_rect_vertices(nir_builder *b)
+{
+ nir_intrinsic_instr *vertex_id =
+ nir_intrinsic_instr_create(b->shader,
+ nir_intrinsic_load_vertex_id);
+ nir_ssa_dest_init(&vertex_id->instr, &vertex_id->dest, 1, 32, "vertexid");
+ nir_builder_instr_insert(b, &vertex_id->instr);
+
+
+ /* vertex 0: -1.0, -1.0
+ * vertex 1: -1.0, 1.0
+ * vertex 2: 1.0, -1.0
+ * vertex 3: 1.0, 1.0
+ *
+ * so:
+ *
+ * channel 0 is vertex_id < 2 ? -1.0 : 1.0
+ * channel 1 is vertex id & 1 ? 1.0 : -1.0
+ */
+
+ nir_ssa_def *one = nir_imm_int(b, 1);
+ nir_ssa_def *c0cmp = nir_ilt(b, &vertex_id->dest.ssa, nir_imm_int(b, 2));
+ nir_ssa_def *c1cmp = nir_ieq(b, nir_iand(b, &vertex_id->dest.ssa, one), one);
+
+ nir_ssa_def *comp[4];
+ comp[0] = nir_bcsel(b, c0cmp,
+ nir_imm_float(b, -1.0f),
+ nir_imm_float(b, 1.0f));
+
+ comp[1] = nir_bcsel(b, c1cmp,
+ nir_imm_float(b, 1.0f),
+ nir_imm_float(b, -1.0f));
+ comp[2] = nir_imm_float(b, 0.0f);
+ comp[3] = nir_imm_float(b, 1.0f);
+ return nir_vec(b, comp, 4);
+}
+
+static nir_shader *
+get_color_clear_rect_vs()
+{
+ nir_builder b;
+ const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
+ nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_VERTEX, options);
+ b.shader->info.name = ralloc_strdup(b.shader, "meta clear vs");
+
+ const struct glsl_type *vec4 = glsl_vec4_type();
+ nir_variable *vs_out_pos =
+ nir_variable_create(b.shader, nir_var_shader_out, vec4, "gl_Position");
+ vs_out_pos->data.location = VARYING_SLOT_POS;
+
+ nir_ssa_def *pos = gen_rect_vertices(&b);
+ nir_store_var(&b, vs_out_pos, pos, 0xf);
+
+ return b.shader;
+}
+
+static nir_shader *
+get_color_clear_rect_fs(struct v3dv_render_pass *pass, uint32_t rt_idx)
+{
+ nir_builder b;
+ const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
+ nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, options);
+ b.shader->info.name = ralloc_strdup(b.shader, "meta clear fs");
+
+ /* Since our implementation can only clear one RT at a time we know there
+ * is a single subpass with a single attachment.
+ */
+ assert(pass->attachment_count == 1);
+ enum pipe_format pformat =
+ vk_format_to_pipe_format(pass->attachments[0].desc.format);
+ const struct glsl_type *fs_out_type =
+ util_format_is_float(pformat) ? glsl_vec4_type() : glsl_uvec4_type();
+
+ nir_variable *fs_out_color =
+ nir_variable_create(b.shader, nir_var_shader_out, fs_out_type, "out_color");
+ fs_out_color->data.location = FRAG_RESULT_DATA0 + rt_idx;
+
+ nir_intrinsic_instr *color_load =
+ nir_intrinsic_instr_create(b.shader, nir_intrinsic_load_push_constant);
+ nir_intrinsic_set_base(color_load, 0);
+ nir_intrinsic_set_range(color_load, 16);
+ color_load->src[0] = nir_src_for_ssa(nir_imm_int(&b, 0));
+ color_load->num_components = 4;
+ nir_ssa_dest_init(&color_load->instr, &color_load->dest, 4, 32, "clear color");
+ nir_builder_instr_insert(&b, &color_load->instr);
+
+ nir_store_var(&b, fs_out_color, &color_load->dest.ssa, 0xf);
+
+ return b.shader;
+}
+
+static VkResult
+create_color_clear_pipeline_layout(struct v3dv_device *device,
+ VkPipelineLayout *pipeline_layout)
+{
+ VkPipelineLayoutCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+ .setLayoutCount = 0,
+ .pushConstantRangeCount = 1,
+ .pPushConstantRanges =
+ &(VkPushConstantRange) { VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16 },
+ };
+
+ return v3dv_CreatePipelineLayout(v3dv_device_to_handle(device),
+ &info, &device->alloc, pipeline_layout);
+}
+
+static VkResult
+create_pipeline(struct v3dv_device *device,
+ struct v3dv_render_pass *pass,
+ uint32_t samples,
+ struct nir_shader *vs_nir,
+ struct nir_shader *fs_nir,
+ const VkPipelineVertexInputStateCreateInfo *vi_state,
+ const VkPipelineDepthStencilStateCreateInfo *ds_state,
+ const VkPipelineColorBlendStateCreateInfo *cb_state,
+ const VkPipelineLayout layout,
+ VkPipeline *pipeline)
+{
+ struct v3dv_shader_module vs_m = { .nir = vs_nir };
+ struct v3dv_shader_module fs_m = { .nir = fs_nir };
+
+ VkPipelineShaderStageCreateInfo stages[2] = {
+ {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ .stage = VK_SHADER_STAGE_VERTEX_BIT,
+ .module = v3dv_shader_module_to_handle(&vs_m),
+ .pName = "main",
+ },
+ {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .module = v3dv_shader_module_to_handle(&fs_m),
+ .pName = "main",
+ },
+ };
+
+ VkGraphicsPipelineCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+
+ .stageCount = 2,
+ .pStages = stages,
+
+ .pVertexInputState = vi_state,
+
+ .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+ .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+ .primitiveRestartEnable = false,
+ },
+
+ .pViewportState = &(VkPipelineViewportStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+ .viewportCount = 1,
+ .scissorCount = 1,
+ },
+
+ .pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+ .rasterizerDiscardEnable = false,
+ .polygonMode = VK_POLYGON_MODE_FILL,
+ .cullMode = VK_CULL_MODE_NONE,
+ .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
+ .depthBiasEnable = false,
+ },
+
+ .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+ .rasterizationSamples = samples,
+ .sampleShadingEnable = false,
+ .pSampleMask = NULL,
+ .alphaToCoverageEnable = false,
+ .alphaToOneEnable = false,
+ },
+
+ .pDepthStencilState = ds_state,
+
+ .pColorBlendState = cb_state,
+
+ /* The meta clear pipeline declares all state as dynamic.
+ * As a consequence, vkCmdBindPipeline writes no dynamic state
+ * to the cmd buffer. Therefore, at the end of the meta clear,
+ * we need only restore dynamic state that was vkCmdSet.
+ *
+ * FIXME: Update this when we support more dynamic states (adding
+ * them now will assert because they are not supported).
+ */
+ .pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+ .dynamicStateCount = 6,
+ .pDynamicStates = (VkDynamicState[]) {
+ VK_DYNAMIC_STATE_VIEWPORT,
+ VK_DYNAMIC_STATE_SCISSOR,
+ VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
+ VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
+ VK_DYNAMIC_STATE_STENCIL_REFERENCE,
+ VK_DYNAMIC_STATE_BLEND_CONSTANTS,
+#if 0
+ VK_DYNAMIC_STATE_LINE_WIDTH,
+ VK_DYNAMIC_STATE_DEPTH_BIAS,
+ VK_DYNAMIC_STATE_DEPTH_BOUNDS,
+#endif
+ },
+ },
+
+ .flags = 0,
+ .layout = layout,
+ .renderPass = v3dv_render_pass_to_handle(pass),
+ .subpass = 0,
+ };
+
+ VkResult result =
+ v3dv_CreateGraphicsPipelines(v3dv_device_to_handle(device),
+ VK_NULL_HANDLE,
+ 1, &info,
+ &device->alloc,
+ pipeline);
+
+ ralloc_free(vs_nir);
+ ralloc_free(fs_nir);
+
+ return result;
+}
+
+static VkResult
+create_color_clear_pipeline(struct v3dv_device *device,
+ uint32_t rt_idx,
+ uint32_t samples,
+ VkRenderPass _pass,
+ VkPipelineLayout *pipeline_layout,
+ VkPipeline *pipeline)
+{
+ /* For now we only support clearing a framebuffer with a single attachment */
+ assert(rt_idx == 0);
+
+ struct v3dv_render_pass *pass = v3dv_render_pass_from_handle(_pass);
+
+ nir_shader *vs_nir = get_color_clear_rect_vs();
+ nir_shader *fs_nir = get_color_clear_rect_fs(pass, rt_idx);
+
+ const VkPipelineVertexInputStateCreateInfo vi_state = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = 0,
+ .vertexAttributeDescriptionCount = 0,
+ };
+
+ const VkPipelineDepthStencilStateCreateInfo ds_state = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
+ .depthTestEnable = false,
+ .depthWriteEnable = false,
+ .depthBoundsTestEnable = false,
+ .stencilTestEnable = false,
+ };
+
+ /* FIXME: for now our color clear pipeline can only clear a single RT,
+ * but in the future we might want to be able to support multiple render
+ * targets. If we do that, then we might also be able to implement partial
+ * color clearing for vkCmdClearAttachments without having to split the
+ * subpass job at all.
+ */
+ VkPipelineColorBlendAttachmentState blend_att_state[1] = { 0 };
+ blend_att_state[rt_idx] = (VkPipelineColorBlendAttachmentState) {
+ .blendEnable = false,
+ .colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
+ VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT |
+ VK_COLOR_COMPONENT_A_BIT,
+ };
+
+ const VkPipelineColorBlendStateCreateInfo cb_state = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+ .logicOpEnable = false,
+ .attachmentCount = 1,
+ .pAttachments = blend_att_state
+ };
+
+ VkResult result = create_color_clear_pipeline_layout(device, pipeline_layout);
+ if (result != VK_SUCCESS)
+ return result;
+
+ return create_pipeline(device,
+ pass,
+ samples,
+ vs_nir, fs_nir,
+ &vi_state,
+ &ds_state,
+ &cb_state,
+ *pipeline_layout,
+ pipeline);
+}
+
+static VkResult
+create_color_clear_render_pass(struct v3dv_device *device,
+ VkFormat format,
+ uint32_t samples,
+ VkRenderPass *pass)
+{
+ VkAttachmentDescription att = {
+ .format = format,
+ .samples = samples,
+ .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
+ .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+ .initialLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .finalLayout = VK_IMAGE_LAYOUT_GENERAL,
+ };
+
+ VkAttachmentReference att_ref = {
+ .attachment = 0,
+ .layout = VK_IMAGE_LAYOUT_GENERAL,
+ };
+
+ VkSubpassDescription subpass = {
+ .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+ .inputAttachmentCount = 0,
+ .colorAttachmentCount = 1,
+ .pColorAttachments = &att_ref,
+ .pResolveAttachments = NULL,
+ .pDepthStencilAttachment = NULL,
+ .preserveAttachmentCount = 0,
+ .pPreserveAttachments = NULL,
+ };
+
+ VkRenderPassCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+ .attachmentCount = 1,
+ .pAttachments = &att,
+ .subpassCount = 1,
+ .pSubpasses = &subpass,
+ .dependencyCount = 0,
+ .pDependencies = NULL,
+ };
+
+ return v3dv_CreateRenderPass(v3dv_device_to_handle(device),
+ &info, &device->alloc, pass);
+}
+
+static VkResult
+ensure_color_clear_pipeline(struct v3dv_device *device,
+ VkFormat format,
+ uint32_t samples)
+{
+ /* FIXME: we need a pipeline per [format, samples], right now this
+ * only works for the first combination we need.
+ */
+ VkResult result = VK_SUCCESS;
+ if (device->meta.color_clear.pipeline)
+ return result;
+
+ if (!device->meta.color_clear.pass) {
+ result =
+ create_color_clear_render_pass(device,
+ format,
+ samples,
+ &device->meta.color_clear.pass);
+ if (result != VK_SUCCESS)
+ return result;
+ }
+
+ if (!device->meta.color_clear.pipeline) {
+ result =
+ create_color_clear_pipeline(device, 0 /* rt_idx*/, samples,
+ device->meta.color_clear.pass,
+ &device->meta.color_clear.playout,
+ &device->meta.color_clear.pipeline);
+ if (result != VK_SUCCESS)
+ return result;
+ }
+
+ return result;
+}
+
static void
emit_color_clear_rect(struct v3dv_cmd_buffer *cmd_buffer,
- uint32_t rt,
+ uint32_t rt_idx,
VkClearColorValue clear_color,
- VkClearRect rect)
+ const VkClearRect *rect)
{
- assert(!"Not implemented.");
+ assert(cmd_buffer->state.pass);
+ struct v3dv_device *device = cmd_buffer->device;
+ struct v3dv_render_pass *pass = cmd_buffer->state.pass;
+ struct v3dv_subpass *subpass =
+ &pass->subpasses[cmd_buffer->state.subpass_idx];
+
+ assert(rt_idx < subpass->color_count);
+ uint32_t attachment_idx = subpass->color_attachments[rt_idx].attachment;
+ assert(attachment_idx != VK_ATTACHMENT_UNUSED &&
+ attachment_idx < pass->attachment_count);
+ VkFormat rt_format = pass->attachments[attachment_idx].desc.format;
+ const uint32_t rt_samples = pass->attachments[attachment_idx].desc.samples;
+
+ if (ensure_color_clear_pipeline(device, rt_format, rt_samples) != VK_SUCCESS)
+ return;
+
+ /* Store command buffer state for the current subpass before we interrupt
+ * it to emit the color clear pass and then finish the job for the
+ * interrupted subpass.
+ */
+ v3dv_cmd_buffer_meta_state_push(cmd_buffer);
+ v3dv_cmd_buffer_finish_job(cmd_buffer);
+
+ struct v3dv_framebuffer *subpass_fb =
+ v3dv_framebuffer_from_handle(cmd_buffer->state.meta.framebuffer);
+ VkCommandBuffer cmd_buffer_handle = v3dv_cmd_buffer_to_handle(cmd_buffer);
+ VkDevice device_handle = v3dv_device_to_handle(cmd_buffer->device);
+
+ /* Emit the pass for each attachment layer, which creates a framebuffer
+ * for each selected layer of the attachment and then renders a scissored
+ * quad in the clear color.
+ */
+ for (uint32_t i = 0; i < rect->layerCount; i++) {
+ struct v3dv_image_view attachment_layer_view;
+ memcpy(&attachment_layer_view,
+ subpass_fb->attachments[rt_idx],
+ sizeof(struct v3dv_image_view));
+ attachment_layer_view.first_layer += rect->baseArrayLayer + i;
+ attachment_layer_view.last_layer = attachment_layer_view.first_layer;
+ VkImageView fb_attachment =
+ v3dv_image_view_to_handle(&attachment_layer_view);
+
+ VkFramebufferCreateInfo fb_info = {
+ .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
+ .renderPass = v3dv_render_pass_to_handle(pass),
+ .attachmentCount = 1,
+ .pAttachments = &fb_attachment,
+ .width = subpass_fb->width,
+ .height = subpass_fb->height,
+ .layers = 1,
+ };
+
+ VkFramebuffer fb;
+ v3dv_CreateFramebuffer(device_handle, &fb_info,
+ &cmd_buffer->device->alloc, &fb);
+
+ VkRenderPassBeginInfo rp_info = {
+ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+ .renderPass = device->meta.color_clear.pass,
+ .framebuffer = fb,
+ .renderArea = { .offset = { 0, 0 },
+ .extent = { fb_info.width, fb_info.height } },
+ .clearValueCount = 0,
+ };
+
+ v3dv_CmdBeginRenderPass(cmd_buffer_handle, &rp_info,
+ VK_SUBPASS_CONTENTS_INLINE);
+
+ struct v3dv_job *job = cmd_buffer->state.job;
+ if (!job) {
+ v3dv_DestroyFramebuffer(device_handle, fb, NULL);
+ goto fail_job_start;
+ }
+ job->is_subpass_continue = true;
+
+ v3dv_CmdPushConstants(cmd_buffer_handle,
+ device->meta.color_clear.playout,
+ VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16,
+ &clear_color);
+
+ v3dv_CmdBindPipeline(cmd_buffer_handle,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ device->meta.color_clear.pipeline);
+
+ const VkViewport viewport = {
+ .x = rect->rect.offset.x,
+ .y = rect->rect.offset.y,
+ .width = rect->rect.extent.width,
+ .height = rect->rect.extent.height,
+ .minDepth = 0.0f,
+ .maxDepth = 1.0f
+ };
+ v3dv_CmdSetViewport(cmd_buffer_handle, 0, 1, &viewport);
+ v3dv_CmdSetScissor(cmd_buffer_handle, 0, 1, &rect->rect);
+
+ v3dv_CmdDraw(cmd_buffer_handle, 4, 1, 0, 0);
+
+ v3dv_CmdEndRenderPass(cmd_buffer_handle);
+
+ /* The Vulkan spec doesn't allow to destroy the framebuffer until all
+ * command buffers that use it have completed execution, however, in
+ * our particular case this is fine, since copy into all framebuffer
+ * info we need to submit and execute the job into the command buffer,
+ * so we don't need to keep the framebuffer object around.
+ */
+ v3dv_DestroyFramebuffer(device_handle, fb, &cmd_buffer->device->alloc);
+ }
+
+fail_job_start:
+ v3dv_cmd_buffer_meta_state_pop(cmd_buffer);
}
static void
emit_ds_clear_rect(struct v3dv_cmd_buffer *cmd_buffer,
VkClearDepthStencilValue clear_ds,
- VkClearRect rect)
+ const VkClearRect *rect)
{
assert(!"Not implemented.");
}
@@ -531,13 +1013,13 @@ v3dv_CmdClearAttachments(VkCommandBuffer commandBuffer,
emit_color_clear_rect(cmd_buffer,
rt_idx,
pAttachments[i].clearValue.color,
- pRects[j]);
+ &pRects[j]);
}
} else {
for (uint32_t j = 0; j < rectCount; j++) {
emit_ds_clear_rect(cmd_buffer,
pAttachments[i].clearValue.depthStencil,
- pRects[j]);
+ &pRects[j]);
}
}
}
diff --git a/src/broadcom/vulkan/v3dv_pipeline.c b/src/broadcom/vulkan/v3dv_pipeline.c
index c0ce412340e..7ff1d47fb62 100644
--- a/src/broadcom/vulkan/v3dv_pipeline.c
+++ b/src/broadcom/vulkan/v3dv_pipeline.c
@@ -192,6 +192,12 @@ const nir_shader_compiler_options v3dv_nir_options = {
* needs to be supported */
};
+const nir_shader_compiler_options *
+v3dv_pipeline_get_nir_options(void)
+{
+ return &v3dv_nir_options;
+}
+
#define OPT(pass, ...) ({ \
bool this_progress = false; \
NIR_PASS(this_progress, nir, pass, ##__VA_ARGS__); \
diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h
index ed6a99ce35d..c72bb6fc4f2 100644
--- a/src/broadcom/vulkan/v3dv_private.h
+++ b/src/broadcom/vulkan/v3dv_private.h
@@ -236,6 +236,15 @@ struct v3dv_device {
* the GPU is idle.
*/
uint32_t last_job_sync;
+
+ /* Resources used for meta operations */
+ struct {
+ struct {
+ VkPipelineLayout playout;
+ VkPipeline pipeline;
+ VkRenderPass pass;
+ } color_clear;
+ } meta;
};
struct v3dv_device_memory {
@@ -660,8 +669,8 @@ struct v3dv_descriptor_state {
};
struct v3dv_cmd_buffer_state {
- const struct v3dv_render_pass *pass;
- const struct v3dv_framebuffer *framebuffer;
+ struct v3dv_render_pass *pass;
+ struct v3dv_framebuffer *framebuffer;
VkRect2D render_area;
/* Current job being recorded */
@@ -684,6 +693,14 @@ struct v3dv_cmd_buffer_state {
/* Used to flag OOM conditions during command buffer recording */
bool oom;
+
+ /* Command buffer state saved during a meta operation */
+ struct {
+ uint32_t subpass_idx;
+ VkRenderPass pass;
+ VkPipeline pipeline;
+ VkFramebuffer framebuffer;
+ } meta;
};
struct v3dv_descriptor {
@@ -738,6 +755,14 @@ struct v3dv_job *v3dv_cmd_buffer_start_job(struct v3dv_cmd_buffer *cmd_buffer,
int32_t subpass_idx);
void v3dv_cmd_buffer_finish_job(struct v3dv_cmd_buffer *cmd_buffer);
+struct v3dv_job *v3dv_cmd_buffer_subpass_start(struct v3dv_cmd_buffer *cmd_buffer,
+ uint32_t subpass_idx);
+
+void v3dv_cmd_buffer_subpass_finish(struct v3dv_cmd_buffer *cmd_buffer);
+
+void v3dv_cmd_buffer_meta_state_push(struct v3dv_cmd_buffer *cmd_buffer);
+void v3dv_cmd_buffer_meta_state_pop(struct v3dv_cmd_buffer *cmd_buffer);
+
void v3dv_render_pass_setup_render_target(struct v3dv_cmd_buffer *cmd_buffer,
int rt,
uint32_t *rt_bpp,
@@ -1055,6 +1080,8 @@ struct v3dv_pipeline {
uint8_t stencil_cfg[2][cl_packet_length(STENCIL_CFG)];
};
+const nir_shader_compiler_options *v3dv_pipeline_get_nir_options(void);
+
static inline uint32_t
v3dv_zs_buffer_from_aspect_bits(VkImageAspectFlags aspects)
{