mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 22:07:35 +00:00
LibGL+LibSoftGPU: Implement fixed pipeline support for GL_COMBINE
`GL_COMBINE` is basically a fixed function calculator to perform simple arithmetics on configurable fragment sources. This patch implements a number of texture env parameters with support for the RGBA internal format.
This commit is contained in:
parent
494024b70e
commit
1d36bfdac1
10 changed files with 461 additions and 58 deletions
|
@ -20,6 +20,7 @@ static constexpr bool ENABLE_STATISTICS_OVERLAY = false;
|
|||
static constexpr int MILLISECONDS_PER_STATISTICS_PERIOD = 500;
|
||||
static constexpr int NUM_LIGHTS = 8;
|
||||
static constexpr int MAX_CLIP_PLANES = 6;
|
||||
static constexpr float MAX_TEXTURE_LOD_BIAS = 2.f;
|
||||
static constexpr int SUBPIXEL_BITS = 6;
|
||||
|
||||
// See: https://www.khronos.org/opengl/wiki/Common_Mistakes#Texture_edge_color_problem
|
||||
|
|
|
@ -813,6 +813,7 @@ GPU::DeviceInfo Device::info() const
|
|||
.num_texture_units = GPU::NUM_SAMPLERS,
|
||||
.num_lights = NUM_LIGHTS,
|
||||
.max_clip_planes = MAX_CLIP_PLANES,
|
||||
.max_texture_lod_bias = MAX_TEXTURE_LOD_BIAS,
|
||||
.stencil_bits = sizeof(GPU::StencilType) * 8,
|
||||
.supports_npot_textures = true,
|
||||
.supports_texture_env_add = true,
|
||||
|
@ -1187,40 +1188,124 @@ void Device::draw_primitives(GPU::PrimitiveType primitive_type, FloatMatrix4x4 c
|
|||
|
||||
ALWAYS_INLINE void Device::shade_fragments(PixelQuad& quad)
|
||||
{
|
||||
quad.out_color = quad.vertex_color;
|
||||
Array<Vector4<f32x4>, GPU::NUM_SAMPLERS> texture_stage_texel;
|
||||
|
||||
auto current_color = quad.vertex_color;
|
||||
for (size_t i : m_enabled_texture_units) {
|
||||
// FIXME: implement GL_TEXTURE_1D, GL_TEXTURE_3D and GL_TEXTURE_CUBE_MAP
|
||||
auto const& sampler = m_samplers[i];
|
||||
|
||||
auto texel = sampler.sample_2d(quad.texture_coordinates[i].xy());
|
||||
texture_stage_texel[i] = texel;
|
||||
INCREASE_STATISTICS_COUNTER(g_num_sampler_calls, 1);
|
||||
|
||||
// FIXME: Implement more blend modes
|
||||
switch (sampler.config().fixed_function_texture_env_mode) {
|
||||
case GPU::TextureEnvMode::Modulate:
|
||||
quad.out_color = quad.out_color * texel;
|
||||
// FIXME: implement support for GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_INTENSITY and GL_RGB internal formats
|
||||
auto& fixed_function_env = sampler.config().fixed_function_texture_environment;
|
||||
switch (fixed_function_env.env_mode) {
|
||||
case GPU::TextureEnvMode::Add:
|
||||
current_color.set_x(current_color.x() + texel.x());
|
||||
current_color.set_y(current_color.y() + texel.y());
|
||||
current_color.set_z(current_color.z() + texel.z());
|
||||
current_color.set_w(current_color.w() * texel.w());
|
||||
break;
|
||||
case GPU::TextureEnvMode::Replace:
|
||||
quad.out_color = texel;
|
||||
case GPU::TextureEnvMode::Blend: {
|
||||
auto blend_color = expand4(fixed_function_env.color);
|
||||
current_color.set_x(mix(current_color.x(), blend_color.x(), texel.x()));
|
||||
current_color.set_y(mix(current_color.y(), blend_color.y(), texel.y()));
|
||||
current_color.set_z(mix(current_color.z(), blend_color.z(), texel.z()));
|
||||
current_color.set_w(current_color.w() * texel.w());
|
||||
break;
|
||||
}
|
||||
case GPU::TextureEnvMode::Combine: {
|
||||
auto get_source_color = [&](GPU::TextureSource source, u8 texture_stage) {
|
||||
switch (source) {
|
||||
case GPU::TextureSource::Constant:
|
||||
return expand4(fixed_function_env.color);
|
||||
case GPU::TextureSource::Previous:
|
||||
return current_color;
|
||||
case GPU::TextureSource::PrimaryColor:
|
||||
return quad.vertex_color;
|
||||
case GPU::TextureSource::Texture:
|
||||
return texel;
|
||||
case GPU::TextureSource::TextureStage:
|
||||
return texture_stage_texel[texture_stage];
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
};
|
||||
auto get_argument_value = [](GPU::TextureOperand operand, auto value) {
|
||||
switch (operand) {
|
||||
case GPU::TextureOperand::OneMinusSourceAlpha:
|
||||
case GPU::TextureOperand::OneMinusSourceColor:
|
||||
return expand4(FloatVector4 { 1.f, 1.f, 1.f, 1.f }) - value;
|
||||
case GPU::TextureOperand::SourceAlpha:
|
||||
case GPU::TextureOperand::SourceColor:
|
||||
return value;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
};
|
||||
auto calculate_combinator = [](GPU::TextureCombinator combinator, auto arg0, auto arg1, auto arg2) {
|
||||
switch (combinator) {
|
||||
case GPU::TextureCombinator::Add:
|
||||
return arg0 + arg1;
|
||||
case GPU::TextureCombinator::AddSigned:
|
||||
return arg0 + arg1 - expand4(FloatVector4 { .5f, .5f, .5f, .5f });
|
||||
case GPU::TextureCombinator::Dot3RGB:
|
||||
case GPU::TextureCombinator::Dot3RGBA: {
|
||||
auto scalar = 4.f * ((arg0.x() - .5f) * (arg1.x() - .5f) + (arg0.y() - 0.5f) * (arg1.y() - 0.5f) + (arg0.z() - 0.5f) * (arg1.z() - 0.5f));
|
||||
return Vector4<f32x4> { scalar, scalar, scalar, scalar };
|
||||
}
|
||||
case GPU::TextureCombinator::Interpolate:
|
||||
return mix(arg0, arg1, arg2);
|
||||
case GPU::TextureCombinator::Modulate:
|
||||
return arg0 * arg1;
|
||||
case GPU::TextureCombinator::Replace:
|
||||
return arg0;
|
||||
case GPU::TextureCombinator::Subtract:
|
||||
return arg0 - arg1;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
};
|
||||
auto calculate_color = [&](GPU::TextureCombinator combinator, auto& operands, auto& sources, u8 texture_stage) {
|
||||
auto arg0 = get_argument_value(operands[0], get_source_color(sources[0], texture_stage));
|
||||
auto arg1 = get_argument_value(operands[1], get_source_color(sources[1], texture_stage));
|
||||
auto arg2 = get_argument_value(operands[2], get_source_color(sources[2], texture_stage));
|
||||
return calculate_combinator(combinator, arg0, arg1, arg2);
|
||||
};
|
||||
|
||||
auto rgb_color = calculate_color(
|
||||
fixed_function_env.rgb_combinator,
|
||||
fixed_function_env.rgb_operand,
|
||||
fixed_function_env.rgb_source,
|
||||
fixed_function_env.rgb_source_texture_stage);
|
||||
auto alpha_color = calculate_color(
|
||||
fixed_function_env.alpha_combinator,
|
||||
fixed_function_env.alpha_operand,
|
||||
fixed_function_env.alpha_source,
|
||||
fixed_function_env.alpha_source_texture_stage);
|
||||
|
||||
current_color.set_x(rgb_color.x() * fixed_function_env.rgb_scale);
|
||||
current_color.set_y(rgb_color.y() * fixed_function_env.rgb_scale);
|
||||
current_color.set_z(rgb_color.z() * fixed_function_env.rgb_scale);
|
||||
current_color.set_w(alpha_color.w() * fixed_function_env.alpha_scale);
|
||||
|
||||
current_color.clamp(expand4(0.f), expand4(1.f));
|
||||
break;
|
||||
}
|
||||
case GPU::TextureEnvMode::Decal: {
|
||||
auto dst_alpha = texel.w();
|
||||
quad.out_color.set_x(mix(quad.out_color.x(), texel.x(), dst_alpha));
|
||||
quad.out_color.set_y(mix(quad.out_color.y(), texel.y(), dst_alpha));
|
||||
quad.out_color.set_z(mix(quad.out_color.z(), texel.z(), dst_alpha));
|
||||
current_color.set_x(mix(current_color.x(), texel.x(), dst_alpha));
|
||||
current_color.set_y(mix(current_color.y(), texel.y(), dst_alpha));
|
||||
current_color.set_z(mix(current_color.z(), texel.z(), dst_alpha));
|
||||
break;
|
||||
}
|
||||
case GPU::TextureEnvMode::Add:
|
||||
quad.out_color.set_x(quad.out_color.x() + texel.x());
|
||||
quad.out_color.set_y(quad.out_color.y() + texel.y());
|
||||
quad.out_color.set_z(quad.out_color.z() + texel.z());
|
||||
quad.out_color.set_w(quad.out_color.w() * texel.w()); // FIXME: If texture format is `GL_INTENSITY` alpha components must be added (https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTexEnv.xml)
|
||||
case GPU::TextureEnvMode::Modulate:
|
||||
current_color = current_color * texel;
|
||||
break;
|
||||
case GPU::TextureEnvMode::Replace:
|
||||
current_color = texel;
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
quad.out_color = current_color;
|
||||
|
||||
// Calculate fog
|
||||
// Math from here: https://opengl-notes.readthedocs.io/en/latest/topics/texturing/aliasing.html
|
||||
|
|
|
@ -134,10 +134,13 @@ Vector4<AK::SIMD::f32x4> Sampler::sample_2d(Vector2<AK::SIMD::f32x4> const& uv)
|
|||
if (m_config.mipmap_filter == GPU::MipMapFilter::None)
|
||||
return sample_2d_lod(uv, expand4(base_level), m_config.texture_min_filter);
|
||||
|
||||
// FIXME: add texture-level support for GL_TEXTURE_LOD_BIAS; below is only texture unit-level
|
||||
auto texture_lod_bias = AK::clamp(m_config.level_of_detail_bias, -MAX_TEXTURE_LOD_BIAS, MAX_TEXTURE_LOD_BIAS);
|
||||
// FIXME: Instead of clamping to num_levels - 1, actually make the max mipmap level configurable with glTexParameteri(GL_TEXTURE_MAX_LEVEL, max_level)
|
||||
auto min_level = expand4(static_cast<float>(base_level));
|
||||
auto max_level = expand4(image.num_levels() - 1.0f);
|
||||
auto level = min(max(log2_approximate(scale_factor) * 0.5f, min_level), max_level);
|
||||
auto max_level = expand4(static_cast<float>(image.num_levels()) - 1.f);
|
||||
auto lambda_xy = log2_approximate(scale_factor) * .5f + texture_lod_bias;
|
||||
auto level = clamp(lambda_xy, min_level, max_level);
|
||||
|
||||
auto lower_level_texel = sample_2d_lod(uv, to_u32x4(level), m_config.texture_min_filter);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue