20 #include <OpenGL/CGLMacro.h>
21 #include <CoreFoundation/CoreFoundation.h>
22 #include <CoreGraphics/CoreGraphics.h>
24 #include <dispatch/dispatch.h>
26 #include <mach-o/dyld.h>
27 #include <objc/objc-runtime.h>
53 CGLRendererInfoObj ri;
54 GLint rendererCount = 0;
55 CGLQueryRendererInfo(-1, &ri, &rendererCount);
56 for (
int i = 0; i < rendererCount; ++i)
59 CGLDescribeRenderer(ri, i, kCGLRPRendererID, &rendererID);
63 if (CGLDescribeRenderer(ri, i, kCGLRPOnline, &online) == kCGLNoError)
64 VUserLog(
" Online : %s", online ?
"yes" :
"no");
67 if (CGLDescribeRenderer(ri, i, kCGLRPAccelerated, &accelerated) == kCGLNoError)
68 VUserLog(
" Accelerated : %s", accelerated ?
"yes" :
"no");
70 GLint videoMegabytes = 0;
71 if (CGLDescribeRenderer(ri, i, kCGLRPVideoMemoryMegabytes, &videoMegabytes) == kCGLNoError
73 VUserLog(
" Video memory : %d MB", videoMegabytes);
75 GLint textureMegabytes = 0;
76 if (CGLDescribeRenderer(ri, i, kCGLRPTextureMemoryMegabytes, &textureMegabytes) == kCGLNoError
78 VUserLog(
" Texture memory : %d MB", textureMegabytes);
81 if (CGLDescribeRenderer(ri, i, kCGLRPDisplayMask, &displayMask) == kCGLNoError)
83 VUserLog(
" Display mask : 0x%x%s", displayMask, displayMask==0xff ?
" (any)" :
"");
84 if (displayMask != 0xff)
85 for (
unsigned long i = 0; i < screenCount; ++i)
86 if (displayMask & screens[i].displayMask)
91 if (CGLDescribeRenderer(ri, i, (CGLRendererProperty)133, &glVersion) == kCGLNoError)
92 VUserLog(
" OpenGL version : %d", glVersion);
95 if (pf != (CGLPixelFormatObj)-1)
97 CGLContextObj cgl_ctx;
98 CGLError error = CGLCreateContext(pf, NULL, &cgl_ctx);
99 if (error != kCGLNoError)
100 VUserLog(
" Error: %s\n", CGLErrorString(error));
103 GLint maxTextureSize;
104 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
105 VUserLog(
" OpenGL 2 : %s (%s) maxTextureSize=%d", glGetString(GL_RENDERER), glGetString(GL_VERSION), maxTextureSize);
106 CGLDestroyContext(cgl_ctx);
110 VUserLog(
" (Can't create an OpenGL 2 context on this renderer.)");
113 if (pf != (CGLPixelFormatObj)-1)
115 CGLContextObj cgl_ctx;
116 CGLError error = CGLCreateContext(pf, NULL, &cgl_ctx);
117 if (error != kCGLNoError)
118 VUserLog(
" Error: %s\n", CGLErrorString(error));
121 GLint maxTextureSize;
122 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
123 VUserLog(
" OpenGL Core Profile: %s (%s) maxTextureSize=%d", glGetString(GL_RENDERER), glGetString(GL_VERSION), maxTextureSize);
124 CGLDestroyContext(cgl_ctx);
128 VUserLog(
" (Can't create an OpenGL Core Profile context on this renderer.)");
131 if (CGLDescribeRenderer(ri, i, kCGLRPAcceleratedCompute, &cl) == kCGLNoError)
132 VUserLog(
" OpenCL supported : %s", cl ?
"yes" :
"no");
134 CGLDestroyRendererInfo(ri);
137 const char *gldriver =
"GLDriver";
138 size_t gldriverLen = strlen(gldriver);
139 uint32_t imageCount = _dyld_image_count();
140 for (uint32_t i = 0; i < imageCount; ++i)
142 const char *dylibPath = _dyld_get_image_name(i);
143 size_t len = strlen(dylibPath);
145 if (strcmp(dylibPath + len - gldriverLen, gldriver) == 0)
148 char *z = strdup(strrchr(dylibPath,
'/')+1);
149 z[strlen(z)-gldriverLen] = 0;
155 typedef void *(*mtlCopyAllDevicesType)(void);
156 mtlCopyAllDevicesType mtlCopyAllDevices = (mtlCopyAllDevicesType)dlsym(RTLD_DEFAULT,
"MTLCopyAllDevices");
157 if (mtlCopyAllDevices)
159 CFArrayRef mtlDevices = (CFArrayRef)mtlCopyAllDevices();
160 int mtlDeviceCount = CFArrayGetCount(mtlDevices);
163 for (
int i = 0; i < mtlDeviceCount; ++i)
165 id dev = (id)CFArrayGetValueAtIndex(mtlDevices, i);
166 VUserLog(
" %s:", (
char *)objc_msgSend(objc_msgSend(dev, sel_getUid(
"name")), sel_getUid(
"UTF8String")));
167 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"registryID")))
168 VUserLog(
" ID : %p", objc_msgSend(dev, sel_getUid(
"registryID")));
169 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"recommendedMaxWorkingSetSize")))
170 VUserLog(
" Recommended max working-set size : %lld MiB", (int64_t)objc_msgSend(dev, sel_getUid(
"recommendedMaxWorkingSetSize"))/1048576);
171 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"maxBufferLength")))
172 VUserLog(
" Max buffer length : %lld MiB", (int64_t)objc_msgSend(dev, sel_getUid(
"maxBufferLength"))/1048576);
173 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"maxThreadgroupMemoryLength")))
174 VUserLog(
" Threadgroup memory : %lld B", (int64_t)objc_msgSend(dev, sel_getUid(
"maxThreadgroupMemoryLength")));
175 VUserLog(
" Low-power : %s", objc_msgSend(dev, sel_getUid(
"isLowPower")) ?
"yes" :
"no");
176 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"isRemovable")))
177 VUserLog(
" Removable : %s", objc_msgSend(dev, sel_getUid(
"isRemovable")) ?
"yes" :
"no");
178 VUserLog(
" Headless : %s", objc_msgSend(dev, sel_getUid(
"isHeadless")) ?
"yes" :
"no");
180 if (objc_msgSend(dev, sel_getUid(
"supportsFeatureSet:"), 10005))
181 VUserLog(
" Feature set : GPU Family 2 v1");
182 else if (objc_msgSend(dev, sel_getUid(
"supportsFeatureSet:"), 10004))
183 VUserLog(
" Feature set : GPU Family 1 v4");
184 else if (objc_msgSend(dev, sel_getUid(
"supportsFeatureSet:"), 10003))
185 VUserLog(
" Feature set : GPU Family 1 v3");
186 else if (objc_msgSend(dev, sel_getUid(
"supportsFeatureSet:"), 10001))
187 VUserLog(
" Feature set : GPU Family 1 v2");
188 else if (objc_msgSend(dev, sel_getUid(
"supportsFeatureSet:"), 10000))
189 VUserLog(
" Feature set : GPU Family 1 v1");
191 VUserLog(
" Feature set : (unknown)");
193 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"readWriteTextureSupport")))
194 VUserLog(
" Read-write texture support tier : %lld", (int64_t)objc_msgSend(dev, sel_getUid(
"readWriteTextureSupport")));
195 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"argumentBuffersSupport")))
196 VUserLog(
" Argument buffer support tier : %lld", (int64_t)objc_msgSend(dev, sel_getUid(
"argumentBuffersSupport")));
197 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"maxArgumentBufferSamplerCount")))
198 VUserLog(
" Max argument buffers : %lld", (int64_t)objc_msgSend(dev, sel_getUid(
"maxArgumentBufferSamplerCount")));
199 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"areProgrammableSamplePositionsSupported")))
200 VUserLog(
" Programmable sample position support: %s", objc_msgSend(dev, sel_getUid(
"areProgrammableSamplePositionsSupported")) ?
"yes" :
"no");
201 if (class_respondsToSelector(object_getClass(dev), sel_getUid(
"areRasterOrderGroupsSupported")))
202 VUserLog(
" Raster order group support : %s", objc_msgSend(dev, sel_getUid(
"areRasterOrderGroupsSupported")) ?
"yes" :
"no");
204 CFRelease(mtlDevices);
213 if (!(flags & kCGDisplaySetModeFlag))
221 for (
unsigned long i = 0; i < screenCount; ++i)
222 if (screens[i].
id == display)
223 VUserLog(
"Display reconfigured: %s", screens[i].name);
239 VUserLog(
"Couldn't create the key for storing the GL Context state: %s", strerror(errno));
253 CGLContextObj context;
271 VUserLog(
"Error: Couldn't create a context.");
290 CGLContextObj cgl_ctx = (CGLContextObj)glContext;
316 glGetIntegerv(GL_MAX_TEXTURE_UNITS, &textureUnits);
317 for (GLint i=0; i<textureUnits; ++i)
319 glActiveTexture(GL_TEXTURE0+i);
342 VUserLog(
"Error: Disued context %p, which isn't in the global share pool. I'm not going to muddy the waters.", cgl_ctx);
350 #define VuoGlContext_checkGL(cap, value) \
352 if (glIsEnabled(cap) != value) \
354 VUserLog("Warning: Caller incorrectly left %s %s", #cap, value ? "disabled" : "enabled"); \
355 VuoLog_backtrace(); \
362 #define VuoGlContext_checkGLInt(key, value) \
365 glGetIntegerv(key, &actualValue); \
366 if (actualValue != value) \
368 VUserLog("Warning: Caller incorrectly left %s set to something other than %s", #key, #value); \
369 VuoLog_backtrace(); \
396 if (!alreadyLockedOnThisThread)
433 if (!alreadyLockedOnThisThread)
445 static dispatch_once_t info = 0;
446 dispatch_once(&info, ^{
455 CGLPixelFormatObj pf;
456 bool shouldDestroyPixelFormat =
false;
458 pf = CGLGetPixelFormat(rootContext);
461 Boolean overridden =
false;
462 GLint displayMask = (int)CFPreferencesGetAppIntegerValue(CFSTR(
"displayMask"), CFSTR(
"org.vuo.Editor"), &overridden);
466 auto displayMaskString = (CFStringRef)CFPreferencesCopyAppValue(CFSTR(
"displayMask"), CFSTR(
"org.vuo.Editor"));
467 if (displayMaskString)
470 CFRelease(displayMaskString);
472 overridden = sscanf(t,
"0x%x", &displayMask) == 1;
479 VDebugLog(
"displayMask = 0x%x", displayMask);
481 shouldDestroyPixelFormat =
true;
484 CGLContextObj context;
486 CGLError error = CGLCreateContext(pf, rootContext, &context);
487 if (shouldDestroyPixelFormat)
488 CGLDestroyPixelFormat(pf);
489 if (error != kCGLNoError)
491 VUserLog(
"Error: %s\n", CGLErrorString(error));
499 CGLGetParameter(context, kCGLCPCurrentRendererID, &rendererID);
500 VUserLog(
"Created OpenGL context %p%s on %s",
502 rootContext ?
VuoText_format(
" (shared with %p)", rootContext) :
" (not shared)",
513 CGLContextObj cgl_ctx = context;
515 glDisable(GL_DEPTH_TEST);
516 glEnable(GL_CULL_FACE);
518 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
519 glBlendEquation(GL_FUNC_ADD);
520 glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
521 glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -.5);
541 VUserLog(
"Error: Called after VuoGlContextPool was initialized. Ignoring the new rootContext.");
545 VDebugLog(
"Setting global root context to %p", rootContext);
553 #define VuoGlCheckBinding(pname) \
556 glGetIntegerv(pname, &value); \
559 VuoLog(file, linenumber, func, #pname " (value %d) was still active when the context was disused. (This may result in leaks.)", value); \
560 VuoLog_backtrace(); \
568 #define VuoGlCheckTextureBinding(pname, unit) \
571 glGetIntegerv(pname, &value); \
574 VuoLog(file, linenumber, func, #pname " (texture %d on unit %d) was still active when the context was disused. (This may result in leaks.)", value, unit); \
575 VuoLog_backtrace(); \
586 static GLint supportedSamples = 0;
587 static dispatch_once_t multisamplingCheck = 0;
588 dispatch_once(&multisamplingCheck, ^{
590 CGLGetParameter((CGLContextObj)context, kCGLCPCurrentRendererID, &rendererID);
591 rendererID &= kCGLRendererIDMatchingMask;
593 CGLContextObj cgl_ctx = (CGLContextObj)context;
594 const char *renderer = (
const char *)glGetString(GL_RENDERER);
596 if (rendererID == kCGLRendererIntelHD4000ID
597 || rendererID == 0x00024500
598 || strcmp(renderer,
"NVIDIA GeForce 320M OpenGL Engine") == 0)
599 supportedSamples = 0;
602 glGetIntegerv(GL_MAX_SAMPLES, &supportedSamples);
603 if (supportedSamples == 1)
604 supportedSamples = 0;
607 return supportedSamples;
626 static dispatch_once_t multisamplingCheck = 0;
627 static int multisample = 0;
628 dispatch_once(&multisamplingCheck, ^{
630 CGLContextObj cgl_ctx;
632 CGLPixelFormatObj pf;
634 CGLPixelFormatAttribute pfa[14] = {
636 kCGLPFAAllowOfflineRenderers,
639 kCGLPFABackingVolatile,
640 kCGLPFAColorSize, (CGLPixelFormatAttribute) 24,
641 kCGLPFADepthSize, (CGLPixelFormatAttribute) (hasDepthBuffer ? 16 : 0),
642 (CGLPixelFormatAttribute) 0
645 CGLError error = CGLChoosePixelFormat(pfa, &pf, &npix);
646 if (error != kCGLNoError)
648 VUserLog(
"Error: %s", CGLErrorString(error));
653 CGLError error = CGLCreateContext(pf, NULL, &cgl_ctx);
654 CGLDestroyPixelFormat(pf);
655 if (error != kCGLNoError)
657 VUserLog(
"Error: %s\n", CGLErrorString(error));
664 Boolean overridden =
false;
665 multisample = (int)CFPreferencesGetAppIntegerValue(CFSTR(
"multisample"), CFSTR(
"org.vuo.Editor"), &overridden);
672 multisample =
MIN(4, supportedSamples);
675 CGLDestroyContext(cgl_ctx);
679 CGLPixelFormatAttribute pfa[18];
683 if (displayMask == -1)
684 pfa[pfaIndex++] = kCGLPFAAccelerated;
686 pfa[pfaIndex++] = kCGLPFAAllowOfflineRenderers;
691 pfa[pfaIndex++] = kCGLPFABackingVolatile;
693 pfa[pfaIndex++] = kCGLPFAColorSize; pfa[pfaIndex++] = (CGLPixelFormatAttribute) 24;
694 pfa[pfaIndex++] = kCGLPFADepthSize; pfa[pfaIndex++] = (CGLPixelFormatAttribute) (hasDepthBuffer ? 16 : 0);
697 pfa[pfaIndex++] = kCGLPFAOpenGLProfile; pfa[pfaIndex++] = (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core;
702 pfa[pfaIndex++] = kCGLPFAMultisample;
703 pfa[pfaIndex++] = kCGLPFASampleBuffers; pfa[pfaIndex++] = (CGLPixelFormatAttribute) 1;
704 pfa[pfaIndex++] = kCGLPFASamples; pfa[pfaIndex++] = (CGLPixelFormatAttribute) multisample;
707 if (displayMask >= 0)
709 pfa[pfaIndex++] = kCGLPFADisplayMask;
710 pfa[pfaIndex++] = (CGLPixelFormatAttribute) displayMask;
714 if (displayMask == 0xff)
716 pfa[pfaIndex++] = kCGLPFARendererID;
717 pfa[pfaIndex++] = (CGLPixelFormatAttribute) kCGLRendererGenericFloatID;
720 pfa[pfaIndex] = (CGLPixelFormatAttribute) 0;
722 CGLPixelFormatObj pf;
724 CGLError error = CGLChoosePixelFormat(pfa, &pf, &npix);
725 if (error == kCGLBadDisplay)
726 return (CGLPixelFormatObj)-1;
727 else if (error != kCGLNoError)
729 VUserLog(
"Error: %s", CGLErrorString(error));
742 CGLContextObj cgl_ctx = (CGLContextObj)context;
749 const unsigned char *contextVersion = glGetString(GL_VERSION);
750 return contextVersion[0] ==
'3'
751 || contextVersion[0] ==
'4';
755 void _VGL_describe(GLenum error, CGLContextObj cgl_ctx,
const char *file,
const unsigned int linenumber,
const char *func);
760 void _VGL(CGLContextObj cgl_ctx,
const char *file,
const unsigned int linenumber,
const char *func)
762 GLint vertexOnGPU, fragmentOnGPU;
763 CGLGetParameter(cgl_ctx, kCGLCPGPUVertexProcessing, &vertexOnGPU);
765 VuoLog(file, linenumber, func,
"OpenGL warning: Falling back to software renderer for vertex shader. This will slow things down.");
766 CGLGetParameter(cgl_ctx, kCGLCPGPUFragmentProcessing, &fragmentOnGPU);
768 VuoLog(file, linenumber, func,
"OpenGL warning: Falling back to software renderer for fragment shader. This will slow things down.");
770 bool foundError =
false;
773 GLenum error = glGetError();
774 if (error == GL_NO_ERROR)
787 void _VGL_describe(GLenum error, CGLContextObj cgl_ctx,
const char *file,
const unsigned int linenumber,
const char *func)
790 const char *errorString =
"(unknown)";
791 if (error == GL_INVALID_ENUM)
792 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.)";
793 else if (error == GL_INVALID_VALUE)
794 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.)";
795 else if (error == GL_INVALID_OPERATION)
796 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.)";
797 else if (error == GL_INVALID_FRAMEBUFFER_OPERATION)
799 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.)";
800 VuoLog(file, linenumber, func,
"OpenGL error %d: %s", error, errorString);
802 GLenum framebufferError = glCheckFramebufferStatus(GL_FRAMEBUFFER);
804 const char *framebufferErrorString =
"(unknown)";
805 if (framebufferError == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)
806 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.)";
809 else if (framebufferError == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT)
810 framebufferErrorString =
"GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT (No images are attached to the framebuffer.)";
811 else if (framebufferError == GL_FRAMEBUFFER_UNSUPPORTED)
812 framebufferErrorString =
"GL_FRAMEBUFFER_UNSUPPORTED (The combination of internal formats of the attached images violates an implementation-dependent set of restrictions.)";
813 else if (framebufferError == GL_FRAMEBUFFER_COMPLETE)
814 framebufferErrorString =
"GL_FRAMEBUFFER_COMPLETE (?)";
815 else if (framebufferError == GL_FRAMEBUFFER_UNDEFINED)
816 framebufferErrorString =
"GL_FRAMEBUFFER_UNDEFINED";
817 VuoLog(file, linenumber, func,
"OpenGL framebuffer error %d: %s", framebufferError, framebufferErrorString);
821 else if (error == GL_OUT_OF_MEMORY)
822 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.)";
823 else if (error == GL_STACK_UNDERFLOW)
824 errorString =
"GL_STACK_UNDERFLOW (An attempt has been made to perform an operation that would cause an internal stack to underflow.)";
825 else if (error == GL_STACK_OVERFLOW)
826 errorString =
"GL_STACK_OVERFLOW (An attempt has been made to perform an operation that would cause an internal stack to overflow.)";
828 VuoLog(file, linenumber, func,
"OpenGL error %d: %s", error, errorString);