From 837fb6128b07b3b394e47da7c11ea667fc920f85 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 6 Feb 2021 20:05:57 +1000 Subject: [PATCH] GPU/HW: Fix mask bit when rendering with transparency and no DSB Fixes some sprites in Bloody Roar on Mali GPUs. --- src/core/gpu_hw.cpp | 2 +- src/core/gpu_hw.h | 17 ++++++------ src/core/gpu_hw_opengl.cpp | 14 +++++++--- src/core/gpu_hw_shadergen.cpp | 34 +++++++++-------------- src/core/gpu_hw_vulkan.cpp | 48 +++++++++++++++++++++++---------- src/core/shader_cache_version.h | 2 +- 6 files changed, 69 insertions(+), 48 deletions(-) diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index 2a691d00c..54819a59e 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -1168,7 +1168,7 @@ void GPU_HW::FlushRender() m_batch_ubo_dirty = false; } - if (m_batch.NeedsTwoPassRendering()) + if (NeedsTwoPassRendering()) { m_renderer_stats.num_batches += 2; DrawBatchVertices(BatchRenderMode::OnlyOpaque, m_batch_base_vertex, vertex_count); diff --git a/src/core/gpu_hw.h b/src/core/gpu_hw.h index 096a200b2..20b71bdc7 100644 --- a/src/core/gpu_hw.h +++ b/src/core/gpu_hw.h @@ -102,14 +102,6 @@ protected: bool check_mask_before_draw; bool use_depth_buffer; - // We need two-pass rendering when using BG-FG blending and texturing, as the transparency can be enabled - // on a per-pixel basis, and the opaque pixels shouldn't be blended at all. - bool NeedsTwoPassRendering() const - { - return transparency_mode == GPUTransparencyMode::BackgroundMinusForeground && - texture_mode != GPUTextureMode::Disabled; - } - // Returns the render mode for this batch. BatchRenderMode GetRenderMode() const { @@ -254,6 +246,15 @@ protected: return true; } + /// We need two-pass rendering when using BG-FG blending and texturing, as the transparency can be enabled + /// on a per-pixel basis, and the opaque pixels shouldn't be blended at all. + bool NeedsTwoPassRendering() const + { + return (m_batch.transparency_mode == GPUTransparencyMode::BackgroundMinusForeground && + m_batch.texture_mode != GPUTextureMode::Disabled) || + (m_batch.transparency_mode != GPUTransparencyMode::Disabled && !m_supports_dual_source_blend); + } + void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) override; void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, bool set_mask, bool check_mask) override; void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override; diff --git a/src/core/gpu_hw_opengl.cpp b/src/core/gpu_hw_opengl.cpp index bc7a4443f..2040fb7ad 100644 --- a/src/core/gpu_hw_opengl.cpp +++ b/src/core/gpu_hw_opengl.cpp @@ -361,8 +361,6 @@ void GPU_HW_OpenGL::SetCapabilities(HostDisplay* host_display) m_supports_dual_source_blend = (max_dual_source_draw_buffers > 0) && (GLAD_GL_VERSION_3_3 || GLAD_GL_ARB_blend_func_extended || GLAD_GL_EXT_blend_func_extended); - if (!m_supports_dual_source_blend) - Log_WarningPrintf("Dual-source blending is not supported, this may break some mask effects."); m_supports_geometry_shaders = GLAD_GL_VERSION_3_2 || GLAD_GL_ARB_geometry_shader4 || GLAD_GL_OES_geometry_shader || GLAD_GL_ES_VERSION_3_2; @@ -754,7 +752,17 @@ void GPU_HW_OpenGL::SetBlendMode() GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD, GL_FUNC_ADD); - glBlendFuncSeparate(GL_ONE, m_supports_dual_source_blend ? GL_SRC1_ALPHA : GL_SRC_ALPHA, GL_ONE, GL_ZERO); + if (m_supports_dual_source_blend) + { + glBlendFuncSeparate(GL_ONE, m_supports_dual_source_blend ? GL_SRC1_ALPHA : GL_SRC_ALPHA, GL_ONE, GL_ZERO); + } + else + { + const float factor = + (m_current_transparency_mode == GPUTransparencyMode::HalfBackgroundPlusHalfForeground) ? 0.5f : 1.0f; + glBlendFuncSeparate(GL_ONE, GL_CONSTANT_ALPHA, GL_ONE, GL_ZERO); + glBlendColor(0.0f, 0.0f, 0.0f, factor); + } } else { diff --git a/src/core/gpu_hw_shadergen.cpp b/src/core/gpu_hw_shadergen.cpp index 7d8787d74..59907a778 100644 --- a/src/core/gpu_hw_shadergen.cpp +++ b/src/core/gpu_hw_shadergen.cpp @@ -939,12 +939,12 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords) o_col0 = float4(color, oalpha); o_col1 = float4(0.0, 0.0, 0.0, u_dst_alpha_factor / ialpha); #else - o_col0 = float4(color, u_dst_alpha_factor / ialpha); + o_col0 = float4(color, oalpha); #endif -#if !PGXP_DEPTH - o_depth = oalpha * v_pos.z; -#endif + #if !PGXP_DEPTH + o_depth = oalpha * v_pos.z; + #endif } else { @@ -952,24 +952,16 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords) discard; #endif - #if TRANSPARENCY_ONLY_OPAQUE - // We don't output the second color here because it's not used (except for filtering). + #if USE_DUAL_SOURCE o_col0 = float4(color, oalpha); - #if USE_DUAL_SOURCE - o_col1 = float4(0.0, 0.0, 0.0, 1.0 - ialpha); - #endif + o_col1 = float4(0.0, 0.0, 0.0, 1.0 - ialpha); #else - #if USE_DUAL_SOURCE - o_col0 = float4(color, oalpha); - o_col1 = float4(0.0, 0.0, 0.0, 1.0 - ialpha); - #else - o_col0 = float4(color, 1.0 - ialpha); - #endif + o_col0 = float4(color, oalpha); #endif -#if !PGXP_DEPTH - o_depth = oalpha * v_pos.z; -#endif + #if !PGXP_DEPTH + o_depth = oalpha * v_pos.z; + #endif } #else // Non-transparency won't enable blending so we can write the mask here regardless. @@ -979,9 +971,9 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords) o_col1 = float4(0.0, 0.0, 0.0, 1.0 - ialpha); #endif -#if !PGXP_DEPTH - o_depth = oalpha * v_pos.z; -#endif + #if !PGXP_DEPTH + o_depth = oalpha * v_pos.z; + #endif #endif } )"; diff --git a/src/core/gpu_hw_vulkan.cpp b/src/core/gpu_hw_vulkan.cpp index 62fbb7389..39c90f718 100644 --- a/src/core/gpu_hw_vulkan.cpp +++ b/src/core/gpu_hw_vulkan.cpp @@ -174,7 +174,8 @@ void GPU_HW_Vulkan::ResetGraphicsAPIState() EndRenderPass(); if (m_host_display->GetDisplayTextureHandle() == &m_vram_texture) - m_vram_texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + m_vram_texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); } void GPU_HW_Vulkan::RestoreGraphicsAPIState() @@ -522,9 +523,9 @@ bool GPU_HW_Vulkan::CreateFramebuffer() !m_vram_read_texture.Create(texture_width, texture_height, 1, 1, texture_format, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) || - !m_display_texture.Create(GPU_MAX_DISPLAY_WIDTH * m_resolution_scale, - GPU_MAX_DISPLAY_HEIGHT * m_resolution_scale, 1, 1, texture_format, - VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + !m_display_texture.Create(GPU_MAX_DISPLAY_WIDTH * m_resolution_scale, GPU_MAX_DISPLAY_HEIGHT * m_resolution_scale, + 1, 1, texture_format, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, + VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) || !m_vram_readback_texture.Create(VRAM_WIDTH, VRAM_HEIGHT, 1, 1, texture_format, VK_SAMPLE_COUNT_1_BIT, @@ -924,16 +925,35 @@ bool GPU_HW_Vulkan::CompilePipelines() static_cast(render_mode) != BatchRenderMode::OnlyOpaque)) || m_texture_filtering != GPUTextureFilter::Nearest) { - gpbuilder.SetBlendAttachment( - 0, true, VK_BLEND_FACTOR_ONE, - m_supports_dual_source_blend ? VK_BLEND_FACTOR_SRC1_ALPHA : VK_BLEND_FACTOR_SRC_ALPHA, - (static_cast(transparency_mode) == - GPUTransparencyMode::BackgroundMinusForeground && - static_cast(render_mode) != BatchRenderMode::TransparencyDisabled && - static_cast(render_mode) != BatchRenderMode::OnlyOpaque) ? - VK_BLEND_OP_REVERSE_SUBTRACT : - VK_BLEND_OP_ADD, - VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD); + if (m_supports_dual_source_blend) + { + gpbuilder.SetBlendAttachment( + 0, true, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_SRC1_ALPHA, + (static_cast(transparency_mode) == + GPUTransparencyMode::BackgroundMinusForeground && + static_cast(render_mode) != BatchRenderMode::TransparencyDisabled && + static_cast(render_mode) != BatchRenderMode::OnlyOpaque) ? + VK_BLEND_OP_REVERSE_SUBTRACT : + VK_BLEND_OP_ADD, + VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD); + } + else + { + const float factor = (static_cast(transparency_mode) == + GPUTransparencyMode::HalfBackgroundPlusHalfForeground) ? + 0.5f : + 1.0f; + gpbuilder.SetBlendAttachment( + 0, true, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_CONSTANT_ALPHA, + (static_cast(transparency_mode) == + GPUTransparencyMode::BackgroundMinusForeground && + static_cast(render_mode) != BatchRenderMode::TransparencyDisabled && + static_cast(render_mode) != BatchRenderMode::OnlyOpaque) ? + VK_BLEND_OP_REVERSE_SUBTRACT : + VK_BLEND_OP_ADD, + VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD); + gpbuilder.SetBlendConstants(0.0f, 0.0f, 0.0f, factor); + } } gpbuilder.SetDynamicViewportAndScissorState(); diff --git a/src/core/shader_cache_version.h b/src/core/shader_cache_version.h index d643c1d92..54e2dbeb2 100644 --- a/src/core/shader_cache_version.h +++ b/src/core/shader_cache_version.h @@ -1,4 +1,4 @@ #pragma once #include "types.h" -static constexpr u32 SHADER_CACHE_VERSION = 1; \ No newline at end of file +static constexpr u32 SHADER_CACHE_VERSION = 2; \ No newline at end of file