diff --git a/src/compiler/shader_enums.h b/src/compiler/shader_enums.h index ac0aed2d124..cd944193ac7 100644 --- a/src/compiler/shader_enums.h +++ b/src/compiler/shader_enums.h @@ -98,6 +98,19 @@ gl_shader_stage_is_callable(gl_shader_stage stage) stage == MESA_SHADER_CALLABLE; } +static inline bool +gl_shader_stage_can_set_fragment_shading_rate(gl_shader_stage stage) +{ + /* According to EXT_fragment_shading_rate : + * + * "This extension adds support for setting the fragment shading rate + * for a primitive in vertex, geometry, and mesh shading stages" + */ + return stage == MESA_SHADER_VERTEX || + stage == MESA_SHADER_GEOMETRY || + stage == MESA_SHADER_MESH; +} + /** * Number of STATE_* values we need to address any GL state. * Used to dimension arrays. diff --git a/src/intel/compiler/brw_nir.c b/src/intel/compiler/brw_nir.c index 080cc09bf11..9998edfc735 100644 --- a/src/intel/compiler/brw_nir.c +++ b/src/intel/compiler/brw_nir.c @@ -1110,6 +1110,9 @@ brw_postprocess_nir(nir_shader *nir, const struct brw_compiler *compiler, OPT(nir_lower_idiv, &options); } + if (gl_shader_stage_can_set_fragment_shading_rate(nir->info.stage)) + brw_nir_lower_shading_rate_output(nir); + brw_nir_optimize(nir, compiler, is_scalar, false); if (is_scalar && nir_shader_has_local_variables(nir)) { diff --git a/src/intel/compiler/brw_nir.h b/src/intel/compiler/brw_nir.h index 3f4d56dcd49..59b65301fb2 100644 --- a/src/intel/compiler/brw_nir.h +++ b/src/intel/compiler/brw_nir.h @@ -120,6 +120,8 @@ bool brw_nir_lower_conversions(nir_shader *nir); bool brw_nir_lower_scoped_barriers(nir_shader *nir); +bool brw_nir_lower_shading_rate_output(nir_shader *nir); + bool brw_nir_lower_storage_image(nir_shader *nir, const struct intel_device_info *devinfo); diff --git a/src/intel/compiler/brw_nir_lower_shading_rate_output.c b/src/intel/compiler/brw_nir_lower_shading_rate_output.c new file mode 100644 index 00000000000..951c78e4c85 --- /dev/null +++ b/src/intel/compiler/brw_nir_lower_shading_rate_output.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* + * Lower the shading rate output from the bit field format described in the + * SPIRV spec : + * + * bit | name | description + * 0 | Vertical2Pixels | Fragment invocation covers 2 pixels vertically + * 1 | Vertical4Pixels | Fragment invocation covers 4 pixels vertically + * 2 | Horizontal2Pixels | Fragment invocation covers 2 pixels horizontally + * 3 | Horizontal4Pixels | Fragment invocation covers 4 pixels horizontally + * + * into a single dword composed of 2 fp16 to be stored in the dword 0 of the + * VUE header. + * + * When no horizontal/vertical bits are set, the size in pixel size in that + * dimension is assumed to be 1. + * + * According to the specification, the shading rate output can be read & + * written. A read after a write should report a different value if the + * implemention decides on different primitive shading rate for some reason. + * This is never the case in our implementation. + */ + +#include "brw_nir.h" +#include "compiler/nir/nir_builder.h" + +static bool +lower_shading_rate_output_instr(nir_builder *b, nir_instr *instr, + UNUSED void *_state) +{ + if (instr->type != nir_instr_type_intrinsic) + return false; + + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + if (intrin->intrinsic != nir_intrinsic_load_output && + intrin->intrinsic != nir_intrinsic_store_output) + return false; + + if (nir_intrinsic_base(intrin) != VARYING_SLOT_PRIMITIVE_SHADING_RATE) + return false; + + b->cursor = intrin->intrinsic == nir_intrinsic_load_output ? + nir_after_instr(instr) : nir_before_instr(instr); + + if (intrin->intrinsic == nir_intrinsic_store_output) { + assert(intrin->src[0].is_ssa); + nir_ssa_def *bit_field = intrin->src[0].ssa; + nir_ssa_def *fp16_x = + nir_i2f16(b, + nir_ishl(b, nir_imm_int(b, 1), + nir_ishr_imm(b, bit_field, 2))); + nir_ssa_def *fp16_y = + nir_i2f16(b, + nir_ishl(b, nir_imm_int(b, 1), + nir_iand_imm(b, bit_field, 0x3))); + nir_ssa_def *packed_fp16_xy = nir_pack_32_2x16_split(b, fp16_x, fp16_y); + + nir_instr_rewrite_src(instr, &intrin->src[0], + nir_src_for_ssa(packed_fp16_xy)); + } else { + assert(intrin->intrinsic == nir_intrinsic_load_output); + nir_ssa_def *packed_fp16_xy = &intrin->dest.ssa; + + nir_ssa_def *u32_x = + nir_i2i32(b, nir_unpack_32_2x16_split_x(b, packed_fp16_xy)); + nir_ssa_def *u32_y = + nir_i2i32(b, nir_unpack_32_2x16_split_y(b, packed_fp16_xy)); + + nir_ssa_def *bit_field = + nir_ior(b, nir_ishl_imm(b, nir_ushr_imm(b, u32_x, 1), 2), + nir_ushr_imm(b, u32_y, 1)); + + nir_ssa_def_rewrite_uses_after(packed_fp16_xy, bit_field, + bit_field->parent_instr); + } + + return true; +} + +bool +brw_nir_lower_shading_rate_output(nir_shader *nir) +{ + /* TODO(mesh): Add Shading Rate support. */ + assert(nir->info.stage != MESA_SHADER_MESH); + + return nir_shader_instructions_pass(nir, lower_shading_rate_output_instr, + nir_metadata_block_index | + nir_metadata_dominance, NULL); +} diff --git a/src/intel/compiler/meson.build b/src/intel/compiler/meson.build index a180d8cd2a2..8668d082d83 100644 --- a/src/intel/compiler/meson.build +++ b/src/intel/compiler/meson.build @@ -90,6 +90,7 @@ libintel_compiler_files = files( 'brw_nir_lower_rt_intrinsics.c', 'brw_nir_lower_scoped_barriers.c', 'brw_nir_lower_shader_calls.c', + 'brw_nir_lower_shading_rate_output.c', 'brw_nir_lower_storage_image.c', 'brw_nir_opt_peephole_ffma.c', 'brw_nir_rt.h',