mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-06 20:18:12 +02:00
tu: Enable alpha-to-coverage emulation
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/39335>
This commit is contained in:
parent
ec37fed52b
commit
e1fd5a4a57
9 changed files with 150 additions and 0 deletions
|
|
@ -38,6 +38,7 @@ libtu_files = files(
|
|||
'tu_image.cc',
|
||||
'tu_knl.cc',
|
||||
'tu_lrz.cc',
|
||||
'tu_nir_lower_demote_samples.cc',
|
||||
'tu_nir_lower_multiview.cc',
|
||||
'tu_nir_lower_ray_query.cc',
|
||||
'tu_pass.cc',
|
||||
|
|
|
|||
|
|
@ -1830,6 +1830,7 @@ static const driOptionDescription tu_dri_options[] = {
|
|||
DRI_CONF_TU_USE_TEX_COORD_ROUND_NEAREST_EVEN_MODE(false)
|
||||
DRI_CONF_TU_IGNORE_FRAG_DEPTH_DIRECTION(false)
|
||||
DRI_CONF_TU_ENABLE_SOFTFLOAT32(false)
|
||||
DRI_CONF_TU_EMULATE_ALPHA_TO_COVERAGE(false)
|
||||
DRI_CONF_SECTION_END
|
||||
};
|
||||
|
||||
|
|
@ -1860,6 +1861,8 @@ tu_init_dri_options(struct tu_instance *instance)
|
|||
driQueryOptionb(&instance->dri_options, "tu_ignore_frag_depth_direction");
|
||||
instance->enable_softfloat32 =
|
||||
driQueryOptionb(&instance->dri_options, "tu_enable_softfloat32");
|
||||
instance->emulate_alpha_to_coverage =
|
||||
driQueryOptionb(&instance->dri_options, "tu_emulate_alpha_to_coverage");
|
||||
}
|
||||
|
||||
static uint32_t instance_count = 0;
|
||||
|
|
|
|||
|
|
@ -229,6 +229,12 @@ struct tu_instance
|
|||
* However we don't want native Vulkan apps using this.
|
||||
*/
|
||||
bool enable_softfloat32;
|
||||
|
||||
/* The hardware implementation of alpha-to-coverage gives visually poor
|
||||
* results for many games. Set this option to enable it in the shader
|
||||
* instead.
|
||||
*/
|
||||
bool emulate_alpha_to_coverage;
|
||||
};
|
||||
VK_DEFINE_HANDLE_CASTS(tu_instance, vk.base, VkInstance,
|
||||
VK_OBJECT_TYPE_INSTANCE)
|
||||
|
|
|
|||
88
src/freedreno/vulkan/tu_nir_lower_demote_samples.cc
Normal file
88
src/freedreno/vulkan/tu_nir_lower_demote_samples.cc
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright © 2025 Valve Corporation
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "tu_shader.h"
|
||||
#include "nir/nir_builder.h"
|
||||
|
||||
/* Lower demote_samples to a write to gl_SampleMask. Take into account
|
||||
* existing writes to gl_SampleMask.
|
||||
*/
|
||||
|
||||
bool
|
||||
tu_nir_lower_demote_samples(nir_shader *nir)
|
||||
{
|
||||
nir_function_impl *entrypoint = nir_shader_get_entrypoint(nir);
|
||||
nir_variable *sample_mask = NULL;
|
||||
|
||||
nir_builder _b = nir_builder_create(entrypoint), *b = &_b;
|
||||
|
||||
bool progress = false;
|
||||
|
||||
uint32_t sample_mask_driver_location = ~0;
|
||||
nir_foreach_block (block, entrypoint) {
|
||||
nir_foreach_instr_safe (instr, block) {
|
||||
if (instr->type != nir_instr_type_intrinsic)
|
||||
continue;
|
||||
|
||||
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
|
||||
if (intrin->intrinsic == nir_intrinsic_store_output) {
|
||||
nir_io_semantics sem = nir_intrinsic_io_semantics(intrin);
|
||||
if (sem.location != FRAG_RESULT_SAMPLE_MASK)
|
||||
continue;
|
||||
} else if (intrin->intrinsic != nir_intrinsic_demote_samples) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sample_mask) {
|
||||
sample_mask = nir_local_variable_create(entrypoint,
|
||||
glsl_uint_type(),
|
||||
"sample_mask");
|
||||
/* Initialize sample_mask to ~0 (all samples) */
|
||||
b->cursor = nir_before_impl(entrypoint);
|
||||
nir_store_var(b, sample_mask, nir_imm_int(b, ~0), 0x1);
|
||||
}
|
||||
|
||||
b->cursor = nir_before_instr(instr);
|
||||
|
||||
if (intrin->intrinsic == nir_intrinsic_demote_samples) {
|
||||
/* For each demote_samples, remove the samples from sample_mask */
|
||||
nir_def *to_demote = intrin->src[0].ssa;
|
||||
|
||||
nir_store_var(b, sample_mask,
|
||||
nir_iand(b, nir_load_var(b, sample_mask),
|
||||
nir_inot(b, to_demote)), 0x1);
|
||||
} else if (intrin->intrinsic == nir_intrinsic_store_output) {
|
||||
/* If there is an existing write to SampleMask, AND it with
|
||||
* sample_mask and remove it.
|
||||
*/
|
||||
nir_def *old_mask = intrin->src[0].ssa;
|
||||
nir_store_var(b, sample_mask,
|
||||
nir_iand(b, nir_load_var(b, sample_mask),
|
||||
old_mask), 0x1);
|
||||
sample_mask_driver_location = nir_intrinsic_base(intrin);
|
||||
}
|
||||
|
||||
nir_instr_remove(instr);
|
||||
progress = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (progress) {
|
||||
if (sample_mask_driver_location == ~0)
|
||||
sample_mask_driver_location = nir->num_outputs++;
|
||||
|
||||
/* Finally, at the end insert a write to SampleMask. */
|
||||
b->cursor = nir_after_impl(entrypoint);
|
||||
nir_store_output(b, nir_load_var(b, sample_mask),
|
||||
nir_imm_int(b, 0),
|
||||
.base = sample_mask_driver_location,
|
||||
.io_semantics = {
|
||||
.location = FRAG_RESULT_SAMPLE_MASK
|
||||
});
|
||||
}
|
||||
|
||||
return nir_progress(progress, entrypoint, nir_metadata_control_flow);
|
||||
}
|
||||
|
||||
|
|
@ -1850,6 +1850,18 @@ tu_pipeline_builder_compile_shaders(struct tu_pipeline_builder *builder,
|
|||
VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) {
|
||||
keys[MESA_SHADER_FRAGMENT].custom_resolve =
|
||||
builder->graphics_state.rp->custom_resolve;
|
||||
|
||||
if (builder->device->physical_device->instance->emulate_alpha_to_coverage) {
|
||||
keys[MESA_SHADER_FRAGMENT].emulate_alpha_to_coverage = true;
|
||||
|
||||
/* Don't emulate if we know it won't be enabled. */
|
||||
if (builder->graphics_state.ms &&
|
||||
!BITSET_TEST(builder->graphics_state.dynamic,
|
||||
MESA_VK_DYNAMIC_MS_ALPHA_TO_COVERAGE_ENABLE)) {
|
||||
if (!builder->graphics_state.ms->alpha_to_coverage_enable)
|
||||
keys[MESA_SHADER_FRAGMENT].emulate_alpha_to_coverage = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (builder->create_flags &
|
||||
|
|
@ -3278,6 +3290,8 @@ tu6_emit_blend(struct tu_cs *cs,
|
|||
{
|
||||
bool rop_reads_dst = cb->logic_op_enable && tu_logic_op_reads_dst((VkLogicOp)cb->logic_op);
|
||||
enum a3xx_rop_code rop = tu6_rop((VkLogicOp)cb->logic_op);
|
||||
if (cs->device->physical_device->instance->emulate_alpha_to_coverage)
|
||||
alpha_to_coverage_enable = false;
|
||||
|
||||
uint32_t blend_enable_mask = 0;
|
||||
for (unsigned i = 0; i < cb->attachment_count; i++) {
|
||||
|
|
|
|||
|
|
@ -1533,6 +1533,20 @@ tu_nir_lower_view_to_zero(nir_shader *shader)
|
|||
lower_view_to_zero, NULL);
|
||||
}
|
||||
|
||||
static bool
|
||||
lower_alpha_to_coverage(nir_shader *shader)
|
||||
{
|
||||
nir_builder b = nir_builder_create(nir_shader_get_entrypoint(shader));
|
||||
b.cursor = nir_before_cf_list(&nir_shader_get_entrypoint(shader)->body);
|
||||
nir_def *a2c_enabled =
|
||||
nir_ine_imm(&b, nir_load_alpha_to_coverage_enable_ir3(&b), 0);
|
||||
|
||||
NIR_PASS(_, shader, nir_lower_alpha_to_coverage, false, a2c_enabled);
|
||||
NIR_PASS(_, shader, tu_nir_lower_demote_samples);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
shared_type_info(const struct glsl_type *type, unsigned *size, unsigned *align)
|
||||
{
|
||||
|
|
@ -3073,6 +3087,9 @@ tu_shader_create(struct tu_device *dev,
|
|||
|
||||
ir3_nir_lower_io(nir);
|
||||
|
||||
if (key->emulate_alpha_to_coverage)
|
||||
lower_alpha_to_coverage(nir);
|
||||
|
||||
struct ir3_const_allocations const_allocs = {};
|
||||
NIR_PASS(_, nir, tu_lower_io, dev, shader, layout,
|
||||
key->read_only_input_attachments, key->dynamic_renderpass,
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ struct tu_shader_key {
|
|||
bool robust_uniform_access2;
|
||||
bool lower_view_index_to_device_index;
|
||||
bool custom_resolve;
|
||||
bool emulate_alpha_to_coverage;
|
||||
enum ir3_wavesize_option api_wavesize, real_wavesize;
|
||||
};
|
||||
|
||||
|
|
@ -143,6 +144,9 @@ tu_nir_lower_multiview(nir_shader *nir, uint32_t mask, struct tu_device *dev);
|
|||
bool
|
||||
tu_nir_lower_ray_queries(nir_shader *nir);
|
||||
|
||||
bool
|
||||
tu_nir_lower_demote_samples(nir_shader *nir);
|
||||
|
||||
nir_shader *
|
||||
tu_spirv_to_nir(struct tu_device *dev,
|
||||
void *mem_ctx,
|
||||
|
|
|
|||
|
|
@ -1388,6 +1388,16 @@ TODO: document the other workarounds.
|
|||
default, the latter is used through this option.
|
||||
-->
|
||||
<option name="tu_use_tex_coord_round_nearest_even_mode" value="true" />
|
||||
|
||||
<!--
|
||||
The hardware algorithm for alpha-to-coverage seems to
|
||||
consistently produce bad results compared to other vendors.
|
||||
Always enabling emulation would potentially regress performance
|
||||
when it is dynamically enabled and off, but both both DXVK and
|
||||
vkd3d-proton are known to compile pipelines with
|
||||
alpha-to-coverage statically disabled.
|
||||
-->
|
||||
<option name="tu_emulate_alpha_to_coverage" value="true" />
|
||||
</engine>
|
||||
<engine engine_name_match="vkd3d">
|
||||
<option name="tu_enable_softfloat32" value="true" />
|
||||
|
|
@ -1406,6 +1416,9 @@ TODO: document the other workarounds.
|
|||
<application name="Creed: Rise to Glory" executable="Creed-Win64-Shipping.exe">
|
||||
<option name="tu_ignore_frag_depth_direction" value="true" />
|
||||
</application>
|
||||
<application name="Half-Life: Alyx" application_name_match="hlvr">
|
||||
<option name="tu_emulate_alpha_to_coverage" value="true" />
|
||||
</application>
|
||||
</device>
|
||||
|
||||
<device driver="asahi">
|
||||
|
|
|
|||
|
|
@ -688,6 +688,10 @@
|
|||
DRI_CONF_OPT_B(tu_enable_softfloat32, def, \
|
||||
"Enable softfloat emulation for float32 denormals")
|
||||
|
||||
#define DRI_CONF_TU_EMULATE_ALPHA_TO_COVERAGE(def) \
|
||||
DRI_CONF_OPT_B(tu_emulate_alpha_to_coverage, def, \
|
||||
"Enable emulation of alpha-to-coverage")
|
||||
|
||||
/**
|
||||
* \brief Honeykrisp specific configuration options
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue