SoftwareGLContext.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932
  1. /*
  2. * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
  3. * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@gmx.de>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "SoftwareGLContext.h"
  8. #include "GLStruct.h"
  9. #include "SoftwareRasterizer.h"
  10. #include <AK/Assertions.h>
  11. #include <AK/Debug.h>
  12. #include <AK/Format.h>
  13. #include <AK/QuickSort.h>
  14. #include <AK/TemporaryChange.h>
  15. #include <AK/Variant.h>
  16. #include <AK/Vector.h>
  17. #include <LibGfx/Bitmap.h>
  18. #include <LibGfx/Painter.h>
  19. #include <LibGfx/Vector4.h>
  20. #include <math.h>
  21. using AK::dbgln;
  22. namespace GL {
  23. // FIXME: We should set this up when we create the context!
  24. static constexpr size_t MATRIX_STACK_LIMIT = 1024;
  25. #define APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(name, ...) \
  26. if (should_append_to_listing()) { \
  27. append_to_listing<&SoftwareGLContext::name>(__VA_ARGS__); \
  28. if (!should_execute_after_appending_to_listing()) \
  29. return; \
  30. }
  31. SoftwareGLContext::SoftwareGLContext(Gfx::Bitmap& frontbuffer)
  32. : m_frontbuffer(frontbuffer)
  33. , m_rasterizer(frontbuffer.size())
  34. {
  35. }
  36. void SoftwareGLContext::gl_begin(GLenum mode)
  37. {
  38. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_begin, mode);
  39. if (m_in_draw_state) {
  40. m_error = GL_INVALID_OPERATION;
  41. return;
  42. }
  43. if (mode < GL_TRIANGLES || mode > GL_POLYGON) {
  44. m_error = GL_INVALID_ENUM;
  45. return;
  46. }
  47. m_current_draw_mode = mode;
  48. m_in_draw_state = true; // Certain commands will now generate an error
  49. m_error = GL_NO_ERROR;
  50. }
  51. void SoftwareGLContext::gl_clear(GLbitfield mask)
  52. {
  53. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear, mask);
  54. if (m_in_draw_state) {
  55. m_error = GL_INVALID_OPERATION;
  56. return;
  57. }
  58. if (mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) {
  59. m_error = GL_INVALID_ENUM;
  60. return;
  61. }
  62. if (mask & GL_COLOR_BUFFER_BIT)
  63. m_rasterizer.clear_color(m_clear_color);
  64. if (mask & GL_DEPTH_BUFFER_BIT)
  65. m_rasterizer.clear_depth(static_cast<float>(m_clear_depth));
  66. m_error = GL_NO_ERROR;
  67. }
  68. void SoftwareGLContext::gl_clear_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
  69. {
  70. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear_color, red, green, blue, alpha);
  71. if (m_in_draw_state) {
  72. m_error = GL_INVALID_OPERATION;
  73. return;
  74. }
  75. m_clear_color = { red, green, blue, alpha };
  76. m_error = GL_NO_ERROR;
  77. }
  78. void SoftwareGLContext::gl_clear_depth(GLdouble depth)
  79. {
  80. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear_depth, depth);
  81. if (m_in_draw_state) {
  82. m_error = GL_INVALID_OPERATION;
  83. return;
  84. }
  85. m_clear_depth = depth;
  86. m_error = GL_NO_ERROR;
  87. }
  88. void SoftwareGLContext::gl_color(GLdouble r, GLdouble g, GLdouble b, GLdouble a)
  89. {
  90. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_color, r, g, b, a);
  91. m_current_vertex_color = { (float)r, (float)g, (float)b, (float)a };
  92. m_error = GL_NO_ERROR;
  93. }
  94. void SoftwareGLContext::gl_end()
  95. {
  96. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_end);
  97. // At this point, the user has effectively specified that they are done with defining the geometry
  98. // of what they want to draw. We now need to do a few things (https://www.khronos.org/opengl/wiki/Rendering_Pipeline_Overview):
  99. //
  100. // 1. Transform all of the vertices in the current vertex list into eye space by mulitplying the model-view matrix
  101. // 2. Transform all of the vertices from eye space into clip space by multiplying by the projection matrix
  102. // 3. If culling is enabled, we cull the desired faces (https://learnopengl.com/Advanced-OpenGL/Face-culling)
  103. // 4. Each element of the vertex is then divided by w to bring the positions into NDC (Normalized Device Coordinates)
  104. // 5. The vertices are sorted (for the rasteriser, how are we doing this? 3Dfx did this top to bottom in terms of vertex y co-ordinates)
  105. // 6. The vertices are then sent off to the rasteriser and drawn to the screen
  106. float scr_width = m_frontbuffer->width();
  107. float scr_height = m_frontbuffer->height();
  108. // Make sure we had a `glBegin` before this call...
  109. if (!m_in_draw_state) {
  110. m_error = GL_INVALID_OPERATION;
  111. return;
  112. }
  113. // Let's construct some triangles
  114. if (m_current_draw_mode == GL_TRIANGLES) {
  115. GLTriangle triangle;
  116. for (size_t i = 0; i < vertex_list.size(); i += 3) {
  117. triangle.vertices[0] = vertex_list.at(i);
  118. triangle.vertices[1] = vertex_list.at(i + 1);
  119. triangle.vertices[2] = vertex_list.at(i + 2);
  120. triangle_list.append(triangle);
  121. }
  122. } else if (m_current_draw_mode == GL_QUADS) {
  123. // We need to construct two triangles to form the quad
  124. GLTriangle triangle;
  125. VERIFY(vertex_list.size() % 4 == 0);
  126. for (size_t i = 0; i < vertex_list.size(); i += 4) {
  127. // Triangle 1
  128. triangle.vertices[0] = vertex_list.at(i);
  129. triangle.vertices[1] = vertex_list.at(i + 1);
  130. triangle.vertices[2] = vertex_list.at(i + 2);
  131. triangle_list.append(triangle);
  132. // Triangle 2
  133. triangle.vertices[0] = vertex_list.at(i + 2);
  134. triangle.vertices[1] = vertex_list.at(i + 3);
  135. triangle.vertices[2] = vertex_list.at(i);
  136. triangle_list.append(triangle);
  137. }
  138. } else if (m_current_draw_mode == GL_TRIANGLE_FAN) {
  139. GLTriangle triangle;
  140. triangle.vertices[0] = vertex_list.at(0); // Root vertex is always the vertex defined first
  141. for (size_t i = 1; i < vertex_list.size() - 1; i++) // This is technically `n-2` triangles. We start at index 1
  142. {
  143. triangle.vertices[1] = vertex_list.at(i);
  144. triangle.vertices[2] = vertex_list.at(i + 1);
  145. triangle_list.append(triangle);
  146. }
  147. } else if (m_current_draw_mode == GL_TRIANGLE_STRIP) {
  148. GLTriangle triangle;
  149. for (size_t i = 0; i < vertex_list.size() - 2; i++) {
  150. triangle.vertices[0] = vertex_list.at(i);
  151. triangle.vertices[1] = vertex_list.at(i + 1);
  152. triangle.vertices[2] = vertex_list.at(i + 2);
  153. triangle_list.append(triangle);
  154. }
  155. } else {
  156. m_error = GL_INVALID_ENUM;
  157. return;
  158. }
  159. // Now let's transform each triangle and send that to the GPU
  160. for (size_t i = 0; i < triangle_list.size(); i++) {
  161. GLTriangle& triangle = triangle_list.at(i);
  162. GLVertex& vertexa = triangle.vertices[0];
  163. GLVertex& vertexb = triangle.vertices[1];
  164. GLVertex& vertexc = triangle.vertices[2];
  165. FloatVector4 veca({ vertexa.x, vertexa.y, vertexa.z, 1.0f });
  166. FloatVector4 vecb({ vertexb.x, vertexb.y, vertexb.z, 1.0f });
  167. FloatVector4 vecc({ vertexc.x, vertexc.y, vertexc.z, 1.0f });
  168. // First multiply the vertex by the MODELVIEW matrix and then the PROJECTION matrix
  169. veca = m_model_view_matrix * veca;
  170. veca = m_projection_matrix * veca;
  171. vecb = m_model_view_matrix * vecb;
  172. vecb = m_projection_matrix * vecb;
  173. vecc = m_model_view_matrix * vecc;
  174. vecc = m_projection_matrix * vecc;
  175. // At this point, we're in clip space
  176. // Here's where we do the clipping. This is a really crude implementation of the
  177. // https://learnopengl.com/Getting-started/Coordinate-Systems
  178. // "Note that if only a part of a primitive e.g. a triangle is outside the clipping volume OpenGL
  179. // will reconstruct the triangle as one or more triangles to fit inside the clipping range. "
  180. //
  181. // ALL VERTICES ARE DEFINED IN A CLOCKWISE ORDER
  182. // Okay, let's do some face culling first
  183. Vector<FloatVector4> vecs;
  184. Vector<GLVertex> verts;
  185. vecs.append(veca);
  186. vecs.append(vecb);
  187. vecs.append(vecc);
  188. m_clipper.clip_triangle_against_frustum(vecs);
  189. // TODO: Copy color and UV information too!
  190. for (size_t vec_idx = 0; vec_idx < vecs.size(); vec_idx++) {
  191. FloatVector4& vec = vecs.at(vec_idx);
  192. GLVertex vertex;
  193. // Perform the perspective divide
  194. if (vec.w() != 0.0f) {
  195. vec.set_x(vec.x() / vec.w());
  196. vec.set_y(vec.y() / vec.w());
  197. vec.set_z(vec.z() / vec.w());
  198. vec.set_w(1 / vec.w());
  199. }
  200. vertex.x = vec.x();
  201. vertex.y = vec.y();
  202. vertex.z = vec.z();
  203. vertex.w = vec.w();
  204. // FIXME: This is to suppress any -Wunused errors
  205. vertex.u = 0.0f;
  206. vertex.v = 0.0f;
  207. if (vec_idx == 0) {
  208. vertex.r = vertexa.r;
  209. vertex.g = vertexa.g;
  210. vertex.b = vertexa.b;
  211. vertex.a = vertexa.a;
  212. } else if (vec_idx == 1) {
  213. vertex.r = vertexb.r;
  214. vertex.g = vertexb.g;
  215. vertex.b = vertexb.b;
  216. vertex.a = vertexb.a;
  217. } else {
  218. vertex.r = vertexc.r;
  219. vertex.g = vertexc.g;
  220. vertex.b = vertexc.b;
  221. vertex.a = vertexc.a;
  222. }
  223. vertex.x = (vec.x() + 1.0f) * (scr_width / 2.0f) + 0.0f; // TODO: 0.0f should be something!?
  224. vertex.y = scr_height - ((vec.y() + 1.0f) * (scr_height / 2.0f) + 0.0f);
  225. vertex.z = vec.z();
  226. verts.append(vertex);
  227. }
  228. if (verts.size() == 0) {
  229. continue;
  230. } else if (verts.size() == 3) {
  231. GLTriangle tri;
  232. tri.vertices[0] = verts.at(0);
  233. tri.vertices[1] = verts.at(1);
  234. tri.vertices[2] = verts.at(2);
  235. processed_triangles.append(tri);
  236. } else if (verts.size() == 4) {
  237. GLTriangle tri1;
  238. GLTriangle tri2;
  239. tri1.vertices[0] = verts.at(0);
  240. tri1.vertices[1] = verts.at(1);
  241. tri1.vertices[2] = verts.at(2);
  242. processed_triangles.append(tri1);
  243. tri2.vertices[0] = verts.at(0);
  244. tri2.vertices[1] = verts.at(2);
  245. tri2.vertices[2] = verts.at(3);
  246. processed_triangles.append(tri2);
  247. }
  248. }
  249. for (size_t i = 0; i < processed_triangles.size(); i++) {
  250. GLTriangle& triangle = processed_triangles.at(i);
  251. // Let's calculate the (signed) area of the triangle
  252. // https://cp-algorithms.com/geometry/oriented-triangle-area.html
  253. float dxAB = triangle.vertices[0].x - triangle.vertices[1].x; // A.x - B.x
  254. float dxBC = triangle.vertices[1].x - triangle.vertices[2].x; // B.X - C.x
  255. float dyAB = triangle.vertices[0].y - triangle.vertices[1].y;
  256. float dyBC = triangle.vertices[1].y - triangle.vertices[2].y;
  257. float area = (dxAB * dyBC) - (dxBC * dyAB);
  258. if (area == 0.0f)
  259. continue;
  260. if (m_cull_faces) {
  261. bool is_front = (m_front_face == GL_CCW ? area > 0 : area < 0);
  262. if (is_front && (m_culled_sides == GL_FRONT || m_culled_sides == GL_FRONT_AND_BACK))
  263. continue;
  264. if (!is_front && (m_culled_sides == GL_BACK || m_culled_sides == GL_FRONT_AND_BACK))
  265. continue;
  266. }
  267. m_rasterizer.submit_triangle(triangle);
  268. }
  269. triangle_list.clear();
  270. processed_triangles.clear();
  271. vertex_list.clear();
  272. m_in_draw_state = false;
  273. m_error = GL_NO_ERROR;
  274. }
  275. void SoftwareGLContext::gl_frustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val)
  276. {
  277. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_frustum, left, right, bottom, top, near_val, far_val);
  278. if (m_in_draw_state) {
  279. m_error = GL_INVALID_OPERATION;
  280. return;
  281. }
  282. // Let's do some math!
  283. // FIXME: Are we losing too much precision by doing this?
  284. float a = static_cast<float>((right + left) / (right - left));
  285. float b = static_cast<float>((top + bottom) / (top - bottom));
  286. float c = static_cast<float>(-((far_val + near_val) / (far_val - near_val)));
  287. float d = static_cast<float>(-((2 * (far_val * near_val)) / (far_val - near_val)));
  288. FloatMatrix4x4 frustum {
  289. ((2 * (float)near_val) / ((float)right - (float)left)), 0, a, 0,
  290. 0, ((2 * (float)near_val) / ((float)top - (float)bottom)), b, 0,
  291. 0, 0, c, d,
  292. 0, 0, -1, 0
  293. };
  294. if (m_current_matrix_mode == GL_PROJECTION) {
  295. m_projection_matrix = m_projection_matrix * frustum;
  296. } else if (m_current_matrix_mode == GL_MODELVIEW) {
  297. dbgln_if(GL_DEBUG, "glFrustum(): frustum created with curr_matrix_mode == GL_MODELVIEW!!!");
  298. m_projection_matrix = m_model_view_matrix * frustum;
  299. }
  300. m_error = GL_NO_ERROR;
  301. }
  302. void SoftwareGLContext::gl_ortho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val)
  303. {
  304. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_ortho, left, right, bottom, top, near_val, far_val);
  305. if (m_in_draw_state) {
  306. m_error = GL_INVALID_OPERATION;
  307. return;
  308. }
  309. if (left == right || bottom == top || near_val == far_val) {
  310. m_error = GL_INVALID_VALUE;
  311. return;
  312. }
  313. auto rl = right - left;
  314. auto tb = top - bottom;
  315. auto fn = far_val - near_val;
  316. auto tx = -(right + left) / rl;
  317. auto ty = -(top + bottom) / tb;
  318. auto tz = -(far_val + near_val) / fn;
  319. FloatMatrix4x4 projection {
  320. static_cast<float>(2 / rl), 0, 0, static_cast<float>(tx),
  321. 0, static_cast<float>(2 / tb), 0, static_cast<float>(ty),
  322. 0, 0, static_cast<float>(-2 / fn), static_cast<float>(tz),
  323. 0, 0, 0, 1
  324. };
  325. if (m_current_matrix_mode == GL_PROJECTION) {
  326. m_projection_matrix = m_projection_matrix * projection;
  327. } else if (m_current_matrix_mode == GL_MODELVIEW) {
  328. m_projection_matrix = m_model_view_matrix * projection;
  329. }
  330. m_error = GL_NO_ERROR;
  331. }
  332. GLenum SoftwareGLContext::gl_get_error()
  333. {
  334. if (m_in_draw_state) {
  335. return GL_INVALID_OPERATION;
  336. }
  337. return m_error;
  338. }
  339. GLubyte* SoftwareGLContext::gl_get_string(GLenum name)
  340. {
  341. if (m_in_draw_state) {
  342. m_error = GL_INVALID_OPERATION;
  343. return nullptr;
  344. }
  345. switch (name) {
  346. case GL_VENDOR:
  347. return reinterpret_cast<GLubyte*>(const_cast<char*>("The SerenityOS Developers"));
  348. case GL_RENDERER:
  349. return reinterpret_cast<GLubyte*>(const_cast<char*>("SerenityOS OpenGL"));
  350. case GL_VERSION:
  351. return reinterpret_cast<GLubyte*>(const_cast<char*>("OpenGL 1.2 SerenityOS"));
  352. default:
  353. dbgln_if(GL_DEBUG, "glGetString(): Unknown enum name!");
  354. break;
  355. }
  356. m_error = GL_INVALID_ENUM;
  357. return nullptr;
  358. }
  359. void SoftwareGLContext::gl_load_identity()
  360. {
  361. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_load_identity);
  362. if (m_in_draw_state) {
  363. m_error = GL_INVALID_OPERATION;
  364. return;
  365. }
  366. if (m_current_matrix_mode == GL_PROJECTION)
  367. m_projection_matrix = FloatMatrix4x4::identity();
  368. else if (m_current_matrix_mode == GL_MODELVIEW)
  369. m_model_view_matrix = FloatMatrix4x4::identity();
  370. else
  371. VERIFY_NOT_REACHED();
  372. m_error = GL_NO_ERROR;
  373. }
  374. void SoftwareGLContext::gl_load_matrix(const FloatMatrix4x4& matrix)
  375. {
  376. if (should_append_to_listing()) {
  377. auto ptr = store_in_listing(matrix);
  378. append_to_listing<&SoftwareGLContext::gl_load_matrix>(*ptr);
  379. if (!should_execute_after_appending_to_listing())
  380. return;
  381. }
  382. if (m_in_draw_state) {
  383. m_error = GL_INVALID_OPERATION;
  384. return;
  385. }
  386. if (m_current_matrix_mode == GL_PROJECTION)
  387. m_projection_matrix = matrix;
  388. else if (m_current_matrix_mode == GL_MODELVIEW)
  389. m_model_view_matrix = matrix;
  390. else
  391. VERIFY_NOT_REACHED();
  392. m_error = GL_NO_ERROR;
  393. }
  394. void SoftwareGLContext::gl_matrix_mode(GLenum mode)
  395. {
  396. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_matrix_mode, mode);
  397. if (m_in_draw_state) {
  398. m_error = GL_INVALID_OPERATION;
  399. return;
  400. }
  401. if (mode < GL_MODELVIEW || mode > GL_PROJECTION) {
  402. m_error = GL_INVALID_ENUM;
  403. return;
  404. }
  405. m_current_matrix_mode = mode;
  406. m_error = GL_NO_ERROR;
  407. }
  408. void SoftwareGLContext::gl_push_matrix()
  409. {
  410. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_push_matrix);
  411. if (m_in_draw_state) {
  412. m_error = GL_INVALID_OPERATION;
  413. return;
  414. }
  415. dbgln_if(GL_DEBUG, "glPushMatrix(): Pushing matrix to the matrix stack (matrix_mode {})", m_current_matrix_mode);
  416. switch (m_current_matrix_mode) {
  417. case GL_PROJECTION:
  418. if (m_projection_matrix_stack.size() >= MATRIX_STACK_LIMIT) {
  419. m_error = GL_STACK_OVERFLOW;
  420. return;
  421. }
  422. m_projection_matrix_stack.append(m_projection_matrix);
  423. break;
  424. case GL_MODELVIEW:
  425. if (m_model_view_matrix_stack.size() >= MATRIX_STACK_LIMIT) {
  426. m_error = GL_STACK_OVERFLOW;
  427. return;
  428. }
  429. m_model_view_matrix_stack.append(m_model_view_matrix);
  430. break;
  431. default:
  432. dbgln_if(GL_DEBUG, "glPushMatrix(): Attempt to push matrix with invalid matrix mode {})", m_current_matrix_mode);
  433. return;
  434. }
  435. m_error = GL_NO_ERROR;
  436. }
  437. void SoftwareGLContext::gl_pop_matrix()
  438. {
  439. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_pop_matrix);
  440. if (m_in_draw_state) {
  441. m_error = GL_INVALID_OPERATION;
  442. return;
  443. }
  444. dbgln_if(GL_DEBUG, "glPopMatrix(): Popping matrix from matrix stack (matrix_mode = {})", m_current_matrix_mode);
  445. // FIXME: Make sure stack::top() doesn't cause any nasty issues if it's empty (that could result in a lockup/hang)
  446. switch (m_current_matrix_mode) {
  447. case GL_PROJECTION:
  448. if (m_projection_matrix_stack.size() == 0) {
  449. m_error = GL_STACK_UNDERFLOW;
  450. return;
  451. }
  452. m_projection_matrix = m_projection_matrix_stack.take_last();
  453. break;
  454. case GL_MODELVIEW:
  455. if (m_model_view_matrix_stack.size() == 0) {
  456. m_error = GL_STACK_UNDERFLOW;
  457. return;
  458. }
  459. m_model_view_matrix = m_model_view_matrix_stack.take_last();
  460. break;
  461. default:
  462. dbgln_if(GL_DEBUG, "glPopMatrix(): Attempt to pop matrix with invalid matrix mode, {}", m_current_matrix_mode);
  463. return;
  464. }
  465. m_error = GL_NO_ERROR;
  466. }
  467. void SoftwareGLContext::gl_rotate(GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
  468. {
  469. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_rotate, angle, x, y, z);
  470. if (m_in_draw_state) {
  471. m_error = GL_INVALID_OPERATION;
  472. return;
  473. }
  474. FloatVector3 axis = { (float)x, (float)y, (float)z };
  475. axis.normalize();
  476. auto rotation_mat = Gfx::rotation_matrix(axis, static_cast<float>(angle));
  477. if (m_current_matrix_mode == GL_MODELVIEW)
  478. m_model_view_matrix = m_model_view_matrix * rotation_mat;
  479. else if (m_current_matrix_mode == GL_PROJECTION)
  480. m_projection_matrix = m_projection_matrix * rotation_mat;
  481. m_error = GL_NO_ERROR;
  482. }
  483. void SoftwareGLContext::gl_scale(GLdouble x, GLdouble y, GLdouble z)
  484. {
  485. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_scale, x, y, z);
  486. if (m_in_draw_state) {
  487. m_error = GL_INVALID_OPERATION;
  488. return;
  489. }
  490. if (m_current_matrix_mode == GL_MODELVIEW) {
  491. m_model_view_matrix = m_model_view_matrix * Gfx::scale_matrix(FloatVector3 { static_cast<float>(x), static_cast<float>(y), static_cast<float>(z) });
  492. } else if (m_current_matrix_mode == GL_PROJECTION) {
  493. m_projection_matrix = m_projection_matrix * Gfx::scale_matrix(FloatVector3 { static_cast<float>(x), static_cast<float>(y), static_cast<float>(z) });
  494. }
  495. m_error = GL_NO_ERROR;
  496. }
  497. void SoftwareGLContext::gl_translate(GLdouble x, GLdouble y, GLdouble z)
  498. {
  499. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_translate, x, y, z);
  500. if (m_in_draw_state) {
  501. m_error = GL_INVALID_OPERATION;
  502. return;
  503. }
  504. if (m_current_matrix_mode == GL_MODELVIEW) {
  505. m_model_view_matrix = m_model_view_matrix * Gfx::translation_matrix(FloatVector3 { (float)x, (float)y, (float)z });
  506. } else if (m_current_matrix_mode == GL_PROJECTION) {
  507. m_projection_matrix = m_projection_matrix * Gfx::translation_matrix(FloatVector3 { (float)x, (float)y, (float)z });
  508. }
  509. m_error = GL_NO_ERROR;
  510. }
  511. void SoftwareGLContext::gl_vertex(GLdouble x, GLdouble y, GLdouble z, GLdouble w)
  512. {
  513. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_vertex, x, y, z, w);
  514. GLVertex vertex;
  515. vertex.x = x;
  516. vertex.y = y;
  517. vertex.z = z;
  518. vertex.w = w;
  519. vertex.r = m_current_vertex_color.x();
  520. vertex.g = m_current_vertex_color.y();
  521. vertex.b = m_current_vertex_color.z();
  522. vertex.a = m_current_vertex_color.w();
  523. // FIXME: This is to suppress any -Wunused errors
  524. vertex.w = 0.0f;
  525. vertex.u = 0.0f;
  526. vertex.v = 0.0f;
  527. vertex_list.append(vertex);
  528. m_error = GL_NO_ERROR;
  529. }
  530. void SoftwareGLContext::gl_viewport(GLint x, GLint y, GLsizei width, GLsizei height)
  531. {
  532. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_viewport, x, y, width, height);
  533. if (m_in_draw_state) {
  534. m_error = GL_INVALID_OPERATION;
  535. return;
  536. }
  537. (void)(x);
  538. (void)(y);
  539. (void)(width);
  540. (void)(height);
  541. m_error = GL_NO_ERROR;
  542. }
  543. void SoftwareGLContext::gl_enable(GLenum capability)
  544. {
  545. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_enable, capability);
  546. if (m_in_draw_state) {
  547. m_error = GL_INVALID_OPERATION;
  548. return;
  549. }
  550. auto rasterizer_options = m_rasterizer.options();
  551. bool update_rasterizer_options = false;
  552. switch (capability) {
  553. case GL_CULL_FACE:
  554. m_cull_faces = true;
  555. break;
  556. case GL_DEPTH_TEST:
  557. m_depth_test_enabled = true;
  558. rasterizer_options.enable_depth_test = true;
  559. update_rasterizer_options = true;
  560. break;
  561. case GL_BLEND:
  562. m_blend_enabled = true;
  563. rasterizer_options.enable_blending = true;
  564. update_rasterizer_options = true;
  565. break;
  566. default:
  567. m_error = GL_INVALID_ENUM;
  568. break;
  569. }
  570. if (update_rasterizer_options)
  571. m_rasterizer.set_options(rasterizer_options);
  572. }
  573. void SoftwareGLContext::gl_disable(GLenum capability)
  574. {
  575. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_disable, capability);
  576. if (m_in_draw_state) {
  577. m_error = GL_INVALID_OPERATION;
  578. return;
  579. }
  580. auto rasterizer_options = m_rasterizer.options();
  581. bool update_rasterizer_options = false;
  582. switch (capability) {
  583. case GL_CULL_FACE:
  584. m_cull_faces = false;
  585. break;
  586. case GL_DEPTH_TEST:
  587. m_depth_test_enabled = false;
  588. rasterizer_options.enable_depth_test = false;
  589. update_rasterizer_options = true;
  590. break;
  591. case GL_BLEND:
  592. m_blend_enabled = false;
  593. rasterizer_options.enable_blending = false;
  594. update_rasterizer_options = false;
  595. break;
  596. default:
  597. m_error = GL_INVALID_ENUM;
  598. break;
  599. }
  600. if (update_rasterizer_options)
  601. m_rasterizer.set_options(rasterizer_options);
  602. }
  603. void SoftwareGLContext::gl_front_face(GLenum face)
  604. {
  605. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_front_face, face);
  606. if (face < GL_CW || face > GL_CCW) {
  607. m_error = GL_INVALID_ENUM;
  608. return;
  609. }
  610. m_front_face = face;
  611. }
  612. void SoftwareGLContext::gl_cull_face(GLenum cull_mode)
  613. {
  614. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_cull_face, cull_mode);
  615. if (cull_mode < GL_FRONT || cull_mode > GL_FRONT_AND_BACK) {
  616. m_error = GL_INVALID_ENUM;
  617. return;
  618. }
  619. m_culled_sides = cull_mode;
  620. }
  621. GLuint SoftwareGLContext::gl_gen_lists(GLsizei range)
  622. {
  623. if (range <= 0) {
  624. m_error = GL_INVALID_VALUE;
  625. return 0;
  626. }
  627. if (m_in_draw_state) {
  628. m_error = GL_INVALID_OPERATION;
  629. return 0;
  630. }
  631. auto initial_entry = m_listings.size();
  632. m_listings.resize(range + initial_entry);
  633. return initial_entry + 1;
  634. }
  635. void SoftwareGLContext::gl_call_list(GLuint list)
  636. {
  637. if (m_gl_call_depth > max_allowed_gl_call_depth)
  638. return;
  639. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_call_list, list);
  640. if (m_listings.size() < list)
  641. return;
  642. TemporaryChange change { m_gl_call_depth, m_gl_call_depth + 1 };
  643. auto& listing = m_listings[list - 1];
  644. for (auto& entry : listing.entries) {
  645. entry.function.visit([&](auto& function) {
  646. entry.arguments.visit([&](auto& arguments) {
  647. auto apply = [&]<typename... Args>(Args && ... args)
  648. {
  649. if constexpr (requires { (this->*function)(forward<Args>(args)...); })
  650. (this->*function)(forward<Args>(args)...);
  651. };
  652. arguments.apply_as_args(apply);
  653. });
  654. });
  655. }
  656. }
  657. void SoftwareGLContext::gl_delete_lists(GLuint list, GLsizei range)
  658. {
  659. if (m_listings.size() < list || m_listings.size() <= list + range)
  660. return;
  661. for (auto& entry : m_listings.span().slice(list - 1, range))
  662. entry.entries.clear();
  663. }
  664. void SoftwareGLContext::gl_end_list()
  665. {
  666. if (m_in_draw_state) {
  667. m_error = GL_INVALID_OPERATION;
  668. return;
  669. }
  670. if (!m_current_listing_index.has_value()) {
  671. m_error = GL_INVALID_OPERATION;
  672. return;
  673. }
  674. m_listings[m_current_listing_index->index] = move(m_current_listing_index->listing);
  675. m_current_listing_index.clear();
  676. }
  677. void SoftwareGLContext::gl_new_list(GLuint list, GLenum mode)
  678. {
  679. if (list == 0) {
  680. m_error = GL_INVALID_VALUE;
  681. return;
  682. }
  683. if (mode != GL_COMPILE && mode != GL_COMPILE_AND_EXECUTE) {
  684. m_error = GL_INVALID_ENUM;
  685. return;
  686. }
  687. if (m_in_draw_state) {
  688. m_error = GL_INVALID_OPERATION;
  689. return;
  690. }
  691. if (m_current_listing_index.has_value()) {
  692. m_error = GL_INVALID_OPERATION;
  693. return;
  694. }
  695. if (m_listings.size() < list)
  696. return;
  697. m_current_listing_index = CurrentListing { {}, static_cast<size_t>(list - 1), mode };
  698. }
  699. void SoftwareGLContext::gl_flush()
  700. {
  701. if (m_in_draw_state) {
  702. m_error = GL_INVALID_OPERATION;
  703. return;
  704. }
  705. // No-op since SoftwareGLContext is completely synchronous at the moment
  706. }
  707. void SoftwareGLContext::gl_finish()
  708. {
  709. if (m_in_draw_state) {
  710. m_error = GL_INVALID_OPERATION;
  711. return;
  712. }
  713. // No-op since SoftwareGLContext is completely synchronous at the moment
  714. }
  715. void SoftwareGLContext::gl_blend_func(GLenum src_factor, GLenum dst_factor)
  716. {
  717. if (m_in_draw_state) {
  718. m_error = GL_INVALID_OPERATION;
  719. return;
  720. }
  721. // FIXME: The list of allowed enums differs between API versions
  722. // This was taken from the 2.0 spec on https://docs.gl/gl2/glBlendFunc
  723. if (!(src_factor == GL_ZERO
  724. || src_factor == GL_ONE
  725. || src_factor == GL_SRC_COLOR
  726. || src_factor == GL_ONE_MINUS_SRC_COLOR
  727. || src_factor == GL_DST_COLOR
  728. || src_factor == GL_ONE_MINUS_DST_COLOR
  729. || src_factor == GL_SRC_ALPHA
  730. || src_factor == GL_ONE_MINUS_SRC_ALPHA
  731. || src_factor == GL_DST_ALPHA
  732. || src_factor == GL_ONE_MINUS_DST_ALPHA
  733. || src_factor == GL_CONSTANT_COLOR
  734. || src_factor == GL_ONE_MINUS_CONSTANT_COLOR
  735. || src_factor == GL_CONSTANT_ALPHA
  736. || src_factor == GL_ONE_MINUS_CONSTANT_ALPHA
  737. || src_factor == GL_SRC_ALPHA_SATURATE)) {
  738. m_error = GL_INVALID_ENUM;
  739. return;
  740. }
  741. if (!(dst_factor == GL_ZERO
  742. || dst_factor == GL_ONE
  743. || dst_factor == GL_SRC_COLOR
  744. || dst_factor == GL_ONE_MINUS_SRC_COLOR
  745. || dst_factor == GL_DST_COLOR
  746. || dst_factor == GL_ONE_MINUS_DST_COLOR
  747. || dst_factor == GL_SRC_ALPHA
  748. || dst_factor == GL_ONE_MINUS_SRC_ALPHA
  749. || dst_factor == GL_DST_ALPHA
  750. || dst_factor == GL_ONE_MINUS_DST_ALPHA
  751. || dst_factor == GL_CONSTANT_COLOR
  752. || dst_factor == GL_ONE_MINUS_CONSTANT_COLOR
  753. || dst_factor == GL_CONSTANT_ALPHA
  754. || dst_factor == GL_ONE_MINUS_CONSTANT_ALPHA)) {
  755. m_error = GL_INVALID_ENUM;
  756. return;
  757. }
  758. m_blend_source_factor = src_factor;
  759. m_blend_destination_factor = dst_factor;
  760. auto options = m_rasterizer.options();
  761. options.blend_source_factor = m_blend_source_factor;
  762. options.blend_destination_factor = m_blend_destination_factor;
  763. m_rasterizer.set_options(options);
  764. }
  765. void SoftwareGLContext::present()
  766. {
  767. m_rasterizer.blit_to(*m_frontbuffer);
  768. }
  769. }