1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-28 08:17:34 +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:
Jelle Raaijmakers 2022-09-04 16:53:23 +02:00 committed by Linus Groh
parent 494024b70e
commit 1d36bfdac1
10 changed files with 461 additions and 58 deletions

View file

@ -72,6 +72,8 @@ Optional<ContextParameter> GLContext::get_context_parameter(GLenum name)
return ContextParameter { .type = GL_INT, .value = { .integer_value = MODELVIEW_MATRIX_STACK_LIMIT } };
case GL_MAX_PROJECTION_STACK_DEPTH:
return ContextParameter { .type = GL_INT, .value = { .integer_value = PROJECTION_MATRIX_STACK_LIMIT } };
case GL_MAX_TEXTURE_LOD_BIAS:
return ContextParameter { .type = GL_DOUBLE, .value = { .double_value = static_cast<GLdouble>(m_device_info.max_texture_lod_bias) } };
case GL_MAX_TEXTURE_SIZE:
return ContextParameter { .type = GL_INT, .value = { .integer_value = 4096 } };
case GL_MAX_TEXTURE_STACK_DEPTH:

View file

@ -144,6 +144,7 @@ extern "C" {
#define GL_MAP2_VERTEX_4 0x0DB8
#define GL_NORMAL_ARRAY 0x8075
#define GL_NORMAL_ARRAY_TYPE 0x807E
#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
// Blend factors
#define GL_ZERO 0
@ -485,6 +486,8 @@ extern "C" {
#define GL_Q 0x2003
// Texture Environment and Parameters
#define GL_ADD 0x0104
#define GL_ALPHA_SCALE 0x0D1C
#define GL_MODULATE 0x2100
#define GL_TEXTURE_ENV_MODE 0x2200
#define GL_DECAL 0x2101
@ -501,9 +504,41 @@ extern "C" {
#define GL_TEXTURE_WRAP_T 0x2803
#define GL_CLAMP 0x2900
#define GL_REPEAT 0x2901
#define GL_MIRRORED_REPEAT 0x8370
#define GL_CLAMP_TO_BORDER 0x812D
#define GL_CLAMP_TO_EDGE 0x812F
#define GL_MIRRORED_REPEAT 0x8370
#define GL_SUBTRACT 0x84E7
#define GL_TEXTURE_FILTER_CONTROL 0x8500
#define GL_TEXTURE_LOD_BIAS 0x8501
#define GL_COMBINE 0x8570
#define GL_COMBINE_RGB 0x8571
#define GL_COMBINE_ALPHA 0x8572
#define GL_RGB_SCALE 0x8573
#define GL_ADD_SIGNED 0x8574
#define GL_INTERPOLATE 0x8575
#define GL_CONSTANT 0x8576
#define GL_PRIMARY_COLOR 0x8577
#define GL_PREVIOUS 0x8578
#define GL_SRC0_RGB 0x8580
#define GL_SOURCE0_RGB 0x8580
#define GL_SRC1_RGB 0x8581
#define GL_SOURCE1_RGB 0x8581
#define GL_SRC2_RGB 0x8582
#define GL_SOURCE2_RGB 0x8582
#define GL_SRC0_ALPHA 0x8588
#define GL_SOURCE0_ALPHA 0x8588
#define GL_SRC1_ALPHA 0x8589
#define GL_SOURCE1_ALPHA 0x8589
#define GL_SRC2_ALPHA 0x858A
#define GL_SOURCE2_ALPHA 0x858A
#define GL_OPERAND0_RGB 0x8590
#define GL_OPERAND1_RGB 0x8591
#define GL_OPERAND2_RGB 0x8592
#define GL_OPERAND0_ALPHA 0x8598
#define GL_OPERAND1_ALPHA 0x8599
#define GL_OPERAND2_ALPHA 0x859A
#define GL_DOT3_RGB 0x86AE
#define GL_DOT3_RGBA 0x86AF
// Texture gen modes
#define GL_EYE_LINEAR 0x2400
@ -538,8 +573,6 @@ extern "C" {
#define GL_MODELVIEW_MATRIX 0x0BA6
#define GL_PROJECTION_MATRIX 0x0BA7
#define GL_ADD 0x0104
// User clipping planes
#define GL_MAX_CLIP_PLANES 0x0D32
#define GL_CLIP_PLANE0 0x3000

View file

@ -935,6 +935,9 @@ void GLContext::build_extension_string()
extensions.append("GL_EXT_texture_env_add"sv);
}
if (m_device_info.max_texture_lod_bias > 0.f)
extensions.append("GL_EXT_texture_lod_bias"sv);
m_extensions = String::join(' ', extensions);
}

View file

@ -19,8 +19,26 @@ public:
RefPtr<Texture2D> texture_2d_target_texture() const { return m_texture_2d_target_texture; }
void set_texture_2d_target_texture(RefPtr<Texture2D> const& texture) { m_texture_2d_target_texture = texture; }
void set_alpha_combinator(GLenum combinator) { m_alpha_combinator = combinator; }
GLenum alpha_combinator() const { return m_alpha_combinator; }
void set_alpha_operand(size_t index, GLenum operand) { m_alpha_operand[index] = operand; }
GLenum alpha_operand(size_t index) const { return m_alpha_operand[index]; }
void set_alpha_scale(float scale) { m_alpha_scale = scale; }
float alpha_scale() const { return m_alpha_scale; }
void set_alpha_source(size_t index, GLenum source) { m_alpha_source[index] = source; }
GLenum alpha_source(size_t index) const { return m_alpha_source[index]; }
void set_env_mode(GLenum mode) { m_env_mode = mode; }
GLenum env_mode() const { return m_env_mode; }
void set_level_of_detail_bias(float bias) { m_level_of_detail_bias = bias; }
float level_of_detail_bias() const { return m_level_of_detail_bias; }
void set_rgb_combinator(GLenum combinator) { m_rgb_combinator = combinator; }
GLenum rgb_combinator() const { return m_rgb_combinator; }
void set_rgb_operand(size_t index, GLenum operand) { m_rgb_operand[index] = operand; }
GLenum rgb_operand(size_t index) const { return m_rgb_operand[index]; }
void set_rgb_scale(float scale) { m_rgb_scale = scale; }
float rgb_scale() const { return m_rgb_scale; }
void set_rgb_source(size_t index, GLenum source) { m_rgb_source[index] = source; }
GLenum rgb_source(size_t index) const { return m_rgb_source[index]; }
bool texture_1d_enabled() const { return m_texture_1d_enabled; };
void set_texture_1d_enabled(bool texture_1d_enabled) { m_texture_1d_enabled = texture_1d_enabled; }
@ -32,7 +50,16 @@ public:
void set_texture_cube_map_enabled(bool texture_cube_map_enabled) { m_texture_cube_map_enabled = texture_cube_map_enabled; }
private:
GLenum m_alpha_combinator { GL_MODULATE };
Array<GLenum, 3> m_alpha_operand { GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA };
float m_alpha_scale { 1.f };
Array<GLenum, 3> m_alpha_source { GL_TEXTURE, GL_PREVIOUS, GL_CONSTANT };
GLenum m_env_mode { GL_MODULATE };
float m_level_of_detail_bias { 0.f };
GLenum m_rgb_combinator { GL_MODULATE };
Array<GLenum, 3> m_rgb_operand { GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_ALPHA };
float m_rgb_scale { 1.f };
Array<GLenum, 3> m_rgb_source { GL_TEXTURE, GL_PREVIOUS, GL_CONSTANT };
// Bound textures
RefPtr<Texture2D> m_texture_2d_target_texture {};

View file

@ -243,27 +243,152 @@ void GLContext::gl_tex_env(GLenum target, GLenum pname, GLfloat param)
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_tex_env, target, pname, param);
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
// FIXME: We currently only support a subset of possible target values. Implement the rest!
RETURN_WITH_ERROR_IF(target != GL_TEXTURE_ENV, GL_INVALID_ENUM);
RETURN_WITH_ERROR_IF(target != GL_TEXTURE_ENV && target != GL_TEXTURE_FILTER_CONTROL, GL_INVALID_ENUM);
RETURN_WITH_ERROR_IF(target == GL_TEXTURE_FILTER_CONTROL && pname != GL_TEXTURE_LOD_BIAS, GL_INVALID_ENUM);
// FIXME: We currently only support a subset of possible pname values. Implement the rest!
RETURN_WITH_ERROR_IF(pname != GL_TEXTURE_ENV_MODE, GL_INVALID_ENUM);
auto param_enum = static_cast<GLenum>(param);
switch (param_enum) {
case GL_MODULATE:
case GL_REPLACE:
case GL_DECAL:
case GL_ADD:
m_active_texture_unit->set_env_mode(param_enum);
m_sampler_config_is_dirty = true;
switch (target) {
case GL_TEXTURE_ENV:
switch (pname) {
case GL_ALPHA_SCALE:
RETURN_WITH_ERROR_IF(param != 1.f && param != 2.f && param != 4.f, GL_INVALID_VALUE);
m_active_texture_unit->set_alpha_scale(param);
break;
case GL_COMBINE_ALPHA: {
auto param_enum = static_cast<GLenum>(param);
switch (param_enum) {
case GL_ADD:
case GL_ADD_SIGNED:
case GL_INTERPOLATE:
case GL_MODULATE:
case GL_REPLACE:
case GL_SUBTRACT:
m_active_texture_unit->set_alpha_combinator(param_enum);
break;
default:
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
}
break;
}
case GL_COMBINE_RGB: {
auto param_enum = static_cast<GLenum>(param);
switch (param_enum) {
case GL_ADD:
case GL_ADD_SIGNED:
case GL_DOT3_RGB:
case GL_DOT3_RGBA:
case GL_INTERPOLATE:
case GL_MODULATE:
case GL_REPLACE:
case GL_SUBTRACT:
m_active_texture_unit->set_rgb_combinator(param_enum);
break;
default:
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
}
break;
}
case GL_OPERAND0_ALPHA:
case GL_OPERAND1_ALPHA:
case GL_OPERAND2_ALPHA: {
auto param_enum = static_cast<GLenum>(param);
switch (param_enum) {
case GL_ONE_MINUS_SRC_ALPHA:
case GL_SRC_ALPHA:
m_active_texture_unit->set_alpha_operand(pname - GL_OPERAND0_ALPHA, param_enum);
break;
default:
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
}
break;
}
case GL_OPERAND0_RGB:
case GL_OPERAND1_RGB:
case GL_OPERAND2_RGB: {
auto param_enum = static_cast<GLenum>(param);
switch (param_enum) {
case GL_ONE_MINUS_SRC_ALPHA:
case GL_ONE_MINUS_SRC_COLOR:
case GL_SRC_ALPHA:
case GL_SRC_COLOR:
m_active_texture_unit->set_rgb_operand(pname - GL_OPERAND0_RGB, param_enum);
break;
default:
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
}
break;
}
case GL_RGB_SCALE:
RETURN_WITH_ERROR_IF(param != 1.f && param != 2.f && param != 4.f, GL_INVALID_VALUE);
m_active_texture_unit->set_rgb_scale(param);
break;
case GL_SRC0_ALPHA:
case GL_SRC1_ALPHA:
case GL_SRC2_ALPHA: {
auto param_enum = static_cast<GLenum>(param);
switch (param_enum) {
case GL_CONSTANT:
case GL_PREVIOUS:
case GL_PRIMARY_COLOR:
case GL_TEXTURE:
case GL_TEXTURE0 ... GL_TEXTURE31:
m_active_texture_unit->set_alpha_source(pname - GL_SRC0_ALPHA, param_enum);
break;
default:
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
}
break;
}
case GL_SRC0_RGB:
case GL_SRC1_RGB:
case GL_SRC2_RGB: {
auto param_enum = static_cast<GLenum>(param);
switch (param_enum) {
case GL_CONSTANT:
case GL_PREVIOUS:
case GL_PRIMARY_COLOR:
case GL_TEXTURE:
case GL_TEXTURE0 ... GL_TEXTURE31:
m_active_texture_unit->set_rgb_source(pname - GL_SRC0_RGB, param_enum);
break;
default:
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
}
break;
}
case GL_TEXTURE_ENV_MODE: {
auto param_enum = static_cast<GLenum>(param);
switch (param_enum) {
case GL_ADD:
case GL_BLEND:
case GL_COMBINE:
case GL_DECAL:
case GL_MODULATE:
case GL_REPLACE:
m_active_texture_unit->set_env_mode(param_enum);
break;
default:
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
}
break;
}
default:
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
}
break;
case GL_TEXTURE_FILTER_CONTROL:
switch (pname) {
case GL_TEXTURE_LOD_BIAS:
m_active_texture_unit->set_level_of_detail_bias(param);
break;
default:
VERIFY_NOT_REACHED();
}
break;
default:
// FIXME: We currently only support a subset of possible param values. Implement the rest!
dbgln_if(GL_DEBUG, "gl_tex_env({:#x}, {:#x}, {}): param unimplemented", target, pname, param);
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
VERIFY_NOT_REACHED();
}
m_sampler_config_is_dirty = true;
}
void GLContext::gl_tex_gen(GLenum coord, GLenum pname, GLint param)
@ -537,6 +662,7 @@ void GLContext::sync_device_sampler_config()
auto texture_2d = texture_unit.texture_2d_target_texture();
VERIFY(!texture_2d.is_null());
config.bound_image = texture_2d->device_image();
config.level_of_detail_bias = texture_unit.level_of_detail_bias();
auto const& sampler = texture_2d->sampler();
@ -620,21 +746,96 @@ void GLContext::sync_device_sampler_config()
VERIFY_NOT_REACHED();
}
switch (texture_unit.env_mode()) {
case GL_MODULATE:
config.fixed_function_texture_env_mode = GPU::TextureEnvMode::Modulate;
break;
case GL_REPLACE:
config.fixed_function_texture_env_mode = GPU::TextureEnvMode::Replace;
break;
case GL_DECAL:
config.fixed_function_texture_env_mode = GPU::TextureEnvMode::Decal;
break;
case GL_ADD:
config.fixed_function_texture_env_mode = GPU::TextureEnvMode::Add;
break;
default:
VERIFY_NOT_REACHED();
auto& fixed_function_env = config.fixed_function_texture_environment;
auto get_env_mode = [](GLenum mode) {
switch (mode) {
case GL_ADD:
return GPU::TextureEnvMode::Add;
case GL_BLEND:
return GPU::TextureEnvMode::Blend;
case GL_COMBINE:
return GPU::TextureEnvMode::Combine;
case GL_DECAL:
return GPU::TextureEnvMode::Decal;
case GL_MODULATE:
return GPU::TextureEnvMode::Modulate;
case GL_REPLACE:
return GPU::TextureEnvMode::Replace;
default:
VERIFY_NOT_REACHED();
}
};
fixed_function_env.env_mode = get_env_mode(texture_unit.env_mode());
fixed_function_env.alpha_scale = texture_unit.alpha_scale();
fixed_function_env.rgb_scale = texture_unit.rgb_scale();
auto get_combinator = [](GLenum combinator) {
switch (combinator) {
case GL_ADD:
return GPU::TextureCombinator::Add;
case GL_ADD_SIGNED:
return GPU::TextureCombinator::AddSigned;
case GL_DOT3_RGB:
return GPU::TextureCombinator::Dot3RGB;
case GL_DOT3_RGBA:
return GPU::TextureCombinator::Dot3RGBA;
case GL_INTERPOLATE:
return GPU::TextureCombinator::Interpolate;
case GL_MODULATE:
return GPU::TextureCombinator::Modulate;
case GL_REPLACE:
return GPU::TextureCombinator::Replace;
case GL_SUBTRACT:
return GPU::TextureCombinator::Subtract;
default:
VERIFY_NOT_REACHED();
}
};
fixed_function_env.alpha_combinator = get_combinator(texture_unit.alpha_combinator());
fixed_function_env.rgb_combinator = get_combinator(texture_unit.rgb_combinator());
auto get_operand = [](GLenum operand) {
switch (operand) {
case GL_ONE_MINUS_SRC_ALPHA:
return GPU::TextureOperand::OneMinusSourceAlpha;
case GL_ONE_MINUS_SRC_COLOR:
return GPU::TextureOperand::OneMinusSourceColor;
case GL_SRC_ALPHA:
return GPU::TextureOperand::SourceAlpha;
case GL_SRC_COLOR:
return GPU::TextureOperand::SourceColor;
default:
VERIFY_NOT_REACHED();
}
};
auto get_source = [](GLenum source) {
switch (source) {
case GL_CONSTANT:
return GPU::TextureSource::Constant;
case GL_PREVIOUS:
return GPU::TextureSource::Previous;
case GL_PRIMARY_COLOR:
return GPU::TextureSource::PrimaryColor;
case GL_TEXTURE:
return GPU::TextureSource::Texture;
case GL_TEXTURE0 ... GL_TEXTURE31:
return GPU::TextureSource::TextureStage;
default:
VERIFY_NOT_REACHED();
}
};
for (size_t j = 0; j < 3; ++j) {
fixed_function_env.alpha_operand[j] = get_operand(texture_unit.alpha_operand(j));
fixed_function_env.alpha_source[j] = get_source(texture_unit.alpha_source(j));
if (fixed_function_env.alpha_source[j] == GPU::TextureSource::TextureStage)
fixed_function_env.alpha_source_texture_stage = texture_unit.alpha_source(j) - GL_TEXTURE0;
fixed_function_env.rgb_operand[j] = get_operand(texture_unit.rgb_operand(j));
fixed_function_env.rgb_source[j] = get_source(texture_unit.rgb_source(j));
if (fixed_function_env.rgb_source[j] == GPU::TextureSource::TextureStage)
fixed_function_env.rgb_source_texture_stage = texture_unit.rgb_source(j) - GL_TEXTURE0;
}
config.border_color = sampler.border_color();