[Vulkan] Add gamma_render_target_as_srgb support

This commit is contained in:
Herman S.
2025-11-25 16:56:58 +09:00
parent 5d74d69aa8
commit 48c13be2d5
5 changed files with 49 additions and 35 deletions

View File

@@ -368,12 +368,14 @@ class SpirvShaderTranslator : public ShaderTranslator {
bool native_2x_msaa_with_attachments,
bool native_2x_msaa_no_attachments,
bool edram_fragment_shader_interlock,
bool gamma_render_target_as_srgb = false,
uint32_t draw_resolution_scale_x = 1,
uint32_t draw_resolution_scale_y = 1)
: features_(features),
native_2x_msaa_with_attachments_(native_2x_msaa_with_attachments),
native_2x_msaa_no_attachments_(native_2x_msaa_no_attachments),
edram_fragment_shader_interlock_(edram_fragment_shader_interlock),
gamma_render_target_as_srgb_(gamma_render_target_as_srgb),
draw_resolution_scale_x_(draw_resolution_scale_x),
draw_resolution_scale_y_(draw_resolution_scale_y) {}
@@ -754,6 +756,9 @@ class SpirvShaderTranslator : public ShaderTranslator {
// flow of the main function, and that there are no returns before either
// (there's a single return from the shader).
bool edram_fragment_shader_interlock_;
// Whether with host render targets, k_8_8_8_8_GAMMA render targets are
// represented as host sRGB (gamma applied by the host after blending).
bool gamma_render_target_as_srgb_;
// Is currently writing the empty depth-only pixel shader, such as for depth
// and stencil testing with fragment shader interlock.

View File

@@ -1251,41 +1251,45 @@ void SpirvShaderTranslator::CompleteFragmentShaderInMain() {
if_rt_write_mask_not_empty.makeEndIf();
if_fsi_color_written.makeEndIf();
} else {
// Convert to gamma space - this is incorrect, since it must be done
// after blending on the Xbox 360, but this is just one of many blending
// issues in the host render target path.
// TODO(Triang3l): Gamma as sRGB check.
uint_vector_temp_.clear();
uint_vector_temp_.push_back(0);
uint_vector_temp_.push_back(1);
uint_vector_temp_.push_back(2);
spv::Id color_rgb = builder_->createRvalueSwizzle(
spv::NoPrecision, type_float3_, color, uint_vector_temp_);
spv::Id is_gamma = builder_->createBinOp(
spv::OpINotEqual, type_bool_,
builder_->createBinOp(
spv::OpBitwiseAnd, type_uint_, main_system_constant_flags_,
builder_->makeUintConstant(kSysFlag_ConvertColor0ToGamma
<< color_target_index)),
const_uint_0_);
SpirvBuilder::IfBuilder if_gamma(
is_gamma, spv::SelectionControlDontFlattenMask, *builder_);
spv::Id color_rgb_gamma = LinearToPWLGamma(color_rgb, false);
if_gamma.makeEndIf();
color_rgb = if_gamma.createMergePhi(color_rgb_gamma, color_rgb);
{
std::unique_ptr<spv::Instruction> color_rgba_shuffle_op =
std::make_unique<spv::Instruction>(
builder_->getUniqueId(), type_float4_, spv::OpVectorShuffle);
color_rgba_shuffle_op->addIdOperand(color_rgb);
color_rgba_shuffle_op->addIdOperand(color);
color_rgba_shuffle_op->addImmediateOperand(0);
color_rgba_shuffle_op->addImmediateOperand(1);
color_rgba_shuffle_op->addImmediateOperand(2);
color_rgba_shuffle_op->addImmediateOperand(3 + 3);
color = color_rgba_shuffle_op->getResultId();
builder_->getBuildPoint()->addInstruction(
std::move(color_rgba_shuffle_op));
if (!gamma_render_target_as_srgb_) {
// Convert to gamma space - this is incorrect, since it must be done
// after blending on the Xbox 360, but this is just one of many
// blending issues in the host render target path. When
// gamma_render_target_as_srgb_ is enabled, the host handles gamma
// conversion via sRGB render target format after blending.
uint_vector_temp_.clear();
uint_vector_temp_.push_back(0);
uint_vector_temp_.push_back(1);
uint_vector_temp_.push_back(2);
spv::Id color_rgb = builder_->createRvalueSwizzle(
spv::NoPrecision, type_float3_, color, uint_vector_temp_);
spv::Id is_gamma = builder_->createBinOp(
spv::OpINotEqual, type_bool_,
builder_->createBinOp(
spv::OpBitwiseAnd, type_uint_, main_system_constant_flags_,
builder_->makeUintConstant(kSysFlag_ConvertColor0ToGamma
<< color_target_index)),
const_uint_0_);
SpirvBuilder::IfBuilder if_gamma(
is_gamma, spv::SelectionControlDontFlattenMask, *builder_);
spv::Id color_rgb_gamma = LinearToPWLGamma(color_rgb, false);
if_gamma.makeEndIf();
color_rgb = if_gamma.createMergePhi(color_rgb_gamma, color_rgb);
{
std::unique_ptr<spv::Instruction> color_rgba_shuffle_op =
std::make_unique<spv::Instruction>(builder_->getUniqueId(),
type_float4_,
spv::OpVectorShuffle);
color_rgba_shuffle_op->addIdOperand(color_rgb);
color_rgba_shuffle_op->addIdOperand(color);
color_rgba_shuffle_op->addImmediateOperand(0);
color_rgba_shuffle_op->addImmediateOperand(1);
color_rgba_shuffle_op->addImmediateOperand(2);
color_rgba_shuffle_op->addImmediateOperand(3 + 3);
color = color_rgba_shuffle_op->getResultId();
builder_->getBuildPoint()->addInstruction(
std::move(color_rgba_shuffle_op));
}
}
builder_->createStore(color, color_variable);

View File

@@ -59,6 +59,7 @@ bool VulkanPipelineCache::Initialize() {
render_target_cache_.msaa_2x_attachments_supported(),
render_target_cache_.msaa_2x_no_attachments_supported(),
edram_fragment_shader_interlock,
render_target_cache_.gamma_render_target_as_srgb(),
render_target_cache_.draw_resolution_scale_x(),
render_target_cache_.draw_resolution_scale_y());

View File

@@ -520,6 +520,7 @@ bool VulkanRenderTargetCache::Initialize(uint32_t shared_memory_binding_count) {
// Host render targets.
depth_float24_round_ = cvars::depth_float24_round;
gamma_render_target_as_srgb_ = cvars::gamma_render_target_as_srgb;
// Host depth storing pipeline layout.
VkDescriptorSetLayout host_depth_store_descriptor_set_layouts[] = {

View File

@@ -155,6 +155,9 @@ class VulkanRenderTargetCache final : public RenderTargetCache {
return depth_unorm24_vulkan_format_supported_;
}
bool depth_float24_round() const { return depth_float24_round_; }
bool gamma_render_target_as_srgb() const {
return gamma_render_target_as_srgb_;
}
bool msaa_2x_attachments_supported() const {
return msaa_2x_attachments_supported_;