blob: 1d84562c320ad8766fa6ac1b16a3a04f31aeb686 [file] [log] [blame]
Lingfeng Yangee4aea32020-10-29 08:52:13 -07001// 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
Jason Macnakfb647c22022-09-02 09:44:00 -070015#include "EmulatedEglConfig.h"
Lingfeng Yangee4aea32020-10-29 08:52:13 -070016
Jason Macnak491f7582022-08-30 14:08:59 -070017#include "OpenGLESDispatch/EGLDispatch.h"
Jason Macnak26872122024-02-23 10:46:09 -080018#include "gfxstream/host/Features.h"
Lingfeng Yang9aae74a2020-10-30 12:01:03 -070019#include "host-common/opengl/emugl_config.h"
Jason Macnakfb647c22022-09-02 09:44:00 -070020#include "host-common/logging.h"
Lingfeng Yangbfe3c722020-10-29 10:33:18 -070021#include "host-common/misc.h"
Joshua Duong9dfbd852022-11-14 13:12:59 -080022#include "host-common/opengl/misc.h"
Lingfeng Yangee4aea32020-10-29 08:52:13 -070023
24#include <stdio.h>
25#include <string.h>
26
Jason Macnaked0c9e62023-03-30 15:58:24 -070027namespace gfxstream {
28namespace gl {
Lingfeng Yangee4aea32020-10-29 08:52:13 -070029namespace {
30
Lingfeng Yangee4aea32020-10-29 08:52:13 -070031#ifndef EGL_PRESERVED_RESOURCES
32#define EGL_PRESERVED_RESOURCES 0x3030
33#endif
34
35const 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
73const size_t kConfigAttributesLen =
74 sizeof(kConfigAttributes) / sizeof(kConfigAttributes[0]);
75
76bool 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
Jason Macnakfb647c22022-09-02 09:44:00 -0700103EmulatedEglConfig::EmulatedEglConfig(EGLint guestConfig,
104 EGLConfig hostConfig,
Jason Macnak26872122024-02-23 10:46:09 -0800105 EGLDisplay hostDisplay,
106 bool glesDynamicVersion)
Jason Macnakfb647c22022-09-02 09:44:00 -0700107 : mGuestConfig(guestConfig),
108 mHostConfig(hostConfig),
Jason Macnak26872122024-02-23 10:46:09 -0800109 mAttribValues(kConfigAttributesLen),
110 mGlesDynamicVersion(glesDynamicVersion) {
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700111 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) {
Jason Macnak26872122024-02-23 10:46:09 -0800126 if (!mGlesDynamicVersion && mAttribValues[i] & EGL_OPENGL_ES3_BIT) {
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700127 mAttribValues[i] &= ~EGL_OPENGL_ES3_BIT;
128 }
129 }
130 }
131}
132
Jason Macnakfb647c22022-09-02 09:44:00 -0700133EmulatedEglConfigList::EmulatedEglConfigList(EGLDisplay display,
Jason Macnak26872122024-02-23 10:46:09 -0800134 GLESDispatchMaxVersion version,
135 const gfxstream::host::FeatureSet& features)
136 : mDisplay(display),
137 mGlesDispatchMaxVersion(version),
138 mGlesDynamicVersion(features.GlesDynamicVersion.enabled) {
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700139 if (display == EGL_NO_DISPLAY) {
Jason Macnakfb647c22022-09-02 09:44:00 -0700140 ERR("Invalid display value %p (EGL_NO_DISPLAY).", (void*)display);
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700141 return;
142 }
143
144 EGLint numHostConfigs = 0;
145 if (!s_egl.eglGetConfigs(display, NULL, 0, &numHostConfigs)) {
Jason Macnakfb647c22022-09-02 09:44:00 -0700146 ERR("Failed to get number of host EGL configs.");
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700147 return;
148 }
Jason Macnakfb647c22022-09-02 09:44:00 -0700149 std::vector<EGLConfig> hostConfigs(numHostConfigs);
150 s_egl.eglGetConfigs(display, hostConfigs.data(), numHostConfigs, &numHostConfigs);
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700151
Jason Macnakfb647c22022-09-02 09:44:00 -0700152 for (EGLConfig hostConfig : hostConfigs) {
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700153 // Filter out configs that are not compatible with our implementation.
Jason Macnakfb647c22022-09-02 09:44:00 -0700154 if (!isCompatibleHostConfig(hostConfig, display)) {
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700155 continue;
156 }
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700157
Jason Macnakfb647c22022-09-02 09:44:00 -0700158 const EGLint guestConfig = static_cast<EGLint>(mConfigs.size());
Jason Macnak26872122024-02-23 10:46:09 -0800159 mConfigs.push_back(EmulatedEglConfig(guestConfig, hostConfig, display, mGlesDynamicVersion));
Jason Macnakfb647c22022-09-02 09:44:00 -0700160 }
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700161}
162
Jason Macnakfb647c22022-09-02 09:44:00 -0700163int EmulatedEglConfigList::chooseConfig(const EGLint* attribs,
164 EGLint* configs,
165 EGLint configsSize) const {
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700166 EGLint numHostConfigs = 0;
167 if (!s_egl.eglGetConfigs(mDisplay, NULL, 0, &numHostConfigs)) {
Jason Macnakfb647c22022-09-02 09:44:00 -0700168 ERR("Failed to get number of host EGL configs.");
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700169 return 0;
170 }
171
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700172 // 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;
Gurchetan Singha772de72022-09-29 14:09:06 -0700180 std::vector<EGLint> newAttribs;
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700181 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 &&
Jason Macnak26872122024-02-23 10:46:09 -0800194 (!mGlesDynamicVersion || mGlesDispatchMaxVersion < GLES_DISPATCH_MAX_VERSION_3_0)) {
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700195 return 0;
196 }
197 }
198 numAttribs += 2;
199 }
200
Gurchetan Singha772de72022-09-29 14:09:06 -0700201 if (numAttribs) {
202 newAttribs.resize(numAttribs);
203 memcpy(&newAttribs[0], attribs, numAttribs * sizeof(EGLint));
204 }
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700205
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
Jason Macnakfb647c22022-09-02 09:44:00 -0700225
226 std::vector<EGLConfig> matchedConfigs(numHostConfigs);
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700227 if (s_egl.eglChooseConfig(mDisplay,
228 &newAttribs[0],
Jason Macnakfb647c22022-09-02 09:44:00 -0700229 matchedConfigs.data(),
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700230 numHostConfigs,
231 &numHostConfigs) == EGL_FALSE) {
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700232 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 }
Jason Macnakfb647c22022-09-02 09:44:00 -0700246 // Find the EmulatedEglConfig with the same EGL_CONFIG_ID
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700247 EGLint hostConfigId;
248 s_egl.eglGetConfigAttrib(
249 mDisplay, matchedConfigs[n], EGL_CONFIG_ID, &hostConfigId);
Jason Macnakfb647c22022-09-02 09:44:00 -0700250 for (const EmulatedEglConfig& config : mConfigs) {
251 if (config.getConfigId() == hostConfigId) {
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700252 // There is a match. Write it to |configs| if it is not NULL.
253 if (configs && result < configsSize) {
Jason Macnakfb647c22022-09-02 09:44:00 -0700254 configs[result] = config.getGuestEglConfig();
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700255 }
Jason Macnakfb647c22022-09-02 09:44:00 -0700256 result++;
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700257 break;
258 }
259 }
260 }
261
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700262 return result;
263}
264
265
Jason Macnakfb647c22022-09-02 09:44:00 -0700266void EmulatedEglConfigList::getPackInfo(EGLint* numConfigs,
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700267 EGLint* numAttributes) const {
268 if (numConfigs) {
Jason Macnakfb647c22022-09-02 09:44:00 -0700269 *numConfigs = mConfigs.size();
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700270 }
271 if (numAttributes) {
272 *numAttributes = static_cast<EGLint>(kConfigAttributesLen);
273 }
274}
275
Jason Macnakfb647c22022-09-02 09:44:00 -0700276EGLint EmulatedEglConfigList::packConfigs(GLuint bufferByteSize, GLuint* buffer) const {
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700277 GLuint numAttribs = static_cast<GLuint>(kConfigAttributesLen);
278 GLuint kGLuintSize = static_cast<GLuint>(sizeof(GLuint));
Jason Macnakfb647c22022-09-02 09:44:00 -0700279 GLuint neededByteSize = (mConfigs.size() + 1) * numAttribs * kGLuintSize;
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700280 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
Jason Macnakfb647c22022-09-02 09:44:00 -0700287 for (int i = 0; i < mConfigs.size(); ++i) {
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700288 memcpy(buffer + (i + 1) * kConfigAttributesLen,
Jason Macnakfb647c22022-09-02 09:44:00 -0700289 mConfigs[i].mAttribValues.data(),
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700290 kConfigAttributesLen * kGLuintSize);
291 }
Jason Macnakfb647c22022-09-02 09:44:00 -0700292 return mConfigs.size();
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700293}
Jason Macnaked0c9e62023-03-30 15:58:24 -0700294
295} // namespace gl
296} // namespace gfxstream