1 | /* $Id: OpenGLTestDarwin.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * VBox host opengl support test
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2009-2023 Oracle and/or its affiliates.
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox base platform packages, as
|
---|
10 | * available from https://www.virtualbox.org.
|
---|
11 | *
|
---|
12 | * This program is free software; you can redistribute it and/or
|
---|
13 | * modify it under the terms of the GNU General Public License
|
---|
14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
15 | * License.
|
---|
16 | *
|
---|
17 | * This program is distributed in the hope that it will be useful, but
|
---|
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
20 | * General Public License for more details.
|
---|
21 | *
|
---|
22 | * You should have received a copy of the GNU General Public License
|
---|
23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
24 | *
|
---|
25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
26 | */
|
---|
27 |
|
---|
28 |
|
---|
29 | /*********************************************************************************************************************************
|
---|
30 | * Header Files *
|
---|
31 | *********************************************************************************************************************************/
|
---|
32 | #include <VBox/VBoxOGL.h>
|
---|
33 |
|
---|
34 | #include <IOKit/IOKitLib.h>
|
---|
35 | #include <OpenGL/OpenGL.h>
|
---|
36 | #include <ApplicationServices/ApplicationServices.h>
|
---|
37 | #include <OpenGL/gl.h>
|
---|
38 | #include <OpenGL/glu.h>
|
---|
39 |
|
---|
40 | #include <iprt/env.h>
|
---|
41 | #include <iprt/log.h>
|
---|
42 | #include <iprt/once.h>
|
---|
43 |
|
---|
44 |
|
---|
45 |
|
---|
46 | /**
|
---|
47 | * @callback_method_impl{FNRTONCE,
|
---|
48 | * For determining the cached VBoxOglIsOfflineRenderingAppropriate result.}
|
---|
49 | */
|
---|
50 | static DECLCALLBACK(int32_t) vboxOglIsOfflineRenderingAppropriateOnce(void *pvUser)
|
---|
51 | {
|
---|
52 | bool *pfAppropriate = (bool *)pvUser;
|
---|
53 |
|
---|
54 | /* It is assumed that it is makes sense to enable offline rendering
|
---|
55 | only in case if host has more than one GPU installed. This routine
|
---|
56 | counts all the PCI devices in IORegistry which have IOName property
|
---|
57 | set to "display". If the number of such devices is greater than one,
|
---|
58 | it sets pfAppropriate to TRUE, otherwise to FALSE. */
|
---|
59 |
|
---|
60 | CFStringRef apKeyStrings[] = { CFSTR(kIOProviderClassKey), CFSTR(kIONameMatchKey) };
|
---|
61 | CFStringRef apValueStrings[] = { CFSTR("IOPCIDevice"), CFSTR("display") };
|
---|
62 | Assert(RT_ELEMENTS(apKeyStrings) == RT_ELEMENTS(apValueStrings));
|
---|
63 |
|
---|
64 | CFDictionaryRef pMatchingDictionary = CFDictionaryCreate(kCFAllocatorDefault,
|
---|
65 | (const void **)apKeyStrings,
|
---|
66 | (const void **)apValueStrings,
|
---|
67 | RT_ELEMENTS(apKeyStrings),
|
---|
68 | &kCFTypeDictionaryKeyCallBacks,
|
---|
69 | &kCFTypeDictionaryValueCallBacks);
|
---|
70 | if (pMatchingDictionary)
|
---|
71 | {
|
---|
72 | /* The reference to pMatchingDictionary is consumed by the function below => no IORelease(pMatchingDictionary)! */
|
---|
73 | io_iterator_t matchingServices;
|
---|
74 | kern_return_t krc = IOServiceGetMatchingServices(kIOMasterPortDefault, pMatchingDictionary, &matchingServices);
|
---|
75 | if (krc == kIOReturnSuccess)
|
---|
76 | {
|
---|
77 | io_object_t matchingService;
|
---|
78 | int cMatchingServices = 0;
|
---|
79 |
|
---|
80 | while ((matchingService = IOIteratorNext(matchingServices)) != 0)
|
---|
81 | {
|
---|
82 | cMatchingServices++;
|
---|
83 | IOObjectRelease(matchingService);
|
---|
84 | }
|
---|
85 |
|
---|
86 | *pfAppropriate = cMatchingServices > 1;
|
---|
87 |
|
---|
88 | IOObjectRelease(matchingServices);
|
---|
89 | }
|
---|
90 | }
|
---|
91 |
|
---|
92 | LogRel(("OpenGL: Offline rendering support is %s (pid=%d)\n", *pfAppropriate ? "ON" : "OFF", (int)getpid()));
|
---|
93 | return VINF_SUCCESS;
|
---|
94 | }
|
---|
95 |
|
---|
96 |
|
---|
97 | bool RTCALL VBoxOglIsOfflineRenderingAppropriate(void)
|
---|
98 | {
|
---|
99 | /* In order to do not slowdown 3D engine which can ask about offline rendering several times,
|
---|
100 | let's cache the result and assume that renderers amount value is constant. Use the IPRT
|
---|
101 | execute once construct to make sure there aren't any threading issues. */
|
---|
102 | static RTONCE s_Once = RTONCE_INITIALIZER;
|
---|
103 | static bool s_fCached = false;
|
---|
104 | int rc = RTOnce(&s_Once, vboxOglIsOfflineRenderingAppropriateOnce, &s_fCached);
|
---|
105 | AssertRC(rc);
|
---|
106 | return s_fCached;
|
---|
107 | }
|
---|
108 |
|
---|
109 |
|
---|
110 | bool RTCALL VBoxOglIs3DAccelerationSupported(void)
|
---|
111 | {
|
---|
112 | if (RTEnvExist("VBOX_3D_FORCE_SUPPORTED"))
|
---|
113 | {
|
---|
114 | LogRel(("VBOX_3D_FORCE_SUPPORTED is specified, skipping 3D test, and treating as supported\n"));
|
---|
115 | return true;
|
---|
116 | }
|
---|
117 |
|
---|
118 | CGOpenGLDisplayMask cglDisplayMask = CGDisplayIDToOpenGLDisplayMask(CGMainDisplayID());
|
---|
119 | CGLPixelFormatAttribute aAttribs[] =
|
---|
120 | {
|
---|
121 | kCGLPFADisplayMask,
|
---|
122 | (CGLPixelFormatAttribute)cglDisplayMask,
|
---|
123 | kCGLPFAAccelerated,
|
---|
124 | kCGLPFADoubleBuffer,
|
---|
125 | VBoxOglIsOfflineRenderingAppropriate() ? kCGLPFAAllowOfflineRenderers : (CGLPixelFormatAttribute)NULL,
|
---|
126 | (CGLPixelFormatAttribute)NULL
|
---|
127 | };
|
---|
128 | CGLPixelFormatObj pPixelFormat = NULL;
|
---|
129 | GLint cPixelFormatsIgnored = 0;
|
---|
130 | CGLError rcCgl = CGLChoosePixelFormat(aAttribs, &pPixelFormat, &cPixelFormatsIgnored);
|
---|
131 | if (rcCgl != kCGLNoError)
|
---|
132 | {
|
---|
133 | LogRel(("OpenGL Info: 3D test unable to choose pixel format (rcCgl=0x%X)\n", rcCgl));
|
---|
134 | return false;
|
---|
135 | }
|
---|
136 |
|
---|
137 | if (pPixelFormat)
|
---|
138 | {
|
---|
139 | CGLContextObj pCglContext = 0;
|
---|
140 | rcCgl = CGLCreateContext(pPixelFormat, NULL, &pCglContext);
|
---|
141 | CGLDestroyPixelFormat(pPixelFormat);
|
---|
142 |
|
---|
143 | if (rcCgl != kCGLNoError)
|
---|
144 | {
|
---|
145 | LogRel(("OpenGL Info: 3D test unable to create context (rcCgl=0x%X)\n", rcCgl));
|
---|
146 | return false;
|
---|
147 | }
|
---|
148 |
|
---|
149 | if (pCglContext)
|
---|
150 | {
|
---|
151 | GLboolean isSupported = GL_TRUE;
|
---|
152 |
|
---|
153 | /*
|
---|
154 | * In the Cocoa port we depend on the GL_EXT_framebuffer_object &
|
---|
155 | * the GL_EXT_texture_rectangle extension. If they are not
|
---|
156 | * available, disable 3D support.
|
---|
157 | */
|
---|
158 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" /* gluCheckExtension deprecated since 10.10 - use MetalKit. */
|
---|
159 | CGLSetCurrentContext(pCglContext);
|
---|
160 | const GLubyte *pszExts = glGetString(GL_EXTENSIONS);
|
---|
161 | isSupported = gluCheckExtension((const GLubyte *)"GL_EXT_framebuffer_object", pszExts);
|
---|
162 | if (isSupported)
|
---|
163 | {
|
---|
164 | isSupported = gluCheckExtension((const GLubyte *)"GL_EXT_texture_rectangle", pszExts);
|
---|
165 | if (!isSupported)
|
---|
166 | LogRel(("OpenGL Info: 3D test found that GL_EXT_texture_rectangle extension not supported.\n"));
|
---|
167 | }
|
---|
168 | else
|
---|
169 | LogRel(("OpenGL Info: 3D test found that GL_EXT_framebuffer_object extension not supported.\n"));
|
---|
170 |
|
---|
171 | CGLDestroyContext(pCglContext);
|
---|
172 | LogRel(("OpenGL Info: 3D test %spassed\n", isSupported == GL_TRUE ? "" : "not "));
|
---|
173 | return isSupported == GL_TRUE;
|
---|
174 | }
|
---|
175 |
|
---|
176 | LogRel(("OpenGL Info: 3D test unable to create context (internal error).\n"));
|
---|
177 | }
|
---|
178 | else
|
---|
179 | LogRel(("OpenGL Info: 3D test unable to choose pixel format (internal error).\n"));
|
---|
180 |
|
---|
181 | return false;
|
---|
182 | }
|
---|
183 |
|
---|