GPU: Two-pass rendering for B-F transparency

This commit is contained in:
Connor McLaughlin 2019-10-06 13:09:03 +10:00
parent 7254d48835
commit 5627955900
5 changed files with 65 additions and 47 deletions

View File

@ -245,12 +245,14 @@ void main()
return ss.str(); return ss.str();
} }
std::string GPU_HW::GenerateFragmentShader(bool transparent, bool textured, TextureColorMode texture_color_mode, std::string GPU_HW::GenerateFragmentShader(TransparencyRenderMode transparency, bool textured,
bool blending) TextureColorMode texture_color_mode, bool blending)
{ {
std::stringstream ss; std::stringstream ss;
GenerateShaderHeader(ss); GenerateShaderHeader(ss);
DefineMacro(ss, "TRANSPARENT", transparent); DefineMacro(ss, "TRANSPARENT", transparency != TransparencyRenderMode::Off);
DefineMacro(ss, "TRANSPARENT_ONLY_OPAQUE", transparency == TransparencyRenderMode::OnlyOpaque);
DefineMacro(ss, "TRANSPARENT_ONLY_TRANSPARENT", transparency == TransparencyRenderMode::OnlyTransparent);
DefineMacro(ss, "TEXTURED", textured); DefineMacro(ss, "TEXTURED", textured);
DefineMacro(ss, "PALETTE", DefineMacro(ss, "PALETTE",
textured && (texture_color_mode == GPU::TextureColorMode::Palette4Bit || textured && (texture_color_mode == GPU::TextureColorMode::Palette4Bit ||
@ -337,9 +339,19 @@ void main()
#if TRANSPARENT #if TRANSPARENT
// Apply semitransparency. If not a semitransparent texel, destination alpha is ignored. // Apply semitransparency. If not a semitransparent texel, destination alpha is ignored.
if (texcol.a != 0) if (texcol.a != 0)
{
#if TRANSPARENT_ONLY_OPAQUE
discard;
#endif
o_col0 = vec4(color * u_transparent_alpha.x, u_transparent_alpha.y); o_col0 = vec4(color * u_transparent_alpha.x, u_transparent_alpha.y);
}
else else
{
#if TRANSPARENT_ONLY_TRANSPARENT
discard;
#endif
o_col0 = vec4(color, 0.0); o_col0 = vec4(color, 0.0);
}
#else #else
// Mask bit from texture. // Mask bit from texture.
o_col0 = vec4(color, texcol.a); o_col0 = vec4(color, texcol.a);
@ -575,4 +587,5 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices)
} }
LoadVertices(rc, num_vertices); LoadVertices(rc, num_vertices);
FlushRender();
} }

View File

@ -56,6 +56,14 @@ protected:
std::vector<HWVertex> vertices; std::vector<HWVertex> vertices;
}; };
enum class TransparencyRenderMode
{
Off,
TransparentAndOpaque,
OnlyOpaque,
OnlyTransparent
};
static constexpr u32 VERTEX_BUFFER_SIZE = 1 * 1024 * 1024; static constexpr u32 VERTEX_BUFFER_SIZE = 1 * 1024 * 1024;
static constexpr u32 MAX_BATCH_VERTEX_COUNT = VERTEX_BUFFER_SIZE / sizeof(HWVertex); static constexpr u32 MAX_BATCH_VERTEX_COUNT = VERTEX_BUFFER_SIZE / sizeof(HWVertex);
static constexpr u32 TEXTURE_TILE_SIZE = 256; static constexpr u32 TEXTURE_TILE_SIZE = 256;
@ -85,8 +93,8 @@ protected:
} }
std::string GenerateVertexShader(bool textured); std::string GenerateVertexShader(bool textured);
std::string GenerateFragmentShader(bool transparent, bool textured, TextureColorMode texture_color_mode, std::string GenerateFragmentShader(TransparencyRenderMode transparency, bool textured,
bool blending); TextureColorMode texture_color_mode, bool blending);
std::string GenerateScreenQuadVertexShader(); std::string GenerateScreenQuadVertexShader();
std::string GenerateFillFragmentShader(); std::string GenerateFillFragmentShader();
std::string GenerateRGB24DecodeFragmentShader(); std::string GenerateRGB24DecodeFragmentShader();

View File

