GPU/HW: Fix mask bit when rendering with transparency and no DSB

Fixes some sprites in Bloody Roar on Mali GPUs.
This commit is contained in:
Connor McLaughlin 2021-02-06 20:05:57 +10:00
parent 011df33fc4
commit 837fb6128b
6 changed files with 69 additions and 48 deletions

View File

@ -1168,7 +1168,7 @@ void GPU_HW::FlushRender()
m_batch_ubo_dirty = false; m_batch_ubo_dirty = false;
} }
if (m_batch.NeedsTwoPassRendering()) if (NeedsTwoPassRendering())
{ {
m_renderer_stats.num_batches += 2; m_renderer_stats.num_batches += 2;
DrawBatchVertices(BatchRenderMode::OnlyOpaque, m_batch_base_vertex, vertex_count); DrawBatchVertices(BatchRenderMode::OnlyOpaque, m_batch_base_vertex, vertex_count);

View File

@ -102,14 +102,6 @@ protected:
bool check_mask_before_draw; bool check_mask_before_draw;
bool use_depth_buffer; 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. // Returns the render mode for this batch.
BatchRenderMode GetRenderMode() const BatchRenderMode GetRenderMode() const
{ {
@ -254,6 +246,15 @@ protected:
return true; 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 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 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; void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override;

View File

@ -361,8 +361,6 @@ void GPU_HW_OpenGL::SetCapabilities(HostDisplay* host_display)
m_supports_dual_source_blend = m_supports_dual_source_blend =
(max_dual_source_draw_buffers > 0) && (max_dual_source_draw_buffers > 0) &&
(GLAD_GL_VERSION_3_3 || GLAD_GL_ARB_blend_func_extended || GLAD_GL_EXT_blend_func_extended); (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 = 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; 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_REVERSE_SUBTRACT :
GL_FUNC_ADD, GL_FUNC_ADD,
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 else
{ {

View File

@ -939,12 +939,12 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords)
o_col0 = float4(color, oalpha); o_col0 = float4(color, oalpha);
o_col1 = float4(0.0, 0.0, 0.0, u_dst_alpha_factor / ialpha); o_col1 = float4(0.0, 0.0, 0.0, u_dst_alpha_factor / ialpha);
#else #else
o_col0 = float4(color, u_dst_alpha_factor / ialpha); o_col0 = float4(color, oalpha);
#endif #endif
#if !PGXP_DEPTH #if !PGXP_DEPTH
o_depth = oalpha * v_pos.z; o_depth = oalpha * v_pos.z;
#endif #endif
} }
else else
{ {
@ -952,24 +952,16 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords)
discard; discard;
#endif #endif
#if TRANSPARENCY_ONLY_OPAQUE #if USE_DUAL_SOURCE
// We don't output the second color here because it's not used (except for filtering).
o_col0 = float4(color, oalpha); o_col0 = float4(color, oalpha);
#if USE_DUAL_SOURCE o_col1 = float4(0.0, 0.0, 0.0, 1.0 - ialpha);
o_col1 = float4(0.0, 0.0, 0.0, 1.0 - ialpha);
#endif
#else #else
#if USE_DUAL_SOURCE o_col0 = float4(color, oalpha);
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
#endif #endif
#if !PGXP_DEPTH #if !PGXP_DEPTH
o_depth = oalpha * v_pos.z; o_depth = oalpha * v_pos.z;
#endif #endif
} }
#else #else
// Non-transparency won't enable blending so we can write the mask here regardless. // 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); o_col1 = float4(0.0, 0.0, 0.0, 1.0 - ialpha);
#endif #endif
#if !PGXP_DEPTH #if !PGXP_DEPTH
o_depth = oalpha * v_pos.z; o_depth = oalpha * v_pos.z;
#endif #endif
#endif #endif
} }
)"; )";

View File

@ -174,7 +174,8 @@ void GPU_HW_Vulkan::ResetGraphicsAPIState()
EndRenderPass(); EndRenderPass();
if (m_host_display->GetDisplayTextureHandle() == &m_vram_texture) 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() 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, !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_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) || VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) ||
!m_display_texture.Create(GPU_MAX_DISPLAY_WIDTH * m_resolution_scale, !m_display_texture.Create(GPU_MAX_DISPLAY_WIDTH * m_resolution_scale, GPU_MAX_DISPLAY_HEIGHT * m_resolution_scale,
GPU_MAX_DISPLAY_HEIGHT * m_resolution_scale, 1, 1, texture_format, 1, 1, texture_format, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D,
VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_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, !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<BatchRenderMode>(render_mode) != BatchRenderMode::OnlyOpaque)) || static_cast<BatchRenderMode>(render_mode) != BatchRenderMode::OnlyOpaque)) ||
m_texture_filtering != GPUTextureFilter::Nearest) m_texture_filtering != GPUTextureFilter::Nearest)
{ {
gpbuilder.SetBlendAttachment( if (m_supports_dual_source_blend)
0, true, VK_BLEND_FACTOR_ONE, {
m_supports_dual_source_blend ? VK_BLEND_FACTOR_SRC1_ALPHA : VK_BLEND_FACTOR_SRC_ALPHA, gpbuilder.SetBlendAttachment(
(static_cast<GPUTransparencyMode>(transparency_mode) == 0, true, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_SRC1_ALPHA,
GPUTransparencyMode::BackgroundMinusForeground && (static_cast<GPUTransparencyMode>(transparency_mode) ==
static_cast<BatchRenderMode>(render_mode) != BatchRenderMode::TransparencyDisabled && GPUTransparencyMode::BackgroundMinusForeground &&
static_cast<BatchRenderMode>(render_mode) != BatchRenderMode::OnlyOpaque) ? static_cast<BatchRenderMode>(render_mode) != BatchRenderMode::TransparencyDisabled &&
VK_BLEND_OP_REVERSE_SUBTRACT : static_cast<BatchRenderMode>(render_mode) != BatchRenderMode::OnlyOpaque) ?
VK_BLEND_OP_ADD, VK_BLEND_OP_REVERSE_SUBTRACT :
VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD); VK_BLEND_OP_ADD,
VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD);
}
else
{
const float factor = (static_cast<GPUTransparencyMode>(transparency_mode) ==
GPUTransparencyMode::HalfBackgroundPlusHalfForeground) ?
0.5f :
1.0f;
gpbuilder.SetBlendAttachment(
0, true, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_CONSTANT_ALPHA,
(static_cast<GPUTransparencyMode>(transparency_mode) ==
GPUTransparencyMode::BackgroundMinusForeground &&
static_cast<BatchRenderMode>(render_mode) != BatchRenderMode::TransparencyDisabled &&
static_cast<BatchRenderMode>(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(); gpbuilder.SetDynamicViewportAndScissorState();

View File

@ -1,4 +1,4 @@
#pragma once #pragma once
#include "types.h" #include "types.h"
static constexpr u32 SHADER_CACHE_VERSION = 1; static constexpr u32 SHADER_CACHE_VERSION = 2;