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
44namespace love
45{
46namespace graphics
47{
48
49class Resource;
50class Buffer;
51
52namespace 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.
58using 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 **/
67class OpenGL
68{
69public:
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
447private:
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.
510extern OpenGL gl;
511
512} // opengl
513} // graphics
514} // love
515
516#endif // LOVE_GRAPHICS_OPENGL_OPENGL_H
517