• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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