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 | |
21 | #ifndef LOVE_GRAPHICS_OPENGL_OPENGL_H |
22 | #define LOVE_GRAPHICS_OPENGL_OPENGL_H |
23 | |
24 | // LOVE |
25 | #include "common/config.h" |
26 | #include "common/int.h" |
27 | #include "common/math.h" |
28 | #include "common/Color.h" |
29 | #include "graphics/Texture.h" |
30 | #include "graphics/vertex.h" |
31 | #include "graphics/depthstencil.h" |
32 | #include "common/Matrix.h" |
33 | |
34 | // GLAD |
35 | #include "libraries/glad/gladfuncs.hpp" |
36 | |
37 | // C++ |
38 | #include <vector> |
39 | #include <stack> |
40 | |
41 | // The last argument to AttribPointer takes a buffer offset casted to a pointer. |
42 | #define BUFFER_OFFSET(i) ((char *) NULL + (i)) |
43 | |
44 | namespace love |
45 | { |
46 | namespace graphics |
47 | { |
48 | |
49 | class Resource; |
50 | class Buffer; |
51 | |
52 | namespace opengl |
53 | { |
54 | |
55 | // Awful, but the library uses the namespace in order to use the functions sanely |
56 | // with proper autocomplete in IDEs while having name mangling safety - |
57 | // no clashes with other GL libraries when linking, etc. |
58 | using namespace glad; |
59 | |
60 | /** |
61 | * Thin layer between OpenGL and the rest of the program. |
62 | * Internally shadows some OpenGL context state for improved efficiency and |
63 | * accuracy (compared to glGet etc.) |
64 | * A class is more convenient and readable than plain namespaced functions, but |
65 | * typically only one OpenGL object should be used (singleton.) |
66 | **/ |
67 | class OpenGL |
68 | { |
69 | public: |
70 | |
71 | // OpenGL GPU vendors. |
72 | enum Vendor |
73 | { |
74 | VENDOR_AMD, |
75 | VENDOR_NVIDIA, |
76 | VENDOR_INTEL, |
77 | VENDOR_MESA_SOFT, // Software renderer. |
78 | VENDOR_APPLE, // Software renderer on desktops. |
79 | VENDOR_MICROSOFT, // Software renderer. |
80 | VENDOR_IMGTEC, |
81 | VENDOR_ARM, |
82 | VENDOR_QUALCOMM, |
83 | VENDOR_BROADCOM, |
84 | VENDOR_VIVANTE, |
85 | VENDOR_UNKNOWN |
86 | }; |
87 | |
88 | enum FramebufferTarget |
89 | { |
90 | FRAMEBUFFER_READ = (1 << 0), |
91 | FRAMEBUFFER_DRAW = (1 << 1), |
92 | FRAMEBUFFER_ALL = (FRAMEBUFFER_READ | FRAMEBUFFER_DRAW), |
93 | }; |
94 | |
95 | enum EnableState |
96 | { |
97 | ENABLE_DEPTH_TEST, |
98 | ENABLE_STENCIL_TEST, |
99 | ENABLE_SCISSOR_TEST, |
100 | ENABLE_FACE_CULL, |
101 | ENABLE_FRAMEBUFFER_SRGB, |
102 | ENABLE_MAX_ENUM |
103 | }; |
104 | |
105 | struct TextureFormat |
106 | { |
107 | GLenum internalformat = 0; |
108 | GLenum externalformat = 0; |
109 | GLenum type = 0; |
110 | |
111 | // For depth/stencil formats. |
112 | GLenum framebufferAttachments[2]; |
113 | |
114 | bool swizzled = false; |
115 | GLint swizzle[4]; |
116 | }; |
117 | |
118 | class TempDebugGroup |
119 | { |
120 | public: |
121 | |
122 | TempDebugGroup(const char *name); |
123 | ~TempDebugGroup(); |
124 | }; |
125 | |
126 | struct Stats |
127 | { |
128 | int shaderSwitches; |
129 | } stats; |
130 | |
131 | struct Bugs |
132 | { |
133 | /** |
134 | * On AMD's Windows (and probably Linux) drivers, |
135 | * glBindFramebuffer + glClear + glBindFramebuffer + draw(fbo_tex) won't |
136 | * work unless there's some kind of draw or state change which causes |
137 | * the driver to update the texture's contents (just drawing the texture |
138 | * won't always do it, with this driver bug). |
139 | * Activating shader program 0 and then activating the actual program |
140 | * seems to always 'fix' it for me. |
141 | * Bug observed January 2016 with multiple AMD GPUs and driver versions. |
142 | * https://love2d.org/forums/viewtopic.php?f=4&t=81496 |
143 | **/ |
144 | bool clearRequiresDriverTextureStateUpdate; |
145 | |
146 | /** |
147 | * AMD's Windows drivers don't always properly generate mipmaps unless |
148 | * glEnable(GL_TEXTURE_2D) is called directly before glGenerateMipmap. |
149 | * This only applies to legacy and Compatibility Profile contexts, of |
150 | * course. |
151 | * https://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation |
152 | **/ |
153 | bool generateMipmapsRequiresTexture2DEnable; |
154 | |
155 | /** |
156 | * Report: Intel HD 4000 on Windows hangs during glClientWaitSync. |
157 | * I found this when googling the issue: |
158 | * https://github.com/mjn33/planetgen/commit/235e23873a22e219fffdd9ede706c1051aa0f107 |
159 | **/ |
160 | bool clientWaitSyncStalls; |
161 | |
162 | /** |
163 | * glTexStorage on some older AMD/ATI graphics drivers on Windows seems |
164 | * to break subsequent sub-rectangle glTexSubImage calls after an |
165 | * initial full-size one (determined after some investigation with an |
166 | * affected user on Discord.) |
167 | * https://bitbucket.org/rude/love/issues/1436/bug-with-lovegraphicsprint-on-older-ati |
168 | * https://github.com/love2d/love/issues/1563 |
169 | **/ |
170 | bool texStorageBreaksSubImage; |
171 | |
172 | /** |
173 | * An Android device with an Adreno 630 (supposedly GLES3.2-capable) |
174 | * fails with GL_INVALID_OPERATION in glTexImage2D if the image is |
175 | * GL_R8, despite the GLES 3.0 spec mandating support for that format. |
176 | * It's possible more Adreno GPUs / drivers are affected as well. |
177 | **/ |
178 | bool brokenR8PixelFormat; |
179 | |
180 | /** |
181 | * Intel HD Graphics drivers on Windows prior to the HD 2500/4000 have |
182 | * completely broken sRGB support. |
183 | * https://github.com/love2d/love/issues/1592 |
184 | **/ |
185 | bool brokenSRGB; |
186 | |
187 | /** |
188 | * Some Android graphics drivers claim to support GLES3.0 but have bugs |
189 | * with certain aspects that users expect to work. For example: |
190 | * https://github.com/love2d/love-android/issues/204 |
191 | **/ |
192 | bool brokenGLES3; |
193 | |
194 | /** |
195 | * Other bugs which have workarounds that don't use conditional code at |
196 | * the moment: |
197 | * |
198 | * Kepler nvidia GPUs in at least OS X 10.10 and 10.11 fail to render |
199 | * geometry with glDrawElements if index data comes from a Buffer Object |
200 | * and vertex data doesn't. One workaround is to use a CPU-side index |
201 | * array when there's also a CPU-side vertex array. |
202 | * https://love2d.org/forums/viewtopic.php?f=4&t=81401&start=10 |
203 | * |
204 | * Some android drivers don't seem to initialize the sampler index |
205 | * values of sampler uniforms in shaders to 0 (which is required by the |
206 | * GLSL ES specification) when linking the shader program. One |
207 | * workaround is to always set the values of said sampler uniforms to 0 |
208 | * just after linking the shader program. |
209 | * https://love2d.org/forums/viewtopic.php?f=4&t=81458 |
210 | **/ |
211 | } bugs; |
212 | |
213 | OpenGL(); |
214 | |
215 | /** |
216 | * Initializes the active OpenGL context. |
217 | **/ |
218 | bool initContext(); |
219 | |
220 | /** |
221 | * Sets up some required context state based on current and default OpenGL |
222 | * state. Call this directly after initializing an OpenGL context! |
223 | **/ |
224 | void setupContext(); |
225 | |
226 | /** |
227 | * Marks current context state as invalid and deletes OpenGL objects owned |
228 | * by this class instance. Call this directly before potentially deleting |
229 | * an OpenGL context! |
230 | **/ |
231 | void deInitContext(); |
232 | |
233 | /** |
234 | * Set up necessary state (LOVE-provided shader uniforms, etc.) for drawing. |
235 | * This *MUST* be called directly before OpenGL drawing functions. |
236 | **/ |
237 | void prepareDraw(); |
238 | |
239 | /** |
240 | * State-tracked glBindBuffer. |
241 | * NOTE: This does not account for multiple VAOs being used! Index buffer |
242 | * bindings are per-VAO in OpenGL, but this doesn't know about that. |
243 | **/ |
244 | void bindBuffer(BufferType type, GLuint buffer); |
245 | |
246 | /** |
247 | * glDeleteBuffers which updates our shadowed state. |
248 | **/ |
249 | void deleteBuffer(GLuint buffer); |
250 | |
251 | /** |
252 | * Set all vertex attribute state. |
253 | **/ |
254 | void setVertexAttributes(const vertex::Attributes &attributes, const vertex::BufferBindings &buffers); |
255 | |
256 | /** |
257 | * Wrapper for glCullFace which eliminates redundant state setting. |
258 | **/ |
259 | void setCullMode(CullMode mode); |
260 | |
261 | /** |
262 | * Wrapper for glClearDepth and glClearDepthf. |
263 | **/ |
264 | void clearDepth(double value); |
265 | |
266 | /** |
267 | * Sets the OpenGL rendering viewport to the specified rectangle. |
268 | * The y-coordinate starts at the top. |
269 | **/ |
270 | void setViewport(const Rect &v); |
271 | Rect getViewport() const; |
272 | |
273 | /** |
274 | * Sets the scissor box to the specified rectangle. |
275 | * The y-coordinate starts at the top and is flipped internally. |
276 | **/ |
277 | void setScissor(const Rect &v, bool canvasActive); |
278 | |
279 | /** |
280 | * Sets the constant color (vertex attribute). This may be applied |
281 | * internally at draw-time. This gets gamma-corrected internally as well. |
282 | **/ |
283 | void setConstantColor(const Colorf &color); |
284 | const Colorf &getConstantColor() const; |
285 | |
286 | /** |
287 | * Sets the global point size. |
288 | **/ |
289 | void setPointSize(float size); |
290 | float getPointSize() const; |
291 | |
292 | /** |
293 | * State-tracked version of glEnable. |
294 | **/ |
295 | void setEnableState(EnableState state, bool enable); |
296 | bool isStateEnabled(EnableState state) const; |
297 | |
298 | /** |
299 | * Binds a Framebuffer Object to the specified target. |
300 | **/ |
301 | void bindFramebuffer(FramebufferTarget target, GLuint framebuffer); |
302 | GLuint getFramebuffer(FramebufferTarget target) const; |
303 | void deleteFramebuffer(GLuint framebuffer); |
304 | |
305 | void framebufferTexture(GLenum attachment, TextureType texType, GLuint texture, int level, int layer = 0, int face = 0); |
306 | |
307 | /** |
308 | * Calls glDepthMask. |
309 | **/ |
310 | void setDepthWrites(bool enable); |
311 | bool hasDepthWrites() const; |
312 | |
313 | /** |
314 | * Calls glUseProgram. |
315 | **/ |
316 | void useProgram(GLuint program); |
317 | |
318 | /** |
319 | * This will usually be 0 (system drawable), but some platforms require a |
320 | * non-zero FBO for rendering. |
321 | **/ |
322 | GLuint getDefaultFBO() const; |
323 | |
324 | /** |
325 | * Gets the ID for love's default texture (used for "untextured" primitives.) |
326 | **/ |
327 | GLuint getDefaultTexture(TextureType type) const; |
328 | |
329 | /** |
330 | * Helper for setting the active texture unit. |
331 | * |
332 | * @param textureunit Index in the range of [0, maxtextureunits-1] |
333 | **/ |
334 | void setTextureUnit(int textureunit); |
335 | |
336 | /** |
337 | * Helper for binding a texture to a specific texture unit. |
338 | * |
339 | * @param textureunit Index in the range of [0, maxtextureunits-1] |
340 | * @param restoreprev Restore previously bound texture unit when done. |
341 | * @param bindforedit If false, the active texture unit may be left alone. |
342 | **/ |
343 | void bindTextureToUnit(TextureType target, GLuint texture, int textureunit, bool restoreprev, bool bindforedit = true); |
344 | void bindTextureToUnit(Texture *texture, int textureunit, bool restoreprev, bool bindforedit = true); |
345 | |
346 | /** |
347 | * Helper for deleting an OpenGL texture. |
348 | * Cleans up if the texture is currently bound. |
349 | **/ |
350 | void deleteTexture(GLuint texture); |
351 | |
352 | /** |
353 | * Sets the texture filter mode for the currently bound texture. |
354 | * The anisotropy parameter of the argument is set to the actual amount of |
355 | * anisotropy that was used. |
356 | **/ |
357 | void setTextureFilter(TextureType target, graphics::Texture::Filter &f); |
358 | |
359 | /** |
360 | * Sets the texture wrap mode for the currently bound texture. |
361 | **/ |
362 | void setTextureWrap(TextureType target, const graphics::Texture::Wrap &w); |
363 | |
364 | /** |
365 | * Equivalent to glTexStorage2D/3D on platforms that support it. Equivalent |
366 | * to glTexImage2D/3D for all levels and slices of a texture otherwise. |
367 | * NOTE: this does not handle compressed texture formats. |
368 | **/ |
369 | bool rawTexStorage(TextureType target, int levels, PixelFormat pixelformat, bool &isSRGB, int width, int height, int depth = 1); |
370 | |
371 | bool isTextureTypeSupported(TextureType type) const; |
372 | bool isClampZeroTextureWrapSupported() const; |
373 | bool isPixelShaderHighpSupported() const; |
374 | bool isInstancingSupported() const; |
375 | bool isDepthCompareSampleSupported() const; |
376 | bool isSamplerLODBiasSupported() const; |
377 | bool isBaseVertexSupported() const; |
378 | |
379 | /** |
380 | * Returns the maximum supported width or height of a texture. |
381 | **/ |
382 | int getMax2DTextureSize() const; |
383 | int getMax3DTextureSize() const; |
384 | int getMaxCubeTextureSize() const; |
385 | int getMaxTextureLayers() const; |
386 | |
387 | /** |
388 | * Returns the maximum supported number of simultaneous render targets. |
389 | **/ |
390 | int getMaxRenderTargets() const; |
391 | |
392 | /** |
393 | * Returns the maximum supported number of MSAA samples for renderbuffers. |
394 | **/ |
395 | int getMaxRenderbufferSamples() const; |
396 | |
397 | /** |
398 | * Returns the maximum number of accessible texture units. |
399 | **/ |
400 | int getMaxTextureUnits() const; |
401 | |
402 | /** |
403 | * Returns the maximum point size. |
404 | **/ |
405 | float getMaxPointSize() const; |
406 | |
407 | /** |
408 | * Returns the maximum anisotropic filtering value that can be used for |
409 | * Texture filtering. |
410 | **/ |
411 | float getMaxAnisotropy() const; |
412 | |
413 | float getMaxLODBias() const; |
414 | |
415 | /** |
416 | * Gets whether the context is Core Profile OpenGL 3.2+. |
417 | **/ |
418 | bool isCoreProfile() const; |
419 | |
420 | /** |
421 | * Get the GPU vendor of this OpenGL context. |
422 | **/ |
423 | Vendor getVendor() const; |
424 | |
425 | static GLenum getGLPrimitiveType(PrimitiveType type); |
426 | static GLenum getGLBufferType(BufferType type); |
427 | static GLenum getGLIndexDataType(IndexDataType type); |
428 | static GLenum getGLVertexDataType(vertex::DataType type, GLboolean &normalized); |
429 | static GLenum getGLBufferUsage(vertex::Usage usage); |
430 | static GLenum getGLTextureType(TextureType type); |
431 | static GLint getGLWrapMode(Texture::WrapMode wmode); |
432 | static GLint getGLCompareMode(CompareMode mode); |
433 | |
434 | static TextureFormat convertPixelFormat(PixelFormat pixelformat, bool renderbuffer, bool &isSRGB); |
435 | static bool isTexStorageSupported(); |
436 | static bool isPixelFormatSupported(PixelFormat pixelformat, bool rendertarget, bool readable, bool isSRGB); |
437 | static bool hasTextureFilteringSupport(PixelFormat pixelformat); |
438 | |
439 | static const char *errorString(GLenum errorcode); |
440 | static const char *framebufferStatusString(GLenum status); |
441 | |
442 | // Get human-readable strings for debug info. |
443 | static const char *debugSeverityString(GLenum severity); |
444 | static const char *debugSourceString(GLenum source); |
445 | static const char *debugTypeString(GLenum type); |
446 | |
447 | private: |
448 | |
449 | void initVendor(); |
450 | void initOpenGLFunctions(); |
451 | void initMaxValues(); |
452 | void createDefaultTexture(); |
453 | |
454 | bool contextInitialized; |
455 | |
456 | bool pixelShaderHighpSupported; |
457 | bool baseVertexSupported; |
458 | |
459 | float maxAnisotropy; |
460 | float maxLODBias; |
461 | int max2DTextureSize; |
462 | int max3DTextureSize; |
463 | int maxCubeTextureSize; |
464 | int maxTextureArrayLayers; |
465 | int maxRenderTargets; |
466 | int maxRenderbufferSamples; |
467 | int maxTextureUnits; |
468 | float maxPointSize; |
469 | |
470 | bool coreProfile; |
471 | |
472 | Vendor vendor; |
473 | |
474 | // Tracked OpenGL state. |
475 | struct |
476 | { |
477 | GLuint boundBuffers[BUFFER_MAX_ENUM]; |
478 | |
479 | // Texture unit state (currently bound texture for each texture unit.) |
480 | std::vector<GLuint> boundTextures[TEXTURE_MAX_ENUM]; |
481 | |
482 | bool enableState[ENABLE_MAX_ENUM]; |
483 | |
484 | GLenum faceCullMode; |
485 | |
486 | int curTextureUnit; |
487 | |
488 | uint32 enabledAttribArrays; |
489 | uint32 instancedAttribArrays; |
490 | |
491 | Colorf constantColor; |
492 | Colorf lastConstantColor; |
493 | |
494 | Rect viewport; |
495 | Rect scissor; |
496 | |
497 | float pointSize; |
498 | |
499 | bool depthWritesEnabled = true; |
500 | |
501 | GLuint boundFramebuffers[2]; |
502 | |
503 | GLuint defaultTexture[TEXTURE_MAX_ENUM]; |
504 | |
505 | } state; |
506 | |
507 | }; // OpenGL |
508 | |
509 | // OpenGL class instance singleton. |
510 | extern OpenGL gl; |
511 | |
512 | } // opengl |
513 | } // graphics |
514 | } // love |
515 | |
516 | #endif // LOVE_GRAPHICS_OPENGL_OPENGL_H |
517 | |