emugl: limit set of extensions we expose to Android
If we expose too many extensions we don't support ourself yet (like EGL_ANDROID_native_fence_sync) then we get unexpected corruption or missing screen updates in our rendered output. Fixes #635, #457, #692, #582 (and a few more duplicates)
This commit is contained in:
parent
77f3badb97
commit
ceae29b2d2
1 changed files with 58 additions and 40 deletions
|
|
@ -26,9 +26,9 @@
|
||||||
#include "external/android-emugl/shared/OpenglCodecCommon/ChecksumCalculatorThreadInfo.h"
|
#include "external/android-emugl/shared/OpenglCodecCommon/ChecksumCalculatorThreadInfo.h"
|
||||||
#include "external/android-emugl/host/include/OpenGLESDispatch/EGLDispatch.h"
|
#include "external/android-emugl/host/include/OpenGLESDispatch/EGLDispatch.h"
|
||||||
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
static const GLint rendererVersion = 1;
|
static const GLint rendererVersion = 1;
|
||||||
static std::shared_ptr<anbox::graphics::LayerComposer> composer;
|
static std::shared_ptr<anbox::graphics::LayerComposer> composer;
|
||||||
|
|
@ -55,38 +55,45 @@ static EGLint rcGetEGLVersion(EGLint *major, EGLint *minor) {
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string filter_extensions(const std::string& extensions, const std::vector<std::string>& whitelist) {
|
||||||
|
std::stringstream approved_extensions;
|
||||||
|
auto extension_list = anbox::utils::string_split(extensions, ' ');
|
||||||
|
for (const auto& ext : extension_list) {
|
||||||
|
if (std::find(whitelist.begin(), whitelist.end(), ext) == whitelist.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (approved_extensions.tellp() > 0)
|
||||||
|
approved_extensions << " ";
|
||||||
|
|
||||||
|
approved_extensions << ext;
|
||||||
|
}
|
||||||
|
return approved_extensions.str();
|
||||||
|
}
|
||||||
|
|
||||||
static EGLint rcQueryEGLString(EGLenum name, void* buffer, EGLint bufferSize) {
|
static EGLint rcQueryEGLString(EGLenum name, void* buffer, EGLint bufferSize) {
|
||||||
if (!renderer)
|
if (!renderer)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
auto result = s_egl.eglQueryString(renderer->getDisplay(), name);
|
std::string result = s_egl.eglQueryString(renderer->getDisplay(), name);
|
||||||
if (!result)
|
if (result.empty())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
std::string approved_result = result;
|
|
||||||
|
|
||||||
// We need to drop a few extensions from the list reported by the driver
|
|
||||||
// as not all are well enough support by our EGL/GLES stack.
|
|
||||||
if (name == EGL_EXTENSIONS) {
|
if (name == EGL_EXTENSIONS) {
|
||||||
std::vector<std::string> common_unsupported_extensions = {
|
// We need to drop a few extensions from the list reported by the driver
|
||||||
// Leads to crashes on the Android side when SurfaceFlinger initializes
|
// as not all are well enough support by our EGL implementation.
|
||||||
// EGL/GLES and it queries surfaces for available attributes.
|
std::vector<std::string> whitelisted_extensions = {
|
||||||
"EGL_EXT_buffer_age"
|
"EGL_KHR_image_base",
|
||||||
|
"EGL_KHR_gl_texture_2D_image",
|
||||||
};
|
};
|
||||||
|
result = filter_extensions(result, whitelisted_extensions);
|
||||||
for (const auto &extension : common_unsupported_extensions) {
|
|
||||||
size_t start_pos = approved_result.find(extension);
|
|
||||||
if (start_pos == std::string::npos) continue;
|
|
||||||
approved_result.replace(start_pos, extension.length(), "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int len = approved_result.length() + 1;
|
int len = result.length() + 1;
|
||||||
if (!buffer || len > bufferSize) {
|
if (!buffer || len > bufferSize) {
|
||||||
return -len;
|
return -len;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(static_cast<char *>(buffer), approved_result.c_str());
|
strcpy(static_cast<char*>(buffer), result.c_str());
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,7 +108,8 @@ static EGLint rcGetGLString(EGLenum name, void *buffer, EGLint bufferSize) {
|
||||||
else
|
else
|
||||||
str = reinterpret_cast<const char*>(s_gles1.glGetString(name));
|
str = reinterpret_cast<const char*>(s_gles1.glGetString(name));
|
||||||
|
|
||||||
if (str) result += str;
|
if (str)
|
||||||
|
result += str;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're forcing version 2.0 no matter what the host provides as
|
// We're forcing version 2.0 no matter what the host provides as
|
||||||
|
|
@ -113,25 +121,35 @@ static EGLint rcGetGLString(EGLenum name, void *buffer, EGLint bufferSize) {
|
||||||
if (name == GL_VERSION)
|
if (name == GL_VERSION)
|
||||||
result = "OpenGL ES 2.0";
|
result = "OpenGL ES 2.0";
|
||||||
else if (name == GL_EXTENSIONS) {
|
else if (name == GL_EXTENSIONS) {
|
||||||
std::string approved_extensions = result;
|
// We need to drop a few extensions from the list reported by the driver
|
||||||
std::vector<std::string> unsupported_extensions = {
|
// as not all are well enough support by our GL implementation.
|
||||||
// Leaving this enabled gives crippeled text rendering when
|
std::vector<std::string> whitelisted_extensions = {
|
||||||
// using the host mesa GLES drivers.
|
"GL_OES_EGL_image",
|
||||||
"GL_EXT_unpack_subimage",
|
"GL_OES_EGL_image_external",
|
||||||
|
"GL_OES_depth24",
|
||||||
|
"GL_OES_depth32",
|
||||||
|
"GL_OES_element_index_uint",
|
||||||
|
"GL_OES_texture_float",
|
||||||
|
"GL_OES_texture_float_linear",
|
||||||
|
"GL_OES_compressed_paletted_texture",
|
||||||
|
"GL_OES_compressed_ETC1_RGB8_texture",
|
||||||
|
"GL_OES_depth_texture",
|
||||||
|
"GL_OES_texture_half_float",
|
||||||
|
"GL_OES_texture_half_float_linear",
|
||||||
|
"GL_OES_packed_depth_stencil",
|
||||||
|
"GL_OES_vertex_half_float",
|
||||||
|
"GL_OES_standard_derivatives",
|
||||||
|
"GL_OES_texture_npot",
|
||||||
|
"GL_OES_rgb8_rgba8",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto &extension : unsupported_extensions) {
|
result = filter_extensions(result, whitelisted_extensions);
|
||||||
size_t start_pos = approved_extensions.find(extension);
|
|
||||||
if (start_pos == std::string::npos) continue;
|
|
||||||
approved_extensions.replace(start_pos, extension.length(), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
result = approved_extensions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int nextBufferSize = result.size() + 1;
|
int nextBufferSize = result.size() + 1;
|
||||||
|
|
||||||
if (!buffer || nextBufferSize > bufferSize) return -nextBufferSize;
|
if (!buffer || nextBufferSize > bufferSize)
|
||||||
|
return -nextBufferSize;
|
||||||
|
|
||||||
snprintf(static_cast<char*>(buffer), nextBufferSize, "%s", result.c_str());
|
snprintf(static_cast<char*>(buffer), nextBufferSize, "%s", result.c_str());
|
||||||
return nextBufferSize;
|
return nextBufferSize;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue