mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-02-16 19:05:39 +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);
|
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
|
} // namespace GL
|
|
@ -40,6 +40,15 @@ public:
|
||||||
void Uniform2f(u32 index, float x, float y) const;
|
void Uniform2f(u32 index, float x, float y) const;
|
||||||
void Uniform3f(u32 index, float x, float y, float z) 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 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:
|
private:
|
||||||
GLuint m_program_id = 0;
|
GLuint m_program_id = 0;
|
||||||
|
|
|
@ -176,7 +176,7 @@ in ivec2 a_pos;
|
||||||
in vec4 a_col0;
|
in vec4 a_col0;
|
||||||
in vec2 a_tex0;
|
in vec2 a_tex0;
|
||||||
|
|
||||||
out vec4 v_col0;
|
out vec3 v_col0;
|
||||||
#if TEXTURED
|
#if TEXTURED
|
||||||
out vec2 v_tex0;
|
out vec2 v_tex0;
|
||||||
#endif
|
#endif
|
||||||
|
@ -190,7 +190,7 @@ void main()
|
||||||
float pos_y = (float(a_pos.y + u_pos_offset.y) / -256.0) + 1.0;
|
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);
|
gl_Position = vec4(pos_x, pos_y, 0.0, 1.0);
|
||||||
|
|
||||||
v_col0 = a_col0;
|
v_col0 = a_col0.rgb;
|
||||||
#if TEXTURED
|
#if TEXTURED
|
||||||
v_tex0 = a_tex0;
|
v_tex0 = a_tex0;
|
||||||
#endif
|
#endif
|
||||||
|
@ -200,7 +200,8 @@ void main()
|
||||||
return ss.str();
|
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;
|
std::stringstream ss;
|
||||||
GenerateShaderHeader(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);
|
DefineMacro(ss, "PALETTE_8_BIT", textured && texture_color_mode == GPU::TextureColorMode::Palette8Bit);
|
||||||
|
|
||||||
ss << R"(
|
ss << R"(
|
||||||
in vec4 v_col0;
|
in vec3 v_col0;
|
||||||
|
uniform vec2 u_transparent_alpha;
|
||||||
#if TEXTURED
|
#if TEXTURED
|
||||||
in vec2 v_tex0;
|
in vec2 v_tex0;
|
||||||
uniform sampler2D samp0;
|
uniform sampler2D samp0;
|
||||||
|
@ -272,13 +274,30 @@ void main()
|
||||||
if (texcol == vec4(0.0, 0.0, 0.0, 0.0))
|
if (texcol == vec4(0.0, 0.0, 0.0, 0.0))
|
||||||
discard;
|
discard;
|
||||||
|
|
||||||
|
vec3 color;
|
||||||
#if BLENDING
|
#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
|
#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
|
#endif
|
||||||
#else
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
|
@ -18,6 +18,7 @@ protected:
|
||||||
u32 color;
|
u32 color;
|
||||||
u16 texcoord;
|
u16 texcoord;
|
||||||
u16 padding;
|
u16 padding;
|
||||||
|
u32 texpage;
|
||||||
|
|
||||||
static constexpr std::tuple<u8, u8> DecodeTexcoord(u16 texcoord)
|
static constexpr std::tuple<u8, u8> DecodeTexcoord(u16 texcoord)
|
||||||
{
|
{
|
||||||
|
@ -74,7 +75,7 @@ protected:
|
||||||
void CalcScissorRect(int* left, int* top, int* right, int* bottom);
|
void CalcScissorRect(int* left, int* top, int* right, int* bottom);
|
||||||
|
|
||||||
std::string GenerateVertexShader(bool textured);
|
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 GenerateScreenQuadVertexShader();
|
||||||
std::string GenerateFillFragmentShader();
|
std::string GenerateFillFragmentShader();
|
||||||
|
|
||||||
|
|
|
@ -143,13 +143,17 @@ bool GPU_HW_OpenGL::CompilePrograms()
|
||||||
{
|
{
|
||||||
for (u32 blending = 0; blending < 2; blending++)
|
for (u32 blending = 0; blending < 2; blending++)
|
||||||
{
|
{
|
||||||
for (u32 format = 0; format < 3; format++)
|
for (u32 transparent = 0; transparent < 2; transparent++)
|
||||||
{
|
{
|
||||||
// TODO: eliminate duplicate shaders here
|
for (u32 format = 0; format < 3; format++)
|
||||||
if (!CompileProgram(m_render_programs[textured][blending][format], ConvertToBoolUnchecked(textured),
|
|
||||||
ConvertToBoolUnchecked(blending), static_cast<TextureColorMode>(format)))
|
|
||||||
{
|
{
|
||||||
return false;
|
// TODO: eliminate duplicate shaders here
|
||||||
|
if (!CompileProgram(m_render_programs[textured][blending][transparent][format],
|
||||||
|
ConvertToBoolUnchecked(textured), ConvertToBoolUnchecked(blending),
|
||||||
|
ConvertToBoolUnchecked(transparent), static_cast<TextureColorMode>(format)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,10 +162,11 @@ bool GPU_HW_OpenGL::CompilePrograms()
|
||||||
return true;
|
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 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()))
|
if (!prog.Compile(vs.c_str(), fs.c_str()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -177,14 +182,16 @@ bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, bool textured, bool blendi
|
||||||
|
|
||||||
prog.Bind();
|
prog.Bind();
|
||||||
prog.RegisterUniform("u_pos_offset");
|
prog.RegisterUniform("u_pos_offset");
|
||||||
|
prog.RegisterUniform("u_transparent_alpha");
|
||||||
prog.Uniform2i(0, 0, 0);
|
prog.Uniform2i(0, 0, 0);
|
||||||
|
prog.Uniform2f(1, 1.0f, 0.0f);
|
||||||
|
|
||||||
if (textured)
|
if (textured)
|
||||||
{
|
{
|
||||||
prog.RegisterUniform("samp0");
|
prog.RegisterUniform("samp0");
|
||||||
prog.RegisterUniform("u_texture_page_base");
|
prog.RegisterUniform("u_texture_page_base");
|
||||||
prog.RegisterUniform("u_texture_palette_base");
|
prog.RegisterUniform("u_texture_palette_base");
|
||||||
prog.Uniform1i(1, 0);
|
prog.Uniform1i(2, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -194,16 +201,26 @@ void GPU_HW_OpenGL::SetProgram()
|
||||||
{
|
{
|
||||||
const GL::Program& prog =
|
const GL::Program& prog =
|
||||||
m_render_programs[BoolToUInt32(m_batch.texture_enable)][BoolToUInt32(m_batch.texture_blending_enable)]
|
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.Bind();
|
||||||
|
|
||||||
prog.Uniform2i(0, m_drawing_offset.x, m_drawing_offset.y);
|
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)
|
if (m_batch.texture_enable)
|
||||||
{
|
{
|
||||||
m_vram_read_texture->Bind();
|
m_vram_read_texture->Bind();
|
||||||
prog.Uniform2i(2, m_batch.texture_page_x, m_batch.texture_page_y);
|
prog.Uniform2i(3, 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(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()
|
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)
|
if (!m_batch.transparency_enable)
|
||||||
{
|
{
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BlendVars& vars = blend_vars[static_cast<u8>(m_batch.transparency_mode)];
|
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFuncSeparate(vars.src_factor, vars.dst_factor, GL_ONE, GL_ZERO);
|
glBlendEquationSeparate(m_batch.transparency_mode == GPU::TransparencyMode::BackgroundMinusForeground ?
|
||||||
glBlendEquationSeparate(vars.func, GL_FUNC_ADD);
|
GL_FUNC_REVERSE_SUBTRACT :
|
||||||
if (vars.color >= 0.0f)
|
GL_FUNC_ADD,
|
||||||
glBlendColor(vars.color, vars.color, vars.color, 1.0f);
|
GL_FUNC_ADD);
|
||||||
|
glBlendFuncSeparate(GL_ONE, GL_SRC_ALPHA, GL_ONE, GL_ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW_OpenGL::UpdateDisplay()
|
void GPU_HW_OpenGL::UpdateDisplay()
|
||||||
|
|
|
@ -44,7 +44,7 @@ private:
|
||||||
void CreateVertexBuffer();
|
void CreateVertexBuffer();
|
||||||
|
|
||||||
bool CompilePrograms();
|
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 SetProgram();
|
||||||
void SetViewport();
|
void SetViewport();
|
||||||
|
@ -62,7 +62,7 @@ private:
|
||||||
GLuint m_vao_id = 0;
|
GLuint m_vao_id = 0;
|
||||||
GLuint m_attributeless_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;
|
std::array<GL::Program, 3> m_texture_page_programs;
|
||||||
|
|
||||||
GLStats m_stats = {};
|
GLStats m_stats = {};
|
||||||
|
|
Loading…
Reference in a new issue