shader: dual-source blending (Vulkan)

This commit is contained in:
nmzik
2026-09-17 23:16:51 +04:00
parent cbedf5707f
commit 6493674726
5 changed files with 30 additions and 2 deletions
@@ -593,6 +593,21 @@ PipelineCache::GraphicsPrograms PipelineCache::GetGraphicsPrograms(
ShaderParams pixel_params;
if (pixel_active) {
pixel_params = PrepareProgram(pixel_regs, sh, target_export_mapping, pixel_info);
const auto& blend = context.GetBlendControl(0);
const auto is_dual_source = [](uint8_t factor) {
return factor >= static_cast<uint8_t>(Prospero::BlendFactor::kSrc1Color) &&
factor <= static_cast<uint8_t>(Prospero::BlendFactor::kOneMinusSrc1Alpha);
};
pixel_info.dual_source_blending =
blend.enable && !context.GetRenderTarget(0).info.blend_bypass &&
(is_dual_source(blend.color_srcblend) || is_dual_source(blend.color_destblend) ||
(blend.separate_alpha_blend &&
(is_dual_source(blend.alpha_srcblend) || is_dual_source(blend.alpha_destblend))));
if (pixel_info.dual_source_blending) {
// MRT1 supplies a second blend source for the same render target as MRT0.
pixel_info.target_output_mode[1] = pixel_info.target_output_mode[0];
pixel_info.target_export_mapping[1] = pixel_info.target_export_mapping[0];
}
}
if (context.GetClipControl().clip_disable) {
const auto& viewport = context.GetScreenViewport().viewports[0];
@@ -610,10 +610,11 @@ static vk::Device VulkanCreateDevice(GraphicContext& graphics,
graphics.mesh_shader_properties.maxMeshOutputPrimitives,
graphics.mesh_shader_properties.maxMeshSharedMemorySize);
}
// VulkanFindPhysicalDevice already checked the required creation features. These two
// VulkanFindPhysicalDevice already checked the required creation features. These
// requirements are specific to this creation path and are not part of device selection.
EXIT_NOT_IMPLEMENTED(supported_features2.features.shaderInt64 != VK_TRUE);
EXIT_NOT_IMPLEMENTED(supported_features2.features.vertexPipelineStoresAndAtomics != VK_TRUE);
EXIT_NOT_IMPLEMENTED(supported_features2.features.dualSrcBlend != VK_TRUE);
vk::PhysicalDeviceFeatures device_features {};
device_features.fragmentStoresAndAtomics = VK_TRUE;
device_features.samplerAnisotropy = VK_TRUE;
@@ -624,6 +625,7 @@ static vk::Device VulkanCreateDevice(GraphicContext& graphics,
device_features.shaderStorageImageWriteWithoutFormat = VK_TRUE;
device_features.shaderImageGatherExtended = VK_TRUE;
device_features.independentBlend = VK_TRUE;
device_features.dualSrcBlend = VK_TRUE;
device_features.tessellationShader = VK_TRUE;
device_features.sampleRateShading = VK_TRUE;
device_features.depthBiasClamp = VK_TRUE;
@@ -553,8 +553,17 @@ void DefineOutputs(EmitterState& state) {
const auto type = uint_output ? TypeU32Vector(state, 4) : TypeF32Vector(state, 4);
binding.variable_id = DefineInterfaceVariable(state, type, spv::StorageClassOutput,
binding.debug_name.c_str());
const bool dual_source = binding.kind == IR::StageOutputKind::Mrt &&
state.program.stage == ShaderType::Pixel &&
state.input_info.pixel->dual_source_blending;
EXIT_NOT_IMPLEMENTED(dual_source && binding.index > 1);
state.builder.AddAnnotation(spv::OpDecorate, binding.variable_id,
spv::DecorationLocation, binding.location);
spv::DecorationLocation,
dual_source ? 0u : binding.location);
if (dual_source) {
state.builder.AddAnnotation(spv::OpDecorate, binding.variable_id,
spv::DecorationIndex, binding.index);
}
break;
}
}
+1
View File
@@ -721,6 +721,7 @@ void BuildStageStaticKey(const ShaderPixelInputInfo& info, std::vector<uint32_t>
key.push_back(static_cast<uint32_t>(info.ps_depth_export_enable));
key.push_back(static_cast<uint32_t>(info.ps_sample_mask_export_enable));
key.push_back(static_cast<uint32_t>(info.ps_early_z));
key.push_back(static_cast<uint32_t>(info.dual_source_blending));
key.insert(key.end(), std::begin(info.target_output_mode), std::end(info.target_output_mode));
for (uint32_t base = 0; base < info.target_export_mapping.size(); base += 4u) {
uint32_t packed = 0;
+1
View File
@@ -175,6 +175,7 @@ struct ShaderPixelInputInfo {
bool ps_depth_export_enable = false;
bool ps_sample_mask_export_enable = false;
bool ps_sample_shading = false;
bool dual_source_blending = false;
bool ps_early_z = false;
bool ps_execute_on_noop = false;
ShaderStageRuntime stage;