[Vulkan] Remove UB-based independent blend logic
On Vulkan, unlike Direct3D, not writing to a color target in the fragment shader produces an undefined result.
This commit is contained in:
parent
d8b2944caa
commit
a5c8df7a37
|
@ -1270,19 +1270,16 @@ void SpirvShaderTranslator::StartFragmentShaderBeforeMain() {
|
||||||
"xe_out_fragment_data_2",
|
"xe_out_fragment_data_2",
|
||||||
"xe_out_fragment_data_3",
|
"xe_out_fragment_data_3",
|
||||||
};
|
};
|
||||||
uint32_t fragment_data_outputs_written =
|
uint32_t color_targets_remaining = current_shader().writes_color_targets();
|
||||||
current_shader().writes_color_targets() &
|
uint32_t color_target_index;
|
||||||
~GetSpirvShaderModification().pixel.color_outputs_disabled;
|
while (xe::bit_scan_forward(color_targets_remaining, &color_target_index)) {
|
||||||
for (uint32_t i = 0; i < xenos::kMaxColorRenderTargets; ++i) {
|
color_targets_remaining &= ~(UINT32_C(1) << color_target_index);
|
||||||
if (!(fragment_data_outputs_written & (uint32_t(1) << i))) {
|
spv::Id output_fragment_data_rt = builder_->createVariable(
|
||||||
continue;
|
spv::NoPrecision, spv::StorageClassOutput, type_float4_,
|
||||||
}
|
kFragmentDataNames[color_target_index]);
|
||||||
spv::Id output_fragment_data_rt =
|
output_fragment_data_[color_target_index] = output_fragment_data_rt;
|
||||||
builder_->createVariable(spv::NoPrecision, spv::StorageClassOutput,
|
|
||||||
type_float4_, kFragmentDataNames[i]);
|
|
||||||
output_fragment_data_[i] = output_fragment_data_rt;
|
|
||||||
builder_->addDecoration(output_fragment_data_rt, spv::DecorationLocation,
|
builder_->addDecoration(output_fragment_data_rt, spv::DecorationLocation,
|
||||||
int(i));
|
int(color_target_index));
|
||||||
// Make invariant as pixel shaders may be used for various precise
|
// Make invariant as pixel shaders may be used for various precise
|
||||||
// computations.
|
// computations.
|
||||||
builder_->addDecoration(output_fragment_data_rt, spv::DecorationInvariant);
|
builder_->addDecoration(output_fragment_data_rt, spv::DecorationInvariant);
|
||||||
|
|
|
@ -46,11 +46,6 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||||
struct PixelShaderModification {
|
struct PixelShaderModification {
|
||||||
// Dynamically indexable register count from SQ_PROGRAM_CNTL.
|
// Dynamically indexable register count from SQ_PROGRAM_CNTL.
|
||||||
uint32_t dynamic_addressable_register_count : 8;
|
uint32_t dynamic_addressable_register_count : 8;
|
||||||
// Color outputs removed from the shader to implement a zero color write
|
|
||||||
// mask when independent blending (and thus independent write masks) is
|
|
||||||
// not supported without switching to a render pass with some attachments
|
|
||||||
// actually excluded.
|
|
||||||
uint32_t color_outputs_disabled : 4;
|
|
||||||
} pixel;
|
} pixel;
|
||||||
uint64_t value = 0;
|
uint64_t value = 0;
|
||||||
|
|
||||||
|
|
|
@ -141,33 +141,6 @@ VulkanPipelineCache::GetCurrentPixelShaderModification(
|
||||||
shader.GetDynamicAddressableRegisterCount(
|
shader.GetDynamicAddressableRegisterCount(
|
||||||
sq_program_cntl.ps_num_reg)));
|
sq_program_cntl.ps_num_reg)));
|
||||||
|
|
||||||
const ui::vulkan::VulkanProvider& provider =
|
|
||||||
command_processor_.GetVulkanProvider();
|
|
||||||
const VkPhysicalDeviceFeatures& device_features = provider.device_features();
|
|
||||||
if (!device_features.independentBlend) {
|
|
||||||
// Since without independent blending, the write mask is common for all
|
|
||||||
// attachments, but the render pass may still include the attachments from
|
|
||||||
// previous draws (to prevent excessive render pass changes potentially
|
|
||||||
// doing stores and loads), disable writing to render targets with a
|
|
||||||
// completely empty write mask by removing the output from the shader.
|
|
||||||
// Only explicitly excluding render targets that the shader actually writes
|
|
||||||
// to, for better pipeline storage compatibility between devices with and
|
|
||||||
// without independent blending (so in the usual situation - the shader
|
|
||||||
// doesn't write to any render targets disabled via the color mask - no
|
|
||||||
// explicit disabling of shader outputs will be needed, and the disabled
|
|
||||||
// output mask will be 0).
|
|
||||||
uint32_t color_targets_remaining = shader.writes_color_targets();
|
|
||||||
uint32_t color_target_index;
|
|
||||||
while (xe::bit_scan_forward(color_targets_remaining, &color_target_index)) {
|
|
||||||
color_targets_remaining &= ~(uint32_t(1) << color_target_index);
|
|
||||||
if (!(normalized_color_mask &
|
|
||||||
(uint32_t(0b1111) << (4 * color_target_index)))) {
|
|
||||||
modification.pixel.color_outputs_disabled |= uint32_t(1)
|
|
||||||
<< color_target_index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return modification;
|
return modification;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue