Graphics.cpp 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825
  1. /**
  2. * Copyright (c) 2006-2023 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 "common/math.h"
  23. #include "common/Vector.h"
  24. #include "Graphics.h"
  25. #include "font/Font.h"
  26. #include "StreamBuffer.h"
  27. #include "GraphicsReadback.h"
  28. #include "math/MathModule.h"
  29. #include "window/Window.h"
  30. #include "Buffer.h"
  31. #include "ShaderStage.h"
  32. #include "libraries/xxHash/xxhash.h"
  33. // C++
  34. #include <vector>
  35. #include <sstream>
  36. #include <algorithm>
  37. #include <iterator>
  38. // C
  39. #include <cmath>
  40. #include <cstdio>
  41. #ifdef LOVE_IOS
  42. #include <SDL_syswm.h>
  43. #endif
  44. namespace love
  45. {
  46. namespace graphics
  47. {
  48. namespace opengl
  49. {
  50. static GLenum getGLBlendOperation(BlendOperation op)
  51. {
  52. switch (op)
  53. {
  54. case BLENDOP_ADD: return GL_FUNC_ADD;
  55. case BLENDOP_SUBTRACT: return GL_FUNC_SUBTRACT;
  56. case BLENDOP_REVERSE_SUBTRACT: return GL_FUNC_REVERSE_SUBTRACT;
  57. case BLENDOP_MIN: return GL_MIN;
  58. case BLENDOP_MAX: return GL_MAX;
  59. case BLENDOP_MAX_ENUM: return 0;
  60. }
  61. return 0;
  62. }
  63. static GLenum getGLBlendFactor(BlendFactor factor)
  64. {
  65. switch (factor)
  66. {
  67. case BLENDFACTOR_ZERO: return GL_ZERO;
  68. case BLENDFACTOR_ONE: return GL_ONE;
  69. case BLENDFACTOR_SRC_COLOR: return GL_SRC_COLOR;
  70. case BLENDFACTOR_ONE_MINUS_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR;
  71. case BLENDFACTOR_SRC_ALPHA: return GL_SRC_ALPHA;
  72. case BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA;
  73. case BLENDFACTOR_DST_COLOR: return GL_DST_COLOR;
  74. case BLENDFACTOR_ONE_MINUS_DST_COLOR: return GL_ONE_MINUS_DST_COLOR;
  75. case BLENDFACTOR_DST_ALPHA: return GL_DST_ALPHA;
  76. case BLENDFACTOR_ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA;
  77. case BLENDFACTOR_SRC_ALPHA_SATURATED: return GL_SRC_ALPHA_SATURATE;
  78. case BLENDFACTOR_MAX_ENUM: return 0;
  79. }
  80. return 0;
  81. }
  82. love::graphics::Graphics *createInstance()
  83. {
  84. love::graphics::Graphics *instance = nullptr;
  85. try
  86. {
  87. instance = new Graphics();
  88. }
  89. catch (love::Exception &e)
  90. {
  91. printf("Cannot create OpenGL renderer: %s\n", e.what());
  92. }
  93. return instance;
  94. }
  95. Graphics::Graphics()
  96. : windowHasStencil(false)
  97. , mainVAO(0)
  98. , internalBackbufferFBO(0)
  99. , requestedBackbufferMSAA(0)
  100. , bufferMapMemory(nullptr)
  101. , bufferMapMemorySize(2 * 1024 * 1024)
  102. , defaultBuffers()
  103. , pixelFormatUsage()
  104. {
  105. gl = OpenGL();
  106. try
  107. {
  108. bufferMapMemory = new char[bufferMapMemorySize];
  109. }
  110. catch (std::exception &)
  111. {
  112. // Handled in getBufferMapMemory.
  113. }
  114. auto window = getInstance<love::window::Window>(M_WINDOW);
  115. if (window != nullptr)
  116. {
  117. window->setGraphics(this);
  118. // Recreate the window using the current renderer, if needed.
  119. if (window->isOpen())
  120. {
  121. int w, h;
  122. love::window::WindowSettings settings;
  123. window->getWindow(w, h, settings);
  124. window->setWindow(w, h, &settings);
  125. }
  126. }
  127. }
  128. Graphics::~Graphics()
  129. {
  130. delete[] bufferMapMemory;
  131. }
  132. const char *Graphics::getName() const
  133. {
  134. return "love.graphics.opengl";
  135. }
  136. love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferUsage type, size_t size)
  137. {
  138. return CreateStreamBuffer(type, size);
  139. }
  140. love::graphics::Texture *Graphics::newTexture(const Texture::Settings &settings, const Texture::Slices *data)
  141. {
  142. return new Texture(this, settings, data);
  143. }
  144. love::graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles)
  145. {
  146. return new ShaderStage(this, stage, source, gles, cachekey);
  147. }
  148. love::graphics::Shader *Graphics::newShaderInternal(StrongRef<love::graphics::ShaderStage> stages[SHADERSTAGE_MAX_ENUM])
  149. {
  150. return new Shader(stages);
  151. }
  152. love::graphics::Buffer *Graphics::newBuffer(const Buffer::Settings &settings, const std::vector<Buffer::DataDeclaration> &format, const void *data, size_t size, size_t arraylength)
  153. {
  154. return new Buffer(this, settings, format, data, size, arraylength);
  155. }
  156. love::graphics::GraphicsReadback *Graphics::newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset)
  157. {
  158. return new GraphicsReadback(this, method, buffer, offset, size, dest, destoffset);
  159. }
  160. love::graphics::GraphicsReadback *Graphics::newReadbackInternal(ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty)
  161. {
  162. return new GraphicsReadback(this, method, texture, slice, mipmap, rect, dest, destx, desty);
  163. }
  164. Matrix4 Graphics::computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const
  165. {
  166. uint32 flags = DEVICE_PROJECTION_DEFAULT;
  167. // The projection matrix is flipped compared to rendering to a texture, due
  168. // to OpenGL considering (0,0) bottom-left instead of top-left.
  169. if (!rendertotexture)
  170. flags |= DEVICE_PROJECTION_FLIP_Y;
  171. return calculateDeviceProjection(projection, flags);
  172. }
  173. void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight)
  174. {
  175. this->width = width;
  176. this->height = height;
  177. this->pixelWidth = pixelwidth;
  178. this->pixelHeight = pixelheight;
  179. if (!isRenderTargetActive())
  180. {
  181. // Set the viewport to top-left corner.
  182. gl.setViewport({0, 0, pixelwidth, pixelheight});
  183. // Re-apply the scissor if it was active, since the rectangle passed to
  184. // glScissor is affected by the viewport dimensions.
  185. if (states.back().scissor)
  186. setScissor(states.back().scissorRect);
  187. resetProjection();
  188. }
  189. updateBackbuffer(width, height, pixelwidth, pixelheight, requestedBackbufferMSAA);
  190. }
  191. void Graphics::updateBackbuffer(int width, int height, int /*pixelwidth*/, int pixelheight, int msaa)
  192. {
  193. bool useinternalbackbuffer = false;
  194. if (msaa > 1)
  195. useinternalbackbuffer = true;
  196. // Our internal backbuffer code needs glBlitFramebuffer.
  197. if (!(GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object || GLAD_ES_VERSION_3_0
  198. || GLAD_EXT_framebuffer_blit || GLAD_ANGLE_framebuffer_blit || GLAD_NV_framebuffer_blit))
  199. {
  200. if (!(msaa > 1 && GLAD_APPLE_framebuffer_multisample))
  201. useinternalbackbuffer = false;
  202. }
  203. GLuint prevFBO = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL);
  204. bool restoreFBO = prevFBO != getInternalBackbufferFBO();
  205. if (useinternalbackbuffer)
  206. {
  207. Texture::Settings settings;
  208. settings.width = width;
  209. settings.height = height;
  210. settings.dpiScale = (float)pixelheight / (float)height;
  211. settings.msaa = msaa;
  212. settings.renderTarget = true;
  213. settings.readable.set(false);
  214. settings.format = isGammaCorrect() ? PIXELFORMAT_RGBA8_sRGB : PIXELFORMAT_RGBA8_UNORM;
  215. internalBackbuffer.set(newTexture(settings), Acquire::NORETAIN);
  216. settings.format = PIXELFORMAT_DEPTH24_UNORM_STENCIL8;
  217. internalBackbufferDepthStencil.set(newTexture(settings), Acquire::NORETAIN);
  218. RenderTargets rts;
  219. rts.colors.push_back(internalBackbuffer.get());
  220. rts.depthStencil.texture = internalBackbufferDepthStencil;
  221. internalBackbufferFBO = bindCachedFBO(rts);
  222. }
  223. else
  224. {
  225. internalBackbuffer.set(nullptr);
  226. internalBackbufferDepthStencil.set(nullptr);
  227. internalBackbufferFBO = 0;
  228. }
  229. requestedBackbufferMSAA = msaa;
  230. if (restoreFBO)
  231. gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, prevFBO);
  232. }
  233. GLuint Graphics::getInternalBackbufferFBO() const
  234. {
  235. if (internalBackbufferFBO != 0)
  236. return internalBackbufferFBO;
  237. else
  238. return getSystemBackbufferFBO();
  239. }
  240. GLuint Graphics::getSystemBackbufferFBO() const
  241. {
  242. #ifdef LOVE_IOS
  243. // Hack: iOS uses a custom FBO.
  244. SDL_SysWMinfo info = {};
  245. SDL_VERSION(&info.version);
  246. SDL_GetWindowWMInfo(SDL_GL_GetCurrentWindow(), &info);
  247. if (info.info.uikit.resolveFramebuffer != 0)
  248. return info.info.uikit.resolveFramebuffer;
  249. else
  250. return info.info.uikit.framebuffer;
  251. #else
  252. return 0;
  253. #endif
  254. }
  255. bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa)
  256. {
  257. this->width = width;
  258. this->height = height;
  259. this->windowHasStencil = windowhasstencil;
  260. this->requestedBackbufferMSAA = msaa;
  261. // Okay, setup OpenGL.
  262. gl.initContext();
  263. if (gl.isCoreProfile())
  264. {
  265. glGenVertexArrays(1, &mainVAO);
  266. glBindVertexArray(mainVAO);
  267. }
  268. gl.setupContext();
  269. created = true;
  270. initCapabilities();
  271. // Enable blending
  272. gl.setEnableState(OpenGL::ENABLE_BLEND, true);
  273. // Auto-generated mipmaps should be the best quality possible
  274. if (!gl.isCoreProfile())
  275. glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
  276. if (!GLAD_ES_VERSION_2_0 && !gl.isCoreProfile())
  277. {
  278. // Make sure antialiasing works when set elsewhere
  279. glEnable(GL_MULTISAMPLE);
  280. // Enable texturing
  281. glEnable(GL_TEXTURE_2D);
  282. }
  283. if (!GLAD_ES_VERSION_2_0)
  284. glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
  285. gl.setTextureUnit(0);
  286. // Set pixel row alignment - code that calls glTexSubImage and glReadPixels
  287. // assumes there's no row alignment, but OpenGL defaults to 4 bytes.
  288. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  289. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  290. // Always enable seamless cubemap filtering when possible.
  291. if (GLAD_VERSION_3_2 || GLAD_ARB_seamless_cube_map)
  292. glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
  293. // Set whether drawing converts input from linear -> sRGB colorspace.
  294. if (!gl.bugs.brokenSRGB && (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB
  295. || GLAD_EXT_framebuffer_sRGB || GLAD_ES_VERSION_3_0))
  296. {
  297. if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
  298. gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, isGammaCorrect());
  299. }
  300. else
  301. setGammaCorrect(false);
  302. setDebug(isDebugEnabled());
  303. setViewportSize(width, height, pixelwidth, pixelheight);
  304. if (batchedDrawState.vb[0] == nullptr)
  305. {
  306. // Initial sizes that should be good enough for most cases. It will
  307. // resize to fit if needed, later.
  308. batchedDrawState.vb[0] = CreateStreamBuffer(BUFFERUSAGE_VERTEX, 1024 * 1024 * 1);
  309. batchedDrawState.vb[1] = CreateStreamBuffer(BUFFERUSAGE_VERTEX, 256 * 1024 * 1);
  310. batchedDrawState.indexBuffer = CreateStreamBuffer(BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
  311. }
  312. // TODO: one buffer each for float, int, uint
  313. if (capabilities.features[FEATURE_TEXEL_BUFFER] && defaultBuffers[BUFFERUSAGE_TEXEL].get() == nullptr)
  314. {
  315. Buffer::Settings settings(BUFFERUSAGEFLAG_TEXEL, BUFFERDATAUSAGE_STATIC);
  316. std::vector<Buffer::DataDeclaration> format = {{"", DATAFORMAT_FLOAT_VEC4, 0}};
  317. const float texel[] = {0.0f, 0.0f, 0.0f, 1.0f};
  318. auto buffer = newBuffer(settings, format, texel, sizeof(texel), 1);
  319. defaultBuffers[BUFFERUSAGE_TEXEL].set(buffer, Acquire::NORETAIN);
  320. }
  321. if (capabilities.features[FEATURE_GLSL4] && defaultBuffers[BUFFERUSAGE_SHADER_STORAGE].get() == nullptr)
  322. {
  323. Buffer::Settings settings(BUFFERUSAGEFLAG_SHADER_STORAGE, BUFFERDATAUSAGE_STATIC);
  324. std::vector<Buffer::DataDeclaration> format = {{"", DATAFORMAT_FLOAT, 0}};
  325. std::vector<float> data;
  326. data.resize(Buffer::SHADER_STORAGE_BUFFER_MAX_STRIDE / 4);
  327. auto buffer = newBuffer(settings, format, data.data(), data.size() * sizeof(float), data.size());
  328. defaultBuffers[BUFFERUSAGE_SHADER_STORAGE].set(buffer, Acquire::NORETAIN);
  329. }
  330. // Load default resources before other Volatile.
  331. for (int i = 0; i < BUFFERUSAGE_MAX_ENUM; i++)
  332. {
  333. if (defaultBuffers[i].get())
  334. ((Buffer *) defaultBuffers[i].get())->loadVolatile();
  335. }
  336. if (defaultBuffers[BUFFERUSAGE_TEXEL].get())
  337. gl.setDefaultTexelBuffer((GLuint) defaultBuffers[BUFFERUSAGE_TEXEL]->getTexelBufferHandle());
  338. if (defaultBuffers[BUFFERUSAGE_SHADER_STORAGE].get())
  339. gl.setDefaultStorageBuffer((GLuint) defaultBuffers[BUFFERUSAGE_SHADER_STORAGE]->getHandle());
  340. // Reload all volatile objects.
  341. if (!Volatile::loadAll())
  342. ::printf("Could not reload all volatile objects.\n");
  343. createQuadIndexBuffer();
  344. // Restore the graphics state.
  345. restoreState(states.back());
  346. // We always need a default shader.
  347. for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++)
  348. {
  349. auto stype = (Shader::StandardShader) i;
  350. if (i == Shader::STANDARD_ARRAY && !capabilities.textureTypes[TEXTURE_2D_ARRAY])
  351. continue;
  352. // Apparently some intel GMA drivers on windows fail to compile shaders
  353. // which use array textures despite claiming support for the extension.
  354. try
  355. {
  356. if (!Shader::standardShaders[i])
  357. {
  358. std::vector<std::string> stages;
  359. Shader::CompileOptions opts;
  360. stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_VERTEX));
  361. stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_PIXEL));
  362. Shader::standardShaders[i] = newShader(stages, opts);
  363. }
  364. }
  365. catch (love::Exception &)
  366. {
  367. if (i == Shader::STANDARD_ARRAY)
  368. capabilities.textureTypes[TEXTURE_2D_ARRAY] = false;
  369. else
  370. throw;
  371. }
  372. }
  373. // A shader should always be active, but the default shader shouldn't be
  374. // returned by getShader(), so we don't do setShader(defaultShader).
  375. if (!Shader::current)
  376. Shader::standardShaders[Shader::STANDARD_DEFAULT]->attach();
  377. return true;
  378. }
  379. void Graphics::unSetMode()
  380. {
  381. if (!isCreated())
  382. return;
  383. flushBatchedDraws();
  384. internalBackbuffer.set(nullptr);
  385. internalBackbufferDepthStencil.set(nullptr);
  386. // Unload all volatile objects. These must be reloaded after the display
  387. // mode change.
  388. Volatile::unloadAll();
  389. clearTemporaryResources();
  390. for (const auto &pair : framebufferObjects)
  391. gl.deleteFramebuffer(pair.second);
  392. framebufferObjects.clear();
  393. if (mainVAO != 0)
  394. {
  395. glDeleteVertexArrays(1, &mainVAO);
  396. mainVAO = 0;
  397. }
  398. gl.deInitContext();
  399. created = false;
  400. }
  401. void Graphics::setActive(bool enable)
  402. {
  403. flushBatchedDraws();
  404. // Make sure all pending OpenGL commands have fully executed before
  405. // returning, when going from active to inactive. This is required on iOS.
  406. if (isCreated() && this->active && !enable)
  407. glFinish();
  408. active = enable;
  409. }
  410. static bool computeDispatchBarriers(Shader *shader, GLbitfield &preDispatchBarriers, GLbitfield &postDispatchBarriers)
  411. {
  412. for (auto buffer : shader->getActiveWritableStorageBuffers())
  413. {
  414. if (buffer == nullptr)
  415. return false;
  416. auto usage = buffer->getUsageFlags();
  417. postDispatchBarriers |= GL_BUFFER_UPDATE_BARRIER_BIT;
  418. if (usage & BUFFERUSAGEFLAG_SHADER_STORAGE)
  419. {
  420. preDispatchBarriers |= GL_SHADER_STORAGE_BARRIER_BIT;
  421. postDispatchBarriers |= GL_SHADER_STORAGE_BARRIER_BIT;
  422. }
  423. // TODO: does this need a pre dispatch barrier too?
  424. if (usage & BUFFERUSAGEFLAG_INDIRECT_ARGUMENTS)
  425. postDispatchBarriers |= GL_COMMAND_BARRIER_BIT;
  426. if (usage & BUFFERUSAGEFLAG_TEXEL)
  427. postDispatchBarriers |= GL_TEXTURE_FETCH_BARRIER_BIT;
  428. if (usage & BUFFERUSAGEFLAG_INDEX)
  429. postDispatchBarriers |= GL_ELEMENT_ARRAY_BARRIER_BIT;
  430. if (usage & BUFFERUSAGEFLAG_VERTEX)
  431. postDispatchBarriers |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
  432. postDispatchBarriers |= GL_PIXEL_BUFFER_BARRIER_BIT;
  433. }
  434. for (const auto &binding : shader->getStorageTextureBindings())
  435. {
  436. if (binding.texture == nullptr)
  437. return false;
  438. if (binding.access == GL_READ_ONLY)
  439. continue;
  440. preDispatchBarriers |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
  441. postDispatchBarriers |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
  442. | GL_TEXTURE_UPDATE_BARRIER_BIT
  443. | GL_TEXTURE_FETCH_BARRIER_BIT;
  444. if (binding.texture->isRenderTarget())
  445. postDispatchBarriers |= GL_FRAMEBUFFER_BARRIER_BIT;
  446. }
  447. return true;
  448. }
  449. bool Graphics::dispatch(love::graphics::Shader *s, int x, int y, int z)
  450. {
  451. auto shader = (Shader *) s;
  452. GLbitfield preDispatchBarriers = 0;
  453. GLbitfield postDispatchBarriers = 0;
  454. if (!computeDispatchBarriers(shader, preDispatchBarriers, postDispatchBarriers))
  455. return false;
  456. // glMemoryBarrier before dispatch to make sure non-compute-read ->
  457. // compute-write is synced.
  458. // TODO: is this needed? spec language around GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
  459. // makes me think so.
  460. // This is overly conservative (dispatch -> dispatch will have redundant
  461. // barriers).
  462. if (preDispatchBarriers != 0)
  463. glMemoryBarrier(preDispatchBarriers);
  464. glDispatchCompute(x, y, z);
  465. // Not as (theoretically) efficient as issuing the barrier right before
  466. // they're used later, but much less complicated.
  467. if (postDispatchBarriers != 0)
  468. glMemoryBarrier(postDispatchBarriers);
  469. return true;
  470. }
  471. bool Graphics::dispatch(love::graphics::Shader *s, love::graphics::Buffer *indirectargs, size_t argsoffset)
  472. {
  473. auto shader = (Shader *) s;
  474. GLbitfield preDispatchBarriers = 0;
  475. GLbitfield postDispatchBarriers = 0;
  476. if (!computeDispatchBarriers(shader, preDispatchBarriers, postDispatchBarriers))
  477. return false;
  478. if (preDispatchBarriers != 0)
  479. glMemoryBarrier(preDispatchBarriers);
  480. // Note: OpenGL has separate bind points for draw versus dispatch indirect
  481. // buffers. Our gl.bindBuffer wrapper uses the draw bind point, so we can't
  482. // use it here.
  483. glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, (GLuint)indirectargs->getHandle());
  484. glDispatchComputeIndirect(argsoffset);
  485. // Not as (theoretically) efficient as issuing the barrier right before
  486. // they're used later, but much less complicated.
  487. if (postDispatchBarriers != 0)
  488. glMemoryBarrier(postDispatchBarriers);
  489. return true;
  490. }
  491. void Graphics::draw(const DrawCommand &cmd)
  492. {
  493. gl.prepareDraw(this);
  494. gl.setVertexAttributes(*cmd.attributes, *cmd.buffers);
  495. gl.bindTextureToUnit(cmd.texture, 0, false);
  496. gl.setCullMode(cmd.cullMode);
  497. GLenum glprimitivetype = OpenGL::getGLPrimitiveType(cmd.primitiveType);
  498. if (cmd.indirectBuffer != nullptr)
  499. {
  500. gl.bindBuffer(BUFFERUSAGE_INDIRECT_ARGUMENTS, (GLuint) cmd.indirectBuffer->getHandle());
  501. glDrawArraysIndirect(glprimitivetype, BUFFER_OFFSET(cmd.indirectBufferOffset));
  502. }
  503. else if (cmd.instanceCount > 1)
  504. glDrawArraysInstanced(glprimitivetype, cmd.vertexStart, cmd.vertexCount, cmd.instanceCount);
  505. else
  506. glDrawArrays(glprimitivetype, cmd.vertexStart, cmd.vertexCount);
  507. ++drawCalls;
  508. }
  509. void Graphics::draw(const DrawIndexedCommand &cmd)
  510. {
  511. gl.prepareDraw(this);
  512. gl.setVertexAttributes(*cmd.attributes, *cmd.buffers);
  513. gl.bindTextureToUnit(cmd.texture, 0, false);
  514. gl.setCullMode(cmd.cullMode);
  515. const void *gloffset = BUFFER_OFFSET(cmd.indexBufferOffset);
  516. GLenum glprimitivetype = OpenGL::getGLPrimitiveType(cmd.primitiveType);
  517. GLenum gldatatype = OpenGL::getGLIndexDataType(cmd.indexType);
  518. gl.bindBuffer(BUFFERUSAGE_INDEX, cmd.indexBuffer->getHandle());
  519. if (cmd.indirectBuffer != nullptr)
  520. {
  521. // Note: OpenGL doesn't support indirect indexed draws with a non-zero
  522. // index buffer offset.
  523. gl.bindBuffer(BUFFERUSAGE_INDIRECT_ARGUMENTS, (GLuint) cmd.indirectBuffer->getHandle());
  524. glDrawElementsIndirect(glprimitivetype, gldatatype, BUFFER_OFFSET(cmd.indirectBufferOffset));
  525. }
  526. else if (cmd.instanceCount > 1)
  527. glDrawElementsInstanced(glprimitivetype, cmd.indexCount, gldatatype, gloffset, cmd.instanceCount);
  528. else
  529. glDrawElements(glprimitivetype, cmd.indexCount, gldatatype, gloffset);
  530. ++drawCalls;
  531. }
  532. static inline void advanceVertexOffsets(const VertexAttributes &attributes, BufferBindings &buffers, int vertexcount)
  533. {
  534. // TODO: Figure out a better way to avoid touching the same buffer multiple
  535. // times, if multiple attributes share the buffer.
  536. uint32 touchedbuffers = 0;
  537. for (unsigned int i = 0; i < VertexAttributes::MAX; i++)
  538. {
  539. if (!attributes.isEnabled(i))
  540. continue;
  541. auto &attrib = attributes.attribs[i];
  542. uint32 bufferbit = 1u << attrib.bufferIndex;
  543. if ((touchedbuffers & bufferbit) == 0)
  544. {
  545. touchedbuffers |= bufferbit;
  546. const auto &layout = attributes.bufferLayouts[attrib.bufferIndex];
  547. buffers.info[attrib.bufferIndex].offset += layout.stride * vertexcount;
  548. }
  549. }
  550. }
  551. void Graphics::drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, love::graphics::Texture *texture)
  552. {
  553. const int MAX_VERTICES_PER_DRAW = LOVE_UINT16_MAX;
  554. const int MAX_QUADS_PER_DRAW = MAX_VERTICES_PER_DRAW / 4;
  555. gl.prepareDraw(this);
  556. gl.bindTextureToUnit(texture, 0, false);
  557. gl.setCullMode(CULL_NONE);
  558. gl.bindBuffer(BUFFERUSAGE_INDEX, quadIndexBuffer->getHandle());
  559. if (gl.isBaseVertexSupported())
  560. {
  561. gl.setVertexAttributes(attributes, buffers);
  562. int basevertex = start * 4;
  563. for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW)
  564. {
  565. int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex);
  566. glDrawElementsBaseVertex(GL_TRIANGLES, quadcount * 6, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0), basevertex);
  567. ++drawCalls;
  568. basevertex += quadcount * 4;
  569. }
  570. }
  571. else
  572. {
  573. BufferBindings bufferscopy = buffers;
  574. if (start > 0)
  575. advanceVertexOffsets(attributes, bufferscopy, start * 4);
  576. for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW)
  577. {
  578. gl.setVertexAttributes(attributes, bufferscopy);
  579. int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex);
  580. glDrawElements(GL_TRIANGLES, quadcount * 6, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));
  581. ++drawCalls;
  582. if (count > MAX_QUADS_PER_DRAW)
  583. advanceVertexOffsets(attributes, bufferscopy, quadcount * 4);
  584. }
  585. }
  586. }
  587. static void APIENTRY debugCB(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /*len*/, const GLchar *msg, const GLvoid* /*usr*/)
  588. {
  589. // Human-readable strings for the debug info.
  590. const char *sourceStr = OpenGL::debugSourceString(source);
  591. const char *typeStr = OpenGL::debugTypeString(type);
  592. const char *severityStr = OpenGL::debugSeverityString(severity);
  593. const char *fmt = "OpenGL: %s [source=%s, type=%s, severity=%s, id=%d]\n";
  594. printf(fmt, msg, sourceStr, typeStr, severityStr, id);
  595. }
  596. void Graphics::setDebug(bool enable)
  597. {
  598. // Make sure debug output is supported. The AMD ext. is a bit different
  599. // so we don't make use of it, since AMD drivers now support KHR_debug.
  600. if (!(GLAD_VERSION_4_3 || GLAD_KHR_debug || GLAD_ARB_debug_output))
  601. return;
  602. // TODO: We don't support GL_KHR_debug in GLES yet.
  603. if (GLAD_ES_VERSION_2_0)
  604. return;
  605. // Ugly hack to reduce code duplication.
  606. if (GLAD_ARB_debug_output && !(GLAD_VERSION_4_3 || GLAD_KHR_debug))
  607. {
  608. fp_glDebugMessageCallback = (pfn_glDebugMessageCallback) fp_glDebugMessageCallbackARB;
  609. fp_glDebugMessageControl = (pfn_glDebugMessageControl) fp_glDebugMessageControlARB;
  610. }
  611. if (!enable)
  612. {
  613. // Disable the debug callback function.
  614. glDebugMessageCallback(nullptr, nullptr);
  615. // We can disable debug output entirely with KHR_debug.
  616. if (GLAD_VERSION_4_3 || GLAD_KHR_debug)
  617. glDisable(GL_DEBUG_OUTPUT);
  618. return;
  619. }
  620. // We don't want asynchronous debug output.
  621. glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
  622. glDebugMessageCallback(debugCB, nullptr);
  623. // Initially, enable everything.
  624. glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
  625. // Disable messages about deprecated OpenGL functionality.
  626. glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE);
  627. glDebugMessageControl(GL_DEBUG_SOURCE_SHADER_COMPILER, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE);
  628. if (GLAD_VERSION_4_3 || GLAD_KHR_debug)
  629. glEnable(GL_DEBUG_OUTPUT);
  630. ::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)\n");
  631. }
  632. void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture)
  633. {
  634. const DisplayState &state = states.back();
  635. OpenGL::TempDebugGroup debuggroup("setRenderTargets");
  636. endPass(false);
  637. bool iswindow = rts.getFirstTarget().texture == nullptr;
  638. Winding vertexwinding = state.winding;
  639. if (iswindow)
  640. {
  641. gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, getInternalBackbufferFBO());
  642. }
  643. else
  644. {
  645. bindCachedFBO(rts);
  646. // Flip front face winding when rendering to a texture, since our
  647. // projection matrix is flipped.
  648. // Note: projection matrix is set at a higher level.
  649. vertexwinding = vertexwinding == WINDING_CW ? WINDING_CCW : WINDING_CW;
  650. }
  651. glFrontFace(vertexwinding == WINDING_CW ? GL_CW : GL_CCW);
  652. gl.setViewport({0, 0, pixelw, pixelh});
  653. // Re-apply the scissor if it was active, since the rectangle passed to
  654. // glScissor is affected by the viewport dimensions.
  655. if (state.scissor)
  656. setScissor(state.scissorRect);
  657. // Make sure the correct sRGB setting is used when drawing to the textures.
  658. if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
  659. {
  660. if (hasSRGBtexture != gl.isStateEnabled(OpenGL::ENABLE_FRAMEBUFFER_SRGB))
  661. gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, hasSRGBtexture);
  662. }
  663. }
  664. void Graphics::endPass(bool presenting)
  665. {
  666. auto &rts = states.back().renderTargets;
  667. love::graphics::Texture *depthstencil = rts.depthStencil.texture.get();
  668. // Discard the depth/stencil buffer if we're using an internal cached one,
  669. // or if we're presenting the backbuffer to the display.
  670. if ((depthstencil == nullptr && (rts.temporaryRTFlags & (TEMPORARY_RT_DEPTH | TEMPORARY_RT_STENCIL)) != 0)
  671. || (presenting && !rts.getFirstTarget().texture.get()))
  672. {
  673. discard({}, true);
  674. }
  675. // Resolve MSAA buffers. MSAA is only supported for 2D render targets so we
  676. // don't have to worry about resolving to slices.
  677. if (rts.colors.size() > 0 && rts.colors[0].texture->getMSAA() > 1)
  678. {
  679. int mip = rts.colors[0].mipmap;
  680. int w = rts.colors[0].texture->getPixelWidth(mip);
  681. int h = rts.colors[0].texture->getPixelHeight(mip);
  682. for (int i = 0; i < (int) rts.colors.size(); i++)
  683. {
  684. Texture *c = (Texture *) rts.colors[i].texture.get();
  685. if (!c->isReadable())
  686. continue;
  687. glReadBuffer(GL_COLOR_ATTACHMENT0 + i);
  688. gl.bindFramebuffer(OpenGL::FRAMEBUFFER_DRAW, c->getFBO());
  689. if (GLAD_APPLE_framebuffer_multisample)
  690. glResolveMultisampleFramebufferAPPLE();
  691. else
  692. glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
  693. }
  694. }
  695. if (depthstencil != nullptr && depthstencil->getMSAA() > 1 && depthstencil->isReadable())
  696. {
  697. gl.bindFramebuffer(OpenGL::FRAMEBUFFER_DRAW, ((Texture *) depthstencil)->getFBO());
  698. if (GLAD_APPLE_framebuffer_multisample)
  699. glResolveMultisampleFramebufferAPPLE();
  700. else
  701. {
  702. int mip = rts.depthStencil.mipmap;
  703. int w = depthstencil->getPixelWidth(mip);
  704. int h = depthstencil->getPixelHeight(mip);
  705. PixelFormat format = depthstencil->getPixelFormat();
  706. GLbitfield mask = 0;
  707. if (isPixelFormatDepth(format))
  708. mask |= GL_DEPTH_BUFFER_BIT;
  709. if (isPixelFormatStencil(format))
  710. mask |= GL_STENCIL_BUFFER_BIT;
  711. if (mask != 0)
  712. glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, mask, GL_NEAREST);
  713. }
  714. }
  715. // generateMipmaps can't be used for depth/stencil textures.
  716. for (const auto &rt : rts.colors)
  717. {
  718. if (rt.texture->getMipmapsMode() == Texture::MIPMAPS_AUTO && rt.mipmap == 0)
  719. rt.texture->generateMipmaps();
  720. }
  721. }
  722. void Graphics::clear(OptionalColorD c, OptionalInt stencil, OptionalDouble depth)
  723. {
  724. if (c.hasValue)
  725. {
  726. bool hasintegerformat = false;
  727. const auto &rts = states.back().renderTargets;
  728. for (const auto &rt : rts.colors)
  729. {
  730. if (rt.texture.get() && isPixelFormatInteger(rt.texture->getPixelFormat()))
  731. hasintegerformat = true;
  732. }
  733. // This variant of clear() uses glClear() which can't clear integer formats,
  734. // so we switch to the MRT variant if needed.
  735. if (hasintegerformat)
  736. {
  737. std::vector<OptionalColorD> colors(rts.colors.size());
  738. for (size_t i = 0; i < colors.size(); i++)
  739. colors[i] = c;
  740. clear(colors, stencil, depth);
  741. return;
  742. }
  743. }
  744. if (c.hasValue || stencil.hasValue || depth.hasValue)
  745. flushBatchedDraws();
  746. GLbitfield flags = 0;
  747. if (c.hasValue)
  748. {
  749. Colorf cf((float)c.value.r, (float)c.value.g, (float)c.value.b, (float)c.value.a);
  750. gammaCorrectColor(cf);
  751. glClearColor(cf.r, cf.g, cf.b, cf.a);
  752. flags |= GL_COLOR_BUFFER_BIT;
  753. }
  754. if (stencil.hasValue)
  755. {
  756. glClearStencil(stencil.value);
  757. flags |= GL_STENCIL_BUFFER_BIT;
  758. }
  759. if (depth.hasValue)
  760. {
  761. gl.clearDepth(depth.value);
  762. flags |= GL_DEPTH_BUFFER_BIT;
  763. }
  764. if (flags != 0)
  765. {
  766. OpenGL::CleanClearState cs(flags);
  767. glClear(flags);
  768. }
  769. if (c.hasValue && gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current)
  770. {
  771. // This seems to be enough to fix the bug for me. Other methods I've
  772. // tried (e.g. dummy draws) don't work in all cases.
  773. gl.useProgram(0);
  774. gl.useProgram((GLuint) Shader::current->getHandle());
  775. }
  776. }
  777. void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth)
  778. {
  779. if (colors.size() == 0 && !stencil.hasValue && !depth.hasValue)
  780. return;
  781. const auto &rts = states.back().renderTargets.colors;
  782. int ncolorRTs = (int) rts.size();
  783. int ncolors = (int) colors.size();
  784. if (ncolors <= 1 && (ncolorRTs == 0 || (ncolorRTs == 1 && rts[0].texture != nullptr && !isPixelFormatInteger(rts[0].texture->getPixelFormat()))))
  785. {
  786. clear(ncolors > 0 ? colors[0] : OptionalColorD(), stencil, depth);
  787. return;
  788. }
  789. flushBatchedDraws();
  790. bool drawbuffersmodified = false;
  791. ncolors = std::min(ncolors, ncolorRTs);
  792. for (int i = 0; i < ncolors; i++)
  793. {
  794. if (!colors[i].hasValue)
  795. continue;
  796. PixelFormatType datatype = PIXELFORMATTYPE_UNORM;
  797. if (rts[i].texture != nullptr)
  798. datatype = getPixelFormatInfo(rts[i].texture->getPixelFormat()).dataType;
  799. ColorD c = colors[i].value;
  800. if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0)
  801. {
  802. if (datatype == PIXELFORMATTYPE_SINT)
  803. {
  804. const GLint carray[] = {(GLint)c.r, (GLint)c.g, (GLint)c.b, (GLint)c.a};
  805. glClearBufferiv(GL_COLOR, i, carray);
  806. }
  807. else if (datatype == PIXELFORMATTYPE_UINT)
  808. {
  809. const GLuint carray[] = {(GLuint)c.r, (GLuint)c.g, (GLuint)c.b, (GLuint)c.a};
  810. glClearBufferuiv(GL_COLOR, i, carray);
  811. }
  812. else
  813. {
  814. Colorf cf((float)c.r, (float)c.g, (float)c.b, (float)c.a);
  815. gammaCorrectColor(cf);
  816. const GLfloat carray[] = {cf.r, cf.g, cf.b, cf.a};
  817. glClearBufferfv(GL_COLOR, i, carray);
  818. }
  819. }
  820. else
  821. {
  822. Colorf cf((float)c.r, (float)c.g, (float)c.b, (float)c.a);
  823. gammaCorrectColor(cf);
  824. glDrawBuffer(GL_COLOR_ATTACHMENT0 + i);
  825. glClearColor(cf.r, cf.g, cf.b, cf.a);
  826. glClear(GL_COLOR_BUFFER_BIT);
  827. drawbuffersmodified = true;
  828. }
  829. }
  830. // Revert to the expected draw buffers once we're done, if glClearBuffer
  831. // wasn't supported.
  832. if (drawbuffersmodified)
  833. {
  834. GLenum bufs[MAX_COLOR_RENDER_TARGETS];
  835. for (int i = 0; i < ncolorRTs; i++)
  836. bufs[i] = GL_COLOR_ATTACHMENT0 + i;
  837. glDrawBuffers(ncolorRTs, bufs);
  838. }
  839. GLbitfield flags = 0;
  840. if (stencil.hasValue)
  841. {
  842. glClearStencil(stencil.value);
  843. flags |= GL_STENCIL_BUFFER_BIT;
  844. }
  845. if (depth.hasValue)
  846. {
  847. gl.clearDepth(depth.value);
  848. flags |= GL_DEPTH_BUFFER_BIT;
  849. }
  850. if (flags != 0)
  851. {
  852. OpenGL::CleanClearState cs(flags);
  853. glClear(flags);
  854. }
  855. if (gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current)
  856. {
  857. // This seems to be enough to fix the bug for me. Other methods I've
  858. // tried (e.g. dummy draws) don't work in all cases.
  859. gl.useProgram(0);
  860. gl.useProgram((GLuint) Shader::current->getHandle());
  861. }
  862. }
  863. void Graphics::discard(const std::vector<bool> &colorbuffers, bool depthstencil)
  864. {
  865. flushBatchedDraws();
  866. discard(OpenGL::FRAMEBUFFER_ALL, colorbuffers, depthstencil);
  867. }
  868. void Graphics::discard(OpenGL::FramebufferTarget target, const std::vector<bool> &colorbuffers, bool depthstencil)
  869. {
  870. if (!(GLAD_VERSION_4_3 || GLAD_ARB_invalidate_subdata || GLAD_ES_VERSION_3_0 || GLAD_EXT_discard_framebuffer))
  871. return;
  872. GLenum gltarget = GL_FRAMEBUFFER;
  873. if (target == OpenGL::FRAMEBUFFER_READ)
  874. gltarget = GL_READ_FRAMEBUFFER;
  875. else if (target == OpenGL::FRAMEBUFFER_DRAW)
  876. gltarget = GL_DRAW_FRAMEBUFFER;
  877. std::vector<GLenum> attachments;
  878. attachments.reserve(colorbuffers.size());
  879. // glDiscardFramebuffer uses different attachment enums for the default FBO.
  880. if (!isRenderTargetActive() && getInternalBackbufferFBO() == 0)
  881. {
  882. if (colorbuffers.size() > 0 && colorbuffers[0])
  883. attachments.push_back(GL_COLOR);
  884. if (depthstencil)
  885. {
  886. attachments.push_back(GL_STENCIL);
  887. attachments.push_back(GL_DEPTH);
  888. }
  889. }
  890. else
  891. {
  892. int rendertargetcount = std::max((int) states.back().renderTargets.colors.size(), 1);
  893. for (int i = 0; i < (int) colorbuffers.size(); i++)
  894. {
  895. if (colorbuffers[i] && i < rendertargetcount)
  896. attachments.push_back(GL_COLOR_ATTACHMENT0 + i);
  897. }
  898. if (depthstencil)
  899. {
  900. attachments.push_back(GL_STENCIL_ATTACHMENT);
  901. attachments.push_back(GL_DEPTH_ATTACHMENT);
  902. }
  903. }
  904. // Hint for the driver that it doesn't need to save these buffers.
  905. if (GLAD_VERSION_4_3 || GLAD_ARB_invalidate_subdata || GLAD_ES_VERSION_3_0)
  906. glInvalidateFramebuffer(gltarget, (GLint) attachments.size(), &attachments[0]);
  907. else if (GLAD_EXT_discard_framebuffer)
  908. glDiscardFramebufferEXT(gltarget, (GLint) attachments.size(), &attachments[0]);
  909. }
  910. void Graphics::cleanupRenderTexture(love::graphics::Texture *texture)
  911. {
  912. if (!texture->isRenderTarget())
  913. return;
  914. for (auto it = framebufferObjects.begin(); it != framebufferObjects.end(); /**/)
  915. {
  916. bool hastexture = false;
  917. const auto &rts = it->first;
  918. for (const RenderTarget &rt : rts.colors)
  919. {
  920. if (rt.texture == texture)
  921. {
  922. hastexture = true;
  923. break;
  924. }
  925. }
  926. hastexture = hastexture || rts.depthStencil.texture == texture;
  927. if (hastexture)
  928. {
  929. if (isCreated())
  930. gl.deleteFramebuffer(it->second);
  931. it = framebufferObjects.erase(it);
  932. }
  933. else
  934. ++it;
  935. }
  936. }
  937. GLuint Graphics::bindCachedFBO(const RenderTargets &targets)
  938. {
  939. GLuint fbo = framebufferObjects[targets];
  940. if (fbo != 0)
  941. {
  942. gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, fbo);
  943. }
  944. else
  945. {
  946. int msaa = targets.getFirstTarget().texture->getMSAA();
  947. bool hasDS = targets.depthStencil.texture != nullptr;
  948. glGenFramebuffers(1, &fbo);
  949. gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, fbo);
  950. int ncolortargets = 0;
  951. GLenum drawbuffers[MAX_COLOR_RENDER_TARGETS];
  952. auto attachRT = [&](const RenderTarget &rt)
  953. {
  954. bool renderbuffer = msaa > 1 || !rt.texture->isReadable();
  955. OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(rt.texture->getPixelFormat(), renderbuffer);
  956. if (fmt.framebufferAttachments[0] == GL_COLOR_ATTACHMENT0)
  957. {
  958. fmt.framebufferAttachments[0] = GL_COLOR_ATTACHMENT0 + ncolortargets;
  959. drawbuffers[ncolortargets] = fmt.framebufferAttachments[0];
  960. ncolortargets++;
  961. }
  962. GLuint handle = (GLuint) rt.texture->getRenderTargetHandle();
  963. for (GLenum attachment : fmt.framebufferAttachments)
  964. {
  965. if (attachment == GL_NONE)
  966. continue;
  967. else if (renderbuffer)
  968. glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, handle);
  969. else
  970. {
  971. TextureType textype = rt.texture->getTextureType();
  972. int layer = textype == TEXTURE_CUBE ? 0 : rt.slice;
  973. int face = textype == TEXTURE_CUBE ? rt.slice : 0;
  974. int level = rt.mipmap;
  975. gl.framebufferTexture(attachment, textype, handle, level, layer, face);
  976. }
  977. }
  978. };
  979. for (const auto &rt : targets.colors)
  980. attachRT(rt);
  981. if (hasDS)
  982. attachRT(targets.depthStencil);
  983. if (ncolortargets > 1)
  984. glDrawBuffers(ncolortargets, drawbuffers);
  985. else if (ncolortargets == 0 && hasDS && (GLAD_ES_VERSION_3_0 || !GLAD_ES_VERSION_2_0))
  986. {
  987. // glDrawBuffers is an ext in GL2. glDrawBuffer doesn't exist in ES3.
  988. GLenum none = GL_NONE;
  989. if (GLAD_ES_VERSION_3_0)
  990. glDrawBuffers(1, &none);
  991. else
  992. glDrawBuffer(GL_NONE);
  993. glReadBuffer(GL_NONE);
  994. }
  995. GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  996. if (status != GL_FRAMEBUFFER_COMPLETE)
  997. {
  998. gl.deleteFramebuffer(fbo);
  999. const char *sstr = OpenGL::framebufferStatusString(status);
  1000. throw love::Exception("Could not create Framebuffer Object! %s", sstr);
  1001. }
  1002. framebufferObjects[targets] = fbo;
  1003. }
  1004. return fbo;
  1005. }
  1006. void Graphics::present(void *screenshotCallbackData)
  1007. {
  1008. if (!isActive())
  1009. return;
  1010. if (isRenderTargetActive())
  1011. throw love::Exception("present cannot be called while a render target is active.");
  1012. deprecations.draw(this);
  1013. flushBatchedDraws();
  1014. endPass(true);
  1015. int w = getPixelWidth();
  1016. int h = getPixelHeight();
  1017. gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, getInternalBackbufferFBO());
  1018. // Copy internal backbuffer to system backbuffer. When MSAA is used this
  1019. // is a direct MSAA resolve.
  1020. if (internalBackbuffer.get())
  1021. {
  1022. gl.bindFramebuffer(OpenGL::FRAMEBUFFER_DRAW, getSystemBackbufferFBO());
  1023. // Discard system backbuffer to prevent it from copying its contents
  1024. // from VRAM to chip memory.
  1025. discard(OpenGL::FRAMEBUFFER_DRAW, {true}, true);
  1026. // updateBackbuffer checks for glBlitFramebuffer support.
  1027. if (GLAD_APPLE_framebuffer_multisample && internalBackbuffer->getMSAA() > 1)
  1028. glResolveMultisampleFramebufferAPPLE();
  1029. else
  1030. glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
  1031. // Discarding the internal backbuffer directly after resolving it should
  1032. // eliminate any copy back to vram it might need to do.
  1033. discard(OpenGL::FRAMEBUFFER_READ, {true}, false);
  1034. }
  1035. if (!pendingScreenshotCallbacks.empty())
  1036. {
  1037. size_t row = 4 * w;
  1038. size_t size = row * h;
  1039. GLubyte *pixels = nullptr;
  1040. GLubyte *screenshot = nullptr;
  1041. try
  1042. {
  1043. pixels = new GLubyte[size];
  1044. screenshot = new GLubyte[size];
  1045. }
  1046. catch (std::exception &)
  1047. {
  1048. delete[] pixels;
  1049. delete[] screenshot;
  1050. throw love::Exception("Out of memory.");
  1051. }
  1052. gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, getSystemBackbufferFBO());
  1053. glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
  1054. // Replace alpha values with full opacity.
  1055. for (size_t i = 3; i < size; i += 4)
  1056. pixels[i] = 255;
  1057. // OpenGL sucks and reads pixels from the lower-left. Let's fix that.
  1058. GLubyte *src = pixels - row;
  1059. GLubyte *dst = screenshot + size;
  1060. for (int i = 0; i < h; ++i)
  1061. memcpy(dst-=row, src+=row, row);
  1062. delete[] pixels;
  1063. auto imagemodule = Module::getInstance<love::image::Image>(M_IMAGE);
  1064. for (int i = 0; i < (int) pendingScreenshotCallbacks.size(); i++)
  1065. {
  1066. const auto &info = pendingScreenshotCallbacks[i];
  1067. image::ImageData *img = nullptr;
  1068. try
  1069. {
  1070. img = imagemodule->newImageData(w, h, PIXELFORMAT_RGBA8_UNORM, screenshot);
  1071. }
  1072. catch (love::Exception &)
  1073. {
  1074. delete[] screenshot;
  1075. info.callback(&info, nullptr, nullptr);
  1076. for (int j = i + 1; j < (int) pendingScreenshotCallbacks.size(); j++)
  1077. {
  1078. const auto &ninfo = pendingScreenshotCallbacks[j];
  1079. ninfo.callback(&ninfo, nullptr, nullptr);
  1080. }
  1081. pendingScreenshotCallbacks.clear();
  1082. throw;
  1083. }
  1084. info.callback(&info, img, screenshotCallbackData);
  1085. img->release();
  1086. }
  1087. delete[] screenshot;
  1088. pendingScreenshotCallbacks.clear();
  1089. }
  1090. #ifdef LOVE_IOS
  1091. // Hack: SDL's color renderbuffer must be bound when swapBuffers is called.
  1092. SDL_SysWMinfo info = {};
  1093. SDL_VERSION(&info.version);
  1094. SDL_GetWindowWMInfo(SDL_GL_GetCurrentWindow(), &info);
  1095. glBindRenderbuffer(GL_RENDERBUFFER, info.info.uikit.colorbuffer);
  1096. #endif
  1097. for (StreamBuffer *buffer : batchedDrawState.vb)
  1098. buffer->nextFrame();
  1099. batchedDrawState.indexBuffer->nextFrame();
  1100. auto window = getInstance<love::window::Window>(M_WINDOW);
  1101. if (window != nullptr)
  1102. window->swapBuffers();
  1103. gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, getInternalBackbufferFBO());
  1104. // Reset the per-frame stat counts.
  1105. drawCalls = 0;
  1106. gl.stats.shaderSwitches = 0;
  1107. renderTargetSwitchCount = 0;
  1108. drawCallsBatched = 0;
  1109. updatePendingReadbacks();
  1110. updateTemporaryResources();
  1111. }
  1112. int Graphics::getRequestedBackbufferMSAA() const
  1113. {
  1114. return requestedBackbufferMSAA;
  1115. }
  1116. int Graphics::getBackbufferMSAA() const
  1117. {
  1118. return internalBackbuffer.get() ? internalBackbuffer->getMSAA() : 0;
  1119. }
  1120. void Graphics::setScissor(const Rect &rect)
  1121. {
  1122. flushBatchedDraws();
  1123. DisplayState &state = states.back();
  1124. if (!gl.isStateEnabled(OpenGL::ENABLE_SCISSOR_TEST))
  1125. gl.setEnableState(OpenGL::ENABLE_SCISSOR_TEST, true);
  1126. double dpiscale = getCurrentDPIScale();
  1127. Rect glrect;
  1128. glrect.x = (int) (rect.x * dpiscale);
  1129. glrect.y = (int) (rect.y * dpiscale);
  1130. glrect.w = (int) (rect.w * dpiscale);
  1131. glrect.h = (int) (rect.h * dpiscale);
  1132. // OpenGL's reversed y-coordinate is compensated for in OpenGL::setScissor.
  1133. gl.setScissor(glrect, isRenderTargetActive());
  1134. state.scissor = true;
  1135. state.scissorRect = rect;
  1136. }
  1137. void Graphics::setScissor()
  1138. {
  1139. if (states.back().scissor)
  1140. flushBatchedDraws();
  1141. states.back().scissor = false;
  1142. if (gl.isStateEnabled(OpenGL::ENABLE_SCISSOR_TEST))
  1143. gl.setEnableState(OpenGL::ENABLE_SCISSOR_TEST, false);
  1144. }
  1145. void Graphics::setStencilMode(StencilAction action, CompareMode compare, int value, uint32 readmask, uint32 writemask)
  1146. {
  1147. DisplayState &state = states.back();
  1148. if (action != STENCIL_KEEP)
  1149. {
  1150. const auto &rts = state.renderTargets;
  1151. love::graphics::Texture *dstexture = rts.depthStencil.texture.get();
  1152. if (!isRenderTargetActive() && !windowHasStencil)
  1153. throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer.");
  1154. else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat())))
  1155. throw love::Exception("Drawing to the stencil buffer with a render target active requires either stencil=true or a custom stencil-type texture to be used, in setRenderTarget.");
  1156. }
  1157. flushBatchedDraws();
  1158. bool enablestencil = action != STENCIL_KEEP || compare != COMPARE_ALWAYS;
  1159. if (enablestencil != gl.isStateEnabled(OpenGL::ENABLE_STENCIL_TEST))
  1160. gl.setEnableState(OpenGL::ENABLE_STENCIL_TEST, enablestencil);
  1161. GLenum glaction = GL_KEEP;
  1162. switch (action)
  1163. {
  1164. case STENCIL_KEEP:
  1165. glaction = GL_KEEP;
  1166. break;
  1167. case STENCIL_ZERO:
  1168. glaction = GL_ZERO;
  1169. break;
  1170. case STENCIL_REPLACE:
  1171. glaction = GL_REPLACE;
  1172. break;
  1173. case STENCIL_INCREMENT:
  1174. glaction = GL_INCR;
  1175. break;
  1176. case STENCIL_DECREMENT:
  1177. glaction = GL_DECR;
  1178. break;
  1179. case STENCIL_INCREMENT_WRAP:
  1180. glaction = GL_INCR_WRAP;
  1181. break;
  1182. case STENCIL_DECREMENT_WRAP:
  1183. glaction = GL_DECR_WRAP;
  1184. break;
  1185. case STENCIL_INVERT:
  1186. glaction = GL_INVERT;
  1187. break;
  1188. case STENCIL_MAX_ENUM:
  1189. glaction = GL_KEEP;
  1190. break;
  1191. }
  1192. /**
  1193. * GPUs do the comparison opposite to what makes sense for love's API. For
  1194. * example, if the compare function is GREATER then the stencil test will
  1195. * pass if the reference value is greater than the value in the stencil
  1196. * buffer. With our API it's more intuitive to assume that
  1197. * setStencilMode(STENCIL_KEEP, COMPARE_GREATER, 4) will make it pass if the
  1198. * stencil buffer has a value greater than 4.
  1199. **/
  1200. GLenum glcompare = OpenGL::getGLCompareMode(getReversedCompareMode(compare));
  1201. if (enablestencil)
  1202. {
  1203. glStencilFunc(glcompare, value, readmask);
  1204. glStencilOp(GL_KEEP, GL_KEEP, glaction);
  1205. }
  1206. if (writemask != gl.getStencilWriteMask())
  1207. gl.setStencilWriteMask(writemask);
  1208. state.stencil.action = action;
  1209. state.stencil.compare = compare;
  1210. state.stencil.value = value;
  1211. state.stencil.readMask = readmask;
  1212. state.stencil.writeMask = writemask;
  1213. }
  1214. void Graphics::setDepthMode(CompareMode compare, bool write)
  1215. {
  1216. DisplayState &state = states.back();
  1217. if (state.depthTest != compare || state.depthWrite != write)
  1218. flushBatchedDraws();
  1219. state.depthTest = compare;
  1220. state.depthWrite = write;
  1221. bool depthenable = compare != COMPARE_ALWAYS || write;
  1222. if (depthenable != gl.isStateEnabled(OpenGL::ENABLE_DEPTH_TEST))
  1223. gl.setEnableState(OpenGL::ENABLE_DEPTH_TEST, depthenable);
  1224. if (depthenable)
  1225. {
  1226. glDepthFunc(OpenGL::getGLCompareMode(compare));
  1227. gl.setDepthWrites(write);
  1228. }
  1229. }
  1230. void Graphics::setFrontFaceWinding(Winding winding)
  1231. {
  1232. DisplayState &state = states.back();
  1233. if (state.winding != winding)
  1234. flushBatchedDraws();
  1235. state.winding = winding;
  1236. if (isRenderTargetActive())
  1237. winding = winding == WINDING_CW ? WINDING_CCW : WINDING_CW;
  1238. glFrontFace(winding == WINDING_CW ? GL_CW : GL_CCW);
  1239. }
  1240. void Graphics::setColor(Colorf c)
  1241. {
  1242. c.r = std::min(std::max(c.r, 0.0f), 1.0f);
  1243. c.g = std::min(std::max(c.g, 0.0f), 1.0f);
  1244. c.b = std::min(std::max(c.b, 0.0f), 1.0f);
  1245. c.a = std::min(std::max(c.a, 0.0f), 1.0f);
  1246. states.back().color = c;
  1247. }
  1248. void Graphics::setColorMask(ColorChannelMask mask)
  1249. {
  1250. flushBatchedDraws();
  1251. uint32 maskbits =
  1252. ((mask.r ? 1 : 0) << 0) | ((mask.g ? 1 : 0) << 1) |
  1253. ((mask.b ? 1 : 0) << 2) | ((mask.a ? 1 : 0) << 3);
  1254. gl.setColorWriteMask(maskbits);
  1255. states.back().colorMask = mask;
  1256. }
  1257. void Graphics::setBlendState(const BlendState &blend)
  1258. {
  1259. if (!(blend == states.back().blend))
  1260. flushBatchedDraws();
  1261. if (blend.operationRGB == BLENDOP_MAX || blend.operationA == BLENDOP_MAX
  1262. || blend.operationRGB == BLENDOP_MIN || blend.operationA == BLENDOP_MIN)
  1263. {
  1264. if (!capabilities.features[FEATURE_BLEND_MINMAX])
  1265. throw love::Exception("The 'min' and 'max' blend operations are not supported on this system.");
  1266. }
  1267. if (blend.enable != gl.isStateEnabled(OpenGL::ENABLE_BLEND))
  1268. gl.setEnableState(OpenGL::ENABLE_BLEND, blend.enable);
  1269. if (blend.enable)
  1270. {
  1271. GLenum opRGB = getGLBlendOperation(blend.operationRGB);
  1272. GLenum opA = getGLBlendOperation(blend.operationA);
  1273. GLenum srcRGB = getGLBlendFactor(blend.srcFactorRGB);
  1274. GLenum srcA = getGLBlendFactor(blend.srcFactorA);
  1275. GLenum dstRGB = getGLBlendFactor(blend.dstFactorRGB);
  1276. GLenum dstA = getGLBlendFactor(blend.dstFactorA);
  1277. glBlendEquationSeparate(opRGB, opA);
  1278. glBlendFuncSeparate(srcRGB, dstRGB, srcA, dstA);
  1279. }
  1280. states.back().blend = blend;
  1281. }
  1282. void Graphics::setPointSize(float size)
  1283. {
  1284. if (size != states.back().pointSize)
  1285. flushBatchedDraws();
  1286. states.back().pointSize = size;
  1287. }
  1288. void Graphics::setWireframe(bool enable)
  1289. {
  1290. // Not supported in OpenGL ES.
  1291. if (GLAD_ES_VERSION_2_0)
  1292. return;
  1293. flushBatchedDraws();
  1294. glPolygonMode(GL_FRONT_AND_BACK, enable ? GL_LINE : GL_FILL);
  1295. states.back().wireframe = enable;
  1296. }
  1297. void *Graphics::getBufferMapMemory(size_t size)
  1298. {
  1299. // We don't need anything more complicated because get/release calls are
  1300. // never interleaved (as of when this comment was written.)
  1301. if (bufferMapMemory == nullptr || size > bufferMapMemorySize)
  1302. return malloc(size);
  1303. return bufferMapMemory;
  1304. }
  1305. void Graphics::releaseBufferMapMemory(void *mem)
  1306. {
  1307. if (mem != bufferMapMemory)
  1308. free(mem);
  1309. }
  1310. Renderer Graphics::getRenderer() const
  1311. {
  1312. return RENDERER_OPENGL;
  1313. }
  1314. bool Graphics::usesGLSLES() const
  1315. {
  1316. return GLAD_ES_VERSION_2_0;
  1317. }
  1318. Graphics::RendererInfo Graphics::getRendererInfo() const
  1319. {
  1320. RendererInfo info;
  1321. if (GLAD_ES_VERSION_2_0)
  1322. info.name = "OpenGL ES";
  1323. else
  1324. info.name = "OpenGL";
  1325. const char *str = (const char *) glGetString(GL_VERSION);
  1326. if (str)
  1327. info.version = str;
  1328. else
  1329. throw love::Exception("Cannot retrieve renderer version information.");
  1330. str = (const char *) glGetString(GL_VENDOR);
  1331. if (str)
  1332. info.vendor = str;
  1333. else
  1334. throw love::Exception("Cannot retrieve renderer vendor information.");
  1335. str = (const char *) glGetString(GL_RENDERER);
  1336. if (str)
  1337. info.device = str;
  1338. else
  1339. throw love::Exception("Cannot retrieve renderer device information.");
  1340. return info;
  1341. }
  1342. void Graphics::getAPIStats(int &shaderswitches) const
  1343. {
  1344. shaderswitches = gl.stats.shaderSwitches;
  1345. }
  1346. void Graphics::initCapabilities()
  1347. {
  1348. capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS] = gl.isMultiFormatMRTSupported();
  1349. capabilities.features[FEATURE_CLAMP_ZERO] = gl.isClampZeroOneTextureWrapSupported();
  1350. capabilities.features[FEATURE_CLAMP_ONE] = gl.isClampZeroOneTextureWrapSupported();
  1351. capabilities.features[FEATURE_BLEND_MINMAX] = GLAD_VERSION_1_4 || GLAD_ES_VERSION_3_0 || GLAD_EXT_blend_minmax;
  1352. capabilities.features[FEATURE_LIGHTEN] = capabilities.features[FEATURE_BLEND_MINMAX];
  1353. capabilities.features[FEATURE_FULL_NPOT] = GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot;
  1354. capabilities.features[FEATURE_PIXEL_SHADER_HIGHP] = gl.isPixelShaderHighpSupported();
  1355. capabilities.features[FEATURE_SHADER_DERIVATIVES] = GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_standard_derivatives;
  1356. capabilities.features[FEATURE_GLSL3] = GLAD_ES_VERSION_3_0 || gl.isCoreProfile();
  1357. capabilities.features[FEATURE_GLSL4] = GLAD_ES_VERSION_3_1 || (gl.isCoreProfile() && GLAD_VERSION_4_3);
  1358. capabilities.features[FEATURE_INSTANCING] = gl.isInstancingSupported();
  1359. capabilities.features[FEATURE_TEXEL_BUFFER] = gl.isBufferUsageSupported(BUFFERUSAGE_TEXEL);
  1360. capabilities.features[FEATURE_INDEX_BUFFER_32BIT] = GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_element_index_uint;
  1361. capabilities.features[FEATURE_COPY_BUFFER] = gl.isCopyBufferSupported();
  1362. capabilities.features[FEATURE_COPY_BUFFER_TO_TEXTURE] = gl.isCopyBufferToTextureSupported();
  1363. capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER] = gl.isCopyTextureToBufferSupported();
  1364. capabilities.features[FEATURE_COPY_RENDER_TARGET_TO_BUFFER] = gl.isCopyRenderTargetToBufferSupported();
  1365. capabilities.features[FEATURE_MIPMAP_RANGE] = GLAD_VERSION_1_2 || GLAD_ES_VERSION_3_0;
  1366. capabilities.features[FEATURE_INDIRECT_DRAW] = capabilities.features[FEATURE_GLSL4];
  1367. static_assert(FEATURE_MAX_ENUM == 19, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
  1368. capabilities.limits[LIMIT_POINT_SIZE] = gl.getMaxPointSize();
  1369. capabilities.limits[LIMIT_TEXTURE_SIZE] = gl.getMax2DTextureSize();
  1370. capabilities.limits[LIMIT_TEXTURE_LAYERS] = gl.getMaxTextureLayers();
  1371. capabilities.limits[LIMIT_VOLUME_TEXTURE_SIZE] = gl.getMax3DTextureSize();
  1372. capabilities.limits[LIMIT_CUBE_TEXTURE_SIZE] = gl.getMaxCubeTextureSize();
  1373. capabilities.limits[LIMIT_TEXEL_BUFFER_SIZE] = gl.getMaxTexelBufferSize();
  1374. capabilities.limits[LIMIT_SHADER_STORAGE_BUFFER_SIZE] = gl.getMaxShaderStorageBufferSize();
  1375. capabilities.limits[LIMIT_THREADGROUPS_X] = gl.getMaxComputeWorkGroupsX();
  1376. capabilities.limits[LIMIT_THREADGROUPS_Y] = gl.getMaxComputeWorkGroupsY();
  1377. capabilities.limits[LIMIT_THREADGROUPS_Z] = gl.getMaxComputeWorkGroupsZ();
  1378. capabilities.limits[LIMIT_RENDER_TARGETS] = gl.getMaxRenderTargets();
  1379. capabilities.limits[LIMIT_TEXTURE_MSAA] = gl.getMaxSamples();
  1380. capabilities.limits[LIMIT_ANISOTROPY] = gl.getMaxAnisotropy();
  1381. static_assert(LIMIT_MAX_ENUM == 13, "Graphics::initCapabilities must be updated when adding a new system limit!");
  1382. for (int i = 0; i < TEXTURE_MAX_ENUM; i++)
  1383. capabilities.textureTypes[i] = gl.isTextureTypeSupported((TextureType) i);
  1384. for (int i = 0; i < PIXELFORMAT_MAX_ENUM; i++)
  1385. {
  1386. auto format = (PixelFormat) i;
  1387. pixelFormatUsage[i][0] = computePixelFormatUsage(format, false);
  1388. pixelFormatUsage[i][1] = computePixelFormatUsage(format, true);
  1389. }
  1390. }
  1391. uint32 Graphics::computePixelFormatUsage(PixelFormat format, bool readable)
  1392. {
  1393. uint32 usage = OpenGL::getPixelFormatUsageFlags(format);
  1394. if (readable && (usage & PIXELFORMATUSAGEFLAGS_SAMPLE) == 0)
  1395. return 0;
  1396. // Even though we might have the necessary OpenGL version or extension,
  1397. // drivers are still allowed to throw FRAMEBUFFER_UNSUPPORTED when attaching
  1398. // a texture to a FBO whose format the driver doesn't like. So we should
  1399. // test with an actual FBO.
  1400. // Avoid the test for depth/stencil formats - not every GL version
  1401. // guarantees support for depth/stencil-only render targets (which we would
  1402. // need for the test below to work), and we already do some finagling in
  1403. // convertPixelFormat to try to use the best-supported internal
  1404. // depth/stencil format for a particular driver.
  1405. if ((usage & PIXELFORMATUSAGEFLAGS_RENDERTARGET) != 0 && !isPixelFormatDepthStencil(format))
  1406. {
  1407. GLuint texture = 0;
  1408. GLuint renderbuffer = 0;
  1409. OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, !readable);
  1410. GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL);
  1411. GLuint fbo = 0;
  1412. glGenFramebuffers(1, &fbo);
  1413. gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, fbo);
  1414. // Make sure at least something is bound to a color attachment. I believe
  1415. // this is required on ES2 but I'm not positive.
  1416. if (isPixelFormatDepthStencil(format))
  1417. gl.framebufferTexture(GL_COLOR_ATTACHMENT0, TEXTURE_2D, gl.getDefaultTexture(TEXTURE_2D, DATA_BASETYPE_FLOAT), 0, 0, 0);
  1418. if (readable)
  1419. {
  1420. glGenTextures(1, &texture);
  1421. gl.bindTextureToUnit(TEXTURE_2D, texture, 0, false);
  1422. SamplerState s;
  1423. s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST;
  1424. gl.setSamplerState(TEXTURE_2D, s);
  1425. gl.rawTexStorage(TEXTURE_2D, 1, format, 1, 1);
  1426. }
  1427. else
  1428. {
  1429. glGenRenderbuffers(1, &renderbuffer);
  1430. glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
  1431. glRenderbufferStorage(GL_RENDERBUFFER, fmt.internalformat, 1, 1);
  1432. }
  1433. for (GLenum attachment : fmt.framebufferAttachments)
  1434. {
  1435. if (attachment == GL_NONE)
  1436. continue;
  1437. if (readable)
  1438. gl.framebufferTexture(attachment, TEXTURE_2D, texture, 0, 0, 0);
  1439. else
  1440. glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, renderbuffer);
  1441. }
  1442. if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
  1443. usage &= ~PIXELFORMATUSAGEFLAGS_RENDERTARGET;
  1444. gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, current_fbo);
  1445. gl.deleteFramebuffer(fbo);
  1446. if (texture != 0)
  1447. gl.deleteTexture(texture);
  1448. if (renderbuffer != 0)
  1449. glDeleteRenderbuffers(1, &renderbuffer);
  1450. }
  1451. return usage;
  1452. }
  1453. bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage)
  1454. {
  1455. format = getSizedFormat(format);
  1456. bool readable = (usage & PIXELFORMATUSAGEFLAGS_SAMPLE) != 0;
  1457. return (usage & pixelFormatUsage[format][readable ? 1 : 0]) == usage;
  1458. }
  1459. } // opengl
  1460. } // graphics
  1461. } // love