OpenGL.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. /**
  2. * Copyright (c) 2006-2015 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. // LOVE
  21. #include "common/config.h"
  22. #include "OpenGL.h"
  23. #include "Shader.h"
  24. #include "Canvas.h"
  25. #include "common/Exception.h"
  26. // C++
  27. #include <algorithm>
  28. #include <limits>
  29. // C
  30. #include <cstring>
  31. // For SDL_GL_GetProcAddress.
  32. #include <SDL_video.h>
  33. #ifdef LOVE_IOS
  34. #include <SDL_syswm.h>
  35. #endif
  36. namespace love
  37. {
  38. namespace graphics
  39. {
  40. namespace opengl
  41. {
  42. OpenGL::OpenGL()
  43. : stats()
  44. , contextInitialized(false)
  45. , maxAnisotropy(1.0f)
  46. , maxTextureSize(0)
  47. , maxRenderTargets(1)
  48. , maxRenderbufferSamples(0)
  49. , maxTextureUnits(1)
  50. , vendor(VENDOR_UNKNOWN)
  51. , state()
  52. {
  53. matrices.transform.reserve(10);
  54. matrices.projection.reserve(2);
  55. }
  56. bool OpenGL::initContext()
  57. {
  58. if (contextInitialized)
  59. return true;
  60. if (!gladLoadGLLoader(SDL_GL_GetProcAddress))
  61. return false;
  62. initOpenGLFunctions();
  63. initVendor();
  64. initMatrices();
  65. contextInitialized = true;
  66. return true;
  67. }
  68. void OpenGL::setupContext()
  69. {
  70. if (!contextInitialized)
  71. return;
  72. initMaxValues();
  73. GLfloat glcolor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
  74. glVertexAttrib4fv(ATTRIB_COLOR, glcolor);
  75. glVertexAttrib4fv(ATTRIB_CONSTANTCOLOR, glcolor);
  76. // Get the current viewport.
  77. glGetIntegerv(GL_VIEWPORT, (GLint *) &state.viewport.x);
  78. // And the current scissor - but we need to compensate for GL scissors
  79. // starting at the bottom left instead of top left.
  80. glGetIntegerv(GL_SCISSOR_BOX, (GLint *) &state.scissor.x);
  81. state.scissor.y = state.viewport.h - (state.scissor.y + state.scissor.h);
  82. if (GLAD_VERSION_1_0)
  83. glGetFloatv(GL_POINT_SIZE, &state.pointSize);
  84. else
  85. state.pointSize = 1.0f;
  86. if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB
  87. || GLAD_EXT_sRGB_write_control)
  88. {
  89. state.framebufferSRGBEnabled = (glIsEnabled(GL_FRAMEBUFFER_SRGB) == GL_TRUE);
  90. }
  91. else
  92. state.framebufferSRGBEnabled = false;
  93. // Initialize multiple texture unit support for shaders.
  94. state.boundTextures.clear();
  95. state.boundTextures.resize(maxTextureUnits, 0);
  96. GLenum curgltextureunit;
  97. glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint *) &curgltextureunit);
  98. state.curTextureUnit = (int) curgltextureunit - GL_TEXTURE0;
  99. // Retrieve currently bound textures for each texture unit.
  100. for (int i = 0; i < (int) state.boundTextures.size(); i++)
  101. {
  102. glActiveTexture(GL_TEXTURE0 + i);
  103. glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &state.boundTextures[i]);
  104. }
  105. glActiveTexture(curgltextureunit);
  106. createDefaultTexture();
  107. // Invalidate the cached matrices by setting some elements to NaN.
  108. float nan = std::numeric_limits<float>::quiet_NaN();
  109. state.lastProjectionMatrix.setTranslation(nan, nan);
  110. state.lastTransformMatrix.setTranslation(nan, nan);
  111. if (GLAD_VERSION_1_0)
  112. glMatrixMode(GL_MODELVIEW);
  113. contextInitialized = true;
  114. }
  115. void OpenGL::deInitContext()
  116. {
  117. if (!contextInitialized)
  118. return;
  119. glDeleteTextures(1, &state.defaultTexture);
  120. state.defaultTexture = 0;
  121. contextInitialized = false;
  122. }
  123. void OpenGL::initVendor()
  124. {
  125. const char *vstr = (const char *) glGetString(GL_VENDOR);
  126. if (!vstr)
  127. {
  128. vendor = VENDOR_UNKNOWN;
  129. return;
  130. }
  131. // http://feedback.wildfiregames.com/report/opengl/feature/GL_VENDOR
  132. // http://stackoverflow.com/questions/2093594/opengl-extensions-available-on-different-android-devices
  133. if (strstr(vstr, "ATI Technologies"))
  134. vendor = VENDOR_AMD;
  135. else if (strstr(vstr, "NVIDIA"))
  136. vendor = VENDOR_NVIDIA;
  137. else if (strstr(vstr, "Intel"))
  138. vendor = VENDOR_INTEL;
  139. else if (strstr(vstr, "Mesa"))
  140. vendor = VENDOR_MESA_SOFT;
  141. else if (strstr(vstr, "Apple Computer") || strstr(vstr, "Apple Inc."))
  142. vendor = VENDOR_APPLE;
  143. else if (strstr(vstr, "Microsoft"))
  144. vendor = VENDOR_MICROSOFT;
  145. else if (strstr(vstr, "Imagination"))
  146. vendor = VENDOR_IMGTEC;
  147. else if (strstr(vstr, "ARM"))
  148. vendor = VENDOR_ARM;
  149. else if (strstr(vstr, "Qualcomm"))
  150. vendor = VENDOR_QUALCOMM;
  151. else if (strstr(vstr, "Broadcom"))
  152. vendor = VENDOR_BROADCOM;
  153. else if (strstr(vstr, "Vivante"))
  154. vendor = VENDOR_VIVANTE;
  155. else
  156. vendor = VENDOR_UNKNOWN;
  157. }
  158. void OpenGL::initOpenGLFunctions()
  159. {
  160. // Alias extension-suffixed framebuffer functions to core versions since
  161. // there are so many different-named extensions that do the same things...
  162. if (!(GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object))
  163. {
  164. if (GLAD_VERSION_1_0 && GLAD_EXT_framebuffer_object)
  165. {
  166. fp_glBindRenderbuffer = fp_glBindRenderbufferEXT;
  167. fp_glDeleteRenderbuffers = fp_glDeleteRenderbuffersEXT;
  168. fp_glGenRenderbuffers = fp_glGenRenderbuffersEXT;
  169. fp_glRenderbufferStorage = fp_glRenderbufferStorageEXT;
  170. fp_glGetRenderbufferParameteriv = fp_glGetRenderbufferParameterivEXT;
  171. fp_glBindFramebuffer = fp_glBindFramebufferEXT;
  172. fp_glDeleteFramebuffers = fp_glDeleteFramebuffersEXT;
  173. fp_glGenFramebuffers = fp_glGenFramebuffersEXT;
  174. fp_glCheckFramebufferStatus = fp_glCheckFramebufferStatusEXT;
  175. fp_glFramebufferTexture2D = fp_glFramebufferTexture2DEXT;
  176. fp_glFramebufferRenderbuffer = fp_glFramebufferRenderbufferEXT;
  177. fp_glGetFramebufferAttachmentParameteriv = fp_glGetFramebufferAttachmentParameterivEXT;
  178. fp_glGenerateMipmap = fp_glGenerateMipmapEXT;
  179. }
  180. if (GLAD_EXT_framebuffer_blit)
  181. fp_glBlitFramebuffer = fp_glBlitFramebufferEXT;
  182. else if (GLAD_ANGLE_framebuffer_blit)
  183. fp_glBlitFramebuffer = fp_glBlitFramebufferANGLE;
  184. else if (GLAD_NV_framebuffer_blit)
  185. fp_glBlitFramebuffer = fp_glBlitFramebufferNV;
  186. if (GLAD_EXT_framebuffer_multisample)
  187. fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleEXT;
  188. else if (GLAD_APPLE_framebuffer_multisample)
  189. fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleAPPLE;
  190. else if (GLAD_ANGLE_framebuffer_multisample)
  191. fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleANGLE;
  192. else if (GLAD_NV_framebuffer_multisample)
  193. fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleNV;
  194. }
  195. }
  196. void OpenGL::initMaxValues()
  197. {
  198. // We'll need this value to clamp anisotropy.
  199. if (GLAD_EXT_texture_filter_anisotropic)
  200. glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
  201. else
  202. maxAnisotropy = 1.0f;
  203. glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
  204. int maxattachments = 1;
  205. int maxdrawbuffers = 1;
  206. if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_2_0)
  207. {
  208. glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxattachments);
  209. glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxdrawbuffers);
  210. }
  211. maxRenderTargets = std::min(maxattachments, maxdrawbuffers);
  212. if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object
  213. || GLAD_EXT_framebuffer_multisample || GLAD_APPLE_framebuffer_multisample
  214. || GLAD_ANGLE_framebuffer_multisample)
  215. {
  216. glGetIntegerv(GL_MAX_SAMPLES, &maxRenderbufferSamples);
  217. }
  218. else
  219. maxRenderbufferSamples = 0;
  220. glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
  221. }
  222. void OpenGL::initMatrices()
  223. {
  224. matrices.transform.clear();
  225. matrices.projection.clear();
  226. matrices.transform.push_back(Matrix());
  227. matrices.projection.push_back(Matrix());
  228. }
  229. void OpenGL::createDefaultTexture()
  230. {
  231. // Set the 'default' texture (id 0) as a repeating white pixel. Otherwise,
  232. // texture2D calls inside a shader would return black when drawing graphics
  233. // primitives, which would create the need to use different "passthrough"
  234. // shaders for untextured primitives vs images.
  235. GLuint curtexture = state.boundTextures[state.curTextureUnit];
  236. glGenTextures(1, &state.defaultTexture);
  237. bindTexture(state.defaultTexture);
  238. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  239. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  240. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  241. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  242. GLubyte pix[] = {255, 255, 255, 255};
  243. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix);
  244. bindTexture(curtexture);
  245. }
  246. void OpenGL::pushTransform()
  247. {
  248. matrices.transform.push_back(matrices.transform.back());
  249. }
  250. void OpenGL::popTransform()
  251. {
  252. matrices.transform.pop_back();
  253. }
  254. Matrix &OpenGL::getTransform()
  255. {
  256. return matrices.transform.back();
  257. }
  258. void OpenGL::prepareDraw()
  259. {
  260. TempDebugGroup debuggroup("Prepare OpenGL draw");
  261. Shader *shader = Shader::current;
  262. if (shader != nullptr)
  263. {
  264. // Make sure the active shader has the correct values for its love-
  265. // provided uniforms.
  266. shader->checkSetScreenParams();
  267. }
  268. const Matrix &curproj = matrices.projection.back();
  269. const Matrix &curxform = matrices.transform.back();
  270. if (GLAD_ES_VERSION_2_0 && shader)
  271. {
  272. // Send built-in uniforms to the current shader.
  273. shader->sendBuiltinMatrix(Shader::BUILTIN_TRANSFORM_MATRIX, 4, curxform.getElements(), 1);
  274. shader->sendBuiltinMatrix(Shader::BUILTIN_PROJECTION_MATRIX, 4, curproj.getElements(), 1);
  275. Matrix tp_matrix(curproj * curxform);
  276. shader->sendBuiltinMatrix(Shader::BUILTIN_TRANSFORM_PROJECTION_MATRIX, 4, tp_matrix.getElements(), 1);
  277. shader->checkSetPointSize(state.pointSize);
  278. }
  279. else if (GLAD_VERSION_1_0)
  280. {
  281. const Matrix &lastproj = state.lastProjectionMatrix;
  282. const Matrix &lastxform = state.lastTransformMatrix;
  283. // We only need to re-upload the projection matrix if it's changed.
  284. if (memcmp(curproj.getElements(), lastproj.getElements(), sizeof(float) * 16) != 0)
  285. {
  286. glMatrixMode(GL_PROJECTION);
  287. glLoadMatrixf(curproj.getElements());
  288. glMatrixMode(GL_MODELVIEW);
  289. state.lastProjectionMatrix = matrices.projection.back();
  290. }
  291. // Same with the transform matrix.
  292. if (memcmp(curxform.getElements(), lastxform.getElements(), sizeof(float) * 16) != 0)
  293. {
  294. glLoadMatrixf(curxform.getElements());
  295. state.lastTransformMatrix = matrices.transform.back();
  296. }
  297. }
  298. }
  299. void OpenGL::drawArrays(GLenum mode, GLint first, GLsizei count)
  300. {
  301. glDrawArrays(mode, first, count);
  302. ++stats.drawCalls;
  303. }
  304. void OpenGL::drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)
  305. {
  306. glDrawElements(mode, count, type, indices);
  307. ++stats.drawCalls;
  308. }
  309. void OpenGL::setViewport(const OpenGL::Viewport &v)
  310. {
  311. glViewport(v.x, v.y, v.w, v.h);
  312. state.viewport = v;
  313. // glScissor starts from the lower left, so we compensate when setting the
  314. // scissor. When the viewport is changed, we need to manually update the
  315. // scissor again.
  316. setScissor(state.scissor);
  317. }
  318. OpenGL::Viewport OpenGL::getViewport() const
  319. {
  320. return state.viewport;
  321. }
  322. void OpenGL::setScissor(const OpenGL::Viewport &v)
  323. {
  324. if (Canvas::current)
  325. glScissor(v.x, v.y, v.w, v.h);
  326. else
  327. {
  328. // With no Canvas active, we need to compensate for glScissor starting
  329. // from the lower left of the viewport instead of the top left.
  330. glScissor(v.x, state.viewport.h - (v.y + v.h), v.w, v.h);
  331. }
  332. state.scissor = v;
  333. }
  334. OpenGL::Viewport OpenGL::getScissor() const
  335. {
  336. return state.scissor;
  337. }
  338. void OpenGL::setPointSize(float size)
  339. {
  340. if (GLAD_VERSION_1_0)
  341. glPointSize(size);
  342. state.pointSize = size;
  343. }
  344. float OpenGL::getPointSize() const
  345. {
  346. return state.pointSize;
  347. }
  348. void OpenGL::setFramebufferSRGB(bool enable)
  349. {
  350. if (enable)
  351. glEnable(GL_FRAMEBUFFER_SRGB);
  352. else
  353. glDisable(GL_FRAMEBUFFER_SRGB);
  354. state.framebufferSRGBEnabled = enable;
  355. }
  356. bool OpenGL::hasFramebufferSRGB() const
  357. {
  358. return state.framebufferSRGBEnabled;
  359. }
  360. void OpenGL::bindFramebuffer(GLenum target, GLuint framebuffer)
  361. {
  362. glBindFramebuffer(target, framebuffer);
  363. if (target == GL_FRAMEBUFFER)
  364. ++stats.framebufferBinds;
  365. }
  366. GLuint OpenGL::getDefaultFBO() const
  367. {
  368. #ifdef LOVE_IOS
  369. // Hack: iOS uses a custom FBO.
  370. SDL_SysWMinfo info = {};
  371. SDL_VERSION(&info.version);
  372. SDL_GetWindowWMInfo(SDL_GL_GetCurrentWindow(), &info);
  373. return info.info.uikit.framebuffer;
  374. #else
  375. return 0;
  376. #endif
  377. }
  378. GLuint OpenGL::getDefaultTexture() const
  379. {
  380. return state.defaultTexture;
  381. }
  382. void OpenGL::setTextureUnit(int textureunit)
  383. {
  384. if (textureunit < 0 || (size_t) textureunit >= state.boundTextures.size())
  385. throw love::Exception("Invalid texture unit index (%d).", textureunit);
  386. if (textureunit != state.curTextureUnit)
  387. glActiveTexture(GL_TEXTURE0 + textureunit);
  388. state.curTextureUnit = textureunit;
  389. }
  390. void OpenGL::bindTexture(GLuint texture)
  391. {
  392. if (texture != state.boundTextures[state.curTextureUnit])
  393. {
  394. state.boundTextures[state.curTextureUnit] = texture;
  395. glBindTexture(GL_TEXTURE_2D, texture);
  396. }
  397. }
  398. void OpenGL::bindTextureToUnit(GLuint texture, int textureunit, bool restoreprev)
  399. {
  400. if (textureunit < 0 || (size_t) textureunit >= state.boundTextures.size())
  401. throw love::Exception("Invalid texture unit index.");
  402. if (texture != state.boundTextures[textureunit])
  403. {
  404. int oldtextureunit = state.curTextureUnit;
  405. setTextureUnit(textureunit);
  406. state.boundTextures[textureunit] = texture;
  407. glBindTexture(GL_TEXTURE_2D, texture);
  408. if (restoreprev)
  409. setTextureUnit(oldtextureunit);
  410. }
  411. }
  412. void OpenGL::deleteTexture(GLuint texture)
  413. {
  414. // glDeleteTextures binds texture 0 to all texture units the deleted texture
  415. // was bound to before deletion.
  416. for (GLuint &texid : state.boundTextures)
  417. {
  418. if (texid == texture)
  419. texid = 0;
  420. }
  421. glDeleteTextures(1, &texture);
  422. }
  423. void OpenGL::setTextureFilter(graphics::Texture::Filter &f)
  424. {
  425. GLint gmin, gmag;
  426. if (f.mipmap == Texture::FILTER_NONE)
  427. {
  428. if (f.min == Texture::FILTER_NEAREST)
  429. gmin = GL_NEAREST;
  430. else // f.min == Texture::FILTER_LINEAR
  431. gmin = GL_LINEAR;
  432. }
  433. else
  434. {
  435. if (f.min == Texture::FILTER_NEAREST && f.mipmap == Texture::FILTER_NEAREST)
  436. gmin = GL_NEAREST_MIPMAP_NEAREST;
  437. else if (f.min == Texture::FILTER_NEAREST && f.mipmap == Texture::FILTER_LINEAR)
  438. gmin = GL_NEAREST_MIPMAP_LINEAR;
  439. else if (f.min == Texture::FILTER_LINEAR && f.mipmap == Texture::FILTER_NEAREST)
  440. gmin = GL_LINEAR_MIPMAP_NEAREST;
  441. else if (f.min == Texture::FILTER_LINEAR && f.mipmap == Texture::FILTER_LINEAR)
  442. gmin = GL_LINEAR_MIPMAP_LINEAR;
  443. else
  444. gmin = GL_LINEAR;
  445. }
  446. switch (f.mag)
  447. {
  448. case Texture::FILTER_NEAREST:
  449. gmag = GL_NEAREST;
  450. break;
  451. case Texture::FILTER_LINEAR:
  452. default:
  453. gmag = GL_LINEAR;
  454. break;
  455. }
  456. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin);
  457. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag);
  458. if (GLAD_EXT_texture_filter_anisotropic)
  459. {
  460. f.anisotropy = std::min(std::max(f.anisotropy, 1.0f), maxAnisotropy);
  461. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, f.anisotropy);
  462. }
  463. else
  464. f.anisotropy = 1.0f;
  465. }
  466. void OpenGL::setTextureWrap(const graphics::Texture::Wrap &w)
  467. {
  468. auto glWrapMode = [](Texture::WrapMode wmode) -> GLint
  469. {
  470. switch (wmode)
  471. {
  472. case Texture::WRAP_CLAMP:
  473. default:
  474. return GL_CLAMP_TO_EDGE;
  475. case Texture::WRAP_REPEAT:
  476. return GL_REPEAT;
  477. case Texture::WRAP_MIRRORED_REPEAT:
  478. return GL_MIRRORED_REPEAT;
  479. }
  480. };
  481. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapMode(w.s));
  482. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapMode(w.t));
  483. }
  484. int OpenGL::getMaxTextureSize() const
  485. {
  486. return maxTextureSize;
  487. }
  488. int OpenGL::getMaxRenderTargets() const
  489. {
  490. return maxRenderTargets;
  491. }
  492. int OpenGL::getMaxRenderbufferSamples() const
  493. {
  494. return maxRenderbufferSamples;
  495. }
  496. int OpenGL::getMaxTextureUnits() const
  497. {
  498. return maxTextureUnits;
  499. }
  500. void OpenGL::updateTextureMemorySize(size_t oldsize, size_t newsize)
  501. {
  502. int64 memsize = (int64) stats.textureMemory + ((int64 )newsize - (int64) oldsize);
  503. stats.textureMemory = (size_t) std::max(memsize, (int64) 0);
  504. }
  505. OpenGL::Vendor OpenGL::getVendor() const
  506. {
  507. return vendor;
  508. }
  509. const char *OpenGL::debugSeverityString(GLenum severity)
  510. {
  511. switch (severity)
  512. {
  513. case GL_DEBUG_SEVERITY_HIGH:
  514. return "high";
  515. case GL_DEBUG_SEVERITY_MEDIUM:
  516. return "medium";
  517. case GL_DEBUG_SEVERITY_LOW:
  518. return "low";
  519. default:
  520. return "unknown";
  521. }
  522. }
  523. const char *OpenGL::debugSourceString(GLenum source)
  524. {
  525. switch (source)
  526. {
  527. case GL_DEBUG_SOURCE_API:
  528. return "API";
  529. case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
  530. return "window";
  531. case GL_DEBUG_SOURCE_SHADER_COMPILER:
  532. return "shader";
  533. case GL_DEBUG_SOURCE_THIRD_PARTY:
  534. return "external";
  535. case GL_DEBUG_SOURCE_APPLICATION:
  536. return "LOVE";
  537. case GL_DEBUG_SOURCE_OTHER:
  538. return "other";
  539. default:
  540. return "unknown";
  541. }
  542. }
  543. const char *OpenGL::debugTypeString(GLenum type)
  544. {
  545. switch (type)
  546. {
  547. case GL_DEBUG_TYPE_ERROR:
  548. return "error";
  549. case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
  550. return "deprecated behavior";
  551. case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
  552. return "undefined behavior";
  553. case GL_DEBUG_TYPE_PERFORMANCE:
  554. return "performance";
  555. case GL_DEBUG_TYPE_PORTABILITY:
  556. return "portability";
  557. case GL_DEBUG_TYPE_OTHER:
  558. return "other";
  559. default:
  560. return "unknown";
  561. }
  562. }
  563. // OpenGL class instance singleton.
  564. OpenGL gl;
  565. } // opengl
  566. } // graphics
  567. } // love