v3dv: don't be too aggressive disabling early Z

When we have a draw call that is incompatible with EZ we should only
disable EZ for the remaining of the job in the case that both of the
following conditions are met:

1. The cause for the incompatibility is an incompatible depth test
   direction.

2. The pipeline does Z writes.

Otherwise it is enough to disable EZ temporarily only for draw calls
with the incompatible pipeline.

Reviewed-by: Alejandro Piñeiro <apinheiro@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16794>
This commit is contained in:
Iago Toral Quiroga 2022-05-30 11:28:50 +02:00
parent 2f7f4060ee
commit 0f65838933
3 changed files with 55 additions and 27 deletions

View file

@ -2882,6 +2882,7 @@ pipeline_set_ez_state(struct v3dv_pipeline *pipeline,
break;
default:
pipeline->ez_state = V3D_EZ_DISABLED;
pipeline->incompatible_ez_test = true;
break;
}
@ -2891,6 +2892,14 @@ pipeline_set_ez_state(struct v3dv_pipeline *pipeline,
!stencil_op_is_no_op(&ds_info->back))) {
pipeline->ez_state = V3D_EZ_DISABLED;
}
/* If the FS writes Z, then it may update against the chosen EZ direction */
struct v3dv_shader_variant *fs_variant =
pipeline->shared_data->variants[BROADCOM_SHADER_FRAGMENT];
if (fs_variant && fs_variant->prog_data.fs->writes_z &&
!fs_variant->prog_data.fs->writes_z_from_fep) {
pipeline->ez_state = V3D_EZ_DISABLED;
}
}
static bool
@ -3047,7 +3056,6 @@ pipeline_init(struct v3dv_pipeline *pipeline,
rs_info, pv_info, ls_info,
ms_info);
pipeline_set_ez_state(pipeline, ds_info);
enable_depth_bias(pipeline, rs_info);
pipeline_set_sample_mask(pipeline, ms_info);
pipeline_set_sample_rate_shading(pipeline, ms_info);
@ -3082,6 +3090,9 @@ pipeline_init(struct v3dv_pipeline *pipeline,
pipeline->default_attribute_values = NULL;
}
/* This must be done after the pipeline has been compiled */
pipeline_set_ez_state(pipeline, ds_info);
return result;
}

View file

