diff --git a/src/intel/compiler/brw/brw_compile_fs.cpp b/src/intel/compiler/brw/brw_compile_fs.cpp index 3148a4d2955..da8dd583277 100644 --- a/src/intel/compiler/brw/brw_compile_fs.cpp +++ b/src/intel/compiler/brw/brw_compile_fs.cpp @@ -870,7 +870,9 @@ brw_nir_populate_fs_prog_data(nir_shader *shader, assert(devinfo->verx10 >= 200 || key->provoking_vertex_last == INTEL_NEVER); prog_data->provoking_vertex_last = key->provoking_vertex_last; - prog_data->uses_sample_mask = + prog_data->uses_fully_covered = + BITSET_TEST(shader->info.system_values_read, SYSTEM_VALUE_FULLY_COVERED); + prog_data->uses_sample_mask = prog_data->uses_fully_covered || BITSET_TEST(shader->info.system_values_read, SYSTEM_VALUE_SAMPLE_MASK_IN); /* From the Ivy Bridge PRM documentation for 3DSTATE_PS: diff --git a/src/intel/compiler/brw/brw_compiler.h b/src/intel/compiler/brw/brw_compiler.h index 0b2f1326f84..c9beecb204b 100644 --- a/src/intel/compiler/brw/brw_compiler.h +++ b/src/intel/compiler/brw/brw_compiler.h @@ -570,6 +570,7 @@ struct brw_fs_prog_data { bool uses_vmask; bool has_side_effects; bool pulls_bary; + bool uses_fully_covered; /** * Whether nonperspective interpolation modes are used by the @@ -700,7 +701,9 @@ brw_fs_prog_data_is_dynamic(const struct brw_fs_prog_data *prog_data) prog_data->alpha_to_coverage == INTEL_SOMETIMES || prog_data->coarse_pixel_dispatch == INTEL_SOMETIMES || prog_data->persample_dispatch == INTEL_SOMETIMES || - prog_data->conservative_raster == INTEL_SOMETIMES; + /* We only care as long as fully covered is used */ + (prog_data->conservative_raster == INTEL_SOMETIMES && + prog_data->uses_fully_covered); } #ifdef GFX_VERx10 diff --git a/src/intel/compiler/brw/brw_nir.c b/src/intel/compiler/brw/brw_nir.c index cc8045a1fb0..e2e7cab6811 100644 --- a/src/intel/compiler/brw/brw_nir.c +++ b/src/intel/compiler/brw/brw_nir.c @@ -1555,6 +1555,8 @@ brw_nir_lower_fs_inputs(nir_shader *nir, if (brw_needs_vertex_attributes_bypass(nir)) brw_nir_lower_fs_barycentrics(nir); + NIR_PASS(_, nir, brw_nir_lower_fully_covered); + if (devinfo->ver >= 11) NIR_PASS(_, nir, brw_nir_lower_frag_shading_rate); diff --git a/src/intel/compiler/brw/brw_nir.h b/src/intel/compiler/brw/brw_nir.h index 5f44d14774d..bb509e77099 100644 --- a/src/intel/compiler/brw/brw_nir.h +++ b/src/intel/compiler/brw/brw_nir.h @@ -155,6 +155,7 @@ bool brw_nir_lower_cs_subgroup_id(nir_shader *nir, bool brw_nir_lower_alpha_to_coverage(nir_shader *shader); bool brw_needs_vertex_attributes_bypass(const nir_shader *shader); void brw_nir_lower_fs_barycentrics(nir_shader *shader); +bool brw_nir_lower_fully_covered(nir_shader *nir); struct brw_lower_urb_cb_data { const struct intel_device_info *devinfo; diff --git a/src/intel/compiler/brw/brw_nir_lower_fully_covered.c b/src/intel/compiler/brw/brw_nir_lower_fully_covered.c new file mode 100644 index 00000000000..7bcc2ea100c --- /dev/null +++ b/src/intel/compiler/brw/brw_nir_lower_fully_covered.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2025 Intel Corporation + * SPDX-License-Identifier: MIT + */ + +#include "compiler/nir/nir_builder.h" +#include "brw_nir.h" + +static nir_def * +load_expected_mask(nir_builder *b) +{ + nir_def *sample_count = nir_load_msaa_rate_intel(b); + + /* A coarse fragment is fully covered if all the pixels that compose it are + * fully covered themselves. + * If we are not dealing with coarse pixels, frag_size will be 1x1, and so + * coarse_sample_count == sample_count. + */ + nir_def *frag_size = nir_load_frag_shading_rate_intel(b); + nir_def *coarse_sample_count = nir_imul(b, + sample_count, + nir_imul(b, + nir_channel(b, frag_size, 0), + nir_channel(b, frag_size, 1))); + + return nir_bfm(b, coarse_sample_count, nir_imm_int(b, 0)); +} + +static bool +lower_fully_covered(nir_builder *b, nir_intrinsic_instr *intrin, void *data) +{ + if (intrin->intrinsic != nir_intrinsic_load_fully_covered) + return false; + + b->cursor = nir_after_instr(&intrin->instr); + + nir_def *coverage_mask = nir_load_coverage_mask_intel(b); + nir_def *expected_mask = load_expected_mask(b); + + nir_def *fully_covered = nir_ieq(b, coverage_mask, expected_mask); + + nir_def *fs_config = nir_load_fs_config_intel(b); + nir_def *cons_raster_on = + nir_test_mask(b, fs_config, INTEL_FS_CONFIG_CONSERVATIVE_RASTER); + + fully_covered = nir_bcsel(b, cons_raster_on, fully_covered, nir_imm_false(b)); + + nir_def_replace(&intrin->def, fully_covered); + + return true; +} + +bool +brw_nir_lower_fully_covered(nir_shader *nir) +{ + if (!BITSET_TEST(nir->info.system_values_read, SYSTEM_VALUE_FULLY_COVERED)) + return false; + + return nir_shader_intrinsics_pass(nir, lower_fully_covered, + nir_metadata_control_flow, NULL); +} diff --git a/src/intel/compiler/brw/meson.build b/src/intel/compiler/brw/meson.build index 11def2115b9..7e38c61c1c3 100644 --- a/src/intel/compiler/brw/meson.build +++ b/src/intel/compiler/brw/meson.build @@ -58,6 +58,7 @@ libintel_compiler_brw_files = files( 'brw_nir_lower_alpha_to_coverage.c', 'brw_nir_lower_fs_barycentrics.c', 'brw_nir_lower_fs_load_output.c', + 'brw_nir_lower_fully_covered.c', 'brw_nir_lower_immediate_offsets.c', 'brw_nir_lower_intersection_shader.c', 'brw_nir_lower_ray_queries.c', diff --git a/src/intel/vulkan/genX_gfx_state.c b/src/intel/vulkan/genX_gfx_state.c index b4dcb021420..bad0f962e7c 100644 --- a/src/intel/vulkan/genX_gfx_state.c +++ b/src/intel/vulkan/genX_gfx_state.c @@ -1094,6 +1094,8 @@ update_ps_extra_wm(struct anv_gfx_dynamic_state *hw_state, assert(!fs_prog_data->inner_coverage); /* Not available in SPIR-V */ if (!fs_prog_data->uses_sample_mask) InputCoverageMaskState = ICMS_NONE; + else if (fs_prog_data->uses_fully_covered) + InputCoverageMaskState = ICMS_INNER_CONSERVATIVE; else if (fs_prog_data->post_depth_coverage) InputCoverageMaskState = ICMS_DEPTH_COVERAGE; else