Serenity Operating System
1/*
2 * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
3 * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org>
4 * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl>
5 *
6 * SPDX-License-Identifier: BSD-2-Clause
7 */
8
9#include <AK/Debug.h>
10#include <LibGL/GLContext.h>
11
12namespace GL {
13
14Optional<ContextParameter> GLContext::get_context_parameter(GLenum name)
15{
16 switch (name) {
17 case GL_ACTIVE_TEXTURE:
18 return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(GL_TEXTURE0 + m_active_texture_unit_index) } };
19 case GL_ALPHA_BITS:
20 return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(u8) * 8 } };
21 case GL_ALPHA_TEST:
22 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_alpha_test_enabled } };
23 case GL_BLEND:
24 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_blend_enabled } };
25 case GL_BLEND_DST:
26 case GL_BLEND_DST_ALPHA:
27 return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_blend_destination_factor) } };
28 case GL_BLEND_SRC:
29 case GL_BLEND_SRC_ALPHA:
30 return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_blend_source_factor) } };
31 case GL_BLUE_BITS:
32 return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(u8) * 8 } };
33 case GL_CLIENT_ACTIVE_TEXTURE:
34 return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(GL_TEXTURE0 + m_client_active_texture) } };
35 case GL_COLOR_CLEAR_VALUE:
36 return ContextParameter {
37 .type = GL_DOUBLE,
38 .count = 4,
39 .value = {
40 .double_list = {
41 static_cast<GLdouble>(m_clear_color.x()),
42 static_cast<GLdouble>(m_clear_color.y()),
43 static_cast<GLdouble>(m_clear_color.z()),
44 static_cast<GLdouble>(m_clear_color.w()),
45 } }
46 };
47 case GL_COLOR_MATERIAL:
48 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_color_material_enabled } };
49 case GL_COLOR_MATERIAL_FACE:
50 return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_color_material_face) } };
51 case GL_COLOR_MATERIAL_MODE:
52 return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_color_material_mode) } };
53 case GL_CURRENT_COLOR:
54 return ContextParameter {
55 .type = GL_DOUBLE,
56 .count = 4,
57 .value = {
58 .double_list = {
59 static_cast<double>(m_current_vertex_color.x()),
60 static_cast<double>(m_current_vertex_color.y()),
61 static_cast<double>(m_current_vertex_color.z()),
62 static_cast<double>(m_current_vertex_color.w()),
63 } }
64 };
65 case GL_CULL_FACE:
66 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_cull_faces } };
67 case GL_DEPTH_BITS:
68 return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(float) * 8 } };
69 case GL_DEPTH_CLEAR_VALUE:
70 return ContextParameter { .type = GL_DOUBLE, .value = { .double_value = static_cast<GLdouble>(m_clear_depth) } };
71 case GL_DEPTH_TEST:
72 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_depth_test_enabled } };
73 case GL_DITHER:
74 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_dither_enabled } };
75 case GL_DOUBLEBUFFER:
76 return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = true } };
77 case GL_FOG: {
78 auto fog_enabled = m_rasterizer->options().fog_enabled;
79 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = fog_enabled } };
80 }
81 case GL_GREEN_BITS:
82 return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(u8) * 8 } };
83 case GL_LIGHTING:
84 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_lighting_enabled } };
85 case GL_LINE_SMOOTH:
86 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_line_smooth } };
87 case GL_MAX_CLIP_PLANES:
88 return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_device_info.max_clip_planes) } };
89 case GL_MAX_LIGHTS:
90 return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_device_info.num_lights) } };
91 case GL_MAX_MODELVIEW_STACK_DEPTH:
92 return ContextParameter { .type = GL_INT, .value = { .integer_value = MODELVIEW_MATRIX_STACK_LIMIT } };
93 case GL_MAX_PROJECTION_STACK_DEPTH:
94 return ContextParameter { .type = GL_INT, .value = { .integer_value = PROJECTION_MATRIX_STACK_LIMIT } };
95 case GL_MAX_TEXTURE_LOD_BIAS:
96 return ContextParameter { .type = GL_DOUBLE, .value = { .double_value = static_cast<GLdouble>(m_device_info.max_texture_lod_bias) } };
97 case GL_MAX_TEXTURE_SIZE:
98 return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_device_info.max_texture_size) } };
99 case GL_MAX_TEXTURE_STACK_DEPTH:
100 return ContextParameter { .type = GL_INT, .value = { .integer_value = TEXTURE_MATRIX_STACK_LIMIT } };
101 case GL_MAX_TEXTURE_UNITS:
102 return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_texture_units.size()) } };
103 case GL_NORMAL_ARRAY_TYPE:
104 return ContextParameter { .type = GL_INT, .value = { .integer_value = GL_FLOAT } };
105 case GL_NORMALIZE:
106 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_normalize } };
107 case GL_PACK_ALIGNMENT:
108 return ContextParameter { .type = GL_INT, .value = { .integer_value = m_packing_parameters.pack_alignment } };
109 case GL_PACK_IMAGE_HEIGHT:
110 return ContextParameter { .type = GL_INT, .value = { .integer_value = m_packing_parameters.image_height } };
111 case GL_PACK_LSB_FIRST:
112 return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_packing_parameters.least_significant_bit_first } };
113 case GL_PACK_ROW_LENGTH:
114 return ContextParameter { .type = GL_INT, .value = { .integer_value = m_packing_parameters.row_length } };
115 case GL_PACK_SKIP_IMAGES:
116 return ContextParameter { .type = GL_INT, .value = { .integer_value = m_packing_parameters.skip_images } };
117 case GL_PACK_SKIP_PIXELS:
118 return ContextParameter { .type = GL_INT, .value = { .integer_value = m_packing_parameters.skip_pixels } };
119 case GL_PACK_SKIP_ROWS:
120 return ContextParameter { .type = GL_INT, .value = { .integer_value = m_packing_parameters.skip_rows } };
121 case GL_PACK_SWAP_BYTES:
122 return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_packing_parameters.swap_bytes } };
123 case GL_POINT_SMOOTH:
124 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_point_smooth } };
125 case GL_POINT_SIZE:
126 return ContextParameter { .type = GL_DOUBLE, .value = { .double_value = static_cast<GLdouble>(m_point_size) } };
127 case GL_POLYGON_OFFSET_FILL:
128 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_depth_offset_enabled } };
129 case GL_RED_BITS:
130 return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(u8) * 8 } };
131 case GL_SAMPLE_BUFFERS:
132 return ContextParameter { .type = GL_INT, .value = { .integer_value = 0 } };
133 case GL_SAMPLES:
134 return ContextParameter { .type = GL_INT, .value = { .integer_value = 1 } };
135 case GL_SCISSOR_BOX: {
136 auto scissor_box = m_rasterizer->options().scissor_box;
137 return ContextParameter {
138 .type = GL_INT,
139 .count = 4,
140 .value = {
141 .integer_list = {
142 scissor_box.x(),
143 scissor_box.y(),
144 scissor_box.width(),
145 scissor_box.height(),
146 } }
147 };
148 }
149 case GL_SCISSOR_TEST: {
150 auto scissor_enabled = m_rasterizer->options().scissor_enabled;
151 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = scissor_enabled } };
152 }
153 case GL_STENCIL_BITS:
154 return ContextParameter { .type = GL_INT, .value = { .integer_value = m_device_info.stencil_bits } };
155 case GL_STENCIL_CLEAR_VALUE:
156 return ContextParameter { .type = GL_INT, .value = { .integer_value = m_clear_stencil } };
157 case GL_STENCIL_TEST:
158 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_stencil_test_enabled } };
159 case GL_TEXTURE_1D:
160 return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_1d_enabled() } };
161 case GL_TEXTURE_2D:
162 return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_2d_enabled() } };
163 case GL_TEXTURE_3D:
164 return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_3d_enabled() } };
165 case GL_TEXTURE_CUBE_MAP:
166 return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_cube_map_enabled() } };
167 case GL_TEXTURE_GEN_Q:
168 case GL_TEXTURE_GEN_R:
169 case GL_TEXTURE_GEN_S:
170 case GL_TEXTURE_GEN_T: {
171 auto generation_enabled = texture_coordinate_generation(m_active_texture_unit_index, name).enabled;
172 return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = generation_enabled } };
173 }
174 case GL_UNPACK_ALIGNMENT:
175 return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpacking_parameters.pack_alignment } };
176 case GL_UNPACK_IMAGE_HEIGHT:
177 return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpacking_parameters.image_height } };
178 case GL_UNPACK_LSB_FIRST:
179 return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_unpacking_parameters.least_significant_bit_first } };
180 case GL_UNPACK_ROW_LENGTH:
181 return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpacking_parameters.row_length } };
182 case GL_UNPACK_SKIP_IMAGES:
183 return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpacking_parameters.skip_images } };
184 case GL_UNPACK_SKIP_PIXELS:
185 return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpacking_parameters.skip_pixels } };
186 case GL_UNPACK_SKIP_ROWS:
187 return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpacking_parameters.skip_rows } };
188 case GL_UNPACK_SWAP_BYTES:
189 return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_unpacking_parameters.swap_bytes } };
190 case GL_VIEWPORT:
191 return ContextParameter {
192 .type = GL_INT,
193 .count = 4,
194 .value = {
195 .integer_list = {
196 m_viewport.x(),
197 m_viewport.y(),
198 m_viewport.width(),
199 m_viewport.height(),
200 } }
201 };
202 default:
203 dbgln_if(GL_DEBUG, "get_context_parameter({:#x}): unknown context parameter", name);
204 return {};
205 }
206}
207
208void GLContext::gl_disable(GLenum capability)
209{
210 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_disable, capability);
211
212 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
213
214 auto rasterizer_options = m_rasterizer->options();
215 bool update_rasterizer_options = false;
216
217 switch (capability) {
218 case GL_CLIP_PLANE0:
219 case GL_CLIP_PLANE1:
220 case GL_CLIP_PLANE2:
221 case GL_CLIP_PLANE3:
222 case GL_CLIP_PLANE4:
223 case GL_CLIP_PLANE5: {
224 auto plane_idx = static_cast<size_t>(capability) - GL_CLIP_PLANE0;
225 m_clip_plane_attributes.enabled &= ~(1 << plane_idx);
226 m_clip_planes_dirty = true;
227 break;
228 }
229 case GL_COLOR_MATERIAL:
230 m_color_material_enabled = false;
231 break;
232 case GL_CULL_FACE:
233 m_cull_faces = false;
234 rasterizer_options.enable_culling = false;
235 update_rasterizer_options = true;
236 break;
237 case GL_DEPTH_TEST:
238 m_depth_test_enabled = false;
239 rasterizer_options.enable_depth_test = false;
240 update_rasterizer_options = true;
241 break;
242 case GL_BLEND:
243 m_blend_enabled = false;
244 rasterizer_options.enable_blending = false;
245 update_rasterizer_options = true;
246 break;
247 case GL_ALPHA_TEST:
248 m_alpha_test_enabled = false;
249 rasterizer_options.enable_alpha_test = false;
250 update_rasterizer_options = true;
251 break;
252 case GL_DITHER:
253 m_dither_enabled = false;
254 break;
255 case GL_FOG:
256 rasterizer_options.fog_enabled = false;
257 update_rasterizer_options = true;
258 break;
259 case GL_LIGHTING:
260 m_lighting_enabled = false;
261 rasterizer_options.lighting_enabled = false;
262 update_rasterizer_options = true;
263 break;
264 case GL_LIGHT0:
265 case GL_LIGHT1:
266 case GL_LIGHT2:
267 case GL_LIGHT3:
268 case GL_LIGHT4:
269 case GL_LIGHT5:
270 case GL_LIGHT6:
271 case GL_LIGHT7:
272 m_light_states.at(capability - GL_LIGHT0).is_enabled = false;
273 m_light_state_is_dirty = true;
274 break;
275 case GL_LINE_SMOOTH:
276 m_line_smooth = false;
277 rasterizer_options.line_smooth = false;
278 update_rasterizer_options = true;
279 break;
280 case GL_NORMALIZE:
281 m_normalize = false;
282 rasterizer_options.normalization_enabled = false;
283 update_rasterizer_options = true;
284 break;
285 case GL_POINT_SMOOTH:
286 m_point_smooth = false;
287 rasterizer_options.point_smooth = false;
288 update_rasterizer_options = true;
289 break;
290 case GL_POLYGON_OFFSET_FILL:
291 m_depth_offset_enabled = false;
292 rasterizer_options.depth_offset_enabled = false;
293 update_rasterizer_options = true;
294 break;
295 case GL_SCISSOR_TEST:
296 rasterizer_options.scissor_enabled = false;
297 update_rasterizer_options = true;
298 break;
299 case GL_STENCIL_TEST:
300 m_stencil_test_enabled = false;
301 rasterizer_options.enable_stencil_test = false;
302 update_rasterizer_options = true;
303 break;
304 case GL_TEXTURE_1D:
305 m_active_texture_unit->set_texture_1d_enabled(false);
306 m_sampler_config_is_dirty = true;
307 m_texture_units_dirty = true;
308 break;
309 case GL_TEXTURE_2D:
310 m_active_texture_unit->set_texture_2d_enabled(false);
311 m_sampler_config_is_dirty = true;
312 m_texture_units_dirty = true;
313 break;
314 case GL_TEXTURE_3D:
315 m_active_texture_unit->set_texture_3d_enabled(false);
316 m_sampler_config_is_dirty = true;
317 m_texture_units_dirty = true;
318 break;
319 case GL_TEXTURE_CUBE_MAP:
320 m_active_texture_unit->set_texture_cube_map_enabled(false);
321 m_sampler_config_is_dirty = true;
322 m_texture_units_dirty = true;
323 break;
324 case GL_TEXTURE_GEN_Q:
325 case GL_TEXTURE_GEN_R:
326 case GL_TEXTURE_GEN_S:
327 case GL_TEXTURE_GEN_T:
328 texture_coordinate_generation(m_active_texture_unit_index, capability).enabled = false;
329 m_texture_units_dirty = true;
330 break;
331 default:
332 dbgln_if(GL_DEBUG, "gl_disable({:#x}): unknown parameter", capability);
333 RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
334 }
335
336 if (update_rasterizer_options)
337 m_rasterizer->set_options(rasterizer_options);
338}
339
340void GLContext::gl_disable_client_state(GLenum cap)
341{
342 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
343
344 switch (cap) {
345 case GL_COLOR_ARRAY:
346 m_client_side_color_array_enabled = false;
347 break;
348 case GL_NORMAL_ARRAY:
349 m_client_side_normal_array_enabled = false;
350 break;
351 case GL_TEXTURE_COORD_ARRAY:
352 m_client_side_texture_coord_array_enabled[m_client_active_texture] = false;
353 break;
354 case GL_VERTEX_ARRAY:
355 m_client_side_vertex_array_enabled = false;
356 break;
357 default:
358 RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
359 }
360}
361
362void GLContext::gl_enable(GLenum capability)
363{
364 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_enable, capability);
365
366 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
367
368 auto rasterizer_options = m_rasterizer->options();
369 bool update_rasterizer_options = false;
370
371 switch (capability) {
372 case GL_CLIP_PLANE0:
373 case GL_CLIP_PLANE1:
374 case GL_CLIP_PLANE2:
375 case GL_CLIP_PLANE3:
376 case GL_CLIP_PLANE4:
377 case GL_CLIP_PLANE5: {
378 auto plane_idx = static_cast<size_t>(capability) - GL_CLIP_PLANE0;
379 m_clip_plane_attributes.enabled |= (1 << plane_idx);
380 m_clip_planes_dirty = true;
381 break;
382 }
383 case GL_COLOR_MATERIAL:
384 m_color_material_enabled = true;
385 break;
386 case GL_CULL_FACE:
387 m_cull_faces = true;
388 rasterizer_options.enable_culling = true;
389 update_rasterizer_options = true;
390 break;
391 case GL_DEPTH_TEST:
392 m_depth_test_enabled = true;
393 rasterizer_options.enable_depth_test = true;
394 update_rasterizer_options = true;
395 break;
396 case GL_BLEND:
397 m_blend_enabled = true;
398 rasterizer_options.enable_blending = true;
399 update_rasterizer_options = true;
400 break;
401 case GL_ALPHA_TEST:
402 m_alpha_test_enabled = true;
403 rasterizer_options.enable_alpha_test = true;
404 update_rasterizer_options = true;
405 break;
406 case GL_DITHER:
407 m_dither_enabled = true;
408 break;
409 case GL_FOG:
410 rasterizer_options.fog_enabled = true;
411 update_rasterizer_options = true;
412 break;
413 case GL_LIGHTING:
414 m_lighting_enabled = true;
415 rasterizer_options.lighting_enabled = true;
416 update_rasterizer_options = true;
417 break;
418 case GL_LIGHT0:
419 case GL_LIGHT1:
420 case GL_LIGHT2:
421 case GL_LIGHT3:
422 case GL_LIGHT4:
423 case GL_LIGHT5:
424 case GL_LIGHT6:
425 case GL_LIGHT7:
426 m_light_states.at(capability - GL_LIGHT0).is_enabled = true;
427 m_light_state_is_dirty = true;
428 break;
429 case GL_LINE_SMOOTH:
430 m_line_smooth = true;
431 rasterizer_options.line_smooth = true;
432 update_rasterizer_options = true;
433 break;
434 case GL_NORMALIZE:
435 m_normalize = true;
436 rasterizer_options.normalization_enabled = true;
437 update_rasterizer_options = true;
438 break;
439 case GL_POINT_SMOOTH:
440 m_point_smooth = true;
441 rasterizer_options.point_smooth = true;
442 update_rasterizer_options = true;
443 break;
444 case GL_POLYGON_OFFSET_FILL:
445 m_depth_offset_enabled = true;
446 rasterizer_options.depth_offset_enabled = true;
447 update_rasterizer_options = true;
448 break;
449 case GL_SCISSOR_TEST:
450 rasterizer_options.scissor_enabled = true;
451 update_rasterizer_options = true;
452 break;
453 case GL_STENCIL_TEST:
454 m_stencil_test_enabled = true;
455 rasterizer_options.enable_stencil_test = true;
456 update_rasterizer_options = true;
457 break;
458 case GL_TEXTURE_1D:
459 m_active_texture_unit->set_texture_1d_enabled(true);
460 m_sampler_config_is_dirty = true;
461 m_texture_units_dirty = true;
462 break;
463 case GL_TEXTURE_2D:
464 m_active_texture_unit->set_texture_2d_enabled(true);
465 m_sampler_config_is_dirty = true;
466 m_texture_units_dirty = true;
467 break;
468 case GL_TEXTURE_3D:
469 m_active_texture_unit->set_texture_3d_enabled(true);
470 m_sampler_config_is_dirty = true;
471 m_texture_units_dirty = true;
472 break;
473 case GL_TEXTURE_CUBE_MAP:
474 m_active_texture_unit->set_texture_cube_map_enabled(true);
475 m_sampler_config_is_dirty = true;
476 m_texture_units_dirty = true;
477 break;
478 case GL_TEXTURE_GEN_Q:
479 case GL_TEXTURE_GEN_R:
480 case GL_TEXTURE_GEN_S:
481 case GL_TEXTURE_GEN_T:
482 texture_coordinate_generation(m_active_texture_unit_index, capability).enabled = true;
483 m_texture_units_dirty = true;
484 break;
485 default:
486 dbgln_if(GL_DEBUG, "gl_enable({:#x}): unknown parameter", capability);
487 RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
488 }
489
490 if (update_rasterizer_options)
491 m_rasterizer->set_options(rasterizer_options);
492}
493
494void GLContext::gl_enable_client_state(GLenum cap)
495{
496 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
497
498 switch (cap) {
499 case GL_COLOR_ARRAY:
500 m_client_side_color_array_enabled = true;
501 break;
502 case GL_NORMAL_ARRAY:
503 m_client_side_normal_array_enabled = true;
504 break;
505 case GL_TEXTURE_COORD_ARRAY:
506 m_client_side_texture_coord_array_enabled[m_client_active_texture] = true;
507 break;
508 case GL_VERTEX_ARRAY:
509 m_client_side_vertex_array_enabled = true;
510 break;
511 default:
512 RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
513 }
514}
515
516void GLContext::gl_get_booleanv(GLenum pname, GLboolean* data)
517{
518 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
519
520 auto optional_parameter = get_context_parameter(pname);
521 RETURN_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM);
522 auto parameter = optional_parameter.release_value();
523
524 switch (parameter.type) {
525 case GL_BOOL:
526 *data = parameter.value.boolean_value ? GL_TRUE : GL_FALSE;
527 break;
528 case GL_DOUBLE:
529 *data = (parameter.value.double_value == 0.0) ? GL_FALSE : GL_TRUE;
530 break;
531 case GL_INT:
532 *data = (parameter.value.integer_value == 0) ? GL_FALSE : GL_TRUE;
533 break;
534 default:
535 VERIFY_NOT_REACHED();
536 }
537}
538
539void GLContext::gl_get_doublev(GLenum pname, GLdouble* params)
540{
541 get_floating_point(pname, params);
542}
543
544template<typename T>
545void GLContext::get_floating_point(GLenum pname, T* params)
546{
547 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
548
549 // Handle matrix retrieval first
550 auto flatten_and_assign_matrix = [¶ms](FloatMatrix4x4 const& matrix) {
551 auto elements = matrix.elements();
552 for (size_t i = 0; i < 4; ++i) {
553 for (size_t j = 0; j < 4; ++j) {
554 // Return transposed matrix since OpenGL defines them as column-major
555 params[i * 4 + j] = static_cast<T>(elements[j][i]);
556 }
557 }
558 };
559 switch (pname) {
560 case GL_MODELVIEW_MATRIX:
561 flatten_and_assign_matrix(model_view_matrix());
562 return;
563 case GL_PROJECTION_MATRIX:
564 flatten_and_assign_matrix(projection_matrix());
565 return;
566 }
567
568 // Regular parameters
569 auto optional_parameter = get_context_parameter(pname);
570 RETURN_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM);
571 auto parameter = optional_parameter.release_value();
572
573 switch (parameter.type) {
574 case GL_BOOL:
575 *params = parameter.value.boolean_value ? GL_TRUE : GL_FALSE;
576 break;
577 case GL_DOUBLE:
578 for (size_t i = 0; i < parameter.count; ++i)
579 params[i] = parameter.value.double_list[i];
580 break;
581 case GL_INT:
582 for (size_t i = 0; i < parameter.count; ++i)
583 params[i] = parameter.value.integer_list[i];
584 break;
585 default:
586 VERIFY_NOT_REACHED();
587 }
588}
589
590void GLContext::gl_get_floatv(GLenum pname, GLfloat* params)
591{
592 get_floating_point(pname, params);
593}
594
595void GLContext::gl_get_integerv(GLenum pname, GLint* data)
596{
597 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
598
599 auto optional_parameter = get_context_parameter(pname);
600 RETURN_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM);
601 auto parameter = optional_parameter.release_value();
602
603 switch (parameter.type) {
604 case GL_BOOL:
605 *data = parameter.value.boolean_value ? GL_TRUE : GL_FALSE;
606 break;
607 case GL_DOUBLE: {
608 double const int_range = static_cast<double>(NumericLimits<GLint>::max()) - NumericLimits<GLint>::min();
609 for (size_t i = 0; i < parameter.count; ++i) {
610 double const result_factor = (clamp(parameter.value.double_list[i], -1.0, 1.0) + 1.0) / 2.0;
611 data[i] = static_cast<GLint>(NumericLimits<GLint>::min() + result_factor * int_range);
612 }
613 break;
614 }
615 case GL_INT:
616 for (size_t i = 0; i < parameter.count; ++i)
617 data[i] = parameter.value.integer_list[i];
618 break;
619 default:
620 VERIFY_NOT_REACHED();
621 }
622}
623
624GLboolean GLContext::gl_is_enabled(GLenum capability)
625{
626 RETURN_VALUE_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION, 0);
627
628 auto optional_parameter = get_context_parameter(capability);
629 RETURN_VALUE_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM, 0);
630
631 auto parameter = optional_parameter.release_value();
632 RETURN_VALUE_WITH_ERROR_IF(!parameter.is_capability, GL_INVALID_ENUM, 0);
633
634 return parameter.value.boolean_value ? GL_TRUE : GL_FALSE;
635}
636
637GPU::PackingSpecification GLContext::get_packing_specification(PackingType packing_type)
638{
639 // FIXME: add support for .least_significant_bit_first, .skip_images, .skip_pixels and .skip_rows
640 auto const& pixel_parameters = (packing_type == PackingType::Pack) ? m_packing_parameters : m_unpacking_parameters;
641 return {
642 .depth_stride = static_cast<u32>(pixel_parameters.image_height),
643 .row_stride = static_cast<u32>(pixel_parameters.row_length),
644 .byte_alignment = pixel_parameters.pack_alignment,
645 .component_bytes_order = pixel_parameters.swap_bytes ? GPU::ComponentBytesOrder::Reversed : GPU::ComponentBytesOrder::Normal,
646 };
647}
648
649}