blob: 68d8a5d63b1ce7d19aab565d3c718b2ad8b3cc1d [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gl/gl_implementation.h"
#include <stddef.h>
#include <string>
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/protected_memory.h"
#include "base/memory/protected_memory_cfi.h"
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "ui/gl/buildflags.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_version_info.h"
namespace gl {
namespace {
const struct {
const char* name;
GLImplementation implementation;
} kGLImplementationNamePairs[] = {
{kGLImplementationDesktopName, kGLImplementationDesktopGL},
{kGLImplementationSwiftShaderName, kGLImplementationSwiftShaderGL},
#if defined(OS_MACOSX)
{kGLImplementationAppleName, kGLImplementationAppleGL},
#endif
{kGLImplementationEGLName, kGLImplementationEGLGLES2},
{kGLImplementationMockName, kGLImplementationMockGL},
{kGLImplementationStubName, kGLImplementationStubGL},
{kGLImplementationDisabledName, kGLImplementationDisabled}};
typedef std::vector<base::NativeLibrary> LibraryArray;
GLImplementation g_gl_implementation = kGLImplementationNone;
LibraryArray* g_libraries;
// Place the function pointer for GetProcAddress in read-only memory after being
// resolved to prevent it being tampered with. See crbug.com/771365 for details.
PROTECTED_MEMORY_SECTION base::ProtectedMemory<GLGetProcAddressProc>
g_get_proc_address;
void CleanupNativeLibraries(void* due_to_fallback) {
if (g_libraries) {
// We do not call base::UnloadNativeLibrary() for these libraries as
// unloading libGL without closing X display is not allowed. See
// https://crbug.com/250813 for details.
// However, if we fallback to a software renderer (e.g., SwiftShader),
// then the above concern becomes irrelevant.
// During fallback from ANGLE to SwiftShader ANGLE library needs to
// be unloaded, otherwise software SwiftShader loading will fail. See
// https://crbug.com/760063 for details.
// During fallback from VMware mesa to SwiftShader mesa libraries need
// to be unloaded. See https://crbug.com/852537 for details.
if (due_to_fallback && *static_cast<bool*>(due_to_fallback)) {
for (auto* library : *g_libraries)
base::UnloadNativeLibrary(library);
}
delete g_libraries;
g_libraries = nullptr;
}
}
gfx::ExtensionSet GetGLExtensionsFromCurrentContext(
GLApi* api,
GLenum extensions_enum,
GLenum num_extensions_enum) {
if (WillUseGLGetStringForExtensions(api)) {
const char* extensions =
reinterpret_cast<const char*>(api->glGetStringFn(extensions_enum));
return extensions ? gfx::MakeExtensionSet(extensions) : gfx::ExtensionSet();
}
GLint num_extensions = 0;
api->glGetIntegervFn(num_extensions_enum, &num_extensions);
std::vector<base::StringPiece> exts(num_extensions);
for (GLint i = 0; i < num_extensions; ++i) {
const char* extension =
reinterpret_cast<const char*>(api->glGetStringiFn(extensions_enum, i));
DCHECK(extension != NULL);
exts[i] = extension;
}
return gfx::ExtensionSet(exts);
}
} // namespace
base::ThreadLocalPointer<CurrentGL>* g_current_gl_context_tls = NULL;
#if defined(USE_EGL)
EGLApi* g_current_egl_context;
#endif
#if defined(OS_WIN)
WGLApi* g_current_wgl_context;
#endif
#if defined(USE_GLX)
GLXApi* g_current_glx_context;
#endif
GLImplementation GetNamedGLImplementation(const std::string& name) {
for (size_t i = 0; i < base::size(kGLImplementationNamePairs); ++i) {
if (name == kGLImplementationNamePairs[i].name)
return kGLImplementationNamePairs[i].implementation;
}
return kGLImplementationNone;
}
GLImplementation GetSoftwareGLImplementation() {
return kGLImplementationSwiftShaderGL;
}
const char* GetGLImplementationName(GLImplementation implementation) {
for (size_t i = 0; i < base::size(kGLImplementationNamePairs); ++i) {
if (implementation == kGLImplementationNamePairs[i].implementation)
return kGLImplementationNamePairs[i].name;
}
return "unknown";
}
void SetGLImplementation(GLImplementation implementation) {
g_gl_implementation = implementation;
}
GLImplementation GetGLImplementation() {
return g_gl_implementation;
}
bool HasDesktopGLFeatures() {
return kGLImplementationDesktopGL == g_gl_implementation ||
kGLImplementationDesktopGLCoreProfile == g_gl_implementation ||
kGLImplementationAppleGL == g_gl_implementation;
}
void AddGLNativeLibrary(base::NativeLibrary library) {
DCHECK(library);
if (!g_libraries) {
g_libraries = new LibraryArray;
base::AtExitManager::RegisterCallback(CleanupNativeLibraries, NULL);
}
g_libraries->push_back(library);
}
void UnloadGLNativeLibraries(bool due_to_fallback) {
CleanupNativeLibraries(&due_to_fallback);
}
void SetGLGetProcAddressProc(GLGetProcAddressProc proc) {
DCHECK(proc);
auto writer = base::AutoWritableMemory::Create(g_get_proc_address);
*g_get_proc_address = proc;
}
GLFunctionPointerType GetGLProcAddress(const char* name) {
DCHECK(g_gl_implementation != kGLImplementationNone);
if (g_libraries) {
for (size_t i = 0; i < g_libraries->size(); ++i) {
GLFunctionPointerType proc = reinterpret_cast<GLFunctionPointerType>(
base::GetFunctionPointerFromNativeLibrary((*g_libraries)[i], name));
if (proc)
return proc;
}
}
if (*g_get_proc_address) {
GLFunctionPointerType proc =
base::UnsanitizedCfiCall(g_get_proc_address)(name);
if (proc)
return proc;
}
return NULL;
}
void InitializeNullDrawGLBindings() {
SetNullDrawGLBindingsEnabled(true);
}
bool HasInitializedNullDrawGLBindings() {
return GetNullDrawBindingsEnabled();
}
std::string FilterGLExtensionList(
const char* extensions,
const std::vector<std::string>& disabled_extensions) {
if (extensions == NULL)
return "";
std::vector<base::StringPiece> extension_vec = base::SplitStringPiece(
extensions, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
auto is_disabled = [&disabled_extensions](const base::StringPiece& ext) {
return base::Contains(disabled_extensions, ext);
};
base::EraseIf(extension_vec, is_disabled);
return base::JoinString(extension_vec, " ");
}
DisableNullDrawGLBindings::DisableNullDrawGLBindings() {
initial_enabled_ = SetNullDrawGLBindingsEnabled(false);
}
DisableNullDrawGLBindings::~DisableNullDrawGLBindings() {
SetNullDrawGLBindingsEnabled(initial_enabled_);
}
GLWindowSystemBindingInfo::GLWindowSystemBindingInfo() {}
GLWindowSystemBindingInfo::~GLWindowSystemBindingInfo() {}
std::string GetGLExtensionsFromCurrentContext() {
return GetGLExtensionsFromCurrentContext(g_current_gl_context);
}
std::string GetGLExtensionsFromCurrentContext(GLApi* api) {
if (WillUseGLGetStringForExtensions(api)) {
const char* extensions =
reinterpret_cast<const char*>(api->glGetStringFn(GL_EXTENSIONS));
return extensions ? std::string(extensions) : std::string();
}
GLint num_extensions = 0;
api->glGetIntegervFn(GL_NUM_EXTENSIONS, &num_extensions);
std::vector<base::StringPiece> exts(num_extensions);
for (GLint i = 0; i < num_extensions; ++i) {
const char* extension =
reinterpret_cast<const char*>(api->glGetStringiFn(GL_EXTENSIONS, i));
DCHECK(extension != NULL);
exts[i] = extension;
}
return base::JoinString(exts, " ");
}
gfx::ExtensionSet GetRequestableGLExtensionsFromCurrentContext() {
return GetRequestableGLExtensionsFromCurrentContext(g_current_gl_context);
}
gfx::ExtensionSet GetRequestableGLExtensionsFromCurrentContext(GLApi* api) {
return GetGLExtensionsFromCurrentContext(api, GL_REQUESTABLE_EXTENSIONS_ANGLE,
GL_NUM_REQUESTABLE_EXTENSIONS_ANGLE);
}
bool WillUseGLGetStringForExtensions() {
return WillUseGLGetStringForExtensions(g_current_gl_context);
}
bool WillUseGLGetStringForExtensions(GLApi* api) {
const char* version_str =
reinterpret_cast<const char*>(api->glGetStringFn(GL_VERSION));
gfx::ExtensionSet extensions;
GLVersionInfo version_info(version_str, nullptr, extensions);
return version_info.is_es || version_info.major_version < 3;
}
base::NativeLibrary LoadLibraryAndPrintError(
const base::FilePath::CharType* filename) {
return LoadLibraryAndPrintError(base::FilePath(filename));
}
base::NativeLibrary LoadLibraryAndPrintError(const base::FilePath& filename) {
base::NativeLibraryLoadError error;
base::NativeLibrary library = base::LoadNativeLibrary(filename, &error);
if (!library) {
LOG(ERROR) << "Failed to load " << filename.MaybeAsASCII() << ": "
<< error.ToString();
return NULL;
}
return library;
}
} // namespace gl