mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-22 13:55:38 +00:00
GPU: Properly handle semitransparent pixels
This commit is contained in:
parent
40d2497087
commit
c02cbc57e8
|
@ -263,4 +263,76 @@ void Program::Uniform4f(u32 index, float x, float y, float z, float w) const
|
|||
glUniform4f(location, x, y, z, w);
|
||||
}
|
||||
|
||||
void Program::Uniform2uiv(u32 index, const u32* v) const
|
||||
{
|
||||
Assert(index < m_uniform_locations.size());
|
||||
const int location = m_uniform_locations[index];
|
||||
if (location >= 0)
|
||||
glUniform2uiv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform3uiv(u32 index, const u32* v) const
|
||||
{
|
||||
Assert(index < m_uniform_locations.size());
|
||||
const int location = m_uniform_locations[index];
|
||||
if (location >= 0)
|
||||
glUniform3uiv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform4uiv(u32 index, const u32* v) const
|
||||
{
|
||||
Assert(index < m_uniform_locations.size());
|
||||
const int location = m_uniform_locations[index];
|
||||
if (location >= 0)
|
||||
glUniform4uiv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform2iv(u32 index, const s32* v) const
|
||||
{
|
||||
Assert(index < m_uniform_locations.size());
|
||||
const int location = m_uniform_locations[index];
|
||||
if (location >= 0)
|
||||
glUniform2iv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform3iv(u32 index, const s32* v) const
|
||||
{
|
||||
Assert(index < m_uniform_locations.size());
|
||||
const int location = m_uniform_locations[index];
|
||||
if (location >= 0)
|
||||
glUniform3iv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform4iv(u32 index, const s32* v) const
|
||||
{
|
||||
Assert(index < m_uniform_locations.size());
|
||||
const int location = m_uniform_locations[index];
|
||||
if (location >= 0)
|
||||
glUniform4iv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform2fv(u32 index, const float* v) const
|
||||
{
|
||||
Assert(index < m_uniform_locations.size());
|
||||
const int location = m_uniform_locations[index];
|
||||
if (location >= 0)
|
||||
glUniform2fv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform3fv(u32 index, const float* v) const
|
||||
{
|
||||
Assert(index < m_uniform_locations.size());
|
||||
const int location = m_uniform_locations[index];
|
||||
if (location >= 0)
|
||||
glUniform3fv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform4fv(u32 index, const float* v) const
|
||||
{
|
||||
Assert(index < m_uniform_locations.size());
|
||||
const int location = m_uniform_locations[index];
|
||||
if (location >= 0)
|
||||
glUniform4fv(location, 1, v);
|
||||
}
|
||||
|
||||
} // namespace GL
|
|
@ -40,6 +40,15 @@ public:
|
|||
void Uniform2f(u32 index, float x, float y) const;
|
||||
void Uniform3f(u32 index, float x, float y, float z) const;
|
||||
void Uniform4f(u32 index, float x, float y, float z, float w) const;
|
||||
void Uniform2uiv(u32 index, const u32* v) const;
|
||||
void Uniform3uiv(u32 index, const u32* v) const;
|
||||
void Uniform4uiv(u32 index, const u32* v) const;
|
||||
void Uniform2iv(u32 index, const s32* v) const;
|
||||
void Uniform3iv(u32 index, const s32* v) const;
|
||||
void Uniform4iv(u32 index, const s32* v) const;
|
||||
void Uniform2fv(u32 index, const float* v) const;
|
||||
void Uniform3fv(u32 index, const float* v) const;
|
||||
void Uniform4fv(u32 index, const float* v) const;
|
||||
|
||||
private:
|
||||
GLuint m_program_id = 0;
|
||||
|
|
|
@ -176,7 +176,7 @@ in ivec2 a_pos;
|
|||
in vec4 a_col0;
|
||||
in vec2 a_tex0;
|
||||
|
||||
out vec4 v_col0;
|
||||
out vec3 v_col0;
|
||||
#if TEXTURED
|
||||
out vec2 v_tex0;
|
||||
#endif
|
||||
|
@ -190,7 +190,7 @@ void main()
|
|||
float pos_y = (float(a_pos.y + u_pos_offset.y) / -256.0) + 1.0;
|
||||
gl_Position = vec4(pos_x, pos_y, 0.0, 1.0);
|
||||
|
||||
v_col0 = a_col0;
|
||||
v_col0 = a_col0.rgb;
|
||||
#if TEXTURED
|
||||
v_tex0 = a_tex0;
|
||||
#endif
|
||||
|
@ -200,7 +200,8 @@ void main()
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
std::string GPU_HW::GenerateFragmentShader(bool textured, bool blending, TextureColorMode texture_color_mode)
|
||||
std::string GPU_HW::GenerateFragmentShader(bool textured, bool blending, bool transparent,
|
||||
TextureColorMode texture_color_mode)
|
||||
{
|
||||
std::stringstream ss;
|
||||
GenerateShaderHeader(ss);
|
||||
|
@ -213,7 +214,8 @@ std::string GPU_HW::GenerateFragmentShader(bool textured, bool blending, Texture
|
|||
DefineMacro(ss, "PALETTE_8_BIT", textured && texture_color_mode == GPU::TextureColorMode::Palette8Bit);
|
||||
|
||||
ss << R"(
|
||||
in vec4 v_col0;
|
||||
in vec3 v_col0;
|
||||
uniform vec2 u_transparent_alpha;
|
||||
#if TEXTURED
|
||||
in vec2 v_tex0;
|
||||
uniform sampler2D samp0;
|
||||
|
@ -272,13 +274,30 @@ void main()
|
|||
if (texcol == vec4(0.0, 0.0, 0.0, 0.0))
|
||||
discard;
|
||||
|
||||
vec3 color;
|
||||
#if BLENDING
|
||||
o_col0 = vec4((ivec4(v_col0 * 255.0) * ivec4(texcol * 255.0)) >> 7) / 255.0;
|
||||
color = vec3((ivec3(v_col0 * 255.0) * ivec3(texcol.rgb * 255.0)) >> 7) / 255.0;
|
||||
#else
|
||||
o_col0 = texcol;
|
||||
color = texcol.rgb;
|
||||
#endif
|
||||
|
||||
#if TRANSPARENT
|
||||
// Apply semitransparency. If not a semitransparent texel, destination alpha is ignored.
|
||||
if (texcol.a != 0)
|
||||
o_col0 = vec4(color * u_transparent_alpha.x, u_transparent_alpha.y);
|
||||
else
|
||||
o_col0 = vec4(color, 0.0);
|
||||
#else
|
||||
// Mask bit from texture.
|
||||
o_col0 = vec4(color, texcol.a);
|
||||
#endif
|
||||
#else
|
||||
o_col0 = v_col0;
|
||||
#if TRANSPARENT
|
||||
o_col0 = vec4(v_col0 * u_transparent_alpha.x, u_transparent_alpha.y);
|
||||
#else
|
||||
// Mask bit is cleared for untextured polygons.
|
||||
o_col0 = vec4(v_col0, 0.0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
)";
|
||||
|
|
|
@ -18,6 +18,7 @@ protected:
|
|||
u32 color;
|
||||
u16 texcoord;
|
||||
u16 padding;
|
||||
u32 texpage;
|
||||
|
||||
static constexpr std::tuple<u8, u8> DecodeTexcoord(u16 texcoord)
|
||||
{
|
||||
|
@ -74,7 +75,7 @@ protected:
|
|||
void CalcScissorRect(int* left, int* top, int* right, int* bottom);
|
||||
|
||||
std::string GenerateVertexShader(bool textured);
|
||||
std::string GenerateFragmentShader(bool textured, bool blending, TextureColorMode texture_color_mode);
|
||||
std::string GenerateFragmentShader(bool textured, bool blending, bool transparent, TextureColorMode texture_color_mode);
|
||||
std::string GenerateScreenQuadVertexShader();
|
||||
std::string GenerateFillFragmentShader();
|
||||
|
||||
|
|
|
@ -142,26 +142,31 @@ bool GPU_HW_OpenGL::CompilePrograms()
|
|||
for (u32 textured = 0; textured < 2; textured++)
|
||||
{
|
||||
for (u32 blending = 0; blending < 2; blending++)
|
||||
{
|
||||
for (u32 transparent = 0; transparent < 2; transparent++)
|
||||
{
|
||||
for (u32 format = 0; format < 3; format++)
|
||||
{
|
||||
// TODO: eliminate duplicate shaders here
|
||||
if (!CompileProgram(m_render_programs[textured][blending][format], ConvertToBoolUnchecked(textured),
|
||||
ConvertToBoolUnchecked(blending), static_cast<TextureColorMode>(format)))
|
||||
if (!CompileProgram(m_render_programs[textured][blending][transparent][format],
|
||||
ConvertToBoolUnchecked(textured), ConvertToBoolUnchecked(blending),
|
||||
ConvertToBoolUnchecked(transparent), static_cast<TextureColorMode>(format)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, bool textured, bool blending, TextureColorMode texture_color_mode)
|
||||
bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, bool textured, bool blending, bool transparent,
|
||||
TextureColorMode texture_color_mode)
|
||||
{
|
||||
const std::string vs = GenerateVertexShader(textured);
|
||||
const std::string fs = GenerateFragmentShader(textured, blending, texture_color_mode);
|
||||
const std::string fs = GenerateFragmentShader(textured, blending, transparent, texture_color_mode);
|
||||
if (!prog.Compile(vs.c_str(), fs.c_str()))
|
||||
return false;
|
||||
|
||||
|
@ -177,14 +182,16 @@ bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, bool textured, bool blendi
|
|||
|
||||
prog.Bind();
|
||||
prog.RegisterUniform("u_pos_offset");
|
||||
prog.RegisterUniform("u_transparent_alpha");
|
||||
prog.Uniform2i(0, 0, 0);
|
||||
prog.Uniform2f(1, 1.0f, 0.0f);
|
||||
|
||||
if (textured)
|
||||
{
|
||||
prog.RegisterUniform("samp0");
|
||||
prog.RegisterUniform("u_texture_page_base");
|
||||
prog.RegisterUniform("u_texture_palette_base");
|
||||
prog.Uniform1i(1, 0);
|
||||
prog.Uniform1i(2, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -194,16 +201,26 @@ void GPU_HW_OpenGL::SetProgram()
|
|||
{
|
||||
const GL::Program& prog =
|
||||
m_render_programs[BoolToUInt32(m_batch.texture_enable)][BoolToUInt32(m_batch.texture_blending_enable)]
|
||||
[static_cast<u32>(m_batch.texture_color_mode)];
|
||||
[BoolToUInt32(m_batch.transparency_enable)][static_cast<u32>(m_batch.texture_color_mode)];
|
||||
prog.Bind();
|
||||
|
||||
prog.Uniform2i(0, m_drawing_offset.x, m_drawing_offset.y);
|
||||
if (m_batch.transparency_enable)
|
||||
{
|
||||
static constexpr float transparent_alpha[4][2] = {{0.5f, 0.5f}, {1.0f, 1.0f}, {1.0f, 1.0f}, {0.25f, 1.0f}};
|
||||
prog.Uniform2fv(1, transparent_alpha[static_cast<u32>(m_batch.transparency_mode)]);
|
||||
}
|
||||
else
|
||||
{
|
||||
static constexpr float disabled_alpha[2] = {1.0f, 0.0f};
|
||||
prog.Uniform2fv(1, disabled_alpha);
|
||||
}
|
||||
|
||||
if (m_batch.texture_enable)
|
||||
{
|
||||
m_vram_read_texture->Bind();
|
||||
prog.Uniform2i(2, m_batch.texture_page_x, m_batch.texture_page_y);
|
||||
prog.Uniform2i(3, m_batch.texture_palette_x, m_batch.texture_palette_y);
|
||||
prog.Uniform2i(3, m_batch.texture_page_x, m_batch.texture_page_y);
|
||||
prog.Uniform2i(4, m_batch.texture_palette_x, m_batch.texture_palette_y);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,32 +245,18 @@ void GPU_HW_OpenGL::SetScissor()
|
|||
|
||||
void GPU_HW_OpenGL::SetBlendState()
|
||||
{
|
||||
struct BlendVars
|
||||
{
|
||||
GLenum src_factor;
|
||||
GLenum func;
|
||||
GLenum dst_factor;
|
||||
float color;
|
||||
};
|
||||
static const std::array<BlendVars, 4> blend_vars = {{
|
||||
{GL_CONSTANT_COLOR, GL_FUNC_ADD, GL_CONSTANT_COLOR, 0.5f}, // B/2 + F/2
|
||||
{GL_ONE, GL_FUNC_ADD, GL_ONE, -1.0f}, // B + F
|
||||
{GL_ONE, GL_FUNC_REVERSE_SUBTRACT, GL_ONE, -1.0f}, // B - F
|
||||
{GL_CONSTANT_COLOR, GL_FUNC_ADD, GL_ONE, 0.25f} // B + F/4
|
||||
}};
|
||||
|
||||
if (!m_batch.transparency_enable)
|
||||
{
|
||||
glDisable(GL_BLEND);
|
||||
return;
|
||||
}
|
||||
|
||||
const BlendVars& vars = blend_vars[static_cast<u8>(m_batch.transparency_mode)];
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFuncSeparate(vars.src_factor, vars.dst_factor, GL_ONE, GL_ZERO);
|
||||
glBlendEquationSeparate(vars.func, GL_FUNC_ADD);
|
||||
if (vars.color >= 0.0f)
|
||||
glBlendColor(vars.color, vars.color, vars.color, 1.0f);
|
||||
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);
|
||||
}
|
||||
|
||||
void GPU_HW_OpenGL::UpdateDisplay()
|
||||
|
|
|
@ -44,7 +44,7 @@ private:
|
|||
void CreateVertexBuffer();
|
||||
|
||||
bool CompilePrograms();
|
||||
bool CompileProgram(GL::Program& prog, bool textured, bool blending, TextureColorMode texture_color_mode);
|
||||
bool CompileProgram(GL::Program& prog, bool textured, bool blending, bool transparent, TextureColorMode texture_color_mode);
|
||||
|
||||
void SetProgram();
|
||||
void SetViewport();
|
||||
|
@ -62,7 +62,7 @@ private:
|
|||
GLuint m_vao_id = 0;
|
||||
GLuint m_attributeless_vao_id = 0;
|
||||
|
||||
std::array<std::array<std::array<GL::Program, 3>, 2>, 2> m_render_programs;
|
||||
std::array<std::array<std::array<std::array<GL::Program, 3>, 2>, 2>, 2> m_render_programs;
|
||||
std::array<GL::Program, 3> m_texture_page_programs;
|
||||
|
||||
GLStats m_stats = {};
|
||||
|
|
Loading…
Reference in a new issue