1 // Copyright (C) 2015 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "EmulatedEglConfig.h"
16
17 #include "OpenGLESDispatch/EGLDispatch.h"
18 #include "gfxstream/host/Features.h"
19 #include "host-common/opengl/emugl_config.h"
20 #include "host-common/logging.h"
21 #include "host-common/misc.h"
22 #include "host-common/opengl/misc.h"
23
24 #include <stdio.h>
25 #include <string.h>
26
27 namespace gfxstream {
28 namespace gl {
29 namespace {
30
31 #ifndef EGL_PRESERVED_RESOURCES
32 #define EGL_PRESERVED_RESOURCES 0x3030
33 #endif
34
35 const GLuint kConfigAttributes[] = {
36 EGL_DEPTH_SIZE, // must be first - see getDepthSize()
37 EGL_STENCIL_SIZE, // must be second - see getStencilSize()
38 EGL_RENDERABLE_TYPE,// must be third - see getRenderableType()
39 EGL_SURFACE_TYPE, // must be fourth - see getSurfaceType()
40 EGL_CONFIG_ID, // must be fifth - see chooseConfig()
41 EGL_BUFFER_SIZE,
42 EGL_ALPHA_SIZE,
43 EGL_BLUE_SIZE,
44 EGL_GREEN_SIZE,
45 EGL_RED_SIZE,
46 EGL_CONFIG_CAVEAT,
47 EGL_LEVEL,
48 EGL_MAX_PBUFFER_HEIGHT,
49 EGL_MAX_PBUFFER_PIXELS,
50 EGL_MAX_PBUFFER_WIDTH,
51 EGL_NATIVE_RENDERABLE,
52 EGL_NATIVE_VISUAL_ID,
53 EGL_NATIVE_VISUAL_TYPE,
54 EGL_PRESERVED_RESOURCES,
55 EGL_SAMPLES,
56 EGL_SAMPLE_BUFFERS,
57 EGL_TRANSPARENT_TYPE,
58 EGL_TRANSPARENT_BLUE_VALUE,
59 EGL_TRANSPARENT_GREEN_VALUE,
60 EGL_TRANSPARENT_RED_VALUE,
61 EGL_BIND_TO_TEXTURE_RGB,
62 EGL_BIND_TO_TEXTURE_RGBA,
63 EGL_MIN_SWAP_INTERVAL,
64 EGL_MAX_SWAP_INTERVAL,
65 EGL_LUMINANCE_SIZE,
66 EGL_ALPHA_MASK_SIZE,
67 EGL_COLOR_BUFFER_TYPE,
68 //EGL_MATCH_NATIVE_PIXMAP,
69 EGL_RECORDABLE_ANDROID,
70 EGL_CONFORMANT
71 };
72
73 const size_t kConfigAttributesLen =
74 sizeof(kConfigAttributes) / sizeof(kConfigAttributes[0]);
75
isCompatibleHostConfig(EGLConfig config,EGLDisplay display)76 bool isCompatibleHostConfig(EGLConfig config, EGLDisplay display) {
77 // Filter out configs which do not support pbuffers, since they
78 // are used to implement window surfaces.
79 EGLint surfaceType;
80 s_egl.eglGetConfigAttrib(
81 display, config, EGL_SURFACE_TYPE, &surfaceType);
82 if (!(surfaceType & EGL_PBUFFER_BIT)) {
83 return false;
84 }
85
86 // Filter out configs that do not support RGB pixel values.
87 EGLint redSize = 0, greenSize = 0, blueSize = 0;
88 s_egl.eglGetConfigAttrib(
89 display, config,EGL_RED_SIZE, &redSize);
90 s_egl.eglGetConfigAttrib(
91 display, config, EGL_GREEN_SIZE, &greenSize);
92 s_egl.eglGetConfigAttrib(
93 display, config, EGL_BLUE_SIZE, &blueSize);
94 if (!redSize || !greenSize || !blueSize) {
95 return false;
96 }
97
98 return true;
99 }
100
101 } // namespace
102
EmulatedEglConfig(EGLint guestConfig,EGLConfig hostConfig,EGLDisplay hostDisplay,bool glesDynamicVersion)103 EmulatedEglConfig::EmulatedEglConfig(EGLint guestConfig,
104 EGLConfig hostConfig,
105 EGLDisplay hostDisplay,
106 bool glesDynamicVersion)
107 : mGuestConfig(guestConfig),
108 mHostConfig(hostConfig),
109 mAttribValues(kConfigAttributesLen),
110 mGlesDynamicVersion(glesDynamicVersion) {
111 for (size_t i = 0; i < kConfigAttributesLen; ++i) {
112 mAttribValues[i] = 0;
113 s_egl.eglGetConfigAttrib(hostDisplay,
114 hostConfig,
115 kConfigAttributes[i],
116 &mAttribValues[i]);
117
118 // This implementation supports guest window surfaces by wrapping
119 // them around host Pbuffers, so always report it to the guest.
120 if (kConfigAttributes[i] == EGL_SURFACE_TYPE) {
121 mAttribValues[i] |= EGL_WINDOW_BIT;
122 }
123
124 // Don't report ES3 renderable type if we don't support it.
125 if (kConfigAttributes[i] == EGL_RENDERABLE_TYPE) {
126 if (!mGlesDynamicVersion && mAttribValues[i] & EGL_OPENGL_ES3_BIT) {
127 mAttribValues[i] &= ~EGL_OPENGL_ES3_BIT;
128 }
129 }
130 }
131 }
132
EmulatedEglConfigList(EGLDisplay display,GLESDispatchMaxVersion version,const gfxstream::host::FeatureSet & features)133 EmulatedEglConfigList::EmulatedEglConfigList(EGLDisplay display,
134 GLESDispatchMaxVersion version,
135 const gfxstream::host::FeatureSet& features)
136 : mDisplay(display),
137 mGlesDispatchMaxVersion(version),
138 mGlesDynamicVersion(features.GlesDynamicVersion.enabled) {
139 if (display == EGL_NO_DISPLAY) {
140 ERR("Invalid display value %p (EGL_NO_DISPLAY).", (void*)display);
141 return;
142 }
143
144 EGLint numHostConfigs = 0;
145 if (!s_egl.eglGetConfigs(display, NULL, 0, &numHostConfigs)) {
146 ERR("Failed to get number of host EGL configs.");
147 return;
148 }
149 std::vector<EGLConfig> hostConfigs(numHostConfigs);
150 s_egl.eglGetConfigs(display, hostConfigs.data(), numHostConfigs, &numHostConfigs);
151
152 for (EGLConfig hostConfig : hostConfigs) {
153 // Filter out configs that are not compatible with our implementation.
154 if (!isCompatibleHostConfig(hostConfig, display)) {
155 continue;
156 }
157
158 const EGLint guestConfig = static_cast<EGLint>(mConfigs.size());
159 mConfigs.push_back(EmulatedEglConfig(guestConfig, hostConfig, display, mGlesDynamicVersion));
160 }
161 }
162
chooseConfig(const EGLint * attribs,EGLint * configs,EGLint configsSize) const163 int EmulatedEglConfigList::chooseConfig(const EGLint* attribs,
164 EGLint* configs,
165 EGLint configsSize) const {
166 EGLint numHostConfigs = 0;
167 if (!s_egl.eglGetConfigs(mDisplay, NULL, 0, &numHostConfigs)) {
168 ERR("Failed to get number of host EGL configs.");
169 return 0;
170 }
171
172 // If EGL_SURFACE_TYPE appears in |attribs|, the value passed to
173 // eglChooseConfig should be forced to EGL_PBUFFER_BIT because that's
174 // what it used by the current implementation, exclusively. This forces
175 // the rewrite of |attribs| into a new array.
176 bool hasSurfaceType = false;
177 bool wantSwapPreserved = false;
178 int surfaceTypeIdx = 0;
179 int numAttribs = 0;
180 std::vector<EGLint> newAttribs;
181 while (attribs[numAttribs] != EGL_NONE) {
182 if (attribs[numAttribs] == EGL_SURFACE_TYPE) {
183 hasSurfaceType = true;
184 surfaceTypeIdx = numAttribs;
185 if (attribs[numAttribs+1] & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) {
186 wantSwapPreserved = true;
187 }
188 }
189
190 // Reject config if guest asked for ES3 and we don't have it.
191 if (attribs[numAttribs] == EGL_RENDERABLE_TYPE) {
192 if (attribs[numAttribs + 1] != EGL_DONT_CARE &&
193 attribs[numAttribs + 1] & EGL_OPENGL_ES3_BIT_KHR &&
194 (!mGlesDynamicVersion || mGlesDispatchMaxVersion < GLES_DISPATCH_MAX_VERSION_3_0)) {
195 return 0;
196 }
197 }
198 numAttribs += 2;
199 }
200
201 if (numAttribs) {
202 newAttribs.resize(numAttribs);
203 memcpy(&newAttribs[0], attribs, numAttribs * sizeof(EGLint));
204 }
205
206 int apiLevel;
207 emugl::getAvdInfo(NULL, &apiLevel);
208
209 if (!hasSurfaceType) {
210 newAttribs.push_back(EGL_SURFACE_TYPE);
211 newAttribs.push_back(0);
212 } else if (wantSwapPreserved && apiLevel <= 19) {
213 newAttribs[surfaceTypeIdx + 1] &= ~(EGLint)EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
214 }
215 if (emugl::getRenderer() == SELECTED_RENDERER_SWIFTSHADER ||
216 emugl::getRenderer() == SELECTED_RENDERER_SWIFTSHADER_INDIRECT ||
217 emugl::getRenderer() == SELECTED_RENDERER_ANGLE ||
218 emugl::getRenderer() == SELECTED_RENDERER_ANGLE_INDIRECT) {
219 newAttribs.push_back(EGL_CONFIG_CAVEAT);
220 newAttribs.push_back(EGL_DONT_CARE);
221 }
222
223 newAttribs.push_back(EGL_NONE);
224
225
226 std::vector<EGLConfig> matchedConfigs(numHostConfigs);
227 if (s_egl.eglChooseConfig(mDisplay,
228 &newAttribs[0],
229 matchedConfigs.data(),
230 numHostConfigs,
231 &numHostConfigs) == EGL_FALSE) {
232 return -s_egl.eglGetError();
233 }
234
235 int result = 0;
236 for (int n = 0; n < numHostConfigs; ++n) {
237 // Don't count or write more than |configsSize| items if |configs|
238 // is not NULL.
239 if (configs && configsSize > 0 && result >= configsSize) {
240 break;
241 }
242 // Skip incompatible host configs.
243 if (!isCompatibleHostConfig(matchedConfigs[n], mDisplay)) {
244 continue;
245 }
246 // Find the EmulatedEglConfig with the same EGL_CONFIG_ID
247 EGLint hostConfigId;
248 s_egl.eglGetConfigAttrib(
249 mDisplay, matchedConfigs[n], EGL_CONFIG_ID, &hostConfigId);
250 for (const EmulatedEglConfig& config : mConfigs) {
251 if (config.getConfigId() == hostConfigId) {
252 // There is a match. Write it to |configs| if it is not NULL.
253 if (configs && result < configsSize) {
254 configs[result] = config.getGuestEglConfig();
255 }
256 result++;
257 break;
258 }
259 }
260 }
261
262 return result;
263 }
264
265
getPackInfo(EGLint * numConfigs,EGLint * numAttributes) const266 void EmulatedEglConfigList::getPackInfo(EGLint* numConfigs,
267 EGLint* numAttributes) const {
268 if (numConfigs) {
269 *numConfigs = mConfigs.size();
270 }
271 if (numAttributes) {
272 *numAttributes = static_cast<EGLint>(kConfigAttributesLen);
273 }
274 }
275
packConfigs(GLuint bufferByteSize,GLuint * buffer) const276 EGLint EmulatedEglConfigList::packConfigs(GLuint bufferByteSize, GLuint* buffer) const {
277 GLuint numAttribs = static_cast<GLuint>(kConfigAttributesLen);
278 GLuint kGLuintSize = static_cast<GLuint>(sizeof(GLuint));
279 GLuint neededByteSize = (mConfigs.size() + 1) * numAttribs * kGLuintSize;
280 if (!buffer || bufferByteSize < neededByteSize) {
281 return -neededByteSize;
282 }
283 // Write to the buffer the config attribute ids, followed for each one
284 // of the configs, their values.
285 memcpy(buffer, kConfigAttributes, kConfigAttributesLen * kGLuintSize);
286
287 for (int i = 0; i < mConfigs.size(); ++i) {
288 memcpy(buffer + (i + 1) * kConfigAttributesLen,
289 mConfigs[i].mAttribValues.data(),
290 kConfigAttributesLen * kGLuintSize);
291 }
292 return mConfigs.size();
293 }
294
295 } // namespace gl
296 } // namespace gfxstream