@ -61,9 +61,6 @@ void GPU_HW_OpenGL::RestoreGraphicsAPIState()
glLineWidth(static_cast<float>(m_resolution_scale)); glLineWidth(static_cast<float>(m_resolution_scale));
UpdateDrawingArea(); UpdateDrawingArea();
m_last_transparency_enable = false;
glDisable(GL_BLEND);
glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
glBindVertexArray(m_vao_id); glBindVertexArray(m_vao_id);
} }
@ -291,17 +288,17 @@ void GPU_HW_OpenGL::CreateVertexBuffer()
bool GPU_HW_OpenGL::CompilePrograms() bool GPU_HW_OpenGL::CompilePrograms()
{ {
for (u32 textured = 0; textured < 2; textured++) for (u32 transparent = 0; transparent < 4; transparent++)
{ {
for (u32 blending = 0; blending < 2; blending++) for (u32 textured = 0; textured < 2; textured++)
{ {
for (u32 transparent = 0; transparent < 2; transparent++) for (u32 format = 0; format < 3; format++)
{ {
for (u32 format = 0; format < 3; format++) for (u32 blending = 0; blending < 2; blending++)
{ {
// TODO: eliminate duplicate shaders here // TODO: eliminate duplicate shaders here
if (!CompileProgram(m_render_programs[transparent][textured][format][blending], if (!CompileProgram(m_render_programs[transparent][textured][format][blending],
ConvertToBoolUnchecked(transparent), ConvertToBoolUnchecked(textured), static_cast<TransparencyRenderMode>(transparent), ConvertToBoolUnchecked(textured),
static_cast<TextureColorMode>(format), ConvertToBoolUnchecked(blending))) static_cast<TextureColorMode>(format), ConvertToBoolUnchecked(blending)))
{ {
return false; return false;
@ -329,7 +326,7 @@ bool GPU_HW_OpenGL::CompilePrograms()
return true; return true;
} }
bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, bool transparent, bool textured, bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, TransparencyRenderMode transparent, bool textured,
TextureColorMode texture_color_mode, bool blending) TextureColorMode texture_color_mode, bool blending)
{ {
const std::string vs = GenerateVertexShader(textured); const std::string vs = GenerateVertexShader(textured);
@ -366,10 +363,10 @@ bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, bool transparent, bool tex
return true; return true;
} }
void GPU_HW_OpenGL::SetDrawState() void GPU_HW_OpenGL::SetDrawState(TransparencyRenderMode render_mode)
{ {
const GL::Program& prog = const GL::Program& prog =
m_render_programs[BoolToUInt32(m_batch.transparency_enable)][BoolToUInt32(m_batch.texture_enable)] m_render_programs[static_cast<u32>(render_mode)][BoolToUInt32(m_batch.texture_enable)]
[static_cast<u32>(m_batch.texture_color_mode)][BoolToUInt32(m_batch.texture_blending_enable)]; [static_cast<u32>(m_batch.texture_color_mode)][BoolToUInt32(m_batch.texture_blending_enable)];
prog.Bind(); prog.Bind();
@ -392,25 +389,17 @@ void GPU_HW_OpenGL::SetDrawState()
m_vram_read_texture->Bind(); m_vram_read_texture->Bind();
} }
if (m_last_transparency_enable != m_batch.transparency_enable || if (render_mode == TransparencyRenderMode::Off || render_mode == TransparencyRenderMode::OnlyOpaque)
(m_last_transparency_enable && m_last_transparency_mode != m_batch.transparency_mode))
{ {
m_last_transparency_enable = m_batch.texture_enable; glDisable(GL_BLEND);
m_last_transparency_mode = m_batch.transparency_mode; }
else
if (!m_batch.transparency_enable) {
{ glEnable(GL_BLEND);
glDisable(GL_BLEND); glBlendEquationSeparate(
} m_batch.transparency_mode == TransparencyMode::BackgroundMinusForeground ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD,
else GL_FUNC_ADD);
{ glBlendFuncSeparate(GL_ONE, GL_SRC_ALPHA, GL_ONE, GL_ZERO);
glEnable(GL_BLEND);
glBlendEquationSeparate(m_batch.transparency_mode == GPU::TransparencyMode::BackgroundMinusForeground ?
GL_FUNC_REVERSE_SUBTRACT :
GL_FUNC_ADD,
GL_FUNC_ADD);
glBlendFuncSeparate(GL_ONE, GL_SRC_ALPHA, GL_ONE, GL_ZERO);
}
} }
if (m_drawing_area_changed) if (m_drawing_area_changed)
@ -472,8 +461,6 @@ void GPU_HW_OpenGL::UpdateDisplay()
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_vram_fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_vram_fbo);
glViewport(0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight()); glViewport(0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight());
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
if (m_last_transparency_enable)
glEnable(GL_BLEND);
} }
else else
{ {
@ -662,14 +649,26 @@ void GPU_HW_OpenGL::FlushRender()
m_stats.num_batches++; m_stats.num_batches++;
m_stats.num_vertices += static_cast<u32>(m_batch.vertices.size()); m_stats.num_vertices += static_cast<u32>(m_batch.vertices.size());
SetDrawState();
Assert((m_batch.vertices.size() * sizeof(HWVertex)) <= VERTEX_BUFFER_SIZE); Assert((m_batch.vertices.size() * sizeof(HWVertex)) <= VERTEX_BUFFER_SIZE);
glBufferSubData(GL_ARRAY_BUFFER, 0, static_cast<GLsizei>(sizeof(HWVertex) * m_batch.vertices.size()), glBufferSubData(GL_ARRAY_BUFFER, 0, static_cast<GLsizei>(sizeof(HWVertex) * m_batch.vertices.size()),
m_batch.vertices.data()); m_batch.vertices.data());
static constexpr std::array<GLenum, 4> gl_primitives = {{GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP}}; static constexpr std::array<GLenum, 4> gl_primitives = {{GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP}};
glDrawArrays(gl_primitives[static_cast<u8>(m_batch.primitive)], 0, static_cast<GLsizei>(m_batch.vertices.size()));
if (m_batch.transparency_enable && m_batch.texture_enable &&
m_batch.transparency_mode == GPU::TransparencyMode::BackgroundMinusForeground)
{
SetDrawState(TransparencyRenderMode::OnlyTransparent);
glDrawArrays(gl_primitives[static_cast<u8>(m_batch.primitive)], 0, static_cast<GLsizei>(m_batch.vertices.size()));
SetDrawState(TransparencyRenderMode::OnlyOpaque);
glDrawArrays(gl_primitives[static_cast<u8>(m_batch.primitive)], 0, static_cast<GLsizei>(m_batch.vertices.size()));
}
else
{
SetDrawState(m_batch.transparency_enable ? TransparencyRenderMode::TransparentAndOpaque :
TransparencyRenderMode::Off);
glDrawArrays(gl_primitives[static_cast<u8>(m_batch.primitive)], 0, static_cast<GLsizei>(m_batch.vertices.size()));
}
m_batch.vertices.clear(); m_batch.vertices.clear();
} }

View File

@ -51,9 +51,9 @@ private:
void CreateVertexBuffer(); void CreateVertexBuffer();
bool CompilePrograms(); bool CompilePrograms();
bool CompileProgram(GL::Program& prog, bool transparent, bool textured, TextureColorMode texture_color_mode, bool CompileProgram(GL::Program& prog, TransparencyRenderMode transparent, bool textured,
bool blending); TextureColorMode texture_color_mode, bool blending);
void SetDrawState(); void SetDrawState(TransparencyRenderMode render_mode);
// downsample texture - used for readbacks at >1xIR. // downsample texture - used for readbacks at >1xIR.
std::unique_ptr<GL::Texture> m_vram_texture; std::unique_ptr<GL::Texture> m_vram_texture;
@ -71,11 +71,9 @@ private:
GLuint m_attributeless_vao_id = 0; GLuint m_attributeless_vao_id = 0;
bool m_vram_read_texture_dirty = true; bool m_vram_read_texture_dirty = true;
bool m_last_transparency_enable = false;
TransparencyMode m_last_transparency_mode = TransparencyMode::BackgroundMinusForeground;
bool m_drawing_area_changed = true; bool m_drawing_area_changed = true;
std::array<std::array<std::array<std::array<GL::Program, 2>, 3>, 2>, 2> m_render_programs; std::array<std::array<std::array<std::array<GL::Program, 2>, 3>, 2>, 4> m_render_programs;
GL::Program m_reinterpret_rgb8_program; GL::Program m_reinterpret_rgb8_program;
GLStats m_stats = {}; GLStats m_stats = {};

View File

@ -94,9 +94,9 @@ int main(int argc, char* argv[])
g_pLog->SetConsoleOutputParams(true, "Pad SPU", level); g_pLog->SetConsoleOutputParams(true, "Pad SPU", level);
g_pLog->SetFilterLevel(level); g_pLog->SetFilterLevel(level);
#else #else
// g_pLog->SetConsoleOutputParams(true, nullptr, LOGLEVEL_DEBUG); g_pLog->SetConsoleOutputParams(true, nullptr, LOGLEVEL_DEBUG);
// g_pLog->SetConsoleOutputParams(true, "GPU GPU_HW_OpenGL SPU Pad DigitalController", LOGLEVEL_DEBUG); // g_pLog->SetConsoleOutputParams(true, "GPU GPU_HW_OpenGL SPU Pad DigitalController", LOGLEVEL_DEBUG);
g_pLog->SetConsoleOutputParams(true, "GPU GPU_HW_OpenGL SPU Pad DigitalController InterruptController", LOGLEVEL_DEBUG); // g_pLog->SetConsoleOutputParams(true, "GPU GPU_HW_OpenGL SPU Pad DigitalController InterruptController", LOGLEVEL_DEBUG);
// g_pLog->SetFilterLevel(LOGLEVEL_TRACE); // g_pLog->SetFilterLevel(LOGLEVEL_TRACE);
g_pLog->SetFilterLevel(LOGLEVEL_DEBUG); g_pLog->SetFilterLevel(LOGLEVEL_DEBUG);
// g_pLog->SetFilterLevel(LOGLEVEL_DEV); // g_pLog->SetFilterLevel(LOGLEVEL_DEV);