123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581 |
- // 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_gl_api_implementation.h"
- #include <vector>
- #include "base/command_line.h"
- #include "base/containers/contains.h"
- #include "base/strings/string_split.h"
- #include "base/strings/string_util.h"
- #include "ui/gl/gl_context.h"
- #include "ui/gl/gl_implementation.h"
- #include "ui/gl/gl_state_restorer.h"
- #include "ui/gl/gl_surface.h"
- #include "ui/gl/gl_switches.h"
- #include "ui/gl/gl_version_info.h"
- #include "ui/gl/shader_tracking.h"
- namespace gl {
- // The GL state for when no context is bound
- static CurrentGL* g_no_context_current_gl = nullptr;
- // If the null draw bindings are currently enabled.
- // TODO: Consider adding a new GLApi that no-ops these functions
- static bool g_null_draw_bindings_enabled = false;
- namespace {
- // TODO(epenner): Could the above function be merged into GetInternalFormat and
- // removed?
- static inline GLenum GetTexInternalFormat(const GLVersionInfo* version,
- GLenum internal_format,
- GLenum format,
- GLenum type) {
- GLenum gl_internal_format = GetInternalFormat(version, internal_format);
- // g_version_info must be initialized when this function is bound.
- if (version->is_es3) {
- if (internal_format == GL_RED_EXT) {
- // GL_EXT_texture_rg case in ES2.
- switch (type) {
- case GL_UNSIGNED_BYTE:
- gl_internal_format = GL_R8_EXT;
- break;
- case GL_UNSIGNED_SHORT:
- gl_internal_format = GL_R16_EXT;
- break;
- case GL_HALF_FLOAT_OES:
- gl_internal_format = GL_R16F_EXT;
- break;
- case GL_FLOAT:
- gl_internal_format = GL_R32F_EXT;
- break;
- default:
- NOTREACHED();
- break;
- }
- return gl_internal_format;
- } else if (internal_format == GL_RG_EXT) {
- // GL_EXT_texture_rg case in ES2.
- switch (type) {
- case GL_UNSIGNED_BYTE:
- gl_internal_format = GL_RG8_EXT;
- break;
- case GL_HALF_FLOAT_OES:
- gl_internal_format = GL_RG16F_EXT;
- break;
- case GL_FLOAT:
- gl_internal_format = GL_RG32F_EXT;
- break;
- default:
- NOTREACHED();
- break;
- }
- return gl_internal_format;
- }
- }
- if (version->IsAtLeastGL(2, 1) || version->IsAtLeastGLES(3, 0)) {
- switch (internal_format) {
- case GL_SRGB_EXT:
- gl_internal_format = GL_SRGB8;
- break;
- case GL_SRGB_ALPHA_EXT:
- gl_internal_format = GL_SRGB8_ALPHA8;
- break;
- default:
- break;
- }
- }
- if (version->is_es2)
- return gl_internal_format;
- // For ES3, use sized float/half_float internal formats whenever posssible.
- if (type == GL_FLOAT) {
- switch (internal_format) {
- // We need to map all the unsized internal formats from ES2 clients.
- case GL_RGBA:
- gl_internal_format = GL_RGBA32F;
- break;
- case GL_RGB:
- gl_internal_format = GL_RGB32F;
- break;
- case GL_LUMINANCE_ALPHA:
- if (!version->is_es)
- gl_internal_format = GL_LUMINANCE_ALPHA32F_ARB;
- break;
- case GL_LUMINANCE:
- if (!version->is_es)
- gl_internal_format = GL_LUMINANCE32F_ARB;
- break;
- case GL_ALPHA:
- if (!version->is_es)
- gl_internal_format = GL_ALPHA32F_ARB;
- break;
- default:
- // We can't assert here because if the client context is ES3,
- // all sized internal_format will reach here.
- break;
- }
- } else if (type == GL_HALF_FLOAT_OES) {
- switch (internal_format) {
- case GL_RGBA:
- gl_internal_format = GL_RGBA16F;
- break;
- case GL_RGB:
- gl_internal_format = GL_RGB16F;
- break;
- case GL_LUMINANCE_ALPHA:
- if (!version->is_es)
- gl_internal_format = GL_LUMINANCE_ALPHA16F_ARB;
- break;
- case GL_LUMINANCE:
- if (!version->is_es)
- gl_internal_format = GL_LUMINANCE16F_ARB;
- break;
- case GL_ALPHA:
- if (!version->is_es)
- gl_internal_format = GL_ALPHA16F_ARB;
- break;
- default:
- break;
- }
- }
- return gl_internal_format;
- }
- static inline GLenum GetTexFormat(const GLVersionInfo* version, GLenum format) {
- GLenum gl_format = format;
- if (version->IsAtLeastGL(2, 1) || version->IsAtLeastGLES(3, 0)) {
- switch (format) {
- case GL_SRGB_EXT:
- gl_format = GL_RGB;
- break;
- case GL_SRGB_ALPHA_EXT:
- gl_format = GL_RGBA;
- break;
- default:
- break;
- }
- }
- return gl_format;
- }
- static inline GLenum GetPixelType(const GLVersionInfo* version,
- GLenum type,
- GLenum format) {
- if (!version->is_es2) {
- if (type == GL_HALF_FLOAT_OES) {
- if (version->is_es) {
- // For ES3+, use HALF_FLOAT instead of HALF_FLOAT_OES whenever possible.
- switch (format) {
- case GL_LUMINANCE:
- case GL_LUMINANCE_ALPHA:
- case GL_ALPHA:
- return type;
- default:
- break;
- }
- }
- return GL_HALF_FLOAT;
- }
- }
- return type;
- }
- } // anonymous namespace
- GLenum GetInternalFormat(const GLVersionInfo* version, GLenum internal_format) {
- if (!version->is_es) {
- if (internal_format == GL_BGRA_EXT || internal_format == GL_BGRA8_EXT)
- return GL_RGBA8;
- }
- if (version->is_es3 && version->is_mesa) {
- // Mesa bug workaround: Mipmapping does not work when using GL_BGRA_EXT
- if (internal_format == GL_BGRA_EXT)
- return GL_RGBA;
- }
- return internal_format;
- }
- void InitializeStaticGLBindingsGL() {
- g_current_gl_context_tls = new base::ThreadLocalPointer<CurrentGL>;
- g_no_context_current_gl = new CurrentGL;
- g_no_context_current_gl->Api = new NoContextGLApi;
- }
- void ClearBindingsGL() {
- if (g_no_context_current_gl) {
- delete g_no_context_current_gl->Api;
- delete g_no_context_current_gl->Driver;
- delete g_no_context_current_gl->Version;
- delete g_no_context_current_gl;
- g_no_context_current_gl = nullptr;
- }
- if (g_current_gl_context_tls) {
- delete g_current_gl_context_tls;
- g_current_gl_context_tls = nullptr;
- }
- }
- bool SetNullDrawGLBindingsEnabled(bool enabled) {
- bool old_value = g_null_draw_bindings_enabled;
- g_null_draw_bindings_enabled = enabled;
- return old_value;
- }
- bool GetNullDrawBindingsEnabled() {
- return g_null_draw_bindings_enabled;
- }
- void SetCurrentGL(CurrentGL* current) {
- CurrentGL* new_current = current ? current : g_no_context_current_gl;
- g_current_gl_context_tls->Set(new_current);
- }
- GLApi::GLApi() = default;
- GLApi::~GLApi() = default;
- GLApiBase::GLApiBase() : driver_(nullptr) {}
- GLApiBase::~GLApiBase() = default;
- void GLApiBase::InitializeBase(DriverGL* driver) {
- driver_ = driver;
- }
- RealGLApi::RealGLApi()
- : logging_enabled_(base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableGPUServiceLogging)) {}
- RealGLApi::~RealGLApi() = default;
- void RealGLApi::Initialize(DriverGL* driver) {
- InitializeBase(driver);
- }
- void RealGLApi::glGetIntegervFn(GLenum pname, GLint* params) {
- if (pname == GL_NUM_EXTENSIONS && disabled_exts_.size()) {
- InitializeFilteredExtensionsIfNeeded();
- *params = static_cast<GLint>(filtered_exts_.size());
- } else {
- GLApiBase::glGetIntegervFn(pname, params);
- }
- }
- const GLubyte* RealGLApi::glGetStringFn(GLenum name) {
- if (name == GL_EXTENSIONS && disabled_exts_.size()) {
- InitializeFilteredExtensionsIfNeeded();
- return reinterpret_cast<const GLubyte*>(filtered_exts_str_.c_str());
- }
- return GLApiBase::glGetStringFn(name);
- }
- const GLubyte* RealGLApi::glGetStringiFn(GLenum name, GLuint index) {
- if (name == GL_EXTENSIONS && disabled_exts_.size()) {
- InitializeFilteredExtensionsIfNeeded();
- if (index >= filtered_exts_.size()) {
- return nullptr;
- }
- return reinterpret_cast<const GLubyte*>(filtered_exts_[index].c_str());
- }
- return GLApiBase::glGetStringiFn(name, index);
- }
- void RealGLApi::glTexImage2DFn(GLenum target,
- GLint level,
- GLint internalformat,
- GLsizei width,
- GLsizei height,
- GLint border,
- GLenum format,
- GLenum type,
- const void* pixels) {
- GLenum gl_internal_format =
- GetTexInternalFormat(version_.get(), internalformat, format, type);
- GLenum gl_format = GetTexFormat(version_.get(), format);
- GLenum gl_type = GetPixelType(version_.get(), type, format);
- // TODO(yizhou): Check if cubemap, 3d texture or texture2d array has the same
- // bug on intel mac.
- if (!version_->is_angle && gl_workarounds_.reset_teximage2d_base_level &&
- target == GL_TEXTURE_2D) {
- GLint base_level = 0;
- GLApiBase::glGetTexParameterivFn(target, GL_TEXTURE_BASE_LEVEL,
- &base_level);
- if (base_level) {
- GLApiBase::glTexParameteriFn(target, GL_TEXTURE_BASE_LEVEL, 0);
- GLApiBase::glTexImage2DFn(target, level, gl_internal_format, width,
- height, border, gl_format, gl_type, pixels);
- GLApiBase::glTexParameteriFn(target, GL_TEXTURE_BASE_LEVEL, base_level);
- return;
- }
- }
- GLApiBase::glTexImage2DFn(target, level, gl_internal_format, width, height,
- border, gl_format, gl_type, pixels);
- }
- void RealGLApi::glTexSubImage2DFn(GLenum target,
- GLint level,
- GLint xoffset,
- GLint yoffset,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLenum type,
- const void* pixels) {
- GLenum gl_format = GetTexFormat(version_.get(), format);
- GLenum gl_type = GetPixelType(version_.get(), type, format);
- GLApiBase::glTexSubImage2DFn(target, level, xoffset, yoffset, width, height,
- gl_format, gl_type, pixels);
- }
- void RealGLApi::glTexStorage2DEXTFn(GLenum target,
- GLsizei levels,
- GLenum internalformat,
- GLsizei width,
- GLsizei height) {
- GLenum gl_internal_format = GetInternalFormat(version_.get(), internalformat);
- GLApiBase::glTexStorage2DEXTFn(target, levels, gl_internal_format, width,
- height);
- }
- void RealGLApi::glTexStorageMem2DEXTFn(GLenum target,
- GLsizei levels,
- GLenum internalformat,
- GLsizei width,
- GLsizei height,
- GLuint memory,
- GLuint64 offset) {
- internalformat = GetInternalFormat(version_.get(), internalformat);
- GLApiBase::glTexStorageMem2DEXTFn(target, levels, internalformat, width,
- height, memory, offset);
- }
- void RealGLApi::glTexStorageMemFlags2DANGLEFn(
- GLenum target,
- GLsizei levels,
- GLenum internalformat,
- GLsizei width,
- GLsizei height,
- GLuint memory,
- GLuint64 offset,
- GLbitfield createFlags,
- GLbitfield usageFlags,
- const void* imageCreateInfoPNext) {
- internalformat = GetInternalFormat(version_.get(), internalformat);
- GLApiBase::glTexStorageMemFlags2DANGLEFn(
- target, levels, internalformat, width, height, memory, offset,
- createFlags, usageFlags, imageCreateInfoPNext);
- }
- void RealGLApi::glRenderbufferStorageEXTFn(GLenum target,
- GLenum internalformat,
- GLsizei width,
- GLsizei height) {
- GLenum gl_internal_format = GetInternalFormat(version_.get(), internalformat);
- GLApiBase::glRenderbufferStorageEXTFn(target, gl_internal_format, width,
- height);
- }
- // The ANGLE and IMG variants of glRenderbufferStorageMultisample currently do
- // not support BGRA render buffers so only the EXT one is customized. If
- // GL_CHROMIUM_renderbuffer_format_BGRA8888 support is added to ANGLE then the
- // ANGLE version should also be customized.
- void RealGLApi::glRenderbufferStorageMultisampleEXTFn(GLenum target,
- GLsizei samples,
- GLenum internalformat,
- GLsizei width,
- GLsizei height) {
- GLenum gl_internal_format = GetInternalFormat(version_.get(), internalformat);
- GLApiBase::glRenderbufferStorageMultisampleEXTFn(
- target, samples, gl_internal_format, width, height);
- }
- void RealGLApi::glRenderbufferStorageMultisampleFn(GLenum target,
- GLsizei samples,
- GLenum internalformat,
- GLsizei width,
- GLsizei height) {
- GLenum gl_internal_format = GetInternalFormat(version_.get(), internalformat);
- GLApiBase::glRenderbufferStorageMultisampleFn(
- target, samples, gl_internal_format, width, height);
- }
- void RealGLApi::glReadPixelsFn(GLint x,
- GLint y,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLenum type,
- void* pixels) {
- GLenum gl_type = GetPixelType(version_.get(), type, format);
- GLApiBase::glReadPixelsFn(x, y, width, height, format, gl_type, pixels);
- }
- void RealGLApi::glClearFn(GLbitfield mask) {
- if (!g_null_draw_bindings_enabled) {
- GLApiBase::glClearFn(mask);
- } else if (logging_enabled_) {
- LOG(WARNING) << "Skipped glClear()";
- }
- }
- void RealGLApi::glClearColorFn(GLclampf red,
- GLclampf green,
- GLclampf blue,
- GLclampf alpha) {
- if (!version_->is_angle && gl_workarounds_.clear_to_zero_or_one_broken &&
- (1 == red || 0 == red) && (1 == green || 0 == green) &&
- (1 == blue || 0 == blue) && (1 == alpha || 0 == alpha)) {
- if (1 == alpha)
- alpha = 2;
- else
- alpha = -1;
- }
- GLApiBase::glClearColorFn(red, green, blue, alpha);
- }
- void RealGLApi::glDrawArraysFn(GLenum mode, GLint first, GLsizei count) {
- if (!g_null_draw_bindings_enabled) {
- GLApiBase::glDrawArraysFn(mode, first, count);
- } else if (logging_enabled_) {
- LOG(WARNING) << "Skipped glDrawArrays()";
- }
- }
- void RealGLApi::glDrawElementsFn(GLenum mode,
- GLsizei count,
- GLenum type,
- const void* indices) {
- if (!g_null_draw_bindings_enabled) {
- GLApiBase::glDrawElementsFn(mode, count, type, indices);
- } else if (logging_enabled_) {
- LOG(WARNING) << "Skipped glDrawElements()";
- }
- }
- void RealGLApi::glClearDepthFn(GLclampd depth) {
- // OpenGL ES only has glClearDepthf, forward the parameters from glClearDepth.
- // Many mock tests expect only glClearDepth is called so don't make the
- // interception when testing with mocks.
- if (version_->is_es && GetGLImplementation() != kGLImplementationMockGL) {
- DCHECK(driver_->fn.glClearDepthfFn);
- GLApiBase::glClearDepthfFn(static_cast<GLclampf>(depth));
- } else {
- DCHECK(driver_->fn.glClearDepthFn);
- GLApiBase::glClearDepthFn(depth);
- }
- }
- void RealGLApi::glDepthRangeFn(GLclampd z_near, GLclampd z_far) {
- // OpenGL ES only has glDepthRangef, forward the parameters from glDepthRange.
- // Many mock tests expect only glDepthRange is called so don't make the
- // interception when testing with mocks.
- if (version_->is_es && GetGLImplementation() != kGLImplementationMockGL) {
- DCHECK(driver_->fn.glDepthRangefFn);
- GLApiBase::glDepthRangefFn(static_cast<GLclampf>(z_near),
- static_cast<GLclampf>(z_far));
- } else {
- DCHECK(driver_->fn.glDepthRangeFn);
- GLApiBase::glDepthRangeFn(z_near, z_far);
- }
- }
- void RealGLApi::glUseProgramFn(GLuint program) {
- ShaderTracking* shader_tracking = ShaderTracking::GetInstance();
- if (shader_tracking) {
- std::vector<char> buffers[2];
- char* strings[2] = {nullptr, nullptr};
- if (program) {
- // The following only works with ANGLE backend because ANGLE makes sure
- // a program's shaders are not actually deleted and source can still be
- // queried even if glDeleteShaders() has been called on them.
- // Also, in theory, different shaders can be attached to the program
- // after the last link, but for now, ignore such corner case patterns.
- GLsizei count = 0;
- GLuint shaders[2] = {0};
- glGetAttachedShadersFn(program, 2, &count, shaders);
- for (GLsizei ii = 0; ii < std::min(2, count); ++ii) {
- buffers[ii].resize(ShaderTracking::kMaxShaderSize);
- glGetShaderSourceFn(shaders[ii], ShaderTracking::kMaxShaderSize,
- nullptr, buffers[ii].data());
- strings[ii] = buffers[ii].data();
- }
- }
- shader_tracking->SetShaders(strings[0], strings[1]);
- }
- GLApiBase::glUseProgramFn(program);
- }
- void RealGLApi::InitializeFilteredExtensionsIfNeeded() {
- DCHECK(disabled_exts_.size());
- if (filtered_exts_.size())
- return;
- DCHECK(filtered_exts_str_.empty());
- if (WillUseGLGetStringForExtensions(this)) {
- filtered_exts_str_ = FilterGLExtensionList(
- reinterpret_cast<const char*>(GLApiBase::glGetStringFn(GL_EXTENSIONS)),
- disabled_exts_);
- filtered_exts_ = base::SplitString(
- filtered_exts_str_, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- } else {
- GLint num_extensions = 0;
- GLApiBase::glGetIntegervFn(GL_NUM_EXTENSIONS, &num_extensions);
- for (GLint i = 0; i < num_extensions; ++i) {
- const char* gl_extension = reinterpret_cast<const char*>(
- GLApiBase::glGetStringiFn(GL_EXTENSIONS, i));
- DCHECK(gl_extension);
- if (!base::Contains(disabled_exts_, gl_extension))
- filtered_exts_.push_back(gl_extension);
- }
- filtered_exts_str_ = base::JoinString(filtered_exts_, " ");
- }
- }
- void RealGLApi::SetDisabledExtensions(const std::string& disabled_extensions) {
- ClearCachedGLExtensions();
- disabled_exts_.clear();
- if (disabled_extensions.empty())
- return;
- disabled_exts_ =
- base::SplitString(disabled_extensions, ", ;", base::KEEP_WHITESPACE,
- base::SPLIT_WANT_NONEMPTY);
- DCHECK(disabled_exts_.size());
- }
- void RealGLApi::ClearCachedGLExtensions() {
- filtered_exts_.clear();
- filtered_exts_str_.clear();
- }
- void RealGLApi::set_gl_workarounds(const GLWorkarounds& workarounds) {
- gl_workarounds_ = workarounds;
- }
- void RealGLApi::set_version(std::unique_ptr<GLVersionInfo> version) {
- version_ = std::move(version);
- }
- TraceGLApi::~TraceGLApi() = default;
- LogGLApi::LogGLApi(GLApi* gl_api) : gl_api_(gl_api) {}
- LogGLApi::~LogGLApi() = default;
- NoContextGLApi::NoContextGLApi() = default;
- NoContextGLApi::~NoContextGLApi() = default;
- } // namespace gl
|