mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 13:58:04 +02:00
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:
parent
152a64185b
commit
7a39e5e902
5 changed files with 587 additions and 24 deletions
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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__); \
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue