1 | /* $Id: OpenGLTestDarwin.cpp 52626 2014-09-05 19:28:16Z vboxsync $ */
|
---|
2 |
|
---|
3 | /** @file
|
---|
4 | * VBox host opengl support test
|
---|
5 | */
|
---|
6 |
|
---|
7 | /*
|
---|
8 | * Copyright (C) 2009-2014 Oracle Corporation
|
---|
9 | *
|
---|
10 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
11 | * available from http://www.virtualbox.org. This file is free software;
|
---|
12 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
13 | * General Public License (GPL) as published by the Free Software
|
---|
14 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
15 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
16 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
17 | */
|
---|
18 |
|
---|
19 |
|
---|
20 | #include <IOKit/IOKitLib.h>
|
---|
21 | #include <OpenGL/OpenGL.h>
|
---|
22 | #include <ApplicationServices/ApplicationServices.h>
|
---|
23 | #include <OpenGL/gl.h>
|
---|
24 | #ifdef VBOX_WITH_COCOA_QT
|
---|
25 | # include <OpenGL/glu.h>
|
---|
26 | # include <iprt/log.h>
|
---|
27 | #endif /* VBOX_WITH_COCOA_QT */
|
---|
28 | #include <iprt/env.h>
|
---|
29 | #include <iprt/log.h>
|
---|
30 |
|
---|
31 | #include <iprt/asm.h>
|
---|
32 | #include <iprt/thread.h>
|
---|
33 |
|
---|
34 | #include <VBox/VBoxOGLTest.h>
|
---|
35 |
|
---|
36 | bool RTCALL VBoxOglIsOfflineRenderingAppropriate()
|
---|
37 | {
|
---|
38 | /* It is assumed that it is makes sense to enable offline rendering
|
---|
39 | only in case if host has more than one GPU installed. This routine
|
---|
40 | counts all the PCI devices in IORegistry which have IOName property
|
---|
41 | set to "display". If the amount of such devices if greater than one,
|
---|
42 | it returns TRUE or FALSE otherwise. */
|
---|
43 |
|
---|
44 | kern_return_t krc;
|
---|
45 | io_iterator_t matchingServices;
|
---|
46 | CFDictionaryRef pMatchingDictionary;
|
---|
47 | static bool fAppropriate = false;
|
---|
48 |
|
---|
49 | /* In order to do not slowdown 3D engine which can ask about offline rendering several times,
|
---|
50 | let's cache the result and assume that renderers amount value is constant. Also prevent threads race
|
---|
51 | on startup. */
|
---|
52 |
|
---|
53 | #define VBOX_OGL_CHECK_UNINITIALIZED (0)
|
---|
54 | #define VBOX_OGL_CHECK_INITIALIZING (1)
|
---|
55 | #define VBOX_OGL_CHECK_INITIALIZED (2)
|
---|
56 |
|
---|
57 | /* Transition VBOX_OGL_CHECK_UNINITIALIZED -> VBOX_OGL_CHECK_INITIALIZING means the current thread
|
---|
58 | is the first one who entered the routine. In this case, it should detect number of GPUs, cache result
|
---|
59 | and return it. If it's not TRUE, then fInitialized is VBOX_OGL_CHECK_INITIALIZING (another thread is performing
|
---|
60 | the check; current thread should wait till result will be cached and return it) or VBOX_OGL_CHECK_INITIALIZED
|
---|
61 | (result is already cached; just return it.) */
|
---|
62 |
|
---|
63 | static uint32_t volatile fInitialized = VBOX_OGL_CHECK_UNINITIALIZED;
|
---|
64 | if (!ASMAtomicCmpXchgU32(&fInitialized, VBOX_OGL_CHECK_INITIALIZING, VBOX_OGL_CHECK_UNINITIALIZED))
|
---|
65 | {
|
---|
66 | while (ASMAtomicReadU32(&fInitialized) != VBOX_OGL_CHECK_INITIALIZED)
|
---|
67 | RTThreadSleep(5);
|
---|
68 |
|
---|
69 | return fAppropriate;
|
---|
70 | }
|
---|
71 |
|
---|
72 | #define VBOX_OGL_RENDERER_MATCH_KEYS_NUM (2)
|
---|
73 |
|
---|
74 | CFStringRef ppDictionaryKeys[VBOX_OGL_RENDERER_MATCH_KEYS_NUM] = { CFSTR(kIOProviderClassKey), CFSTR(kIONameMatchKey) };
|
---|
75 | CFStringRef ppDictionaryVals[VBOX_OGL_RENDERER_MATCH_KEYS_NUM] = { CFSTR("IOPCIDevice"), CFSTR("display") };
|
---|
76 |
|
---|
77 | pMatchingDictionary = CFDictionaryCreate(kCFAllocatorDefault,
|
---|
78 | (const void **)ppDictionaryKeys,
|
---|
79 | (const void **)ppDictionaryVals,
|
---|
80 | VBOX_OGL_RENDERER_MATCH_KEYS_NUM,
|
---|
81 | &kCFTypeDictionaryKeyCallBacks,
|
---|
82 | &kCFTypeDictionaryValueCallBacks);
|
---|
83 | if (pMatchingDictionary)
|
---|
84 | {
|
---|
85 | /* The reference to pMatchingDictionary is consumed by the function below => no IORelease(pMatchingDictionary)! */
|
---|
86 | krc = IOServiceGetMatchingServices(kIOMasterPortDefault, pMatchingDictionary, &matchingServices);
|
---|
87 | if (krc == kIOReturnSuccess)
|
---|
88 | {
|
---|
89 | io_object_t matchingService;
|
---|
90 | int cMatchingServices = 0;
|
---|
91 |
|
---|
92 | while ((matchingService = IOIteratorNext(matchingServices)) != 0)
|
---|
93 | {
|
---|
94 | cMatchingServices++;
|
---|
95 | IOObjectRelease(matchingService);
|
---|
96 | }
|
---|
97 |
|
---|
98 | fAppropriate = (cMatchingServices > 1);
|
---|
99 |
|
---|
100 | IOObjectRelease(matchingServices);
|
---|
101 | }
|
---|
102 |
|
---|
103 | }
|
---|
104 |
|
---|
105 | LogRel(("OpenGL: Offline rendering support is %s (PID=%d)\n", fAppropriate ? "ON" : "OFF", (int)getpid()));
|
---|
106 |
|
---|
107 | ASMAtomicWriteU32(&fInitialized, VBOX_OGL_CHECK_INITIALIZED);
|
---|
108 |
|
---|
109 | return fAppropriate;
|
---|
110 | }
|
---|
111 |
|
---|
112 | bool RTCALL VBoxOglIs3DAccelerationSupported()
|
---|
113 | {
|
---|
114 | if (RTEnvExist("VBOX_CROGL_FORCE_SUPPORTED"))
|
---|
115 | {
|
---|
116 | LogRel(("VBOX_CROGL_FORCE_SUPPORTED is specified, skipping 3D test, and treating as supported\n"));
|
---|
117 | return true;
|
---|
118 | }
|
---|
119 |
|
---|
120 | CGDirectDisplayID display = CGMainDisplayID ();
|
---|
121 | CGOpenGLDisplayMask cglDisplayMask = CGDisplayIDToOpenGLDisplayMask (display);
|
---|
122 | CGLPixelFormatObj pixelFormat = NULL;
|
---|
123 | GLint numPixelFormats = 0;
|
---|
124 |
|
---|
125 | CGLPixelFormatAttribute attribs[] = {
|
---|
126 | kCGLPFADisplayMask,
|
---|
127 | (CGLPixelFormatAttribute)cglDisplayMask,
|
---|
128 | kCGLPFAAccelerated,
|
---|
129 | kCGLPFADoubleBuffer,
|
---|
130 | kCGLPFAWindow,
|
---|
131 | VBoxOglIsOfflineRenderingAppropriate() ? kCGLPFAAllowOfflineRenderers : (CGLPixelFormatAttribute)NULL,
|
---|
132 | (CGLPixelFormatAttribute)NULL
|
---|
133 | };
|
---|
134 |
|
---|
135 | display = CGMainDisplayID();
|
---|
136 | cglDisplayMask = CGDisplayIDToOpenGLDisplayMask(display);
|
---|
137 | CGLChoosePixelFormat(attribs, &pixelFormat, &numPixelFormats);
|
---|
138 |
|
---|
139 | if (pixelFormat)
|
---|
140 | {
|
---|
141 | CGLContextObj cglContext = 0;
|
---|
142 | CGLCreateContext(pixelFormat, NULL, &cglContext);
|
---|
143 | CGLDestroyPixelFormat(pixelFormat);
|
---|
144 | if (cglContext)
|
---|
145 | {
|
---|
146 | GLboolean isSupported = GL_TRUE;
|
---|
147 | #ifdef VBOX_WITH_COCOA_QT
|
---|
148 | /* On the Cocoa port we depend on the GL_EXT_framebuffer_object &
|
---|
149 | * the GL_EXT_texture_rectangle extension. If they are not
|
---|
150 | * available, disable 3D support. */
|
---|
151 | CGLSetCurrentContext(cglContext);
|
---|
152 | const GLubyte* strExt;
|
---|
153 | strExt = glGetString(GL_EXTENSIONS);
|
---|
154 | isSupported = gluCheckExtension((const GLubyte*)"GL_EXT_framebuffer_object", strExt);
|
---|
155 | if (isSupported)
|
---|
156 | {
|
---|
157 | isSupported = gluCheckExtension((const GLubyte*)"GL_EXT_texture_rectangle", strExt);
|
---|
158 | if (!isSupported)
|
---|
159 | LogRel(("OpenGL Info: GL_EXT_texture_rectangle extension not supported\n"));
|
---|
160 | }
|
---|
161 | else
|
---|
162 | LogRel(("OpenGL Info: GL_EXT_framebuffer_object extension not supported\n"));
|
---|
163 | #endif /* VBOX_WITH_COCOA_QT */
|
---|
164 | CGLDestroyContext(cglContext);
|
---|
165 | return isSupported == GL_TRUE ? true : false;
|
---|
166 | }
|
---|
167 | }
|
---|
168 |
|
---|
169 | return false;
|
---|
170 | }
|
---|
171 |
|
---|