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>
This commit is contained in:
Iago Toral Quiroga 2020-03-31 12:59:44 +02:00 committed by Marge Bot
parent 152a64185b
commit 7a39e5e902
5 changed files with 587 additions and 24 deletions

View file

@ -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;

View file

@ -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)

View file

@ -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]);
}
}
}

View file

@ -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__); \

View file

@ -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)
{