21#include <OpenGL/CGLMacro.h>
22#include <CoreFoundation/CoreFoundation.h>
23#include <CoreGraphics/CoreGraphics.h>
25#include <dispatch/dispatch.h>
27#include <mach-o/dyld.h>
28#include <objc/objc-runtime.h>
65#pragma clang diagnostic push
66#pragma clang diagnostic ignored "-Wdeprecated-declarations"
70 CGLRendererInfoObj ri;
71 GLint rendererCount = 0;
72 CGLQueryRendererInfo(-1, &ri, &rendererCount);
73 for (
int i = 0; i < rendererCount; ++i)
76 CGLDescribeRenderer(ri, i, kCGLRPRendererID, &rendererID);
80 if (CGLDescribeRenderer(ri, i, kCGLRPOnline, &online) == kCGLNoError)
81 VUserLog(
" Online : %s", online ?
"yes" :
"no");
84 if (CGLDescribeRenderer(ri, i, kCGLRPAccelerated, &accelerated) == kCGLNoError)
85 VUserLog(
" Accelerated : %s", accelerated ?
"yes" :
"no");
87 GLint videoMegabytes = 0;
88 if (CGLDescribeRenderer(ri, i, kCGLRPVideoMemoryMegabytes, &videoMegabytes) == kCGLNoError
90 VUserLog(
" Video memory : %d MB", videoMegabytes);
92 GLint textureMegabytes = 0;
93 if (CGLDescribeRenderer(ri, i, kCGLRPTextureMemoryMegabytes, &textureMegabytes) == kCGLNoError
95 VUserLog(
" Texture memory : %d MB", textureMegabytes);
98 if (CGLDescribeRenderer(ri, i, kCGLRPDisplayMask, &displayMask) == kCGLNoError)
100 VUserLog(
" Display mask : %s (0x%x)%s",
101 std::bitset<32>(displayMask).to_string().c_str(),
102 displayMask, (displayMask & 0xff) == 0xff ?
" (any)" :
"");
103 if ((displayMask & 0xff) != 0xff)
104 for (
unsigned long i = 0; i < screenCount; ++i)
105 if (displayMask & screens[i].displayMask)
107 std::bitset<32>(screens[i].displayMask).to_string().c_str(),
112 if (CGLDescribeRenderer(ri, i, (CGLRendererProperty)133, &glVersion) == kCGLNoError)
113 VUserLog(
" OpenGL version : %d", glVersion);
116 if (pf != (CGLPixelFormatObj)-1)
118 CGLContextObj cgl_ctx;
119 CGLError error = CGLCreateContext(pf, NULL, &cgl_ctx);
120 if (error != kCGLNoError)
121 VUserLog(
" Error: %s", CGLErrorString(error));
124 GLint maxTextureSize;
125 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
126 VUserLog(
" OpenGL 2 : %s (%s) maxTextureSize=%d", glGetString(GL_RENDERER), glGetString(GL_VERSION), maxTextureSize);
127 CGLDestroyContext(cgl_ctx);
131 VUserLog(
" (Can't create an OpenGL 2 context on this renderer.)");
134 if (pf != (CGLPixelFormatObj)-1)
136 CGLContextObj cgl_ctx;
137 CGLError error = CGLCreateContext(pf, NULL, &cgl_ctx);
138 if (error != kCGLNoError)
139 VUserLog(
" Error: %s", CGLErrorString(error));
142 GLint maxTextureSize;
143 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
144 VUserLog(
" OpenGL Core Profile: %s (%s) maxTextureSize=%d", glGetString(GL_RENDERER), glGetString(GL_VERSION), maxTextureSize);
145 CGLDestroyContext(cgl_ctx);
149 VUserLog(
" (Can't create an OpenGL Core Profile context on this renderer.)");
151 CGLDestroyRendererInfo(ri);
152#pragma clang diagnostic pop
155 VUserLog(
"OpenGL driver binaries:");
156 const char *gldriver =
"GLDriver";
157 size_t gldriverLen = strlen(gldriver);
158 uint32_t imageCount = _dyld_image_count();
159 for (uint32_t i = 0; i < imageCount; ++i)
161 const char *dylibPath = _dyld_get_image_name(i);
162 size_t len = strlen(dylibPath);
164 if (strcmp(dylibPath + len - gldriverLen, gldriver) == 0)
167 char *z = strdup(strrchr(dylibPath,
'/')+1);
168 z[strlen(z)-gldriverLen] = 0;
174 typedef void *(*mtlCopyAllDevicesType)(void);
175 mtlCopyAllDevicesType mtlCopyAllDevices = (mtlCopyAllDevicesType)dlsym(RTLD_DEFAULT,
"MTLCopyAllDevices");
176 if (mtlCopyAllDevices)
178 CFArrayRef mtlDevices = (CFArrayRef)mtlCopyAllDevices();
179 int mtlDeviceCount = CFArrayGetCount(mtlDevices);
182 for (
int i = 0; i < mtlDeviceCount; ++i)
184 id dev = (id)CFArrayGetValueAtIndex(mtlDevices, i);
185 id devName = ((id (*)(id, SEL))objc_msgSend)(dev, sel_getUid(
"name"));
186 const char *devNameZ = ((
char * (*)(
id,
SEL))objc_msgSend)(devName, sel_getUid(
"UTF8String"));
188 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"registryID")))
189 VUserLog(
" ID : %p", ((
id (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"registryID")));
190 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"peerGroupID")))
191 VUserLog(
" Peer group : %llu", ((uint64_t (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"peerGroupID")));
193 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"recommendedMaxWorkingSetSize")))
194 VUserLog(
" Recommended max working-set size : %lld MiB", ((int64_t (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"recommendedMaxWorkingSetSize"))/1048576);
195 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"maxBufferLength")))
196 VUserLog(
" Max buffer length : %lld MiB", ((int64_t (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"maxBufferLength"))/1048576);
197 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"maxThreadgroupMemoryLength")))
198 VUserLog(
" Threadgroup memory : %lld B", ((int64_t (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"maxThreadgroupMemoryLength")));
199 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"sparseTileSizeInBytes")))
200 VUserLog(
" Sparse tile size : %llu B", ((uint64_t (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"sparseTileSizeInBytes")));
202 VUserLog(
" Low-power : %s", ((
bool (*)(
id,
SEL))objc_msgSend) ?
"yes" :
"no");
203 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"isRemovable")))
204 VUserLog(
" Removable : %s", ((
bool (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"isRemovable")) ?
"yes" :
"no");
205 VUserLog(
" Headless : %s", ((
bool (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"isHeadless")) ?
"yes" :
"no");
207 if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFeatureSet:"), 10005))
208 VUserLog(
" Feature set : GPU Family 2 v1");
209 else if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFeatureSet:"), 10004))
210 VUserLog(
" Feature set : GPU Family 1 v4");
211 else if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFeatureSet:"), 10003))
212 VUserLog(
" Feature set : GPU Family 1 v3");
213 else if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFeatureSet:"), 10001))
214 VUserLog(
" Feature set : GPU Family 1 v2");
215 else if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFeatureSet:"), 10000))
216 VUserLog(
" Feature set : GPU Family 1 v1");
218 VUserLog(
" Feature set : (unknown)");
220 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"supportsFamily:")))
224 if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFamily:"), 1008))
226 else if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFamily:"), 1007))
228 else if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFamily:"), 1006))
230 else if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFamily:"), 1005))
232 else if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFamily:"), 1004))
234 else if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFamily:"), 1003))
236 else if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFamily:"), 1002))
238 else if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFamily:"), 1001))
241 if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFamily:"), 2002))
243 else if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFamily:"), 2001))
246 if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFamily:"), 3003))
248 else if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFamily:"), 3002))
250 else if (((
bool (*)(
id,
SEL,
int))objc_msgSend)(dev, sel_getUid(
"supportsFamily:"), 3001))
254 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"readWriteTextureSupport")))
255 VUserLog(
" Read-write texture support tier : %lld", ((int64_t (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"readWriteTextureSupport")));
256 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"argumentBuffersSupport")))
257 VUserLog(
" Argument buffer support tier : %lld", ((int64_t (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"argumentBuffersSupport")));
258 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"maxArgumentBufferSamplerCount")))
259 VUserLog(
" Max argument buffers : %lld", ((int64_t (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"maxArgumentBufferSamplerCount")));
260 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"areProgrammableSamplePositionsSupported")))
261 VUserLog(
" Programmable sample position support: %s", ((
bool (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"areProgrammableSamplePositionsSupported")) ?
"yes" :
"no");
262 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"areRasterOrderGroupsSupported")))
263 VUserLog(
" Raster order group support : %s", ((
bool (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"areRasterOrderGroupsSupported")) ?
"yes" :
"no");
265 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"supportsDynamicLibraries")))
266 VUserLog(
" Dynamic library support : %s", ((
bool (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"supportsDynamicLibraries")) ?
"yes" :
"no");
267 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"supportsFunctionPointers")))
268 VUserLog(
" Function pointer support : %s", ((
bool (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"supportsFunctionPointers")) ?
"yes" :
"no");
269 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"supportsRaytracing")))
270 VUserLog(
" Raytracing support : %s", ((
bool (*)(
id,
SEL))objc_msgSend)(dev, sel_getUid(
"supportsRaytracing")) ?
"yes" :
"no");
272 CFRelease(mtlDevices);
281 if (!(flags & kCGDisplaySetModeFlag))
289 for (
unsigned long i = 0; i < screenCount; ++i)
290 if (screens[i].
id == display)
291 VUserLog(
"Display reconfigured: %s", screens[i].name);
307 VUserLog(
"Couldn't create the key for storing the GL Context state: %s", strerror(errno));
321 CGLContextObj context;
339 VUserLog(
"Error: Couldn't create a context.");
358 CGLContextObj cgl_ctx = (CGLContextObj)glContext;
384 glGetIntegerv(GL_MAX_TEXTURE_UNITS, &textureUnits);
385 for (GLint i=0; i<textureUnits; ++i)
387 glActiveTexture(GL_TEXTURE0+i);
410 VUserLog(
"Error: Disued context %p, which isn't in the global share pool. I'm not going to muddy the waters.", cgl_ctx);
418 #define VuoGlContext_checkGL(cap, value) \
420 if (glIsEnabled(cap) != value) \
422 VUserLog("Warning: Caller incorrectly left %s %s", #cap, value ? "disabled" : "enabled"); \
423 VuoLog_backtrace(); \
430 #define VuoGlContext_checkGLInt(key, value) \
433 glGetIntegerv(key, &actualValue); \
434 if (actualValue != value) \
436 VUserLog("Warning: Caller incorrectly left %s set to something other than %s", #key, #value); \
437 VuoLog_backtrace(); \
457#pragma clang diagnostic push
458#pragma clang diagnostic ignored "-Wdeprecated-declarations"
466 if (!alreadyLockedOnThisThread)
503 if (!alreadyLockedOnThisThread)
508#pragma clang diagnostic pop
516#pragma clang diagnostic push
517#pragma clang diagnostic ignored "-Wdeprecated-declarations"
518 static dispatch_once_t info = 0;
519 dispatch_once(&info, ^{
524 CGLPixelFormatObj pf;
525 bool shouldDestroyPixelFormat =
false;
528 pf = CGLGetPixelFormat(rootContext);
531 Boolean overridden =
false;
532 displayMask = (int)CFPreferencesGetAppIntegerValue(CFSTR(
"displayMask"), CFSTR(
"org.vuo.Editor"), &overridden);
536 auto displayMaskString = (CFStringRef)CFPreferencesCopyAppValue(CFSTR(
"displayMask"), CFSTR(
"org.vuo.Editor"));
537 if (displayMaskString)
540 CFRelease(displayMaskString);
542 overridden = sscanf(t,
"0x%x", &displayMask) == 1;
550 shouldDestroyPixelFormat =
true;
553 CGLContextObj context;
555 CGLError error = CGLCreateContext(pf, rootContext, &context);
556 if (shouldDestroyPixelFormat)
557 CGLDestroyPixelFormat(pf);
558 if (error != kCGLNoError)
560 VUserLog(
"Error: %s", CGLErrorString(error));
568 CGLGetParameter(context, kCGLCPCurrentRendererID, &rendererID);
569 char *sharingText = rootContext ?
VuoText_format(
" (shared with %p)", rootContext) : strdup(
" (not shared)");
570 char *displayMaskText = rootContext ? nullptr : (displayMask == -1 ? strdup(
" (macOS default)") :
VuoText_format(
" (selected using displayMask %s)", std::bitset<32>(displayMask).to_string().c_str()));
573 free(displayMaskText);
583 CGLContextObj cgl_ctx = context;
585 glDisable(GL_DEPTH_TEST);
586 glEnable(GL_CULL_FACE);
588 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
589 glBlendEquation(GL_FUNC_ADD);
590 glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
591 glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -.5);
595#pragma clang diagnostic pop
612 VUserLog(
"Error: Called after VuoGlContextPool was initialized. Ignoring the new rootContext.");
616 VUserLog(
"Setting global root context to %p", rootContext);
624#define VuoGlCheckBinding(pname) \
627 glGetIntegerv(pname, &value); \
630 VuoLog(VuoLog_moduleName, file, linenumber, func, #pname " (value %d) was still active when the context was disused. (This may result in leaks.)", value); \
631 VuoLog_backtrace(); \
639#define VuoGlCheckTextureBinding(pname, unit) \
642 glGetIntegerv(pname, &value); \
645 VuoLog(VuoLog_moduleName, file, linenumber, func, #pname " (texture %d on unit %d) was still active when the context was disused. (This may result in leaks.)", value, unit); \
646 VuoLog_backtrace(); \
657 static GLint supportedSamples = 0;
658 static dispatch_once_t multisamplingCheck = 0;
659 dispatch_once(&multisamplingCheck, ^{
661#pragma clang diagnostic push
662#pragma clang diagnostic ignored "-Wdeprecated-declarations"
663 CGLGetParameter((CGLContextObj)context, kCGLCPCurrentRendererID, &rendererID);
664#pragma clang diagnostic pop
665 rendererID &= kCGLRendererIDMatchingMask;
667 CGLContextObj cgl_ctx = (CGLContextObj)context;
668 const char *renderer = (
const char *)glGetString(GL_RENDERER);
670 if (rendererID == kCGLRendererIntelHD4000ID
671 || rendererID == 0x00024500
672 || strcmp(renderer,
"NVIDIA GeForce 320M OpenGL Engine") == 0)
673 supportedSamples = 0;
676 glGetIntegerv(GL_MAX_SAMPLES, &supportedSamples);
677 if (supportedSamples == 1)
678 supportedSamples = 0;
681 return supportedSamples;
699#pragma clang diagnostic push
700#pragma clang diagnostic ignored "-Wdeprecated-declarations"
702 static dispatch_once_t multisamplingCheck = 0;
703 static int multisample = 0;
704 dispatch_once(&multisamplingCheck, ^{
706 CGLContextObj cgl_ctx;
708 CGLPixelFormatObj pf;
710 CGLPixelFormatAttribute pfa[14] = {
712 kCGLPFAAllowOfflineRenderers,
715 kCGLPFABackingVolatile,
716 kCGLPFAColorSize, (CGLPixelFormatAttribute) 24,
717 kCGLPFADepthSize, (CGLPixelFormatAttribute) (hasDepthBuffer ? 16 : 0),
718 (CGLPixelFormatAttribute) 0
721 CGLError error = CGLChoosePixelFormat(pfa, &pf, &npix);
722 if (error != kCGLNoError)
724 VUserLog(
"Error: %s", CGLErrorString(error));
729 CGLError error = CGLCreateContext(pf, NULL, &cgl_ctx);
730 CGLDestroyPixelFormat(pf);
731 if (error != kCGLNoError)
733 VUserLog(
"Error: %s", CGLErrorString(error));
740 Boolean overridden =
false;
741 multisample = (int)CFPreferencesGetAppIntegerValue(CFSTR(
"multisample"), CFSTR(
"org.vuo.Editor"), &overridden);
748 multisample =
MIN(4, supportedSamples);
751 CGLDestroyContext(cgl_ctx);
755 CGLPixelFormatAttribute pfa[18];
759 if (displayMask == -1)
760 pfa[pfaIndex++] = kCGLPFAAccelerated;
762 pfa[pfaIndex++] = kCGLPFAAllowOfflineRenderers;
767 pfa[pfaIndex++] = kCGLPFABackingVolatile;
769 pfa[pfaIndex++] = kCGLPFAColorSize; pfa[pfaIndex++] = (CGLPixelFormatAttribute) 24;
770 pfa[pfaIndex++] = kCGLPFADepthSize; pfa[pfaIndex++] = (CGLPixelFormatAttribute) (hasDepthBuffer ? 16 : 0);
773 pfa[pfaIndex++] = kCGLPFAOpenGLProfile; pfa[pfaIndex++] = (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core;
778 pfa[pfaIndex++] = kCGLPFAMultisample;
779 pfa[pfaIndex++] = kCGLPFASampleBuffers; pfa[pfaIndex++] = (CGLPixelFormatAttribute) 1;
780 pfa[pfaIndex++] = kCGLPFASamples; pfa[pfaIndex++] = (CGLPixelFormatAttribute) multisample;
783 if (displayMask >= 0)
785 pfa[pfaIndex++] = kCGLPFADisplayMask;
786 pfa[pfaIndex++] = (CGLPixelFormatAttribute) displayMask;
790 if ((displayMask & 0xff) == 0xff && displayMask != -1)
792 pfa[pfaIndex++] = kCGLPFARendererID;
793 pfa[pfaIndex++] = (CGLPixelFormatAttribute) kCGLRendererGenericFloatID;
796 pfa[pfaIndex] = (CGLPixelFormatAttribute) 0;
798 CGLPixelFormatObj pf;
800 CGLError error = CGLChoosePixelFormat(pfa, &pf, &npix);
801 if (error == kCGLBadDisplay)
802 return (CGLPixelFormatObj)-1;
803 else if (error != kCGLNoError)
805 VUserLog(
"Error: %s", CGLErrorString(error));
810#pragma clang diagnostic pop
819 CGLContextObj cgl_ctx = (CGLContextObj)context;
826 const unsigned char *contextVersion = glGetString(GL_VERSION);
827 return contextVersion[0] ==
'3'
828 || contextVersion[0] ==
'4';
832void _VGL_describe(GLenum error, CGLContextObj cgl_ctx,
const char *file,
const unsigned int linenumber,
const char *func);
837void _VGL(CGLContextObj cgl_ctx,
const char *file,
const unsigned int linenumber,
const char *func)
839#pragma clang diagnostic push
840#pragma clang diagnostic ignored "-Wdeprecated-declarations"
841 GLint vertexOnGPU, fragmentOnGPU;
842 CGLGetParameter(cgl_ctx, kCGLCPGPUVertexProcessing, &vertexOnGPU);
844 VuoLog(
VuoLog_moduleName, file, linenumber, func,
"OpenGL warning: Falling back to software renderer for vertex shader. This will slow things down.");
845 CGLGetParameter(cgl_ctx, kCGLCPGPUFragmentProcessing, &fragmentOnGPU);
847 VuoLog(
VuoLog_moduleName, file, linenumber, func,
"OpenGL warning: Falling back to software renderer for fragment shader. This will slow things down.");
848#pragma clang diagnostic pop
850 bool foundError =
false;
853 GLenum error = glGetError();
854 if (error == GL_NO_ERROR)
856 _VGL_describe(error, cgl_ctx, file, linenumber, func);
867void _VGL_describe(GLenum error, CGLContextObj cgl_ctx,
const char *file,
const unsigned int linenumber,
const char *func)
870 const char *errorString =
"(unknown)";
871 if (error == GL_INVALID_ENUM)
872 errorString =
"GL_INVALID_ENUM (An unacceptable value is specified for an enumerated argument. The offending command is ignored and has no other side effect than to set the error flag.)";
873 else if (error == GL_INVALID_VALUE)
874 errorString =
"GL_INVALID_VALUE (A numeric argument is out of range. The offending command is ignored and has no other side effect than to set the error flag.)";
875 else if (error == GL_INVALID_OPERATION)
876 errorString =
"GL_INVALID_OPERATION (The specified operation is not allowed in the current state. The offending command is ignored and has no other side effect than to set the error flag.)";
877 else if (error == GL_INVALID_FRAMEBUFFER_OPERATION)
879 errorString =
"GL_INVALID_FRAMEBUFFER_OPERATION (The framebuffer object is not complete. The offending command is ignored and has no other side effect than to set the error flag.)";
882 GLenum framebufferError = glCheckFramebufferStatus(GL_FRAMEBUFFER);
884 const char *framebufferErrorString =
"(unknown)";
885 if (framebufferError == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)
886 framebufferErrorString =
"GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT (Not all framebuffer attachment points are framebuffer attachment complete. This means that at least one attachment point with a renderbuffer or texture attached has its attached object no longer in existence or has an attached image with a width or height of zero, or the color attachment point has a non-color-renderable image attached, or the depth attachment point has a non-depth-renderable image attached, or the stencil attachment point has a non-stencil-renderable image attached.)";
889 else if (framebufferError == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT)
890 framebufferErrorString =
"GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT (No images are attached to the framebuffer.)";
891 else if (framebufferError == GL_FRAMEBUFFER_UNSUPPORTED)
892 framebufferErrorString =
"GL_FRAMEBUFFER_UNSUPPORTED (The combination of internal formats of the attached images violates an implementation-dependent set of restrictions.)";
893 else if (framebufferError == GL_FRAMEBUFFER_COMPLETE)
894 framebufferErrorString =
"GL_FRAMEBUFFER_COMPLETE (?)";
895 else if (framebufferError == GL_FRAMEBUFFER_UNDEFINED)
896 framebufferErrorString =
"GL_FRAMEBUFFER_UNDEFINED";
897 VuoLog(
VuoLog_moduleName, file, linenumber, func,
"OpenGL framebuffer error %d: %s", framebufferError, framebufferErrorString);
901 else if (error == GL_OUT_OF_MEMORY)
902 errorString =
"GL_OUT_OF_MEMORY (There is not enough memory left to execute the command. The state of the GL is undefined, except for the state of the error flags, after this error is recorded.)";
903 else if (error == GL_STACK_UNDERFLOW)
904 errorString =
"GL_STACK_UNDERFLOW (An attempt has been made to perform an operation that would cause an internal stack to underflow.)";
905 else if (error == GL_STACK_OVERFLOW)
906 errorString =
"GL_STACK_OVERFLOW (An attempt has been made to perform an operation that would cause an internal stack to overflow.)";