2021-01-06 11:58:01 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
|
2021-05-29 10:38:28 +00:00
|
|
|
* Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org>
|
2023-01-30 15:08:50 +00:00
|
|
|
* Copyright (c) 2022-2023, Jelle Raaijmakers <jelle@gmta.nl>
|
2021-01-06 11:58:01 +00:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
2022-01-12 15:39:59 +00:00
|
|
|
#include <AK/Debug.h>
|
2023-01-30 15:08:50 +00:00
|
|
|
#include <AK/StringBuilder.h>
|
2022-03-09 19:56:58 +00:00
|
|
|
#include <AK/Vector.h>
|
|
|
|
#include <LibGL/GLContext.h>
|
2022-08-24 21:47:49 +00:00
|
|
|
#include <LibGL/Image.h>
|
2022-03-27 16:54:31 +00:00
|
|
|
#include <LibGPU/Device.h>
|
2022-03-15 00:11:58 +00:00
|
|
|
#include <LibGPU/Enums.h>
|
2022-08-24 21:47:49 +00:00
|
|
|
#include <LibGPU/ImageDataLayout.h>
|
2022-03-15 12:19:03 +00:00
|
|
|
#include <LibGPU/ImageFormat.h>
|
2021-04-23 23:57:01 +00:00
|
|
|
#include <LibGfx/Bitmap.h>
|
2021-01-06 11:58:01 +00:00
|
|
|
|
|
|
|
__attribute__((visibility("hidden"))) GL::GLContext* g_gl_context;
|
|
|
|
|
|
|
|
namespace GL {
|
|
|
|
|
2022-03-27 16:54:31 +00:00
|
|
|
GLContext::GLContext(RefPtr<GPU::Driver> driver, NonnullOwnPtr<GPU::Device> device, Gfx::Bitmap& frontbuffer)
|
2022-09-16 21:41:11 +00:00
|
|
|
: m_driver { driver }
|
2022-03-27 16:54:31 +00:00
|
|
|
, m_rasterizer { move(device) }
|
2022-03-27 14:49:15 +00:00
|
|
|
, m_device_info { m_rasterizer->info() }
|
2022-09-16 21:41:11 +00:00
|
|
|
, m_viewport { frontbuffer.rect() }
|
|
|
|
, m_frontbuffer { frontbuffer }
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
|
|
|
m_texture_units.resize(m_device_info.num_texture_units);
|
|
|
|
m_active_texture_unit = &m_texture_units[0];
|
|
|
|
|
|
|
|
// All texture units are initialized with default textures for all targets; these
|
|
|
|
// can be referenced later on with texture name 0 in operations like glBindTexture().
|
|
|
|
auto default_texture_2d = adopt_ref(*new Texture2D());
|
|
|
|
m_default_textures.set(GL_TEXTURE_2D, default_texture_2d);
|
|
|
|
for (auto& texture_unit : m_texture_units)
|
|
|
|
texture_unit.set_texture_2d_target_texture(default_texture_2d);
|
|
|
|
|
|
|
|
// Query the number lights from the device and set set up their state
|
|
|
|
// locally in the GL
|
|
|
|
m_light_states.resize(m_device_info.num_lights);
|
|
|
|
|
|
|
|
// Set-up light0's state, as it has a different default state
|
|
|
|
// to the other lights, as per the OpenGL 1.5 spec
|
|
|
|
auto& light0 = m_light_states.at(0);
|
|
|
|
light0.diffuse_intensity = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
|
|
light0.specular_intensity = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
|
|
m_light_state_is_dirty = true;
|
|
|
|
|
|
|
|
m_client_side_texture_coord_array_enabled.resize(m_device_info.num_texture_units);
|
|
|
|
m_client_tex_coord_pointer.resize(m_device_info.num_texture_units);
|
|
|
|
m_current_vertex_tex_coord.resize(m_device_info.num_texture_units);
|
|
|
|
for (auto& tex_coord : m_current_vertex_tex_coord)
|
|
|
|
tex_coord = { 0.0f, 0.0f, 0.0f, 1.0f };
|
|
|
|
|
|
|
|
// Initialize the texture coordinate generation coefficients
|
|
|
|
// Indices 0,1,2,3 refer to the S,T,R and Q coordinate of the respective texture
|
|
|
|
// coordinate generation config.
|
|
|
|
m_texture_coordinate_generation.resize(m_device_info.num_texture_units);
|
|
|
|
for (auto& texture_coordinate_generation : m_texture_coordinate_generation) {
|
2022-09-04 22:40:27 +00:00
|
|
|
texture_coordinate_generation[0].object_plane_coefficients = { 1.f, 0.f, 0.f, 0.f };
|
|
|
|
texture_coordinate_generation[0].eye_plane_coefficients = { 1.f, 0.f, 0.f, 0.f };
|
|
|
|
texture_coordinate_generation[1].object_plane_coefficients = { 0.f, 1.f, 0.f, 0.f };
|
|
|
|
texture_coordinate_generation[1].eye_plane_coefficients = { 0.f, 1.f, 0.f, 0.f };
|
|
|
|
texture_coordinate_generation[2].object_plane_coefficients = { 0.f, 0.f, 0.f, 0.f };
|
|
|
|
texture_coordinate_generation[2].eye_plane_coefficients = { 0.f, 0.f, 0.f, 0.f };
|
|
|
|
texture_coordinate_generation[3].object_plane_coefficients = { 0.f, 0.f, 0.f, 0.f };
|
|
|
|
texture_coordinate_generation[3].eye_plane_coefficients = { 0.f, 0.f, 0.f, 0.f };
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2023-01-30 15:08:50 +00:00
|
|
|
m_extensions = build_extension_string().release_value_but_fixme_should_propagate_errors();
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2021-01-06 11:58:01 +00:00
|
|
|
GLContext::~GLContext()
|
|
|
|
{
|
2022-01-12 15:39:59 +00:00
|
|
|
dbgln_if(GL_DEBUG, "GLContext::~GLContext() {:p}", this);
|
2021-01-06 11:58:01 +00:00
|
|
|
if (g_gl_context == this)
|
|
|
|
make_context_current(nullptr);
|
|
|
|
}
|
|
|
|
|
2022-03-09 19:56:58 +00:00
|
|
|
void GLContext::gl_begin(GLenum mode)
|
|
|
|
{
|
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_begin, mode);
|
|
|
|
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
RETURN_WITH_ERROR_IF(mode > GL_POLYGON, GL_INVALID_ENUM);
|
|
|
|
|
|
|
|
m_current_draw_mode = mode;
|
|
|
|
m_in_draw_state = true; // Certain commands will now generate an error
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLContext::gl_clear(GLbitfield mask)
|
|
|
|
{
|
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear, mask);
|
|
|
|
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
RETURN_WITH_ERROR_IF(mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT), GL_INVALID_ENUM);
|
|
|
|
|
|
|
|
if (mask & GL_COLOR_BUFFER_BIT)
|
2022-03-27 14:49:15 +00:00
|
|
|
m_rasterizer->clear_color(m_clear_color);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
|
|
|
if (mask & GL_DEPTH_BUFFER_BIT)
|
2022-03-27 14:49:15 +00:00
|
|
|
m_rasterizer->clear_depth(m_clear_depth);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
|
|
|
if (mask & GL_STENCIL_BUFFER_BIT)
|
2022-03-27 14:49:15 +00:00
|
|
|
m_rasterizer->clear_stencil(m_clear_stencil);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GLContext::gl_clear_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
|
|
|
|
{
|
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear_color, red, green, blue, alpha);
|
|
|
|
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
|
|
|
|
m_clear_color = { red, green, blue, alpha };
|
|
|
|
m_clear_color.clamp(0.f, 1.f);
|
|
|
|
}
|
|
|
|
|
2023-01-01 20:11:20 +00:00
|
|
|
void GLContext::gl_clear_depth(GLfloat depth)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear_depth, depth);
|
|
|
|
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
|
2023-01-01 20:11:20 +00:00
|
|
|
m_clear_depth = clamp(depth, 0.f, 1.f);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GLContext::gl_end()
|
|
|
|
{
|
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_end);
|
|
|
|
|
|
|
|
// Make sure we had a `glBegin` before this call...
|
|
|
|
RETURN_WITH_ERROR_IF(!m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
m_in_draw_state = false;
|
|
|
|
|
|
|
|
sync_device_config();
|
|
|
|
|
2022-03-15 00:11:58 +00:00
|
|
|
GPU::PrimitiveType primitive_type;
|
2022-03-09 19:56:58 +00:00
|
|
|
switch (m_current_draw_mode) {
|
LibGL+LibGPU+LibSoftGPU: Implement point and line drawing
Implement (anti)aliased point drawing and anti-aliased line drawing.
Supported through LibGL's `GL_POINTS`, `GL_LINES`, `GL_LINE_LOOP` and
`GL_LINE_STRIP`.
In order to support this, `LibSoftGPU`s rasterization logic was
reworked. Now, any primitive can be drawn by invoking `rasterize()`
which takes care of the quad loop and fragment testing logic. Three
callbacks need to be passed:
* `set_coverage_mask`: the primitive needs to provide initial coverage
mask information so fragments can be discarded early.
* `set_quad_depth`: fragments survived stencil testing, so depth values
need to be set so depth testing can take place.
* `set_quad_attributes`: fragments survived depth testing, so fragment
shading is going to take place. All attributes like color, tex coords
and fog depth need to be set so alpha testing and eventually,
fragment rasterization can take place.
As of this commit, there are four instantiations of this function:
* Triangle rasterization
* Points - aliased
* Points - anti-aliased
* Lines - anti-aliased
In order to standardize vertex processing for all primitive types,
things like vertex transformation, lighting and tex coord generation
are now taking place before clipping.
2022-05-08 00:13:14 +00:00
|
|
|
case GL_LINE_LOOP:
|
|
|
|
primitive_type = GPU::PrimitiveType::LineLoop;
|
|
|
|
break;
|
|
|
|
case GL_LINE_STRIP:
|
|
|
|
primitive_type = GPU::PrimitiveType::LineStrip;
|
|
|
|
break;
|
|
|
|
case GL_LINES:
|
|
|
|
primitive_type = GPU::PrimitiveType::Lines;
|
|
|
|
break;
|
|
|
|
case GL_POINTS:
|
|
|
|
primitive_type = GPU::PrimitiveType::Points;
|
|
|
|
break;
|
2022-03-09 19:56:58 +00:00
|
|
|
case GL_TRIANGLES:
|
2022-03-15 00:11:58 +00:00
|
|
|
primitive_type = GPU::PrimitiveType::Triangles;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
|
|
|
case GL_TRIANGLE_STRIP:
|
|
|
|
case GL_QUAD_STRIP:
|
2022-03-15 00:11:58 +00:00
|
|
|
primitive_type = GPU::PrimitiveType::TriangleStrip;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
|
|
|
case GL_TRIANGLE_FAN:
|
|
|
|
case GL_POLYGON:
|
2022-03-15 00:11:58 +00:00
|
|
|
primitive_type = GPU::PrimitiveType::TriangleFan;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
|
|
|
case GL_QUADS:
|
2022-03-15 00:11:58 +00:00
|
|
|
primitive_type = GPU::PrimitiveType::Quads;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
}
|
|
|
|
|
2022-09-04 22:40:27 +00:00
|
|
|
m_rasterizer->draw_primitives(primitive_type, model_view_matrix(), projection_matrix(), m_vertex_list);
|
2022-03-09 19:56:58 +00:00
|
|
|
m_vertex_list.clear_with_capacity();
|
|
|
|
}
|
|
|
|
|
|
|
|
GLenum GLContext::gl_get_error()
|
|
|
|
{
|
|
|
|
if (m_in_draw_state)
|
|
|
|
return GL_INVALID_OPERATION;
|
|
|
|
|
|
|
|
auto last_error = m_error;
|
|
|
|
m_error = GL_NO_ERROR;
|
|
|
|
return last_error;
|
|
|
|
}
|
|
|
|
|
2022-09-01 11:27:11 +00:00
|
|
|
GLubyte const* GLContext::gl_get_string(GLenum name)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
|
|
|
RETURN_VALUE_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION, nullptr);
|
|
|
|
|
|
|
|
switch (name) {
|
|
|
|
case GL_VENDOR:
|
2022-09-01 11:27:11 +00:00
|
|
|
return reinterpret_cast<GLubyte const*>(m_device_info.vendor_name.characters());
|
2022-03-09 19:56:58 +00:00
|
|
|
case GL_RENDERER:
|
2022-09-01 11:27:11 +00:00
|
|
|
return reinterpret_cast<GLubyte const*>(m_device_info.device_name.characters());
|
2022-03-09 19:56:58 +00:00
|
|
|
case GL_VERSION:
|
2022-09-01 11:27:11 +00:00
|
|
|
return reinterpret_cast<GLubyte const*>("1.5");
|
2022-03-09 19:56:58 +00:00
|
|
|
case GL_EXTENSIONS:
|
2023-01-30 15:08:50 +00:00
|
|
|
return reinterpret_cast<GLubyte const*>(m_extensions.data());
|
2022-03-09 19:56:58 +00:00
|
|
|
case GL_SHADING_LANGUAGE_VERSION:
|
2022-09-01 11:27:11 +00:00
|
|
|
return reinterpret_cast<GLubyte const*>("0.0");
|
2022-03-09 19:56:58 +00:00
|
|
|
default:
|
|
|
|
dbgln_if(GL_DEBUG, "gl_get_string({:#x}): unknown name", name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
RETURN_VALUE_WITH_ERROR_IF(true, GL_INVALID_ENUM, nullptr);
|
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_viewport(GLint x, GLint y, GLsizei width, GLsizei height)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_viewport, x, y, width, height);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
m_viewport = { x, y, width, height };
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
auto rasterizer_options = m_rasterizer->options();
|
|
|
|
rasterizer_options.viewport = m_viewport;
|
|
|
|
m_rasterizer->set_options(rasterizer_options);
|
2022-03-10 09:38:22 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_front_face(GLenum face)
|
2022-03-10 09:38:22 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_front_face, face);
|
2022-03-10 09:38:22 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(face < GL_CW || face > GL_CCW, GL_INVALID_ENUM);
|
2022-03-10 09:38:22 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
m_front_face = face;
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
auto rasterizer_options = m_rasterizer->options();
|
|
|
|
rasterizer_options.front_face = (face == GL_CW) ? GPU::WindingOrder::Clockwise : GPU::WindingOrder::CounterClockwise;
|
|
|
|
m_rasterizer->set_options(rasterizer_options);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_cull_face(GLenum cull_mode)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_cull_face, cull_mode);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-06-03 23:19:15 +00:00
|
|
|
RETURN_WITH_ERROR_IF(cull_mode != GL_FRONT && cull_mode != GL_BACK && cull_mode != GL_FRONT_AND_BACK, GL_INVALID_ENUM);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
m_culled_sides = cull_mode;
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
auto rasterizer_options = m_rasterizer->options();
|
|
|
|
rasterizer_options.cull_back = cull_mode == GL_BACK || cull_mode == GL_FRONT_AND_BACK;
|
|
|
|
rasterizer_options.cull_front = cull_mode == GL_FRONT || cull_mode == GL_FRONT_AND_BACK;
|
|
|
|
m_rasterizer->set_options(rasterizer_options);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_flush()
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
// No-op since GLContext is completely synchronous at the moment
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_finish()
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
// No-op since GLContext is completely synchronous at the moment
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_blend_func(GLenum src_factor, GLenum dst_factor)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_blend_func, src_factor, dst_factor);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
// FIXME: The list of allowed enums differs between API versions
|
|
|
|
// This was taken from the 2.0 spec on https://docs.gl/gl2/glBlendFunc
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(!(src_factor == GL_ZERO
|
|
|
|
|| src_factor == GL_ONE
|
|
|
|
|| src_factor == GL_SRC_COLOR
|
|
|
|
|| src_factor == GL_ONE_MINUS_SRC_COLOR
|
|
|
|
|| src_factor == GL_DST_COLOR
|
|
|
|
|| src_factor == GL_ONE_MINUS_DST_COLOR
|
|
|
|
|| src_factor == GL_SRC_ALPHA
|
|
|
|
|| src_factor == GL_ONE_MINUS_SRC_ALPHA
|
|
|
|
|| src_factor == GL_DST_ALPHA
|
|
|
|
|| src_factor == GL_ONE_MINUS_DST_ALPHA
|
|
|
|
|| src_factor == GL_CONSTANT_COLOR
|
|
|
|
|| src_factor == GL_ONE_MINUS_CONSTANT_COLOR
|
|
|
|
|| src_factor == GL_CONSTANT_ALPHA
|
|
|
|
|| src_factor == GL_ONE_MINUS_CONSTANT_ALPHA
|
|
|
|
|| src_factor == GL_SRC_ALPHA_SATURATE),
|
|
|
|
GL_INVALID_ENUM);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(!(dst_factor == GL_ZERO
|
|
|
|
|| dst_factor == GL_ONE
|
|
|
|
|| dst_factor == GL_SRC_COLOR
|
|
|
|
|| dst_factor == GL_ONE_MINUS_SRC_COLOR
|
|
|
|
|| dst_factor == GL_DST_COLOR
|
|
|
|
|| dst_factor == GL_ONE_MINUS_DST_COLOR
|
|
|
|
|| dst_factor == GL_SRC_ALPHA
|
|
|
|
|| dst_factor == GL_ONE_MINUS_SRC_ALPHA
|
|
|
|
|| dst_factor == GL_DST_ALPHA
|
|
|
|
|| dst_factor == GL_ONE_MINUS_DST_ALPHA
|
|
|
|
|| dst_factor == GL_CONSTANT_COLOR
|
|
|
|
|| dst_factor == GL_ONE_MINUS_CONSTANT_COLOR
|
|
|
|
|| dst_factor == GL_CONSTANT_ALPHA
|
|
|
|
|| dst_factor == GL_ONE_MINUS_CONSTANT_ALPHA),
|
|
|
|
GL_INVALID_ENUM);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
m_blend_source_factor = src_factor;
|
|
|
|
m_blend_destination_factor = dst_factor;
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-10-16 22:06:11 +00:00
|
|
|
auto map_gl_blend_factor_to_device = [](GLenum factor) constexpr {
|
2022-05-01 00:30:32 +00:00
|
|
|
switch (factor) {
|
|
|
|
case GL_ZERO:
|
|
|
|
return GPU::BlendFactor::Zero;
|
|
|
|
case GL_ONE:
|
|
|
|
return GPU::BlendFactor::One;
|
|
|
|
case GL_SRC_ALPHA:
|
|
|
|
return GPU::BlendFactor::SrcAlpha;
|
|
|
|
case GL_ONE_MINUS_SRC_ALPHA:
|
|
|
|
return GPU::BlendFactor::OneMinusSrcAlpha;
|
|
|
|
case GL_SRC_COLOR:
|
|
|
|
return GPU::BlendFactor::SrcColor;
|
|
|
|
case GL_ONE_MINUS_SRC_COLOR:
|
|
|
|
return GPU::BlendFactor::OneMinusSrcColor;
|
|
|
|
case GL_DST_ALPHA:
|
|
|
|
return GPU::BlendFactor::DstAlpha;
|
|
|
|
case GL_ONE_MINUS_DST_ALPHA:
|
|
|
|
return GPU::BlendFactor::OneMinusDstAlpha;
|
|
|
|
case GL_DST_COLOR:
|
|
|
|
return GPU::BlendFactor::DstColor;
|
|
|
|
case GL_ONE_MINUS_DST_COLOR:
|
|
|
|
return GPU::BlendFactor::OneMinusDstColor;
|
|
|
|
case GL_SRC_ALPHA_SATURATE:
|
|
|
|
return GPU::BlendFactor::SrcAlphaSaturate;
|
|
|
|
default:
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
}
|
|
|
|
};
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
auto options = m_rasterizer->options();
|
|
|
|
options.blend_source_factor = map_gl_blend_factor_to_device(m_blend_source_factor);
|
|
|
|
options.blend_destination_factor = map_gl_blend_factor_to_device(m_blend_destination_factor);
|
|
|
|
m_rasterizer->set_options(options);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_alpha_func(GLenum func, GLclampf ref)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_alpha_func, func, ref);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(func < GL_NEVER || func > GL_ALWAYS, GL_INVALID_ENUM);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
m_alpha_test_func = func;
|
|
|
|
m_alpha_test_ref_value = ref;
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
auto options = m_rasterizer->options();
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
switch (func) {
|
|
|
|
case GL_NEVER:
|
|
|
|
options.alpha_test_func = GPU::AlphaTestFunction::Never;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_ALWAYS:
|
|
|
|
options.alpha_test_func = GPU::AlphaTestFunction::Always;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_LESS:
|
|
|
|
options.alpha_test_func = GPU::AlphaTestFunction::Less;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_LEQUAL:
|
|
|
|
options.alpha_test_func = GPU::AlphaTestFunction::LessOrEqual;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_EQUAL:
|
|
|
|
options.alpha_test_func = GPU::AlphaTestFunction::Equal;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_NOTEQUAL:
|
|
|
|
options.alpha_test_func = GPU::AlphaTestFunction::NotEqual;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_GEQUAL:
|
|
|
|
options.alpha_test_func = GPU::AlphaTestFunction::GreaterOrEqual;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_GREATER:
|
|
|
|
options.alpha_test_func = GPU::AlphaTestFunction::Greater;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
|
|
|
default:
|
2022-05-01 00:30:32 +00:00
|
|
|
VERIFY_NOT_REACHED();
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
options.alpha_test_ref_value = m_alpha_test_ref_value;
|
|
|
|
m_rasterizer->set_options(options);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_hint(GLenum target, GLenum mode)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_hint, target, mode);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(target != GL_PERSPECTIVE_CORRECTION_HINT
|
|
|
|
&& target != GL_POINT_SMOOTH_HINT
|
|
|
|
&& target != GL_LINE_SMOOTH_HINT
|
|
|
|
&& target != GL_POLYGON_SMOOTH_HINT
|
|
|
|
&& target != GL_FOG_HINT
|
|
|
|
&& target != GL_GENERATE_MIPMAP_HINT
|
|
|
|
&& target != GL_TEXTURE_COMPRESSION_HINT,
|
|
|
|
GL_INVALID_ENUM);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(mode != GL_DONT_CARE
|
|
|
|
&& mode != GL_FASTEST
|
|
|
|
&& mode != GL_NICEST,
|
|
|
|
GL_INVALID_ENUM);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
// According to the spec implementors are free to ignore glHint. So we do.
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_read_buffer(GLenum mode)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_read_buffer, mode);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
// FIXME: Also allow aux buffers GL_AUX0 through GL_AUX3 here
|
|
|
|
// plus any aux buffer between 0 and GL_AUX_BUFFERS
|
|
|
|
RETURN_WITH_ERROR_IF(mode != GL_FRONT_LEFT
|
|
|
|
&& mode != GL_FRONT_RIGHT
|
|
|
|
&& mode != GL_BACK_LEFT
|
|
|
|
&& mode != GL_BACK_RIGHT
|
|
|
|
&& mode != GL_FRONT
|
|
|
|
&& mode != GL_BACK
|
|
|
|
&& mode != GL_LEFT
|
|
|
|
&& mode != GL_RIGHT,
|
2022-03-09 19:56:58 +00:00
|
|
|
GL_INVALID_ENUM);
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
// FIXME: We do not currently have aux buffers, so make it an invalid
|
|
|
|
// operation to select anything but front or back buffers. Also we do
|
|
|
|
// not allow selecting the stereoscopic RIGHT buffers since we do not
|
|
|
|
// have them configured.
|
|
|
|
RETURN_WITH_ERROR_IF(mode != GL_FRONT_LEFT
|
|
|
|
&& mode != GL_FRONT
|
|
|
|
&& mode != GL_BACK_LEFT
|
|
|
|
&& mode != GL_BACK
|
|
|
|
&& mode != GL_FRONT
|
|
|
|
&& mode != GL_BACK
|
|
|
|
&& mode != GL_LEFT,
|
|
|
|
GL_INVALID_OPERATION);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
m_current_read_buffer = mode;
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_draw_buffer(GLenum buffer)
|
2022-03-09 11:40:26 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_draw_buffer, buffer);
|
2022-03-09 11:40:26 +00:00
|
|
|
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
// FIXME: Also allow aux buffers GL_AUX0 through GL_AUX3 here
|
|
|
|
// plus any aux buffer between 0 and GL_AUX_BUFFERS
|
|
|
|
RETURN_WITH_ERROR_IF(buffer != GL_NONE
|
|
|
|
&& buffer != GL_FRONT_LEFT
|
|
|
|
&& buffer != GL_FRONT_RIGHT
|
|
|
|
&& buffer != GL_BACK_LEFT
|
|
|
|
&& buffer != GL_BACK_RIGHT
|
|
|
|
&& buffer != GL_FRONT
|
|
|
|
&& buffer != GL_BACK
|
|
|
|
&& buffer != GL_LEFT
|
|
|
|
&& buffer != GL_RIGHT,
|
|
|
|
GL_INVALID_ENUM);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
// FIXME: We do not currently have aux buffers, so make it an invalid
|
|
|
|
// operation to select anything but front or back buffers. Also we do
|
|
|
|
// not allow selecting the stereoscopic RIGHT buffers since we do not
|
|
|
|
// have them configured.
|
|
|
|
RETURN_WITH_ERROR_IF(buffer != GL_NONE
|
|
|
|
&& buffer != GL_FRONT_LEFT
|
|
|
|
&& buffer != GL_FRONT
|
|
|
|
&& buffer != GL_BACK_LEFT
|
|
|
|
&& buffer != GL_BACK
|
|
|
|
&& buffer != GL_FRONT
|
|
|
|
&& buffer != GL_BACK
|
|
|
|
&& buffer != GL_LEFT,
|
|
|
|
GL_INVALID_OPERATION);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
m_current_draw_buffer = buffer;
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-03-27 14:49:15 +00:00
|
|
|
auto rasterizer_options = m_rasterizer->options();
|
2022-05-01 00:30:32 +00:00
|
|
|
// FIXME: We only have a single draw buffer in SoftGPU at the moment,
|
|
|
|
// so we simply disable color writes if GL_NONE is selected
|
|
|
|
rasterizer_options.enable_color_write = m_current_draw_buffer != GL_NONE;
|
2022-03-27 14:49:15 +00:00
|
|
|
m_rasterizer->set_options(rasterizer_options);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_read_pixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-09-04 18:02:37 +00:00
|
|
|
RETURN_WITH_ERROR_IF(format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM);
|
2022-08-24 21:47:49 +00:00
|
|
|
auto pixel_type_or_error = get_validated_pixel_type(GL_NONE, GL_NONE, format, type);
|
|
|
|
RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code());
|
|
|
|
|
|
|
|
auto pixel_type = pixel_type_or_error.release_value();
|
|
|
|
GPU::ImageDataLayout output_layout = {
|
|
|
|
.pixel_type = pixel_type,
|
|
|
|
.packing = get_packing_specification(PackingType::Pack),
|
|
|
|
.dimensions = {
|
|
|
|
.width = static_cast<u32>(width),
|
|
|
|
.height = static_cast<u32>(height),
|
|
|
|
.depth = 1,
|
|
|
|
},
|
|
|
|
.selection = {
|
|
|
|
.width = static_cast<u32>(width),
|
|
|
|
.height = static_cast<u32>(height),
|
|
|
|
.depth = 1,
|
|
|
|
},
|
|
|
|
};
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-08-24 21:47:49 +00:00
|
|
|
if (pixel_type.format == GPU::PixelFormat::DepthComponent) {
|
|
|
|
// FIXME: This check needs to be a bit more sophisticated. Currently the buffers are
|
|
|
|
// hardcoded. Once we add proper structures for them we need to correct this check
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
// Error because only back buffer has a depth buffer
|
|
|
|
RETURN_WITH_ERROR_IF(m_current_read_buffer == GL_FRONT
|
|
|
|
|| m_current_read_buffer == GL_FRONT_LEFT
|
|
|
|
|| m_current_read_buffer == GL_FRONT_RIGHT,
|
|
|
|
GL_INVALID_OPERATION);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-08-24 21:47:49 +00:00
|
|
|
m_rasterizer->blit_from_depth_buffer(pixels, { x, y }, output_layout);
|
|
|
|
} else if (pixel_type.format == GPU::PixelFormat::StencilIndex) {
|
|
|
|
dbgln("gl_read_pixels(): GL_STENCIL_INDEX is not yet supported");
|
|
|
|
} else {
|
|
|
|
m_rasterizer->blit_from_color_buffer(pixels, { x, y }, output_layout);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_depth_mask(GLboolean flag)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_depth_mask, flag);
|
|
|
|
|
2022-03-09 19:56:58 +00:00
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
auto options = m_rasterizer->options();
|
|
|
|
options.enable_depth_write = (flag != GL_FALSE);
|
|
|
|
m_rasterizer->set_options(options);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_draw_pixels(GLsizei width, GLsizei height, GLenum format, GLenum type, void const* data)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_draw_pixels, width, height, format, type, data);
|
|
|
|
|
2022-08-24 21:47:49 +00:00
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
// FIXME: GL_INVALID_OPERATION is generated if format is GL_STENCIL_INDEX and there is no stencil buffer
|
|
|
|
// FIXME: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER
|
|
|
|
// target and the buffer object's data store is currently mapped.
|
|
|
|
// FIXME: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER
|
|
|
|
// target and the data would be unpacked from the buffer object such that the memory reads required would
|
|
|
|
// exceed the data store size.
|
|
|
|
// FIXME: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER
|
|
|
|
// target and data is not evenly divisible into the number of bytes needed to store in memory a datum
|
|
|
|
// indicated by type.
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-09-04 18:02:37 +00:00
|
|
|
RETURN_WITH_ERROR_IF(format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM);
|
2022-08-24 21:47:49 +00:00
|
|
|
auto pixel_type_or_error = get_validated_pixel_type(GL_NONE, GL_NONE, format, type);
|
|
|
|
RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code());
|
|
|
|
|
|
|
|
auto pixel_type = pixel_type_or_error.release_value();
|
|
|
|
GPU::ImageDataLayout input_layout = {
|
|
|
|
.pixel_type = pixel_type,
|
|
|
|
.packing = get_packing_specification(PackingType::Unpack),
|
|
|
|
.dimensions = {
|
|
|
|
.width = static_cast<u32>(width),
|
|
|
|
.height = static_cast<u32>(height),
|
|
|
|
.depth = 1,
|
|
|
|
},
|
|
|
|
.selection = {
|
|
|
|
.width = static_cast<u32>(width),
|
|
|
|
.height = static_cast<u32>(height),
|
|
|
|
.depth = 1,
|
|
|
|
},
|
|
|
|
};
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-08-24 21:47:49 +00:00
|
|
|
if (pixel_type.format == GPU::PixelFormat::DepthComponent) {
|
|
|
|
m_rasterizer->blit_to_depth_buffer_at_raster_position(data, input_layout);
|
|
|
|
} else if (pixel_type.format == GPU::PixelFormat::StencilIndex) {
|
|
|
|
dbgln("gl_draw_pixels(): GL_STENCIL_INDEX is not yet supported");
|
2022-05-01 00:30:32 +00:00
|
|
|
} else {
|
2022-08-24 21:47:49 +00:00
|
|
|
m_rasterizer->blit_to_color_buffer_at_raster_position(data, input_layout);
|
2022-05-01 00:30:32 +00:00
|
|
|
}
|
|
|
|
}
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_depth_range(GLdouble min, GLdouble max)
|
|
|
|
{
|
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_depth_range, min, max);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
auto options = m_rasterizer->options();
|
|
|
|
options.depth_min = clamp<float>(min, 0.f, 1.f);
|
|
|
|
options.depth_max = clamp<float>(max, 0.f, 1.f);
|
|
|
|
m_rasterizer->set_options(options);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_depth_func(GLenum func)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_depth_func, func);
|
|
|
|
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(!(func == GL_NEVER
|
|
|
|
|| func == GL_LESS
|
|
|
|
|| func == GL_EQUAL
|
|
|
|
|| func == GL_LEQUAL
|
|
|
|
|| func == GL_GREATER
|
|
|
|
|| func == GL_NOTEQUAL
|
|
|
|
|| func == GL_GEQUAL
|
|
|
|
|| func == GL_ALWAYS),
|
|
|
|
GL_INVALID_ENUM);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-03-27 14:49:15 +00:00
|
|
|
auto options = m_rasterizer->options();
|
2022-05-01 00:30:32 +00:00
|
|
|
|
|
|
|
switch (func) {
|
|
|
|
case GL_NEVER:
|
|
|
|
options.depth_func = GPU::DepthTestFunction::Never;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_ALWAYS:
|
|
|
|
options.depth_func = GPU::DepthTestFunction::Always;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_LESS:
|
|
|
|
options.depth_func = GPU::DepthTestFunction::Less;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_LEQUAL:
|
|
|
|
options.depth_func = GPU::DepthTestFunction::LessOrEqual;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_EQUAL:
|
|
|
|
options.depth_func = GPU::DepthTestFunction::Equal;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_NOTEQUAL:
|
|
|
|
options.depth_func = GPU::DepthTestFunction::NotEqual;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_GEQUAL:
|
|
|
|
options.depth_func = GPU::DepthTestFunction::GreaterOrEqual;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_GREATER:
|
|
|
|
options.depth_func = GPU::DepthTestFunction::Greater;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
m_rasterizer->set_options(options);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-03-27 14:49:15 +00:00
|
|
|
auto options = m_rasterizer->options();
|
2022-09-13 08:33:31 +00:00
|
|
|
options.color_mask = (red == GL_TRUE ? 0xff : 0)
|
|
|
|
| (green == GL_TRUE ? 0xff00 : 0)
|
|
|
|
| (blue == GL_TRUE ? 0xff0000 : 0)
|
|
|
|
| (alpha == GL_TRUE ? 0xff000000 : 0);
|
2022-05-01 00:30:32 +00:00
|
|
|
m_rasterizer->set_options(options);
|
|
|
|
}
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_polygon_mode(GLenum face, GLenum mode)
|
|
|
|
{
|
|
|
|
RETURN_WITH_ERROR_IF(!(face == GL_BACK || face == GL_FRONT || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM);
|
|
|
|
RETURN_WITH_ERROR_IF(!(mode == GL_POINT || mode == GL_LINE || mode == GL_FILL), GL_INVALID_ENUM);
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
auto options = m_rasterizer->options();
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
// FIXME: This must support different polygon modes for front- and backside
|
|
|
|
if (face == GL_BACK) {
|
|
|
|
dbgln_if(GL_DEBUG, "gl_polygon_mode(GL_BACK, {:#x}): unimplemented", mode);
|
2022-03-09 19:56:58 +00:00
|
|
|
return;
|
2022-05-01 00:30:32 +00:00
|
|
|
}
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
auto map_mode = [](GLenum mode) -> GPU::PolygonMode {
|
|
|
|
switch (mode) {
|
|
|
|
case GL_FILL:
|
|
|
|
return GPU::PolygonMode::Fill;
|
|
|
|
case GL_LINE:
|
|
|
|
return GPU::PolygonMode::Line;
|
|
|
|
case GL_POINT:
|
|
|
|
return GPU::PolygonMode::Point;
|
|
|
|
default:
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
}
|
2022-03-09 19:56:58 +00:00
|
|
|
};
|
2022-05-01 00:30:32 +00:00
|
|
|
|
|
|
|
options.polygon_mode = map_mode(mode);
|
|
|
|
m_rasterizer->set_options(options);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_polygon_offset(GLfloat factor, GLfloat units)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_polygon_offset, factor, units);
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
auto rasterizer_options = m_rasterizer->options();
|
|
|
|
rasterizer_options.depth_offset_factor = factor;
|
|
|
|
rasterizer_options.depth_offset_constant = units;
|
|
|
|
m_rasterizer->set_options(rasterizer_options);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-09-01 11:27:11 +00:00
|
|
|
void GLContext::gl_fogfv(GLenum pname, GLfloat const* params)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_fogfv, pname, params);
|
2022-03-09 19:56:58 +00:00
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
auto options = m_rasterizer->options();
|
2022-03-09 19:56:58 +00:00
|
|
|
|
|
|
|
switch (pname) {
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_FOG_COLOR:
|
|
|
|
options.fog_color = { params[0], params[1], params[2], params[3] };
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
|
|
|
default:
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
m_rasterizer->set_options(options);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_fogf(GLenum pname, GLfloat param)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_fogf, pname, param);
|
2022-03-09 19:56:58 +00:00
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(param < 0.0f, GL_INVALID_VALUE);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
auto options = m_rasterizer->options();
|
2022-03-09 19:56:58 +00:00
|
|
|
|
|
|
|
switch (pname) {
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_FOG_DENSITY:
|
|
|
|
options.fog_density = param;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_FOG_END:
|
|
|
|
options.fog_end = param;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_FOG_START:
|
|
|
|
options.fog_start = param;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
|
|
|
default:
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
m_rasterizer->set_options(options);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_fogi(GLenum pname, GLint param)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_fogi, pname, param);
|
2022-03-09 19:56:58 +00:00
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(param != GL_LINEAR && param != GL_EXP && param != GL_EXP2, GL_INVALID_ENUM);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
auto options = m_rasterizer->options();
|
2022-03-09 19:56:58 +00:00
|
|
|
|
|
|
|
switch (pname) {
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_FOG_MODE:
|
|
|
|
switch (param) {
|
|
|
|
case GL_LINEAR:
|
|
|
|
options.fog_mode = GPU::FogMode::Linear;
|
|
|
|
break;
|
|
|
|
case GL_EXP:
|
|
|
|
options.fog_mode = GPU::FogMode::Exp;
|
|
|
|
break;
|
|
|
|
case GL_EXP2:
|
|
|
|
options.fog_mode = GPU::FogMode::Exp2;
|
|
|
|
break;
|
|
|
|
}
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
|
|
|
default:
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
m_rasterizer->set_options(options);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_pixel_storei(GLenum pname, GLint param)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-10-16 18:26:16 +00:00
|
|
|
auto const is_packing_parameter = (pname >= GL_PACK_SWAP_BYTES && pname <= GL_PACK_ALIGNMENT)
|
|
|
|
|| pname == GL_PACK_SKIP_IMAGES
|
|
|
|
|| pname == GL_PACK_IMAGE_HEIGHT;
|
|
|
|
auto& pixel_parameters = is_packing_parameter ? m_packing_parameters : m_unpacking_parameters;
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
switch (pname) {
|
|
|
|
case GL_PACK_ALIGNMENT:
|
2022-10-16 18:26:16 +00:00
|
|
|
case GL_UNPACK_ALIGNMENT:
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(param != 1 && param != 2 && param != 4 && param != 8, GL_INVALID_VALUE);
|
2022-10-16 18:26:16 +00:00
|
|
|
pixel_parameters.pack_alignment = param;
|
|
|
|
break;
|
|
|
|
case GL_PACK_IMAGE_HEIGHT:
|
|
|
|
case GL_UNPACK_IMAGE_HEIGHT:
|
|
|
|
RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE);
|
|
|
|
pixel_parameters.image_height = param;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-10-16 18:26:16 +00:00
|
|
|
case GL_PACK_LSB_FIRST:
|
|
|
|
case GL_UNPACK_LSB_FIRST:
|
|
|
|
pixel_parameters.least_significant_bit_first = (param != 0);
|
|
|
|
break;
|
|
|
|
case GL_PACK_ROW_LENGTH:
|
2022-05-01 00:30:32 +00:00
|
|
|
case GL_UNPACK_ROW_LENGTH:
|
|
|
|
RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE);
|
2022-10-16 18:26:16 +00:00
|
|
|
pixel_parameters.row_length = param;
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
2022-10-16 18:26:16 +00:00
|
|
|
case GL_PACK_SKIP_IMAGES:
|
|
|
|
case GL_UNPACK_SKIP_IMAGES:
|
|
|
|
RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE);
|
|
|
|
pixel_parameters.skip_images = param;
|
|
|
|
break;
|
|
|
|
case GL_PACK_SKIP_PIXELS:
|
|
|
|
case GL_UNPACK_SKIP_PIXELS:
|
|
|
|
RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE);
|
|
|
|
pixel_parameters.skip_pixels = param;
|
|
|
|
break;
|
|
|
|
case GL_PACK_SKIP_ROWS:
|
|
|
|
case GL_UNPACK_SKIP_ROWS:
|
|
|
|
RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE);
|
|
|
|
pixel_parameters.skip_rows = param;
|
|
|
|
break;
|
|
|
|
case GL_PACK_SWAP_BYTES:
|
|
|
|
case GL_UNPACK_SWAP_BYTES:
|
|
|
|
pixel_parameters.swap_bytes = (param != 0);
|
2022-03-09 19:56:58 +00:00
|
|
|
break;
|
|
|
|
default:
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_scissor(GLint x, GLint y, GLsizei width, GLsizei height)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_scissor, x, y, width, height);
|
|
|
|
RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
auto options = m_rasterizer->options();
|
|
|
|
options.scissor_box = { x, y, width, height };
|
|
|
|
m_rasterizer->set_options(options);
|
|
|
|
}
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_raster_pos(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
|
|
|
|
{
|
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_raster_pos, x, y, z, w);
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
|
2022-09-04 22:40:27 +00:00
|
|
|
m_rasterizer->set_raster_position({ x, y, z, w }, model_view_matrix(), projection_matrix());
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_line_width(GLfloat width)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_line_width, width);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
RETURN_WITH_ERROR_IF(width <= 0, GL_INVALID_VALUE);
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
m_line_width = width;
|
2022-05-07 23:46:46 +00:00
|
|
|
auto options = m_rasterizer->options();
|
|
|
|
options.line_width = width;
|
|
|
|
m_rasterizer->set_options(options);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_push_attrib(GLbitfield mask)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_push_attrib, mask);
|
2022-03-09 19:56:58 +00:00
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
// FIXME: implement
|
|
|
|
dbgln_if(GL_DEBUG, "GLContext FIXME: implement gl_push_attrib({})", mask);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_pop_attrib()
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_pop_attrib);
|
2022-03-09 19:56:58 +00:00
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
// FIXME: implement
|
|
|
|
dbgln_if(GL_DEBUG, "GLContext FIXME: implement gl_pop_attrib()");
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_bitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, GLubyte const* bitmap)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_bitmap, width, height, xorig, yorig, xmove, ymove, bitmap);
|
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
|
|
|
|
if (bitmap != nullptr) {
|
|
|
|
// FIXME: implement
|
|
|
|
dbgln_if(GL_DEBUG, "gl_bitmap({}, {}, {}, {}, {}, {}, {}): unimplemented", width, height, xorig, yorig, xmove, ymove, bitmap);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
2022-05-01 00:30:32 +00:00
|
|
|
|
|
|
|
auto raster_position = m_rasterizer->raster_position();
|
|
|
|
raster_position.window_coordinates += { xmove, ymove, 0.f, 0.f };
|
|
|
|
m_rasterizer->set_raster_position(raster_position);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::gl_rect(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_rect, x1, y1, x2, y2);
|
2022-03-09 19:56:58 +00:00
|
|
|
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
gl_begin(GL_POLYGON);
|
|
|
|
gl_vertex(x1, y1, 0.0, 1.0);
|
|
|
|
gl_vertex(x2, y1, 0.0, 1.0);
|
|
|
|
gl_vertex(x2, y2, 0.0, 1.0);
|
|
|
|
gl_vertex(x1, y2, 0.0, 1.0);
|
|
|
|
gl_end();
|
|
|
|
}
|
2022-03-09 19:56:58 +00:00
|
|
|
|
2022-05-07 23:41:30 +00:00
|
|
|
void GLContext::gl_point_size(GLfloat size)
|
|
|
|
{
|
|
|
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_point_size, size);
|
|
|
|
RETURN_WITH_ERROR_IF(size <= 0.f, GL_INVALID_VALUE);
|
|
|
|
|
|
|
|
m_point_size = size;
|
|
|
|
|
|
|
|
auto rasterizer_options = m_rasterizer->options();
|
|
|
|
rasterizer_options.point_size = size;
|
|
|
|
m_rasterizer->set_options(rasterizer_options);
|
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::present()
|
|
|
|
{
|
2022-09-04 17:56:00 +00:00
|
|
|
m_rasterizer->blit_from_color_buffer(*m_frontbuffer);
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
void GLContext::sync_device_config()
|
2022-03-09 19:56:58 +00:00
|
|
|
{
|
2022-05-01 00:30:32 +00:00
|
|
|
sync_device_sampler_config();
|
2022-09-04 22:40:27 +00:00
|
|
|
sync_device_texture_units();
|
2022-05-01 00:30:32 +00:00
|
|
|
sync_light_state();
|
|
|
|
sync_stencil_configuration();
|
2022-05-06 09:40:55 +00:00
|
|
|
sync_clip_planes();
|
2022-03-09 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
2023-01-30 15:08:50 +00:00
|
|
|
ErrorOr<ByteBuffer> GLContext::build_extension_string()
|
2022-03-25 11:50:36 +00:00
|
|
|
{
|
2023-01-30 15:08:50 +00:00
|
|
|
Vector<StringView, 6> extensions;
|
2022-03-25 11:50:36 +00:00
|
|
|
|
2022-05-01 00:30:32 +00:00
|
|
|
// FIXME: npot texture support became a required core feature starting with OpenGL 2.0 (https://www.khronos.org/opengl/wiki/NPOT_Texture)
|
|
|
|
// Ideally we would verify if the selected device adheres to the requested OpenGL context version before context creation
|
|
|
|
// and refuse to create a context if it doesn't.
|
|
|
|
if (m_device_info.supports_npot_textures)
|
2023-01-30 15:08:50 +00:00
|
|
|
TRY(extensions.try_append("GL_ARB_texture_non_power_of_two"sv));
|
2022-05-01 00:30:32 +00:00
|
|
|
|
|
|
|
if (m_device_info.num_texture_units > 1)
|
2023-01-30 15:08:50 +00:00
|
|
|
TRY(extensions.try_append("GL_ARB_multitexture"sv));
|
2022-05-01 00:30:32 +00:00
|
|
|
|
2022-09-09 12:41:07 +00:00
|
|
|
if (m_device_info.supports_texture_clamp_to_edge)
|
2023-01-30 15:08:50 +00:00
|
|
|
TRY(extensions.try_append("GL_EXT_texture_edge_clamp"sv));
|
2022-09-09 12:41:07 +00:00
|
|
|
|
2022-08-28 22:10:04 +00:00
|
|
|
if (m_device_info.supports_texture_env_add) {
|
2023-01-30 15:08:50 +00:00
|
|
|
TRY(extensions.try_append("GL_ARB_texture_env_add"sv));
|
|
|
|
TRY(extensions.try_append("GL_EXT_texture_env_add"sv));
|
2022-08-28 22:10:04 +00:00
|
|
|
}
|
|
|
|
|
2022-09-04 14:53:23 +00:00
|
|
|
if (m_device_info.max_texture_lod_bias > 0.f)
|
2023-01-30 15:08:50 +00:00
|
|
|
TRY(extensions.try_append("GL_EXT_texture_lod_bias"sv));
|
2022-09-04 14:53:23 +00:00
|
|
|
|
2023-01-30 15:08:50 +00:00
|
|
|
StringBuilder string_builder {};
|
|
|
|
TRY(string_builder.try_join(' ', extensions));
|
|
|
|
|
|
|
|
// Create null-terminated string
|
2023-03-09 15:00:14 +00:00
|
|
|
auto extensions_bytes = TRY(string_builder.to_byte_buffer());
|
2023-01-30 15:08:50 +00:00
|
|
|
TRY(extensions_bytes.try_append(0));
|
|
|
|
return extensions_bytes;
|
2022-03-25 11:50:36 +00:00
|
|
|
}
|
|
|
|
|
2022-09-16 11:58:30 +00:00
|
|
|
ErrorOr<NonnullOwnPtr<GLContext>> create_context(Gfx::Bitmap& bitmap)
|
2021-01-06 11:58:01 +00:00
|
|
|
{
|
2022-03-27 16:54:31 +00:00
|
|
|
// FIXME: Make driver selectable. This is currently hardcoded to LibSoftGPU
|
2022-09-16 11:58:30 +00:00
|
|
|
auto driver = TRY(GPU::Driver::try_create("softgpu"sv));
|
|
|
|
auto device = TRY(driver->try_create_device(bitmap.size()));
|
2022-03-27 16:54:31 +00:00
|
|
|
auto context = make<GLContext>(driver, move(device), bitmap);
|
2022-01-12 15:39:59 +00:00
|
|
|
dbgln_if(GL_DEBUG, "GL::create_context({}) -> {:p}", bitmap.size(), context.ptr());
|
2021-01-06 11:58:01 +00:00
|
|
|
|
|
|
|
if (!g_gl_context)
|
2022-01-12 15:39:59 +00:00
|
|
|
make_context_current(context);
|
2021-01-06 11:58:01 +00:00
|
|
|
|
|
|
|
return context;
|
|
|
|
}
|
|
|
|
|
|
|
|
void make_context_current(GLContext* context)
|
|
|
|
{
|
2022-01-12 15:39:59 +00:00
|
|
|
if (g_gl_context == context)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dbgln_if(GL_DEBUG, "GL::make_context_current({:p})", context);
|
2021-01-06 11:58:01 +00:00
|
|
|
g_gl_context = context;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|