blob: bb2bdff07e9b2eb90055f9a9aa1499fd170b1bc3 [file] [log] [blame]
/*
* 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 "OpenGLESDispatch/EGLDispatch.h"
#include "aemu/base/system/System.h"
#include "aemu/base/misc/StringUtils.h"
#include "host-common/feature_control.h"
#include "host-common/opengl/misc.h"
#include <algorithm>
namespace gfxstream {
namespace gl {
// 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_compression_rgtc)
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)
#if defined(__linux__)
WHITELIST(GL_EXT_texture_compression_bptc)
WHITELIST(GL_EXT_texture_compression_s3tc)
#endif
#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;
}
} // namespace gl
} // namespace gfxstream