OpenGL.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. /**
  2. * Copyright (c) 2006-2016 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. #include <cstdio>
  32. // For SDL_GL_GetProcAddress.
  33. #include <SDL_video.h>
  34. #ifdef LOVE_IOS
  35. #include <SDL_syswm.h>
  36. #endif
  37. #ifdef LOVE_ANDROID
  38. #include <dlfcn.h>
  39. #endif
  40. namespace love
  41. {
  42. namespace graphics
  43. {
  44. namespace opengl
  45. {
  46. static void *LOVEGetProcAddress(const char *name)
  47. {
  48. #ifdef LOVE_ANDROID
  49. void *proc = dlsym(RTLD_DEFAULT, name);
  50. if (proc)
  51. return proc;
  52. #endif
  53. return SDL_GL_GetProcAddress(name);
  54. }
  55. OpenGL::OpenGL()
  56. : stats()
  57. , contextInitialized(false)
  58. , maxAnisotropy(1.0f)
  59. , maxTextureSize(0)
  60. , maxRenderTargets(1)
  61. , maxRenderbufferSamples(0)
  62. , maxTextureUnits(1)
  63. , vendor(VENDOR_UNKNOWN)
  64. , state()
  65. {
  66. matrices.transform.reserve(10);
  67. matrices.projection.reserve(2);
  68. }
  69. bool OpenGL::initContext()
  70. {
  71. if (contextInitialized)
  72. return true;
  73. if (!gladLoadGLLoader(LOVEGetProcAddress))
  74. return false;
  75. initOpenGLFunctions();
  76. initVendor();
  77. initMatrices();
  78. bugs = {};
  79. #if defined(LOVE_WINDOWS) || defined(LOVE_LINUX)
  80. // See the comments in OpenGL.h.
  81. if (getVendor() == VENDOR_AMD)
  82. {
  83. bugs.clearRequiresDriverTextureStateUpdate = true;
  84. bugs.generateMipmapsRequiresTexture2DEnable = true;
  85. }
  86. #endif
  87. contextInitialized = true;
  88. return true;
  89. }
  90. void OpenGL::setupContext()
  91. {
  92. if (!contextInitialized)
  93. return;
  94. initMaxValues();
  95. GLfloat glcolor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
  96. glVertexAttrib4fv(ATTRIB_COLOR, glcolor);
  97. glVertexAttrib4fv(ATTRIB_CONSTANTCOLOR, glcolor);
  98. GLint maxvertexattribs = 1;
  99. glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxvertexattribs);
  100. state.enabledAttribArrays = (uint32) ((1ull << uint32(maxvertexattribs)) - 1);
  101. useVertexAttribArrays(0);
  102. // Get the current viewport.
  103. glGetIntegerv(GL_VIEWPORT, (GLint *) &state.viewport.x);
  104. // And the current scissor - but we need to compensate for GL scissors
  105. // starting at the bottom left instead of top left.
  106. glGetIntegerv(GL_SCISSOR_BOX, (GLint *) &state.scissor.x);
  107. state.scissor.y = state.viewport.h - (state.scissor.y + state.scissor.h);
  108. if (GLAD_VERSION_1_0)
  109. glGetFloatv(GL_POINT_SIZE, &state.pointSize);
  110. else
  111. state.pointSize = 1.0f;
  112. if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB
  113. || GLAD_EXT_sRGB_write_control)
  114. {
  115. state.framebufferSRGBEnabled = (glIsEnabled(GL_FRAMEBUFFER_SRGB) == GL_TRUE);
  116. }
  117. else
  118. state.framebufferSRGBEnabled = false;
  119. for (int i = 0; i < (int) BUFFER_MAX_ENUM; i++)
  120. {
  121. state.boundBuffers[i] = 0;
  122. glBindBuffer(getGLBufferType((BufferType) i), 0);
  123. }
  124. // Initialize multiple texture unit support for shaders.
  125. state.boundTextures.clear();
  126. state.boundTextures.resize(maxTextureUnits, 0);
  127. for (int i = 0; i < (int) state.boundTextures.size(); i++)
  128. {
  129. glActiveTexture(GL_TEXTURE0 + i);
  130. glBindTexture(GL_TEXTURE_2D, 0);
  131. }
  132. glActiveTexture(GL_TEXTURE0);
  133. state.curTextureUnit = 0;
  134. createDefaultTexture();
  135. // Invalidate the cached matrices by setting some elements to NaN.
  136. float nan = std::numeric_limits<float>::quiet_NaN();
  137. state.lastProjectionMatrix.setTranslation(nan, nan);
  138. state.lastTransformMatrix.setTranslation(nan, nan);
  139. if (GLAD_VERSION_1_0)
  140. glMatrixMode(GL_MODELVIEW);
  141. contextInitialized = true;
  142. }
  143. void OpenGL::deInitContext()
  144. {
  145. if (!contextInitialized)
  146. return;
  147. glDeleteTextures(1, &state.defaultTexture);
  148. state.defaultTexture = 0;
  149. contextInitialized = false;
  150. }
  151. void OpenGL::initVendor()
  152. {
  153. const char *vstr = (const char *) glGetString(GL_VENDOR);
  154. if (!vstr)
  155. {
  156. vendor = VENDOR_UNKNOWN;
  157. return;
  158. }
  159. // http://feedback.wildfiregames.com/report/opengl/feature/GL_VENDOR
  160. // http://stackoverflow.com/questions/2093594/opengl-extensions-available-on-different-android-devices
  161. if (strstr(vstr, "ATI Technologies"))
  162. vendor = VENDOR_AMD;
  163. else if (strstr(vstr, "NVIDIA"))
  164. vendor = VENDOR_NVIDIA;
  165. else if (strstr(vstr, "Intel"))
  166. vendor = VENDOR_INTEL;
  167. else if (strstr(vstr, "Mesa"))
  168. vendor = VENDOR_MESA_SOFT;
  169. else if (strstr(vstr, "Apple Computer") || strstr(vstr, "Apple Inc."))
  170. vendor = VENDOR_APPLE;
  171. else if (strstr(vstr, "Microsoft"))
  172. vendor = VENDOR_MICROSOFT;
  173. else if (strstr(vstr, "Imagination"))
  174. vendor = VENDOR_IMGTEC;
  175. else if (strstr(vstr, "ARM"))
  176. vendor = VENDOR_ARM;
  177. else if (strstr(vstr, "Qualcomm"))
  178. vendor = VENDOR_QUALCOMM;
  179. else if (strstr(vstr, "Broadcom"))
  180. vendor = VENDOR_BROADCOM;
  181. else if (strstr(vstr, "Vivante"))
  182. vendor = VENDOR_VIVANTE;
  183. else
  184. vendor = VENDOR_UNKNOWN;
  185. }
  186. void OpenGL::initOpenGLFunctions()
  187. {
  188. // Alias extension-suffixed framebuffer functions to core versions since
  189. // there are so many different-named extensions that do the same things...
  190. if (!(GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object))
  191. {
  192. if (GLAD_VERSION_1_0 && GLAD_EXT_framebuffer_object)
  193. {
  194. fp_glBindRenderbuffer = fp_glBindRenderbufferEXT;
  195. fp_glDeleteRenderbuffers = fp_glDeleteRenderbuffersEXT;
  196. fp_glGenRenderbuffers = fp_glGenRenderbuffersEXT;
  197. fp_glRenderbufferStorage = fp_glRenderbufferStorageEXT;
  198. fp_glGetRenderbufferParameteriv = fp_glGetRenderbufferParameterivEXT;
  199. fp_glBindFramebuffer = fp_glBindFramebufferEXT;
  200. fp_glDeleteFramebuffers = fp_glDeleteFramebuffersEXT;
  201. fp_glGenFramebuffers = fp_glGenFramebuffersEXT;
  202. fp_glCheckFramebufferStatus = fp_glCheckFramebufferStatusEXT;
  203. fp_glFramebufferTexture2D = fp_glFramebufferTexture2DEXT;
  204. fp_glFramebufferRenderbuffer = fp_glFramebufferRenderbufferEXT;
  205. fp_glGetFramebufferAttachmentParameteriv = fp_glGetFramebufferAttachmentParameterivEXT;
  206. fp_glGenerateMipmap = fp_glGenerateMipmapEXT;
  207. }
  208. if (GLAD_EXT_framebuffer_blit)
  209. fp_glBlitFramebuffer = fp_glBlitFramebufferEXT;
  210. else if (GLAD_ANGLE_framebuffer_blit)
  211. fp_glBlitFramebuffer = fp_glBlitFramebufferANGLE;
  212. else if (GLAD_NV_framebuffer_blit)
  213. fp_glBlitFramebuffer = fp_glBlitFramebufferNV;
  214. if (GLAD_EXT_framebuffer_multisample)
  215. fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleEXT;
  216. else if (GLAD_APPLE_framebuffer_multisample)
  217. fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleAPPLE;
  218. else if (GLAD_ANGLE_framebuffer_multisample)
  219. fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleANGLE;
  220. else if (GLAD_NV_framebuffer_multisample)
  221. fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleNV;
  222. }
  223. }
  224. void OpenGL::initMaxValues()
  225. {
  226. // We'll need this value to clamp anisotropy.
  227. if (GLAD_EXT_texture_filter_anisotropic)
  228. glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
  229. else
  230. maxAnisotropy = 1.0f;
  231. glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
  232. int maxattachments = 1;
  233. int maxdrawbuffers = 1;
  234. if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_2_0)
  235. {
  236. glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxattachments);
  237. glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxdrawbuffers);
  238. }
  239. maxRenderTargets = std::min(maxattachments, maxdrawbuffers);
  240. if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object
  241. || GLAD_EXT_framebuffer_multisample || GLAD_APPLE_framebuffer_multisample
  242. || GLAD_ANGLE_framebuffer_multisample)
  243. {
  244. glGetIntegerv(GL_MAX_SAMPLES, &maxRenderbufferSamples);
  245. }
  246. else
  247. maxRenderbufferSamples = 0;
  248. glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
  249. GLfloat limits[2];
  250. glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, limits);
  251. maxPointSize = limits[1];
  252. }
  253. void OpenGL::initMatrices()
  254. {
  255. matrices.transform.clear();
  256. matrices.projection.clear();
  257. matrices.transform.push_back(Matrix4());
  258. matrices.projection.push_back(Matrix4());
  259. }
  260. void OpenGL::createDefaultTexture()
  261. {
  262. // Set the 'default' texture (id 0) as a repeating white pixel. Otherwise,
  263. // texture2D calls inside a shader would return black when drawing graphics
  264. // primitives, which would create the need to use different "passthrough"
  265. // shaders for untextured primitives vs images.
  266. GLuint curtexture = state.boundTextures[state.curTextureUnit];
  267. glGenTextures(1, &state.defaultTexture);
  268. bindTexture(state.defaultTexture);
  269. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  270. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  271. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  272. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  273. GLubyte pix[] = {255, 255, 255, 255};
  274. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix);
  275. bindTexture(curtexture);
  276. }
  277. void OpenGL::pushTransform()
  278. {
  279. matrices.transform.push_back(matrices.transform.back());
  280. }
  281. void OpenGL::popTransform()
  282. {
  283. matrices.transform.pop_back();
  284. }
  285. Matrix4 &OpenGL::getTransform()
  286. {
  287. return matrices.transform.back();
  288. }
  289. void OpenGL::prepareDraw()
  290. {
  291. TempDebugGroup debuggroup("Prepare OpenGL draw");
  292. // Make sure the active shader's love-provided uniforms are up to date.
  293. if (Shader::current != nullptr)
  294. Shader::current->checkSetBuiltinUniforms();
  295. // We use glLoadMatrix rather than uniforms for our matrices when possible,
  296. // because uniform uploads can be significantly slower than glLoadMatrix.
  297. if (GLAD_VERSION_1_0)
  298. {
  299. const Matrix4 &curproj = matrices.projection.back();
  300. const Matrix4 &curxform = matrices.transform.back();
  301. const Matrix4 &lastproj = state.lastProjectionMatrix;
  302. const Matrix4 &lastxform = state.lastTransformMatrix;
  303. // We only need to re-upload the projection matrix if it's changed.
  304. if (memcmp(curproj.getElements(), lastproj.getElements(), sizeof(float) * 16) != 0)
  305. {
  306. glMatrixMode(GL_PROJECTION);
  307. glLoadMatrixf(curproj.getElements());
  308. glMatrixMode(GL_MODELVIEW);
  309. state.lastProjectionMatrix = matrices.projection.back();
  310. }
  311. // Same with the transform matrix.
  312. if (memcmp(curxform.getElements(), lastxform.getElements(), sizeof(float) * 16) != 0)
  313. {
  314. glLoadMatrixf(curxform.getElements());
  315. state.lastTransformMatrix = matrices.transform.back();
  316. }
  317. }
  318. }
  319. GLenum OpenGL::getGLBufferType(BufferType type)
  320. {
  321. switch (type)
  322. {
  323. case BUFFER_VERTEX:
  324. return GL_ARRAY_BUFFER;
  325. case BUFFER_INDEX:
  326. return GL_ELEMENT_ARRAY_BUFFER;
  327. case BUFFER_MAX_ENUM:
  328. return GL_ZERO;
  329. }
  330. }
  331. void OpenGL::bindBuffer(BufferType type, GLuint buffer)
  332. {
  333. if (state.boundBuffers[type] != buffer)
  334. {
  335. glBindBuffer(getGLBufferType(type), buffer);
  336. state.boundBuffers[type] = buffer;
  337. }
  338. }
  339. void OpenGL::deleteBuffer(GLuint buffer)
  340. {
  341. glDeleteBuffers(1, &buffer);
  342. for (int i = 0; i < (int) BUFFER_MAX_ENUM; i++)
  343. {
  344. if (state.boundBuffers[i] == buffer)
  345. state.boundBuffers[i] = 0;
  346. }
  347. }
  348. void OpenGL::drawArrays(GLenum mode, GLint first, GLsizei count)
  349. {
  350. glDrawArrays(mode, first, count);
  351. ++stats.drawCalls;
  352. }
  353. void OpenGL::drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)
  354. {
  355. glDrawElements(mode, count, type, indices);
  356. ++stats.drawCalls;
  357. }
  358. void OpenGL::useVertexAttribArrays(uint32 arraybits)
  359. {
  360. uint32 diff = arraybits ^ state.enabledAttribArrays;
  361. if (diff == 0)
  362. return;
  363. // Max 32 attributes. As of when this was written, no GL driver exposes more
  364. // than 32. Lets hope that doesn't change...
  365. for (uint32 i = 0; i < 32; i++)
  366. {
  367. uint32 bit = 1 << i;
  368. if (diff & bit)
  369. {
  370. if (arraybits & bit)
  371. glEnableVertexAttribArray(i);
  372. else
  373. glDisableVertexAttribArray(i);
  374. }
  375. }
  376. state.enabledAttribArrays = arraybits;
  377. // glDisableVertexAttribArray will make the constant value for a vertex
  378. // attribute undefined. We rely on the per-vertex color attribute being
  379. // white when no per-vertex color is used, so we set it here.
  380. // FIXME: Is there a better place to do this?
  381. if ((diff & ATTRIBFLAG_COLOR) && !(arraybits & ATTRIBFLAG_COLOR))
  382. glVertexAttrib4f(ATTRIB_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
  383. }
  384. void OpenGL::setViewport(const OpenGL::Viewport &v)
  385. {
  386. glViewport(v.x, v.y, v.w, v.h);
  387. state.viewport = v;
  388. // glScissor starts from the lower left, so we compensate when setting the
  389. // scissor. When the viewport is changed, we need to manually update the
  390. // scissor again.
  391. setScissor(state.scissor);
  392. }
  393. OpenGL::Viewport OpenGL::getViewport() const
  394. {
  395. return state.viewport;
  396. }
  397. void OpenGL::setScissor(const OpenGL::Viewport &v)
  398. {
  399. if (Canvas::current)
  400. glScissor(v.x, v.y, v.w, v.h);
  401. else
  402. {
  403. // With no Canvas active, we need to compensate for glScissor starting
  404. // from the lower left of the viewport instead of the top left.
  405. glScissor(v.x, state.viewport.h - (v.y + v.h), v.w, v.h);
  406. }
  407. state.scissor = v;
  408. }
  409. OpenGL::Viewport OpenGL::getScissor() const
  410. {
  411. return state.scissor;
  412. }
  413. void OpenGL::setPointSize(float size)
  414. {
  415. if (GLAD_VERSION_1_0)
  416. glPointSize(size);
  417. state.pointSize = size;
  418. }
  419. float OpenGL::getPointSize() const
  420. {
  421. return state.pointSize;
  422. }
  423. void OpenGL::setFramebufferSRGB(bool enable)
  424. {
  425. if (enable)
  426. glEnable(GL_FRAMEBUFFER_SRGB);
  427. else
  428. glDisable(GL_FRAMEBUFFER_SRGB);
  429. state.framebufferSRGBEnabled = enable;
  430. }
  431. bool OpenGL::hasFramebufferSRGB() const
  432. {
  433. return state.framebufferSRGBEnabled;
  434. }
  435. void OpenGL::bindFramebuffer(GLenum target, GLuint framebuffer)
  436. {
  437. glBindFramebuffer(target, framebuffer);
  438. if (target == GL_FRAMEBUFFER)
  439. ++stats.framebufferBinds;
  440. }
  441. void OpenGL::useProgram(GLuint program)
  442. {
  443. glUseProgram(program);
  444. ++stats.shaderSwitches;
  445. }
  446. GLuint OpenGL::getDefaultFBO() const
  447. {
  448. #ifdef LOVE_IOS
  449. // Hack: iOS uses a custom FBO.
  450. SDL_SysWMinfo info = {};
  451. SDL_VERSION(&info.version);
  452. SDL_GetWindowWMInfo(SDL_GL_GetCurrentWindow(), &info);
  453. return info.info.uikit.framebuffer;
  454. #else
  455. return 0;
  456. #endif
  457. }
  458. GLuint OpenGL::getDefaultTexture() const
  459. {
  460. return state.defaultTexture;
  461. }
  462. void OpenGL::setTextureUnit(int textureunit)
  463. {
  464. if (textureunit != state.curTextureUnit)
  465. glActiveTexture(GL_TEXTURE0 + textureunit);
  466. state.curTextureUnit = textureunit;
  467. }
  468. void OpenGL::bindTextureToUnit(GLuint texture, int textureunit, bool restoreprev)
  469. {
  470. if (texture != state.boundTextures[textureunit])
  471. {
  472. int oldtextureunit = state.curTextureUnit;
  473. if (oldtextureunit != textureunit)
  474. glActiveTexture(GL_TEXTURE0 + textureunit);
  475. state.boundTextures[textureunit] = texture;
  476. glBindTexture(GL_TEXTURE_2D, texture);
  477. if (restoreprev && oldtextureunit != textureunit)
  478. glActiveTexture(GL_TEXTURE0 + oldtextureunit);
  479. else
  480. state.curTextureUnit = textureunit;
  481. }
  482. }
  483. void OpenGL::deleteTexture(GLuint texture)
  484. {
  485. // glDeleteTextures binds texture 0 to all texture units the deleted texture
  486. // was bound to before deletion.
  487. for (GLuint &texid : state.boundTextures)
  488. {
  489. if (texid == texture)
  490. texid = 0;
  491. }
  492. glDeleteTextures(1, &texture);
  493. }
  494. void OpenGL::setTextureFilter(graphics::Texture::Filter &f)
  495. {
  496. GLint gmin, gmag;
  497. if (f.mipmap == Texture::FILTER_NONE)
  498. {
  499. if (f.min == Texture::FILTER_NEAREST)
  500. gmin = GL_NEAREST;
  501. else // f.min == Texture::FILTER_LINEAR
  502. gmin = GL_LINEAR;
  503. }
  504. else
  505. {
  506. if (f.min == Texture::FILTER_NEAREST && f.mipmap == Texture::FILTER_NEAREST)
  507. gmin = GL_NEAREST_MIPMAP_NEAREST;
  508. else if (f.min == Texture::FILTER_NEAREST && f.mipmap == Texture::FILTER_LINEAR)
  509. gmin = GL_NEAREST_MIPMAP_LINEAR;
  510. else if (f.min == Texture::FILTER_LINEAR && f.mipmap == Texture::FILTER_NEAREST)
  511. gmin = GL_LINEAR_MIPMAP_NEAREST;
  512. else if (f.min == Texture::FILTER_LINEAR && f.mipmap == Texture::FILTER_LINEAR)
  513. gmin = GL_LINEAR_MIPMAP_LINEAR;
  514. else
  515. gmin = GL_LINEAR;
  516. }
  517. switch (f.mag)
  518. {
  519. case Texture::FILTER_NEAREST:
  520. gmag = GL_NEAREST;
  521. break;
  522. case Texture::FILTER_LINEAR:
  523. default:
  524. gmag = GL_LINEAR;
  525. break;
  526. }
  527. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin);
  528. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag);
  529. if (GLAD_EXT_texture_filter_anisotropic)
  530. {
  531. f.anisotropy = std::min(std::max(f.anisotropy, 1.0f), maxAnisotropy);
  532. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, f.anisotropy);
  533. }
  534. else
  535. f.anisotropy = 1.0f;
  536. }
  537. GLint OpenGL::getGLWrapMode(Texture::WrapMode wmode)
  538. {
  539. switch (wmode)
  540. {
  541. case Texture::WRAP_CLAMP:
  542. default:
  543. return GL_CLAMP_TO_EDGE;
  544. case Texture::WRAP_CLAMP_ZERO:
  545. return GL_CLAMP_TO_BORDER;
  546. case Texture::WRAP_REPEAT:
  547. return GL_REPEAT;
  548. case Texture::WRAP_MIRRORED_REPEAT:
  549. return GL_MIRRORED_REPEAT;
  550. }
  551. }
  552. void OpenGL::setTextureWrap(const graphics::Texture::Wrap &w)
  553. {
  554. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, getGLWrapMode(w.s));
  555. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, getGLWrapMode(w.t));
  556. }
  557. bool OpenGL::isClampZeroTextureWrapSupported() const
  558. {
  559. return GLAD_VERSION_1_3 || GLAD_EXT_texture_border_clamp || GLAD_NV_texture_border_clamp;
  560. }
  561. int OpenGL::getMaxTextureSize() const
  562. {
  563. return maxTextureSize;
  564. }
  565. int OpenGL::getMaxRenderTargets() const
  566. {
  567. return maxRenderTargets;
  568. }
  569. int OpenGL::getMaxRenderbufferSamples() const
  570. {
  571. return maxRenderbufferSamples;
  572. }
  573. int OpenGL::getMaxTextureUnits() const
  574. {
  575. return maxTextureUnits;
  576. }
  577. float OpenGL::getMaxPointSize() const
  578. {
  579. return maxPointSize;
  580. }
  581. void OpenGL::updateTextureMemorySize(size_t oldsize, size_t newsize)
  582. {
  583. int64 memsize = (int64) stats.textureMemory + ((int64) newsize - (int64) oldsize);
  584. stats.textureMemory = (size_t) std::max(memsize, (int64) 0);
  585. }
  586. OpenGL::Vendor OpenGL::getVendor() const
  587. {
  588. return vendor;
  589. }
  590. const char *OpenGL::errorString(GLenum errorcode)
  591. {
  592. switch (errorcode)
  593. {
  594. case GL_NO_ERROR:
  595. return "no error";
  596. case GL_INVALID_ENUM:
  597. return "invalid enum";
  598. case GL_INVALID_VALUE:
  599. return "invalid value";
  600. case GL_INVALID_OPERATION:
  601. return "invalid operation";
  602. case GL_OUT_OF_MEMORY:
  603. return "out of memory";
  604. case GL_INVALID_FRAMEBUFFER_OPERATION:
  605. return "invalid framebuffer operation";
  606. case GL_CONTEXT_LOST:
  607. return "OpenGL context has been lost";
  608. default:
  609. break;
  610. }
  611. static char text[64] = {};
  612. memset(text, 0, sizeof(text));
  613. sprintf(text, "0x%x", errorcode);
  614. return text;
  615. }
  616. const char *OpenGL::debugSeverityString(GLenum severity)
  617. {
  618. switch (severity)
  619. {
  620. case GL_DEBUG_SEVERITY_HIGH:
  621. return "high";
  622. case GL_DEBUG_SEVERITY_MEDIUM:
  623. return "medium";
  624. case GL_DEBUG_SEVERITY_LOW:
  625. return "low";
  626. default:
  627. return "unknown";
  628. }
  629. }
  630. const char *OpenGL::debugSourceString(GLenum source)
  631. {
  632. switch (source)
  633. {
  634. case GL_DEBUG_SOURCE_API:
  635. return "API";
  636. case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
  637. return "window";
  638. case GL_DEBUG_SOURCE_SHADER_COMPILER:
  639. return "shader";
  640. case GL_DEBUG_SOURCE_THIRD_PARTY:
  641. return "external";
  642. case GL_DEBUG_SOURCE_APPLICATION:
  643. return "LOVE";
  644. case GL_DEBUG_SOURCE_OTHER:
  645. return "other";
  646. default:
  647. return "unknown";
  648. }
  649. }
  650. const char *OpenGL::debugTypeString(GLenum type)
  651. {
  652. switch (type)
  653. {
  654. case GL_DEBUG_TYPE_ERROR:
  655. return "error";
  656. case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
  657. return "deprecated behavior";
  658. case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
  659. return "undefined behavior";
  660. case GL_DEBUG_TYPE_PERFORMANCE:
  661. return "performance";
  662. case GL_DEBUG_TYPE_PORTABILITY:
  663. return "portability";
  664. case GL_DEBUG_TYPE_OTHER:
  665. return "other";
  666. default:
  667. return "unknown";
  668. }
  669. }
  670. // OpenGL class instance singleton.
  671. OpenGL gl;
  672. } // opengl
  673. } // graphics
  674. } // love