You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
244 lines
7.5 KiB
244 lines
7.5 KiB
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "GLESVersionDetector.h"
|
|
|
|
#include "EGLDispatch.h"
|
|
|
|
#include "base/System.h"
|
|
#include "base/StringUtils.h"
|
|
#include "host-common/feature_control.h"
|
|
#include "host-common/misc.h"
|
|
|
|
#include <algorithm>
|
|
|
|
// Config + context attributes to query the underlying OpenGL if it is
|
|
// a OpenGL ES backend. Only try for OpenGL ES 3, and assume OpenGL ES 2
|
|
// exists (if it doesn't, this is the least of our problems).
|
|
static const EGLint gles3ConfigAttribs[] =
|
|
{ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
|
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT, EGL_NONE };
|
|
|
|
static const EGLint pbufAttribs[] =
|
|
{ EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
|
|
|
|
static const EGLint gles31Attribs[] =
|
|
{ EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
|
|
EGL_CONTEXT_MINOR_VERSION_KHR, 1, EGL_NONE };
|
|
|
|
static const EGLint gles30Attribs[] =
|
|
{ EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
|
|
EGL_CONTEXT_MINOR_VERSION_KHR, 0, EGL_NONE };
|
|
|
|
static bool sTryContextCreation(EGLDisplay dpy, GLESDispatchMaxVersion ver) {
|
|
EGLConfig config;
|
|
EGLSurface surface;
|
|
|
|
const EGLint* contextAttribs = nullptr;
|
|
|
|
// Assume ES2 capable.
|
|
if (ver == GLES_DISPATCH_MAX_VERSION_2) return true;
|
|
|
|
switch (ver) {
|
|
case GLES_DISPATCH_MAX_VERSION_3_0:
|
|
contextAttribs = gles30Attribs;
|
|
break;
|
|
case GLES_DISPATCH_MAX_VERSION_3_1:
|
|
contextAttribs = gles31Attribs;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!contextAttribs) return false;
|
|
|
|
int numConfigs;
|
|
if (!s_egl.eglChooseConfig(
|
|
dpy, gles3ConfigAttribs, &config, 1, &numConfigs) ||
|
|
numConfigs == 0) {
|
|
return false;
|
|
}
|
|
|
|
surface = s_egl.eglCreatePbufferSurface(dpy, config, pbufAttribs);
|
|
if (surface == EGL_NO_SURFACE) {
|
|
return false;
|
|
}
|
|
|
|
EGLContext ctx = s_egl.eglCreateContext(dpy, config, EGL_NO_CONTEXT,
|
|
contextAttribs);
|
|
|
|
if (ctx == EGL_NO_CONTEXT) {
|
|
s_egl.eglDestroySurface(dpy, surface);
|
|
return false;
|
|
} else {
|
|
s_egl.eglDestroyContext(dpy, ctx);
|
|
s_egl.eglDestroySurface(dpy, surface);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
GLESDispatchMaxVersion calcMaxVersionFromDispatch(EGLDisplay dpy) {
|
|
|
|
// TODO: 3.1 is the highest
|
|
GLESDispatchMaxVersion maxVersion =
|
|
GLES_DISPATCH_MAX_VERSION_3_1;
|
|
|
|
// TODO: CTS conformance for OpenGL ES 3.1
|
|
bool playStoreImage = feature_is_enabled(
|
|
kFeature_PlayStoreImage);
|
|
|
|
if (emugl::getRenderer() == SELECTED_RENDERER_HOST
|
|
|| emugl::getRenderer() == SELECTED_RENDERER_SWIFTSHADER_INDIRECT
|
|
|| emugl::getRenderer() == SELECTED_RENDERER_ANGLE_INDIRECT
|
|
|| emugl::getRenderer() == SELECTED_RENDERER_ANGLE9_INDIRECT) {
|
|
if (s_egl.eglGetMaxGLESVersion) {
|
|
maxVersion =
|
|
(GLESDispatchMaxVersion)s_egl.eglGetMaxGLESVersion(dpy);
|
|
}
|
|
} else {
|
|
if (playStoreImage ||
|
|
!sTryContextCreation(dpy, GLES_DISPATCH_MAX_VERSION_3_1)) {
|
|
maxVersion = GLES_DISPATCH_MAX_VERSION_3_0;
|
|
if (!sTryContextCreation(dpy, GLES_DISPATCH_MAX_VERSION_3_0)) {
|
|
maxVersion = GLES_DISPATCH_MAX_VERSION_2;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (playStoreImage) {
|
|
maxVersion =
|
|
std::min(maxVersion,
|
|
GLES_DISPATCH_MAX_VERSION_3_0);
|
|
}
|
|
|
|
int maj = 2; int min = 0;
|
|
switch (maxVersion) {
|
|
case GLES_DISPATCH_MAX_VERSION_2:
|
|
maj = 2; min = 0; break;
|
|
case GLES_DISPATCH_MAX_VERSION_3_0:
|
|
maj = 3; min = 0; break;
|
|
case GLES_DISPATCH_MAX_VERSION_3_1:
|
|
maj = 3; min = 1; break;
|
|
case GLES_DISPATCH_MAX_VERSION_3_2:
|
|
maj = 3; min = 2; break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
emugl::setGlesVersion(maj, min);
|
|
|
|
return maxVersion;
|
|
}
|
|
|
|
// For determining whether or not to use core profile OpenGL.
|
|
// (Note: This does not affect the detection of possible core profile configs,
|
|
// just whether to use them)
|
|
bool shouldEnableCoreProfile() {
|
|
int dispatchMaj, dispatchMin;
|
|
|
|
emugl::getGlesVersion(&dispatchMaj, &dispatchMin);
|
|
return emugl::getRenderer() == SELECTED_RENDERER_HOST &&
|
|
dispatchMaj > 2;
|
|
}
|
|
|
|
void sAddExtensionIfSupported(GLESDispatchMaxVersion currVersion,
|
|
const std::string& from,
|
|
GLESDispatchMaxVersion extVersion,
|
|
const std::string& ext,
|
|
std::string& to) {
|
|
// If we chose a GLES version less than or equal to
|
|
// the |extVersion| the extension |ext| is tagged with,
|
|
// filter it according to the whitelist.
|
|
if (emugl::hasExtension(from.c_str(), ext.c_str()) &&
|
|
currVersion > extVersion) {
|
|
to += ext;
|
|
to += " ";
|
|
}
|
|
}
|
|
|
|
static bool sWhitelistedExtensionsGLES2(const std::string& hostExt) {
|
|
|
|
#define WHITELIST(ext) \
|
|
if (hostExt == #ext) return true; \
|
|
|
|
WHITELIST(GL_OES_compressed_ETC1_RGB8_texture)
|
|
WHITELIST(GL_OES_depth24)
|
|
WHITELIST(GL_OES_depth32)
|
|
WHITELIST(GL_OES_depth_texture)
|
|
WHITELIST(GL_OES_depth_texture_cube_map)
|
|
WHITELIST(GL_OES_EGL_image)
|
|
WHITELIST(GL_OES_EGL_image_external)
|
|
WHITELIST(GL_OES_EGL_sync)
|
|
WHITELIST(GL_OES_element_index_uint)
|
|
WHITELIST(GL_OES_framebuffer_object)
|
|
WHITELIST(GL_OES_packed_depth_stencil)
|
|
WHITELIST(GL_OES_rgb8_rgba8)
|
|
WHITELIST(GL_OES_standard_derivatives)
|
|
WHITELIST(GL_OES_texture_float)
|
|
WHITELIST(GL_OES_texture_float_linear)
|
|
WHITELIST(GL_OES_texture_half_float)
|
|
WHITELIST(GL_OES_texture_half_float_linear)
|
|
WHITELIST(GL_OES_texture_npot)
|
|
WHITELIST(GL_OES_texture_3D)
|
|
WHITELIST(GL_EXT_blend_minmax)
|
|
WHITELIST(GL_EXT_color_buffer_half_float)
|
|
WHITELIST(GL_EXT_draw_buffers)
|
|
WHITELIST(GL_EXT_instanced_arrays)
|
|
WHITELIST(GL_EXT_occlusion_query_boolean)
|
|
WHITELIST(GL_EXT_read_format_bgra)
|
|
WHITELIST(GL_EXT_texture_filter_anisotropic)
|
|
WHITELIST(GL_EXT_texture_format_BGRA8888)
|
|
WHITELIST(GL_EXT_texture_rg)
|
|
WHITELIST(GL_ANGLE_framebuffer_blit)
|
|
WHITELIST(GL_ANGLE_framebuffer_multisample)
|
|
WHITELIST(GL_ANGLE_instanced_arrays)
|
|
WHITELIST(GL_CHROMIUM_texture_filtering_hint)
|
|
WHITELIST(GL_NV_fence)
|
|
WHITELIST(GL_NV_framebuffer_blit)
|
|
WHITELIST(GL_NV_read_depth)
|
|
|
|
#undef WHITELIST
|
|
|
|
return false;
|
|
}
|
|
|
|
std::string filterExtensionsBasedOnMaxVersion(GLESDispatchMaxVersion ver,
|
|
const std::string& exts) {
|
|
// We need to advertise ES 2 extensions if:
|
|
// a. the dispatch version on the host is ES 2
|
|
// b. the guest image is not updated for ES 3+
|
|
// (GLESDynamicVersion is disabled)
|
|
if (ver > GLES_DISPATCH_MAX_VERSION_2 &&
|
|
feature_is_enabled(
|
|
kFeature_GLESDynamicVersion)) {
|
|
return exts;
|
|
}
|
|
|
|
std::string filteredExtensions;
|
|
filteredExtensions.reserve(4096);
|
|
auto add = [&filteredExtensions](const std::string& hostExt) {
|
|
if (!hostExt.empty() &&
|
|
sWhitelistedExtensionsGLES2(hostExt)) {
|
|
filteredExtensions += hostExt;
|
|
filteredExtensions += " ";
|
|
}
|
|
};
|
|
|
|
android::base::split<std::string>(exts, " ", add);
|
|
|
|
return filteredExtensions;
|
|
}
|