1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 14:27:35 +00:00

LibGL+LibGPU+LibSoftGPU: Implement blend equations

This implements support for `glBlendEquation` and
`glBlendEquationSeparate`. These functions modify the calculation of the
resulting color in blending mode.
This commit is contained in:
Jelle Raaijmakers 2024-02-15 22:55:28 +01:00
parent 55668c3e48
commit aa3a6767f6
10 changed files with 202 additions and 30 deletions

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org>
* Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
* Copyright (c) 2022-2023, Jelle Raaijmakers <jelle@gmta.nl>
* Copyright (c) 2022-2024, Jelle Raaijmakers <jelle@gmta.nl>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -140,7 +140,7 @@ ALWAYS_INLINE static bool is_blend_factor_constant(GPU::BlendFactor blend_factor
return (blend_factor == GPU::BlendFactor::One || blend_factor == GPU::BlendFactor::Zero);
}
// OpenGL 1.5 § 4.1.8, table 4.1
// 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)
{
switch (blend_factor) {
@ -173,6 +173,42 @@ ALWAYS_INLINE static Vector4<f32x4> get_blend_factor(GPU::BlendFactor blend_fact
}
}
// OpenGL 2.0 § 4.1.8, table 4.1
ALWAYS_INLINE static Vector4<f32x4> blend_colors(
GPU::BlendEquation rgb_mode,
GPU::BlendEquation alpha_mode,
Vector4<f32x4> const& source,
Vector4<f32x4> const& source_weights,
Vector4<f32x4> const& destination,
Vector4<f32x4> const& destination_weights)
{
auto apply_equation = [&](GPU::BlendEquation mode, auto source, auto source_weights, auto destination, auto destination_weights) -> auto {
switch (mode) {
case GPU::BlendEquation::Add:
return source * source_weights + destination * destination_weights;
case GPU::BlendEquation::Subtract:
return source * source_weights - destination * destination_weights;
case GPU::BlendEquation::ReverseSubtract:
return destination * source_weights - source * destination_weights;
case GPU::BlendEquation::Min:
return AK::min(source, destination);
case GPU::BlendEquation::Max:
return AK::max(source, destination);
default:
VERIFY_NOT_REACHED();
}
};
// Single calculation if RGB mode is the same as the alpha mode
if (rgb_mode == alpha_mode)
return apply_equation(rgb_mode, source, source_weights, destination, destination_weights);
// Split RGB/alpha calculation
auto rgb = apply_equation(rgb_mode, source.xyz(), source_weights.xyz(), destination.xyz(), destination_weights.xyz());
auto alpha = apply_equation(alpha_mode, source.w(), source_weights.w(), destination.w(), destination_weights.w());
return { rgb.x(), rgb.y(), rgb.z(), alpha };
}
template<typename CB1, typename CB2, typename CB3>
ALWAYS_INLINE void Device::rasterize(Gfx::IntRect& render_bounds, CB1 set_coverage_mask, CB2 set_quad_depth, CB3 set_quad_attributes)
{
@ -239,16 +275,16 @@ ALWAYS_INLINE void Device::rasterize(Gfx::IntRect& render_bounds, CB1 set_covera
auto const qy0 = render_bounds_top & ~1;
auto const qy1 = render_bounds_bottom & ~1;
// Blend factors
Vector4<f32x4> src_factor;
Vector4<f32x4> dst_factor;
auto const src_factor_is_constant = is_blend_factor_constant(m_options.blend_source_factor);
auto const dst_factor_is_constant = is_blend_factor_constant(m_options.blend_destination_factor);
// Blend weights
Vector4<f32x4> source_weights;
Vector4<f32x4> destination_weights;
auto const source_weights_are_constant = is_blend_factor_constant(m_options.blend_source_factor);
auto const destination_weights_are_constant = is_blend_factor_constant(m_options.blend_destination_factor);
if (m_options.enable_blending) {
if (src_factor_is_constant)
src_factor = get_blend_factor(m_options.blend_source_factor, {}, {});
if (dst_factor_is_constant)
dst_factor = get_blend_factor(m_options.blend_destination_factor, {}, {});
if (source_weights_are_constant)
source_weights = get_blend_factor(m_options.blend_source_factor, {}, {});
if (destination_weights_are_constant)
destination_weights = get_blend_factor(m_options.blend_destination_factor, {}, {});
}
// Rasterize all quads
@ -436,19 +472,19 @@ ALWAYS_INLINE void Device::rasterize(Gfx::IntRect& render_bounds, CB1 set_covera
auto out_color = quad.get_output_vector4(SHADER_OUTPUT_FIRST_COLOR);
// Blend color values from pixel_staging into color_buffer
if (m_options.enable_blending) {
INCREASE_STATISTICS_COUNTER(g_num_pixels_blended, maskcount(quad.mask));
// Blend color values from pixel_staging into color_buffer
auto const& src = out_color;
auto const dst = to_vec4(dst_u32);
auto const& source_color = out_color;
auto const destination_color = to_vec4(dst_u32);
if (!src_factor_is_constant)
src_factor = get_blend_factor(m_options.blend_source_factor, src, dst);
if (!dst_factor_is_constant)
dst_factor = get_blend_factor(m_options.blend_destination_factor, src, dst);
if (!source_weights_are_constant)
source_weights = get_blend_factor(m_options.blend_source_factor, source_color, destination_color);
if (!destination_weights_are_constant)
destination_weights = get_blend_factor(m_options.blend_destination_factor, source_color, destination_color);
out_color = src * src_factor + dst * dst_factor;
out_color = blend_colors(m_options.blend_equation_rgb, m_options.blend_equation_alpha, source_color, source_weights, destination_color, destination_weights);
}
auto const argb32_color = to_argb32(out_color);