mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-30 00:31:14 +00:00
LibGL: Centralize all context parameters
The `glGet*` family of functions requires that all parameters of different types are transparently converted into each other. For example, you can request a boolean parameter as a float or a list of double values as an integer. It might be considered bad practice to request parameters through the wrongly-typed function, but to be spec- compliant we need to implement this. Introduce a new `::get_context_parameter()` to obtain a parameter value, which is then converted to the right type by the respective `::gl_get_*()` functions.
This commit is contained in:
parent
2af9b625e8
commit
b1ac181537
Notes:
sideshowbarker
2024-07-17 22:50:43 +09:00
Author: https://github.com/gmta Commit: https://github.com/SerenityOS/serenity/commit/b1ac181537a Pull-request: https://github.com/SerenityOS/serenity/pull/11154 Reviewed-by: https://github.com/sunverwerth ✅
|
@ -161,6 +161,7 @@ extern "C" {
|
|||
#define GL_3_BYTES 0x1408
|
||||
#define GL_4_BYTES 0x1409
|
||||
#define GL_DOUBLE 0x140A
|
||||
#define GL_BOOL 0x8B56
|
||||
|
||||
// Format enums
|
||||
#define GL_COLOR_INDEX 0x1900
|
||||
|
@ -343,6 +344,7 @@ extern "C" {
|
|||
|
||||
// OpenGL State & GLGet
|
||||
#define GL_MODELVIEW_MATRIX 0x0BA6
|
||||
#define GL_PROJECTION_MATRIX 0x0BA7
|
||||
|
||||
//
|
||||
// OpenGL typedefs
|
||||
|
|
|
@ -61,6 +61,75 @@ SoftwareGLContext::SoftwareGLContext(Gfx::Bitmap& frontbuffer)
|
|||
{
|
||||
}
|
||||
|
||||
Optional<ContextParameter> SoftwareGLContext::get_context_parameter(GLenum name)
|
||||
{
|
||||
switch (name) {
|
||||
case GL_ALPHA_BITS:
|
||||
return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(float) * 8 } };
|
||||
case GL_ALPHA_TEST:
|
||||
return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_alpha_test_enabled } };
|
||||
case GL_BLEND:
|
||||
return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_blend_enabled } };
|
||||
case GL_BLEND_DST_ALPHA:
|
||||
return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_blend_destination_factor) } };
|
||||
case GL_BLEND_SRC_ALPHA:
|
||||
return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_blend_source_factor) } };
|
||||
case GL_BLUE_BITS:
|
||||
return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(float) * 8 } };
|
||||
case GL_CULL_FACE:
|
||||
return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_cull_faces } };
|
||||
case GL_DEPTH_BITS:
|
||||
return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(float) * 8 } };
|
||||
case GL_DEPTH_TEST:
|
||||
return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_depth_test_enabled } };
|
||||
case GL_DOUBLEBUFFER:
|
||||
return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = true } };
|
||||
case GL_GREEN_BITS:
|
||||
return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(float) * 8 } };
|
||||
case GL_MAX_TEXTURE_SIZE:
|
||||
return ContextParameter { .type = GL_INT, .value = { .integer_value = 4096 } };
|
||||
case GL_MAX_TEXTURE_UNITS:
|
||||
return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_texture_units.size()) } };
|
||||
case GL_PACK_ALIGNMENT:
|
||||
return ContextParameter { .type = GL_INT, .value = { .integer_value = m_pack_alignment } };
|
||||
case GL_RED_BITS:
|
||||
return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(float) * 8 } };
|
||||
case GL_SCISSOR_BOX: {
|
||||
auto scissor_box = m_rasterizer.options().scissor_box;
|
||||
return ContextParameter {
|
||||
.type = GL_INT,
|
||||
.count = 4,
|
||||
.value = {
|
||||
.integer_list = {
|
||||
scissor_box.x(),
|
||||
scissor_box.y(),
|
||||
scissor_box.width(),
|
||||
scissor_box.height(),
|
||||
} }
|
||||
};
|
||||
} break;
|
||||
case GL_STENCIL_BITS:
|
||||
return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(float) * 8 } };
|
||||
case GL_STENCIL_TEST:
|
||||
return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_stencil_test_enabled } };
|
||||
case GL_TEXTURE_1D:
|
||||
return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_1d_enabled() } };
|
||||
case GL_TEXTURE_2D:
|
||||
return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_2d_enabled() } };
|
||||
case GL_TEXTURE_3D:
|
||||
return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_3d_enabled() } };
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_cube_map_enabled() } };
|
||||
case GL_UNPACK_ALIGNMENT:
|
||||
return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpack_alignment } };
|
||||
case GL_UNPACK_ROW_LENGTH:
|
||||
return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpack_row_length } };
|
||||
default:
|
||||
dbgln_if(GL_DEBUG, "get_context_parameter({:#x}): unknown context parameter", name);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void SoftwareGLContext::gl_begin(GLenum mode)
|
||||
{
|
||||
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_begin, mode);
|
||||
|
@ -368,7 +437,7 @@ GLubyte* SoftwareGLContext::gl_get_string(GLenum name)
|
|||
case GL_SHADING_LANGUAGE_VERSION:
|
||||
return reinterpret_cast<GLubyte*>(const_cast<char*>("0.0"));
|
||||
default:
|
||||
dbgln_if(GL_DEBUG, "glGetString(): Unknown enum name!");
|
||||
dbgln_if(GL_DEBUG, "gl_get_string({:#x}): unknown name", name);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1572,41 +1641,22 @@ void SoftwareGLContext::gl_get_booleanv(GLenum pname, GLboolean* data)
|
|||
{
|
||||
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
||||
|
||||
switch (pname) {
|
||||
case GL_BLEND:
|
||||
*data = m_blend_enabled ? GL_TRUE : GL_FALSE;
|
||||
auto optional_parameter = get_context_parameter(pname);
|
||||
RETURN_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM);
|
||||
auto parameter = optional_parameter.release_value();
|
||||
|
||||
switch (parameter.type) {
|
||||
case GL_BOOL:
|
||||
*data = parameter.value.boolean_value ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GL_ALPHA_TEST:
|
||||
*data = m_alpha_test_func ? GL_TRUE : GL_FALSE;
|
||||
case GL_DOUBLE:
|
||||
*data = (parameter.value.double_value == 0.0) ? GL_FALSE : GL_TRUE;
|
||||
break;
|
||||
case GL_DEPTH_TEST:
|
||||
*data = m_depth_test_enabled ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GL_DOUBLEBUFFER:
|
||||
*data = GL_TRUE;
|
||||
break;
|
||||
case GL_CULL_FACE:
|
||||
*data = m_cull_faces ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GL_STENCIL_TEST:
|
||||
*data = m_stencil_test_enabled ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GL_TEXTURE_1D:
|
||||
*data = m_active_texture_unit->texture_1d_enabled() ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GL_TEXTURE_2D:
|
||||
*data = m_active_texture_unit->texture_2d_enabled() ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GL_TEXTURE_3D:
|
||||
*data = m_active_texture_unit->texture_3d_enabled() ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
*data = m_active_texture_unit->texture_cube_map_enabled() ? GL_TRUE : GL_FALSE;
|
||||
case GL_INT:
|
||||
*data = (parameter.value.integer_value == 0) ? GL_FALSE : GL_TRUE;
|
||||
break;
|
||||
default:
|
||||
// According to the Khronos docs, we always return GL_INVALID_ENUM if we encounter a non-accepted value
|
||||
// for `pname`
|
||||
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1625,30 +1675,53 @@ void SoftwareGLContext::get_floating_point(GLenum pname, T* params)
|
|||
{
|
||||
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
||||
|
||||
// Handle special matrix cases first
|
||||
auto flatten_and_assign_matrix = [¶ms](const FloatMatrix4x4& matrix) {
|
||||
auto elements = matrix.elements();
|
||||
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
for (size_t j = 0; j < 4; ++j) {
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
for (size_t j = 0; j < 4; ++j)
|
||||
params[i * 4 + j] = static_cast<T>(elements[i][j]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
switch (pname) {
|
||||
case GL_MODELVIEW_MATRIX:
|
||||
if (m_current_matrix_mode == GL_MODELVIEW)
|
||||
flatten_and_assign_matrix(m_model_view_matrix);
|
||||
else {
|
||||
if (m_model_view_matrix_stack.is_empty())
|
||||
else if (m_model_view_matrix_stack.is_empty())
|
||||
flatten_and_assign_matrix(FloatMatrix4x4::identity());
|
||||
else
|
||||
flatten_and_assign_matrix(m_model_view_matrix_stack.last());
|
||||
return;
|
||||
case GL_PROJECTION_MATRIX:
|
||||
if (m_current_matrix_mode == GL_PROJECTION)
|
||||
flatten_and_assign_matrix(m_projection_matrix);
|
||||
else if (m_projection_matrix_stack.is_empty())
|
||||
flatten_and_assign_matrix(FloatMatrix4x4::identity());
|
||||
else
|
||||
flatten_and_assign_matrix(m_projection_matrix_stack.last());
|
||||
return;
|
||||
}
|
||||
|
||||
// Regular parameters
|
||||
auto optional_parameter = get_context_parameter(pname);
|
||||
RETURN_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM);
|
||||
auto parameter = optional_parameter.release_value();
|
||||
|
||||
switch (parameter.type) {
|
||||
case GL_BOOL:
|
||||
*params = parameter.value.boolean_value ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GL_DOUBLE:
|
||||
for (size_t i = 0; i < parameter.count; ++i) {
|
||||
params[i] = parameter.value.double_list[i];
|
||||
}
|
||||
break;
|
||||
case GL_INT:
|
||||
for (size_t i = 0; i < parameter.count; ++i) {
|
||||
params[i] = parameter.value.integer_list[i];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dbgln_if(GL_DEBUG, "FIXME: unimplemented floating point parameter {:#x}", pname);
|
||||
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1656,48 +1729,29 @@ void SoftwareGLContext::gl_get_integerv(GLenum pname, GLint* data)
|
|||
{
|
||||
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
||||
|
||||
switch (pname) {
|
||||
case GL_BLEND_SRC_ALPHA:
|
||||
*data = m_blend_source_factor;
|
||||
auto optional_parameter = get_context_parameter(pname);
|
||||
RETURN_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM);
|
||||
auto parameter = optional_parameter.release_value();
|
||||
|
||||
switch (parameter.type) {
|
||||
case GL_BOOL:
|
||||
*data = parameter.value.boolean_value ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GL_BLEND_DST_ALPHA:
|
||||
*data = m_blend_destination_factor;
|
||||
break;
|
||||
case GL_MAX_TEXTURE_UNITS:
|
||||
*data = m_texture_units.size();
|
||||
break;
|
||||
case GL_MAX_TEXTURE_SIZE:
|
||||
*data = 4096;
|
||||
break;
|
||||
case GL_PACK_ALIGNMENT:
|
||||
*data = m_pack_alignment;
|
||||
break;
|
||||
case GL_SCISSOR_BOX: {
|
||||
auto scissor_box = m_rasterizer.options().scissor_box;
|
||||
data[0] = scissor_box.x();
|
||||
data[1] = scissor_box.y();
|
||||
data[2] = scissor_box.width();
|
||||
data[3] = scissor_box.height();
|
||||
case GL_DOUBLE: {
|
||||
double const int_range = static_cast<double>(NumericLimits<GLint>::max()) - NumericLimits<GLint>::min();
|
||||
for (size_t i = 0; i < parameter.count; ++i) {
|
||||
double const result_factor = (clamp(parameter.value.double_list[i], -1.0, 1.0) + 1.0) / 2.0;
|
||||
data[i] = static_cast<GLint>(NumericLimits<GLint>::min() + result_factor * int_range);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GL_UNPACK_ALIGNMENT:
|
||||
*data = m_unpack_alignment;
|
||||
break;
|
||||
case GL_UNPACK_ROW_LENGTH:
|
||||
*data = m_unpack_row_length;
|
||||
break;
|
||||
case GL_RED_BITS:
|
||||
case GL_GREEN_BITS:
|
||||
case GL_BLUE_BITS:
|
||||
case GL_ALPHA_BITS:
|
||||
case GL_DEPTH_BITS:
|
||||
case GL_STENCIL_BITS:
|
||||
*data = sizeof(float) * 8;
|
||||
case GL_INT:
|
||||
for (size_t i = 0; i < parameter.count; ++i) {
|
||||
data[i] = parameter.value.integer_list[i];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// According to the Khronos docs, we always return GL_INVALID_ENUM if we encounter a non-accepted value
|
||||
// for `pname`
|
||||
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "Tex/Texture.h"
|
||||
#include "Tex/TextureUnit.h"
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <AK/Tuple.h>
|
||||
#include <AK/Variant.h>
|
||||
|
@ -25,6 +26,18 @@
|
|||
|
||||
namespace GL {
|
||||
|
||||
struct ContextParameter {
|
||||
GLenum type;
|
||||
u8 count { 1 };
|
||||
union {
|
||||
bool boolean_value;
|
||||
GLint integer_value;
|
||||
GLint integer_list[4];
|
||||
GLdouble double_value;
|
||||
GLdouble double_list[4];
|
||||
} value;
|
||||
};
|
||||
|
||||
class SoftwareGLContext : public GLContext {
|
||||
public:
|
||||
SoftwareGLContext(Gfx::Bitmap&);
|
||||
|
@ -135,6 +148,8 @@ private:
|
|||
m_current_listing_index->listing.entries.empend(member, Listing::ArgumentsFor<member> { forward<Args>(args)... });
|
||||
}
|
||||
|
||||
Optional<ContextParameter> get_context_parameter(GLenum pname);
|
||||
|
||||
template<typename T>
|
||||
void get_floating_point(GLenum pname, T* params);
|
||||
|
||||
|
|
Loading…
Reference in a new issue