diff --git a/src/xenia/gpu/spirv_shader_translator.h b/src/xenia/gpu/spirv_shader_translator.h index 5ab2644c6..99c0d72fd 100644 --- a/src/xenia/gpu/spirv_shader_translator.h +++ b/src/xenia/gpu/spirv_shader_translator.h @@ -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. diff --git a/src/xenia/gpu/spirv_shader_translator_rb.cc b/src/xenia/gpu/spirv_shader_translator_rb.cc index 1589b652f..ec1ccf68b 100644 --- a/src/xenia/gpu/spirv_shader_translator_rb.cc +++ b/src/xenia/gpu/spirv_shader_translator_rb.cc @@ -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 color_rgba_shuffle_op = - std::make_unique( - 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 color_rgba_shuffle_op = + std::make_unique(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); diff --git a/src/xenia/gpu/vulkan/vulkan_pipeline_cache.cc b/src/xenia/gpu/vulkan/vulkan_pipeline_cache.cc index 066e7e40a..dc0129da9 100644 --- a/src/xenia/gpu/vulkan/vulkan_pipeline_cache.cc +++ b/src/xenia/gpu/vulkan/vulkan_pipeline_cache.cc @@ -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()); diff --git a/src/xenia/gpu/vulkan/vulkan_render_target_cache.cc b/src/xenia/gpu/vulkan/vulkan_render_target_cache.cc index 35382f43b..9783d3973 100644 --- a/src/xenia/gpu/vulkan/vulkan_render_target_cache.cc +++ b/src/xenia/gpu/vulkan/vulkan_render_target_cache.cc @@ -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[] = { diff --git a/src/xenia/gpu/vulkan/vulkan_render_target_cache.h b/src/xenia/gpu/vulkan/vulkan_render_target_cache.h index aa7ed5c7d..f1f1136b5 100644 --- a/src/xenia/gpu/vulkan/vulkan_render_target_cache.h +++ b/src/xenia/gpu/vulkan/vulkan_render_target_cache.h @@ -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_;