LibGL+LibGPU+LibSoftGPU: Implement constant blending color

Available since OpenGL 2.0, calling `glBlendColor` allows you to set a
constant color to be used as a blend factor.
This commit is contained in:
Jelle Raaijmakers 2024-04-09 23:09:04 +02:00 committed by Tim Schumacher
commit 2831e68999
Notes: sideshowbarker 2024-07-17 01:12:07 +09:00
6 changed files with 71 additions and 24 deletions

View file

@ -8,6 +8,19 @@
namespace GL {
void GLContext::gl_blend_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
{
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_blend_color, red, green, blue, alpha);
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
m_blend_color = { red, green, blue, alpha };
m_blend_color.clamp(0.f, 1.f);
auto options = m_rasterizer->options();
options.blend_color = m_blend_color;
m_rasterizer->set_options(options);
}
void GLContext::gl_blend_equation_separate(GLenum rgb_mode, GLenum alpha_mode)
{
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_blend_equation_separate, rgb_mode, alpha_mode);
@ -119,6 +132,14 @@ void GLContext::gl_blend_func(GLenum src_factor, GLenum dst_factor)
return GPU::BlendFactor::DstAlpha;
case GL_ONE_MINUS_DST_ALPHA:
return GPU::BlendFactor::OneMinusDstAlpha;
case GL_CONSTANT_COLOR:
return GPU::BlendFactor::ConstantColor;
case GL_ONE_MINUS_CONSTANT_COLOR:
return GPU::BlendFactor::OneMinusConstantColor;
case GL_CONSTANT_ALPHA:
return GPU::BlendFactor::ConstantAlpha;
case GL_ONE_MINUS_CONSTANT_ALPHA:
return GPU::BlendFactor::OneMinusConstantAlpha;
case GL_SRC_ALPHA_SATURATE:
return GPU::BlendFactor::SrcAlphaSaturate;
default:

View file

