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