1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17 #include "GLESVersionDetector.h"
18 
19 #include "OpenGLESDispatch/EGLDispatch.h"
20 
21 #include "aemu/base/system/System.h"
22 #include "aemu/base/misc/StringUtils.h"
23 #include "host-common/feature_control.h"
24 #include "host-common/opengl/misc.h"
25 
26 #include <algorithm>
27 
28 namespace gfxstream {
29 namespace gl {
30 
31 // Config + context attributes to query the underlying OpenGL if it is
32 // a OpenGL ES backend. Only try for OpenGL ES 3, and assume OpenGL ES 2
33 // exists (if it doesn't, this is the least of our problems).
34 static const EGLint gles3ConfigAttribs[] =
35     { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
36       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT, EGL_NONE };
37 
38 static const EGLint pbufAttribs[] =
39     { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
40 
41 static const EGLint gles31Attribs[] =
42    { EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
43      EGL_CONTEXT_MINOR_VERSION_KHR, 1, EGL_NONE };
44 
45 static const EGLint gles30Attribs[] =
46    { EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
47      EGL_CONTEXT_MINOR_VERSION_KHR, 0, EGL_NONE };
48 
sTryContextCreation(EGLDisplay dpy,GLESDispatchMaxVersion ver)49 static bool sTryContextCreation(EGLDisplay dpy, GLESDispatchMaxVersion ver) {
50     EGLConfig config;
51     EGLSurface surface;
52 
53     const EGLint* contextAttribs = nullptr;
54 
55     // Assume ES2 capable.
56     if (ver == GLES_DISPATCH_MAX_VERSION_2) return true;
57 
58     switch (ver) {
59     case GLES_DISPATCH_MAX_VERSION_3_0:
60         contextAttribs = gles30Attribs;
61         break;
62     case GLES_DISPATCH_MAX_VERSION_3_1:
63         contextAttribs = gles31Attribs;
64         break;
65     default:
66         break;
67     }
68 
69     if (!contextAttribs) return false;
70 
71     int numConfigs;
72     if (!s_egl.eglChooseConfig(
73             dpy, gles3ConfigAttribs, &config, 1, &numConfigs) ||
74         numConfigs == 0) {
75         return false;
76     }
77 
78     surface = s_egl.eglCreatePbufferSurface(dpy, config, pbufAttribs);
79     if (surface == EGL_NO_SURFACE) {
80         return false;
81     }
82 
83     EGLContext ctx = s_egl.eglCreateContext(dpy, config, EGL_NO_CONTEXT,
84                                             contextAttribs);
85 
86     if (ctx == EGL_NO_CONTEXT) {
87         s_egl.eglDestroySurface(dpy, surface);
88         return false;
89     } else {
90         s_egl.eglDestroyContext(dpy, ctx);
91         s_egl.eglDestroySurface(dpy, surface);
92         return true;
93     }
94 }
95 
calcMaxVersionFromDispatch(const gfxstream::host::FeatureSet & features,EGLDisplay dpy)96 GLESDispatchMaxVersion calcMaxVersionFromDispatch(const gfxstream::host::FeatureSet& features,
97                                                   EGLDisplay dpy) {
98     // TODO: 3.1 is the highest
99     GLESDispatchMaxVersion maxVersion =
100        GLES_DISPATCH_MAX_VERSION_3_1;
101 
102     // TODO: CTS conformance for OpenGL ES 3.1
103     bool playStoreImage = features.PlayStoreImage.enabled;
104 
105     if (emugl::getRenderer() == SELECTED_RENDERER_HOST
106         || emugl::getRenderer() == SELECTED_RENDERER_SWIFTSHADER_INDIRECT
107         || emugl::getRenderer() == SELECTED_RENDERER_ANGLE_INDIRECT
108         || emugl::getRenderer() == SELECTED_RENDERER_ANGLE9_INDIRECT) {
109         if (s_egl.eglGetMaxGLESVersion) {
110             maxVersion =
111                 (GLESDispatchMaxVersion)s_egl.eglGetMaxGLESVersion(dpy);
112         }
113     } else {
114         if (playStoreImage ||
115             !sTryContextCreation(dpy, GLES_DISPATCH_MAX_VERSION_3_1)) {
116             maxVersion = GLES_DISPATCH_MAX_VERSION_3_0;
117             if (!sTryContextCreation(dpy, GLES_DISPATCH_MAX_VERSION_3_0)) {
118                 maxVersion = GLES_DISPATCH_MAX_VERSION_2;
119             }
120         }
121     }
122 
123     if (playStoreImage) {
124         maxVersion =
125             std::min(maxVersion,
126                      GLES_DISPATCH_MAX_VERSION_3_0);
127     }
128 
129     int maj = 2; int min = 0;
130     switch (maxVersion) {
131         case GLES_DISPATCH_MAX_VERSION_2:
132             maj = 2; min = 0; break;
133         case GLES_DISPATCH_MAX_VERSION_3_0:
134             maj = 3; min = 0; break;
135         case GLES_DISPATCH_MAX_VERSION_3_1:
136             maj = 3; min = 1; break;
137         case GLES_DISPATCH_MAX_VERSION_3_2:
138             maj = 3; min = 2; break;
139         default:
140             break;
141     }
142 
143     emugl::setGlesVersion(maj, min);
144 
145     return maxVersion;
146 }
147 
148 // For determining whether or not to use core profile OpenGL.
149 // (Note: This does not affect the detection of possible core profile configs,
150 // just whether to use them)
shouldEnableCoreProfile()151 bool shouldEnableCoreProfile() {
152     int dispatchMaj, dispatchMin;
153 
154     emugl::getGlesVersion(&dispatchMaj, &dispatchMin);
155     return emugl::getRenderer() == SELECTED_RENDERER_HOST &&
156            dispatchMaj > 2;
157 }
158 
sAddExtensionIfSupported(GLESDispatchMaxVersion currVersion,const std::string & from,GLESDispatchMaxVersion extVersion,const std::string & ext,std::string & to)159 void sAddExtensionIfSupported(GLESDispatchMaxVersion currVersion,
160                               const std::string& from,
161                               GLESDispatchMaxVersion extVersion,
162                               const std::string& ext,
163                               std::string& to) {
164     // If we chose a GLES version less than or equal to
165     // the |extVersion| the extension |ext| is tagged with,
166     // filter it according to the whitelist.
167     if (emugl::hasExtension(from.c_str(), ext.c_str()) &&
168         currVersion > extVersion) {
169         to += ext;
170         to += " ";
171     }
172 }
173 
sWhitelistedExtensionsGLES2(const std::string & hostExt)174 static bool sWhitelistedExtensionsGLES2(const std::string& hostExt) {
175 
176 #define WHITELIST(ext) \
177     if (hostExt == #ext) return true; \
178 
179 WHITELIST(GL_OES_compressed_ETC1_RGB8_texture)
180 WHITELIST(GL_OES_depth24)
181 WHITELIST(GL_OES_depth32)
182 WHITELIST(GL_OES_depth_texture)
183 WHITELIST(GL_OES_depth_texture_cube_map)
184 WHITELIST(GL_OES_EGL_image)
185 WHITELIST(GL_OES_EGL_image_external)
186 WHITELIST(GL_OES_EGL_sync)
187 WHITELIST(GL_OES_element_index_uint)
188 WHITELIST(GL_OES_framebuffer_object)
189 WHITELIST(GL_OES_packed_depth_stencil)
190 WHITELIST(GL_OES_rgb8_rgba8)
191 WHITELIST(GL_OES_standard_derivatives)
192 WHITELIST(GL_OES_texture_float)
193 WHITELIST(GL_OES_texture_float_linear)
194 WHITELIST(GL_OES_texture_half_float)
195 WHITELIST(GL_OES_texture_half_float_linear)
196 WHITELIST(GL_OES_texture_npot)
197 WHITELIST(GL_OES_texture_3D)
198 WHITELIST(GL_OVR_multiview2)
199 WHITELIST(GL_EXT_multiview_texture_multisample)
200 WHITELIST(GL_EXT_blend_minmax)
201 WHITELIST(GL_EXT_color_buffer_half_float)
202 WHITELIST(GL_EXT_draw_buffers)
203 WHITELIST(GL_EXT_instanced_arrays)
204 WHITELIST(GL_EXT_occlusion_query_boolean)
205 WHITELIST(GL_EXT_read_format_bgra)
206 WHITELIST(GL_EXT_texture_compression_rgtc)
207 WHITELIST(GL_EXT_texture_filter_anisotropic)
208 WHITELIST(GL_EXT_texture_format_BGRA8888)
209 WHITELIST(GL_EXT_texture_rg)
210 WHITELIST(GL_ANGLE_framebuffer_blit)
211 WHITELIST(GL_ANGLE_framebuffer_multisample)
212 WHITELIST(GL_ANGLE_instanced_arrays)
213 WHITELIST(GL_CHROMIUM_texture_filtering_hint)
214 WHITELIST(GL_NV_fence)
215 WHITELIST(GL_NV_framebuffer_blit)
216 WHITELIST(GL_NV_read_depth)
217 
218 #if defined(__linux__)
219 WHITELIST(GL_EXT_texture_compression_bptc)
220 WHITELIST(GL_EXT_texture_compression_s3tc)
221 #endif
222 
223 #undef WHITELIST
224 
225     return false;
226 }
227 
filterExtensionsBasedOnMaxVersion(const gfxstream::host::FeatureSet & features,GLESDispatchMaxVersion ver,const std::string & exts)228 std::string filterExtensionsBasedOnMaxVersion(const gfxstream::host::FeatureSet& features,
229                                               GLESDispatchMaxVersion ver,
230                                               const std::string& exts) {
231     // We need to advertise ES 2 extensions if:
232     // a. the dispatch version on the host is ES 2
233     // b. the guest image is not updated for ES 3+
234     // (GLESDynamicVersion is disabled)
235     if (ver > GLES_DISPATCH_MAX_VERSION_2 && features.GlesDynamicVersion.enabled) {
236         return exts;
237     }
238 
239     std::string filteredExtensions;
240     filteredExtensions.reserve(4096);
241     auto add = [&filteredExtensions](const std::string& hostExt) {
242         if (!hostExt.empty() &&
243             sWhitelistedExtensionsGLES2(hostExt)) {
244             filteredExtensions += hostExt;
245             filteredExtensions += " ";
246         }
247     };
248 
249     android::base::split<std::string>(exts, " ", add);
250 
251     return filteredExtensions;
252 }
253 
254 }  // namespace gl
255 }  // namespace gfxstream
256