Serenity Operating System
at master 983 lines 35 kB view raw
1/* 2 * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com> 3 * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org> 4 * Copyright (c) 2022-2023, Jelle Raaijmakers <jelle@gmta.nl> 5 * 6 * SPDX-License-Identifier: BSD-2-Clause 7 */ 8 9#include <AK/Debug.h> 10#include <AK/StringBuilder.h> 11#include <AK/Vector.h> 12#include <LibGL/GLContext.h> 13#include <LibGL/Image.h> 14#include <LibGPU/Device.h> 15#include <LibGPU/Enums.h> 16#include <LibGPU/ImageDataLayout.h> 17#include <LibGPU/ImageFormat.h> 18#include <LibGfx/Bitmap.h> 19 20__attribute__((visibility("hidden"))) GL::GLContext* g_gl_context; 21 22namespace GL { 23 24GLContext::GLContext(RefPtr<GPU::Driver> driver, NonnullOwnPtr<GPU::Device> device, Gfx::Bitmap& frontbuffer) 25 : m_driver { driver } 26 , m_rasterizer { move(device) } 27 , m_device_info { m_rasterizer->info() } 28 , m_viewport { frontbuffer.rect() } 29 , m_frontbuffer { frontbuffer } 30{ 31 m_texture_units.resize(m_device_info.num_texture_units); 32 m_active_texture_unit = &m_texture_units[0]; 33 34 // All texture units are initialized with default textures for all targets; these 35 // can be referenced later on with texture name 0 in operations like glBindTexture(). 36 auto default_texture_2d = adopt_ref(*new Texture2D()); 37 m_default_textures.set(GL_TEXTURE_2D, default_texture_2d); 38 for (auto& texture_unit : m_texture_units) 39 texture_unit.set_texture_2d_target_texture(default_texture_2d); 40 41 // Query the number lights from the device and set set up their state 42 // locally in the GL 43 m_light_states.resize(m_device_info.num_lights); 44 45 // Set-up light0's state, as it has a different default state 46 // to the other lights, as per the OpenGL 1.5 spec 47 auto& light0 = m_light_states.at(0); 48 light0.diffuse_intensity = { 1.0f, 1.0f, 1.0f, 1.0f }; 49 light0.specular_intensity = { 1.0f, 1.0f, 1.0f, 1.0f }; 50 m_light_state_is_dirty = true; 51 52 m_client_side_texture_coord_array_enabled.resize(m_device_info.num_texture_units); 53 m_client_tex_coord_pointer.resize(m_device_info.num_texture_units); 54 m_current_vertex_tex_coord.resize(m_device_info.num_texture_units); 55 for (auto& tex_coord : m_current_vertex_tex_coord) 56 tex_coord = { 0.0f, 0.0f, 0.0f, 1.0f }; 57 58 // Initialize the texture coordinate generation coefficients 59 // Indices 0,1,2,3 refer to the S,T,R and Q coordinate of the respective texture 60 // coordinate generation config. 61 m_texture_coordinate_generation.resize(m_device_info.num_texture_units); 62 for (auto& texture_coordinate_generation : m_texture_coordinate_generation) { 63 texture_coordinate_generation[0].object_plane_coefficients = { 1.f, 0.f, 0.f, 0.f }; 64 texture_coordinate_generation[0].eye_plane_coefficients = { 1.f, 0.f, 0.f, 0.f }; 65 texture_coordinate_generation[1].object_plane_coefficients = { 0.f, 1.f, 0.f, 0.f }; 66 texture_coordinate_generation[1].eye_plane_coefficients = { 0.f, 1.f, 0.f, 0.f }; 67 texture_coordinate_generation[2].object_plane_coefficients = { 0.f, 0.f, 0.f, 0.f }; 68 texture_coordinate_generation[2].eye_plane_coefficients = { 0.f, 0.f, 0.f, 0.f }; 69 texture_coordinate_generation[3].object_plane_coefficients = { 0.f, 0.f, 0.f, 0.f }; 70 texture_coordinate_generation[3].eye_plane_coefficients = { 0.f, 0.f, 0.f, 0.f }; 71 } 72 73 m_extensions = build_extension_string().release_value_but_fixme_should_propagate_errors(); 74} 75 76GLContext::~GLContext() 77{ 78 dbgln_if(GL_DEBUG, "GLContext::~GLContext() {:p}", this); 79 if (g_gl_context == this) 80 make_context_current(nullptr); 81} 82 83void GLContext::gl_begin(GLenum mode) 84{ 85 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_begin, mode); 86 87 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 88 RETURN_WITH_ERROR_IF(mode > GL_POLYGON, GL_INVALID_ENUM); 89 90 m_current_draw_mode = mode; 91 m_in_draw_state = true; // Certain commands will now generate an error 92} 93 94void GLContext::gl_clear(GLbitfield mask) 95{ 96 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear, mask); 97 98 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 99 RETURN_WITH_ERROR_IF(mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT), GL_INVALID_ENUM); 100 101 if (mask & GL_COLOR_BUFFER_BIT) 102 m_rasterizer->clear_color(m_clear_color); 103 104 if (mask & GL_DEPTH_BUFFER_BIT) 105 m_rasterizer->clear_depth(m_clear_depth); 106 107 if (mask & GL_STENCIL_BUFFER_BIT) 108 m_rasterizer->clear_stencil(m_clear_stencil); 109} 110 111void GLContext::gl_clear_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) 112{ 113 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear_color, red, green, blue, alpha); 114 115 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 116 117 m_clear_color = { red, green, blue, alpha }; 118 m_clear_color.clamp(0.f, 1.f); 119} 120 121void GLContext::gl_clear_depth(GLfloat depth) 122{ 123 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear_depth, depth); 124 125 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 126 127 m_clear_depth = clamp(depth, 0.f, 1.f); 128} 129 130void GLContext::gl_end() 131{ 132 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_end); 133 134 // Make sure we had a `glBegin` before this call... 135 RETURN_WITH_ERROR_IF(!m_in_draw_state, GL_INVALID_OPERATION); 136 m_in_draw_state = false; 137 138 sync_device_config(); 139 140 GPU::PrimitiveType primitive_type; 141 switch (m_current_draw_mode) { 142 case GL_LINE_LOOP: 143 primitive_type = GPU::PrimitiveType::LineLoop; 144 break; 145 case GL_LINE_STRIP: 146 primitive_type = GPU::PrimitiveType::LineStrip; 147 break; 148 case GL_LINES: 149 primitive_type = GPU::PrimitiveType::Lines; 150 break; 151 case GL_POINTS: 152 primitive_type = GPU::PrimitiveType::Points; 153 break; 154 case GL_TRIANGLES: 155 primitive_type = GPU::PrimitiveType::Triangles; 156 break; 157 case GL_TRIANGLE_STRIP: 158 case GL_QUAD_STRIP: 159 primitive_type = GPU::PrimitiveType::TriangleStrip; 160 break; 161 case GL_TRIANGLE_FAN: 162 case GL_POLYGON: 163 primitive_type = GPU::PrimitiveType::TriangleFan; 164 break; 165 case GL_QUADS: 166 primitive_type = GPU::PrimitiveType::Quads; 167 break; 168 default: 169 VERIFY_NOT_REACHED(); 170 } 171 172 m_rasterizer->draw_primitives(primitive_type, model_view_matrix(), projection_matrix(), m_vertex_list); 173 m_vertex_list.clear_with_capacity(); 174} 175 176GLenum GLContext::gl_get_error() 177{ 178 if (m_in_draw_state) 179 return GL_INVALID_OPERATION; 180 181 auto last_error = m_error; 182 m_error = GL_NO_ERROR; 183 return last_error; 184} 185 186GLubyte const* GLContext::gl_get_string(GLenum name) 187{ 188 RETURN_VALUE_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION, nullptr); 189 190 switch (name) { 191 case GL_VENDOR: 192 return reinterpret_cast<GLubyte const*>(m_device_info.vendor_name.characters()); 193 case GL_RENDERER: 194 return reinterpret_cast<GLubyte const*>(m_device_info.device_name.characters()); 195 case GL_VERSION: 196 return reinterpret_cast<GLubyte const*>("1.5"); 197 case GL_EXTENSIONS: 198 return reinterpret_cast<GLubyte const*>(m_extensions.data()); 199 case GL_SHADING_LANGUAGE_VERSION: 200 return reinterpret_cast<GLubyte const*>("0.0"); 201 default: 202 dbgln_if(GL_DEBUG, "gl_get_string({:#x}): unknown name", name); 203 break; 204 } 205 206 RETURN_VALUE_WITH_ERROR_IF(true, GL_INVALID_ENUM, nullptr); 207} 208 209void GLContext::gl_viewport(GLint x, GLint y, GLsizei width, GLsizei height) 210{ 211 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_viewport, x, y, width, height); 212 213 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 214 RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE); 215 216 m_viewport = { x, y, width, height }; 217 218 auto rasterizer_options = m_rasterizer->options(); 219 rasterizer_options.viewport = m_viewport; 220 m_rasterizer->set_options(rasterizer_options); 221} 222 223void GLContext::gl_front_face(GLenum face) 224{ 225 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_front_face, face); 226 227 RETURN_WITH_ERROR_IF(face < GL_CW || face > GL_CCW, GL_INVALID_ENUM); 228 229 m_front_face = face; 230 231 auto rasterizer_options = m_rasterizer->options(); 232 rasterizer_options.front_face = (face == GL_CW) ? GPU::WindingOrder::Clockwise : GPU::WindingOrder::CounterClockwise; 233 m_rasterizer->set_options(rasterizer_options); 234} 235 236void GLContext::gl_cull_face(GLenum cull_mode) 237{ 238 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_cull_face, cull_mode); 239 240 RETURN_WITH_ERROR_IF(cull_mode != GL_FRONT && cull_mode != GL_BACK && cull_mode != GL_FRONT_AND_BACK, GL_INVALID_ENUM); 241 242 m_culled_sides = cull_mode; 243 244 auto rasterizer_options = m_rasterizer->options(); 245 rasterizer_options.cull_back = cull_mode == GL_BACK || cull_mode == GL_FRONT_AND_BACK; 246 rasterizer_options.cull_front = cull_mode == GL_FRONT || cull_mode == GL_FRONT_AND_BACK; 247 m_rasterizer->set_options(rasterizer_options); 248} 249 250void GLContext::gl_flush() 251{ 252 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 253 254 // No-op since GLContext is completely synchronous at the moment 255} 256 257void GLContext::gl_finish() 258{ 259 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 260 261 // No-op since GLContext is completely synchronous at the moment 262} 263 264void GLContext::gl_blend_func(GLenum src_factor, GLenum dst_factor) 265{ 266 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_blend_func, src_factor, dst_factor); 267 268 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 269 270 // FIXME: The list of allowed enums differs between API versions 271 // This was taken from the 2.0 spec on https://docs.gl/gl2/glBlendFunc 272 273 RETURN_WITH_ERROR_IF(!(src_factor == GL_ZERO 274 || src_factor == GL_ONE 275 || src_factor == GL_SRC_COLOR 276 || src_factor == GL_ONE_MINUS_SRC_COLOR 277 || src_factor == GL_DST_COLOR 278 || src_factor == GL_ONE_MINUS_DST_COLOR 279 || src_factor == GL_SRC_ALPHA 280 || src_factor == GL_ONE_MINUS_SRC_ALPHA 281 || src_factor == GL_DST_ALPHA 282 || src_factor == GL_ONE_MINUS_DST_ALPHA 283 || src_factor == GL_CONSTANT_COLOR 284 || src_factor == GL_ONE_MINUS_CONSTANT_COLOR 285 || src_factor == GL_CONSTANT_ALPHA 286 || src_factor == GL_ONE_MINUS_CONSTANT_ALPHA 287 || src_factor == GL_SRC_ALPHA_SATURATE), 288 GL_INVALID_ENUM); 289 290 RETURN_WITH_ERROR_IF(!(dst_factor == GL_ZERO 291 || dst_factor == GL_ONE 292 || dst_factor == GL_SRC_COLOR 293 || dst_factor == GL_ONE_MINUS_SRC_COLOR 294 || dst_factor == GL_DST_COLOR 295 || dst_factor == GL_ONE_MINUS_DST_COLOR 296 || dst_factor == GL_SRC_ALPHA 297 || dst_factor == GL_ONE_MINUS_SRC_ALPHA 298 || dst_factor == GL_DST_ALPHA 299 || dst_factor == GL_ONE_MINUS_DST_ALPHA 300 || dst_factor == GL_CONSTANT_COLOR 301 || dst_factor == GL_ONE_MINUS_CONSTANT_COLOR 302 || dst_factor == GL_CONSTANT_ALPHA 303 || dst_factor == GL_ONE_MINUS_CONSTANT_ALPHA), 304 GL_INVALID_ENUM); 305 306 m_blend_source_factor = src_factor; 307 m_blend_destination_factor = dst_factor; 308 309 auto map_gl_blend_factor_to_device = [](GLenum factor) constexpr { 310 switch (factor) { 311 case GL_ZERO: 312 return GPU::BlendFactor::Zero; 313 case GL_ONE: 314 return GPU::BlendFactor::One; 315 case GL_SRC_ALPHA: 316 return GPU::BlendFactor::SrcAlpha; 317 case GL_ONE_MINUS_SRC_ALPHA: 318 return GPU::BlendFactor::OneMinusSrcAlpha; 319 case GL_SRC_COLOR: 320 return GPU::BlendFactor::SrcColor; 321 case GL_ONE_MINUS_SRC_COLOR: 322 return GPU::BlendFactor::OneMinusSrcColor; 323 case GL_DST_ALPHA: 324 return GPU::BlendFactor::DstAlpha; 325 case GL_ONE_MINUS_DST_ALPHA: 326 return GPU::BlendFactor::OneMinusDstAlpha; 327 case GL_DST_COLOR: 328 return GPU::BlendFactor::DstColor; 329 case GL_ONE_MINUS_DST_COLOR: 330 return GPU::BlendFactor::OneMinusDstColor; 331 case GL_SRC_ALPHA_SATURATE: 332 return GPU::BlendFactor::SrcAlphaSaturate; 333 default: 334 VERIFY_NOT_REACHED(); 335 } 336 }; 337 338 auto options = m_rasterizer->options(); 339 options.blend_source_factor = map_gl_blend_factor_to_device(m_blend_source_factor); 340 options.blend_destination_factor = map_gl_blend_factor_to_device(m_blend_destination_factor); 341 m_rasterizer->set_options(options); 342} 343 344void GLContext::gl_alpha_func(GLenum func, GLclampf ref) 345{ 346 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_alpha_func, func, ref); 347 348 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 349 RETURN_WITH_ERROR_IF(func < GL_NEVER || func > GL_ALWAYS, GL_INVALID_ENUM); 350 351 m_alpha_test_func = func; 352 m_alpha_test_ref_value = ref; 353 354 auto options = m_rasterizer->options(); 355 356 switch (func) { 357 case GL_NEVER: 358 options.alpha_test_func = GPU::AlphaTestFunction::Never; 359 break; 360 case GL_ALWAYS: 361 options.alpha_test_func = GPU::AlphaTestFunction::Always; 362 break; 363 case GL_LESS: 364 options.alpha_test_func = GPU::AlphaTestFunction::Less; 365 break; 366 case GL_LEQUAL: 367 options.alpha_test_func = GPU::AlphaTestFunction::LessOrEqual; 368 break; 369 case GL_EQUAL: 370 options.alpha_test_func = GPU::AlphaTestFunction::Equal; 371 break; 372 case GL_NOTEQUAL: 373 options.alpha_test_func = GPU::AlphaTestFunction::NotEqual; 374 break; 375 case GL_GEQUAL: 376 options.alpha_test_func = GPU::AlphaTestFunction::GreaterOrEqual; 377 break; 378 case GL_GREATER: 379 options.alpha_test_func = GPU::AlphaTestFunction::Greater; 380 break; 381 default: 382 VERIFY_NOT_REACHED(); 383 } 384 385 options.alpha_test_ref_value = m_alpha_test_ref_value; 386 m_rasterizer->set_options(options); 387} 388 389void GLContext::gl_hint(GLenum target, GLenum mode) 390{ 391 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_hint, target, mode); 392 393 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 394 395 RETURN_WITH_ERROR_IF(target != GL_PERSPECTIVE_CORRECTION_HINT 396 && target != GL_POINT_SMOOTH_HINT 397 && target != GL_LINE_SMOOTH_HINT 398 && target != GL_POLYGON_SMOOTH_HINT 399 && target != GL_FOG_HINT 400 && target != GL_GENERATE_MIPMAP_HINT 401 && target != GL_TEXTURE_COMPRESSION_HINT, 402 GL_INVALID_ENUM); 403 404 RETURN_WITH_ERROR_IF(mode != GL_DONT_CARE 405 && mode != GL_FASTEST 406 && mode != GL_NICEST, 407 GL_INVALID_ENUM); 408 409 // According to the spec implementors are free to ignore glHint. So we do. 410} 411 412void GLContext::gl_read_buffer(GLenum mode) 413{ 414 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_read_buffer, mode); 415 416 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 417 418 // FIXME: Also allow aux buffers GL_AUX0 through GL_AUX3 here 419 // plus any aux buffer between 0 and GL_AUX_BUFFERS 420 RETURN_WITH_ERROR_IF(mode != GL_FRONT_LEFT 421 && mode != GL_FRONT_RIGHT 422 && mode != GL_BACK_LEFT 423 && mode != GL_BACK_RIGHT 424 && mode != GL_FRONT 425 && mode != GL_BACK 426 && mode != GL_LEFT 427 && mode != GL_RIGHT, 428 GL_INVALID_ENUM); 429 430 // FIXME: We do not currently have aux buffers, so make it an invalid 431 // operation to select anything but front or back buffers. Also we do 432 // not allow selecting the stereoscopic RIGHT buffers since we do not 433 // have them configured. 434 RETURN_WITH_ERROR_IF(mode != GL_FRONT_LEFT 435 && mode != GL_FRONT 436 && mode != GL_BACK_LEFT 437 && mode != GL_BACK 438 && mode != GL_FRONT 439 && mode != GL_BACK 440 && mode != GL_LEFT, 441 GL_INVALID_OPERATION); 442 443 m_current_read_buffer = mode; 444} 445 446void GLContext::gl_draw_buffer(GLenum buffer) 447{ 448 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_draw_buffer, buffer); 449 450 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 451 452 // FIXME: Also allow aux buffers GL_AUX0 through GL_AUX3 here 453 // plus any aux buffer between 0 and GL_AUX_BUFFERS 454 RETURN_WITH_ERROR_IF(buffer != GL_NONE 455 && buffer != GL_FRONT_LEFT 456 && buffer != GL_FRONT_RIGHT 457 && buffer != GL_BACK_LEFT 458 && buffer != GL_BACK_RIGHT 459 && buffer != GL_FRONT 460 && buffer != GL_BACK 461 && buffer != GL_LEFT 462 && buffer != GL_RIGHT, 463 GL_INVALID_ENUM); 464 465 // FIXME: We do not currently have aux buffers, so make it an invalid 466 // operation to select anything but front or back buffers. Also we do 467 // not allow selecting the stereoscopic RIGHT buffers since we do not 468 // have them configured. 469 RETURN_WITH_ERROR_IF(buffer != GL_NONE 470 && buffer != GL_FRONT_LEFT 471 && buffer != GL_FRONT 472 && buffer != GL_BACK_LEFT 473 && buffer != GL_BACK 474 && buffer != GL_FRONT 475 && buffer != GL_BACK 476 && buffer != GL_LEFT, 477 GL_INVALID_OPERATION); 478 479 m_current_draw_buffer = buffer; 480 481 auto rasterizer_options = m_rasterizer->options(); 482 // FIXME: We only have a single draw buffer in SoftGPU at the moment, 483 // so we simply disable color writes if GL_NONE is selected 484 rasterizer_options.enable_color_write = m_current_draw_buffer != GL_NONE; 485 m_rasterizer->set_options(rasterizer_options); 486} 487 488void GLContext::gl_read_pixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) 489{ 490 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 491 RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE); 492 493 RETURN_WITH_ERROR_IF(format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM); 494 auto pixel_type_or_error = get_validated_pixel_type(GL_NONE, GL_NONE, format, type); 495 RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code()); 496 497 auto pixel_type = pixel_type_or_error.release_value(); 498 GPU::ImageDataLayout output_layout = { 499 .pixel_type = pixel_type, 500 .packing = get_packing_specification(PackingType::Pack), 501 .dimensions = { 502 .width = static_cast<u32>(width), 503 .height = static_cast<u32>(height), 504 .depth = 1, 505 }, 506 .selection = { 507 .width = static_cast<u32>(width), 508 .height = static_cast<u32>(height), 509 .depth = 1, 510 }, 511 }; 512 513 if (pixel_type.format == GPU::PixelFormat::DepthComponent) { 514 // FIXME: This check needs to be a bit more sophisticated. Currently the buffers are 515 // hardcoded. Once we add proper structures for them we need to correct this check 516 517 // Error because only back buffer has a depth buffer 518 RETURN_WITH_ERROR_IF(m_current_read_buffer == GL_FRONT 519 || m_current_read_buffer == GL_FRONT_LEFT 520 || m_current_read_buffer == GL_FRONT_RIGHT, 521 GL_INVALID_OPERATION); 522 523 m_rasterizer->blit_from_depth_buffer(pixels, { x, y }, output_layout); 524 } else if (pixel_type.format == GPU::PixelFormat::StencilIndex) { 525 dbgln("gl_read_pixels(): GL_STENCIL_INDEX is not yet supported"); 526 } else { 527 m_rasterizer->blit_from_color_buffer(pixels, { x, y }, output_layout); 528 } 529} 530 531void GLContext::gl_depth_mask(GLboolean flag) 532{ 533 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_depth_mask, flag); 534 535 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 536 537 auto options = m_rasterizer->options(); 538 options.enable_depth_write = (flag != GL_FALSE); 539 m_rasterizer->set_options(options); 540} 541 542void GLContext::gl_draw_pixels(GLsizei width, GLsizei height, GLenum format, GLenum type, void const* data) 543{ 544 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_draw_pixels, width, height, format, type, data); 545 546 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 547 RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE); 548 549 // FIXME: GL_INVALID_OPERATION is generated if format is GL_STENCIL_INDEX and there is no stencil buffer 550 // FIXME: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER 551 // target and the buffer object's data store is currently mapped. 552 // FIXME: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER 553 // target and the data would be unpacked from the buffer object such that the memory reads required would 554 // exceed the data store size. 555 // FIXME: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER 556 // target and data is not evenly divisible into the number of bytes needed to store in memory a datum 557 // indicated by type. 558 559 RETURN_WITH_ERROR_IF(format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM); 560 auto pixel_type_or_error = get_validated_pixel_type(GL_NONE, GL_NONE, format, type); 561 RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code()); 562 563 auto pixel_type = pixel_type_or_error.release_value(); 564 GPU::ImageDataLayout input_layout = { 565 .pixel_type = pixel_type, 566 .packing = get_packing_specification(PackingType::Unpack), 567 .dimensions = { 568 .width = static_cast<u32>(width), 569 .height = static_cast<u32>(height), 570 .depth = 1, 571 }, 572 .selection = { 573 .width = static_cast<u32>(width), 574 .height = static_cast<u32>(height), 575 .depth = 1, 576 }, 577 }; 578 579 if (pixel_type.format == GPU::PixelFormat::DepthComponent) { 580 m_rasterizer->blit_to_depth_buffer_at_raster_position(data, input_layout); 581 } else if (pixel_type.format == GPU::PixelFormat::StencilIndex) { 582 dbgln("gl_draw_pixels(): GL_STENCIL_INDEX is not yet supported"); 583 } else { 584 m_rasterizer->blit_to_color_buffer_at_raster_position(data, input_layout); 585 } 586} 587 588void GLContext::gl_depth_range(GLdouble min, GLdouble max) 589{ 590 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_depth_range, min, max); 591 592 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 593 594 auto options = m_rasterizer->options(); 595 options.depth_min = clamp<float>(min, 0.f, 1.f); 596 options.depth_max = clamp<float>(max, 0.f, 1.f); 597 m_rasterizer->set_options(options); 598} 599 600void GLContext::gl_depth_func(GLenum func) 601{ 602 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_depth_func, func); 603 604 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 605 606 RETURN_WITH_ERROR_IF(!(func == GL_NEVER 607 || func == GL_LESS 608 || func == GL_EQUAL 609 || func == GL_LEQUAL 610 || func == GL_GREATER 611 || func == GL_NOTEQUAL 612 || func == GL_GEQUAL 613 || func == GL_ALWAYS), 614 GL_INVALID_ENUM); 615 616 auto options = m_rasterizer->options(); 617 618 switch (func) { 619 case GL_NEVER: 620 options.depth_func = GPU::DepthTestFunction::Never; 621 break; 622 case GL_ALWAYS: 623 options.depth_func = GPU::DepthTestFunction::Always; 624 break; 625 case GL_LESS: 626 options.depth_func = GPU::DepthTestFunction::Less; 627 break; 628 case GL_LEQUAL: 629 options.depth_func = GPU::DepthTestFunction::LessOrEqual; 630 break; 631 case GL_EQUAL: 632 options.depth_func = GPU::DepthTestFunction::Equal; 633 break; 634 case GL_NOTEQUAL: 635 options.depth_func = GPU::DepthTestFunction::NotEqual; 636 break; 637 case GL_GEQUAL: 638 options.depth_func = GPU::DepthTestFunction::GreaterOrEqual; 639 break; 640 case GL_GREATER: 641 options.depth_func = GPU::DepthTestFunction::Greater; 642 break; 643 default: 644 VERIFY_NOT_REACHED(); 645 } 646 647 m_rasterizer->set_options(options); 648} 649 650void GLContext::gl_color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) 651{ 652 auto options = m_rasterizer->options(); 653 options.color_mask = (red == GL_TRUE ? 0xff : 0) 654 | (green == GL_TRUE ? 0xff00 : 0) 655 | (blue == GL_TRUE ? 0xff0000 : 0) 656 | (alpha == GL_TRUE ? 0xff000000 : 0); 657 m_rasterizer->set_options(options); 658} 659 660void GLContext::gl_polygon_mode(GLenum face, GLenum mode) 661{ 662 RETURN_WITH_ERROR_IF(!(face == GL_BACK || face == GL_FRONT || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM); 663 RETURN_WITH_ERROR_IF(!(mode == GL_POINT || mode == GL_LINE || mode == GL_FILL), GL_INVALID_ENUM); 664 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 665 666 auto options = m_rasterizer->options(); 667 668 // FIXME: This must support different polygon modes for front- and backside 669 if (face == GL_BACK) { 670 dbgln_if(GL_DEBUG, "gl_polygon_mode(GL_BACK, {:#x}): unimplemented", mode); 671 return; 672 } 673 674 auto map_mode = [](GLenum mode) -> GPU::PolygonMode { 675 switch (mode) { 676 case GL_FILL: 677 return GPU::PolygonMode::Fill; 678 case GL_LINE: 679 return GPU::PolygonMode::Line; 680 case GL_POINT: 681 return GPU::PolygonMode::Point; 682 default: 683 VERIFY_NOT_REACHED(); 684 } 685 }; 686 687 options.polygon_mode = map_mode(mode); 688 m_rasterizer->set_options(options); 689} 690 691void GLContext::gl_polygon_offset(GLfloat factor, GLfloat units) 692{ 693 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_polygon_offset, factor, units); 694 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 695 696 auto rasterizer_options = m_rasterizer->options(); 697 rasterizer_options.depth_offset_factor = factor; 698 rasterizer_options.depth_offset_constant = units; 699 m_rasterizer->set_options(rasterizer_options); 700} 701 702void GLContext::gl_fogfv(GLenum pname, GLfloat const* params) 703{ 704 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_fogfv, pname, params); 705 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 706 707 auto options = m_rasterizer->options(); 708 709 switch (pname) { 710 case GL_FOG_COLOR: 711 options.fog_color = { params[0], params[1], params[2], params[3] }; 712 break; 713 default: 714 RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); 715 } 716 717 m_rasterizer->set_options(options); 718} 719 720void GLContext::gl_fogf(GLenum pname, GLfloat param) 721{ 722 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_fogf, pname, param); 723 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 724 RETURN_WITH_ERROR_IF(param < 0.0f, GL_INVALID_VALUE); 725 726 auto options = m_rasterizer->options(); 727 728 switch (pname) { 729 case GL_FOG_DENSITY: 730 options.fog_density = param; 731 break; 732 case GL_FOG_END: 733 options.fog_end = param; 734 break; 735 case GL_FOG_START: 736 options.fog_start = param; 737 break; 738 default: 739 RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); 740 } 741 742 m_rasterizer->set_options(options); 743} 744 745void GLContext::gl_fogi(GLenum pname, GLint param) 746{ 747 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_fogi, pname, param); 748 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 749 RETURN_WITH_ERROR_IF(param != GL_LINEAR && param != GL_EXP && param != GL_EXP2, GL_INVALID_ENUM); 750 751 auto options = m_rasterizer->options(); 752 753 switch (pname) { 754 case GL_FOG_MODE: 755 switch (param) { 756 case GL_LINEAR: 757 options.fog_mode = GPU::FogMode::Linear; 758 break; 759 case GL_EXP: 760 options.fog_mode = GPU::FogMode::Exp; 761 break; 762 case GL_EXP2: 763 options.fog_mode = GPU::FogMode::Exp2; 764 break; 765 } 766 break; 767 default: 768 RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); 769 } 770 771 m_rasterizer->set_options(options); 772} 773 774void GLContext::gl_pixel_storei(GLenum pname, GLint param) 775{ 776 auto const is_packing_parameter = (pname >= GL_PACK_SWAP_BYTES && pname <= GL_PACK_ALIGNMENT) 777 || pname == GL_PACK_SKIP_IMAGES 778 || pname == GL_PACK_IMAGE_HEIGHT; 779 auto& pixel_parameters = is_packing_parameter ? m_packing_parameters : m_unpacking_parameters; 780 781 switch (pname) { 782 case GL_PACK_ALIGNMENT: 783 case GL_UNPACK_ALIGNMENT: 784 RETURN_WITH_ERROR_IF(param != 1 && param != 2 && param != 4 && param != 8, GL_INVALID_VALUE); 785 pixel_parameters.pack_alignment = param; 786 break; 787 case GL_PACK_IMAGE_HEIGHT: 788 case GL_UNPACK_IMAGE_HEIGHT: 789 RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE); 790 pixel_parameters.image_height = param; 791 break; 792 case GL_PACK_LSB_FIRST: 793 case GL_UNPACK_LSB_FIRST: 794 pixel_parameters.least_significant_bit_first = (param != 0); 795 break; 796 case GL_PACK_ROW_LENGTH: 797 case GL_UNPACK_ROW_LENGTH: 798 RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE); 799 pixel_parameters.row_length = param; 800 break; 801 case GL_PACK_SKIP_IMAGES: 802 case GL_UNPACK_SKIP_IMAGES: 803 RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE); 804 pixel_parameters.skip_images = param; 805 break; 806 case GL_PACK_SKIP_PIXELS: 807 case GL_UNPACK_SKIP_PIXELS: 808 RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE); 809 pixel_parameters.skip_pixels = param; 810 break; 811 case GL_PACK_SKIP_ROWS: 812 case GL_UNPACK_SKIP_ROWS: 813 RETURN_WITH_ERROR_IF(param < 0, GL_INVALID_VALUE); 814 pixel_parameters.skip_rows = param; 815 break; 816 case GL_PACK_SWAP_BYTES: 817 case GL_UNPACK_SWAP_BYTES: 818 pixel_parameters.swap_bytes = (param != 0); 819 break; 820 default: 821 RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); 822 } 823} 824 825void GLContext::gl_scissor(GLint x, GLint y, GLsizei width, GLsizei height) 826{ 827 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_scissor, x, y, width, height); 828 RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE); 829 830 auto options = m_rasterizer->options(); 831 options.scissor_box = { x, y, width, height }; 832 m_rasterizer->set_options(options); 833} 834 835void GLContext::gl_raster_pos(GLfloat x, GLfloat y, GLfloat z, GLfloat w) 836{ 837 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_raster_pos, x, y, z, w); 838 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 839 840 m_rasterizer->set_raster_position({ x, y, z, w }, model_view_matrix(), projection_matrix()); 841} 842 843void GLContext::gl_line_width(GLfloat width) 844{ 845 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_line_width, width); 846 847 RETURN_WITH_ERROR_IF(width <= 0, GL_INVALID_VALUE); 848 849 m_line_width = width; 850 auto options = m_rasterizer->options(); 851 options.line_width = width; 852 m_rasterizer->set_options(options); 853} 854 855void GLContext::gl_push_attrib(GLbitfield mask) 856{ 857 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_push_attrib, mask); 858 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 859 860 // FIXME: implement 861 dbgln_if(GL_DEBUG, "GLContext FIXME: implement gl_push_attrib({})", mask); 862} 863 864void GLContext::gl_pop_attrib() 865{ 866 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_pop_attrib); 867 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 868 869 // FIXME: implement 870 dbgln_if(GL_DEBUG, "GLContext FIXME: implement gl_pop_attrib()"); 871} 872 873void GLContext::gl_bitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, GLubyte const* bitmap) 874{ 875 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_bitmap, width, height, xorig, yorig, xmove, ymove, bitmap); 876 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 877 878 if (bitmap != nullptr) { 879 // FIXME: implement 880 dbgln_if(GL_DEBUG, "gl_bitmap({}, {}, {}, {}, {}, {}, {}): unimplemented", width, height, xorig, yorig, xmove, ymove, bitmap); 881 } 882 883 auto raster_position = m_rasterizer->raster_position(); 884 raster_position.window_coordinates += { xmove, ymove, 0.f, 0.f }; 885 m_rasterizer->set_raster_position(raster_position); 886} 887 888void GLContext::gl_rect(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2) 889{ 890 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_rect, x1, y1, x2, y2); 891 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 892 893 gl_begin(GL_POLYGON); 894 gl_vertex(x1, y1, 0.0, 1.0); 895 gl_vertex(x2, y1, 0.0, 1.0); 896 gl_vertex(x2, y2, 0.0, 1.0); 897 gl_vertex(x1, y2, 0.0, 1.0); 898 gl_end(); 899} 900 901void GLContext::gl_point_size(GLfloat size) 902{ 903 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_point_size, size); 904 RETURN_WITH_ERROR_IF(size <= 0.f, GL_INVALID_VALUE); 905 906 m_point_size = size; 907 908 auto rasterizer_options = m_rasterizer->options(); 909 rasterizer_options.point_size = size; 910 m_rasterizer->set_options(rasterizer_options); 911} 912 913void GLContext::present() 914{ 915 m_rasterizer->blit_from_color_buffer(*m_frontbuffer); 916} 917 918void GLContext::sync_device_config() 919{ 920 sync_device_sampler_config(); 921 sync_device_texture_units(); 922 sync_light_state(); 923 sync_stencil_configuration(); 924 sync_clip_planes(); 925} 926 927ErrorOr<ByteBuffer> GLContext::build_extension_string() 928{ 929 Vector<StringView, 6> extensions; 930 931 // FIXME: npot texture support became a required core feature starting with OpenGL 2.0 (https://www.khronos.org/opengl/wiki/NPOT_Texture) 932 // Ideally we would verify if the selected device adheres to the requested OpenGL context version before context creation 933 // and refuse to create a context if it doesn't. 934 if (m_device_info.supports_npot_textures) 935 TRY(extensions.try_append("GL_ARB_texture_non_power_of_two"sv)); 936 937 if (m_device_info.num_texture_units > 1) 938 TRY(extensions.try_append("GL_ARB_multitexture"sv)); 939 940 if (m_device_info.supports_texture_clamp_to_edge) 941 TRY(extensions.try_append("GL_EXT_texture_edge_clamp"sv)); 942 943 if (m_device_info.supports_texture_env_add) { 944 TRY(extensions.try_append("GL_ARB_texture_env_add"sv)); 945 TRY(extensions.try_append("GL_EXT_texture_env_add"sv)); 946 } 947 948 if (m_device_info.max_texture_lod_bias > 0.f) 949 TRY(extensions.try_append("GL_EXT_texture_lod_bias"sv)); 950 951 StringBuilder string_builder {}; 952 TRY(string_builder.try_join(' ', extensions)); 953 954 // Create null-terminated string 955 auto extensions_bytes = TRY(string_builder.to_byte_buffer()); 956 TRY(extensions_bytes.try_append(0)); 957 return extensions_bytes; 958} 959 960ErrorOr<NonnullOwnPtr<GLContext>> create_context(Gfx::Bitmap& bitmap) 961{ 962 // FIXME: Make driver selectable. This is currently hardcoded to LibSoftGPU 963 auto driver = TRY(GPU::Driver::try_create("softgpu"sv)); 964 auto device = TRY(driver->try_create_device(bitmap.size())); 965 auto context = make<GLContext>(driver, move(device), bitmap); 966 dbgln_if(GL_DEBUG, "GL::create_context({}) -> {:p}", bitmap.size(), context.ptr()); 967 968 if (!g_gl_context) 969 make_context_current(context); 970 971 return context; 972} 973 974void make_context_current(GLContext* context) 975{ 976 if (g_gl_context == context) 977 return; 978 979 dbgln_if(GL_DEBUG, "GL::make_context_current({:p})", context); 980 g_gl_context = context; 981} 982 983}