Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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 | |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 15 | #include "EmulatedEglConfig.h" |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 16 | |
Jason Macnak | 491f758 | 2022-08-30 14:08:59 -0700 | [diff] [blame] | 17 | #include "OpenGLESDispatch/EGLDispatch.h" |
Jason Macnak | 2687212 | 2024-02-23 10:46:09 -0800 | [diff] [blame] | 18 | #include "gfxstream/host/Features.h" |
Lingfeng Yang | 9aae74a | 2020-10-30 12:01:03 -0700 | [diff] [blame] | 19 | #include "host-common/opengl/emugl_config.h" |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 20 | #include "host-common/logging.h" |
Lingfeng Yang | bfe3c72 | 2020-10-29 10:33:18 -0700 | [diff] [blame] | 21 | #include "host-common/misc.h" |
Joshua Duong | 9dfbd85 | 2022-11-14 13:12:59 -0800 | [diff] [blame] | 22 | #include "host-common/opengl/misc.h" |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 23 | |
| 24 | #include <stdio.h> |
| 25 | #include <string.h> |
| 26 | |
Jason Macnak | ed0c9e6 | 2023-03-30 15:58:24 -0700 | [diff] [blame] | 27 | namespace gfxstream { |
| 28 | namespace gl { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 29 | namespace { |
| 30 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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 | |
| 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 | |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 103 | EmulatedEglConfig::EmulatedEglConfig(EGLint guestConfig, |
| 104 | EGLConfig hostConfig, |
Jason Macnak | 2687212 | 2024-02-23 10:46:09 -0800 | [diff] [blame] | 105 | EGLDisplay hostDisplay, |
| 106 | bool glesDynamicVersion) |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 107 | : mGuestConfig(guestConfig), |
| 108 | mHostConfig(hostConfig), |
Jason Macnak | 2687212 | 2024-02-23 10:46:09 -0800 | [diff] [blame] | 109 | mAttribValues(kConfigAttributesLen), |
| 110 | mGlesDynamicVersion(glesDynamicVersion) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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) { |
Jason Macnak | 2687212 | 2024-02-23 10:46:09 -0800 | [diff] [blame] | 126 | if (!mGlesDynamicVersion && mAttribValues[i] & EGL_OPENGL_ES3_BIT) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 127 | mAttribValues[i] &= ~EGL_OPENGL_ES3_BIT; |
| 128 | } |
| 129 | } |
| 130 | } |
| 131 | } |
| 132 | |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 133 | EmulatedEglConfigList::EmulatedEglConfigList(EGLDisplay display, |
Jason Macnak | 2687212 | 2024-02-23 10:46:09 -0800 | [diff] [blame] | 134 | GLESDispatchMaxVersion version, |
| 135 | const gfxstream::host::FeatureSet& features) |
| 136 | : mDisplay(display), |
| 137 | mGlesDispatchMaxVersion(version), |
| 138 | mGlesDynamicVersion(features.GlesDynamicVersion.enabled) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 139 | if (display == EGL_NO_DISPLAY) { |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 140 | ERR("Invalid display value %p (EGL_NO_DISPLAY).", (void*)display); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 141 | return; |
| 142 | } |
| 143 | |
| 144 | EGLint numHostConfigs = 0; |
| 145 | if (!s_egl.eglGetConfigs(display, NULL, 0, &numHostConfigs)) { |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 146 | ERR("Failed to get number of host EGL configs."); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 147 | return; |
| 148 | } |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 149 | std::vector<EGLConfig> hostConfigs(numHostConfigs); |
| 150 | s_egl.eglGetConfigs(display, hostConfigs.data(), numHostConfigs, &numHostConfigs); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 151 | |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 152 | for (EGLConfig hostConfig : hostConfigs) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 153 | // Filter out configs that are not compatible with our implementation. |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 154 | if (!isCompatibleHostConfig(hostConfig, display)) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 155 | continue; |
| 156 | } |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 157 | |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 158 | const EGLint guestConfig = static_cast<EGLint>(mConfigs.size()); |
Jason Macnak | 2687212 | 2024-02-23 10:46:09 -0800 | [diff] [blame] | 159 | mConfigs.push_back(EmulatedEglConfig(guestConfig, hostConfig, display, mGlesDynamicVersion)); |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 160 | } |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 161 | } |
| 162 | |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 163 | int EmulatedEglConfigList::chooseConfig(const EGLint* attribs, |
| 164 | EGLint* configs, |
| 165 | EGLint configsSize) const { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 166 | EGLint numHostConfigs = 0; |
| 167 | if (!s_egl.eglGetConfigs(mDisplay, NULL, 0, &numHostConfigs)) { |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 168 | ERR("Failed to get number of host EGL configs."); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 169 | return 0; |
| 170 | } |
| 171 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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; |
Gurchetan Singh | a772de7 | 2022-09-29 14:09:06 -0700 | [diff] [blame] | 180 | std::vector<EGLint> newAttribs; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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 && |
Jason Macnak | 2687212 | 2024-02-23 10:46:09 -0800 | [diff] [blame] | 194 | (!mGlesDynamicVersion || mGlesDispatchMaxVersion < GLES_DISPATCH_MAX_VERSION_3_0)) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 195 | return 0; |
| 196 | } |
| 197 | } |
| 198 | numAttribs += 2; |
| 199 | } |
| 200 | |
Gurchetan Singh | a772de7 | 2022-09-29 14:09:06 -0700 | [diff] [blame] | 201 | if (numAttribs) { |
| 202 | newAttribs.resize(numAttribs); |
| 203 | memcpy(&newAttribs[0], attribs, numAttribs * sizeof(EGLint)); |
| 204 | } |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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 | |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 225 | |
| 226 | std::vector<EGLConfig> matchedConfigs(numHostConfigs); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 227 | if (s_egl.eglChooseConfig(mDisplay, |
| 228 | &newAttribs[0], |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 229 | matchedConfigs.data(), |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 230 | numHostConfigs, |
| 231 | &numHostConfigs) == EGL_FALSE) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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 | } |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 246 | // Find the EmulatedEglConfig with the same EGL_CONFIG_ID |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 247 | EGLint hostConfigId; |
| 248 | s_egl.eglGetConfigAttrib( |
| 249 | mDisplay, matchedConfigs[n], EGL_CONFIG_ID, &hostConfigId); |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 250 | for (const EmulatedEglConfig& config : mConfigs) { |
| 251 | if (config.getConfigId() == hostConfigId) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 252 | // There is a match. Write it to |configs| if it is not NULL. |
| 253 | if (configs && result < configsSize) { |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 254 | configs[result] = config.getGuestEglConfig(); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 255 | } |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 256 | result++; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 257 | break; |
| 258 | } |
| 259 | } |
| 260 | } |
| 261 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 262 | return result; |
| 263 | } |
| 264 | |
| 265 | |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 266 | void EmulatedEglConfigList::getPackInfo(EGLint* numConfigs, |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 267 | EGLint* numAttributes) const { |
| 268 | if (numConfigs) { |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 269 | *numConfigs = mConfigs.size(); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 270 | } |
| 271 | if (numAttributes) { |
| 272 | *numAttributes = static_cast<EGLint>(kConfigAttributesLen); |
| 273 | } |
| 274 | } |
| 275 | |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 276 | EGLint EmulatedEglConfigList::packConfigs(GLuint bufferByteSize, GLuint* buffer) const { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 277 | GLuint numAttribs = static_cast<GLuint>(kConfigAttributesLen); |
| 278 | GLuint kGLuintSize = static_cast<GLuint>(sizeof(GLuint)); |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 279 | GLuint neededByteSize = (mConfigs.size() + 1) * numAttribs * kGLuintSize; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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 | |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 287 | for (int i = 0; i < mConfigs.size(); ++i) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 288 | memcpy(buffer + (i + 1) * kConfigAttributesLen, |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 289 | mConfigs[i].mAttribValues.data(), |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 290 | kConfigAttributesLen * kGLuintSize); |
| 291 | } |
Jason Macnak | fb647c2 | 2022-09-02 09:44:00 -0700 | [diff] [blame] | 292 | return mConfigs.size(); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 293 | } |
Jason Macnak | ed0c9e6 | 2023-03-30 15:58:24 -0700 | [diff] [blame] | 294 | |
| 295 | } // namespace gl |
| 296 | } // namespace gfxstream |