ContextParameter.cpp 24 KB

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