@ -1913,6 +1913,11 @@ struct v3dv_pipeline {
enum v3dv_ez_state ez_state;
/* If ez_state is V3D_EZ_DISABLED, if the reason for disabling is that the
* pipeline selects an incompatible depth test function.
*/
bool incompatible_ez_test;
bool msaa;
bool sample_rate_shading;
uint32_t sample_mask;

View file

@ -1400,7 +1400,10 @@ v3dX(cmd_buffer_emit_varyings_state)(struct v3dv_cmd_buffer *cmd_buffer)
}
}
static void
/* Updates job early Z state tracking. Returns False if EZ must be disabled
* for the current draw call.
*/
static bool
job_update_ez_state(struct v3dv_job *job,
struct v3dv_pipeline *pipeline,
struct v3dv_cmd_buffer *cmd_buffer)
@ -1414,9 +1417,15 @@ job_update_ez_state(struct v3dv_job *job,
*/
if (job->first_ez_state == V3D_EZ_DISABLED) {
assert(job->ez_state == V3D_EZ_DISABLED);
return;
return false;
}
/* If ez_state is V3D_EZ_DISABLED it means that we have already decided
* that EZ must be disabled for the remaining of the frame.
*/
if (job->ez_state == V3D_EZ_DISABLED)
return false;
/* This is part of the pre draw call handling, so we should be inside a
* render pass.
*/
@ -1436,7 +1445,7 @@ job_update_ez_state(struct v3dv_job *job,
if (subpass->ds_attachment.attachment == VK_ATTACHMENT_UNUSED) {
job->first_ez_state = V3D_EZ_DISABLED;
job->ez_state = V3D_EZ_DISABLED;
return;
return false;
}
/* GFXH-1918: the early-z buffer may load incorrect depth values
@ -1465,7 +1474,7 @@ job_update_ez_state(struct v3dv_job *job,
"without framebuffer info disables early-z tests.\n");
job->first_ez_state = V3D_EZ_DISABLED;
job->ez_state = V3D_EZ_DISABLED;
return;
return false;
}
if (((fb->width % 2) != 0 || (fb->height % 2) != 0)) {
@ -1473,7 +1482,7 @@ job_update_ez_state(struct v3dv_job *job,
"or height disables early-Z tests.\n");
job->first_ez_state = V3D_EZ_DISABLED;
job->ez_state = V3D_EZ_DISABLED;
return;
return false;
}
}
}
@ -1481,16 +1490,8 @@ job_update_ez_state(struct v3dv_job *job,
/* Otherwise, we can decide to selectively enable or disable EZ for draw
* calls using the CFG_BITS packet based on the bound pipeline state.
*/
/* If the FS writes Z, then it may update against the chosen EZ direction */
struct v3dv_shader_variant *fs_variant =
pipeline->shared_data->variants[BROADCOM_SHADER_FRAGMENT];
if (fs_variant->prog_data.fs->writes_z &&
!fs_variant->prog_data.fs->writes_z_from_fep) {
job->ez_state = V3D_EZ_DISABLED;
return;
}
bool disable_ez = false;
bool incompatible_test = false;
switch (pipeline->ez_state) {
case V3D_EZ_UNDECIDED:
/* If the pipeline didn't pick a direction but didn't disable, then go
@ -1504,24 +1505,35 @@ job_update_ez_state(struct v3dv_job *job,
/* If the pipeline picked a direction, then it needs to match the current
* direction if we've decided on one.
*/
if (job->ez_state == V3D_EZ_UNDECIDED)
if (job->ez_state == V3D_EZ_UNDECIDED) {
job->ez_state = pipeline->ez_state;
else if (job->ez_state != pipeline->ez_state)
job->ez_state = V3D_EZ_DISABLED;
} else if (job->ez_state != pipeline->ez_state) {
disable_ez = true;
incompatible_test = true;
}
break;
case V3D_EZ_DISABLED:
/* If the pipeline disables EZ because of a bad Z func or stencil
* operation, then we can't do any more EZ in this frame.
*/
job->ez_state = V3D_EZ_DISABLED;
disable_ez = true;
incompatible_test = pipeline->incompatible_ez_test;
break;
}
if (job->first_ez_state == V3D_EZ_UNDECIDED &&
job->ez_state != V3D_EZ_DISABLED) {
if (job->first_ez_state == V3D_EZ_UNDECIDED && !disable_ez) {
assert(job->ez_state != V3D_EZ_DISABLED);
job->first_ez_state = job->ez_state;
}
/* If we had to disable EZ because of an incompatible test direction and
* and the pipeline writes depth then we need to disable EZ for the rest of
* the frame.
*/
if (incompatible_test && pipeline->z_updates_enable) {
assert(disable_ez);
job->ez_state = V3D_EZ_DISABLED;
}
return !disable_ez;
}
void
@ -1533,13 +1545,13 @@ v3dX(cmd_buffer_emit_configuration_bits)(struct v3dv_cmd_buffer *cmd_buffer)
struct v3dv_pipeline *pipeline = cmd_buffer->state.gfx.pipeline;
assert(pipeline);
job_update_ez_state(job, pipeline, cmd_buffer);
bool enable_ez = job_update_ez_state(job, pipeline, cmd_buffer);
v3dv_cl_ensure_space_with_branch(&job->bcl, cl_packet_length(CFG_BITS));
v3dv_return_if_oom(cmd_buffer, NULL);
cl_emit_with_prepacked(&job->bcl, CFG_BITS, pipeline->cfg_bits, config) {
config.early_z_enable = job->ez_state != V3D_EZ_DISABLED;
config.early_z_enable = enable_ez;
config.early_z_updates_enable = config.early_z_enable &&
pipeline->z_updates_enable;
}