nvk: Emit FSR state

This is mostly a matter of filling out the
VARIABLE_PIXEL_SHADING_INDEX_TO_RATE tables.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31585>
This commit is contained in:
Faith Ekstrand
2024-10-07 17:45:57 -05:00
committed by Marge Bot
parent 55854de584
commit 16bd3f0f50
4 changed files with 279 additions and 5 deletions
+247 -3
View File
@@ -406,6 +406,7 @@ nvk_push_draw_state_init(struct nvk_queue *queue, struct nv_push *p)
P_IMMD(p, NV9097, SET_VIEWPORT_PIXEL, CENTER_AT_HALF_INTEGERS);
P_IMMD(p, NV9097, SET_MME_SHADOW_SCRATCH(NVK_MME_SCRATCH_SHADING_RATE_CONTROL), 0);
P_IMMD(p, NV9097, SET_MME_SHADOW_SCRATCH(NVK_MME_SCRATCH_ANTI_ALIAS),
nvk_mme_anti_alias_init());
@@ -2140,6 +2141,251 @@ nvk_flush_rs_state(struct nvk_cmd_buffer *cmd)
}
}
uint32_t
nvk_mme_shading_rate_control_sample_shading(bool sample_shading)
{
return nvk_mme_val_mask((!sample_shading) << 1, 1 << 1);
}
static uint32_t
nvk_mme_shading_rate_control_enable(bool enable)
{
return nvk_mme_val_mask(enable, 1 << 0);
}
void
nvk_mme_set_shading_rate_control(struct mme_builder *b)
{
if (b->devinfo->cls_eng3d < TURING_A)
return;
struct mme_value val_mask = mme_load(b);
struct mme_value old_src = nvk_mme_load_scratch(b, SHADING_RATE_CONTROL);
struct mme_value src = nvk_mme_set_masked(b, old_src, val_mask);
mme_free_reg(b, val_mask);
mme_if(b, ine, src, old_src) {
mme_free_reg(b, old_src);
nvk_mme_store_scratch(b, SHADING_RATE_CONTROL, src);
struct mme_value enable1 = mme_merge(b, mme_zero(), src, 0, 1, 0);
struct mme_value enable2 = mme_merge(b, mme_zero(), src, 0, 1, 1);
struct mme_value enable = mme_and(b, enable1, enable2);
struct mme_value i = mme_mov(b, mme_zero());
mme_while(b, ine, i, mme_imm(16 * 4)) {
mme_mthd_arr(b, NVC597_SET_VARIABLE_PIXEL_RATE_SHADING_CONTROL(0), i);
mme_emit(b, enable);
mme_add_to(b, i, i, mme_imm(4));
}
}
}
static void
nvk_mme_set_shading_rate_control_test_check(
const struct nv_device_info *devinfo,
const struct nvk_mme_test_case *test,
const struct nvk_mme_mthd_data *results)
{
if (devinfo->cls_eng3d < TURING_A)
return;
assert(results[0].mthd == NVK_SET_MME_SCRATCH(SHADING_RATE_CONTROL));
bool enable = (results[0].data & 3) == 3;
for (uint32_t i = 0; i < 16; i++) {
assert(results[i + 1].mthd ==
NVC597_SET_VARIABLE_PIXEL_RATE_SHADING_CONTROL(i));
assert(results[i + 1].data == enable);
}
}
const struct nvk_mme_test_case nvk_mme_set_shading_rate_control_tests[] = {{
.init = (struct nvk_mme_mthd_data[]) {
{ NVK_SET_MME_SCRATCH(SHADING_RATE_CONTROL), 0 },
{ }
},
.params = (uint32_t[]) { 0x00030003 },
.check = nvk_mme_set_shading_rate_control_test_check,
}, {
.init = (struct nvk_mme_mthd_data[]) {
{ NVK_SET_MME_SCRATCH(SHADING_RATE_CONTROL), 0 },
{ }
},
.params = (uint32_t[]) { 0x00030001 },
.check = nvk_mme_set_shading_rate_control_test_check,
}, {}};
static VkExtent2D
nvk_combine_fs_log2_rates(VkFragmentShadingRateCombinerOpKHR op,
VkExtent2D a_log2, VkExtent2D b_log2)
{
switch (op) {
case VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR:
return a_log2;
case VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR:
return b_log2;
case VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR:
return (VkExtent2D) {
.width = MIN2(a_log2.width, b_log2.width),
.height = MIN2(a_log2.height, b_log2.height),
};
case VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR:
return (VkExtent2D) {
.width = MAX2(a_log2.width, b_log2.width),
.height = MAX2(a_log2.height, b_log2.height),
};
case VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR:
return (VkExtent2D) {
.width = a_log2.width + b_log2.width,
.height = a_log2.height + b_log2.height,
};
default:
unreachable("Invalid FSR combiner op");
}
}
static uint8_t
vk_to_nvc597_shading_rate_log2(VkExtent2D rate_log2)
{
rate_log2.width = MIN2(rate_log2.width, 2);
rate_log2.height = MIN2(rate_log2.height, 2);
const uint8_t idx = (rate_log2.width << 2) | rate_log2.height;
/* From the Vulkan 1.3.297 spec:
*
* "A fragment shading rate Rxy representing any of Axy, Bxy or Cxy
* is clamped as follows. [...] From this list of supported rates,
* the following steps are applied in order, to select a single
* value:
*
* 1. Keep only rates where Rx' ≤ Rx and Ry' ≤ Ry.
*
* - Implementations may also keep rates where Rx' ≤ Ry and
* Ry' ≤ Rx.
*
* 2. Keep only rates with the highest area (Rx' × Ry').
*
* 3. Keep only rates with the lowest aspect ratio (Rx' + Ry').
*
* 4. In cases where a wide (e.g. 4x1) and tall (e.g. 1x4) rate
* remain, the implementation may choose either rate. However, it
* must choose this rate consistently for the same shading rates,
* render pass transform, and combiner operations for the
* lifetime of the VkDevice.
*
* We have the following rates: 1x1, 2x1, 1x2, 2x2, 4x2, 2x4, 4x4.
*/
static const uint8_t vk_to_nvc597[] = {
#define NVC597_FSR(X) NVC597_SET_VARIABLE_PIXEL_RATE_SHADING_INDEX_TO_RATE_A_RATE_INDEX0_PS_##X
NVC597_FSR(X1_PER_RASTER_PIXEL),
NVC597_FSR(X1_PER_1X2_RASTER_PIXELS),
NVC597_FSR(X1_PER_1X2_RASTER_PIXELS), /* 1x4 */
NVC597_FSR(X1_PER_1X2_RASTER_PIXELS), /* 1x8 */
NVC597_FSR(X1_PER_2X1_RASTER_PIXELS),
NVC597_FSR(X1_PER_2X2_RASTER_PIXELS),
NVC597_FSR(X1_PER_2X4_RASTER_PIXELS),
NVC597_FSR(X1_PER_2X4_RASTER_PIXELS), /* 2x8 */
NVC597_FSR(X1_PER_2X1_RASTER_PIXELS), /* 4x1 */
NVC597_FSR(X1_PER_4X2_RASTER_PIXELS),
NVC597_FSR(X1_PER_4X4_RASTER_PIXELS),
NVC597_FSR(X1_PER_4X4_RASTER_PIXELS), /* 4x8 */
NVC597_FSR(X1_PER_2X1_RASTER_PIXELS), /* 8x1 */
NVC597_FSR(X1_PER_4X2_RASTER_PIXELS), /* 8x2 */
NVC597_FSR(X1_PER_4X4_RASTER_PIXELS), /* 8x4 */
NVC597_FSR(X1_PER_4X4_RASTER_PIXELS), /* 8x8 */
#undef NVC597_FSR
};
assert(idx < ARRAY_SIZE(vk_to_nvc597));
return vk_to_nvc597[idx];
}
static void
nvk_flush_fsr_state(struct nvk_cmd_buffer *cmd)
{
const struct vk_dynamic_graphics_state *dyn =
&cmd->vk.dynamic_graphics_state;
if (nvk_cmd_buffer_3d_cls(cmd) < TURING_A) {
assert(vk_fragment_shading_rate_is_disabled(&dyn->fsr));
return;
}
if (!BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_FSR))
return;
if (vk_fragment_shading_rate_is_disabled(&dyn->fsr)) {
struct nv_push *p = nvk_cmd_buffer_push(cmd, 2);
P_1INC(p, NV9097, CALL_MME_MACRO(NVK_MME_SET_SHADING_RATE_CONTROL));
P_INLINE_DATA(p, nvk_mme_shading_rate_control_enable(false));
} else {
struct nv_push *p = nvk_cmd_buffer_push(cmd, 2 + 16 * 3);
assert(util_is_power_of_two_or_zero(dyn->fsr.fragment_size.width));
assert(util_is_power_of_two_or_zero(dyn->fsr.fragment_size.height));
const VkExtent2D state_fs_log2 = {
.width = util_logbase2(dyn->fsr.fragment_size.width),
.height = util_logbase2(dyn->fsr.fragment_size.height),
};
for (uint32_t prim_idx = 0; prim_idx < 16; prim_idx++) {
const VkExtent2D prim_fs_log2 = {
.width = (prim_idx >> 2) & 3,
.height = prim_idx & 3,
};
const VkExtent2D state_prim_fs_log2 =
nvk_combine_fs_log2_rates(dyn->fsr.combiner_ops[0],
state_fs_log2, prim_fs_log2);
uint8_t rates[16] = {};
for (uint32_t att_idx = 0; att_idx < 16; att_idx++) {
const VkExtent2D att_fs_log2 = {
.width = (att_idx >> 2) & 3,
.height = att_idx & 3,
};
const VkExtent2D fs_log2 =
nvk_combine_fs_log2_rates(dyn->fsr.combiner_ops[1],
state_prim_fs_log2, att_fs_log2);
rates[att_idx] = vk_to_nvc597_shading_rate_log2(fs_log2);
}
P_MTHD(p, NVC597, SET_VARIABLE_PIXEL_RATE_SHADING_INDEX_TO_RATE_A(prim_idx));
P_NVC597_SET_VARIABLE_PIXEL_RATE_SHADING_INDEX_TO_RATE_A(p, prim_idx, {
.rate_index0 = rates[0],
.rate_index1 = rates[1],
.rate_index2 = rates[2],
.rate_index3 = rates[3],
.rate_index4 = rates[4],
.rate_index5 = rates[5],
.rate_index6 = rates[6],
.rate_index7 = rates[7],
});
P_NVC597_SET_VARIABLE_PIXEL_RATE_SHADING_INDEX_TO_RATE_B(p, prim_idx, {
.rate_index8 = rates[8],
.rate_index9 = rates[9],
.rate_index10 = rates[10],
.rate_index11 = rates[11],
.rate_index12 = rates[12],
.rate_index13 = rates[13],
.rate_index14 = rates[14],
.rate_index15 = rates[15],
});
}
P_1INC(p, NV9097, CALL_MME_MACRO(NVK_MME_SET_SHADING_RATE_CONTROL));
P_INLINE_DATA(p, nvk_mme_shading_rate_control_enable(true));
}
}
static uint32_t
nvk_mme_anti_alias_init(void)
{
@@ -2892,9 +3138,7 @@ nvk_cmd_flush_gfx_dynamic_state(struct nvk_cmd_buffer *cmd)
nvk_flush_ts_state(cmd);
nvk_flush_vp_state(cmd);
nvk_flush_rs_state(cmd);
/* MESA_VK_DYNAMIC_FSR */
nvk_flush_fsr_state(cmd);
nvk_flush_ms_state(cmd);
nvk_flush_ds_state(cmd);
nvk_flush_cb_state(cmd);
+2
View File
@@ -17,6 +17,7 @@ static const nvk_mme_builder_func mme_builders[NVK_MME_COUNT] = {
[NVK_MME_SET_VB_ENABLES] = nvk_mme_set_vb_enables,
[NVK_MME_SET_VB_STRIDE] = nvk_mme_set_vb_stride,
[NVK_MME_SET_TESS_PARAMS] = nvk_mme_set_tess_params,
[NVK_MME_SET_SHADING_RATE_CONTROL] = nvk_mme_set_shading_rate_control,
[NVK_MME_SET_ANTI_ALIAS] = nvk_mme_set_anti_alias,
[NVK_MME_DRAW] = nvk_mme_draw,
[NVK_MME_DRAW_INDEXED] = nvk_mme_draw_indexed,
@@ -40,6 +41,7 @@ static const struct nvk_mme_test_case *mme_tests[NVK_MME_COUNT] = {
[NVK_MME_CLEAR] = nvk_mme_clear_tests,
[NVK_MME_BIND_VB] = nvk_mme_bind_vb_tests,
[NVK_MME_SET_TESS_PARAMS] = nvk_mme_set_tess_params_tests,
[NVK_MME_SET_SHADING_RATE_CONTROL] = nvk_mme_set_shading_rate_control_tests,
[NVK_MME_SET_ANTI_ALIAS] = nvk_mme_set_anti_alias_tests,
};
+7
View File
@@ -21,6 +21,7 @@ enum nvk_mme {
NVK_MME_SET_VB_ENABLES,
NVK_MME_SET_VB_STRIDE,
NVK_MME_SET_TESS_PARAMS,
NVK_MME_SET_SHADING_RATE_CONTROL,
NVK_MME_SET_ANTI_ALIAS,
NVK_MME_DRAW,
NVK_MME_DRAW_INDEXED,
@@ -76,6 +77,9 @@ enum nvk_mme_scratch {
NVK_MME_SCRATCH_SAMPLE_MASKS_4PASS_3,
NVK_MME_SCRATCH_ANTI_ALIAS,
/* Shading rate control */
NVK_MME_SCRATCH_SHADING_RATE_CONTROL,
/* Addres of cb0 */
NVK_MME_SCRATCH_CB0_ADDR_HI,
NVK_MME_SCRATCH_CB0_ADDR_LO,
@@ -211,6 +215,7 @@ void nvk_mme_bind_vb(struct mme_builder *b);
void nvk_mme_set_vb_enables(struct mme_builder *b);
void nvk_mme_set_vb_stride(struct mme_builder *b);
void nvk_mme_set_tess_params(struct mme_builder *b);
void nvk_mme_set_shading_rate_control(struct mme_builder *b);
void nvk_mme_set_anti_alias(struct mme_builder *b);
void nvk_mme_draw(struct mme_builder *b);
void nvk_mme_draw_indexed(struct mme_builder *b);
@@ -233,6 +238,7 @@ uint32_t nvk_mme_tess_params(enum nak_ts_domain domain,
enum nak_ts_spacing spacing,
enum nak_ts_prims prims);
uint32_t nvk_mme_anti_alias_min_sample_shading(float mss);
uint32_t nvk_mme_shading_rate_control_sample_shading(bool sample_shading);
struct nvk_mme_mthd_data {
uint16_t mthd;
@@ -253,6 +259,7 @@ struct nvk_mme_test_case {
extern const struct nvk_mme_test_case nvk_mme_clear_tests[];
extern const struct nvk_mme_test_case nvk_mme_bind_vb_tests[];
extern const struct nvk_mme_test_case nvk_mme_set_tess_params_tests[];
extern const struct nvk_mme_test_case nvk_mme_set_shading_rate_control_tests[];
extern const struct nvk_mme_test_case nvk_mme_set_anti_alias_tests[];
void nvk_test_all_mmes(const struct nv_device_info *devinfo);
+23 -2
View File
@@ -715,7 +715,7 @@ nvk_max_shader_push_dw(struct nvk_physical_device *pdev,
max_dw_count += 2;
if (stage == MESA_SHADER_FRAGMENT)
max_dw_count += 11;
max_dw_count += 13;
if (last_vtgm) {
max_dw_count += 6;
@@ -774,7 +774,7 @@ nvk_shader_fill_push(struct nvk_device *dev,
}
if (shader->info.stage == MESA_SHADER_FRAGMENT) {
max_dw_count += 11;
max_dw_count += 13;
P_MTHD(p, NVC397, SET_SUBTILING_PERF_KNOB_A);
P_NV9097_SET_SUBTILING_PERF_KNOB_A(p, {
@@ -800,6 +800,27 @@ nvk_shader_fill_push(struct nvk_device *dev,
.z_max_unbounded_enable = shader->info.fs.writes_depth,
});
if (pdev->info.cls_eng3d >= TURING_A) {
/* From the Vulkan 1.3.297 spec:
*
* "If sample shading is enabled, an implementation must invoke
* the fragment shader at least
*
* max( ⌈ minSampleShading × rasterizationSamples ⌉, 1)
*
* times per fragment."
*
* The max() here means that, regardless of the actual value of
* minSampleShading, we need to invoke at least once per pixel,
* meaning that we need to disable fragment shading rate. We also
* need to disable FSR if sample shading is used by the shader.
*/
P_1INC(p, NV9097, CALL_MME_MACRO(NVK_MME_SET_SHADING_RATE_CONTROL));
P_INLINE_DATA(p, nvk_mme_shading_rate_control_sample_shading(
shader->sample_shading_enable ||
shader->info.fs.uses_sample_shading));
}
float mss = 0;
if (shader->info.fs.uses_sample_shading) {
mss = 1;