mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 20:07:36 +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
3 changed files with 153 additions and 82 deletions
|
@ -161,6 +161,7 @@ extern "C" {
|
||||||
#define GL_3_BYTES 0x1408
|
#define GL_3_BYTES 0x1408
|
||||||
#define GL_4_BYTES 0x1409
|
#define GL_4_BYTES 0x1409
|
||||||
#define GL_DOUBLE 0x140A
|
#define GL_DOUBLE 0x140A
|
||||||
|
#define GL_BOOL 0x8B56
|
||||||
|
|
||||||
// Format enums
|
// Format enums
|
||||||
#define GL_COLOR_INDEX 0x1900
|
#define GL_COLOR_INDEX 0x1900
|
||||||
|
@ -343,6 +344,7 @@ extern "C" {
|
||||||
|
|
||||||
// OpenGL State & GLGet
|
// OpenGL State & GLGet
|
||||||
#define GL_MODELVIEW_MATRIX 0x0BA6
|
#define GL_MODELVIEW_MATRIX 0x0BA6
|
||||||
|
#define GL_PROJECTION_MATRIX 0x0BA7
|
||||||
|
|
||||||
//
|
//
|
||||||
// OpenGL typedefs
|
// 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)
|
void SoftwareGLContext::gl_begin(GLenum mode)
|
||||||
{
|
{
|
||||||
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_begin, 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:
|
case GL_SHADING_LANGUAGE_VERSION:
|
||||||
return reinterpret_cast<GLubyte*>(const_cast<char*>("0.0"));
|
return reinterpret_cast<GLubyte*>(const_cast<char*>("0.0"));
|
||||||
default:
|
default:
|
||||||
dbgln_if(GL_DEBUG, "glGetString(): Unknown enum name!");
|
dbgln_if(GL_DEBUG, "gl_get_string({:#x}): unknown name", name);
|
||||||
break;
|
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);
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
||||||
|
|
||||||
switch (pname) {
|
auto optional_parameter = get_context_parameter(pname);
|
||||||
case GL_BLEND:
|
RETURN_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM);
|
||||||
*data = m_blend_enabled ? GL_TRUE : GL_FALSE;
|
auto parameter = optional_parameter.release_value();
|
||||||
|
|
||||||
|
switch (parameter.type) {
|
||||||
|
case GL_BOOL:
|
||||||
|
*data = parameter.value.boolean_value ? GL_TRUE : GL_FALSE;
|
||||||
break;
|
break;
|
||||||
case GL_ALPHA_TEST:
|
case GL_DOUBLE:
|
||||||
*data = m_alpha_test_func ? GL_TRUE : GL_FALSE;
|
*data = (parameter.value.double_value == 0.0) ? GL_FALSE : GL_TRUE;
|
||||||
break;
|
break;
|
||||||
case GL_DEPTH_TEST:
|
case GL_INT:
|
||||||
*data = m_depth_test_enabled ? GL_TRUE : GL_FALSE;
|
*data = (parameter.value.integer_value == 0) ? GL_FALSE : GL_TRUE;
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// According to the Khronos docs, we always return GL_INVALID_ENUM if we encounter a non-accepted value
|
VERIFY_NOT_REACHED();
|
||||||
// for `pname`
|
|
||||||
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1625,30 +1675,53 @@ void SoftwareGLContext::get_floating_point(GLenum pname, T* params)
|
||||||
{
|
{
|
||||||
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
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 flatten_and_assign_matrix = [¶ms](const FloatMatrix4x4& matrix) {
|
||||||
auto elements = matrix.elements();
|
auto elements = matrix.elements();
|
||||||
|
for (size_t i = 0; i < 4; ++i)
|
||||||
for (size_t i = 0; i < 4; ++i) {
|
for (size_t j = 0; j < 4; ++j)
|
||||||
for (size_t j = 0; j < 4; ++j) {
|
|
||||||
params[i * 4 + j] = static_cast<T>(elements[i][j]);
|
params[i * 4 + j] = static_cast<T>(elements[i][j]);
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (pname) {
|
switch (pname) {
|
||||||
case GL_MODELVIEW_MATRIX:
|
case GL_MODELVIEW_MATRIX:
|
||||||
if (m_current_matrix_mode == GL_MODELVIEW)
|
if (m_current_matrix_mode == GL_MODELVIEW)
|
||||||
flatten_and_assign_matrix(m_model_view_matrix);
|
flatten_and_assign_matrix(m_model_view_matrix);
|
||||||
else {
|
else if (m_model_view_matrix_stack.is_empty())
|
||||||
if (m_model_view_matrix_stack.is_empty())
|
|
||||||
flatten_and_assign_matrix(FloatMatrix4x4::identity());
|
flatten_and_assign_matrix(FloatMatrix4x4::identity());
|
||||||
else
|
else
|
||||||
flatten_and_assign_matrix(m_model_view_matrix_stack.last());
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
dbgln_if(GL_DEBUG, "FIXME: unimplemented floating point parameter {:#x}", pname);
|
VERIFY_NOT_REACHED();
|
||||||
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1656,48 +1729,29 @@ void SoftwareGLContext::gl_get_integerv(GLenum pname, GLint* data)
|
||||||
{
|
{
|
||||||
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
||||||
|
|
||||||
switch (pname) {
|
auto optional_parameter = get_context_parameter(pname);
|
||||||
case GL_BLEND_SRC_ALPHA:
|
RETURN_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM);
|
||||||
*data = m_blend_source_factor;
|
auto parameter = optional_parameter.release_value();
|
||||||
|
|
||||||
|
switch (parameter.type) {
|
||||||
|
case GL_BOOL:
|
||||||
|
*data = parameter.value.boolean_value ? GL_TRUE : GL_FALSE;
|
||||||
break;
|
break;
|
||||||
case GL_BLEND_DST_ALPHA:
|
case GL_DOUBLE: {
|
||||||
*data = m_blend_destination_factor;
|
double const int_range = static_cast<double>(NumericLimits<GLint>::max()) - NumericLimits<GLint>::min();
|
||||||
break;
|
for (size_t i = 0; i < parameter.count; ++i) {
|
||||||
case GL_MAX_TEXTURE_UNITS:
|
double const result_factor = (clamp(parameter.value.double_list[i], -1.0, 1.0) + 1.0) / 2.0;
|
||||||
*data = m_texture_units.size();
|
data[i] = static_cast<GLint>(NumericLimits<GLint>::min() + result_factor * int_range);
|
||||||
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();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_UNPACK_ALIGNMENT:
|
case GL_INT:
|
||||||
*data = m_unpack_alignment;
|
for (size_t i = 0; i < parameter.count; ++i) {
|
||||||
break;
|
data[i] = parameter.value.integer_list[i];
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// According to the Khronos docs, we always return GL_INVALID_ENUM if we encounter a non-accepted value
|
VERIFY_NOT_REACHED();
|
||||||
// for `pname`
|
|
||||||
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "Tex/Texture.h"
|
#include "Tex/Texture.h"
|
||||||
#include "Tex/TextureUnit.h"
|
#include "Tex/TextureUnit.h"
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
|
#include <AK/Optional.h>
|
||||||
#include <AK/RefPtr.h>
|
#include <AK/RefPtr.h>
|
||||||
#include <AK/Tuple.h>
|
#include <AK/Tuple.h>
|
||||||
#include <AK/Variant.h>
|
#include <AK/Variant.h>
|
||||||
|
@ -25,6 +26,18 @@
|
||||||
|
|
||||||
namespace GL {
|
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 {
|
class SoftwareGLContext : public GLContext {
|
||||||
public:
|
public:
|
||||||
SoftwareGLContext(Gfx::Bitmap&);
|
SoftwareGLContext(Gfx::Bitmap&);
|
||||||
|
@ -135,6 +148,8 @@ private:
|
||||||
m_current_listing_index->listing.entries.empend(member, Listing::ArgumentsFor<member> { forward<Args>(args)... });
|
m_current_listing_index->listing.entries.empend(member, Listing::ArgumentsFor<member> { forward<Args>(args)... });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Optional<ContextParameter> get_context_parameter(GLenum pname);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void get_floating_point(GLenum pname, T* params);
|
void get_floating_point(GLenum pname, T* params);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue