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