radeonsi: rewrite how small prim precision is passed to culling code
Instead of passing 2 different 4-bit precision values via the SGPR, pass the quant mode enum + log_samples as 3 bits, and 2-bit log_samples separately. This saves 3 bits in the SGPR, which we'll need for culling states. This completely changes how the small prim precision is computed from the state bits. Reviewed-by: Timur Kristóf <timur.kristof@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31865>
This commit is contained in:
@@ -262,6 +262,22 @@ static nir_def *get_num_vertices_per_prim(nir_builder *b, struct lower_abi_state
|
||||
return nir_iadd_imm(b, GET_FIELD_NIR(GS_STATE_OUTPRIM), 1);
|
||||
}
|
||||
|
||||
static nir_def *get_small_prim_precision(nir_builder *b, struct lower_abi_state *s, bool lines)
|
||||
{
|
||||
/* Compute FP32 value "num_samples / quant_mode" using integer ops.
|
||||
* See si_shader.h for how this works.
|
||||
*/
|
||||
struct si_shader_args *args = s->args;
|
||||
nir_def *precision = GET_FIELD_NIR(GS_STATE_SMALL_PRIM_PRECISION);
|
||||
nir_def *log_samples = GET_FIELD_NIR(GS_STATE_SMALL_PRIM_PRECISION_LOG_SAMPLES);
|
||||
|
||||
if (lines)
|
||||
precision = nir_iadd(b, precision, log_samples);
|
||||
|
||||
/* The final FP32 value is: 1/2^(15 - precision) */
|
||||
return nir_ishl_imm(b, nir_ior_imm(b, precision, 0x70), 23);
|
||||
}
|
||||
|
||||
static bool lower_intrinsic(nir_builder *b, nir_instr *instr, struct lower_abi_state *s)
|
||||
{
|
||||
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
|
||||
@@ -409,20 +425,12 @@ static bool lower_intrinsic(nir_builder *b, nir_instr *instr, struct lower_abi_s
|
||||
case nir_intrinsic_load_cull_front_face_enabled_amd:
|
||||
replacement = nir_imm_bool(b, key->ge.opt.ngg_culling & SI_NGG_CULL_FRONT_FACE);
|
||||
break;
|
||||
case nir_intrinsic_load_cull_small_triangle_precision_amd: {
|
||||
nir_def *small_prim_precision = GET_FIELD_NIR(GS_STATE_SMALL_PRIM_PRECISION);
|
||||
/* Extract the small prim precision. */
|
||||
small_prim_precision = nir_ior_imm(b, small_prim_precision, 0x70);
|
||||
replacement = nir_ishl_imm(b, small_prim_precision, 23);
|
||||
case nir_intrinsic_load_cull_small_triangle_precision_amd:
|
||||
replacement = get_small_prim_precision(b, s, false);
|
||||
break;
|
||||
}
|
||||
case nir_intrinsic_load_cull_small_line_precision_amd: {
|
||||
nir_def *small_prim_precision = GET_FIELD_NIR(GS_STATE_SMALL_PRIM_PRECISION_NO_AA);
|
||||
/* Extract the small prim precision. */
|
||||
small_prim_precision = nir_ior_imm(b, small_prim_precision, 0x70);
|
||||
replacement = nir_ishl_imm(b, small_prim_precision, 23);
|
||||
case nir_intrinsic_load_cull_small_line_precision_amd:
|
||||
replacement = get_small_prim_precision(b, s, true);
|
||||
break;
|
||||
}
|
||||
case nir_intrinsic_load_cull_small_triangles_enabled_amd:
|
||||
/* Triangles always have small primitive culling enabled. */
|
||||
replacement = nir_imm_bool(b, true);
|
||||
|
||||
@@ -749,7 +749,7 @@ struct si_framebuffer {
|
||||
|
||||
enum si_quant_mode
|
||||
{
|
||||
/* This is the list we want to support. */
|
||||
/* The small prim precision computation depends on the enum values to be like this. */
|
||||
SI_QUANT_MODE_16_8_FIXED_POINT_1_256TH,
|
||||
SI_QUANT_MODE_14_10_FIXED_POINT_1_1024TH,
|
||||
SI_QUANT_MODE_12_12_FIXED_POINT_1_4096TH,
|
||||
|
||||
@@ -244,17 +244,57 @@ enum
|
||||
*/
|
||||
#define GS_STATE_NUM_ES_OUTPUTS__SHIFT 13
|
||||
#define GS_STATE_NUM_ES_OUTPUTS__MASK 0x3f
|
||||
/* Small prim filter precision = num_samples / quant_mode, which can only be equal to 1/2^n
|
||||
* where n is between 4 and 12. Knowing that, we only need to store 4 bits of the FP32 exponent.
|
||||
* Set it like this: value = (fui(num_samples / quant_mode) >> 23) & 0xf;
|
||||
* Expand to FP32 like this: ((0x70 | value) << 23);
|
||||
* With 0x70 = 112, we get 2^(112 + value - 127) = 2^(value - 15), which is always a negative
|
||||
* exponent and it's equal to 1/2^(15 - value).
|
||||
/* Small prim filter precision = num_samples / quant_mode where num_samples is in {1, 2, 4, 8} and
|
||||
* quant_mode is in {256, 1024, 4096}, which is equal to 1/2^n where n is between 5 and 12.
|
||||
*
|
||||
* Equation 1: Represent the value as 1/2^n.
|
||||
* Assumption: log_samples <= 3 and log_quant_mode >= 8
|
||||
* num_samples / quant_mode =
|
||||
* 2^log_samples / 2^log_quant_mode =
|
||||
* 1 / 2^(log_quant_mode - log_samples) [because log_samples < log_quant_mode]
|
||||
*
|
||||
* Knowing that, we only need 4 bits to represent the FP32 exponent and thus the FP32 number.
|
||||
*
|
||||
* Equation 2: Encoding the exponent.
|
||||
* 1/2^(15 - value) in FP32 = ((value | 0x70) << 23) in binary if value < 15
|
||||
* Proof: With 0x70 = 112, we get FP32 exponent 2^(112 + value - 127) according to the FP32
|
||||
* definition, which can be simplified to 2^(value - 15), which is a negative exponent
|
||||
* for value < 15. Given that 2^-n = 1/2^n, the FP32 number is equal to 1/2^(15 - value).
|
||||
*
|
||||
* Equation 3: Convert quant_mode_enum to log_quant_mode.
|
||||
* quant_mode_enum:
|
||||
* 0 means 256 = 2^8 --> log2(256) = 8
|
||||
* 1 means 1024 = 2^10 --> log2(1024) = 10
|
||||
* 2 means 4096 = 2^12 --> log2(4096) = 12
|
||||
*
|
||||
* Conversion to log_quant_mode:
|
||||
* log_quant_mode = quant_mode_enum * 2 + 8. Proof:
|
||||
* 0 * 2 + 8 = 8
|
||||
* 1 * 2 + 8 = 10
|
||||
* 2 * 2 + 8 = 12
|
||||
*
|
||||
* Equation 4: Get the exponent value for Equation 2 from Equation 1.
|
||||
* 15 - value = log_quant_mode - log_samples
|
||||
* value = 15 - (log_quant_mode + log_samples)
|
||||
*
|
||||
* Combine equations 2, 3, and 4 to get the expression computing the FP32 number from log_samples
|
||||
* and quant_mode_enum using integer ops:
|
||||
* (value | 0x70) << 23 =
|
||||
* ((15 - (log_quant_mode + log_samples)) | 0x70) << 23 =
|
||||
* ((15 - (quant_mode_enum * 2 + 8 + log_samples)) | 0x70) << 23 =
|
||||
* ((15 - quant_mode_enum * 2 - 8 - log_samples) | 0x70) << 23 =
|
||||
* ((7 - quant_mode_enum * 2 - log_samples) | 0x70) << 23 =
|
||||
*
|
||||
* Since "log_samples <= 3" and "quant_mode_enum * 2 <= 4", we need a SGPR field that stores:
|
||||
* triangle_precision = 7 - quant_mode_enum * 2 - log_samples
|
||||
*
|
||||
* Line precision ignores log_samples, so the shader should do:
|
||||
* line_precision = triangle_precision + log_samples
|
||||
*/
|
||||
#define GS_STATE_SMALL_PRIM_PRECISION_NO_AA__SHIFT 19
|
||||
#define GS_STATE_SMALL_PRIM_PRECISION_NO_AA__MASK 0xf
|
||||
#define GS_STATE_SMALL_PRIM_PRECISION__SHIFT 23
|
||||
#define GS_STATE_SMALL_PRIM_PRECISION__MASK 0xf
|
||||
#define GS_STATE_SMALL_PRIM_PRECISION__SHIFT 22 /* triangle_precision */
|
||||
#define GS_STATE_SMALL_PRIM_PRECISION__MASK 0x7
|
||||
#define GS_STATE_SMALL_PRIM_PRECISION_LOG_SAMPLES__SHIFT 25
|
||||
#define GS_STATE_SMALL_PRIM_PRECISION_LOG_SAMPLES__MASK 0x3
|
||||
#define GS_STATE_STREAMOUT_QUERY_ENABLED__SHIFT 27
|
||||
#define GS_STATE_STREAMOUT_QUERY_ENABLED__MASK 0x1
|
||||
#define GS_STATE_PROVOKING_VTX_FIRST__SHIFT 28
|
||||
|
||||
@@ -94,7 +94,6 @@ static void si_emit_cull_state(struct si_context *sctx, unsigned index)
|
||||
sctx->last_small_prim_cull_info = info;
|
||||
}
|
||||
|
||||
/* This will end up in SGPR6 as (value << 8), shifted by the hw. */
|
||||
radeon_add_to_buffer_list(sctx, &sctx->gfx_cs, sctx->small_prim_cull_info_buf,
|
||||
RADEON_USAGE_READ | RADEON_PRIO_CONST_BUFFER);
|
||||
|
||||
@@ -117,35 +116,12 @@ static void si_emit_cull_state(struct si_context *sctx, unsigned index)
|
||||
* primitive culling. (more precision means a tighter bounding box
|
||||
* around primitives and more accurate elimination)
|
||||
*/
|
||||
unsigned quant_mode = sctx->viewports.as_scissor[0].quant_mode;
|
||||
float small_prim_precision_no_aa = 0;
|
||||
unsigned num_samples = si_get_num_coverage_samples(sctx);
|
||||
unsigned log_samples = util_logbase2(si_get_num_coverage_samples(sctx));
|
||||
unsigned precision = 7 - sctx->viewports.as_scissor[0].quant_mode * 2 - log_samples;
|
||||
assert((precision & ~0x7) == 0);
|
||||
|
||||
if (quant_mode == SI_QUANT_MODE_12_12_FIXED_POINT_1_4096TH)
|
||||
small_prim_precision_no_aa = 1.0 / 4096.0;
|
||||
else if (quant_mode == SI_QUANT_MODE_14_10_FIXED_POINT_1_1024TH)
|
||||
small_prim_precision_no_aa = 1.0 / 1024.0;
|
||||
else
|
||||
small_prim_precision_no_aa = 1.0 / 256.0;
|
||||
|
||||
float small_prim_precision = num_samples * small_prim_precision_no_aa;
|
||||
|
||||
/* Set VS_STATE.SMALL_PRIM_PRECISION for NGG culling.
|
||||
*
|
||||
* small_prim_precision is 1 / 2^n. We only need n between 5 (1/32) and 12 (1/4096).
|
||||
* Such a floating point value can be packed into 4 bits as follows:
|
||||
* If we pass the first 4 bits of the exponent to the shader and set the next 3 bits
|
||||
* to 1, we'll get the number exactly because all other bits are always 0. See:
|
||||
* 1
|
||||
* value = (0x70 | value.exponent[0:3]) << 23 = ------------------------------
|
||||
* 2 ^ (15 - value.exponent[0:3])
|
||||
*
|
||||
* So pass only the first 4 bits of the float exponent to the shader.
|
||||
*/
|
||||
SET_FIELD(sctx->current_gs_state, GS_STATE_SMALL_PRIM_PRECISION_NO_AA,
|
||||
(fui(small_prim_precision_no_aa) >> 23) & 0xf);
|
||||
SET_FIELD(sctx->current_gs_state, GS_STATE_SMALL_PRIM_PRECISION,
|
||||
(fui(small_prim_precision) >> 23) & 0xf);
|
||||
SET_FIELD(sctx->current_gs_state, GS_STATE_SMALL_PRIM_PRECISION, precision);
|
||||
SET_FIELD(sctx->current_gs_state, GS_STATE_SMALL_PRIM_PRECISION_LOG_SAMPLES, log_samples);
|
||||
}
|
||||
|
||||
static void si_set_scissor_states(struct pipe_context *pctx, unsigned start_slot,
|
||||
|
||||
Reference in New Issue
Block a user