• 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 "FbConfig.h"
16 
17 #include "host-common/opengl/emugl_config.h"
18 #include "host-common/feature_control.h"
19 #include "host-common/misc.h"
20 #include "FrameBuffer.h"
21 #include "OpenGLESDispatch/EGLDispatch.h"
22 
23 #include <stdio.h>
24 #include <string.h>
25 
26 namespace {
27 
28 #define E(...)  fprintf(stderr, __VA_ARGS__)
29 
30 #ifndef EGL_PRESERVED_RESOURCES
31 #define EGL_PRESERVED_RESOURCES 0x3030
32 #endif
33 
34 const GLuint kConfigAttributes[] = {
35     EGL_DEPTH_SIZE,     // must be first - see getDepthSize()
36     EGL_STENCIL_SIZE,   // must be second - see getStencilSize()
37     EGL_RENDERABLE_TYPE,// must be third - see getRenderableType()
38     EGL_SURFACE_TYPE,   // must be fourth - see getSurfaceType()
39     EGL_CONFIG_ID,      // must be fifth  - see chooseConfig()
40     EGL_BUFFER_SIZE,
41     EGL_ALPHA_SIZE,
42     EGL_BLUE_SIZE,
43     EGL_GREEN_SIZE,
44     EGL_RED_SIZE,
45     EGL_CONFIG_CAVEAT,
46     EGL_LEVEL,
47     EGL_MAX_PBUFFER_HEIGHT,
48     EGL_MAX_PBUFFER_PIXELS,
49     EGL_MAX_PBUFFER_WIDTH,
50     EGL_NATIVE_RENDERABLE,
51     EGL_NATIVE_VISUAL_ID,
52     EGL_NATIVE_VISUAL_TYPE,
53     EGL_PRESERVED_RESOURCES,
54     EGL_SAMPLES,
55     EGL_SAMPLE_BUFFERS,
56     EGL_TRANSPARENT_TYPE,
57     EGL_TRANSPARENT_BLUE_VALUE,
58     EGL_TRANSPARENT_GREEN_VALUE,
59     EGL_TRANSPARENT_RED_VALUE,
60     EGL_BIND_TO_TEXTURE_RGB,
61     EGL_BIND_TO_TEXTURE_RGBA,
62     EGL_MIN_SWAP_INTERVAL,
63     EGL_MAX_SWAP_INTERVAL,
64     EGL_LUMINANCE_SIZE,
65     EGL_ALPHA_MASK_SIZE,
66     EGL_COLOR_BUFFER_TYPE,
67     //EGL_MATCH_NATIVE_PIXMAP,
68     EGL_RECORDABLE_ANDROID,
69     EGL_CONFORMANT
70 };
71 
72 const size_t kConfigAttributesLen =
73         sizeof(kConfigAttributes) / sizeof(kConfigAttributes[0]);
74 
isCompatibleHostConfig(EGLConfig config,EGLDisplay display)75 bool isCompatibleHostConfig(EGLConfig config, EGLDisplay display) {
76     // Filter out configs which do not support pbuffers, since they
77     // are used to implement window surfaces.
78     EGLint surfaceType;
79     s_egl.eglGetConfigAttrib(
80             display, config, EGL_SURFACE_TYPE, &surfaceType);
81     if (!(surfaceType & EGL_PBUFFER_BIT)) {
82         return false;
83     }
84 
85     // Filter out configs that do not support RGB pixel values.
86     EGLint redSize = 0, greenSize = 0, blueSize = 0;
87     s_egl.eglGetConfigAttrib(
88             display, config,EGL_RED_SIZE, &redSize);
89     s_egl.eglGetConfigAttrib(
90             display, config, EGL_GREEN_SIZE, &greenSize);
91     s_egl.eglGetConfigAttrib(
92             display, config, EGL_BLUE_SIZE, &blueSize);
93     if (!redSize || !greenSize || !blueSize) {
94         return false;
95     }
96 
97     return true;
98 }
99 
100 }  // namespace
101 
~FbConfig()102 FbConfig::~FbConfig() {
103     delete [] mAttribValues;
104 }
105 
FbConfig(EGLConfig hostConfig,EGLDisplay hostDisplay)106 FbConfig::FbConfig(EGLConfig hostConfig, EGLDisplay hostDisplay) :
107         mEglConfig(hostConfig), mAttribValues() {
108     mAttribValues = new GLint[kConfigAttributesLen];
109     for (size_t i = 0; i < kConfigAttributesLen; ++i) {
110         mAttribValues[i] = 0;
111         s_egl.eglGetConfigAttrib(hostDisplay,
112                                  hostConfig,
113                                  kConfigAttributes[i],
114                                  &mAttribValues[i]);
115 
116         // This implementation supports guest window surfaces by wrapping
117         // them around host Pbuffers, so always report it to the guest.
118         if (kConfigAttributes[i] == EGL_SURFACE_TYPE) {
119             mAttribValues[i] |= EGL_WINDOW_BIT;
120         }
121 
122         // Don't report ES3 renderable type if we don't support it.
123         if (kConfigAttributes[i] == EGL_RENDERABLE_TYPE) {
124             if (!feature_is_enabled(
125                         kFeature_GLESDynamicVersion) &&
126                 mAttribValues[i] & EGL_OPENGL_ES3_BIT) {
127                 mAttribValues[i] &= ~EGL_OPENGL_ES3_BIT;
128             }
129         }
130     }
131 }
132 
FbConfigList(EGLDisplay display)133 FbConfigList::FbConfigList(EGLDisplay display) : mDisplay(display) {
134     if (display == EGL_NO_DISPLAY) {
135         E("%s: Invalid display value %p (EGL_NO_DISPLAY)\n",
136           __FUNCTION__, (void*)display);
137         return;
138     }
139 
140     EGLint numHostConfigs = 0;
141     if (!s_egl.eglGetConfigs(display, NULL, 0, &numHostConfigs)) {
142         E("%s: Could not get number of host EGL configs\n", __FUNCTION__);
143         return;
144     }
145     EGLConfig* hostConfigs = new EGLConfig[numHostConfigs];
146     s_egl.eglGetConfigs(display, hostConfigs, numHostConfigs, &numHostConfigs);
147 
148     mConfigs = new FbConfig*[numHostConfigs];
149     for (EGLint i = 0;  i < numHostConfigs; ++i) {
150         // Filter out configs that are not compatible with our implementation.
151         if (!isCompatibleHostConfig(hostConfigs[i], display)) {
152             continue;
153         }
154         mConfigs[mCount] = new FbConfig(hostConfigs[i], display);
155         mCount++;
156     }
157 
158     delete [] hostConfigs;
159 }
160 
~FbConfigList()161 FbConfigList::~FbConfigList() {
162     for (int n = 0; n < mCount; ++n) {
163         delete mConfigs[n];
164     }
165     delete [] mConfigs;
166 }
167 
chooseConfig(const EGLint * attribs,EGLint * configs,EGLint configsSize) const168 int FbConfigList::chooseConfig(const EGLint* attribs,
169                                EGLint* configs,
170                                EGLint configsSize) const {
171     EGLint numHostConfigs = 0;
172     if (!s_egl.eglGetConfigs(mDisplay, NULL, 0, &numHostConfigs)) {
173         E("%s: Could not get number of host EGL configs\n", __FUNCTION__);
174         return 0;
175     }
176 
177     EGLConfig* matchedConfigs = new EGLConfig[numHostConfigs];
178 
179     // If EGL_SURFACE_TYPE appears in |attribs|, the value passed to
180     // eglChooseConfig should be forced to EGL_PBUFFER_BIT because that's
181     // what it used by the current implementation, exclusively. This forces
182     // the rewrite of |attribs| into a new array.
183     bool hasSurfaceType = false;
184     bool wantSwapPreserved = false;
185     int surfaceTypeIdx = 0;
186     int numAttribs = 0;
187     while (attribs[numAttribs] != EGL_NONE) {
188         if (attribs[numAttribs] == EGL_SURFACE_TYPE) {
189             hasSurfaceType = true;
190             surfaceTypeIdx = numAttribs;
191             if (attribs[numAttribs+1] & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) {
192                 wantSwapPreserved = true;
193             }
194         }
195 
196         // Reject config if guest asked for ES3 and we don't have it.
197         if (attribs[numAttribs] == EGL_RENDERABLE_TYPE) {
198             if (attribs[numAttribs + 1] != EGL_DONT_CARE &&
199                 attribs[numAttribs + 1] & EGL_OPENGL_ES3_BIT_KHR &&
200                 (!feature_is_enabled(
201                          kFeature_GLESDynamicVersion) ||
202                  FrameBuffer::getMaxGLESVersion() <
203                          GLES_DISPATCH_MAX_VERSION_3_0)) {
204                 return 0;
205             }
206         }
207         numAttribs += 2;
208     }
209 
210     std::vector<EGLint> newAttribs(numAttribs);
211     memcpy(&newAttribs[0], attribs, numAttribs * sizeof(EGLint));
212 
213     int apiLevel;
214     emugl::getAvdInfo(NULL, &apiLevel);
215 
216     if (!hasSurfaceType) {
217         newAttribs.push_back(EGL_SURFACE_TYPE);
218         newAttribs.push_back(0);
219     } else if (wantSwapPreserved && apiLevel <= 19) {
220         newAttribs[surfaceTypeIdx + 1] &= ~(EGLint)EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
221     }
222     if (emugl::getRenderer() == SELECTED_RENDERER_SWIFTSHADER ||
223         emugl::getRenderer() == SELECTED_RENDERER_SWIFTSHADER_INDIRECT ||
224         emugl::getRenderer() == SELECTED_RENDERER_ANGLE ||
225         emugl::getRenderer() == SELECTED_RENDERER_ANGLE_INDIRECT) {
226         newAttribs.push_back(EGL_CONFIG_CAVEAT);
227         newAttribs.push_back(EGL_DONT_CARE);
228     }
229 
230     newAttribs.push_back(EGL_NONE);
231 
232     if (s_egl.eglChooseConfig(mDisplay,
233                               &newAttribs[0],
234                               matchedConfigs,
235                               numHostConfigs,
236                               &numHostConfigs) == EGL_FALSE) {
237         delete [] matchedConfigs;
238         return -s_egl.eglGetError();
239     }
240 
241     int result = 0;
242     for (int n = 0; n < numHostConfigs; ++n) {
243         // Don't count or write more than |configsSize| items if |configs|
244         // is not NULL.
245         if (configs && configsSize > 0 && result >= configsSize) {
246             break;
247         }
248         // Skip incompatible host configs.
249         if (!isCompatibleHostConfig(matchedConfigs[n], mDisplay)) {
250             continue;
251         }
252         // Find the FbConfig with the same EGL_CONFIG_ID
253         EGLint hostConfigId;
254         s_egl.eglGetConfigAttrib(
255                 mDisplay, matchedConfigs[n], EGL_CONFIG_ID, &hostConfigId);
256         for (int k = 0; k < mCount; ++k) {
257             int guestConfigId = mConfigs[k]->getConfigId();
258             if (guestConfigId == hostConfigId) {
259                 // There is a match. Write it to |configs| if it is not NULL.
260                 if (configs && result < configsSize) {
261                     configs[result] = (uint32_t)k;
262                 }
263                 result ++;
264                 break;
265             }
266         }
267     }
268 
269     delete [] matchedConfigs;
270 
271     return result;
272 }
273 
274 
getPackInfo(EGLint * numConfigs,EGLint * numAttributes) const275 void FbConfigList::getPackInfo(EGLint* numConfigs,
276                                EGLint* numAttributes) const {
277     if (numConfigs) {
278         *numConfigs = mCount;
279     }
280     if (numAttributes) {
281         *numAttributes = static_cast<EGLint>(kConfigAttributesLen);
282     }
283 }
284 
packConfigs(GLuint bufferByteSize,GLuint * buffer) const285 EGLint FbConfigList::packConfigs(GLuint bufferByteSize, GLuint* buffer) const {
286     GLuint numAttribs = static_cast<GLuint>(kConfigAttributesLen);
287     GLuint kGLuintSize = static_cast<GLuint>(sizeof(GLuint));
288     GLuint neededByteSize = (mCount + 1) * numAttribs * kGLuintSize;
289     if (!buffer || bufferByteSize < neededByteSize) {
290         return -neededByteSize;
291     }
292     // Write to the buffer the config attribute ids, followed for each one
293     // of the configs, their values.
294     memcpy(buffer, kConfigAttributes, kConfigAttributesLen * kGLuintSize);
295 
296     for (int i = 0; i < mCount; ++i) {
297         memcpy(buffer + (i + 1) * kConfigAttributesLen,
298                mConfigs[i]->mAttribValues,
299                kConfigAttributesLen * kGLuintSize);
300     }
301     return mCount;
302 }
303