@ -48,6 +48,11 @@
{"type": "GLubyte const*", "name": "bitmap"}
]
},
"BlendColor": {
"arguments": [
{"type": "GLclampf", "name": ["red", "green", "blue", "alpha"]}
]
},
"BlendEquation": {
"arguments": [
{"type": "GLenum", "name": "mode"},

View file

@ -148,6 +148,7 @@ public:
GLboolean gl_is_list(GLuint list);
void gl_flush();
void gl_finish();
void gl_blend_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
void gl_blend_equation_separate(GLenum rgb_mode, GLenum alpha_mode);
void gl_blend_func(GLenum src_factor, GLenum dst_factor);
void gl_shade_model(GLenum mode);
@ -334,6 +335,7 @@ private:
GLenum m_culled_sides = GL_BACK;
bool m_blend_enabled = false;
FloatVector4 m_blend_color { 0.f, 0.f, 0.f, 0.f };
GLenum m_blend_source_factor = GL_ONE;
GLenum m_blend_destination_factor = GL_ZERO;
@ -473,6 +475,7 @@ private:
decltype(&GLContext::gl_cull_face),
decltype(&GLContext::gl_call_list),
decltype(&GLContext::gl_call_lists),
decltype(&GLContext::gl_blend_color),
decltype(&GLContext::gl_blend_equation_separate),
decltype(&GLContext::gl_blend_func),
decltype(&GLContext::gl_shade_model),

View file

@ -33,14 +33,18 @@ enum class BlendEquation {
enum class BlendFactor {
Zero,
One,
SrcAlpha,
OneMinusSrcAlpha,
SrcColor,
OneMinusSrcColor,
DstAlpha,
OneMinusDstAlpha,
DstColor,
OneMinusDstColor,
SrcAlpha,
OneMinusSrcAlpha,
DstAlpha,
OneMinusDstAlpha,
ConstantColor,
OneMinusConstantColor,
ConstantAlpha,
OneMinusConstantAlpha,
SrcAlphaSaturate,
};

View file

@ -23,6 +23,7 @@ struct RasterizerOptions {
AlphaTestFunction alpha_test_func { AlphaTestFunction::Always };
float alpha_test_ref_value { 0 };
bool enable_blending { false };
FloatVector4 blend_color { 0.f, 0.f, 0.f, 0.f };
BlendEquation blend_equation_rgb { BlendEquation::Add };
BlendEquation blend_equation_alpha { BlendEquation::Add };
BlendFactor blend_source_factor { BlendFactor::One };

View file

@ -137,37 +137,50 @@ ALWAYS_INLINE static void test_alpha(PixelQuad& quad, GPU::AlphaTestFunction alp
ALWAYS_INLINE static bool is_blend_factor_constant(GPU::BlendFactor blend_factor)
{
return (blend_factor == GPU::BlendFactor::One || blend_factor == GPU::BlendFactor::Zero);
return blend_factor == GPU::BlendFactor::Zero
|| blend_factor == GPU::BlendFactor::One
|| blend_factor == GPU::BlendFactor::ConstantColor
|| blend_factor == GPU::BlendFactor::OneMinusConstantColor
|| blend_factor == GPU::BlendFactor::ConstantAlpha
|| blend_factor == GPU::BlendFactor::OneMinusConstantAlpha;
}
// OpenGL 2.0 § 4.1.8, table 4.2
ALWAYS_INLINE static Vector4<f32x4> get_blend_factor(GPU::BlendFactor blend_factor, Vector4<f32x4> const& source_color, Vector4<f32x4> const& destination_color)
ALWAYS_INLINE static Vector4<f32x4> get_blend_factor(GPU::BlendFactor blend_factor, FloatVector4 blend_color, Vector4<f32x4> const& source_color, Vector4<f32x4> const& destination_color)
{
switch (blend_factor) {
case GPU::BlendFactor::DstAlpha:
return to_vec4(destination_color.w());
case GPU::BlendFactor::DstColor:
return destination_color;
case GPU::BlendFactor::Zero:
return to_vec4(expand4(0.f));
case GPU::BlendFactor::One:
return to_vec4(expand4(1.f));
case GPU::BlendFactor::OneMinusDstAlpha:
return to_vec4(1.f - destination_color.w());
case GPU::BlendFactor::OneMinusDstColor:
return to_vec4(expand4(1.f)) - destination_color;
case GPU::BlendFactor::OneMinusSrcAlpha:
return to_vec4(1.f - source_color.w());
case GPU::BlendFactor::SrcColor:
return source_color;
case GPU::BlendFactor::OneMinusSrcColor:
return to_vec4(expand4(1.f)) - source_color;
case GPU::BlendFactor::DstColor:
return destination_color;
case GPU::BlendFactor::OneMinusDstColor:
return to_vec4(expand4(1.f)) - destination_color;
case GPU::BlendFactor::SrcAlpha:
return to_vec4(source_color.w());
case GPU::BlendFactor::OneMinusSrcAlpha:
return to_vec4(1.f - source_color.w());
case GPU::BlendFactor::DstAlpha:
return to_vec4(destination_color.w());
case GPU::BlendFactor::OneMinusDstAlpha:
return to_vec4(1.f - destination_color.w());
case GPU::BlendFactor::ConstantColor:
return expand4(blend_color);
case GPU::BlendFactor::OneMinusConstantColor:
return expand4(FloatVector4 { 1.f, 1.f, 1.f, 1.f } - blend_color);
case GPU::BlendFactor::ConstantAlpha:
return to_vec4(expand4(blend_color.w()));
case GPU::BlendFactor::OneMinusConstantAlpha:
return to_vec4(expand4(1.f - blend_color.w()));
case GPU::BlendFactor::SrcAlphaSaturate: {
auto saturated = min(source_color.w(), 1.f - destination_color.w());
return { saturated, saturated, saturated, expand4(1.f) };
}
case GPU::BlendFactor::SrcColor:
return source_color;
case GPU::BlendFactor::Zero:
return to_vec4(expand4(0.f));
default:
VERIFY_NOT_REACHED();
}
@ -282,9 +295,9 @@ ALWAYS_INLINE void Device::rasterize(Gfx::IntRect& render_bounds, CB1 set_covera
auto const destination_weights_are_constant = is_blend_factor_constant(m_options.blend_destination_factor);
if (m_options.enable_blending) {
if (source_weights_are_constant)
source_weights = get_blend_factor(m_options.blend_source_factor, {}, {});
source_weights = get_blend_factor(m_options.blend_source_factor, m_options.blend_color, {}, {});
if (destination_weights_are_constant)
destination_weights = get_blend_factor(m_options.blend_destination_factor, {}, {});
destination_weights = get_blend_factor(m_options.blend_destination_factor, m_options.blend_color, {}, {});
}
// Rasterize all quads
@ -480,9 +493,9 @@ ALWAYS_INLINE void Device::rasterize(Gfx::IntRect& render_bounds, CB1 set_covera
auto const destination_color = to_vec4(dst_u32);
if (!source_weights_are_constant)
source_weights = get_blend_factor(m_options.blend_source_factor, source_color, destination_color);
source_weights = get_blend_factor(m_options.blend_source_factor, m_options.blend_color, source_color, destination_color);
if (!destination_weights_are_constant)
destination_weights = get_blend_factor(m_options.blend_destination_factor, source_color, destination_color);
destination_weights = get_blend_factor(m_options.blend_destination_factor, m_options.blend_color, source_color, destination_color);
out_color = blend_colors(m_options.blend_equation_rgb, m_options.blend_equation_alpha, source_color, source_weights, destination_color, destination_weights);
}