[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_with_attachments,
bool native_2x_msaa_no_attachments, bool native_2x_msaa_no_attachments,
bool edram_fragment_shader_interlock, bool edram_fragment_shader_interlock,
bool gamma_render_target_as_srgb = false,
uint32_t draw_resolution_scale_x = 1, uint32_t draw_resolution_scale_x = 1,
uint32_t draw_resolution_scale_y = 1) uint32_t draw_resolution_scale_y = 1)
: features_(features), : features_(features),
native_2x_msaa_with_attachments_(native_2x_msaa_with_attachments), native_2x_msaa_with_attachments_(native_2x_msaa_with_attachments),
native_2x_msaa_no_attachments_(native_2x_msaa_no_attachments), native_2x_msaa_no_attachments_(native_2x_msaa_no_attachments),
edram_fragment_shader_interlock_(edram_fragment_shader_interlock), 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_x_(draw_resolution_scale_x),
draw_resolution_scale_y_(draw_resolution_scale_y) {} 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 // flow of the main function, and that there are no returns before either
// (there's a single return from the shader). // (there's a single return from the shader).
bool edram_fragment_shader_interlock_; 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 // Is currently writing the empty depth-only pixel shader, such as for depth
// and stencil testing with fragment shader interlock. // and stencil testing with fragment shader interlock.

View File

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

View File

@@ -155,6 +155,9 @@ class VulkanRenderTargetCache final : public RenderTargetCache {
return depth_unorm24_vulkan_format_supported_; return depth_unorm24_vulkan_format_supported_;
} }
bool depth_float24_round() const { return depth_float24_round_; } 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 { bool msaa_2x_attachments_supported() const {
return msaa_2x_attachments_supported_; return msaa_2x_attachments_supported_;