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