[Vulkan] Alpha to coverage improvements
Refactor redundant code, fix 2x MSAA sample mapping and only declare gl_FragCoord when alpha to coverage can run
This commit is contained in:
@@ -1980,14 +1980,17 @@ void SpirvShaderTranslator::StartFragmentShaderBeforeMain() {
|
||||
}
|
||||
|
||||
// Fragment coordinates.
|
||||
// TODO(Triang3l): More conditions - alpha to coverage (if RT 0 is written,
|
||||
// and there's no early depth / stencil), depth writing in the fragment shader
|
||||
// TODO(Triang3l): More conditions - depth writing in the fragment shader
|
||||
// (per-sample if supported).
|
||||
// Also needed for alpha-to-mask dithering in FBO mode.
|
||||
// FSI: Always needed for EDRAM offset calculation and depth derivatives.
|
||||
// param_gen: Needed for PsParamGen calculation.
|
||||
// FBO alpha-to-coverage: Needed for dithering pattern, but only when
|
||||
// alpha-to-coverage can actually run (no early fragment tests).
|
||||
bool need_frag_coord =
|
||||
edram_fragment_shader_interlock_ || param_gen_needed ||
|
||||
(!edram_fragment_shader_interlock_ && !is_depth_only_fragment_shader_ &&
|
||||
current_shader().writes_color_target(0));
|
||||
current_shader().writes_color_target(0) &&
|
||||
!IsExecutionModeEarlyFragmentTests());
|
||||
if (need_frag_coord) {
|
||||
input_fragment_coordinates_ = builder_->createVariable(
|
||||
spv::NoPrecision, spv::StorageClassInput, type_float4_, "gl_FragCoord");
|
||||
|
||||
@@ -3675,103 +3675,98 @@ void SpirvShaderTranslator::FSI_AlphaToMask() {
|
||||
// 4x MSAA
|
||||
builder_->setBuildPoint(&block_4x_msaa);
|
||||
spv::Id coverage_4x = spv::NoResult;
|
||||
{
|
||||
FSI_AlphaToMaskSample(true, 0, 0.75f, threshold_offset, 1.0f / 16.0f,
|
||||
coverage_4x);
|
||||
FSI_AlphaToMaskSample(false, 1, 0.25f, threshold_offset, 1.0f / 16.0f,
|
||||
coverage_4x);
|
||||
FSI_AlphaToMaskSample(false, 2, 0.5f, threshold_offset, 1.0f / 16.0f,
|
||||
coverage_4x);
|
||||
FSI_AlphaToMaskSample(false, 3, 1.0f, threshold_offset, 1.0f / 16.0f,
|
||||
coverage_4x);
|
||||
|
||||
if (!edram_fragment_shader_interlock_) {
|
||||
// Write to gl_SampleMask[0] and discard if zero coverage
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.push_back(builder_->makeIntConstant(0));
|
||||
spv::Id sample_mask_element = builder_->createAccessChain(
|
||||
spv::StorageClassOutput, output_fragment_sample_mask_,
|
||||
id_vector_temp_);
|
||||
spv::Id coverage_int =
|
||||
builder_->createUnaryOp(spv::OpBitcast, type_int_, coverage_4x);
|
||||
builder_->createStore(coverage_int, sample_mask_element);
|
||||
|
||||
// Discard if coverage is zero
|
||||
spv::Id coverage_zero =
|
||||
builder_->createBinOp(spv::OpIEqual, type_bool_, coverage_4x,
|
||||
builder_->makeUintConstant(0));
|
||||
SpirvBuilder::IfBuilder coverage_discard_if(
|
||||
coverage_zero, spv::SelectionControlDontFlattenMask, *builder_);
|
||||
builder_->createNoResultOp(spv::OpKill);
|
||||
// OpKill terminates the block, so makeEndIf with false to not branch
|
||||
coverage_discard_if.makeEndIf(false);
|
||||
}
|
||||
}
|
||||
FSI_AlphaToMaskSample(true, 0, 0.75f, threshold_offset, 1.0f / 16.0f,
|
||||
coverage_4x);
|
||||
FSI_AlphaToMaskSample(false, 1, 0.25f, threshold_offset, 1.0f / 16.0f,
|
||||
coverage_4x);
|
||||
FSI_AlphaToMaskSample(false, 2, 0.5f, threshold_offset, 1.0f / 16.0f,
|
||||
coverage_4x);
|
||||
FSI_AlphaToMaskSample(false, 3, 1.0f, threshold_offset, 1.0f / 16.0f,
|
||||
coverage_4x);
|
||||
builder_->createBranch(&block_msaa_mode_merge);
|
||||
|
||||
// 2x MSAA
|
||||
builder_->setBuildPoint(&block_2x_msaa);
|
||||
spv::Id coverage_2x = spv::NoResult;
|
||||
{
|
||||
// Using guest sample indices (0 and 1) for both FSI and non-FSI.
|
||||
// FSI mode uses guest sample indices (0 and 1).
|
||||
// FBO mode sample mapping depends on whether native 2x MSAA is supported:
|
||||
// - Native 2x: host samples 1, 0 (reversed from guest order)
|
||||
// - 2x as 4x: host samples 0, 3
|
||||
if (edram_fragment_shader_interlock_) {
|
||||
// FSI: Use guest indices 0, 1.
|
||||
FSI_AlphaToMaskSample(true, 0, 0.5f, threshold_offset, 1.0f / 8.0f,
|
||||
coverage_2x);
|
||||
FSI_AlphaToMaskSample(false, 1, 1.0f, threshold_offset, 1.0f / 8.0f,
|
||||
coverage_2x);
|
||||
|
||||
if (!edram_fragment_shader_interlock_) {
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.push_back(builder_->makeIntConstant(0));
|
||||
spv::Id sample_mask_element = builder_->createAccessChain(
|
||||
spv::StorageClassOutput, output_fragment_sample_mask_,
|
||||
id_vector_temp_);
|
||||
spv::Id coverage_int =
|
||||
builder_->createUnaryOp(spv::OpBitcast, type_int_, coverage_2x);
|
||||
builder_->createStore(coverage_int, sample_mask_element);
|
||||
|
||||
spv::Id coverage_zero =
|
||||
builder_->createBinOp(spv::OpIEqual, type_bool_, coverage_2x,
|
||||
builder_->makeUintConstant(0));
|
||||
SpirvBuilder::IfBuilder coverage_discard_if(
|
||||
coverage_zero, spv::SelectionControlDontFlattenMask, *builder_);
|
||||
builder_->createNoResultOp(spv::OpKill);
|
||||
coverage_discard_if.makeEndIf(false);
|
||||
} else {
|
||||
// FBO: Account for native 2x vs 2x-as-4x sample mapping.
|
||||
if (native_2x_msaa_no_attachments_) {
|
||||
// Native 2x: D3D10.1+ standard - top is 1, bottom is 0.
|
||||
FSI_AlphaToMaskSample(true, 1, 0.5f, threshold_offset, 1.0f / 8.0f,
|
||||
coverage_2x);
|
||||
FSI_AlphaToMaskSample(false, 0, 1.0f, threshold_offset, 1.0f / 8.0f,
|
||||
coverage_2x);
|
||||
} else {
|
||||
// 2x as 4x: Use samples 0 and 3.
|
||||
FSI_AlphaToMaskSample(true, 0, 0.5f, threshold_offset, 1.0f / 8.0f,
|
||||
coverage_2x);
|
||||
FSI_AlphaToMaskSample(false, 3, 1.0f, threshold_offset, 1.0f / 8.0f,
|
||||
coverage_2x);
|
||||
}
|
||||
}
|
||||
builder_->createBranch(&block_msaa_mode_merge);
|
||||
|
||||
builder_->setBuildPoint(&block_msaa_mode_merge);
|
||||
// Merge coverage from 4x and 2x MSAA paths using PHI.
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.reserve(2 * 2);
|
||||
id_vector_temp_.push_back(coverage_4x);
|
||||
id_vector_temp_.push_back(block_4x_msaa.getId());
|
||||
id_vector_temp_.push_back(coverage_2x);
|
||||
id_vector_temp_.push_back(block_2x_msaa.getId());
|
||||
spv::Id coverage_msaa_enabled =
|
||||
builder_->createOp(spv::OpPhi, type_uint_, id_vector_temp_);
|
||||
builder_->createBranch(&block_msaa_merge);
|
||||
|
||||
// MSAA disabled - single sample
|
||||
builder_->setBuildPoint(&block_msaa_disabled);
|
||||
spv::Id coverage_1x = spv::NoResult;
|
||||
{
|
||||
FSI_AlphaToMaskSample(true, 0, 1.0f, threshold_offset, 1.0f / 4.0f,
|
||||
coverage_1x);
|
||||
|
||||
if (!edram_fragment_shader_interlock_) {
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.push_back(builder_->makeIntConstant(0));
|
||||
spv::Id sample_mask_element = builder_->createAccessChain(
|
||||
spv::StorageClassOutput, output_fragment_sample_mask_,
|
||||
id_vector_temp_);
|
||||
spv::Id coverage_int =
|
||||
builder_->createUnaryOp(spv::OpBitcast, type_int_, coverage_1x);
|
||||
builder_->createStore(coverage_int, sample_mask_element);
|
||||
|
||||
spv::Id coverage_zero =
|
||||
builder_->createBinOp(spv::OpIEqual, type_bool_, coverage_1x,
|
||||
builder_->makeUintConstant(0));
|
||||
SpirvBuilder::IfBuilder coverage_discard_if(
|
||||
coverage_zero, spv::SelectionControlDontFlattenMask, *builder_);
|
||||
builder_->createNoResultOp(spv::OpKill);
|
||||
coverage_discard_if.makeEndIf(false);
|
||||
}
|
||||
}
|
||||
FSI_AlphaToMaskSample(true, 0, 1.0f, threshold_offset, 1.0f / 4.0f,
|
||||
coverage_1x);
|
||||
builder_->createBranch(&block_msaa_merge);
|
||||
|
||||
builder_->setBuildPoint(&block_msaa_merge);
|
||||
// Merge coverage from MSAA enabled and disabled paths using PHI.
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.reserve(2 * 2);
|
||||
id_vector_temp_.push_back(coverage_msaa_enabled);
|
||||
id_vector_temp_.push_back(block_msaa_mode_merge.getId());
|
||||
id_vector_temp_.push_back(coverage_1x);
|
||||
id_vector_temp_.push_back(block_msaa_disabled.getId());
|
||||
spv::Id coverage_final =
|
||||
builder_->createOp(spv::OpPhi, type_uint_, id_vector_temp_);
|
||||
|
||||
// Write coverage to gl_SampleMask and discard if zero (FBO mode only).
|
||||
if (!edram_fragment_shader_interlock_) {
|
||||
// Write to gl_SampleMask[0].
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.push_back(builder_->makeIntConstant(0));
|
||||
spv::Id sample_mask_element = builder_->createAccessChain(
|
||||
spv::StorageClassOutput, output_fragment_sample_mask_, id_vector_temp_);
|
||||
spv::Id coverage_int =
|
||||
builder_->createUnaryOp(spv::OpBitcast, type_int_, coverage_final);
|
||||
builder_->createStore(coverage_int, sample_mask_element);
|
||||
|
||||
// Discard fragment if coverage is zero.
|
||||
spv::Id coverage_zero =
|
||||
builder_->createBinOp(spv::OpIEqual, type_bool_, coverage_final,
|
||||
builder_->makeUintConstant(0));
|
||||
SpirvBuilder::IfBuilder coverage_discard_if(
|
||||
coverage_zero, spv::SelectionControlDontFlattenMask, *builder_);
|
||||
builder_->createNoResultOp(spv::OpKill);
|
||||
// OpKill terminates the block, so makeEndIf with false to not branch.
|
||||
coverage_discard_if.makeEndIf(false);
|
||||
}
|
||||
|
||||
builder_->createBranch(&block_alpha_to_mask_merge);
|
||||
builder_->setBuildPoint(&block_alpha_to_mask_merge);
|
||||
|
||||
Reference in New Issue
Block a user