diff options
author | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-12 21:17:27 +0000 |
---|---|---|
committer | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-12 21:17:27 +0000 |
commit | c9e2cbbbcad5f0ae5b9c5ccaf6a36a8a4a61e0e7 (patch) | |
tree | e33d97dc2edae8702ddb6a17ba0d89a506412693 /ui/gl | |
parent | fc25fd35147b2d5e74d5450e8586592c6a10813d (diff) | |
download | chromium_src-c9e2cbbbcad5f0ae5b9c5ccaf6a36a8a4a61e0e7.zip chromium_src-c9e2cbbbcad5f0ae5b9c5ccaf6a36a8a4a61e0e7.tar.gz chromium_src-c9e2cbbbcad5f0ae5b9c5ccaf6a36a8a4a61e0e7.tar.bz2 |
ui: Move gl/ directory out of gfx/, up to ui/.
BUG=104040
R=ben@chromium.org
TBR=tony@chromium.org
Review URL: https://chromiumcodereview.appspot.com/10392068
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@136777 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/gl')
70 files changed, 9756 insertions, 0 deletions
diff --git a/ui/gl/DEPS b/ui/gl/DEPS new file mode 100644 index 0000000..4d34aad --- /dev/null +++ b/ui/gl/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+third_party/angle/include", + "+third_party/mesa/MesaLib/include", +] diff --git a/ui/gl/OWNERS b/ui/gl/OWNERS new file mode 100644 index 0000000..9ce8991 --- /dev/null +++ b/ui/gl/OWNERS @@ -0,0 +1,4 @@ +apatrick@chromium.org +backer@chromium.org +kbr@chromium.org +gman@chromium.org diff --git a/ui/gl/android_native_window.cc b/ui/gl/android_native_window.cc new file mode 100644 index 0000000..f75b753 --- /dev/null +++ b/ui/gl/android_native_window.cc @@ -0,0 +1,26 @@ +// 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/android_native_window.h" + +#include <android/native_window.h> + +namespace gfx { + +AndroidNativeWindow::AndroidNativeWindow(ANativeWindow* window) + : window_(window) { + if (window_) + ANativeWindow_acquire(window_); +} + +AndroidNativeWindow::~AndroidNativeWindow() { + if (window_) + ANativeWindow_release(window_); +} + +ANativeWindow* AndroidNativeWindow::GetNativeHandle() const { + return window_; +} + +} // namespace gfx diff --git a/ui/gl/android_native_window.h b/ui/gl/android_native_window.h new file mode 100644 index 0000000..bde5904 --- /dev/null +++ b/ui/gl/android_native_window.h @@ -0,0 +1,32 @@ +// 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. + +#ifndef UI_GL_ANDROID_NATIVE_WINDOW_H_ +#define UI_GL_ANDROID_NATIVE_WINDOW_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/compiler_specific.h" + +struct ANativeWindow; + +namespace gfx { + +// This class deals with the Android native window ref count. +class AndroidNativeWindow { + public: + explicit AndroidNativeWindow(ANativeWindow* window); + ~AndroidNativeWindow(); + + ANativeWindow* GetNativeHandle() const; + + private: + ANativeWindow* window_; + + DISALLOW_COPY_AND_ASSIGN(AndroidNativeWindow); +}; + +} // namespace gfx + +#endif // UI_GL_ANDROID_NATIVE_WINDOW_H_ diff --git a/ui/gl/egl_util.cc b/ui/gl/egl_util.cc new file mode 100644 index 0000000..91d1b12 --- /dev/null +++ b/ui/gl/egl_util.cc @@ -0,0 +1,53 @@ +// 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/egl_util.h" + +#if defined(OS_ANDROID) +#include <EGL/egl.h> +#else +#include "third_party/angle/include/EGL/egl.h" +#endif + +// This needs to be after the EGL includes +#include "ui/gl/gl_bindings.h" + +namespace gfx { + +// Returns the last EGL error as a string. +const char* GetLastEGLErrorString() { + EGLint error = eglGetError(); + switch (error) { + case EGL_SUCCESS: + return "EGL_SUCCESS"; + case EGL_BAD_ACCESS: + return "EGL_BAD_ACCESS"; + case EGL_BAD_ALLOC: + return "EGL_BAD_ALLOC"; + case EGL_BAD_ATTRIBUTE: + return "EGL_BAD_ATTRIBUTE"; + case EGL_BAD_CONTEXT: + return "EGL_BAD_CONTEXT"; + case EGL_BAD_CONFIG: + return "EGL_BAD_CONFIG"; + case EGL_BAD_CURRENT_SURFACE: + return "EGL_BAD_CURRENT_SURFACE"; + case EGL_BAD_DISPLAY: + return "EGL_BAD_DISPLAY"; + case EGL_BAD_SURFACE: + return "EGL_BAD_SURFACE"; + case EGL_BAD_MATCH: + return "EGL_BAD_MATCH"; + case EGL_BAD_PARAMETER: + return "EGL_BAD_PARAMETER"; + case EGL_BAD_NATIVE_PIXMAP: + return "EGL_BAD_NATIVE_PIXMAP"; + case EGL_BAD_NATIVE_WINDOW: + return "EGL_BAD_NATIVE_WINDOW"; + default: + return "UNKNOWN"; + } +} + +} // namespace gfx diff --git a/ui/gl/egl_util.h b/ui/gl/egl_util.h new file mode 100644 index 0000000..bf6a019 --- /dev/null +++ b/ui/gl/egl_util.h @@ -0,0 +1,16 @@ +// 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. + +#ifndef UI_GL_EGL_UTIL_H_ +#define UI_GL_EGL_UTIL_H_ +#pragma once + +namespace gfx { + +// Returns the last EGL error as a string. +const char* GetLastEGLErrorString(); + +} // namespace gfx + +#endif // UI_GL_EGL_UTIL_H_ diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py new file mode 100755 index 0000000..22ab46a --- /dev/null +++ b/ui/gl/generate_bindings.py @@ -0,0 +1,1531 @@ +#!/usr/bin/env python +# 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. + +"""code generator for GL/GLES extension wrangler.""" + +import os +import collections +import re +import sys + +GL_FUNCTIONS = [ +{ 'return_type': 'void', + 'names': ['glActiveTexture'], + 'arguments': 'GLenum texture', }, +{ 'return_type': 'void', + 'names': ['glAttachShader'], + 'arguments': 'GLuint program, GLuint shader', }, +{ 'return_type': 'void', + 'names': ['glBeginQuery'], + 'arguments': 'GLenum target, GLuint id', }, +{ 'return_type': 'void', + 'names': ['glBeginQueryARB', 'glBeginQueryEXT'], + 'arguments': 'GLenum target, GLuint id', }, +{ 'return_type': 'void', + 'names': ['glBindAttribLocation'], + 'arguments': 'GLuint program, GLuint index, const char* name', }, +{ 'return_type': 'void', + 'names': ['glBindBuffer'], + 'arguments': 'GLenum target, GLuint buffer', }, +{ 'return_type': 'void', + 'names': ['glBindFragDataLocation'], + 'arguments': 'GLuint program, GLuint colorNumber, const char* name', }, +{ 'return_type': 'void', + 'names': ['glBindFragDataLocationIndexed'], + 'arguments': + 'GLuint program, GLuint colorNumber, GLuint index, const char* name', }, +{ 'return_type': 'void', + 'names': ['glBindFramebufferEXT', 'glBindFramebuffer'], + 'arguments': 'GLenum target, GLuint framebuffer', }, +{ 'return_type': 'void', + 'names': ['glBindRenderbufferEXT', 'glBindRenderbuffer'], + 'arguments': 'GLenum target, GLuint renderbuffer', }, +{ 'return_type': 'void', + 'names': ['glBindTexture'], + 'arguments': 'GLenum target, GLuint texture', }, +{ 'return_type': 'void', + 'names': ['glBlendColor'], + 'arguments': 'GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha', }, +{ 'return_type': 'void', + 'names': ['glBlendEquation'], + 'arguments': ' GLenum mode ', }, +{ 'return_type': 'void', + 'names': ['glBlendEquationSeparate'], + 'arguments': 'GLenum modeRGB, GLenum modeAlpha', }, +{ 'return_type': 'void', + 'names': ['glBlendFunc'], + 'arguments': 'GLenum sfactor, GLenum dfactor', }, +{ 'return_type': 'void', + 'names': ['glBlendFuncSeparate'], + 'arguments': + 'GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha', }, +{ 'return_type': 'void', + 'names': ['glBlitFramebufferEXT', 'glBlitFramebuffer'], + 'arguments': 'GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, ' + 'GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, ' + 'GLbitfield mask, GLenum filter', }, +{ 'return_type': 'void', + 'names': ['glBlitFramebufferANGLE', 'glBlitFramebuffer'], + 'arguments': 'GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, ' + 'GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, ' + 'GLbitfield mask, GLenum filter', }, +{ 'return_type': 'void', + 'names': ['glBufferData'], + 'arguments': 'GLenum target, GLsizei size, const void* data, GLenum usage', }, +{ 'return_type': 'void', + 'names': ['glBufferSubData'], + 'arguments': 'GLenum target, GLint offset, GLsizei size, const void* data', }, +{ 'return_type': 'GLenum', + 'names': ['glCheckFramebufferStatusEXT', + 'glCheckFramebufferStatus'], + 'arguments': 'GLenum target', + 'logging_code': """ + GL_SERVICE_LOG("GL_RESULT: " << GLES2Util::GetStringEnum(result)); +""", }, +{ 'return_type': 'void', + 'names': ['glClear'], + 'arguments': 'GLbitfield mask', }, +{ 'return_type': 'void', + 'names': ['glClearColor'], + 'arguments': 'GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha', }, +{ 'return_type': 'void', + 'names': ['glClearDepth'], + 'arguments': 'GLclampd depth', }, +{ 'return_type': 'void', + 'names': ['glClearDepthf'], + 'arguments': 'GLclampf depth', }, +{ 'return_type': 'void', + 'names': ['glClearStencil'], + 'arguments': 'GLint s', }, +{ 'return_type': 'void', + 'names': ['glColorMask'], + 'arguments': + 'GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha', }, +{ 'return_type': 'void', + 'names': ['glCompileShader'], + 'arguments': 'GLuint shader', }, +{ 'return_type': 'void', + 'names': ['glCompressedTexImage2D'], + 'arguments': + 'GLenum target, GLint level, GLenum internalformat, GLsizei width, ' + 'GLsizei height, GLint border, GLsizei imageSize, const void* data', }, +{ 'return_type': 'void', + 'names': ['glCompressedTexSubImage2D'], + 'arguments': + 'GLenum target, GLint level, GLint xoffset, GLint yoffset, ' + 'GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, ' + 'const void* data', }, +{ 'return_type': 'void', + 'names': ['glCopyTexImage2D'], + 'arguments': + 'GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, ' + 'GLsizei width, GLsizei height, GLint border', }, +{ 'return_type': 'void', + 'names': ['glCopyTexSubImage2D'], + 'arguments': + 'GLenum target, GLint level, GLint xoffset, ' + 'GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height', }, +{ 'return_type': 'GLuint', + 'names': ['glCreateProgram'], + 'arguments': 'void', }, +{ 'return_type': 'GLuint', + 'names': ['glCreateShader'], + 'arguments': 'GLenum type', }, +{ 'return_type': 'void', + 'names': ['glCullFace'], + 'arguments': 'GLenum mode', }, +{ 'return_type': 'void', + 'names': ['glDeleteBuffersARB', 'glDeleteBuffers'], + 'arguments': 'GLsizei n, const GLuint* buffers', }, +{ 'return_type': 'void', + 'names': ['glDeleteFramebuffersEXT', 'glDeleteFramebuffers'], + 'arguments': 'GLsizei n, const GLuint* framebuffers', }, +{ 'return_type': 'void', + 'names': ['glDeleteProgram'], + 'arguments': 'GLuint program', }, +{ 'return_type': 'void', + 'names': ['glDeleteQueries'], + 'arguments': 'GLsizei n, const GLuint* ids', }, +{ 'return_type': 'void', + 'names': ['glDeleteQueriesARB', 'glDeleteQueriesEXT'], + 'arguments': 'GLsizei n, const GLuint* ids', }, +{ 'return_type': 'void', + 'names': ['glDeleteRenderbuffersEXT', 'glDeleteRenderbuffers'], + 'arguments': 'GLsizei n, const GLuint* renderbuffers', }, +{ 'return_type': 'void', + 'names': ['glDeleteShader'], + 'arguments': 'GLuint shader', }, +{ 'return_type': 'void', + 'names': ['glDeleteTextures'], + 'arguments': 'GLsizei n, const GLuint* textures', }, +{ 'return_type': 'void', + 'names': ['glDepthFunc'], + 'arguments': 'GLenum func', }, +{ 'return_type': 'void', + 'names': ['glDepthMask'], + 'arguments': 'GLboolean flag', }, +{ 'return_type': 'void', + 'names': ['glDepthRange'], + 'arguments': 'GLclampd zNear, GLclampd zFar', }, +{ 'return_type': 'void', + 'names': ['glDepthRangef'], + 'arguments': 'GLclampf zNear, GLclampf zFar', }, +{ 'return_type': 'void', + 'names': ['glDetachShader'], + 'arguments': 'GLuint program, GLuint shader', }, +{ 'return_type': 'void', + 'names': ['glDisable'], + 'arguments': 'GLenum cap', }, +{ 'return_type': 'void', + 'names': ['glDisableVertexAttribArray'], + 'arguments': 'GLuint index', }, +{ 'return_type': 'void', + 'names': ['glDrawArrays'], + 'arguments': 'GLenum mode, GLint first, GLsizei count', }, +{ 'return_type': 'void', + 'names': ['glDrawBuffer'], + 'arguments': 'GLenum mode', }, +{ 'return_type': 'void', + 'names': ['glDrawBuffersARB'], + 'arguments': 'GLsizei n, const GLenum* bufs', }, +{ 'return_type': 'void', + 'names': ['glDrawElements'], + 'arguments': + 'GLenum mode, GLsizei count, GLenum type, const void* indices', }, +{ 'return_type': 'void', + 'names': ['glEGLImageTargetTexture2DOES'], + 'arguments': 'GLenum target, GLeglImageOES image', }, +{ 'return_type': 'void', + 'names': ['glEGLImageTargetRenderbufferStorageOES'], + 'arguments': 'GLenum target, GLeglImageOES image', }, +{ 'return_type': 'void', + 'names': ['glEnable'], + 'arguments': 'GLenum cap', }, +{ 'return_type': 'void', + 'names': ['glEnableVertexAttribArray'], + 'arguments': 'GLuint index', }, +{ 'return_type': 'void', + 'names': ['glEndQuery'], + 'arguments': 'GLenum target', }, +{ 'return_type': 'void', + 'names': ['glEndQueryARB', 'glEndQueryEXT'], + 'arguments': 'GLenum target', }, +{ 'return_type': 'void', + 'names': ['glFinish'], + 'arguments': 'void', }, +{ 'return_type': 'void', + 'names': ['glFlush'], + 'arguments': 'void', }, +{ 'return_type': 'void', + 'names': ['glFramebufferRenderbufferEXT', 'glFramebufferRenderbuffer'], + 'arguments': \ + 'GLenum target, GLenum attachment, GLenum renderbuffertarget, ' + 'GLuint renderbuffer', }, +{ 'return_type': 'void', + 'names': ['glFramebufferTexture2DEXT', 'glFramebufferTexture2D'], + 'arguments': + 'GLenum target, GLenum attachment, GLenum textarget, GLuint texture, ' + 'GLint level', }, +{ 'return_type': 'void', + 'names': ['glFrontFace'], + 'arguments': 'GLenum mode', }, +{ 'return_type': 'void', + 'names': ['glGenBuffersARB', 'glGenBuffers'], + 'arguments': 'GLsizei n, GLuint* buffers', }, +{ 'return_type': 'void', + 'names': ['glGenQueries'], + 'arguments': 'GLsizei n, GLuint* ids', }, +{ 'return_type': 'void', + 'names': ['glGenQueriesARB', 'glGenQueriesEXT'], + 'arguments': 'GLsizei n, GLuint* ids', }, +{ 'return_type': 'void', + 'names': ['glGenerateMipmapEXT', 'glGenerateMipmap'], + 'arguments': 'GLenum target', }, +{ 'return_type': 'void', + 'names': ['glGenFramebuffersEXT', 'glGenFramebuffers'], + 'arguments': 'GLsizei n, GLuint* framebuffers', }, +{ 'return_type': 'void', + 'names': ['glGenRenderbuffersEXT', 'glGenRenderbuffers'], + 'arguments': 'GLsizei n, GLuint* renderbuffers', }, +{ 'return_type': 'void', + 'names': ['glGenTextures'], + 'arguments': 'GLsizei n, GLuint* textures', }, +{ 'return_type': 'void', + 'names': ['glGetActiveAttrib'], + 'arguments': + 'GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, ' + 'GLint* size, GLenum* type, char* name', }, +{ 'return_type': 'void', + 'names': ['glGetActiveUniform'], + 'arguments': + 'GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, ' + 'GLint* size, GLenum* type, char* name', }, +{ 'return_type': 'void', + 'names': ['glGetAttachedShaders'], + 'arguments': + 'GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders', }, +{ 'return_type': 'GLint', + 'names': ['glGetAttribLocation'], + 'arguments': 'GLuint program, const char* name', }, +{ 'return_type': 'void', + 'names': ['glGetBooleanv'], + 'arguments': 'GLenum pname, GLboolean* params', }, +{ 'return_type': 'void', + 'names': ['glGetBufferParameteriv'], + 'arguments': 'GLenum target, GLenum pname, GLint* params', }, +{ 'return_type': 'GLenum', + 'names': ['glGetError'], + 'arguments': 'void', + 'logging_code': """ + GL_SERVICE_LOG("GL_RESULT: " << GLES2Util::GetStringError(result)); +""", }, +{ 'return_type': 'void', + 'names': ['glGetFloatv'], + 'arguments': 'GLenum pname, GLfloat* params', }, +{ 'return_type': 'void', + 'names': ['glGetFramebufferAttachmentParameterivEXT', + 'glGetFramebufferAttachmentParameteriv'], + 'arguments': 'GLenum target, ' + 'GLenum attachment, GLenum pname, GLint* params', }, +{ 'return_type': 'GLenum', + 'names': ['glGetGraphicsResetStatusARB'], + 'arguments': 'void', }, +{ 'return_type': 'void', + 'names': ['glGetIntegerv'], + 'arguments': 'GLenum pname, GLint* params', }, +{ 'return_type': 'void', + 'names': ['glGetProgramiv'], + 'arguments': 'GLuint program, GLenum pname, GLint* params', }, +{ 'return_type': 'void', + 'names': ['glGetProgramInfoLog'], + 'arguments': + 'GLuint program, GLsizei bufsize, GLsizei* length, char* infolog', }, +{ 'return_type': 'void', + 'names': ['glGetQueryiv'], + 'arguments': 'GLenum target, GLenum pname, GLint* params', }, +{ 'return_type': 'void', + 'names': ['glGetQueryivARB', 'glGetQueryivEXT'], + 'arguments': 'GLenum target, GLenum pname, GLint* params', }, +{ 'return_type': 'void', + 'names': ['glGetQueryObjecti64v'], + 'arguments': 'GLuint id, GLenum pname, GLint64* params', }, +{ 'return_type': 'void', + 'names': ['glGetQueryObjectiv'], + 'arguments': 'GLuint id, GLenum pname, GLint* params', }, +{ 'return_type': 'void', + 'names': ['glGetQueryObjectui64v'], + 'arguments': 'GLuint id, GLenum pname, GLuint64* params', }, +{ 'return_type': 'void', + 'names': ['glGetQueryObjectuiv'], + 'arguments': 'GLuint id, GLenum pname, GLuint* params', }, +{ 'return_type': 'void', + 'names': ['glGetQueryObjectuivARB', 'glGetQueryObjectuivEXT'], + 'arguments': 'GLuint id, GLenum pname, GLuint* params', }, +{ 'return_type': 'void', + 'names': ['glGetRenderbufferParameterivEXT', 'glGetRenderbufferParameteriv'], + 'arguments': 'GLenum target, GLenum pname, GLint* params', }, +{ 'return_type': 'void', + 'names': ['glGetShaderiv'], + 'arguments': 'GLuint shader, GLenum pname, GLint* params', }, +{ 'return_type': 'void', + 'names': ['glGetShaderInfoLog'], + 'arguments': + 'GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog', }, +{ 'return_type': 'void', + 'names': ['glGetShaderPrecisionFormat'], + 'arguments': 'GLenum shadertype, GLenum precisiontype, ' + 'GLint* range, GLint* precision', }, +{ 'return_type': 'void', + 'names': ['glGetShaderSource'], + 'arguments': + 'GLuint shader, GLsizei bufsize, GLsizei* length, char* source', }, +{ 'return_type': 'const GLubyte*', + 'names': ['glGetString'], + 'arguments': 'GLenum name', }, +{ 'return_type': 'void', + 'names': ['glGetTexLevelParameterfv'], + 'arguments': 'GLenum target, GLint level, GLenum pname, GLfloat* params', }, +{ 'return_type': 'void', + 'names': ['glGetTexLevelParameteriv'], + 'arguments': 'GLenum target, GLint level, GLenum pname, GLint* params', }, +{ 'return_type': 'void', + 'names': ['glGetTexParameterfv'], + 'arguments': 'GLenum target, GLenum pname, GLfloat* params', }, +{ 'return_type': 'void', + 'names': ['glGetTexParameteriv'], + 'arguments': 'GLenum target, GLenum pname, GLint* params', }, +{ 'return_type': 'void', + 'names': ['glGetTranslatedShaderSourceANGLE'], + 'arguments': + 'GLuint shader, GLsizei bufsize, GLsizei* length, char* source', }, +{ 'return_type': 'void', + 'names': ['glGetUniformfv'], + 'arguments': 'GLuint program, GLint location, GLfloat* params', }, +{ 'return_type': 'void', + 'names': ['glGetUniformiv'], + 'arguments': 'GLuint program, GLint location, GLint* params', }, +{ 'return_type': 'GLint', + 'names': ['glGetUniformLocation'], + 'arguments': 'GLuint program, const char* name', }, +{ 'return_type': 'void', + 'names': ['glGetVertexAttribfv'], + 'arguments': 'GLuint index, GLenum pname, GLfloat* params', }, +{ 'return_type': 'void', + 'names': ['glGetVertexAttribiv'], + 'arguments': 'GLuint index, GLenum pname, GLint* params', }, +{ 'return_type': 'void', + 'names': ['glGetVertexAttribPointerv'], + 'arguments': 'GLuint index, GLenum pname, void** pointer', }, +{ 'return_type': 'void', + 'names': ['glHint'], + 'arguments': 'GLenum target, GLenum mode', }, +{ 'return_type': 'GLboolean', + 'names': ['glIsBuffer'], + 'arguments': 'GLuint buffer', }, +{ 'return_type': 'GLboolean', + 'names': ['glIsEnabled'], + 'arguments': 'GLenum cap', }, +{ 'return_type': 'GLboolean', + 'names': ['glIsFramebufferEXT', 'glIsFramebuffer'], + 'arguments': 'GLuint framebuffer', }, +{ 'return_type': 'GLboolean', + 'names': ['glIsProgram'], + 'arguments': 'GLuint program', }, +{ 'return_type': 'GLboolean', + 'names': ['glIsQueryARB', 'glIsQueryEXT'], + 'arguments': 'GLuint query', }, +{ 'return_type': 'GLboolean', + 'names': ['glIsRenderbufferEXT', 'glIsRenderbuffer'], + 'arguments': 'GLuint renderbuffer', }, +{ 'return_type': 'GLboolean', + 'names': ['glIsShader'], + 'arguments': 'GLuint shader', }, +{ 'return_type': 'GLboolean', + 'names': ['glIsTexture'], + 'arguments': 'GLuint texture', }, +{ 'return_type': 'void', + 'names': ['glLineWidth'], + 'arguments': 'GLfloat width', }, +{ 'return_type': 'void', + 'names': ['glLinkProgram'], + 'arguments': 'GLuint program', }, +{ 'return_type': 'void*', + 'names': ['glMapBuffer', 'glMapBufferOES'], + 'arguments': 'GLenum target, GLenum access', }, +{ 'return_type': 'void', + 'names': ['glPixelStorei'], + 'arguments': 'GLenum pname, GLint param', }, +{ 'return_type': 'void', + 'names': ['glPolygonOffset'], + 'arguments': 'GLfloat factor, GLfloat units', }, +{ 'return_type': 'void', + 'names': ['glQueryCounter'], + 'arguments': 'GLuint id, GLenum target', }, +{ 'return_type': 'void', + 'names': ['glReadBuffer'], + 'arguments': 'GLenum src', }, +{ 'return_type': 'void', + 'names': ['glReadPixels'], + 'arguments': + 'GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, ' + 'GLenum type, void* pixels', }, +{ 'return_type': 'void', + 'names': ['glReleaseShaderCompiler'], + 'arguments': 'void', }, +{ 'return_type': 'void', + 'names': ['glRenderbufferStorageMultisampleEXT', + 'glRenderbufferStorageMultisample'], + 'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, ' + 'GLsizei width, GLsizei height', }, +{ 'return_type': 'void', + 'names': ['glRenderbufferStorageMultisampleANGLE', + 'glRenderbufferStorageMultisample'], + 'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, ' + 'GLsizei width, GLsizei height', }, +{ 'return_type': 'void', + 'names': ['glRenderbufferStorageEXT', 'glRenderbufferStorage'], + 'arguments': + 'GLenum target, GLenum internalformat, GLsizei width, GLsizei height', }, +{ 'return_type': 'void', + 'names': ['glSampleCoverage'], + 'arguments': 'GLclampf value, GLboolean invert', }, +{ 'return_type': 'void', + 'names': ['glScissor'], + 'arguments': 'GLint x, GLint y, GLsizei width, GLsizei height', }, +{ 'return_type': 'void', + 'names': ['glShaderBinary'], + 'arguments': 'GLsizei n, const GLuint* shaders, GLenum binaryformat, ' + 'const void* binary, GLsizei length', }, +{ 'return_type': 'void', + 'names': ['glShaderSource'], + 'arguments': + 'GLuint shader, GLsizei count, const char** str, const GLint* length', + 'logging_code': """ + GL_SERVICE_LOG_CODE_BLOCK({ + for (GLsizei ii = 0; ii < count; ++ii) { + if (str[ii]) { + if (length && length[ii] >= 0) { + std::string source(str[ii], length[ii]); + GL_SERVICE_LOG(" " << ii << ": ---\\n" << source << "\\n---"); + } else { + GL_SERVICE_LOG(" " << ii << ": ---\\n" << str[ii] << "\\n---"); + } + } else { + GL_SERVICE_LOG(" " << ii << ": NULL"); + } + } + }); +""", }, +{ 'return_type': 'void', + 'names': ['glStencilFunc'], + 'arguments': 'GLenum func, GLint ref, GLuint mask', }, +{ 'return_type': 'void', + 'names': ['glStencilFuncSeparate'], + 'arguments': 'GLenum face, GLenum func, GLint ref, GLuint mask', }, +{ 'return_type': 'void', + 'names': ['glStencilMask'], + 'arguments': 'GLuint mask', }, +{ 'return_type': 'void', + 'names': ['glStencilMaskSeparate'], + 'arguments': 'GLenum face, GLuint mask', }, +{ 'return_type': 'void', + 'names': ['glStencilOp'], + 'arguments': 'GLenum fail, GLenum zfail, GLenum zpass', }, +{ 'return_type': 'void', + 'names': ['glStencilOpSeparate'], + 'arguments': 'GLenum face, GLenum fail, GLenum zfail, GLenum zpass', }, +{ 'return_type': 'void', + 'names': ['glTexImage2D'], + 'arguments': + 'GLenum target, GLint level, GLint internalformat, GLsizei width, ' + 'GLsizei height, GLint border, GLenum format, GLenum type, ' + 'const void* pixels', }, +{ 'return_type': 'void', + 'names': ['glTexParameterf'], + 'arguments': 'GLenum target, GLenum pname, GLfloat param', }, +{ 'return_type': 'void', + 'names': ['glTexParameterfv'], + 'arguments': 'GLenum target, GLenum pname, const GLfloat* params', }, +{ 'return_type': 'void', + 'names': ['glTexParameteri'], + 'arguments': 'GLenum target, GLenum pname, GLint param', }, +{ 'return_type': 'void', + 'names': ['glTexParameteriv'], + 'arguments': 'GLenum target, GLenum pname, const GLint* params', }, +{ 'return_type': 'void', + 'names': ['glTexStorage2DEXT'], + 'arguments': 'GLenum target, GLsizei levels, GLenum internalformat, ' + 'GLsizei width, GLsizei height', }, +{ 'return_type': 'void', + 'names': ['glTexSubImage2D'], + 'arguments': + 'GLenum target, GLint level, GLint xoffset, GLint yoffset, ' + 'GLsizei width, GLsizei height, GLenum format, GLenum type, ' + 'const void* pixels', }, +{ 'return_type': 'void', + 'names': ['glUniform1f'], + 'arguments': 'GLint location, GLfloat x', }, +{ 'return_type': 'void', + 'names': ['glUniform1fv'], + 'arguments': 'GLint location, GLsizei count, const GLfloat* v', }, +{ 'return_type': 'void', + 'names': ['glUniform1i'], + 'arguments': 'GLint location, GLint x', }, +{ 'return_type': 'void', + 'names': ['glUniform1iv'], + 'arguments': 'GLint location, GLsizei count, const GLint* v', }, +{ 'return_type': 'void', + 'names': ['glUniform2f'], + 'arguments': 'GLint location, GLfloat x, GLfloat y', }, +{ 'return_type': 'void', + 'names': ['glUniform2fv'], + 'arguments': 'GLint location, GLsizei count, const GLfloat* v', }, +{ 'return_type': 'void', + 'names': ['glUniform2i'], + 'arguments': 'GLint location, GLint x, GLint y', }, +{ 'return_type': 'void', + 'names': ['glUniform2iv'], + 'arguments': 'GLint location, GLsizei count, const GLint* v', }, +{ 'return_type': 'void', + 'names': ['glUniform3f'], + 'arguments': 'GLint location, GLfloat x, GLfloat y, GLfloat z', }, +{ 'return_type': 'void', + 'names': ['glUniform3fv'], + 'arguments': 'GLint location, GLsizei count, const GLfloat* v', }, +{ 'return_type': 'void', + 'names': ['glUniform3i'], + 'arguments': 'GLint location, GLint x, GLint y, GLint z', }, +{ 'return_type': 'void', + 'names': ['glUniform3iv'], + 'arguments': 'GLint location, GLsizei count, const GLint* v', }, +{ 'return_type': 'void', + 'names': ['glUniform4f'], + 'arguments': 'GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w', }, +{ 'return_type': 'void', + 'names': ['glUniform4fv'], + 'arguments': 'GLint location, GLsizei count, const GLfloat* v', }, +{ 'return_type': 'void', + 'names': ['glUniform4i'], + 'arguments': 'GLint location, GLint x, GLint y, GLint z, GLint w', }, +{ 'return_type': 'void', + 'names': ['glUniform4iv'], + 'arguments': 'GLint location, GLsizei count, const GLint* v', }, +{ 'return_type': 'void', + 'names': ['glUniformMatrix2fv'], + 'arguments': 'GLint location, GLsizei count, ' + 'GLboolean transpose, const GLfloat* value', }, +{ 'return_type': 'void', + 'names': ['glUniformMatrix3fv'], + 'arguments': 'GLint location, GLsizei count, ' + 'GLboolean transpose, const GLfloat* value', }, +{ 'return_type': 'void', + 'names': ['glUniformMatrix4fv'], + 'arguments': 'GLint location, GLsizei count, ' + 'GLboolean transpose, const GLfloat* value', }, +{ 'return_type': 'GLboolean', + 'names': ['glUnmapBuffer', 'glUnmapBufferOES'], + 'arguments': 'GLenum target', }, +{ 'return_type': 'void', + 'names': ['glUseProgram'], + 'arguments': 'GLuint program', }, +{ 'return_type': 'void', + 'names': ['glValidateProgram'], + 'arguments': 'GLuint program', }, +{ 'return_type': 'void', + 'names': ['glVertexAttrib1f'], + 'arguments': 'GLuint indx, GLfloat x', }, +{ 'return_type': 'void', + 'names': ['glVertexAttrib1fv'], + 'arguments': 'GLuint indx, const GLfloat* values', }, +{ 'return_type': 'void', + 'names': ['glVertexAttrib2f'], + 'arguments': 'GLuint indx, GLfloat x, GLfloat y', }, +{ 'return_type': 'void', + 'names': ['glVertexAttrib2fv'], + 'arguments': 'GLuint indx, const GLfloat* values', }, +{ 'return_type': 'void', + 'names': ['glVertexAttrib3f'], + 'arguments': 'GLuint indx, GLfloat x, GLfloat y, GLfloat z', }, +{ 'return_type': 'void', + 'names': ['glVertexAttrib3fv'], + 'arguments': 'GLuint indx, const GLfloat* values', }, +{ 'return_type': 'void', + 'names': ['glVertexAttrib4f'], + 'arguments': 'GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w', }, +{ 'return_type': 'void', + 'names': ['glVertexAttrib4fv'], + 'arguments': 'GLuint indx, const GLfloat* values', }, +{ 'return_type': 'void', + 'names': ['glVertexAttribPointer'], + 'arguments': 'GLuint indx, GLint size, GLenum type, GLboolean normalized, ' + 'GLsizei stride, const void* ptr', }, +{ 'return_type': 'void', + 'names': ['glViewport'], + 'arguments': 'GLint x, GLint y, GLsizei width, GLsizei height', }, +{ 'return_type': 'void', + 'names': ['glGenFencesNV'], + 'arguments': 'GLsizei n, GLuint* fences', }, +{ 'return_type': 'void', + 'names': ['glDeleteFencesNV'], + 'arguments': 'GLsizei n, const GLuint* fences', }, +{ 'return_type': 'void', + 'names': ['glSetFenceNV'], + 'arguments': 'GLuint fence, GLenum condition', }, +{ 'return_type': 'GLboolean', + 'names': ['glTestFenceNV'], + 'arguments': 'GLuint fence', }, +{ 'return_type': 'void', + 'names': ['glFinishFenceNV'], + 'arguments': 'GLuint fence', }, +{ 'return_type': 'GLboolean', + 'names': ['glIsFenceNV'], + 'arguments': 'GLuint fence', }, +{ 'return_type': 'void', + 'names': ['glGetFenceivNV'], + 'arguments': 'GLuint fence, GLenum pname, GLint* params', }, +{ 'return_type': 'GLsync', + 'names': ['glFenceSync'], + 'arguments': 'GLenum condition, GLbitfield flags', }, +{ 'return_type': 'void', + 'names': ['glDeleteSync'], + 'arguments': 'GLsync sync', }, +{ 'return_type': 'void', + 'names': ['glGetSynciv'], + 'arguments': + 'GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length,' + 'GLint* values', }, +{ 'return_type': 'void', + 'names': ['glDrawArraysInstancedANGLE', 'glDrawArraysInstancedARB'], + 'arguments': 'GLenum mode, GLint first, GLsizei count, GLsizei primcount', }, +{ 'return_type': 'void', + 'names': ['glDrawElementsInstancedANGLE', 'glDrawElementsInstancedARB'], + 'arguments': + 'GLenum mode, GLsizei count, GLenum type, const void* indices, ' + 'GLsizei primcount', }, +{ 'return_type': 'void', + 'names': ['glVertexAttribDivisorANGLE', 'glVertexAttribDivisorARB'], + 'arguments': + 'GLuint index, GLuint divisor', }, +] + +OSMESA_FUNCTIONS = [ +{ 'return_type': 'OSMesaContext', + 'names': ['OSMesaCreateContext'], + 'arguments': 'GLenum format, OSMesaContext sharelist', }, +{ 'return_type': 'OSMesaContext', + 'names': ['OSMesaCreateContextExt'], + 'arguments': + 'GLenum format, GLint depthBits, GLint stencilBits, GLint accumBits, ' + 'OSMesaContext sharelist', }, +{ 'return_type': 'void', + 'names': ['OSMesaDestroyContext'], + 'arguments': 'OSMesaContext ctx', }, +{ 'return_type': 'GLboolean', + 'names': ['OSMesaMakeCurrent'], + 'arguments': 'OSMesaContext ctx, void* buffer, GLenum type, GLsizei width, ' + 'GLsizei height', }, +{ 'return_type': 'OSMesaContext', + 'names': ['OSMesaGetCurrentContext'], + 'arguments': 'void', }, +{ 'return_type': 'void', + 'names': ['OSMesaPixelStore'], + 'arguments': 'GLint pname, GLint value', }, +{ 'return_type': 'void', + 'names': ['OSMesaGetIntegerv'], + 'arguments': 'GLint pname, GLint* value', }, +{ 'return_type': 'GLboolean', + 'names': ['OSMesaGetDepthBuffer'], + 'arguments': + 'OSMesaContext c, GLint* width, GLint* height, GLint* bytesPerValue, ' + 'void** buffer', }, +{ 'return_type': 'GLboolean', + 'names': ['OSMesaGetColorBuffer'], + 'arguments': 'OSMesaContext c, GLint* width, GLint* height, GLint* format, ' + 'void** buffer', }, +{ 'return_type': 'OSMESAproc', + 'names': ['OSMesaGetProcAddress'], + 'arguments': 'const char* funcName', }, +{ 'return_type': 'void', + 'names': ['OSMesaColorClamp'], + 'arguments': 'GLboolean enable', }, +] + +EGL_FUNCTIONS = [ +{ 'return_type': 'EGLint', + 'names': ['eglGetError'], + 'arguments': 'void', }, +{ 'return_type': 'EGLDisplay', + 'names': ['eglGetDisplay'], + 'arguments': 'EGLNativeDisplayType display_id', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglInitialize'], + 'arguments': 'EGLDisplay dpy, EGLint* major, EGLint* minor', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglTerminate'], + 'arguments': 'EGLDisplay dpy', }, +{ 'return_type': 'const char*', + 'names': ['eglQueryString'], + 'arguments': 'EGLDisplay dpy, EGLint name', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglGetConfigs'], + 'arguments': 'EGLDisplay dpy, EGLConfig* configs, EGLint config_size, ' + 'EGLint* num_config', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglChooseConfig'], + 'arguments': 'EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, ' + 'EGLint config_size, EGLint* num_config', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglGetConfigAttrib'], + 'arguments': + 'EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value', }, +{ 'return_type': 'EGLImageKHR', + 'names': ['eglCreateImageKHR'], + 'arguments': + 'EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, ' + 'const EGLint* attrib_list', + 'other_extensions': ['EGL_KHR_image_base'] }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglDestroyImageKHR'], + 'arguments': 'EGLDisplay dpy, EGLImageKHR image', + 'other_extensions': ['EGL_KHR_image_base'] }, +{ 'return_type': 'EGLSurface', + 'names': ['eglCreateWindowSurface'], + 'arguments': 'EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, ' + 'const EGLint* attrib_list', }, +{ 'return_type': 'EGLSurface', + 'names': ['eglCreatePbufferSurface'], + 'arguments': 'EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list', }, +{ 'return_type': 'EGLSurface', + 'names': ['eglCreatePixmapSurface'], + 'arguments': 'EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, ' + 'const EGLint* attrib_list', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglDestroySurface'], + 'arguments': 'EGLDisplay dpy, EGLSurface surface', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglQuerySurface'], + 'arguments': + 'EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint* value', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglBindAPI'], + 'arguments': 'EGLenum api', }, +{ 'return_type': 'EGLenum', + 'names': ['eglQueryAPI'], + 'arguments': 'void', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglWaitClient'], + 'arguments': 'void', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglReleaseThread'], + 'arguments': 'void', }, +{ 'return_type': 'EGLSurface', + 'names': ['eglCreatePbufferFromClientBuffer'], + 'arguments': + 'EGLDisplay dpy, EGLenum buftype, void* buffer, EGLConfig config, ' + 'const EGLint* attrib_list', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglSurfaceAttrib'], + 'arguments': + 'EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglBindTexImage'], + 'arguments': 'EGLDisplay dpy, EGLSurface surface, EGLint buffer', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglReleaseTexImage'], + 'arguments': 'EGLDisplay dpy, EGLSurface surface, EGLint buffer', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglSwapInterval'], + 'arguments': 'EGLDisplay dpy, EGLint interval', }, +{ 'return_type': 'EGLContext', + 'names': ['eglCreateContext'], + 'arguments': 'EGLDisplay dpy, EGLConfig config, EGLContext share_context, ' + 'const EGLint* attrib_list', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglDestroyContext'], + 'arguments': 'EGLDisplay dpy, EGLContext ctx', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglMakeCurrent'], + 'arguments': + 'EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx', }, +{ 'return_type': 'EGLContext', + 'names': ['eglGetCurrentContext'], + 'arguments': 'void', }, +{ 'return_type': 'EGLSurface', + 'names': ['eglGetCurrentSurface'], + 'arguments': 'EGLint readdraw', }, +{ 'return_type': 'EGLDisplay', + 'names': ['eglGetCurrentDisplay'], + 'arguments': 'void', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglQueryContext'], + 'arguments': + 'EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint* value', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglWaitGL'], + 'arguments': 'void', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglWaitNative'], + 'arguments': 'EGLint engine', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglSwapBuffers'], + 'arguments': 'EGLDisplay dpy, EGLSurface surface', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglCopyBuffers'], + 'arguments': + 'EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target', }, +{ 'return_type': '__eglMustCastToProperFunctionPointerType', + 'names': ['eglGetProcAddress'], + 'arguments': 'const char* procname', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglPostSubBufferNV'], + 'arguments': 'EGLDisplay dpy, EGLSurface surface, ' + 'EGLint x, EGLint y, EGLint width, EGLint height', }, +{ 'return_type': 'EGLBoolean', + 'names': ['eglQuerySurfacePointerANGLE'], + 'arguments': + 'EGLDisplay dpy, EGLSurface surface, EGLint attribute, void** value', }, +] + +WGL_FUNCTIONS = [ +{ 'return_type': 'HGLRC', + 'names': ['wglCreateContext'], + 'arguments': 'HDC hdc', }, +{ 'return_type': 'HGLRC', + 'names': ['wglCreateLayerContext'], + 'arguments': 'HDC hdc, int iLayerPlane', }, +{ 'return_type': 'BOOL', + 'names': ['wglCopyContext'], + 'arguments': 'HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask', }, +{ 'return_type': 'BOOL', + 'names': ['wglDeleteContext'], + 'arguments': 'HGLRC hglrc', }, +{ 'return_type': 'HGLRC', + 'names': ['wglGetCurrentContext'], + 'arguments': '', }, +{ 'return_type': 'HDC', + 'names': ['wglGetCurrentDC'], + 'arguments': '', }, +{ 'return_type': 'BOOL', + 'names': ['wglMakeCurrent'], + 'arguments': 'HDC hdc, HGLRC hglrc', }, +{ 'return_type': 'BOOL', + 'names': ['wglShareLists'], + 'arguments': 'HGLRC hglrc1, HGLRC hglrc2', }, +{ 'return_type': 'BOOL', + 'names': ['wglSwapIntervalEXT'], + 'arguments': 'int interval', }, +{ 'return_type': 'BOOL', + 'names': ['wglSwapLayerBuffers'], + 'arguments': 'HDC hdc, UINT fuPlanes', }, +{ 'return_type': 'const char*', + 'names': ['wglGetExtensionsStringARB'], + 'arguments': 'HDC hDC', }, +{ 'return_type': 'const char*', + 'names': ['wglGetExtensionsStringEXT'], + 'arguments': '', }, +{ 'return_type': 'BOOL', + 'names': ['wglChoosePixelFormatARB'], + 'arguments': + 'HDC dc, const int* int_attrib_list, const float* float_attrib_list, ' + 'UINT max_formats, int* formats, UINT* num_formats', }, +{ 'return_type': 'HPBUFFERARB', + 'names': ['wglCreatePbufferARB'], + 'arguments': 'HDC hDC, int iPixelFormat, int iWidth, int iHeight, ' + 'const int* piAttribList', }, +{ 'return_type': 'HDC', + 'names': ['wglGetPbufferDCARB'], + 'arguments': 'HPBUFFERARB hPbuffer', }, +{ 'return_type': 'int', + 'names': ['wglReleasePbufferDCARB'], + 'arguments': 'HPBUFFERARB hPbuffer, HDC hDC', }, +{ 'return_type': 'BOOL', + 'names': ['wglDestroyPbufferARB'], + 'arguments': 'HPBUFFERARB hPbuffer', }, +{ 'return_type': 'BOOL', + 'names': ['wglQueryPbufferARB'], + 'arguments': 'HPBUFFERARB hPbuffer, int iAttribute, int* piValue', }, +] + +GLX_FUNCTIONS = [ +{ 'return_type': 'XVisualInfo*', + 'names': ['glXChooseVisual'], + 'arguments': 'Display* dpy, int screen, int* attribList', }, +{ 'return_type': 'void', + 'names': ['glXCopySubBufferMESA'], + 'arguments': 'Display* dpy, GLXDrawable drawable, ' + 'int x, int y, int width, int height', }, +{ 'return_type': 'GLXContext', + 'names': ['glXCreateContext'], + 'arguments': + 'Display* dpy, XVisualInfo* vis, GLXContext shareList, int direct', }, +{ 'return_type': 'void', + 'names': ['glXBindTexImageEXT'], + 'arguments': + 'Display* dpy, GLXDrawable drawable, int buffer, int* attribList', }, +{ 'return_type': 'void', + 'names': ['glXReleaseTexImageEXT'], + 'arguments': 'Display* dpy, GLXDrawable drawable, int buffer', }, +{ 'return_type': 'void', + 'names': ['glXDestroyContext'], + 'arguments': 'Display* dpy, GLXContext ctx', }, +{ 'return_type': 'int', + 'names': ['glXMakeCurrent'], + 'arguments': 'Display* dpy, GLXDrawable drawable, GLXContext ctx', }, +{ 'return_type': 'void', + 'names': ['glXCopyContext'], + 'arguments': + 'Display* dpy, GLXContext src, GLXContext dst, unsigned long mask', }, +{ 'return_type': 'void', + 'names': ['glXSwapBuffers'], + 'arguments': 'Display* dpy, GLXDrawable drawable', }, +{ 'return_type': 'GLXPixmap', + 'names': ['glXCreateGLXPixmap'], + 'arguments': 'Display* dpy, XVisualInfo* visual, Pixmap pixmap', }, +{ 'return_type': 'void', + 'names': ['glXDestroyGLXPixmap'], + 'arguments': 'Display* dpy, GLXPixmap pixmap', }, +{ 'return_type': 'int', + 'names': ['glXQueryExtension'], + 'arguments': 'Display* dpy, int* errorb, int* event', }, +{ 'return_type': 'int', + 'names': ['glXQueryVersion'], + 'arguments': 'Display* dpy, int* maj, int* min', }, +{ 'return_type': 'int', + 'names': ['glXIsDirect'], + 'arguments': 'Display* dpy, GLXContext ctx', }, +{ 'return_type': 'int', + 'names': ['glXGetConfig'], + 'arguments': 'Display* dpy, XVisualInfo* visual, int attrib, int* value', }, +{ 'return_type': 'GLXContext', + 'names': ['glXGetCurrentContext'], + 'arguments': 'void', }, +{ 'return_type': 'GLXDrawable', + 'names': ['glXGetCurrentDrawable'], + 'arguments': 'void', }, +{ 'return_type': 'void', + 'names': ['glXWaitGL'], + 'arguments': 'void', }, +{ 'return_type': 'void', + 'names': ['glXWaitX'], + 'arguments': 'void', }, +{ 'return_type': 'void', + 'names': ['glXUseXFont'], + 'arguments': 'Font font, int first, int count, int list', }, +{ 'return_type': 'const char*', + 'names': ['glXQueryExtensionsString'], + 'arguments': 'Display* dpy, int screen', }, +{ 'return_type': 'const char*', + 'names': ['glXQueryServerString'], + 'arguments': 'Display* dpy, int screen, int name', }, +{ 'return_type': 'const char*', + 'names': ['glXGetClientString'], + 'arguments': 'Display* dpy, int name', }, +{ 'return_type': 'Display*', + 'names': ['glXGetCurrentDisplay'], + 'arguments': 'void', }, +{ 'return_type': 'GLXFBConfig*', + 'names': ['glXChooseFBConfig'], + 'arguments': + 'Display* dpy, int screen, const int* attribList, int* nitems', }, +{ 'return_type': 'int', + 'names': ['glXGetFBConfigAttrib'], + 'arguments': 'Display* dpy, GLXFBConfig config, int attribute, int* value', }, +{ 'return_type': 'GLXFBConfig*', + 'names': ['glXGetFBConfigs'], + 'arguments': 'Display* dpy, int screen, int* nelements', }, +{ 'return_type': 'XVisualInfo*', + 'names': ['glXGetVisualFromFBConfig'], + 'arguments': 'Display* dpy, GLXFBConfig config', }, +{ 'return_type': 'GLXWindow', + 'names': ['glXCreateWindow'], + 'arguments': + 'Display* dpy, GLXFBConfig config, Window win, const int* attribList', }, +{ 'return_type': 'void', + 'names': ['glXDestroyWindow'], + 'arguments': 'Display* dpy, GLXWindow window', }, +{ 'return_type': 'GLXPixmap', + 'names': ['glXCreatePixmap'], + 'arguments': 'Display* dpy, GLXFBConfig config, ' + 'Pixmap pixmap, const int* attribList', }, +{ 'return_type': 'void', + 'names': ['glXDestroyPixmap'], + 'arguments': 'Display* dpy, GLXPixmap pixmap', }, +{ 'return_type': 'GLXPbuffer', + 'names': ['glXCreatePbuffer'], + 'arguments': 'Display* dpy, GLXFBConfig config, const int* attribList', }, +{ 'return_type': 'void', + 'names': ['glXDestroyPbuffer'], + 'arguments': 'Display* dpy, GLXPbuffer pbuf', }, +{ 'return_type': 'void', + 'names': ['glXQueryDrawable'], + 'arguments': + 'Display* dpy, GLXDrawable draw, int attribute, unsigned int* value', }, +{ 'return_type': 'GLXContext', + 'names': ['glXCreateNewContext'], + 'arguments': 'Display* dpy, GLXFBConfig config, int renderType, ' + 'GLXContext shareList, int direct', }, +{ 'return_type': 'int', + 'names': ['glXMakeContextCurrent'], + 'arguments': + 'Display* dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx', }, +{ 'return_type': 'GLXDrawable', + 'names': ['glXGetCurrentReadDrawable'], + 'arguments': 'void', }, +{ 'return_type': 'int', + 'names': ['glXQueryContext'], + 'arguments': 'Display* dpy, GLXContext ctx, int attribute, int* value', }, +{ 'return_type': 'void', + 'names': ['glXSelectEvent'], + 'arguments': 'Display* dpy, GLXDrawable drawable, unsigned long mask', }, +{ 'return_type': 'void', + 'names': ['glXGetSelectedEvent'], + 'arguments': 'Display* dpy, GLXDrawable drawable, unsigned long* mask', }, +{ 'return_type': 'void', + 'names': ['glXSwapIntervalEXT'], + 'arguments': 'Display* dpy, GLXDrawable drawable, int interval', }, +{ 'return_type': 'GLXFBConfig', + 'names': ['glXGetFBConfigFromVisualSGIX'], + 'arguments': 'Display* dpy, XVisualInfo* visualInfo', }, +{ 'return_type': 'GLXContext', + 'names': ['glXCreateContextAttribsARB'], + 'arguments': + 'Display* dpy, GLXFBConfig config, GLXContext share_context, int direct, ' + 'const int* attrib_list', }, +] + +FUNCTION_SETS = [ + [GL_FUNCTIONS, 'gl', ['../../third_party/mesa/MesaLib/include/GL/glext.h', + '../../third_party/khronos/GLES2/gl2ext.h'], []], + [OSMESA_FUNCTIONS, 'osmesa', [], []], + [EGL_FUNCTIONS, 'egl', ['../../third_party/khronos/EGL/eglext.h'], + [ + 'EGL_ANGLE_d3d_share_handle_client_buffer', + ], + ], + [WGL_FUNCTIONS, 'wgl', [ + '../../third_party/mesa/MesaLib/include/GL/wglext.h'], []], + [GLX_FUNCTIONS, 'glx', [ + '../../third_party/mesa/MesaLib/include/GL/glxext.h'], []], +] + +def GenerateHeader(file, functions, set_name, used_extension_functions): + """Generates gl_binding_autogen_x.h""" + + # Write file header. + file.write('// Copyright (c) 2011 The Chromium Authors. All rights reserved.\n') + file.write('// Use of this source code is governed by a BSD-style license that can be\n') + file.write('// found in the LICENSE file.\n') + file.write('\n') + file.write('// This file is automatically generated.\n') + file.write('\n') + file.write('#ifndef UI_GFX_GL_GL_BINDINGS_AUTOGEN_%s_H_\n' % set_name.upper()) + file.write('#define UI_GFX_GL_GL_BINDINGS_AUTOGEN_%s_H_\n' % set_name.upper()) + + # Write prototype for initialization function. + file.write('\n') + file.write('namespace gfx {\n') + file.write('\n') + file.write('class GLContext;\n') + file.write('\n') + file.write('void InitializeGLBindings%s();\n' % set_name.upper()) + file.write('void InitializeGLExtensionBindings%s(GLContext* context);\n' % + set_name.upper()) + file.write('void InitializeDebugGLBindings%s();\n' % set_name.upper()) + file.write('void ClearGLBindings%s();\n' % set_name.upper()) + + # Write typedefs for function pointer types. Always use the GL name for the + # typedef. + file.write('\n') + for func in functions: + file.write('typedef %s (GL_BINDING_CALL *%sProc)(%s);\n' % + (func['return_type'], func['names'][0], func['arguments'])) + + # Write declarations for booleans indicating which extensions are available. + file.write('\n') + for extension, ext_functions in used_extension_functions: + file.write('GL_EXPORT extern bool g_%s;\n' % extension) + + # Write declarations for function pointers. Always use the GL name for the + # declaration. + file.write('\n') + for func in functions: + file.write('GL_EXPORT extern %sProc g_%s;\n' % + (func['names'][0], func['names'][0])) + file.write('\n') + file.write( '} // namespace gfx\n') + + # Write macros to invoke function pointers. Always use the GL name for the + # macro. + file.write('\n') + for func in functions: + file.write('#define %s ::gfx::g_%s\n' % + (func['names'][0], func['names'][0])) + + file.write('\n') + file.write('#endif // UI_GFX_GL_GL_BINDINGS_AUTOGEN_%s_H_\n' % + set_name.upper()) + + +def GenerateSource(file, functions, set_name, used_extension_functions): + """Generates gl_binding_autogen_x.cc""" + + # Write file header. + file.write('// Copyright (c) 2011 The Chromium Authors. All rights reserved.\n') + file.write('// Use of this source code is governed by a BSD-style license that can be\n') + file.write('// found in the LICENSE file.\n') + file.write('\n') + file.write('// This file is automatically generated.\n') + file.write('\n') + file.write('#include <string>\n') + file.write('#include "gpu/command_buffer/common/gles2_cmd_utils.h"\n') + file.write('#include "ui/gl/gl_bindings.h"\n') + file.write('#include "ui/gl/gl_context.h"\n') + file.write('#include "ui/gl/gl_implementation.h"\n') + + # Write definitions for booleans indicating which extensions are available. + file.write('\n') + file.write('using gpu::gles2::GLES2Util;\n') + file.write('\n') + file.write('namespace gfx {\n') + file.write('\n') + for extension, ext_functions in used_extension_functions: + file.write('bool g_%s;\n' % extension) + + # Write definitions of function pointers. + file.write('\n') + file.write('static bool g_debugBindingsInitialized;\n') + file.write('static void UpdateDebugGLExtensionBindings();\n') + file.write('\n') + for func in functions: + file.write('%sProc g_%s;\n' % (func['names'][0], func['names'][0])) + + file.write('\n') + for func in functions: + file.write('static %sProc g_debug_%s;\n' % + (func['names'][0], func['names'][0])) + + # Write function to initialize the core function pointers. The code assumes + # any non-NULL pointer returned by GetGLCoreProcAddress() is valid, although + # it may be overwritten by an extension function pointer later. + file.write('\n') + file.write('void InitializeGLBindings%s() {\n' % set_name.upper()) + for func in functions: + first_name = func['names'][0] + for i, name in enumerate(func['names']): + if i: + file.write(' if (!g_%s)\n ' % first_name) + file.write( + ' g_%s = reinterpret_cast<%sProc>(GetGLCoreProcAddress("%s"));\n' % + (first_name, first_name, name)) + file.write('}\n') + file.write('\n') + + # Write function to initialize the extension function pointers. This function + # uses a current context to query which extensions are actually supported. + file.write('void InitializeGLExtensionBindings%s(GLContext* context) {\n' % + set_name.upper()) + file.write(' DCHECK(context && context->IsCurrent(NULL));\n') + for extension, ext_functions in used_extension_functions: + file.write(' g_%s = context->HasExtension("%s");\n' % + (extension, extension)) + file.write(' if (g_%s) {\n' % + (extension)) + queried_entry_points = set() + for entry_point_name, function_name in ext_functions: + # Replace the pointer unconditionally unless this extension has several + # alternatives for the same entry point (e.g., + # GL_ARB_blend_func_extended). + if entry_point_name in queried_entry_points: + file.write(' if (!g_%s)\n ' % entry_point_name) + file.write( + ' g_%s = reinterpret_cast<%sProc>(GetGLProcAddress("%s"));\n' % + (entry_point_name, entry_point_name, function_name)) + queried_entry_points.add(entry_point_name) + file.write(' }\n') + file.write(' if (g_debugBindingsInitialized)\n') + file.write(' UpdateDebugGLExtensionBindings();\n') + file.write('}\n') + file.write('\n') + + # Write logging wrappers for each function. + file.write('extern "C" {\n') + for func in functions: + names = func['names'] + return_type = func['return_type'] + arguments = func['arguments'] + file.write('\n') + file.write('static %s GL_BINDING_CALL Debug_%s(%s) {\n' % + (return_type, names[0], arguments)) + argument_names = re.sub( + r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2', arguments) + argument_names = re.sub( + r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2', argument_names) + log_argument_names = re.sub( + r'const char\* ([a-zA-Z0-9_]+)', r'CONSTCHAR_\1', arguments) + log_argument_names = re.sub( + r'(const )?[a-zA-Z0-9_]+\* ([a-zA-Z0-9_]+)', + r'CONSTVOID_\2', log_argument_names) + log_argument_names = re.sub( + r'(?<!E)GLenum ([a-zA-Z0-9_]+)', r'GLenum_\1', log_argument_names) + log_argument_names = re.sub( + r'(?<!E)GLboolean ([a-zA-Z0-9_]+)', r'GLboolean_\1', log_argument_names) + log_argument_names = re.sub( + r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2', + log_argument_names) + log_argument_names = re.sub( + r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2', + log_argument_names) + log_argument_names = re.sub( + r'CONSTVOID_([a-zA-Z0-9_]+)', + r'static_cast<const void*>(\1)', log_argument_names); + log_argument_names = re.sub( + r'CONSTCHAR_([a-zA-Z0-9_]+)', r'\1', log_argument_names); + log_argument_names = re.sub( + r'GLenum_([a-zA-Z0-9_]+)', r'GLES2Util::GetStringEnum(\1)', + log_argument_names) + log_argument_names = re.sub( + r'GLboolean_([a-zA-Z0-9_]+)', r'GLES2Util::GetStringBool(\1)', + log_argument_names) + log_argument_names = log_argument_names.replace(',', ' << ", " <<') + if argument_names == 'void' or argument_names == '': + argument_names = '' + log_argument_names = '' + else: + log_argument_names = " << " + log_argument_names + function_name = names[0] + if return_type == 'void': + file.write(' GL_SERVICE_LOG("%s" << "(" %s << ")");\n' % + (function_name, log_argument_names)) + file.write(' g_debug_%s(%s);\n' % + (function_name, argument_names)) + if 'logging_code' in func: + file.write("%s\n" % func['logging_code']) + else: + file.write(' GL_SERVICE_LOG("%s" << "(" %s << ")");\n' % + (function_name, log_argument_names)) + file.write(' %s result = g_debug_%s(%s);\n' % + (return_type, function_name, argument_names)) + if 'logging_code' in func: + file.write("%s\n" % func['logging_code']) + else: + file.write(' GL_SERVICE_LOG("GL_RESULT: " << result);\n'); + file.write(' return result;\n') + file.write('}\n') + file.write('} // extern "C"\n') + + # Write function to initialize the debug function pointers. + file.write('\n') + file.write('void InitializeDebugGLBindings%s() {\n' % set_name.upper()) + for func in functions: + first_name = func['names'][0] + file.write(' if (!g_debug_%s) {\n' % first_name) + file.write(' g_debug_%s = g_%s;\n' % (first_name, first_name)) + file.write(' g_%s = Debug_%s;\n' % (first_name, first_name)) + file.write(' }\n') + file.write(' g_debugBindingsInitialized = true;\n') + file.write('}\n') + + # Write function to update the debug function pointers to extension functions + # after the extensions have been initialized. + file.write('\n') + file.write('static void UpdateDebugGLExtensionBindings() {\n') + for extension, ext_functions in used_extension_functions: + for name, _ in ext_functions: + file.write(' if (g_debug_%s != g_%s &&\n' % (name, name)) + file.write(' g_%s != Debug_%s) {\n' % (name, name)) + file.write(' g_debug_%s = g_%s;\n' % (name, name)) + file.write(' g_%s = Debug_%s;\n' % (name, name)) + file.write(' }\n') + file.write('}\n') + + # Write function to clear all function pointers. + file.write('\n') + file.write('void ClearGLBindings%s() {\n' % set_name.upper()) + # Clear the availability of GL extensions. + for extension, ext_functions in used_extension_functions: + file.write(' g_%s = false;\n' % extension) + # Clear GL bindings. + file.write('\n') + for func in functions: + file.write(' g_%s = NULL;\n' % func['names'][0]) + # Clear debug GL bindings. + file.write('\n') + for func in functions: + file.write(' g_debug_%s = NULL;\n' % func['names'][0]) + file.write(' g_debugBindingsInitialized = false;\n') + file.write('}\n') + + file.write('\n') + file.write('} // namespace gfx\n') + + +def GenerateMockSource(file, functions): + """Generates functions that invoke a mock GLInterface""" + + file.write('// Copyright (c) 2011 The Chromium Authors. All rights reserved.\n') + file.write('// Use of this source code is governed by a BSD-style license that can be\n') + file.write('// found in the LICENSE file.\n') + file.write('\n') + file.write('// This file is automatically generated.\n') + file.write('\n') + file.write('#include <string.h>\n') + file.write('\n') + file.write('#include "ui/gl/gl_interface.h"\n') + + file.write('\n') + file.write('namespace gfx {\n') + + # Write function that trampoline into the GLInterface. + for func in functions: + file.write('\n') + file.write('%s GL_BINDING_CALL Mock_%s(%s) {\n' % + (func['return_type'], func['names'][0], func['arguments'])) + argument_names = re.sub(r'(const )?[a-zA-Z0-9]+\** ([a-zA-Z0-9]+)', r'\2', + func['arguments']) + if argument_names == 'void': + argument_names = '' + function_name = func['names'][0][2:] + if func['return_type'] == 'void': + file.write(' GLInterface::GetGLInterface()->%s(%s);\n' % + (function_name, argument_names)) + else: + file.write(' return GLInterface::GetGLInterface()->%s(%s);\n' % + (function_name, argument_names)) + file.write('}\n') + + # Write an 'invalid' function to catch code calling through uninitialized + # function pointers or trying to interpret the return value of + # GLProcAddress(). + file.write('\n') + file.write('static void MockInvalidFunction() {\n') + file.write(' NOTREACHED();\n') + file.write('}\n') + + # Write a function to lookup a mock GL function based on its name. + file.write('\n') + file.write('void* GL_BINDING_CALL GetMockGLProcAddress(const char* name) {\n') + for func in functions: + first_name = func['names'][0] + file.write(' if (strcmp(name, "%s") == 0)\n' % first_name) + file.write(' return reinterpret_cast<void*>(Mock_%s);\n' % first_name) + # Always return a non-NULL pointer like some EGL implementations do. + file.write(' return reinterpret_cast<void*>(&MockInvalidFunction);\n') + file.write('}\n'); + + file.write('\n') + file.write('} // namespace gfx\n') + + +def ParseExtensionFunctionsFromHeader(header_file): + """Parse a C extension header file and return a map from extension names to + a list of functions. + + Args: + header_file: Line-iterable C header file. + Returns: + Map of extension name => functions. + """ + extension_start = re.compile(r'#define ([A-Z]+_[A-Z]+_[a-zA-Z]\w+) 1') + extension_function = re.compile(r'.+\s+([a-z]+\w+)\s*\(.+\);') + typedef = re.compile(r'typedef .*') + macro_start = re.compile(r'^#(if|ifdef|ifndef).*') + macro_end = re.compile(r'^#endif.*') + macro_depth = 0 + current_extension = None + current_extension_depth = 0 + extensions = collections.defaultdict(lambda: []) + for line in header_file: + if macro_start.match(line): + macro_depth += 1 + elif macro_end.match(line): + macro_depth -= 1 + if macro_depth < current_extension_depth: + current_extension = None + match = extension_start.match(line) + if match: + current_extension = match.group(1) + current_extension_depth = macro_depth + assert current_extension not in extensions, \ + "Duplicate extension: " + current_extension + match = extension_function.match(line) + if match and current_extension and not typedef.match(line): + extensions[current_extension].append(match.group(1)) + return extensions + + +def GetExtensionFunctions(extension_headers): + """Parse extension functions from a list of header files. + + Args: + extension_headers: List of header file names. + Returns: + Map of extension name => list of functions. + """ + extensions = {} + for header in extension_headers: + extensions.update(ParseExtensionFunctionsFromHeader(open(header))) + return extensions + + +def GetFunctionToExtensionMap(extensions): + """Construct map from a function names to extensions which define the + function. + + Args: + extensions: Map of extension name => functions. + Returns: + Map of function name => extension name. + """ + function_to_extensions = {} + for extension, functions in extensions.items(): + for function in functions: + if not function in function_to_extensions: + function_to_extensions[function] = [] + function_to_extensions[function].append(extension) + return function_to_extensions + + +def LooksLikeExtensionFunction(function): + """Heuristic to see if a function name is consistent with extension function + naming.""" + vendor = re.match(r'\w+?([A-Z][A-Z]+)$', function) + return vendor is not None and not vendor.group(1) in ['GL', 'API', 'DC'] + + +def GetUsedExtensionFunctions(functions, extension_headers, extra_extensions): + """Determine which functions belong to extensions. + + Args: + functions: List of (return type, function names, arguments). + extension_headers: List of header file names. + Returns: + List of (extension name, [function name alternatives]) sorted with least + preferred extensions first. + """ + # Parse known extensions. + extensions = GetExtensionFunctions(extension_headers) + functions_to_extensions = GetFunctionToExtensionMap(extensions) + + # Collect all used extension functions. + used_extension_functions = collections.defaultdict(lambda: []) + for func in functions: + for name in func['names']: + # Make sure we know about all extension functions. + if (LooksLikeExtensionFunction(name) and + not name in functions_to_extensions): + raise RuntimeError('%s looks like an extension function but does not ' + 'belong to any of the known extensions.' % name) + if name in functions_to_extensions: + extensions = functions_to_extensions[name][:] + if 'other_extensions' in func: + extensions.extend(func['other_extensions']) + for extension in extensions: + used_extension_functions[extension].append((func['names'][0], name)) + + # Add extensions that do not have any functions. + used_extension_functions.update(dict( + [(e, []) for e in extra_extensions if e not in used_extension_functions])) + + def ExtensionSortKey(name): + # Prefer ratified extensions and EXTs. + preferences = ['_ARB_', '_OES_', '_EXT_', ''] + for i, category in enumerate(preferences): + if category in name: + return -i + used_extension_functions = sorted(used_extension_functions.items(), + key = lambda item: ExtensionSortKey(item[0])) + return used_extension_functions + + +def main(argv): + """This is the main function.""" + + if len(argv) >= 1: + dir = argv[0] + else: + dir = '.' + + for [functions, set_name, extension_headers, extensions] in FUNCTION_SETS: + used_extension_functions = GetUsedExtensionFunctions( + functions, extension_headers, extensions) + + header_file = open( + os.path.join(dir, 'gl_bindings_autogen_%s.h' % set_name), 'wb') + GenerateHeader(header_file, functions, set_name, used_extension_functions) + header_file.close() + + source_file = open( + os.path.join(dir, 'gl_bindings_autogen_%s.cc' % set_name), 'wb') + GenerateSource(source_file, functions, set_name, used_extension_functions) + source_file.close() + + source_file = open(os.path.join(dir, 'gl_bindings_autogen_mock.cc'), 'wb') + GenerateMockSource(source_file, GL_FUNCTIONS) + source_file.close() + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/ui/gl/gl.gyp b/ui/gl/gl.gyp new file mode 100644 index 0000000..87f9803 --- /dev/null +++ b/ui/gl/gl.gyp @@ -0,0 +1,206 @@ +# 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. + +{ + 'variables': { + 'chromium_code': 1, + }, + + 'targets': [ + { + 'target_name': 'gl', + 'type': '<(component)', + 'product_name': 'gl_wrapper', # Avoid colliding with OS X's libGL.dylib + 'dependencies': [ + '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', + '<(DEPTH)/gpu/command_buffer/command_buffer.gyp:gles2_utils', + '<(DEPTH)/skia/skia.gyp:skia', + '<(DEPTH)/ui/ui.gyp:ui', + ], + 'variables': { + 'gl_binding_output_dir': '<(SHARED_INTERMEDIATE_DIR)/ui/gl', + }, + 'defines': [ + 'GL_IMPLEMENTATION', + ], + 'include_dirs': [ + '<(DEPTH)/third_party/swiftshader/include', + '<(DEPTH)/third_party/mesa/MesaLib/include', + '<(gl_binding_output_dir)', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '<(DEPTH)/third_party/mesa/MesaLib/include', + '<(gl_binding_output_dir)', + ], + }, + 'sources': [ + 'gl_bindings.h', + 'gl_bindings_skia_in_process.cc', + 'gl_bindings_skia_in_process.h', + 'gl_context.cc', + 'gl_context.h', + 'gl_context_android.cc', + 'gl_context_linux.cc', + 'gl_context_mac.mm', + 'gl_context_osmesa.cc', + 'gl_context_osmesa.h', + 'gl_context_stub.cc', + 'gl_context_stub.h', + 'gl_context_win.cc', + 'gl_export.h', + 'gl_fence.cc', + 'gl_fence.h', + 'gl_implementation.cc', + 'gl_implementation.h', + 'gl_implementation_android.cc', + 'gl_implementation_linux.cc', + 'gl_implementation_mac.cc', + 'gl_implementation_win.cc', + 'gl_interface.cc', + 'gl_interface.h', + 'gl_share_group.cc', + 'gl_share_group.h', + 'gl_surface.cc', + 'gl_surface.h', + 'gl_surface_android.cc', + 'gl_surface_android.h', + 'gl_surface_linux.cc', + 'gl_surface_mac.cc', + 'gl_surface_stub.cc', + 'gl_surface_stub.h', + 'gl_surface_win.cc', + 'gl_surface_osmesa.cc', + 'gl_surface_osmesa.h', + 'gl_switches.cc', + 'gl_switches.h', + 'scoped_make_current.cc', + 'scoped_make_current.h', + '<(gl_binding_output_dir)/gl_bindings_autogen_gl.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_gl.h', + '<(gl_binding_output_dir)/gl_bindings_autogen_mock.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_osmesa.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_osmesa.h', + ], + # hard_dependency is necessary for this target because it has actions + # that generate header files included by dependent targets. The header + # files must be generated before the dependents are compiled. The usual + # semantics are to allow the two targets to build concurrently. + 'hard_dependency': 1, + 'actions': [ + { + 'action_name': 'generate_gl_bindings', + 'inputs': [ + 'generate_bindings.py', + '<(DEPTH)/third_party/khronos/GLES2/gl2ext.h', + '<(DEPTH)/third_party/khronos/EGL/eglext.h', + '<(DEPTH)/third_party/mesa/MesaLib/include/GL/glext.h', + '<(DEPTH)/third_party/mesa/MesaLib/include/GL/glxext.h', + '<(DEPTH)/third_party/mesa/MesaLib/include/GL/wglext.h', + ], + 'outputs': [ + '<(gl_binding_output_dir)/gl_bindings_autogen_egl.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_egl.h', + '<(gl_binding_output_dir)/gl_bindings_autogen_gl.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_gl.h', + '<(gl_binding_output_dir)/gl_bindings_autogen_glx.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_glx.h', + '<(gl_binding_output_dir)/gl_bindings_autogen_mock.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_osmesa.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_osmesa.h', + '<(gl_binding_output_dir)/gl_bindings_autogen_wgl.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_wgl.h', + ], + 'action': [ + 'python', + 'generate_bindings.py', + '<(gl_binding_output_dir)', + ], + }, + ], + 'conditions': [ + ['OS != "mac"', { + 'sources': [ + 'egl_util.cc', + 'egl_util.h', + 'gl_context_egl.cc', + 'gl_context_egl.h', + 'gl_surface_egl.cc', + 'gl_surface_egl.h', + '<(gl_binding_output_dir)/gl_bindings_autogen_egl.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_egl.h', + ], + 'include_dirs': [ + '<(DEPTH)/third_party/angle/include', + ], + }], + ['use_x11 == 1', { + 'sources': [ + 'gl_context_glx.cc', + 'gl_context_glx.h', + 'gl_surface_glx.cc', + 'gl_surface_glx.h', + '<(gl_binding_output_dir)/gl_bindings_autogen_glx.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_glx.h', + ], + 'all_dependent_settings': { + 'defines': [ + 'GL_GLEXT_PROTOTYPES', + ], + }, + }], + ['OS=="win"', { + 'sources': [ + 'gl_context_wgl.cc', + 'gl_context_wgl.h', + 'gl_surface_wgl.cc', + 'gl_surface_wgl.h', + '<(gl_binding_output_dir)/gl_bindings_autogen_wgl.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_wgl.h', + ], + 'include_dirs': [ + '$(DXSDK_DIR)/include', + ], + }], + ['OS=="mac"', { + 'sources': [ + 'gl_context_cgl.cc', + 'gl_context_cgl.h', + 'gl_surface_cgl.cc', + 'gl_surface_cgl.h', + ], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/OpenGL.framework', + ], + }, + }], + ['OS=="mac" and use_aura == 1', { + 'sources': [ + 'gl_context_nsview.mm', + 'gl_context_nsview.h', + 'gl_surface_nsview.mm', + 'gl_surface_nsview.h', + ], + }], + ['OS=="android"', { + 'sources': [ + 'android_native_window.cc', + 'android_native_window.h', + ], + 'sources!': [ + '<(gl_binding_output_dir)/gl_bindings_autogen_osmesa.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_osmesa.h', + 'system_monitor_posix.cc', + ], + 'defines': [ + 'GL_GLEXT_PROTOTYPES', + 'EGL_EGLEXT_PROTOTYPES', + ], + }], + ], + }, + ], +} diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h new file mode 100644 index 0000000..625dac9 --- /dev/null +++ b/ui/gl/gl_bindings.h @@ -0,0 +1,105 @@ +// 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. + +#ifndef UI_GL_GL_BINDINGS_H_ +#define UI_GL_GL_BINDINGS_H_ +#pragma once + +// Includes the platform independent and platform dependent GL headers. +// Only include this in cc files. It pulls in system headers, including +// the X11 headers on linux, which define all kinds of macros that are +// liable to cause conflicts. + +#include <GL/gl.h> +#include <GL/glext.h> + +#include "base/logging.h" +#include "build/build_config.h" +#include "ui/gl/gl_export.h" + +// The standard OpenGL native extension headers are also included. +#if defined(OS_WIN) +#include <GL/wglext.h> +#elif defined(OS_MACOSX) +#include <OpenGL/OpenGL.h> +#elif defined(USE_X11) +#include <GL/glx.h> +#include <GL/glxext.h> + +// Undefine some macros defined by X headers. This is why this file should only +// be included in .cc files. +#undef Bool +#undef None +#undef Status +#endif + +#if defined(OS_WIN) +#define GL_BINDING_CALL WINAPI +#else +#define GL_BINDING_CALL +#endif + +#define GL_SERVICE_LOG(args) DLOG(INFO) << args; +#if defined(NDEBUG) + #define GL_SERVICE_LOG_CODE_BLOCK(code) +#else + #define GL_SERVICE_LOG_CODE_BLOCK(code) code +#endif + +// Forward declare OSMesa types. +typedef struct osmesa_context *OSMesaContext; +typedef void (*OSMESAproc)(); + +#if !defined(OS_MACOSX) + +// Forward declare EGL types. +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; +typedef int EGLint; +typedef void *EGLConfig; +typedef void *EGLContext; +typedef void *EGLDisplay; +typedef void *EGLImageKHR; +typedef void *EGLSurface; +typedef void *EGLClientBuffer; +typedef void (*__eglMustCastToProperFunctionPointerType)(void); +typedef void* GLeglImageOES; + +#if defined(OS_WIN) +typedef HDC EGLNativeDisplayType; +typedef HBITMAP EGLNativePixmapType; +typedef HWND EGLNativeWindowType; +#elif defined(OS_ANDROID) +typedef void *EGLNativeDisplayType; +typedef struct egl_native_pixmap_t *EGLNativePixmapType; +typedef struct ANativeWindow *EGLNativeWindowType; +#else +typedef Display *EGLNativeDisplayType; +typedef Pixmap EGLNativePixmapType; +typedef Window EGLNativeWindowType; +#endif + +#endif // !OS_MACOSX + +#include "gl_bindings_autogen_gl.h" +#include "gl_bindings_autogen_osmesa.h" + +#if defined(OS_WIN) +#include "gl_bindings_autogen_egl.h" +#include "gl_bindings_autogen_wgl.h" +#elif defined(USE_X11) +#include "gl_bindings_autogen_egl.h" +#include "gl_bindings_autogen_glx.h" +#elif defined(OS_ANDROID) +#include "gl_bindings_autogen_egl.h" +#endif + +namespace gfx { + +// Find an entry point to the mock GL implementation. +void* GL_BINDING_CALL GetMockGLProcAddress(const char* name); + +} // namespace gfx + +#endif // UI_GL_GL_BINDINGS_H_ diff --git a/ui/gl/gl_bindings_skia_in_process.cc b/ui/gl/gl_bindings_skia_in_process.cc new file mode 100644 index 0000000..a2f6433 --- /dev/null +++ b/ui/gl/gl_bindings_skia_in_process.cc @@ -0,0 +1,676 @@ +// 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_bindings_skia_in_process.h" + +#include "base/logging.h" +#include "third_party/skia/include/gpu/gl/GrGLInterface.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_implementation.h" + +namespace { + +extern "C" { +// The following stub functions are required because the glXXX routines exported +// via gl_bindings.h use call-type GL_BINDING_CALL, which on Windows is stdcall. +// Skia has been built such that its GrGLInterface GL pointers are __cdecl. + +GLvoid StubGLActiveTexture(GLenum texture) { + glActiveTexture(texture); +} + +GLvoid StubGLAttachShader(GLuint program, GLuint shader) { + glAttachShader(program, shader); +} + +GLvoid StubGLBeginQuery(GLenum target, GLuint id) { + glBeginQuery(target, id); +} + +GLvoid StubGLBindAttribLocation(GLuint program, GLuint index, + const char* name) { + glBindAttribLocation(program, index, name); +} + +GLvoid StubGLBindBuffer(GLenum target, GLuint buffer) { + glBindBuffer(target, buffer); +} + +GLvoid StubGLBindFragDataLocation(GLuint program, GLuint colorNumber, + const GLchar * name) { + glBindFragDataLocation(program, colorNumber, name); +} + +GLvoid StubGLBindFragDataLocationIndexed(GLuint program, GLuint colorNumber, + GLuint index, const GLchar * name) { + glBindFragDataLocationIndexed(program, colorNumber, index, name); +} + +GLvoid StubGLBindFramebuffer(GLenum target, GLuint framebuffer) { + glBindFramebufferEXT(target, framebuffer); +} + +GLvoid StubGLBindRenderbuffer(GLenum target, GLuint renderbuffer) { + glBindRenderbufferEXT(target, renderbuffer); +} + +GLvoid StubGLBindTexture(GLenum target, GLuint texture) { + glBindTexture(target, texture); +} + +GLvoid StubGLBlendColor(GLclampf red, GLclampf green, GLclampf blue, + GLclampf alpha) { + glBlendColor(red, green, blue, alpha); +} + +GLvoid StubGLBlendFunc(GLenum sfactor, GLenum dfactor) { + glBlendFunc(sfactor, dfactor); +} + +GLvoid StubGLBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) { + glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, + mask, filter); +} + +GLvoid StubGLBufferData(GLenum target, GLsizeiptr size, const void* data, + GLenum usage) { + glBufferData(target, size, data, usage); +} + +GLvoid StubGLBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, + const void* data) { + glBufferSubData(target, offset, size, data); +} + +GLenum StubGLCheckFramebufferStatus(GLenum target) { + return glCheckFramebufferStatusEXT(target); +} + +GLvoid StubGLClear(GLbitfield mask) { + glClear(mask); +} + +GLvoid StubGLClearColor(GLclampf red, GLclampf green, GLclampf blue, + GLclampf alpha) { + glClearColor(red, green, blue, alpha); +} + +GLvoid StubGLClearStencil(GLint s) { + glClearStencil(s); +} + +GLvoid StubGLColorMask(GLboolean red, GLboolean green, GLboolean blue, + GLboolean alpha) { + glColorMask(red, green, blue, alpha); +} + +GLvoid StubGLCompileShader(GLuint shader) { + glCompileShader(shader); +} + +GLvoid StubGLCompressedTexImage2D(GLenum target, GLint level, + GLenum internalformat, GLsizei width, + GLsizei height, GLint border, + GLsizei imageSize, const void* data) { + glCompressedTexImage2D(target, level, internalformat, width, height, border, + imageSize, data); +} + +GLuint StubGLCreateProgram(void) { + return glCreateProgram(); +} + +GLuint StubGLCreateShader(GLenum type) { + return glCreateShader(type); +} + +GLvoid StubGLCullFace(GLenum mode) { + glCullFace(mode); +} + +GLvoid StubGLDeleteBuffers(GLsizei n, const GLuint* buffers) { + glDeleteBuffersARB(n, buffers); +} + +GLvoid StubGLDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) { + glDeleteFramebuffersEXT(n, framebuffers); +} + +GLvoid StubGLDeleteQueries(GLsizei n, const GLuint* ids) { + glDeleteQueries(n, ids); +} + +GLvoid StubGLDeleteProgram(GLuint program) { + glDeleteProgram(program); +} + +GLvoid StubGLDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) { + glDeleteRenderbuffersEXT(n, renderbuffers); +} + +GLvoid StubGLDeleteShader(GLuint shader) { + glDeleteShader(shader); +} + +GLvoid StubGLDeleteTextures(GLsizei n, const GLuint* textures) { + glDeleteTextures(n, textures); +} + +GLvoid StubGLDepthMask(GLboolean flag) { + glDepthMask(flag); +} + +GLvoid StubGLDisable(GLenum cap) { + glDisable(cap); +} + +GLvoid StubGLDisableVertexAttribArray(GLuint index) { + glDisableVertexAttribArray(index); +} + +GLvoid StubGLDrawArrays(GLenum mode, GLint first, GLsizei count) { + glDrawArrays(mode, first, count); +} + +GLvoid StubGLDrawBuffer(GLenum mode) { + glDrawBuffer(mode); +} + +GLvoid StubGLDrawBuffers(GLsizei n, const GLenum* bufs) { + glDrawBuffersARB(n, bufs); +} + +GLvoid StubGLDrawElements(GLenum mode, GLsizei count, GLenum type, + const void* indices) { + glDrawElements(mode, count, type, indices); +} + +GLvoid StubGLEnable(GLenum cap) { + glEnable(cap); +} + +GLvoid StubGLEnableVertexAttribArray(GLuint index) { + glEnableVertexAttribArray(index); +} + +GLvoid StubGLEndQuery(GLenum target) { + glEndQuery(target); +} + +GLvoid StubGLFinish() { + glFinish(); +} + +GLvoid StubGLFlush() { + glFlush(); +} + +GLvoid StubGLFramebufferRenderbuffer(GLenum target, GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer) { + glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, + renderbuffer); +} + +GLvoid StubGLFramebufferTexture2D(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level) { + glFramebufferTexture2DEXT(target, attachment, textarget, texture, level); +} + +GLvoid StubGLFrontFace(GLenum mode) { + glFrontFace(mode); +} + +GLvoid StubGLGenBuffers(GLsizei n, GLuint* buffers) { + glGenBuffersARB(n, buffers); +} + +GLvoid StubGLGenFramebuffers(GLsizei n, GLuint* framebuffers) { + glGenFramebuffersEXT(n, framebuffers); +} + +GLvoid StubGLGenQueries(GLsizei n, GLuint* ids) { + glGenQueries(n, ids); +} + +GLvoid StubGLGenRenderbuffers(GLsizei n, GLuint* renderbuffers) { + glGenRenderbuffersEXT(n, renderbuffers); +} + +GLvoid StubGLGenTextures(GLsizei n, GLuint* textures) { + glGenTextures(n, textures); +} + +GLvoid StubGLGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) { + glGetBufferParameteriv(target, pname, params); +} + +GLvoid StubGLGetFramebufferAttachmentParameteriv(GLenum target, + GLenum attachment, + GLenum pname, GLint* params) { + glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, params); +} + +GLenum StubGLGetError() { + return glGetError(); +} + +GLvoid StubGLGetIntegerv(GLenum pname, GLint* params) { + glGetIntegerv(pname, params); +} + +GLvoid StubGLGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, + char* infolog) { + glGetProgramInfoLog(program, bufsize, length, infolog); +} + +GLvoid StubGLGetProgramiv(GLuint program, GLenum pname, GLint* params) { + glGetProgramiv(program, pname, params); +} + +GLvoid StubGLGetRenderbufferParameteriv(GLenum target, + GLenum pname, GLint* params) { + glGetRenderbufferParameterivEXT(target, pname, params); +} + +GLvoid StubGLGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, + char* infolog) { + glGetShaderInfoLog(shader, bufsize, length, infolog); +} + +GLvoid StubGLGetShaderiv(GLuint shader, GLenum pname, GLint* params) { + glGetShaderiv(shader, pname, params); +} + +const GLubyte* StubGLGetString(GLenum name) { + return glGetString(name); +} + +GLvoid StubGLGetQueryiv(GLenum target, GLenum pname, GLint* params) { + glGetQueryiv(target, pname, params); +} + +GLvoid StubGLGetQueryObjecti64v(GLuint id, GLenum pname, GLint64* params) { + glGetQueryObjecti64v(id, pname, params); +} + +GLvoid StubGLGetQueryObjectiv(GLuint id, GLenum pname, GLint* params) { + glGetQueryObjectiv(id, pname, params); +} + +GLvoid StubGLGetQueryObjectui64v(GLuint id, GLenum pname, GLuint64* params) { + glGetQueryObjectui64v(id, pname, params); +} + +GLvoid StubGLGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) { + glGetQueryObjectuiv(id, pname, params); +} + +GLvoid StubGLGetTexLevelParameteriv(GLenum target, GLint level, + GLenum pname, GLint* params) { + glGetTexLevelParameteriv(target, level, pname, params); +} + +GLint StubGLGetUniformLocation(GLuint program, const char* name) { + return glGetUniformLocation(program, name); +} + +GLvoid StubGLLineWidth(GLfloat width) { + glLineWidth(width); +} + +GLvoid StubGLLinkProgram(GLuint program) { + glLinkProgram(program); +} + +void* StubGLMapBuffer(GLenum target, GLenum access) { + return glMapBuffer(target, access); +} + +GLvoid StubGLPixelStorei(GLenum pname, GLint param) { + glPixelStorei(pname, param); +} + +GLvoid StubGLQueryCounter(GLuint id, GLenum target) { + glQueryCounter(id, target); +} + +GLvoid StubGLReadBuffer(GLenum src) { + glReadBuffer(src); +} + +GLvoid StubGLReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, void* pixels) { + glReadPixels(x, y, width, height, format, type, pixels); +} + +GLvoid StubGLRenderbufferStorage(GLenum target, GLenum internalformat, + GLsizei width, GLsizei height) { + glRenderbufferStorageEXT(target, internalformat, width, height); +} + +GLvoid StubGLRenderbufferStorageMultisample(GLenum target, GLsizei samples, + GLenum internalformat, + GLsizei width, GLsizei height) { + glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, + height); +} + +GLvoid StubGLScissor(GLint x, GLint y, GLsizei width, GLsizei height) { + glScissor(x, y, width, height); +} + +GLvoid StubGLShaderSource(GLuint shader, GLsizei count, const char** str, + const GLint* length) { + glShaderSource(shader, count, str, length); +} + +GLvoid StubGLStencilFunc(GLenum func, GLint ref, GLuint mask) { + glStencilFunc(func, ref, mask); +} + +GLvoid StubGLStencilFuncSeparate(GLenum face, GLenum func, GLint ref, + GLuint mask) { + glStencilFuncSeparate(face, func, ref, mask); +} + +GLvoid StubGLStencilMask(GLuint mask) { + glStencilMask(mask); +} + +GLvoid StubGLStencilMaskSeparate(GLenum face, GLuint mask) { + glStencilMaskSeparate(face, mask); +} + +GLvoid StubGLStencilOp(GLenum fail, GLenum zfail, GLenum zpass) { + glStencilOp(fail, zfail, zpass); +} + +GLvoid StubGLStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, + GLenum zpass) { + glStencilOpSeparate(face, fail, zfail, zpass); +} + +GLvoid StubGLTexImage2D(GLenum target, GLint level, GLint internalformat, + GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, const void* pixels) { + glTexImage2D(target, level, internalformat, width, height, border, format, + type, pixels); +} + +GLvoid StubGLTexParameteri(GLenum target, GLenum pname, GLint param) { + glTexParameteri(target, pname, param); +} + +GLvoid StubGLTexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat, + GLsizei width, GLsizei height) { + glTexStorage2DEXT(target, levels, internalFormat, width, height); +} + +GLvoid StubGLTexSubImage2D(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLenum type, const void* pixels) { + glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, + pixels); +} + +GLvoid StubGLUniform1f(GLint location, GLfloat v) { + glUniform1i(location, v); +} + +GLvoid StubGLUniform1i(GLint location, GLint v) { + glUniform1i(location, v); +} + +GLvoid StubGLUniform1fv(GLint location, GLsizei count, const GLfloat* v) { + glUniform1fv(location, count, v); +} + +GLvoid StubGLUniform1iv(GLint location, GLsizei count, const GLint* v) { + glUniform1iv(location, count, v); +} + +GLvoid StubGLUniform2f(GLint location, GLfloat v0, GLfloat v1) { + glUniform2i(location, v0, v1); +} + +GLvoid StubGLUniform2i(GLint location, GLint v0, GLint v1) { + glUniform2i(location, v0, v1); +} + +GLvoid StubGLUniform2fv(GLint location, GLsizei count, const GLfloat* v) { + glUniform2fv(location, count, v); +} + +GLvoid StubGLUniform2iv(GLint location, GLsizei count, const GLint* v) { + glUniform2iv(location, count, v); +} + +GLvoid StubGLUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { + glUniform3i(location, v0, v1, v2); +} + +GLvoid StubGLUniform3i(GLint location, GLint v0, GLint v1, GLint v2) { + glUniform3i(location, v0, v1, v2); +} + +GLvoid StubGLUniform3fv(GLint location, GLsizei count, const GLfloat* v) { + glUniform3fv(location, count, v); +} + +GLvoid StubGLUniform3iv(GLint location, GLsizei count, const GLint* v) { + glUniform3iv(location, count, v); +} + +GLvoid StubGLUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, + GLfloat v3) { + glUniform4i(location, v0, v1, v2, v3); +} + +GLvoid StubGLUniform4i(GLint location, GLint v0, GLint v1, GLint v2, + GLint v3) { + glUniform4i(location, v0, v1, v2, v3); +} + +GLvoid StubGLUniform4fv(GLint location, GLsizei count, const GLfloat* v) { + glUniform4fv(location, count, v); +} + +GLvoid StubGLUniform4iv(GLint location, GLsizei count, const GLint* v) { + glUniform4iv(location, count, v); +} + +GLvoid StubGLUniformMatrix2fv(GLint location, GLsizei count, + GLboolean transpose, const GLfloat* value) { + glUniformMatrix2fv(location, count, transpose, value); +} + +GLvoid StubGLUniformMatrix3fv(GLint location, GLsizei count, + GLboolean transpose, const GLfloat* value) { + glUniformMatrix3fv(location, count, transpose, value); +} + +GLvoid StubGLUniformMatrix4fv(GLint location, GLsizei count, + GLboolean transpose, const GLfloat* value) { + glUniformMatrix4fv(location, count, transpose, value); +} + +GLboolean StubGLUnmapBuffer(GLenum target) { + return glUnmapBuffer(target); +} + +GLvoid StubGLUseProgram(GLuint program) { + glUseProgram(program); +} + +GLvoid StubGLVertexAttrib4fv(GLuint indx, const GLfloat* values) { + glVertexAttrib4fv(indx, values); +} + +GLvoid StubGLVertexAttribPointer(GLuint indx, GLint size, GLenum type, + GLboolean normalized, GLsizei stride, + const void* ptr) { + glVertexAttribPointer(indx, size, type, normalized, stride, ptr); +} + +GLvoid StubGLViewport(GLint x, GLint y, GLsizei width, GLsizei height) { + glViewport(x, y, width, height); +} +} // extern "C" +} // namespace + +namespace gfx { + +GrGLInterface* CreateInProcessSkiaGLBinding() { + GrGLBinding binding; + switch (gfx::GetGLImplementation()) { + case gfx::kGLImplementationNone: + NOTREACHED(); + return NULL; + case gfx::kGLImplementationDesktopGL: + case gfx::kGLImplementationAppleGL: + binding = kDesktop_GrGLBinding; + break; + case gfx::kGLImplementationOSMesaGL: + binding = kDesktop_GrGLBinding; + break; + case gfx::kGLImplementationEGLGLES2: + binding = kES2_GrGLBinding; + break; + case gfx::kGLImplementationMockGL: + NOTREACHED(); + return NULL; + default: + NOTREACHED(); + return NULL; + } + + GrGLInterface* interface = new GrGLInterface; + + interface->fBindingsExported = binding; + interface->fActiveTexture = StubGLActiveTexture; + interface->fAttachShader = StubGLAttachShader; + interface->fBeginQuery = StubGLBeginQuery; + interface->fBindAttribLocation = StubGLBindAttribLocation; + interface->fBindBuffer = StubGLBindBuffer; + interface->fBindFragDataLocation = StubGLBindFragDataLocation; + interface->fBindTexture = StubGLBindTexture; + interface->fBlendColor = StubGLBlendColor; + interface->fBlendFunc = StubGLBlendFunc; + interface->fBufferData = StubGLBufferData; + interface->fBufferSubData = StubGLBufferSubData; + interface->fClear = StubGLClear; + interface->fClearColor = StubGLClearColor; + interface->fClearStencil = StubGLClearStencil; + interface->fColorMask = StubGLColorMask; + interface->fCompileShader = StubGLCompileShader; + interface->fCompressedTexImage2D = StubGLCompressedTexImage2D; + interface->fCreateProgram = StubGLCreateProgram; + interface->fCreateShader = StubGLCreateShader; + interface->fCullFace = StubGLCullFace; + interface->fDeleteBuffers = StubGLDeleteBuffers; + interface->fDeleteProgram = StubGLDeleteProgram; + interface->fDeleteQueries = StubGLDeleteQueries; + interface->fDeleteShader = StubGLDeleteShader; + interface->fDeleteTextures = StubGLDeleteTextures; + interface->fDepthMask = StubGLDepthMask; + interface->fDisable = StubGLDisable; + interface->fDisableVertexAttribArray = StubGLDisableVertexAttribArray; + interface->fDrawArrays = StubGLDrawArrays; + interface->fDrawBuffer = StubGLDrawBuffer; + interface->fDrawBuffers = StubGLDrawBuffers; + interface->fDrawElements = StubGLDrawElements; + interface->fEnable = StubGLEnable; + interface->fEnableVertexAttribArray = StubGLEnableVertexAttribArray; + interface->fEndQuery = StubGLEndQuery; + interface->fFinish = StubGLFinish; + interface->fFlush = StubGLFlush; + interface->fFrontFace = StubGLFrontFace; + interface->fGenBuffers = StubGLGenBuffers; + interface->fGenQueries = StubGLGenQueries; + interface->fGenTextures = StubGLGenTextures; + interface->fGetBufferParameteriv = StubGLGetBufferParameteriv; + interface->fGetError = StubGLGetError; + interface->fGetIntegerv = StubGLGetIntegerv; + interface->fGetQueryiv = StubGLGetQueryiv; + interface->fGetQueryObjecti64v = StubGLGetQueryObjecti64v; + interface->fGetQueryObjectiv = StubGLGetQueryObjectiv; + interface->fGetQueryObjectui64v = StubGLGetQueryObjectui64v; + interface->fGetQueryObjectuiv = StubGLGetQueryObjectuiv; + interface->fGetProgramInfoLog = StubGLGetProgramInfoLog; + interface->fGetProgramiv = StubGLGetProgramiv; + interface->fGetShaderInfoLog = StubGLGetShaderInfoLog; + interface->fGetShaderiv = StubGLGetShaderiv; + interface->fGetString = StubGLGetString; + interface->fGetTexLevelParameteriv = StubGLGetTexLevelParameteriv; + interface->fGetUniformLocation = StubGLGetUniformLocation; + interface->fLineWidth = StubGLLineWidth; + interface->fLinkProgram = StubGLLinkProgram; + interface->fPixelStorei = StubGLPixelStorei; + interface->fQueryCounter = StubGLQueryCounter; + interface->fReadBuffer = StubGLReadBuffer; + interface->fReadPixels = StubGLReadPixels; + interface->fScissor = StubGLScissor; + interface->fShaderSource = StubGLShaderSource; + interface->fStencilFunc = StubGLStencilFunc; + interface->fStencilFuncSeparate = StubGLStencilFuncSeparate; + interface->fStencilMask = StubGLStencilMask; + interface->fStencilMaskSeparate = StubGLStencilMaskSeparate; + interface->fStencilOp = StubGLStencilOp; + interface->fStencilOpSeparate = StubGLStencilOpSeparate; + interface->fTexImage2D = StubGLTexImage2D; + interface->fTexParameteri = StubGLTexParameteri; + interface->fTexSubImage2D = StubGLTexSubImage2D; + interface->fTexStorage2D = StubGLTexStorage2D; + interface->fUniform1f = StubGLUniform1f; + interface->fUniform1i = StubGLUniform1i; + interface->fUniform1fv = StubGLUniform1fv; + interface->fUniform1iv = StubGLUniform1iv; + interface->fUniform2f = StubGLUniform2f; + interface->fUniform2i = StubGLUniform2i; + interface->fUniform2fv = StubGLUniform2fv; + interface->fUniform2iv = StubGLUniform2iv; + interface->fUniform3f = StubGLUniform3f; + interface->fUniform3i = StubGLUniform3i; + interface->fUniform3fv = StubGLUniform3fv; + interface->fUniform3iv = StubGLUniform3iv; + interface->fUniform4f = StubGLUniform4f; + interface->fUniform4i = StubGLUniform4i; + interface->fUniform4fv = StubGLUniform4fv; + interface->fUniform4iv = StubGLUniform4iv; + interface->fUniformMatrix2fv = StubGLUniformMatrix2fv; + interface->fUniformMatrix3fv = StubGLUniformMatrix3fv; + interface->fUniformMatrix4fv = StubGLUniformMatrix4fv; + interface->fUseProgram = StubGLUseProgram; + interface->fVertexAttrib4fv = StubGLVertexAttrib4fv; + interface->fVertexAttribPointer = StubGLVertexAttribPointer; + interface->fViewport = StubGLViewport; + interface->fBindFramebuffer = StubGLBindFramebuffer; + interface->fBindRenderbuffer = StubGLBindRenderbuffer; + interface->fCheckFramebufferStatus = StubGLCheckFramebufferStatus; + interface->fDeleteFramebuffers = StubGLDeleteFramebuffers; + interface->fDeleteRenderbuffers = StubGLDeleteRenderbuffers; + interface->fFramebufferRenderbuffer = StubGLFramebufferRenderbuffer; + interface->fFramebufferTexture2D = StubGLFramebufferTexture2D; + interface->fGenFramebuffers = StubGLGenFramebuffers; + interface->fGenRenderbuffers = StubGLGenRenderbuffers; + interface->fGetFramebufferAttachmentParameteriv = + StubGLGetFramebufferAttachmentParameteriv; + interface->fGetRenderbufferParameteriv = StubGLGetRenderbufferParameteriv; + interface->fRenderbufferStorage = StubGLRenderbufferStorage; + interface->fRenderbufferStorageMultisample = + StubGLRenderbufferStorageMultisample; + interface->fBlitFramebuffer = StubGLBlitFramebuffer; + interface->fMapBuffer = StubGLMapBuffer; + interface->fUnmapBuffer = StubGLUnmapBuffer; + interface->fBindFragDataLocationIndexed = + StubGLBindFragDataLocationIndexed; + return interface; +} + +} // namespace gfx diff --git a/ui/gl/gl_bindings_skia_in_process.h b/ui/gl/gl_bindings_skia_in_process.h new file mode 100644 index 0000000..5bd356a --- /dev/null +++ b/ui/gl/gl_bindings_skia_in_process.h @@ -0,0 +1,21 @@ +// 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. + +#ifndef UI_GL_GL_BINDINGS_SKIA_IN_PROCESS_H_ +#define UI_GL_GL_BINDINGS_SKIA_IN_PROCESS_H_ +#pragma once + +#include "ui/gl/gl_export.h" + +struct GrGLInterface; + +namespace gfx { + +// The GPU back-end for skia requires pointers to GL functions. This function +// creates a binding for skia-gpu to the in-process GL +GL_EXPORT GrGLInterface* CreateInProcessSkiaGLBinding(); + +} // namespace gfx + +#endif // UI_GL_GL_BINDINGS_SKIA_IN_PROCESS_H_ diff --git a/ui/gl/gl_context.cc b/ui/gl/gl_context.cc new file mode 100644 index 0000000..8652e25 --- /dev/null +++ b/ui/gl/gl_context.cc @@ -0,0 +1,111 @@ +// 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 <string> + +#include "base/command_line.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/threading/thread_local.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface.h" +#include "ui/gl/gl_switches.h" + +namespace gfx { + +namespace { +base::LazyInstance<base::ThreadLocalPointer<GLContext> >::Leaky + current_context_ = LAZY_INSTANCE_INITIALIZER; +} // namespace + +GLContext::GLContext(GLShareGroup* share_group) : share_group_(share_group) { + if (!share_group_.get()) + share_group_ = new GLShareGroup; + + share_group_->AddContext(this); +} + +GLContext::~GLContext() { + share_group_->RemoveContext(this); + if (GetCurrent() == this) { + SetCurrent(NULL, NULL); + } +} + +std::string GLContext::GetExtensions() { + DCHECK(IsCurrent(NULL)); + + std::string extensions; + if (GLSurface::GetCurrent()) { + extensions = GLSurface::GetCurrent()->GetExtensions(); + } + + const char* gl_ext = reinterpret_cast<const char*>( + glGetString(GL_EXTENSIONS)); + if (gl_ext) { + extensions += (!extensions.empty() && gl_ext[0]) ? " " : ""; + extensions += gl_ext; + } + + return extensions; +} + +bool GLContext::HasExtension(const char* name) { + std::string extensions = GetExtensions(); + extensions += " "; + + std::string delimited_name(name); + delimited_name += " "; + + return extensions.find(delimited_name) != std::string::npos; +} + +GLShareGroup* GLContext::share_group() { + return share_group_.get(); +} + +bool GLContext::LosesAllContextsOnContextLost() { + switch (GetGLImplementation()) { + case kGLImplementationDesktopGL: + return false; + case kGLImplementationEGLGLES2: + return true; + case kGLImplementationOSMesaGL: + case kGLImplementationAppleGL: + return false; + case kGLImplementationMockGL: + return false; + default: + NOTREACHED(); + return true; + } +} + +GLContext* GLContext::GetCurrent() { + return current_context_.Pointer()->Get(); +} + +void GLContext::SetCurrent(GLContext* context, GLSurface* surface) { + current_context_.Pointer()->Set(context); + GLSurface::SetCurrent(surface); +} + +bool GLContext::WasAllocatedUsingARBRobustness() { + return false; +} + +bool GLContext::InitializeExtensionBindings() { + DCHECK(IsCurrent(NULL)); + static bool initialized = false; + if (initialized) + return initialized; + initialized = InitializeGLExtensionBindings(GetGLImplementation(), this); + if (!initialized) + LOG(ERROR) << "Could not initialize extension bindings."; + return initialized; +} + +} // namespace gfx diff --git a/ui/gl/gl_context.h b/ui/gl/gl_context.h new file mode 100644 index 0000000..dc76c00 --- /dev/null +++ b/ui/gl/gl_context.h @@ -0,0 +1,95 @@ +// 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. + +#ifndef UI_GL_GL_CONTEXT_H_ +#define UI_GL_GL_CONTEXT_H_ +#pragma once + +#include <string> + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "ui/gl/gl_share_group.h" +#include "ui/gl/gpu_preference.h" + +namespace gfx { + +class GLSurface; + +// Encapsulates an OpenGL context, hiding platform specific management. +class GL_EXPORT GLContext : public base::RefCounted<GLContext> { + public: + explicit GLContext(GLShareGroup* share_group); + + // Initializes the GL context to be compatible with the given surface. The GL + // context can be made with other surface's of the same type. The compatible + // surface is only needed for certain platforms like WGL, OSMesa and GLX. It + // should be specific for all platforms though. + virtual bool Initialize( + GLSurface* compatible_surface, GpuPreference gpu_preference) = 0; + + // Destroys the GL context. + virtual void Destroy() = 0; + + // Makes the GL context and a surface current on the current thread. + virtual bool MakeCurrent(GLSurface* surface) = 0; + + // Releases this GL context and surface as current on the current thread. + virtual void ReleaseCurrent(GLSurface* surface) = 0; + + // Returns true if this context and surface is current. Pass a null surface + // if the current surface is not important. + virtual bool IsCurrent(GLSurface* surface) = 0; + + // Get the underlying platform specific GL context "handle". + virtual void* GetHandle() = 0; + + // Set swap interval. This context must be current. + virtual void SetSwapInterval(int interval) = 0; + + // Returns space separated list of extensions. The context must be current. + virtual std::string GetExtensions(); + + // Returns whether the current context supports the named extension. The + // context must be current. + bool HasExtension(const char* name); + + GLShareGroup* share_group(); + + // Create a GL context that is compatible with the given surface. + // |share_group|, if non-NULL, is a group of contexts which the + // internally created OpenGL context shares textures and other resources. + static scoped_refptr<GLContext> CreateGLContext( + GLShareGroup* share_group, + GLSurface* compatible_surface, + GpuPreference gpu_preference); + + static bool LosesAllContextsOnContextLost(); + + static bool SupportsDualGpus(); + + static GLContext* GetCurrent(); + + virtual bool WasAllocatedUsingARBRobustness(); + + protected: + virtual ~GLContext(); + static void SetCurrent(GLContext* context, GLSurface* surface); + + // Initialize function pointers to extension functions in the GL + // implementation. Should be called immediately after this context is made + // current. + bool InitializeExtensionBindings(); + + private: + friend class base::RefCounted<GLContext>; + + scoped_refptr<GLShareGroup> share_group_; + + DISALLOW_COPY_AND_ASSIGN(GLContext); +}; + +} // namespace gfx + +#endif // UI_GL_GL_CONTEXT_H_ diff --git a/ui/gl/gl_context_android.cc b/ui/gl/gl_context_android.cc new file mode 100644 index 0000000..38d91e8 --- /dev/null +++ b/ui/gl/gl_context_android.cc @@ -0,0 +1,34 @@ +// 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_context.h" + +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_context_egl.h" +#include "ui/gl/gl_context_stub.h" +#include "ui/gl/gl_implementation.h" + +namespace gfx { + +// static +scoped_refptr<GLContext> GLContext::CreateGLContext( + GLShareGroup* share_group, + GLSurface* compatible_surface, + GpuPreference gpu_preference) { + if (GetGLImplementation() == kGLImplementationMockGL) + return scoped_refptr<GLContext>(new GLContextStub()); + + scoped_refptr<GLContextEGL> context(new GLContextEGL(share_group)); + if (!context->Initialize(compatible_surface, gpu_preference)) + return NULL; + return context; +} + +bool GLContext::SupportsDualGpus() { + return false; +} + +} diff --git a/ui/gl/gl_context_cgl.cc b/ui/gl/gl_context_cgl.cc new file mode 100644 index 0000000..790baad --- /dev/null +++ b/ui/gl/gl_context_cgl.cc @@ -0,0 +1,163 @@ +// 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_context_cgl.h" + +#include <OpenGL/CGLRenderers.h> +#include <vector> + +#include "base/debug/trace_event.h" +#include "base/logging.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface_cgl.h" + +namespace gfx { + +GLContextCGL::GLContextCGL(GLShareGroup* share_group) + : GLContext(share_group), + context_(NULL), + gpu_preference_(PreferIntegratedGpu) { +} + +bool GLContextCGL::Initialize(GLSurface* compatible_surface, + GpuPreference gpu_preference) { + DCHECK(compatible_surface); + + GLContextCGL* share_context = share_group() ? + static_cast<GLContextCGL*>(share_group()->GetContext()) : NULL; + if (SupportsDualGpus()) { + // Ensure the GPU preference is compatible with contexts already in the + // share group. + if (share_context && gpu_preference != share_context->GetGpuPreference()) + return false; + } + + std::vector<CGLPixelFormatAttribute> attribs; + bool using_offline_renderer = + SupportsDualGpus() && gpu_preference == PreferIntegratedGpu; + if (using_offline_renderer) { + attribs.push_back(kCGLPFAAllowOfflineRenderers); + } + if (GetGLImplementation() == kGLImplementationAppleGL) { + attribs.push_back(kCGLPFARendererID); + attribs.push_back((CGLPixelFormatAttribute) kCGLRendererGenericFloatID); + } + attribs.push_back((CGLPixelFormatAttribute) 0); + + CGLPixelFormatObj format; + GLint num_pixel_formats; + if (CGLChoosePixelFormat(&attribs.front(), + &format, + &num_pixel_formats) != kCGLNoError) { + LOG(ERROR) << "Error choosing pixel format."; + return false; + } + if (!format) { + LOG(ERROR) << "format == 0."; + return false; + } + DCHECK_NE(num_pixel_formats, 0); + + CGLError res = CGLCreateContext( + format, + share_context ? + static_cast<CGLContextObj>(share_context->GetHandle()) : NULL, + reinterpret_cast<CGLContextObj*>(&context_)); + CGLReleasePixelFormat(format); + if (res != kCGLNoError) { + LOG(ERROR) << "Error creating context."; + Destroy(); + return false; + } + + gpu_preference_ = gpu_preference; + return true; +} + +void GLContextCGL::Destroy() { + if (context_) { + CGLDestroyContext(static_cast<CGLContextObj>(context_)); + context_ = NULL; + } +} + +bool GLContextCGL::MakeCurrent(GLSurface* surface) { + DCHECK(context_); + if (IsCurrent(surface)) + return true; + + TRACE_EVENT0("gpu", "GLContextCGL::MakeCurrent"); + + if (CGLSetCurrentContext( + static_cast<CGLContextObj>(context_)) != kCGLNoError) { + LOG(ERROR) << "Unable to make gl context current."; + return false; + } + + SetCurrent(this, surface); + if (!InitializeExtensionBindings()) { + ReleaseCurrent(surface); + return false; + } + + if (!surface->OnMakeCurrent(this)) { + LOG(ERROR) << "Unable to make gl context current."; + return false; + } + + return true; +} + +void GLContextCGL::ReleaseCurrent(GLSurface* surface) { + if (!IsCurrent(surface)) + return; + + SetCurrent(NULL, NULL); + CGLSetCurrentContext(NULL); +} + +bool GLContextCGL::IsCurrent(GLSurface* surface) { + bool native_context_is_current = CGLGetCurrentContext() == context_; + + // If our context is current then our notion of which GLContext is + // current must be correct. On the other hand, third-party code + // using OpenGL might change the current context. + DCHECK(!native_context_is_current || (GetCurrent() == this)); + + if (!native_context_is_current) + return false; + + return true; +} + +void* GLContextCGL::GetHandle() { + return context_; +} + +void GLContextCGL::SetSwapInterval(int interval) { + DCHECK(IsCurrent(NULL)); + LOG(WARNING) << "GLContex: GLContextCGL::SetSwapInterval is ignored."; +} + +GLContextCGL::~GLContextCGL() { + Destroy(); +} + +GpuPreference GLContextCGL::GetGpuPreference() { + return gpu_preference_; +} + +void GLContextCGL::ForceUseOfDiscreteGPU() { + static CGLPixelFormatObj format = NULL; + if (format) + return; + CGLPixelFormatAttribute attribs[1]; + attribs[0] = static_cast<CGLPixelFormatAttribute>(0); + GLint num_pixel_formats = 0; + CGLChoosePixelFormat(attribs, &format, &num_pixel_formats); + // format is deliberately leaked. +} + +} // namespace gfx diff --git a/ui/gl/gl_context_cgl.h b/ui/gl/gl_context_cgl.h new file mode 100644 index 0000000..0331568 --- /dev/null +++ b/ui/gl/gl_context_cgl.h @@ -0,0 +1,51 @@ +// 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. + +#ifndef UI_GL_GL_CONTEXT_CGL_H_ +#define UI_GL_GL_CONTEXT_CGL_H_ +#pragma once + +#include "ui/gl/gl_context.h" + +namespace gfx { + +class GLSurface; + +// Encapsulates a CGL OpenGL context. +class GLContextCGL : public GLContext { + public: + explicit GLContextCGL(GLShareGroup* share_group); + + // Implement GLContext. + virtual bool Initialize(GLSurface* compatible_surface, + GpuPreference gpu_preference) OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool MakeCurrent(GLSurface* surface) OVERRIDE; + virtual void ReleaseCurrent(GLSurface* surface) OVERRIDE; + virtual bool IsCurrent(GLSurface* surface) OVERRIDE; + virtual void* GetHandle() OVERRIDE; + virtual void SetSwapInterval(int interval) OVERRIDE; + + protected: + virtual ~GLContextCGL(); + + private: + // Expose ForceUseOfDiscreteGPU only to GLContext implementation. + friend class GLContext; + + GpuPreference GetGpuPreference(); + + // Helper for dual-GPU support on systems where this is necessary + // for stability reasons. + static void ForceUseOfDiscreteGPU(); + + void* context_; + GpuPreference gpu_preference_; + + DISALLOW_COPY_AND_ASSIGN(GLContextCGL); +}; + +} // namespace gfx + +#endif // UI_GL_GL_CONTEXT_CGL_H_ diff --git a/ui/gl/gl_context_egl.cc b/ui/gl/gl_context_egl.cc new file mode 100644 index 0000000..fa655a0 --- /dev/null +++ b/ui/gl/gl_context_egl.cc @@ -0,0 +1,160 @@ +// 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_context_egl.h" + +#include "base/debug/trace_event.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "build/build_config.h" +#include "third_party/angle/include/EGL/egl.h" +#include "ui/gl/egl_util.h" +#include "ui/gl/gl_surface.h" + +// This header must come after the above third-party include, as +// it brings in #defines that cause conflicts. +#include "ui/gl/gl_bindings.h" + +#if defined(USE_X11) +extern "C" { +#include <X11/Xlib.h> +} +#endif + +namespace gfx { + +std::string GLContextEGL::GetExtensions() { + const char* extensions = eglQueryString(display_, + EGL_EXTENSIONS); + if (!extensions) + return GLContext::GetExtensions(); + + return GLContext::GetExtensions() + " " + extensions; +} + +GLContextEGL::GLContextEGL(GLShareGroup* share_group) + : GLContext(share_group), + context_(NULL), + display_(NULL), + config_(NULL) { +} + +GLContextEGL::~GLContextEGL() { + Destroy(); +} + +bool GLContextEGL::Initialize( + GLSurface* compatible_surface, GpuPreference gpu_preference) { + DCHECK(compatible_surface); + DCHECK(!context_); + + static const EGLint kContextAttributes[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + display_ = compatible_surface->GetDisplay(); + config_ = compatible_surface->GetConfig(); + + context_ = eglCreateContext( + display_, + config_, + share_group() ? share_group()->GetHandle() : NULL, + kContextAttributes); + if (!context_) { + LOG(ERROR) << "eglCreateContext failed with error " + << GetLastEGLErrorString(); + Destroy(); + return false; + } + + return true; +} + +void GLContextEGL::Destroy() { + if (context_) { + if (!eglDestroyContext(display_, context_)) { + LOG(ERROR) << "eglDestroyContext failed with error " + << GetLastEGLErrorString(); + } + + context_ = NULL; + } +} + +bool GLContextEGL::MakeCurrent(GLSurface* surface) { + DCHECK(context_); + if (IsCurrent(surface)) + return true; + + TRACE_EVENT0("gpu", "GLContextEGL::MakeCurrent"); + + if (!eglMakeCurrent(display_, + surface->GetHandle(), + surface->GetHandle(), + context_)) { + DVLOG(1) << "eglMakeCurrent failed with error " + << GetLastEGLErrorString(); + return false; + } + + SetCurrent(this, surface); + if (!InitializeExtensionBindings()) { + ReleaseCurrent(surface); + return false; + } + + if (!surface->OnMakeCurrent(this)) { + LOG(ERROR) << "Could not make current."; + return false; + } + + return true; +} + +void GLContextEGL::ReleaseCurrent(GLSurface* surface) { + if (!IsCurrent(surface)) + return; + + SetCurrent(NULL, NULL); + eglMakeCurrent(display_, + EGL_NO_SURFACE, + EGL_NO_SURFACE, + EGL_NO_CONTEXT); +} + +bool GLContextEGL::IsCurrent(GLSurface* surface) { + DCHECK(context_); + + bool native_context_is_current = context_ == eglGetCurrentContext(); + + // If our context is current then our notion of which GLContext is + // current must be correct. On the other hand, third-party code + // using OpenGL might change the current context. + DCHECK(!native_context_is_current || (GetCurrent() == this)); + + if (!native_context_is_current) + return false; + + if (surface) { + if (surface->GetHandle() != eglGetCurrentSurface(EGL_DRAW)) + return false; + } + + return true; +} + +void* GLContextEGL::GetHandle() { + return context_; +} + +void GLContextEGL::SetSwapInterval(int interval) { + DCHECK(IsCurrent(NULL)); + if (!eglSwapInterval(display_, interval)) { + LOG(ERROR) << "eglSwapInterval failed with error " + << GetLastEGLErrorString(); + } +} + +} // namespace gfx diff --git a/ui/gl/gl_context_egl.h b/ui/gl/gl_context_egl.h new file mode 100644 index 0000000..4e98da8 --- /dev/null +++ b/ui/gl/gl_context_egl.h @@ -0,0 +1,49 @@ +// 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. + +#ifndef UI_GL_GL_CONTEXT_EGL_H_ +#define UI_GL_GL_CONTEXT_EGL_H_ +#pragma once + +#include <string> + +#include "base/compiler_specific.h" +#include "ui/gl/gl_context.h" + +typedef void* EGLContext; +typedef void* EGLDisplay; +typedef void* EGLConfig; + +namespace gfx { + +class GLSurface; + +// Encapsulates an EGL OpenGL ES context. +class GLContextEGL : public GLContext { + public: + explicit GLContextEGL(GLShareGroup* share_group); + virtual ~GLContextEGL(); + + // Implement GLContext. + virtual bool Initialize( + GLSurface* compatible_surface, GpuPreference gpu_preference) OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool MakeCurrent(GLSurface* surface) OVERRIDE; + virtual void ReleaseCurrent(GLSurface* surface) OVERRIDE; + virtual bool IsCurrent(GLSurface* surface) OVERRIDE; + virtual void* GetHandle() OVERRIDE; + virtual void SetSwapInterval(int interval) OVERRIDE; + virtual std::string GetExtensions() OVERRIDE; + + private: + EGLContext context_; + EGLDisplay display_; + EGLConfig config_; + + DISALLOW_COPY_AND_ASSIGN(GLContextEGL); +}; + +} // namespace gfx + +#endif // UI_GL_GL_CONTEXT_EGL_H_ diff --git a/ui/gl/gl_context_glx.cc b/ui/gl/gl_context_glx.cc new file mode 100644 index 0000000..af94040 --- /dev/null +++ b/ui/gl/gl_context_glx.cc @@ -0,0 +1,253 @@ +// 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. + +extern "C" { +#include <X11/Xlib.h> +} + +#include "ui/gl/gl_context_glx.h" + +#include "base/debug/trace_event.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/mesa/MesaLib/include/GL/osmesa.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface_glx.h" + +namespace gfx { + +namespace { + +// scoped_ptr functor for XFree(). Use as follows: +// scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...); +// where "XVisualInfo" is any X type that is freed with XFree. +class ScopedPtrXFree { + public: + void operator()(void* x) const { + ::XFree(x); + } +}; + +} // namespace anonymous + +GLContextGLX::GLContextGLX(GLShareGroup* share_group) + : GLContext(share_group), + context_(NULL), + display_(NULL) { +} + +GLContextGLX::~GLContextGLX() { + Destroy(); +} + +Display* GLContextGLX::display() { + return display_; +} + +bool GLContextGLX::Initialize( + GLSurface* compatible_surface, GpuPreference gpu_preference) { + display_ = static_cast<Display*>(compatible_surface->GetDisplay()); + + GLXContext share_handle = static_cast<GLXContext>( + share_group() ? share_group()->GetHandle() : NULL); + + if (GLSurfaceGLX::IsCreateContextRobustnessSupported()) { + DLOG(INFO) << "GLX_ARB_create_context_robustness supported."; + + std::vector<int> attribs; + attribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); + attribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB); + attribs.push_back(0); + context_ = glXCreateContextAttribsARB( + display_, + static_cast<GLXFBConfig>(compatible_surface->GetConfig()), + share_handle, + True, + &attribs.front()); + if (context_) { + DLOG(INFO) << " Successfully allocated " + << (compatible_surface->IsOffscreen() ? + "offscreen" : "onscreen") + << " GL context with LOSE_CONTEXT_ON_RESET_ARB"; + } else { + // TODO(kbr): it is not expected that things will work properly + // in this case, since we will likely allocate our offscreen + // contexts with this bit set and the onscreen contexts without, + // and won't be able to put them in the same share group. + // Consider what to do here; force loss of all contexts and + // reallocation without ARB_robustness? + LOG(ERROR) << + " FAILED to allocate GL context with LOSE_CONTEXT_ON_RESET_ARB"; + } + } + + if (!context_) { + // The means by which the context is created depends on whether + // the drawable type works reliably with GLX 1.3. If it does not + // then fall back to GLX 1.2. + if (compatible_surface->IsOffscreen()) { + context_ = glXCreateNewContext( + display_, + static_cast<GLXFBConfig>(compatible_surface->GetConfig()), + GLX_RGBA_TYPE, + share_handle, + True); + } else { + // Get the visuals for the X drawable. + XWindowAttributes attributes; + if (!XGetWindowAttributes( + display_, + reinterpret_cast<GLXDrawable>(compatible_surface->GetHandle()), + &attributes)) { + LOG(ERROR) << "XGetWindowAttributes failed for window " << + reinterpret_cast<GLXDrawable>( + compatible_surface->GetHandle()) << "."; + return false; + } + + XVisualInfo visual_info_template; + visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); + + int visual_info_count = 0; + scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list( + XGetVisualInfo(display_, VisualIDMask, + &visual_info_template, + &visual_info_count)); + + DCHECK(visual_info_list.get()); + if (visual_info_count == 0) { + LOG(ERROR) << "No visual info for visual ID."; + return false; + } + + // Attempt to create a context with each visual in turn until one works. + context_ = glXCreateContext( + display_, + visual_info_list.get(), + share_handle, + True); + } + } + + if (!context_) { + LOG(ERROR) << "Couldn't create GL context."; + return false; + } + + DLOG(INFO) << (compatible_surface->IsOffscreen() ? "Offscreen" : "Onscreen") + << " context was " + << (glXIsDirect(display_, + static_cast<GLXContext>(context_)) + ? "direct" : "indirect") + << "."; + + return true; +} + +void GLContextGLX::Destroy() { + if (context_) { + glXDestroyContext(display_, + static_cast<GLXContext>(context_)); + context_ = NULL; + } +} + +bool GLContextGLX::MakeCurrent(GLSurface* surface) { + DCHECK(context_); + if (IsCurrent(surface)) + return true; + + TRACE_EVENT0("gpu", "GLContextGLX::MakeCurrent"); + if (!glXMakeCurrent( + display_, + reinterpret_cast<GLXDrawable>(surface->GetHandle()), + static_cast<GLXContext>(context_))) { + LOG(ERROR) << "Couldn't make context current with X drawable."; + Destroy(); + return false; + } + + SetCurrent(this, surface); + if (!InitializeExtensionBindings()) { + ReleaseCurrent(surface); + Destroy(); + return false; + } + + if (!surface->OnMakeCurrent(this)) { + LOG(ERROR) << "Could not make current."; + ReleaseCurrent(surface); + Destroy(); + return false; + } + + return true; +} + +void GLContextGLX::ReleaseCurrent(GLSurface* surface) { + if (!IsCurrent(surface)) + return; + + SetCurrent(NULL, NULL); + if (!glXMakeCurrent(display_, 0, 0)) + LOG(ERROR) << "glXMakeCurrent failed in ReleaseCurrent"; +} + +bool GLContextGLX::IsCurrent(GLSurface* surface) { + bool native_context_is_current = + glXGetCurrentContext() == static_cast<GLXContext>(context_); + + // If our context is current then our notion of which GLContext is + // current must be correct. On the other hand, third-party code + // using OpenGL might change the current context. + DCHECK(!native_context_is_current || (GetCurrent() == this)); + + if (!native_context_is_current) + return false; + + if (surface) { + if (glXGetCurrentDrawable() != + reinterpret_cast<GLXDrawable>(surface->GetHandle())) { + return false; + } + } + + return true; +} + +void* GLContextGLX::GetHandle() { + return context_; +} + +void GLContextGLX::SetSwapInterval(int interval) { + DCHECK(IsCurrent(NULL)); + if (HasExtension("GLX_EXT_swap_control") && glXSwapIntervalEXT) { + glXSwapIntervalEXT( + display_, + glXGetCurrentDrawable(), + interval); + } else { + if(interval == 0) + LOG(WARNING) << + "Could not disable vsync: driver does not " + "support GLX_EXT_swap_control"; + } +} + +std::string GLContextGLX::GetExtensions() { + DCHECK(IsCurrent(NULL)); + const char* extensions = GLSurfaceGLX::GetGLXExtensions(); + if (extensions) { + return GLContext::GetExtensions() + " " + extensions; + } + + return GLContext::GetExtensions(); +} + +bool GLContextGLX::WasAllocatedUsingARBRobustness() { + return GLSurfaceGLX::IsCreateContextRobustnessSupported(); +} + +} // namespace gfx diff --git a/ui/gl/gl_context_glx.h b/ui/gl/gl_context_glx.h new file mode 100644 index 0000000..60155df --- /dev/null +++ b/ui/gl/gl_context_glx.h @@ -0,0 +1,48 @@ +// 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. + +#ifndef UI_GL_GL_CONTEXT_GLX_H_ +#define UI_GL_GL_CONTEXT_GLX_H_ +#pragma once + +#include <string> + +#include "base/compiler_specific.h" +#include "ui/base/x/x11_util.h" +#include "ui/gl/gl_context.h" + +namespace gfx { + +class GLSurface; + +// Encapsulates a GLX OpenGL context. +class GLContextGLX : public GLContext { + public: + explicit GLContextGLX(GLShareGroup* share_group); + virtual ~GLContextGLX(); + + Display* display(); + + // Implement GLContext. + virtual bool Initialize( + GLSurface* compatible_surface, GpuPreference gpu_preference) OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool MakeCurrent(GLSurface* surface) OVERRIDE; + virtual void ReleaseCurrent(GLSurface* surface) OVERRIDE; + virtual bool IsCurrent(GLSurface* surface) OVERRIDE; + virtual void* GetHandle() OVERRIDE; + virtual void SetSwapInterval(int interval) OVERRIDE; + virtual std::string GetExtensions() OVERRIDE; + virtual bool WasAllocatedUsingARBRobustness() OVERRIDE; + + private: + void* context_; + Display* display_; + + DISALLOW_COPY_AND_ASSIGN(GLContextGLX); +}; + +} // namespace gfx + +#endif // UI_GL_GL_CONTEXT_GLX_H_ diff --git a/ui/gl/gl_context_linux.cc b/ui/gl/gl_context_linux.cc new file mode 100644 index 0000000..2b5d16f --- /dev/null +++ b/ui/gl/gl_context_linux.cc @@ -0,0 +1,63 @@ +// 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_context.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/mesa/MesaLib/include/GL/osmesa.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_context_egl.h" +#include "ui/gl/gl_context_glx.h" +#include "ui/gl/gl_context_osmesa.h" +#include "ui/gl/gl_context_stub.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface_egl.h" +#include "ui/gl/gl_surface_glx.h" +#include "ui/gl/gl_surface_osmesa.h" +#include "ui/gl/gl_surface_stub.h" + +namespace gfx { + +class GLShareGroup; + +scoped_refptr<GLContext> GLContext::CreateGLContext( + GLShareGroup* share_group, + GLSurface* compatible_surface, + GpuPreference gpu_preference) { + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_refptr<GLContext> context(new GLContextOSMesa(share_group)); + if (!context->Initialize(compatible_surface, gpu_preference)) + return NULL; + + return context; + } + case kGLImplementationDesktopGL: { + scoped_refptr<GLContext> context(new GLContextGLX(share_group)); + if (!context->Initialize(compatible_surface, gpu_preference)) + return NULL; + + return context; + } + case kGLImplementationEGLGLES2: { + scoped_refptr<GLContext> context(new GLContextEGL(share_group)); + if (!context->Initialize(compatible_surface, gpu_preference)) + return NULL; + + return context; + } + case kGLImplementationMockGL: + return new GLContextStub; + default: + NOTREACHED(); + return NULL; + } +} + +bool GLContext::SupportsDualGpus() { + return false; +} + +} // namespace gfx diff --git a/ui/gl/gl_context_mac.mm b/ui/gl/gl_context_mac.mm new file mode 100644 index 0000000..06829be --- /dev/null +++ b/ui/gl/gl_context_mac.mm @@ -0,0 +1,184 @@ +// 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 "base/basictypes.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "base/mac/mac_util.h" +#include "base/memory/scoped_generic_obj.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/mesa/MesaLib/include/GL/osmesa.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_context_cgl.h" +#include "ui/gl/gl_context_osmesa.h" +#include "ui/gl/gl_context_stub.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface.h" +#include "ui/gl/gl_switches.h" + +#if defined(USE_AURA) +#include "ui/gl/gl_context_nsview.h" +#endif + +namespace { + +// ScopedGenericObj functor for CGLDestroyRendererInfo(). +class ScopedDestroyRendererInfo { + public: + void operator()(CGLRendererInfoObj x) const { + CGLDestroyRendererInfo(x); + } +}; + +} // namespace + +namespace gfx { + +class GLShareGroup; + +scoped_refptr<GLContext> GLContext::CreateGLContext( + GLShareGroup* share_group, + GLSurface* compatible_surface, + GpuPreference gpu_preference) { + switch (GetGLImplementation()) { + case kGLImplementationDesktopGL: + case kGLImplementationAppleGL: { + scoped_refptr<GLContext> context; +#if defined(USE_AURA) + if (compatible_surface->IsOffscreen()) + context = new GLContextCGL(share_group); + else + context = new GLContextNSView(share_group); +#else + context = new GLContextCGL(share_group); +#endif // USE_AURA + if (!context->Initialize(compatible_surface, gpu_preference)) + return NULL; + + return context; + } + case kGLImplementationOSMesaGL: { + scoped_refptr<GLContext> context(new GLContextOSMesa(share_group)); + if (!context->Initialize(compatible_surface, gpu_preference)) + return NULL; + + return context; + } + case kGLImplementationMockGL: + return new GLContextStub; + default: + NOTREACHED(); + return NULL; + } +} + +bool GLContext::SupportsDualGpus() { + // We need to know the GL implementation in order to correctly + // answer whether dual GPUs are supported. This introduces an + // initialization cycle with GLSurface::InitializeOneOff() which we + // need to break. + static bool initialized = false; + static bool initializing = false; + static bool supports_dual_gpus = false; + + if (initialized) { + return supports_dual_gpus; + } else { + if (!initializing) { + initializing = true; + if (!GLSurface::InitializeOneOff()) { + return false; + } + } + initialized = true; + } + + if (!base::mac::IsOSLionOrLater()) { + return false; + } + + if (GetGLImplementation() != kGLImplementationDesktopGL) { + return false; + } + + // Enumerate all hardware-accelerated renderers. If we find one + // online and one offline, assume we're on a dual-GPU system. + GLuint display_mask = static_cast<GLuint>(-1); + CGLRendererInfoObj renderer_info = NULL; + GLint num_renderers = 0; + + bool found_online = false; + bool found_offline = false; + + if (CGLQueryRendererInfo(display_mask, + &renderer_info, + &num_renderers) != kCGLNoError) { + return false; + } + + ScopedGenericObj<CGLRendererInfoObj, ScopedDestroyRendererInfo> + scoper(renderer_info); + + for (GLint i = 0; i < num_renderers; ++i) { + GLint accelerated = 0; + if (CGLDescribeRenderer(renderer_info, + i, + kCGLRPAccelerated, + &accelerated) != kCGLNoError) { + return false; + } + + if (!accelerated) + continue; + + GLint online = 0; + if (CGLDescribeRenderer(renderer_info, + i, + kCGLRPOnline, + &online) != kCGLNoError) { + return false; + } + + if (online) { + found_online = true; + } else { + found_offline = true; + } + } + + if (found_online && found_offline) { + // Only switch GPUs dynamically on recent MacBook Pro models. + // Otherwise, keep the system on the discrete GPU for the lifetime + // of the browser process, since switching back and forth causes + // system stability issues. http://crbug.com/113703 + std::string model; + int32 model_major, model_minor; + if (!base::mac::ParseModelIdentifier(base::mac::GetModelIdentifier(), + &model, &model_major, &model_minor)) { + return false; + } + + const int kMacBookProFirstDualAMDIntelGPUModel = 8; + + bool forcibly_disable = + ((model == "MacBookPro") && + (model_major < kMacBookProFirstDualAMDIntelGPUModel)) || + CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableGpuSwitching) || + // http://crbug.com/127713 : disable dynamic GPU switching on + // 10.8 until system stability issues are resolved by Apple. + base::mac::IsOSMountainLion(); + + if (forcibly_disable) { + GLContextCGL::ForceUseOfDiscreteGPU(); + return false; + } + + supports_dual_gpus = true; + } + + return supports_dual_gpus; +} + +} // namespace gfx diff --git a/ui/gl/gl_context_nsview.h b/ui/gl/gl_context_nsview.h new file mode 100644 index 0000000..3c54157f --- /dev/null +++ b/ui/gl/gl_context_nsview.h @@ -0,0 +1,48 @@ +// 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. + +#ifndef UI_GL_GL_CONTEXT_NSVIEW_H_ +#define UI_GL_GL_CONTEXT_NSVIEW_H_ +#pragma once + +#import <AppKit/NSOpenGL.h> + +#include "base/compiler_specific.h" +#include "base/memory/scoped_nsobject.h" +#include "ui/gl/gl_context.h" + +namespace gfx { + +class GLSurface; + +// GLContextNSView encapsulates an NSView-based GLContext. This is paired with +// the GLSurfaceNSView class. +class GLContextNSView : public GLContext { + public: + explicit GLContextNSView(GLShareGroup* group); + virtual ~GLContextNSView(); + + // GLContext: + virtual bool Initialize(GLSurface* surface, + GpuPreference gpu_preference) OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool MakeCurrent(GLSurface* surface) OVERRIDE; + virtual void ReleaseCurrent(GLSurface* surface) OVERRIDE; + virtual bool IsCurrent(GLSurface* surface) OVERRIDE; + virtual void* GetHandle() OVERRIDE; + virtual void SetSwapInterval(int interval) OVERRIDE; + + // Flush the |context_|. Swaps buffers. + void FlushBuffer(); + + private: + scoped_nsobject<NSOpenGLContext> context_; + GpuPreference gpu_preference_; + + DISALLOW_COPY_AND_ASSIGN(GLContextNSView); +}; + +} // namespace gfx + +#endif // UI_GL_GL_CONTEXT_NSVIEW_H_ diff --git a/ui/gl/gl_context_nsview.mm b/ui/gl/gl_context_nsview.mm new file mode 100644 index 0000000..898bf01 --- /dev/null +++ b/ui/gl/gl_context_nsview.mm @@ -0,0 +1,99 @@ +// 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_context_nsview.h" + +#include <vector> + +#import <AppKit/NSOpenGL.h> +#import <AppKit/NSView.h> + +#include "base/debug/trace_event.h" +#include "base/logging.h" +#include "ui/gl/gl_surface_nsview.h" + +namespace gfx { + +GLContextNSView::GLContextNSView(GLShareGroup* group) + : GLContext(group) { +} + +GLContextNSView::~GLContextNSView() { +} + +bool GLContextNSView::Initialize(GLSurface* surface, + GpuPreference gpu_preference) { + DCHECK(!context_) << "NSGLContext was previously initialized."; + gpu_preference_ = gpu_preference; + + std::vector<NSOpenGLPixelFormatAttribute> attributes; + attributes.push_back(NSOpenGLPFAAccelerated); + attributes.push_back(NSOpenGLPFADoubleBuffer); + attributes.push_back(0); + + scoped_nsobject<NSOpenGLPixelFormat> pixel_format; + pixel_format.reset([[NSOpenGLPixelFormat alloc] + initWithAttributes:&attributes.front()]); + if (!pixel_format) { + LOG(ERROR) << "NSOpenGLPixelFormat initWithAttributes failed."; + return false; + } + + context_.reset([[NSOpenGLContext alloc] initWithFormat:pixel_format + shareContext:nil]); + if (!context_) { + LOG(ERROR) << "NSOpenGLContext initWithFormat failed"; + return false; + } + + return true; +} + +void GLContextNSView::Destroy() { + context_.reset(nil); +} + +bool GLContextNSView::MakeCurrent(GLSurface* surface) { + TRACE_EVENT0("gpu", "GLContextNSView::MakeCurrent"); + AcceleratedWidget view = + static_cast<AcceleratedWidget>(surface->GetHandle()); + // Only set the context's view if the view is parented. + // I.e. it is a valid drawable. + if ([view window]) + [context_ setView:view]; + [context_ makeCurrentContext]; + + SetCurrent(this, surface); + + if (!surface->OnMakeCurrent(this)) { + LOG(ERROR) << "Unable to make gl context current."; + return false; + } + + return true; +} + +void GLContextNSView::ReleaseCurrent(GLSurface* surface) { + [NSOpenGLContext clearCurrentContext]; +} + +bool GLContextNSView::IsCurrent(GLSurface* surface) { + return context_ == [NSOpenGLContext currentContext]; +} + +void* GLContextNSView::GetHandle() { + return context_; +} + +void GLContextNSView::SetSwapInterval(int interval) { + DCHECK(interval == 0 || interval == 1); + GLint swap = interval; + [context_ setValues:&swap forParameter:NSOpenGLCPSwapInterval]; +} + +void GLContextNSView::FlushBuffer() { + [context_ flushBuffer]; +} + +} // namespace gfx diff --git a/ui/gl/gl_context_osmesa.cc b/ui/gl/gl_context_osmesa.cc new file mode 100644 index 0000000..1787ef9 --- /dev/null +++ b/ui/gl/gl_context_osmesa.cc @@ -0,0 +1,130 @@ +// 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_context_osmesa.h" + +#include <GL/osmesa.h> + +#include "base/logging.h" +#include "ui/gfx/size.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_surface.h" + +namespace gfx { + +GLContextOSMesa::GLContextOSMesa(GLShareGroup* share_group) + : GLContext(share_group), + context_(NULL) { +} + +bool GLContextOSMesa::Initialize(GLSurface* compatible_surface, + GpuPreference gpu_preference) { + DCHECK(!context_); + + OSMesaContext share_handle = static_cast<OSMesaContext>( + share_group() ? share_group()->GetHandle() : NULL); + + GLuint format = compatible_surface->GetFormat(); + DCHECK_NE(format, (unsigned)0); + context_ = OSMesaCreateContextExt(format, + 0, // depth bits + 0, // stencil bits + 0, // accum bits + share_handle); + if (!context_) { + LOG(ERROR) << "OSMesaCreateContextExt failed."; + return false; + } + + return true; +} + +void GLContextOSMesa::Destroy() { + if (context_) { + OSMesaDestroyContext(static_cast<OSMesaContext>(context_)); + context_ = NULL; + } +} + +bool GLContextOSMesa::MakeCurrent(GLSurface* surface) { + DCHECK(context_); + + gfx::Size size = surface->GetSize(); + + if (!OSMesaMakeCurrent(context_, + surface->GetHandle(), + GL_UNSIGNED_BYTE, + size.width(), + size.height())) { + LOG(ERROR) << "OSMesaMakeCurrent failed."; + Destroy(); + return false; + } + + // Row 0 is at the top. + OSMesaPixelStore(OSMESA_Y_UP, 0); + + SetCurrent(this, surface); + if (!InitializeExtensionBindings()) { + ReleaseCurrent(surface); + return false; + } + + if (!surface->OnMakeCurrent(this)) { + LOG(ERROR) << "Could not make current."; + return false; + } + + return true; +} + +void GLContextOSMesa::ReleaseCurrent(GLSurface* surface) { + if (!IsCurrent(surface)) + return; + + SetCurrent(NULL, NULL); + OSMesaMakeCurrent(NULL, NULL, GL_UNSIGNED_BYTE, 0, 0); +} + +bool GLContextOSMesa::IsCurrent(GLSurface* surface) { + DCHECK(context_); + + bool native_context_is_current = + context_ == OSMesaGetCurrentContext(); + + // If our context is current then our notion of which GLContext is + // current must be correct. On the other hand, third-party code + // using OpenGL might change the current context. + DCHECK(!native_context_is_current || (GetCurrent() == this)); + + if (!native_context_is_current) + return false; + + if (surface) { + GLint width; + GLint height; + GLint format; + void* buffer = NULL; + OSMesaGetColorBuffer(context_, &width, &height, &format, &buffer); + if (buffer != surface->GetHandle()) + return false; + } + + return true; +} + +void* GLContextOSMesa::GetHandle() { + return context_; +} + +void GLContextOSMesa::SetSwapInterval(int interval) { + DCHECK(IsCurrent(NULL)); + LOG(WARNING) << "GLContextOSMesa::SetSwapInterval is ignored."; +} + +GLContextOSMesa::~GLContextOSMesa() { + Destroy(); +} + +} // namespace gfx diff --git a/ui/gl/gl_context_osmesa.h b/ui/gl/gl_context_osmesa.h new file mode 100644 index 0000000..cef3fd9 --- /dev/null +++ b/ui/gl/gl_context_osmesa.h @@ -0,0 +1,46 @@ +// 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. + +#ifndef UI_GL_GL_CONTEXT_OSMESA_H_ +#define UI_GL_GL_CONTEXT_OSMESA_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ui/gl/gl_context.h" + +typedef struct osmesa_context* OSMesaContext; + +namespace gfx { + +class GLShareGroup; +class GLSurface; + +// Encapsulates an OSMesa OpenGL context that uses software rendering. +class GLContextOSMesa : public GLContext { + public: + explicit GLContextOSMesa(GLShareGroup* share_group); + + // Implement GLContext. + virtual bool Initialize(GLSurface* compatible_surface, + GpuPreference gpu_preference) OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool MakeCurrent(GLSurface* surface) OVERRIDE; + virtual void ReleaseCurrent(GLSurface* surface) OVERRIDE; + virtual bool IsCurrent(GLSurface* surface) OVERRIDE; + virtual void* GetHandle() OVERRIDE; + virtual void SetSwapInterval(int interval) OVERRIDE; + + protected: + virtual ~GLContextOSMesa(); + + private: + OSMesaContext context_; + + DISALLOW_COPY_AND_ASSIGN(GLContextOSMesa); +}; + +} // namespace gfx + +#endif // UI_GL_GL_CONTEXT_OSMESA_H_ diff --git a/ui/gl/gl_context_stub.cc b/ui/gl/gl_context_stub.cc new file mode 100644 index 0000000..d1364c4 --- /dev/null +++ b/ui/gl/gl_context_stub.cc @@ -0,0 +1,43 @@ +// 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_context_stub.h" + +namespace gfx { + +GLContextStub::GLContextStub() : GLContext(NULL) {} + +bool GLContextStub::Initialize( + GLSurface* compatible_surface, GpuPreference gpu_preference) { + return true; +} + +void GLContextStub::Destroy() {} + +bool GLContextStub::MakeCurrent(GLSurface* surface) { + SetCurrent(this, surface); + return true; +} + +void GLContextStub::ReleaseCurrent(GLSurface* surface) { +} + +bool GLContextStub::IsCurrent(GLSurface* surface) { + return true; +} + +void* GLContextStub::GetHandle() { + return NULL; +} + +void GLContextStub::SetSwapInterval(int interval) { +} + +std::string GLContextStub::GetExtensions() { + return std::string(); +} + +GLContextStub::~GLContextStub() {} + +} // namespace gfx diff --git a/ui/gl/gl_context_stub.h b/ui/gl/gl_context_stub.h new file mode 100644 index 0000000..a602f4b --- /dev/null +++ b/ui/gl/gl_context_stub.h @@ -0,0 +1,38 @@ +// 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. + +#ifndef UI_GL_GL_CONTEXT_STUB_H_ +#define UI_GL_GL_CONTEXT_STUB_H_ +#pragma once + +#include "ui/gl/gl_context.h" + +namespace gfx { + +// A GLContext that does nothing for unit tests. +class GL_EXPORT GLContextStub : public GLContext { + public: + GLContextStub(); + + // Implement GLContext. + virtual bool Initialize(GLSurface* compatible_surface, + GpuPreference gpu_preference) OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool MakeCurrent(GLSurface* surface) OVERRIDE; + virtual void ReleaseCurrent(GLSurface* surface) OVERRIDE; + virtual bool IsCurrent(GLSurface* surface) OVERRIDE; + virtual void* GetHandle() OVERRIDE; + virtual void SetSwapInterval(int interval) OVERRIDE; + virtual std::string GetExtensions() OVERRIDE; + + protected: + virtual ~GLContextStub(); + + private: + DISALLOW_COPY_AND_ASSIGN(GLContextStub); +}; + +} // namespace gfx + +#endif // UI_GL_GL_CONTEXT_STUB_H_ diff --git a/ui/gl/gl_context_wgl.cc b/ui/gl/gl_context_wgl.cc new file mode 100644 index 0000000..e6b8307 --- /dev/null +++ b/ui/gl/gl_context_wgl.cc @@ -0,0 +1,141 @@ +// 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. + +// This file implements the GLContextWGL and PbufferGLContext classes. + +#include "ui/gl/gl_context_wgl.h" + +#include "base/debug/trace_event.h" +#include "base/logging.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface_wgl.h" + +namespace gfx { + +GLContextWGL::GLContextWGL(GLShareGroup* share_group) + : GLContext(share_group), + context_(NULL) { +} + +GLContextWGL::~GLContextWGL() { + Destroy(); +} + +std::string GLContextWGL::GetExtensions() { + const char* extensions = NULL; + if (wglGetExtensionsStringARB) + extensions = wglGetExtensionsStringARB(GLSurfaceWGL::GetDisplayDC()); + else if (wglGetExtensionsStringEXT) + extensions = wglGetExtensionsStringEXT(); + + if (extensions) + return GLContext::GetExtensions() + " " + extensions; + + return GLContext::GetExtensions(); +} + +bool GLContextWGL::Initialize( + GLSurface* compatible_surface, GpuPreference gpu_preference) { + // Get the handle of another initialized context in the share group _before_ + // setting context_. Otherwise this context will be considered initialized + // and could potentially be returned by GetHandle. + HGLRC share_handle = static_cast<HGLRC>(share_group()->GetHandle()); + + context_ = wglCreateContext( + static_cast<HDC>(compatible_surface->GetHandle())); + if (!context_) { + LOG(ERROR) << "Failed to create GL context."; + Destroy(); + return false; + } + + if (share_handle) { + if (!wglShareLists(share_handle, context_)) { + LOG(ERROR) << "Could not share GL contexts."; + Destroy(); + return false; + } + } + + return true; +} + +void GLContextWGL::Destroy() { + if (context_) { + wglDeleteContext(context_); + context_ = NULL; + } +} + +bool GLContextWGL::MakeCurrent(GLSurface* surface) { + DCHECK(context_); + if (IsCurrent(surface)) + return true; + + TRACE_EVENT0("gpu", "GLContextWGL::MakeCurrent"); + + if (!wglMakeCurrent(static_cast<HDC>(surface->GetHandle()), context_)) { + LOG(ERROR) << "Unable to make gl context current."; + return false; + } + + SetCurrent(this, surface); + if (!InitializeExtensionBindings()) { + ReleaseCurrent(surface); + return false; + } + + if (!surface->OnMakeCurrent(this)) { + LOG(ERROR) << "Could not make current."; + return false; + } + + return true; +} + +void GLContextWGL::ReleaseCurrent(GLSurface* surface) { + if (!IsCurrent(surface)) + return; + + SetCurrent(NULL, NULL); + wglMakeCurrent(NULL, NULL); +} + +bool GLContextWGL::IsCurrent(GLSurface* surface) { + bool native_context_is_current = + wglGetCurrentContext() == context_; + + // If our context is current then our notion of which GLContext is + // current must be correct. On the other hand, third-party code + // using OpenGL might change the current context. + DCHECK(!native_context_is_current || (GetCurrent() == this)); + + if (!native_context_is_current) + return false; + + if (surface) { + if (wglGetCurrentDC() != surface->GetHandle()) + return false; + } + + return true; +} + +void* GLContextWGL::GetHandle() { + return context_; +} + +void GLContextWGL::SetSwapInterval(int interval) { + DCHECK(IsCurrent(NULL)); + if (gfx::g_WGL_EXT_swap_control) { + wglSwapIntervalEXT(interval); + } else { + LOG(WARNING) << + "Could not disable vsync: driver does not " + "support WGL_EXT_swap_control"; + } +} + +} // namespace gfx diff --git a/ui/gl/gl_context_wgl.h b/ui/gl/gl_context_wgl.h new file mode 100644 index 0000000..1fc6177 --- /dev/null +++ b/ui/gl/gl_context_wgl.h @@ -0,0 +1,43 @@ +// 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. + +#ifndef UI_GL_GL_CONTEXT_WGL_H_ +#define UI_GL_GL_CONTEXT_WGL_H_ +#pragma once + +#include <string> + +#include "ui/gfx/native_widget_types.h" +#include "ui/gl/gl_context.h" + +namespace gfx { + +class GLSurface; + +// This class is a wrapper around a GL context. +class GLContextWGL : public GLContext { + public: + explicit GLContextWGL(GLShareGroup* share_group); + virtual ~GLContextWGL(); + + // Implement GLContext. + virtual bool Initialize( + GLSurface* compatible_surface, GpuPreference gpu_preference); + virtual void Destroy(); + virtual bool MakeCurrent(GLSurface* surface); + virtual void ReleaseCurrent(GLSurface* surface); + virtual bool IsCurrent(GLSurface* surface); + virtual void* GetHandle(); + virtual void SetSwapInterval(int interval); + virtual std::string GetExtensions(); + + private: + HGLRC context_; + + DISALLOW_COPY_AND_ASSIGN(GLContextWGL); +}; + +} // namespace gfx + +#endif // UI_GL_GL_CONTEXT_WGL_H_ diff --git a/ui/gl/gl_context_win.cc b/ui/gl/gl_context_win.cc new file mode 100644 index 0000000..c42daa9 --- /dev/null +++ b/ui/gl/gl_context_win.cc @@ -0,0 +1,61 @@ +// 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_context.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/mesa/MesaLib/include/GL/osmesa.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_context_egl.h" +#include "ui/gl/gl_context_osmesa.h" +#include "ui/gl/gl_context_stub.h" +#include "ui/gl/gl_context_wgl.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface_egl.h" +#include "ui/gl/gl_surface_osmesa.h" +#include "ui/gl/gl_surface_stub.h" +#include "ui/gl/gl_surface_wgl.h" + +namespace gfx { + +scoped_refptr<GLContext> GLContext::CreateGLContext( + GLShareGroup* share_group, + GLSurface* compatible_surface, + GpuPreference gpu_preference) { + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_refptr<GLContext> context(new GLContextOSMesa(share_group)); + if (!context->Initialize(compatible_surface, gpu_preference)) + return NULL; + + return context; + } + case kGLImplementationEGLGLES2: { + scoped_refptr<GLContext> context(new GLContextEGL(share_group)); + if (!context->Initialize(compatible_surface, gpu_preference)) + return NULL; + + return context; + } + case kGLImplementationDesktopGL: { + scoped_refptr<GLContext> context(new GLContextWGL(share_group)); + if (!context->Initialize(compatible_surface, gpu_preference)) + return NULL; + + return context; + } + case kGLImplementationMockGL: + return new GLContextStub; + default: + NOTREACHED(); + return NULL; + } +} + +bool GLContext::SupportsDualGpus() { + return false; +} + +} // namespace gfx diff --git a/ui/gl/gl_export.h b/ui/gl/gl_export.h new file mode 100644 index 0000000..30e6979 --- /dev/null +++ b/ui/gl/gl_export.h @@ -0,0 +1,26 @@ +// 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. + +#ifndef UI_GL_GL_EXPORT_H_ +#define UI_GL_GL_EXPORT_H_ +#pragma once + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(GL_IMPLEMENTATION) +#define GL_EXPORT __declspec(dllexport) +#else +#define GL_EXPORT __declspec(dllimport) +#endif // defined(GL_IMPLEMENTATION) + +#else // defined(WIN32) +#define GL_EXPORT __attribute__((visibility("default"))) +#endif + +#else // defined(COMPONENT_BUILD) +#define GL_EXPORT +#endif + +#endif // UI_GL_GL_EXPORT_H_ diff --git a/ui/gl/gl_fence.cc b/ui/gl/gl_fence.cc new file mode 100644 index 0000000..82cdf30 --- /dev/null +++ b/ui/gl/gl_fence.cc @@ -0,0 +1,108 @@ +// 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_fence.h" + +#include "base/compiler_specific.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_context.h" + +namespace { + +class GLFenceNVFence: public gfx::GLFence { + public: + GLFenceNVFence() { + // What if either of these GL calls fails? TestFenceNV will return true. + // See spec: + // http://www.opengl.org/registry/specs/NV/fence.txt + // + // What should happen if TestFenceNV is called for a name before SetFenceNV + // is called? + // We generate an INVALID_OPERATION error, and return TRUE. + // This follows the semantics for texture object names before + // they are bound, in that they acquire their state upon binding. + // We will arbitrarily return TRUE for consistency. + glGenFencesNV(1, &fence_); + glSetFenceNV(fence_, GL_ALL_COMPLETED_NV); + glFlush(); + } + + virtual bool HasCompleted() OVERRIDE { + return IsContextLost() || glTestFenceNV(fence_); + } + + private: + ~GLFenceNVFence() { + glDeleteFencesNV(1, &fence_); + } + + GLuint fence_; +}; + +class GLFenceARBSync: public gfx::GLFence { + public: + GLFenceARBSync() { + sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glFlush(); + } + + virtual bool HasCompleted() OVERRIDE { + // Handle the case where FenceSync failed. + if (!sync_ || IsContextLost()) + return true; + + GLsizei length = 0; + GLsizei value = 0; + glGetSynciv(sync_, + GL_SYNC_STATUS, + 1, // bufSize + &length, + &value); + return length == 1 && value == GL_SIGNALED; + } + + private: + ~GLFenceARBSync() { + glDeleteSync(sync_); + } + + GLsync sync_; +}; + +} // namespace + +namespace gfx { + +GLFence::GLFence() { +} + +GLFence::~GLFence() { +} + +// static +GLFence* GLFence::Create() { + if (gfx::g_GL_NV_fence) { + return new GLFenceNVFence(); + } else if (gfx::g_GL_ARB_sync) { + return new GLFenceARBSync(); + } else { + return NULL; + } +} + +// static +bool GLFence::IsContextLost() { + if (!gfx::g_GL_ARB_robustness) + return false; + + if (!gfx::GLContext::GetCurrent() || + !gfx::GLContext::GetCurrent()-> + WasAllocatedUsingARBRobustness()) + return false; + + GLenum status = glGetGraphicsResetStatusARB(); + return status != GL_NO_ERROR; +} + +} // namespace gfx diff --git a/ui/gl/gl_fence.h b/ui/gl/gl_fence.h new file mode 100644 index 0000000..62a7116 --- /dev/null +++ b/ui/gl/gl_fence.h @@ -0,0 +1,31 @@ +// 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. + +#ifndef UI_GL_GL_FENCE_H_ +#define UI_GL_GL_FENCE_H_ +#pragma once + +#include "base/basictypes.h" +#include "ui/gl/gl_export.h" + +namespace gfx { + +class GL_EXPORT GLFence { + public: + GLFence(); + virtual ~GLFence(); + + static GLFence* Create(); + virtual bool HasCompleted() = 0; + + protected: + static bool IsContextLost(); + + private: + DISALLOW_COPY_AND_ASSIGN(GLFence); +}; + +} // namespace gfx + +#endif // UI_GL_GL_FENCE_H_ diff --git a/ui/gl/gl_implementation.cc b/ui/gl/gl_implementation.cc new file mode 100644 index 0000000..0a10f22 --- /dev/null +++ b/ui/gl/gl_implementation.cc @@ -0,0 +1,151 @@ +// 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 <algorithm> +#include <string> + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/logging.h" + +namespace gfx { + +namespace { + +const struct { + const char* name; + GLImplementation implementation; +} kGLImplementationNamePairs[] = { + { kGLImplementationDesktopName, kGLImplementationDesktopGL }, + { kGLImplementationOSMesaName, kGLImplementationOSMesaGL }, +#if defined(OS_MACOSX) + { kGLImplementationAppleName, kGLImplementationAppleGL }, +#endif + { kGLImplementationEGLName, kGLImplementationEGLGLES2 }, + { kGLImplementationMockName, kGLImplementationMockGL } +}; + +typedef std::vector<base::NativeLibrary> LibraryArray; + +GLImplementation g_gl_implementation = kGLImplementationNone; +LibraryArray* g_libraries; +GLGetProcAddressProc g_get_proc_address; + +void CleanupNativeLibraries(void* unused) { + if (g_libraries) { + for (LibraryArray::iterator it = g_libraries->begin(); + it != g_libraries->end(); ++it) { + base::UnloadNativeLibrary(*it); + } + delete g_libraries; + g_libraries = NULL; + } +} + +bool ExportsCoreFunctionsFromGetProcAddress(GLImplementation implementation) { + switch (GetGLImplementation()) { + case kGLImplementationDesktopGL: + case kGLImplementationOSMesaGL: + case kGLImplementationAppleGL: + case kGLImplementationMockGL: + return true; + case kGLImplementationEGLGLES2: + return false; + default: + NOTREACHED(); + return true; + } +} + +} + +GLImplementation GetNamedGLImplementation(const std::string& name) { + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kGLImplementationNamePairs); ++i) { + if (name == kGLImplementationNamePairs[i].name) + return kGLImplementationNamePairs[i].implementation; + } + + return kGLImplementationNone; +} + +const char* GetGLImplementationName(GLImplementation implementation) { + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(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 || + kGLImplementationOSMesaGL == 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() { + CleanupNativeLibraries(NULL); +} + +void SetGLGetProcAddressProc(GLGetProcAddressProc proc) { + DCHECK(proc); + g_get_proc_address = proc; +} + +void* GetGLCoreProcAddress(const char* name) { + DCHECK(g_gl_implementation != kGLImplementationNone); + + if (g_libraries) { + for (size_t i = 0; i < g_libraries->size(); ++i) { + void* proc = base::GetFunctionPointerFromNativeLibrary((*g_libraries)[i], + name); + if (proc) + return proc; + } + } + if (ExportsCoreFunctionsFromGetProcAddress(g_gl_implementation) && + g_get_proc_address) { + void* proc = g_get_proc_address(name); + if (proc) + return proc; + } + + return NULL; +} + +void* GetGLProcAddress(const char* name) { + DCHECK(g_gl_implementation != kGLImplementationNone); + + void* proc = GetGLCoreProcAddress(name); + if (!proc && g_get_proc_address) { + proc = g_get_proc_address(name); + if (proc) + return proc; + } + + return proc; +} + +} // namespace gfx diff --git a/ui/gl/gl_implementation.h b/ui/gl/gl_implementation.h new file mode 100644 index 0000000..9ee1f2d --- /dev/null +++ b/ui/gl/gl_implementation.h @@ -0,0 +1,86 @@ +// 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. + +#ifndef UI_GL_GL_IMPLEMENTATION_H_ +#define UI_GL_GL_IMPLEMENTATION_H_ +#pragma once + +#include <string> +#include <vector> + +#include "base/native_library.h" +#include "build/build_config.h" +#include "ui/gl/gl_export.h" +#include "ui/gl/gl_switches.h" + +namespace gfx { + +class GLContext; + +// The GL implementation currently in use. +enum GLImplementation { + kGLImplementationNone, + kGLImplementationDesktopGL, + kGLImplementationOSMesaGL, + kGLImplementationAppleGL, + kGLImplementationEGLGLES2, + kGLImplementationMockGL +}; + +void GetAllowedGLImplementations(std::vector<GLImplementation>* impls); + +#if defined(OS_WIN) +typedef void* (WINAPI *GLGetProcAddressProc)(const char* name); +#else +typedef void* (*GLGetProcAddressProc)(const char* name); +#endif + +// Initialize a particular GL implementation. +GL_EXPORT bool InitializeGLBindings(GLImplementation implementation); + +// Initialize extension function bindings for a GL implementation. +GL_EXPORT bool InitializeGLExtensionBindings(GLImplementation implementation, + GLContext* context); + +// Initialize Debug logging wrappers for GL bindings. +void InitializeDebugGLBindings(); + +void ClearGLBindings(); + +// Set the current GL implementation. +void SetGLImplementation(GLImplementation implementation); + +// Get the current GL implementation. +GL_EXPORT GLImplementation GetGLImplementation(); + +// Does the underlying GL support all features from Desktop GL 2.0 that were +// removed from the ES 2.0 spec without requiring specific extension strings. +GL_EXPORT bool HasDesktopGLFeatures(); + +// Get the GL implementation with a given name. +GLImplementation GetNamedGLImplementation(const std::string& name); + +// Get the name of a GL implementation. +const char* GetGLImplementationName(GLImplementation implementation); + +// Add a native library to those searched for GL entry points. +void AddGLNativeLibrary(base::NativeLibrary library); + +// Unloads all native libraries. +void UnloadGLNativeLibraries(); + +// Set an additional function that will be called to find GL entry points. +void SetGLGetProcAddressProc(GLGetProcAddressProc proc); + +// Find a core (non-extension) entry point in the current GL implementation. On +// EGL based implementations core entry points will not be queried through +// GLGetProcAddressProc. +void* GetGLCoreProcAddress(const char* name); + +// Find an entry point in the current GL implementation. +void* GetGLProcAddress(const char* name); + +} // namespace gfx + +#endif // UI_GL_GL_IMPLEMENTATION_H_ diff --git a/ui/gl/gl_implementation_android.cc b/ui/gl/gl_implementation_android.cc new file mode 100644 index 0000000..254c037 --- /dev/null +++ b/ui/gl/gl_implementation_android.cc @@ -0,0 +1,132 @@ +// 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 "base/base_paths.h" +#include "base/command_line.h" +#include "base/file_path.h" +#include "base/logging.h" +#include "base/native_library.h" +#include "base/path_service.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_implementation.h" + +namespace gfx { + +namespace { + +void GL_BINDING_CALL MarshalClearDepthToClearDepthf(GLclampd depth) { + glClearDepthf(static_cast<GLclampf>(depth)); +} + +void GL_BINDING_CALL MarshalDepthRangeToDepthRangef(GLclampd z_near, + GLclampd z_far) { + glDepthRangef(static_cast<GLclampf>(z_near), static_cast<GLclampf>(z_far)); +} + +base::NativeLibrary LoadLibrary(const FilePath& filename) { + std::string error; + base::NativeLibrary library = base::LoadNativeLibrary(filename, &error); + if (!library) { + DVLOG(1) << "Failed to load " << filename.MaybeAsASCII() << ": " << error; + return NULL; + } + return library; +} + +base::NativeLibrary LoadLibrary(const char* filename) { + return LoadLibrary(FilePath(filename)); +} + +} // namespace anonymous + +void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) { + impls->push_back(kGLImplementationEGLGLES2); +} + +bool InitializeGLBindings(GLImplementation implementation) { + // Prevent reinitialization with a different implementation. Once the gpu + // unit tests have initialized with kGLImplementationMock, we don't want to + // later switch to another GL implementation. + if (GetGLImplementation() != kGLImplementationNone) + return true; + + switch (implementation) { + case kGLImplementationEGLGLES2: { + base::NativeLibrary gles_library = LoadLibrary("libGLESv2.so"); + if (!gles_library) + return false; + base::NativeLibrary egl_library = LoadLibrary("libEGL.so"); + if (!egl_library) { + base::UnloadNativeLibrary(gles_library); + return false; + } + + GLGetProcAddressProc get_proc_address = + reinterpret_cast<GLGetProcAddressProc>( + base::GetFunctionPointerFromNativeLibrary( + egl_library, "eglGetProcAddress")); + if (!get_proc_address) { + LOG(ERROR) << "eglGetProcAddress not found."; + base::UnloadNativeLibrary(egl_library); + base::UnloadNativeLibrary(gles_library); + return false; + } + + SetGLGetProcAddressProc(get_proc_address); + AddGLNativeLibrary(egl_library); + AddGLNativeLibrary(gles_library); + SetGLImplementation(kGLImplementationEGLGLES2); + + InitializeGLBindingsGL(); + InitializeGLBindingsEGL(); + + // These two functions take single precision float rather than double + // precision float parameters in GLES. + ::gfx::g_glClearDepth = MarshalClearDepthToClearDepthf; + ::gfx::g_glDepthRange = MarshalDepthRangeToDepthRangef; + break; + } + case kGLImplementationMockGL: { + SetGLGetProcAddressProc(GetMockGLProcAddress); + SetGLImplementation(kGLImplementationMockGL); + InitializeGLBindingsGL(); + break; + } + default: + NOTIMPLEMENTED() << "InitializeGLBindings on Android"; + return false; + } + + return true; +} + +bool InitializeGLExtensionBindings(GLImplementation implementation, + GLContext* context) { + switch (implementation) { + case kGLImplementationEGLGLES2: + InitializeGLExtensionBindingsGL(context); + InitializeGLExtensionBindingsEGL(context); + break; + case kGLImplementationMockGL: + InitializeGLExtensionBindingsGL(context); + break; + default: + return false; + } + + return true; +} + +void InitializeDebugGLBindings() { +} + +void ClearGLBindings() { + ClearGLBindingsEGL(); + ClearGLBindingsGL(); + SetGLImplementation(kGLImplementationNone); + + UnloadGLNativeLibraries(); +} + +} // namespace gfx diff --git a/ui/gl/gl_implementation_linux.cc b/ui/gl/gl_implementation_linux.cc new file mode 100644 index 0000000..35f68ac --- /dev/null +++ b/ui/gl/gl_implementation_linux.cc @@ -0,0 +1,228 @@ +// 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 <vector> + +#include "base/base_paths.h" +#include "base/command_line.h" +#include "base/file_path.h" +#include "base/logging.h" +#include "base/native_library.h" +#include "base/path_service.h" +#include "base/threading/thread_restrictions.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_switches.h" + +namespace gfx { +namespace { + +// TODO(piman): it should be Desktop GL marshalling from double to float. Today +// on native GLES, we do float->double->float. +void GL_BINDING_CALL MarshalClearDepthToClearDepthf(GLclampd depth) { + glClearDepthf(static_cast<GLclampf>(depth)); +} + +void GL_BINDING_CALL MarshalDepthRangeToDepthRangef(GLclampd z_near, + GLclampd z_far) { + glDepthRangef(static_cast<GLclampf>(z_near), static_cast<GLclampf>(z_far)); +} + +// Load a library, printing an error message on failure. +base::NativeLibrary LoadLibrary(const FilePath& filename) { + std::string error; + base::NativeLibrary library = base::LoadNativeLibrary(filename, + &error); + if (!library) { + DVLOG(1) << "Failed to load " << filename.MaybeAsASCII() << ": " << error; + return NULL; + } + return library; +} + +base::NativeLibrary LoadLibrary(const char* filename) { + return LoadLibrary(FilePath(filename)); +} + +} // namespace anonymous + +void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) { + impls->push_back(kGLImplementationDesktopGL); + impls->push_back(kGLImplementationEGLGLES2); + impls->push_back(kGLImplementationOSMesaGL); +} + +bool InitializeGLBindings(GLImplementation implementation) { + // Prevent reinitialization with a different implementation. Once the gpu + // unit tests have initialized with kGLImplementationMock, we don't want to + // later switch to another GL implementation. + if (GetGLImplementation() != kGLImplementationNone) + return true; + + // Allow the main thread or another to initialize these bindings + // after instituting restrictions on I/O. Going forward they will + // likely be used in the browser process on most platforms. The + // one-time initialization cost is small, between 2 and 5 ms. + base::ThreadRestrictions::ScopedAllowIO allow_io; + + switch (implementation) { + case kGLImplementationOSMesaGL: { + FilePath module_path; + if (!PathService::Get(base::DIR_MODULE, &module_path)) { + LOG(ERROR) << "PathService::Get failed."; + return false; + } + + base::NativeLibrary library = LoadLibrary( + module_path.Append("libosmesa.so")); + if (!library) + return false; + + GLGetProcAddressProc get_proc_address = + reinterpret_cast<GLGetProcAddressProc>( + base::GetFunctionPointerFromNativeLibrary( + library, "OSMesaGetProcAddress")); + if (!get_proc_address) { + LOG(ERROR) << "OSMesaGetProcAddress not found."; + base::UnloadNativeLibrary(library); + return false; + } + + SetGLGetProcAddressProc(get_proc_address); + AddGLNativeLibrary(library); + SetGLImplementation(kGLImplementationOSMesaGL); + + InitializeGLBindingsGL(); + InitializeGLBindingsOSMESA(); + break; + } + case kGLImplementationDesktopGL: { + base::NativeLibrary library = NULL; + const CommandLine* command_line = CommandLine::ForCurrentProcess(); + + if (command_line->HasSwitch(switches::kTestGLLib)) + library = LoadLibrary(command_line->GetSwitchValueASCII( + switches::kTestGLLib).c_str()); + + if (!library) { +#if defined(OS_OPENBSD) + library = LoadLibrary("libGL.so"); +#else + library = LoadLibrary("libGL.so.1"); +#endif + } + + if (!library) + return false; + + GLGetProcAddressProc get_proc_address = + reinterpret_cast<GLGetProcAddressProc>( + base::GetFunctionPointerFromNativeLibrary( + library, "glXGetProcAddress")); + if (!get_proc_address) { + LOG(ERROR) << "glxGetProcAddress not found."; + base::UnloadNativeLibrary(library); + return false; + } + + SetGLGetProcAddressProc(get_proc_address); + AddGLNativeLibrary(library); + SetGLImplementation(kGLImplementationDesktopGL); + + InitializeGLBindingsGL(); + InitializeGLBindingsGLX(); + break; + } + case kGLImplementationEGLGLES2: { + base::NativeLibrary gles_library = LoadLibrary("libGLESv2.so.2"); + if (!gles_library) + return false; + base::NativeLibrary egl_library = LoadLibrary("libEGL.so.1"); + if (!egl_library) { + base::UnloadNativeLibrary(gles_library); + return false; + } + + GLGetProcAddressProc get_proc_address = + reinterpret_cast<GLGetProcAddressProc>( + base::GetFunctionPointerFromNativeLibrary( + egl_library, "eglGetProcAddress")); + if (!get_proc_address) { + LOG(ERROR) << "eglGetProcAddress not found."; + base::UnloadNativeLibrary(egl_library); + base::UnloadNativeLibrary(gles_library); + return false; + } + + SetGLGetProcAddressProc(get_proc_address); + AddGLNativeLibrary(egl_library); + AddGLNativeLibrary(gles_library); + SetGLImplementation(kGLImplementationEGLGLES2); + + InitializeGLBindingsGL(); + InitializeGLBindingsEGL(); + + // These two functions take single precision float rather than double + // precision float parameters in GLES. + ::gfx::g_glClearDepth = MarshalClearDepthToClearDepthf; + ::gfx::g_glDepthRange = MarshalDepthRangeToDepthRangef; + break; + } + case kGLImplementationMockGL: { + SetGLGetProcAddressProc(GetMockGLProcAddress); + SetGLImplementation(kGLImplementationMockGL); + InitializeGLBindingsGL(); + break; + } + default: + return false; + } + + + return true; +} + +bool InitializeGLExtensionBindings(GLImplementation implementation, + GLContext* context) { + switch (implementation) { + case kGLImplementationOSMesaGL: + InitializeGLExtensionBindingsGL(context); + InitializeGLExtensionBindingsOSMESA(context); + break; + case kGLImplementationDesktopGL: + InitializeGLExtensionBindingsGL(context); + InitializeGLExtensionBindingsGLX(context); + break; + case kGLImplementationEGLGLES2: + InitializeGLExtensionBindingsGL(context); + InitializeGLExtensionBindingsEGL(context); + break; + case kGLImplementationMockGL: + InitializeGLExtensionBindingsGL(context); + break; + default: + return false; + } + + return true; +} + +void InitializeDebugGLBindings() { + InitializeDebugGLBindingsEGL(); + InitializeDebugGLBindingsGL(); + InitializeDebugGLBindingsGLX(); + InitializeDebugGLBindingsOSMESA(); +} + +void ClearGLBindings() { + ClearGLBindingsEGL(); + ClearGLBindingsGL(); + ClearGLBindingsGLX(); + ClearGLBindingsOSMESA(); + SetGLImplementation(kGLImplementationNone); + + UnloadGLNativeLibraries(); +} + +} // namespace gfx diff --git a/ui/gl/gl_implementation_mac.cc b/ui/gl/gl_implementation_mac.cc new file mode 100644 index 0000000..f05e3eb9 --- /dev/null +++ b/ui/gl/gl_implementation_mac.cc @@ -0,0 +1,140 @@ +// 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 "base/base_paths.h" +#include "base/file_path.h" +#include "base/logging.h" +#include "base/mac/foundation_util.h" +#include "base/native_library.h" +#include "base/path_service.h" +#include "base/threading/thread_restrictions.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_implementation.h" + +namespace gfx { +namespace { +const char kOpenGLFrameworkPath[] = + "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"; +} // namespace anonymous + +void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) { + impls->push_back(kGLImplementationDesktopGL); + impls->push_back(kGLImplementationAppleGL); + impls->push_back(kGLImplementationOSMesaGL); +} + +bool InitializeGLBindings(GLImplementation implementation) { + // Prevent reinitialization with a different implementation. Once the gpu + // unit tests have initialized with kGLImplementationMock, we don't want to + // later switch to another GL implementation. + if (GetGLImplementation() != kGLImplementationNone) + return true; + + // Allow the main thread or another to initialize these bindings + // after instituting restrictions on I/O. Going forward they will + // likely be used in the browser process on most platforms. The + // one-time initialization cost is small, between 2 and 5 ms. + base::ThreadRestrictions::ScopedAllowIO allow_io; + + switch (implementation) { + case kGLImplementationOSMesaGL: { + // osmesa.so is located in the build directory. This code path is only + // valid in a developer build environment. + FilePath exe_path; + if (!PathService::Get(base::FILE_EXE, &exe_path)) { + LOG(ERROR) << "PathService::Get failed."; + return false; + } + FilePath bundle_path = base::mac::GetAppBundlePath(exe_path); + FilePath build_dir_path = bundle_path.DirName(); + FilePath osmesa_path = build_dir_path.Append("osmesa.so"); + + // When using OSMesa, just use OSMesaGetProcAddress to find entry points. + base::NativeLibrary library = base::LoadNativeLibrary(osmesa_path, NULL); + if (!library) { + LOG(ERROR) << "osmesa.so not found at " << osmesa_path.value(); + return false; + } + + GLGetProcAddressProc get_proc_address = + reinterpret_cast<GLGetProcAddressProc>( + base::GetFunctionPointerFromNativeLibrary( + library, "OSMesaGetProcAddress")); + if (!get_proc_address) { + LOG(ERROR) << "OSMesaGetProcAddress not found."; + base::UnloadNativeLibrary(library); + return false; + } + + SetGLGetProcAddressProc(get_proc_address); + AddGLNativeLibrary(library); + SetGLImplementation(kGLImplementationOSMesaGL); + + InitializeGLBindingsGL(); + InitializeGLBindingsOSMESA(); + break; + } + case kGLImplementationDesktopGL: + case kGLImplementationAppleGL: { + base::NativeLibrary library = base::LoadNativeLibrary( + FilePath(kOpenGLFrameworkPath), NULL); + if (!library) { + LOG(ERROR) << "OpenGL framework not found"; + return false; + } + + AddGLNativeLibrary(library); + SetGLImplementation(implementation); + + InitializeGLBindingsGL(); + break; + } + case kGLImplementationMockGL: { + SetGLGetProcAddressProc(GetMockGLProcAddress); + SetGLImplementation(kGLImplementationMockGL); + InitializeGLBindingsGL(); + break; + } + default: + return false; + } + + return true; +} + +bool InitializeGLExtensionBindings(GLImplementation implementation, + GLContext* context) { + switch (implementation) { + case kGLImplementationOSMesaGL: + InitializeGLExtensionBindingsGL(context); + InitializeGLExtensionBindingsOSMESA(context); + break; + case kGLImplementationDesktopGL: + case kGLImplementationAppleGL: + InitializeGLExtensionBindingsGL(context); + break; + case kGLImplementationMockGL: + InitializeGLExtensionBindingsGL(context); + break; + default: + return false; + } + + return true; +} + +void InitializeDebugGLBindings() { + InitializeDebugGLBindingsGL(); + InitializeDebugGLBindingsOSMESA(); +} + +void ClearGLBindings() { + ClearGLBindingsGL(); + ClearGLBindingsOSMESA(); + SetGLImplementation(kGLImplementationNone); + + UnloadGLNativeLibraries(); +} + +} // namespace gfx diff --git a/ui/gl/gl_implementation_win.cc b/ui/gl/gl_implementation_win.cc new file mode 100644 index 0000000..7625b20 --- /dev/null +++ b/ui/gl/gl_implementation_win.cc @@ -0,0 +1,290 @@ +// 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 <d3dx9.h> + +#include <vector> + +#include "base/at_exit.h" +#include "base/base_paths.h" +#include "base/bind.h" +#include "base/command_line.h" +#include "base/file_path.h" +#include "base/logging.h" +#include "base/native_library.h" +#include "base/path_service.h" +#include "base/stringprintf.h" +#include "base/threading/thread_restrictions.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_implementation.h" + +#if defined(ENABLE_SWIFTSHADER) +#include "software_renderer.h" +#endif + +namespace gfx { + +namespace { + +typedef std::vector<base::NativeLibrary> LibraryArray; +LibraryArray* g_d3dx_libraries; + +void GL_BINDING_CALL MarshalClearDepthToClearDepthf(GLclampd depth) { + glClearDepthf(static_cast<GLclampf>(depth)); +} + +void GL_BINDING_CALL MarshalDepthRangeToDepthRangef(GLclampd z_near, + GLclampd z_far) { + glDepthRangef(static_cast<GLclampf>(z_near), static_cast<GLclampf>(z_far)); +} + +void UnloadD3DXLibraries(void* unused) { + if (g_d3dx_libraries) { + for (LibraryArray::iterator it = g_d3dx_libraries->begin(); + it != g_d3dx_libraries->end(); ++it) { + base::UnloadNativeLibrary(*it); + } + delete g_d3dx_libraries; + g_d3dx_libraries = NULL; + } +} + +bool LoadD3DXLibrary(const FilePath& module_path, + const FilePath::StringType& name) { + base::NativeLibrary library = base::LoadNativeLibrary(FilePath(name), NULL); + if (!library) { + library = base::LoadNativeLibrary(module_path.Append(name), NULL); + if (!library) { + DVLOG(1) << name << " not found."; + return false; + } + } + + if (!g_d3dx_libraries) { + g_d3dx_libraries = new LibraryArray; + base::AtExitManager::RegisterCallback(UnloadD3DXLibraries, NULL); + } + g_d3dx_libraries->push_back(library); + return true; +} + +} // namespace anonymous + +void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) { + impls->push_back(kGLImplementationEGLGLES2); + impls->push_back(kGLImplementationDesktopGL); + impls->push_back(kGLImplementationOSMesaGL); +} + +bool InitializeGLBindings(GLImplementation implementation) { + // Prevent reinitialization with a different implementation. Once the gpu + // unit tests have initialized with kGLImplementationMock, we don't want to + // later switch to another GL implementation. + if (GetGLImplementation() != kGLImplementationNone) + return true; + + // Allow the main thread or another to initialize these bindings + // after instituting restrictions on I/O. Going forward they will + // likely be used in the browser process on most platforms. The + // one-time initialization cost is small, between 2 and 5 ms. + base::ThreadRestrictions::ScopedAllowIO allow_io; + + switch (implementation) { + case kGLImplementationOSMesaGL: { + FilePath module_path; + if (!PathService::Get(base::DIR_MODULE, &module_path)) { + LOG(ERROR) << "PathService::Get failed."; + return false; + } + + base::NativeLibrary library = base::LoadNativeLibrary( + module_path.Append(L"osmesa.dll"), NULL); + if (!library) { + DVLOG(1) << "osmesa.dll not found"; + return false; + } + + GLGetProcAddressProc get_proc_address = + reinterpret_cast<GLGetProcAddressProc>( + base::GetFunctionPointerFromNativeLibrary( + library, "OSMesaGetProcAddress")); + if (!get_proc_address) { + DLOG(ERROR) << "OSMesaGetProcAddress not found."; + base::UnloadNativeLibrary(library); + return false; + } + + SetGLGetProcAddressProc(get_proc_address); + AddGLNativeLibrary(library); + SetGLImplementation(kGLImplementationOSMesaGL); + + InitializeGLBindingsGL(); + InitializeGLBindingsOSMESA(); + break; + } + case kGLImplementationEGLGLES2: { + FilePath module_path; + if (!PathService::Get(base::DIR_MODULE, &module_path)) + return false; + + // Attempt to load D3DX and its dependencies using the default search path + // and if that fails, using an absolute path. This is to ensure these DLLs + // are loaded before ANGLE is loaded in case they are not in the default + // search path. + LoadD3DXLibrary(module_path, base::StringPrintf(L"d3dcompiler_%d.dll", + D3DX_SDK_VERSION)); + LoadD3DXLibrary(module_path, base::StringPrintf(L"d3dx9_%d.dll", + D3DX_SDK_VERSION)); + + FilePath gles_path; + const CommandLine* command_line = CommandLine::ForCurrentProcess(); + bool using_swift_shader = + command_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader"; + if (using_swift_shader) { + if (!command_line->HasSwitch(switches::kSwiftShaderPath)) + return false; + gles_path = + command_line->GetSwitchValuePath(switches::kSwiftShaderPath); + // Preload library + LoadLibrary(L"ddraw.dll"); + } else { + gles_path = module_path; + } + + // Load libglesv2.dll before libegl.dll because the latter is dependent on + // the former and if there is another version of libglesv2.dll in the dll + // search path, it will get loaded instead. + base::NativeLibrary gles_library = base::LoadNativeLibrary( + gles_path.Append(L"libglesv2.dll"), NULL); + if (!gles_library) { + DVLOG(1) << "libglesv2.dll not found"; + return false; + } + + // When using EGL, first try eglGetProcAddress and then Windows + // GetProcAddress on both the EGL and GLES2 DLLs. + base::NativeLibrary egl_library = base::LoadNativeLibrary( + gles_path.Append(L"libegl.dll"), NULL); + if (!egl_library) { + DVLOG(1) << "libegl.dll not found."; + base::UnloadNativeLibrary(gles_library); + return false; + } + +#if defined(ENABLE_SWIFTSHADER) + if (using_swift_shader) { + SetupSoftwareRenderer(gles_library); + } +#endif + + GLGetProcAddressProc get_proc_address = + reinterpret_cast<GLGetProcAddressProc>( + base::GetFunctionPointerFromNativeLibrary( + egl_library, "eglGetProcAddress")); + if (!get_proc_address) { + LOG(ERROR) << "eglGetProcAddress not found."; + base::UnloadNativeLibrary(egl_library); + base::UnloadNativeLibrary(gles_library); + return false; + } + + SetGLGetProcAddressProc(get_proc_address); + AddGLNativeLibrary(egl_library); + AddGLNativeLibrary(gles_library); + SetGLImplementation(kGLImplementationEGLGLES2); + + InitializeGLBindingsGL(); + InitializeGLBindingsEGL(); + + // These two functions take single precision float rather than double + // precision float parameters in GLES. + ::gfx::g_glClearDepth = MarshalClearDepthToClearDepthf; + ::gfx::g_glDepthRange = MarshalDepthRangeToDepthRangef; + break; + } + case kGLImplementationDesktopGL: { + // When using Windows OpenGL, first try wglGetProcAddress and then + // Windows GetProcAddress. + base::NativeLibrary library = base::LoadNativeLibrary( + FilePath(L"opengl32.dll"), NULL); + if (!library) { + DVLOG(1) << "opengl32.dll not found"; + return false; + } + + GLGetProcAddressProc get_proc_address = + reinterpret_cast<GLGetProcAddressProc>( + base::GetFunctionPointerFromNativeLibrary( + library, "wglGetProcAddress")); + if (!get_proc_address) { + LOG(ERROR) << "wglGetProcAddress not found."; + base::UnloadNativeLibrary(library); + return false; + } + + SetGLGetProcAddressProc(get_proc_address); + AddGLNativeLibrary(library); + SetGLImplementation(kGLImplementationDesktopGL); + + InitializeGLBindingsGL(); + InitializeGLBindingsWGL(); + break; + } + case kGLImplementationMockGL: { + SetGLGetProcAddressProc(GetMockGLProcAddress); + SetGLImplementation(kGLImplementationMockGL); + InitializeGLBindingsGL(); + break; + } + default: + return false; + } + + return true; +} + +bool InitializeGLExtensionBindings(GLImplementation implementation, + GLContext* context) { + switch (implementation) { + case kGLImplementationOSMesaGL: + InitializeGLExtensionBindingsGL(context); + InitializeGLExtensionBindingsOSMESA(context); + break; + case kGLImplementationEGLGLES2: + InitializeGLExtensionBindingsGL(context); + InitializeGLExtensionBindingsEGL(context); + break; + case kGLImplementationDesktopGL: + InitializeGLExtensionBindingsGL(context); + InitializeGLExtensionBindingsWGL(context); + break; + case kGLImplementationMockGL: + InitializeGLExtensionBindingsGL(context); + break; + default: + return false; + } + + return true; +} + +void InitializeDebugGLBindings() { + InitializeDebugGLBindingsEGL(); + InitializeDebugGLBindingsGL(); + InitializeDebugGLBindingsOSMESA(); + InitializeDebugGLBindingsWGL(); +} + +void ClearGLBindings() { + ClearGLBindingsEGL(); + ClearGLBindingsGL(); + ClearGLBindingsOSMESA(); + ClearGLBindingsWGL(); + SetGLImplementation(kGLImplementationNone); + + UnloadGLNativeLibraries(); + UnloadD3DXLibraries(NULL); +} + +} // namespace gfx diff --git a/ui/gl/gl_interface.cc b/ui/gl/gl_interface.cc new file mode 100644 index 0000000..0cb61e7 --- /dev/null +++ b/ui/gl/gl_interface.cc @@ -0,0 +1,20 @@ +// 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_interface.h" + +namespace gfx { + +GLInterface* GLInterface::interface_; + +void GLInterface::SetGLInterface(GLInterface* gl_interface) { + interface_ = gl_interface; +} + +GLInterface* GLInterface::GetGLInterface() { + return interface_; +} + +} // namespace gfx + diff --git a/ui/gl/gl_interface.h b/ui/gl/gl_interface.h new file mode 100644 index 0000000..db120b6 --- /dev/null +++ b/ui/gl/gl_interface.h @@ -0,0 +1,640 @@ +// 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. + +#ifndef UI_GL_GL_INTERFACE_H_ +#define UI_GL_GL_INTERFACE_H_ +#pragma once + +// This file implements glue to a GL interface so we can mock it for unit +// testing. It has to be Desktop GL, not GLES2 as it is used to test the service +// side code. + +#include "ui/gl/gl_bindings.h" + +namespace gfx { + +class GL_EXPORT GLInterface { + public: + virtual ~GLInterface() {} + + static void SetGLInterface(GLInterface* gl_interface); + + static GLInterface* GetGLInterface(); + + virtual void ActiveTexture(GLenum texture) = 0; + + virtual void AttachShader(GLuint program, + GLuint shader) = 0; + + virtual void BeginQuery(GLenum target, GLuint id) = 0; + + virtual void BeginQueryARB(GLenum target, GLuint id) = 0; + + virtual void BindAttribLocation(GLuint program, + GLuint index, + const char* name) = 0; + + virtual void BindBuffer(GLenum target, GLuint buffer) = 0; + + virtual void BindFragDataLocationIndexed(GLuint program, + GLuint colorNumber, + GLuint index, + const char* name) = 0; + + virtual void BindFragDataLocation(GLuint program, + GLuint colorNumber, + const char* name) = 0; + + virtual void BindFramebufferEXT(GLenum target, GLuint framebuffer) = 0; + + virtual void BindRenderbufferEXT(GLenum target, GLuint renderbuffer) = 0; + + virtual void BindTexture(GLenum target, GLuint texture) = 0; + + virtual void BlendColor(GLclampf red, + GLclampf green, + GLclampf blue, + GLclampf alpha) = 0; + + virtual void BlendEquation(GLenum mode) = 0; + + virtual void BlendEquationSeparate(GLenum modeRGB, + GLenum modeAlpha) = 0; + + virtual void BlendFunc(GLenum sfactor, GLenum dfactor) = 0; + + virtual void BlendFuncSeparate(GLenum srcRGB, + GLenum dstRGB, + GLenum srcAlpha, + GLenum dstAlpha) = 0; + + virtual void BlitFramebufferANGLE( + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) = 0; + + virtual void BlitFramebufferEXT( + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) = 0; + + virtual void BufferData(GLenum target, + GLsizeiptr size, + const void* data, + GLenum usage) = 0; + + virtual void BufferSubData(GLenum target, + GLintptr offset, + GLsizeiptr size, + const void* data) = 0; + + virtual GLenum CheckFramebufferStatusEXT(GLenum target) = 0; + + virtual void Clear(GLbitfield mask) = 0; + + virtual void ClearColor(GLclampf red, + GLclampf green, + GLclampf blue, + GLclampf alpha) = 0; + + virtual void ClearDepth(GLclampd depth) = 0; + + virtual void ClearDepthf(GLclampf depth) = 0; + + virtual void ClearStencil(GLint s) = 0; + + virtual void ColorMask(GLboolean red, + GLboolean green, + GLboolean blue, + GLboolean alpha) = 0; + + virtual void CompileShader(GLuint shader) = 0; + + virtual void CompressedTexImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, GLsizei height, + GLint border, + GLsizei imageSize, + const void* data) = 0; + + virtual void CompressedTexSubImage2D(GLenum target, + GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, + GLsizei imageSize, + const void* data) = 0; + + virtual void CopyTexImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLint x, GLint y, + GLsizei width, GLsizei height, + GLint border) = 0; + + virtual void CopyTexSubImage2D(GLenum target, + GLint level, + GLint xoffset, GLint yoffset, + GLint x, GLint y, + GLsizei width, GLsizei height) = 0; + + virtual GLuint CreateProgram() = 0; + + virtual GLuint CreateShader(GLenum type) = 0; + + virtual void CullFace(GLenum mode) = 0; + + virtual void DeleteBuffersARB(GLsizei n, const GLuint* buffers) = 0; + + virtual void DeleteFramebuffersEXT(GLsizei n, const GLuint* framebuffers) = 0; + + virtual void DeleteProgram(GLuint program) = 0; + + virtual void DeleteRenderbuffersEXT(GLsizei n, + const GLuint* renderbuffers) = 0; + + virtual void DeleteQueries(GLsizei n, const GLuint* ids) = 0; + + virtual void DeleteQueriesARB(GLsizei n, const GLuint* ids) = 0; + + virtual void DeleteShader(GLuint shader) = 0; + + virtual void DeleteTextures(GLsizei n, const GLuint* textures) = 0; + + virtual void DepthFunc(GLenum func) = 0; + + virtual void DepthMask(GLboolean flag) = 0; + + virtual void DepthRange(GLclampd zNear, GLclampd zFar) = 0; + + virtual void DepthRangef(GLclampf zNear, GLclampf zFar) = 0; + + virtual void DetachShader(GLuint program, GLuint shader) = 0; + + virtual void Disable(GLenum cap) = 0; + + virtual void DisableVertexAttribArray(GLuint index) = 0; + + virtual void DrawArrays(GLenum mode, GLint first, GLsizei count) = 0; + + virtual void DrawBuffer(GLenum mode) = 0; + + virtual void DrawBuffersARB(GLsizei n, const GLenum* bufs) = 0; + + virtual void DrawElements(GLenum mode, + GLsizei count, + GLenum type, + const void* indices) = 0; + + virtual void EGLImageTargetTexture2DOES( + GLenum target, GLeglImageOES image) = 0; + + virtual void EGLImageTargetRenderbufferStorageOES( + GLenum target, GLeglImageOES image) = 0; + + virtual void Enable(GLenum cap) = 0; + + virtual void EnableVertexAttribArray(GLuint index) = 0; + + virtual void EndQuery(GLenum target) = 0; + + virtual void EndQueryARB(GLenum target) = 0; + + virtual void Finish() = 0; + + virtual void Flush() = 0; + + virtual void FramebufferRenderbufferEXT(GLenum target, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer) = 0; + + virtual void FramebufferTexture2DEXT(GLenum target, + GLenum attachment, + GLenum textarget, + GLuint texture, + GLint level) = 0; + + virtual void FrontFace(GLenum mode) = 0; + + virtual void GenBuffersARB(GLsizei n, GLuint* buffers) = 0; + + virtual void GenerateMipmapEXT(GLenum target) = 0; + + virtual void GenFramebuffersEXT(GLsizei n, GLuint* framebuffers) = 0; + + virtual void GenQueries(GLsizei n, GLuint* ids) = 0; + + virtual void GenQueriesARB(GLsizei n, GLuint* ids) = 0; + + virtual void GenRenderbuffersEXT(GLsizei n, GLuint* renderbuffers) = 0; + + virtual void GenTextures(GLsizei n, GLuint* textures) = 0; + + virtual void GetActiveAttrib(GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei* length, + GLint* size, + GLenum* type, + char* name) = 0; + + virtual void GetActiveUniform(GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei* length, + GLint* size, + GLenum* type, + char* name) = 0; + + virtual void GetAttachedShaders(GLuint program, + GLsizei maxcount, + GLsizei* count, + GLuint* shaders) = 0; + + virtual GLint GetAttribLocation(GLuint program, const char* name) = 0; + + virtual void GetBooleanv(GLenum pname, GLboolean* params) = 0; + + virtual void GetBufferParameteriv(GLenum target, + GLenum pname, + GLint* params) = 0; + + virtual GLenum GetError() = 0; + + virtual void GetFloatv(GLenum pname, GLfloat* params) = 0; + + virtual void GetFramebufferAttachmentParameterivEXT(GLenum target, + GLenum attachment, + GLenum pname, + GLint* params) = 0; + + virtual void GetIntegerv(GLenum pname, GLint* params) = 0; + + virtual void GetProgramiv(GLuint program, GLenum pname, GLint* params) = 0; + + // TODO(gman): Implement this + virtual void GetProgramInfoLog(GLuint program, + GLsizei bufsize, + GLsizei* length, + char* infolog) = 0; + + virtual void GetQueryiv(GLenum target, GLenum pname, GLint* params) = 0; + + virtual void GetQueryivARB(GLenum target, GLenum pname, GLint* params) = 0; + + virtual void GetQueryObjecti64v(GLuint id, GLenum pname, GLint64* params) = 0; + + virtual void GetQueryObjectiv(GLuint id, GLenum pname, GLint* params) = 0; + + virtual void GetQueryObjectui64v(GLuint id, + GLenum pname, + GLuint64* params) = 0; + + virtual void GetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) = 0; + + virtual void GetQueryObjectuivARB(GLuint id, + GLenum pname, + GLuint* params) = 0; + + virtual void GetRenderbufferParameterivEXT(GLenum target, + GLenum pname, + GLint* params) = 0; + + virtual void GetShaderiv(GLuint shader, GLenum pname, GLint* params) = 0; + + // TODO(gman): Implement this + virtual void GetShaderInfoLog(GLuint shader, + GLsizei bufsize, + GLsizei* length, + char* infolog) = 0; + + virtual void GetShaderPrecisionFormat(GLenum shadertype, + GLenum precisiontype, + GLint* range, + GLint* precision) = 0; + + // TODO(gman): Implement this + virtual void GetShaderSource(GLuint shader, + GLsizei bufsize, + GLsizei* length, + char* source) = 0; + + virtual const GLubyte* GetString(GLenum name) = 0; + + virtual void GetTexLevelParameterfv(GLenum target, + GLint level, + GLenum pname, + GLfloat* params) = 0; + + virtual void GetTexLevelParameteriv(GLenum target, + GLint level, + GLenum pname, + GLint* params) = 0; + + virtual void GetTexParameterfv(GLenum target, + GLenum pname, + GLfloat* params) = 0; + + virtual void GetTexParameteriv(GLenum target, + GLenum pname, + GLint* params) = 0; + + virtual void GetTranslatedShaderSourceANGLE(GLuint shader, + GLsizei bufsize, + GLsizei* length, + char* source) = 0; + + virtual void GetUniformfv(GLuint program, + GLint location, + GLfloat* params) = 0; + + virtual void GetUniformiv(GLuint program, + GLint location, + GLint* params) = 0; + + virtual GLint GetUniformLocation(GLuint program, const char* name) = 0; + + virtual void GetVertexAttribfv(GLuint index, + GLenum pname, + GLfloat* params) = 0; + + virtual void GetVertexAttribiv(GLuint index, + GLenum pname, + GLint* params) = 0; + + virtual void GetVertexAttribPointerv(GLuint index, + GLenum pname, + void** pointer) = 0; + + virtual void Hint(GLenum target, GLenum mode) = 0; + + virtual GLboolean IsBuffer(GLuint buffer) = 0; + + virtual GLboolean IsEnabled(GLenum cap) = 0; + + virtual GLboolean IsFramebufferEXT(GLuint framebuffer) = 0; + + virtual GLboolean IsProgram(GLuint program) = 0; + + virtual GLboolean IsQueryARB(GLuint query) = 0; + + virtual GLboolean IsRenderbufferEXT(GLuint renderbuffer) = 0; + + virtual GLboolean IsShader(GLuint shader) = 0; + + virtual GLboolean IsTexture(GLuint texture) = 0; + + virtual void* MapBuffer(GLenum target, GLenum access) = 0; + + virtual void LineWidth(GLfloat width) = 0; + + virtual void LinkProgram(GLuint program) = 0; + + virtual void PixelStorei(GLenum pname, GLint param) = 0; + + virtual void PolygonOffset(GLfloat factor, GLfloat units) = 0; + + virtual void QueryCounter(GLuint id, GLenum target) = 0; + + virtual void ReadBuffer(GLenum src) = 0; + + virtual void ReadPixels(GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, + GLenum type, + void* pixels) = 0; + + virtual void ReleaseShaderCompiler(void) = 0; + + virtual void RenderbufferStorageEXT(GLenum target, + GLenum internalformat, + GLsizei width, GLsizei height) = 0; + + virtual void RenderbufferStorageMultisampleANGLE(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) = 0; + + virtual void RenderbufferStorageMultisampleEXT(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) = 0; + + virtual void SampleCoverage(GLclampf value, GLboolean invert) = 0; + + virtual void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) = 0; + + virtual void ShaderBinary(GLsizei n, + const GLuint* shaders, + GLenum binaryformat, + const void* binary, + GLsizei length) = 0; + + virtual void ShaderSource(GLuint shader, + GLsizei count, + const char** str, + const GLint* length) = 0; + + virtual void StencilFunc(GLenum func, GLint ref, GLuint mask) = 0; + + virtual void StencilFuncSeparate(GLenum face, + GLenum func, + GLint ref, + GLuint mask) = 0; + + virtual void StencilMask(GLuint mask) = 0; + + virtual void StencilMaskSeparate(GLenum face, GLuint mask) = 0; + + virtual void StencilOp(GLenum fail, GLenum zfail, GLenum zpass) = 0; + + virtual void StencilOpSeparate(GLenum face, + GLenum fail, + GLenum zfail, + GLenum zpass) = 0; + + virtual void TexImage2D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void* pixels) = 0; + + virtual void TexParameterf(GLenum target, GLenum pname, GLfloat param) = 0; + + virtual void TexParameterfv(GLenum target, + GLenum pname, + const GLfloat* params) = 0; + + virtual void TexParameteri(GLenum target, GLenum pname, GLint param) = 0; + + virtual void TexParameteriv(GLenum target, + GLenum pname, + const GLint* params) = 0; + + virtual void TexStorage2DEXT(GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height) = 0; + + virtual void TexSubImage2D(GLenum target, + GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, + GLenum type, + const void* pixels) = 0; + + virtual void Uniform1f(GLint location, GLfloat x) = 0; + + virtual void Uniform1fv(GLint location, GLsizei count, const GLfloat* v) = 0; + + virtual void Uniform1i(GLint location, GLint x) = 0; + + virtual void Uniform1iv(GLint location, GLsizei count, const GLint* v) = 0; + + virtual void Uniform2f(GLint location, GLfloat x, GLfloat y) = 0; + + virtual void Uniform2fv(GLint location, GLsizei count, const GLfloat* v) = 0; + + virtual void Uniform2i(GLint location, GLint x, GLint y) = 0; + + virtual void Uniform2iv(GLint location, GLsizei count, const GLint* v) = 0; + + virtual void Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) = 0; + + virtual void Uniform3fv(GLint location, GLsizei count, const GLfloat* v) = 0; + + virtual void Uniform3i(GLint location, GLint x, GLint y, GLint z) = 0; + + virtual void Uniform3iv(GLint location, GLsizei count, const GLint* v) = 0; + + virtual void Uniform4f(GLint location, + GLfloat x, + GLfloat y, + GLfloat z, + GLfloat w) = 0; + + virtual void Uniform4fv(GLint location, GLsizei count, const GLfloat* v) = 0; + + virtual void Uniform4i(GLint location, + GLint x, + GLint y, + GLint z, + GLint w) = 0; + + virtual void Uniform4iv(GLint location, GLsizei count, const GLint* v) = 0; + + virtual void UniformMatrix2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat* value) = 0; + + virtual void UniformMatrix3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat* value) = 0; + + virtual void UniformMatrix4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat* value) = 0; + + virtual GLboolean UnmapBuffer(GLenum target) = 0; + + virtual void UseProgram(GLuint program) = 0; + + virtual void ValidateProgram(GLuint program) = 0; + + virtual void VertexAttrib1f(GLuint indx, GLfloat x) = 0; + + virtual void VertexAttrib1fv(GLuint indx, const GLfloat* values) = 0; + + virtual void VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) = 0; + + virtual void VertexAttrib2fv(GLuint indx, const GLfloat* values) = 0; + + virtual void VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) = 0; + + virtual void VertexAttrib3fv(GLuint indx, const GLfloat* values) = 0; + + virtual void VertexAttrib4f(GLuint indx, + GLfloat x, + GLfloat y, + GLfloat z, + GLfloat w) = 0; + + virtual void VertexAttrib4fv(GLuint indx, const GLfloat* values) = 0; + + virtual void VertexAttribPointer(GLuint indx, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void* ptr) = 0; + + virtual void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) = 0; + + virtual void SwapBuffers() = 0; + + virtual GLuint GetMaxValueInBufferCHROMIUM(GLuint buffer_id, + GLsizei count, + GLenum type, + GLuint offset) = 0; + + virtual void GenFencesNV(GLsizei n, GLuint *fences) = 0; + + virtual void DeleteFencesNV(GLsizei n, const GLuint *fences) = 0; + + virtual void SetFenceNV(GLuint fence, GLenum condition) = 0; + + virtual GLboolean TestFenceNV(GLuint fence) = 0; + + virtual void FinishFenceNV(GLuint fence) = 0; + + virtual GLboolean IsFenceNV(GLuint fence) = 0; + + virtual void GetFenceivNV(GLuint fence, GLenum pname, GLint *params) = 0; + + virtual void SetSurfaceCHROMIUM(GLuint id) = 0; + + virtual GLenum GetGraphicsResetStatusARB() = 0; + + virtual GLsync FenceSync(GLenum condition, GLbitfield flags) = 0; + + virtual void DeleteSync(GLsync sync) = 0; + + virtual void GetSynciv(GLsync sync, + GLenum pname, + GLsizei bufSize, + GLsizei* length, + GLint* values) = 0; + + virtual void DrawArraysInstancedANGLE(GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount) = 0; + + virtual void DrawElementsInstancedANGLE(GLenum mode, + GLsizei count, + GLenum type, + const void* indices, + GLsizei primcount) = 0; + + virtual void VertexAttribDivisorANGLE(GLuint index, GLuint divisor) = 0; + + private: + static GLInterface* interface_; +}; + +} // namespace gfx + +#endif // UI_GL_GL_INTERFACE_H_ diff --git a/ui/gl/gl_share_group.cc b/ui/gl/gl_share_group.cc new file mode 100644 index 0000000..8ab0cc7 --- /dev/null +++ b/ui/gl/gl_share_group.cc @@ -0,0 +1,44 @@ +// 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_share_group.h" + +#include "ui/gl/gl_context.h" + +namespace gfx { + +GLShareGroup::GLShareGroup() { +} + +void GLShareGroup::AddContext(GLContext* context) { + contexts_.insert(context); +} + +void GLShareGroup::RemoveContext(GLContext* context) { + contexts_.erase(context); +} + +void* GLShareGroup::GetHandle() { + GLContext* context = GetContext(); + if (context) + return context->GetHandle(); + + return NULL; +} + +GLContext* GLShareGroup::GetContext() { + for (ContextSet::iterator it = contexts_.begin(); + it != contexts_.end(); + ++it) { + if ((*it)->GetHandle()) + return *it; + } + + return NULL; +} + +GLShareGroup::~GLShareGroup() { +} + +} // namespace gfx diff --git a/ui/gl/gl_share_group.h b/ui/gl/gl_share_group.h new file mode 100644 index 0000000..2b39ba5 --- /dev/null +++ b/ui/gl/gl_share_group.h @@ -0,0 +1,52 @@ +// 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. + +#ifndef UI_GL_GL_SHARE_GROUP_H_ +#define UI_GL_GL_SHARE_GROUP_H_ +#pragma once + +#include <set> + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "ui/gl/gl_export.h" + +namespace gfx { + +class GLContext; + +// A group of GL contexts that share an ID namespace. +class GL_EXPORT GLShareGroup : public base::RefCounted<GLShareGroup> { + public: + GLShareGroup(); + + // These two should only be called from the constructor and destructor of + // GLContext. + void AddContext(GLContext* context); + void RemoveContext(GLContext* context); + + // Returns a handle to any initialized context in the share group or NULL if + // there are no initialized contexts in the share group. + void* GetHandle(); + + // Returns a pointer to any initialized context in the share group + // or NULL if there are no initialized contexts in the share group. + GLContext* GetContext(); + + private: + friend class base::RefCounted<GLShareGroup>; + + ~GLShareGroup(); + + // References to GLContext are by raw pointer to avoid a reference count + // cycle. + typedef std::set<GLContext*> ContextSet; + ContextSet contexts_; + + DISALLOW_COPY_AND_ASSIGN(GLShareGroup); +}; + +} // namespace gfx + +#endif // UI_GL_GL_SHARE_GROUP_H_ diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc new file mode 100644 index 0000000..cc6c3b3 --- /dev/null +++ b/ui/gl/gl_surface.cc @@ -0,0 +1,208 @@ +// 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_surface.h" + +#include <algorithm> +#include <vector> + +#include "base/command_line.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/threading/thread_local.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_implementation.h" + +namespace gfx { + +namespace { +base::LazyInstance<base::ThreadLocalPointer<GLSurface> >::Leaky + current_surface_ = LAZY_INSTANCE_INITIALIZER; +} // namespace + +// static +bool GLSurface::InitializeOneOff() { + static bool initialized = false; + if (initialized) + return true; + + std::vector<GLImplementation> allowed_impls; + GetAllowedGLImplementations(&allowed_impls); + DCHECK(!allowed_impls.empty()); + + // The default implementation is always the first one in list. + GLImplementation impl = allowed_impls[0]; + bool fallback_to_osmesa = false; + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) { + std::string requested_implementation_name = + CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL); + if (requested_implementation_name == "any") { + fallback_to_osmesa = true; + } else if (requested_implementation_name == "swiftshader") { + impl = kGLImplementationEGLGLES2; + } else { + impl = GetNamedGLImplementation(requested_implementation_name); + if (std::find(allowed_impls.begin(), + allowed_impls.end(), + impl) == allowed_impls.end()) { + LOG(ERROR) << "Requested GL implementation is not available."; + return false; + } + } + } + + initialized = InitializeGLBindings(impl) && InitializeOneOffInternal(); + if (!initialized && fallback_to_osmesa) { + ClearGLBindings(); + initialized = InitializeGLBindings(kGLImplementationOSMesaGL) && + InitializeOneOffInternal(); + } + + if (initialized) { + DVLOG(1) << "Using " + << GetGLImplementationName(GetGLImplementation()) + << " GL implementation."; + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableGPUServiceLogging)) + InitializeDebugGLBindings(); + } + return initialized; +} + +GLSurface::GLSurface() {} + +bool GLSurface::Initialize() +{ + return true; +} + +bool GLSurface::Resize(const gfx::Size& size) { + NOTIMPLEMENTED(); + return false; +} + +std::string GLSurface::GetExtensions() { + // Use of GLSurfaceAdapter class means that we can't compare + // GetCurrent() and this directly. + DCHECK_EQ(GetCurrent()->GetHandle(), GetHandle()); + return std::string(""); +} + +unsigned int GLSurface::GetBackingFrameBufferObject() { + return 0; +} + +bool GLSurface::PostSubBuffer(int x, int y, int width, int height) { + return false; +} + +bool GLSurface::OnMakeCurrent(GLContext* context) { + return true; +} + +void GLSurface::SetBufferAllocation(BufferAllocationState state) { +} + +void* GLSurface::GetShareHandle() { + NOTIMPLEMENTED(); + return NULL; +} + +void* GLSurface::GetDisplay() { + NOTIMPLEMENTED(); + return NULL; +} + +void* GLSurface::GetConfig() { + NOTIMPLEMENTED(); + return NULL; +} + +unsigned GLSurface::GetFormat() { + NOTIMPLEMENTED(); + return 0; +} + +GLSurface* GLSurface::GetCurrent() { + return current_surface_.Pointer()->Get(); +} + +GLSurface::~GLSurface() { + if (GetCurrent() == this) + SetCurrent(NULL); +} + +void GLSurface::SetCurrent(GLSurface* surface) { + current_surface_.Pointer()->Set(surface); +} + +GLSurfaceAdapter::GLSurfaceAdapter(GLSurface* surface) : surface_(surface) {} + +bool GLSurfaceAdapter::Initialize() { + return surface_->Initialize(); +} + +void GLSurfaceAdapter::Destroy() { + surface_->Destroy(); +} + +bool GLSurfaceAdapter::Resize(const gfx::Size& size) { + return surface_->Resize(size); +} + +bool GLSurfaceAdapter::IsOffscreen() { + return surface_->IsOffscreen(); +} + +bool GLSurfaceAdapter::SwapBuffers() { + return surface_->SwapBuffers(); +} + +bool GLSurfaceAdapter::PostSubBuffer(int x, int y, int width, int height) { + return surface_->PostSubBuffer(x, y, width, height); +} + +std::string GLSurfaceAdapter::GetExtensions() { + return surface_->GetExtensions(); +} + +gfx::Size GLSurfaceAdapter::GetSize() { + return surface_->GetSize(); +} + +void* GLSurfaceAdapter::GetHandle() { + return surface_->GetHandle(); +} + +unsigned int GLSurfaceAdapter::GetBackingFrameBufferObject() { + return surface_->GetBackingFrameBufferObject(); +} + +bool GLSurfaceAdapter::OnMakeCurrent(GLContext* context) { + return surface_->OnMakeCurrent(context); +} + +void GLSurfaceAdapter::SetBufferAllocation(BufferAllocationState state) { + surface_->SetBufferAllocation(state); +} + +void* GLSurfaceAdapter::GetShareHandle() { + return surface_->GetShareHandle(); +} + +void* GLSurfaceAdapter::GetDisplay() { + return surface_->GetDisplay(); +} + +void* GLSurfaceAdapter::GetConfig() { + return surface_->GetConfig(); +} + +unsigned GLSurfaceAdapter::GetFormat() { + return surface_->GetFormat(); +} + +GLSurfaceAdapter::~GLSurfaceAdapter() {} + +} // namespace gfx diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h new file mode 100644 index 0000000..efa4f23 --- /dev/null +++ b/ui/gl/gl_surface.h @@ -0,0 +1,157 @@ +// 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. + +#ifndef UI_GL_GL_SURFACE_H_ +#define UI_GL_GL_SURFACE_H_ +#pragma once + +#include "base/memory/ref_counted.h" +#include "build/build_config.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/size.h" +#include "ui/gl/gl_export.h" + +namespace gfx { + +class GLContext; + +#if defined(OS_ANDROID) +class AndroidNativeWindow; +#endif + +// Encapsulates a surface that can be rendered to with GL, hiding platform +// specific management. +class GL_EXPORT GLSurface : public base::RefCounted<GLSurface> { + public: + GLSurface(); + + // (Re)create the surface. TODO(apatrick): This is an ugly hack to allow the + // EGL surface associated to be recreated without destroying the associated + // context. The implementation of this function for other GLSurface derived + // classes is in a pending changelist. + virtual bool Initialize(); + + // Destroys the surface. + virtual void Destroy() = 0; + + virtual bool Resize(const gfx::Size& size); + + // Returns true if this surface is offscreen. + virtual bool IsOffscreen() = 0; + + // Swaps front and back buffers. This has no effect for off-screen + // contexts. + virtual bool SwapBuffers() = 0; + + // Get the size of the surface. + virtual gfx::Size GetSize() = 0; + +#if defined(OS_ANDROID) + virtual void SetNativeWindow(AndroidNativeWindow* window) { } +#endif + + // Get the underlying platform specific surface "handle". + virtual void* GetHandle() = 0; + + // Returns space separated list of surface specific extensions. + // The surface must be current. + virtual std::string GetExtensions(); + + // Returns the internal frame buffer object name if the surface is backed by + // FBO. Otherwise returns 0. + virtual unsigned int GetBackingFrameBufferObject(); + + // Copy part of the backbuffer to the frontbuffer. + virtual bool PostSubBuffer(int x, int y, int width, int height); + + static bool InitializeOneOff(); + + // Called after a context is made current with this surface. Returns false + // on error. + virtual bool OnMakeCurrent(GLContext* context); + + // Used for explicit buffer management. Expect buffers to be destroyed only + // when surface is not visible. + enum BufferAllocationState { + BUFFER_ALLOCATION_FRONT_AND_BACK, + BUFFER_ALLOCATION_FRONT_ONLY, + BUFFER_ALLOCATION_NONE + }; + virtual void SetBufferAllocation(BufferAllocationState state); + + // Get a handle used to share the surface with another process. Returns null + // if this is not possible. + virtual void* GetShareHandle(); + + // Get the platform specific display on which this surface resides, if + // available. + virtual void* GetDisplay(); + + // Get the platfrom specific configuration for this surface, if available. + virtual void* GetConfig(); + + // Get the GL pixel format of the surface, if available. + virtual unsigned GetFormat(); + + // Create a GL surface that renders directly to a view. + static scoped_refptr<GLSurface> CreateViewGLSurface( + bool software, + gfx::AcceleratedWidget window); + + // Create a GL surface used for offscreen rendering. + static scoped_refptr<GLSurface> CreateOffscreenGLSurface( + bool software, + const gfx::Size& size); + + static GLSurface* GetCurrent(); + + protected: + virtual ~GLSurface(); + static bool InitializeOneOffInternal(); + static void SetCurrent(GLSurface* surface); + + private: + friend class base::RefCounted<GLSurface>; + friend class GLContext; + + DISALLOW_COPY_AND_ASSIGN(GLSurface); +}; + +// Implementation of GLSurface that forwards all calls through to another +// GLSurface. +class GL_EXPORT GLSurfaceAdapter : public GLSurface { + public: + explicit GLSurfaceAdapter(GLSurface* surface); + + virtual bool Initialize() OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool Resize(const gfx::Size& size) OVERRIDE; + virtual bool IsOffscreen() OVERRIDE; + virtual bool SwapBuffers() OVERRIDE; + virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; + virtual std::string GetExtensions() OVERRIDE; + virtual gfx::Size GetSize() OVERRIDE; + virtual void* GetHandle() OVERRIDE; + virtual unsigned int GetBackingFrameBufferObject() OVERRIDE; + virtual bool OnMakeCurrent(GLContext* context) OVERRIDE; + virtual void SetBufferAllocation(BufferAllocationState state) OVERRIDE; + virtual void* GetShareHandle() OVERRIDE; + virtual void* GetDisplay() OVERRIDE; + virtual void* GetConfig() OVERRIDE; + virtual unsigned GetFormat() OVERRIDE; + + GLSurface* surface() const { return surface_.get(); } + + protected: + virtual ~GLSurfaceAdapter(); + + private: + scoped_refptr<GLSurface> surface_; + + DISALLOW_COPY_AND_ASSIGN(GLSurfaceAdapter); +}; + +} // namespace gfx + +#endif // UI_GL_GL_SURFACE_H_ diff --git a/ui/gl/gl_surface_android.cc b/ui/gl/gl_surface_android.cc new file mode 100644 index 0000000..5500ba0 --- /dev/null +++ b/ui/gl/gl_surface_android.cc @@ -0,0 +1,181 @@ +// 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_surface_android.h" + +#include <EGL/egl.h> + +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "ui/gl/android_native_window.h" +#include "ui/gl/egl_util.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_implementation.h" + +namespace gfx { + +bool GLSurface::InitializeOneOffInternal() { + static bool initialized = false; + if (initialized) + return true; + + switch (GetGLImplementation()) { + case kGLImplementationEGLGLES2: + if (!GLSurfaceEGL::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; + return false; + } + break; + default: + NOTREACHED(); + break; + } + + initialized = true; + return true; +} +// static +scoped_refptr<GLSurface> +GLSurface::CreateViewGLSurface(bool software, gfx::AcceleratedWidget window) { + if (software) + return NULL; + + switch (GetGLImplementation()) { + case kGLImplementationEGLGLES2: { + // window is unused + scoped_refptr<AndroidViewSurface> surface(new AndroidViewSurface()); + if (!surface->Initialize()) + return NULL; + return surface; + } + default: + NOTREACHED(); + return NULL; + } +} + +// static +scoped_refptr<GLSurface> +GLSurface::CreateOffscreenGLSurface(bool software, const gfx::Size& size) { + if (software) + return NULL; + + switch (GetGLImplementation()) { + case kGLImplementationEGLGLES2: { + scoped_refptr<PbufferGLSurfaceEGL> surface( + new PbufferGLSurfaceEGL(false, size)); + if (!surface->Initialize()) + return NULL; + return surface; + } + default: + NOTREACHED(); + return NULL; + } +} + +AndroidViewSurface::AndroidViewSurface() + : NativeViewGLSurfaceEGL(false, 0), + pbuffer_surface_(new PbufferGLSurfaceEGL(false, Size(1, 1))), + window_(NULL) { +} + +AndroidViewSurface::~AndroidViewSurface() { +} + +bool AndroidViewSurface::Initialize() { + DCHECK(pbuffer_surface_.get()); + return pbuffer_surface_->Initialize(); +} + +void AndroidViewSurface::Destroy() { + if (pbuffer_surface_.get()) { + pbuffer_surface_->Destroy(); + } else { + window_ = NULL; + } + NativeViewGLSurfaceEGL::Destroy(); +} + +bool AndroidViewSurface::IsOffscreen() { + return false; +} + +bool AndroidViewSurface::SwapBuffers() { + if (!pbuffer_surface_.get()) + return NativeViewGLSurfaceEGL::SwapBuffers(); + return true; +} + +gfx::Size AndroidViewSurface::GetSize() { + if (pbuffer_surface_.get()) + return pbuffer_surface_->GetSize(); + else + return NativeViewGLSurfaceEGL::GetSize(); +} + +EGLSurface AndroidViewSurface::GetHandle() { + if (pbuffer_surface_.get()) + return pbuffer_surface_->GetHandle(); + else + return NativeViewGLSurfaceEGL::GetHandle(); +} + +bool AndroidViewSurface::Resize(const gfx::Size& size) { + if (pbuffer_surface_.get()) + return pbuffer_surface_->Resize(size); + else if (GetHandle()) { + DCHECK(window_ && window_->GetNativeHandle()); + // Deactivate and restore any currently active context. + EGLContext context = eglGetCurrentContext(); + if (context != EGL_NO_CONTEXT) { + eglMakeCurrent(GetDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + } + NativeViewGLSurfaceEGL::Destroy(); + if (CreateWindowSurface(window_)) { + if (context != EGL_NO_CONTEXT) + eglMakeCurrent(GetDisplay(), GetHandle(), GetHandle(), context); + } + } + return true; +} + +bool AndroidViewSurface::CreateWindowSurface(AndroidNativeWindow* window) { + DCHECK(window->GetNativeHandle()); + window_ = window; + EGLSurface surface = eglCreateWindowSurface(GetDisplay(), + GetConfig(), + window->GetNativeHandle(), + NULL); + if (surface == EGL_NO_SURFACE) { + LOG(ERROR) << "eglCreateWindowSurface failed with error " + << GetLastEGLErrorString(); + Destroy(); + return false; + } + + SetHandle(surface); + return true; +} + +void AndroidViewSurface::SetNativeWindow(AndroidNativeWindow* window) { + if (window->GetNativeHandle()) { + DCHECK(pbuffer_surface_.get()); + pbuffer_surface_->Destroy(); + pbuffer_surface_ = NULL; + + CreateWindowSurface(window); + } else { + DCHECK(GetHandle()); + NativeViewGLSurfaceEGL::Destroy(); + window_ = NULL; + + pbuffer_surface_ = new PbufferGLSurfaceEGL(false, Size(1,1)); + pbuffer_surface_->Initialize(); + } +} + +} // namespace gfx diff --git a/ui/gl/gl_surface_android.h b/ui/gl/gl_surface_android.h new file mode 100644 index 0000000..904274e --- /dev/null +++ b/ui/gl/gl_surface_android.h @@ -0,0 +1,45 @@ +// 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. + +#ifndef UI_GL_GL_SURFACE_ANDROID_H_ +#define UI_GL_GL_SURFACE_ANDROID_H_ +#pragma once + +#include "base/memory/ref_counted.h" +#include "ui/gl/gl_surface_egl.h" + +namespace gfx { + +// A view surface. This can be created in the GPU process (default case), or +// browser process (in-process-gpu), or render process (in-process-webgl). When +// it is initialized, it always uses a pbuffer EGL surface until the native view +// is set. The native view is in charge of sharing the GL texture with UI thread +// in the browser process through SurfaceTexture. +class AndroidViewSurface : public NativeViewGLSurfaceEGL { + public: + AndroidViewSurface(); + virtual ~AndroidViewSurface(); + + // Implement GLSurface. + virtual bool Initialize() OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool Resize(const gfx::Size& size) OVERRIDE; + virtual bool IsOffscreen() OVERRIDE; + virtual bool SwapBuffers() OVERRIDE; + virtual gfx::Size GetSize() OVERRIDE; + virtual EGLSurface GetHandle() OVERRIDE; + virtual void SetNativeWindow(AndroidNativeWindow* window) OVERRIDE; + + private: + bool CreateWindowSurface(AndroidNativeWindow* window); + + scoped_refptr<PbufferGLSurfaceEGL> pbuffer_surface_; + AndroidNativeWindow* window_; + + DISALLOW_COPY_AND_ASSIGN(AndroidViewSurface); +}; + +} // namespace gfx + +#endif // UI_GL_GL_SURFACE_ANDROID_H_ diff --git a/ui/gl/gl_surface_cgl.cc b/ui/gl/gl_surface_cgl.cc new file mode 100644 index 0000000..4f2fba2 --- /dev/null +++ b/ui/gl/gl_surface_cgl.cc @@ -0,0 +1,101 @@ +// 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_surface_cgl.h" + +#include <OpenGL/CGLRenderers.h> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/mac/mac_util.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_implementation.h" + +namespace gfx { + +namespace { +CGLPixelFormatObj g_pixel_format; +} + +GLSurfaceCGL::GLSurfaceCGL() {} + +bool GLSurfaceCGL::InitializeOneOff() { + static bool initialized = false; + if (initialized) + return true; + + // This is called from the sandbox warmup code on Mac OS X. + // GPU-related stuff is very slow without this, probably because + // the sandbox prevents loading graphics drivers or some such. + std::vector<CGLPixelFormatAttribute> attribs; + if (GLContext::SupportsDualGpus()) { + // Avoid switching to the discrete GPU just for this pixel + // format selection. + attribs.push_back(kCGLPFAAllowOfflineRenderers); + } + if (GetGLImplementation() == kGLImplementationAppleGL) { + attribs.push_back(kCGLPFARendererID); + attribs.push_back(static_cast<CGLPixelFormatAttribute>( + kCGLRendererGenericFloatID)); + } + attribs.push_back(static_cast<CGLPixelFormatAttribute>(0)); + + CGLPixelFormatObj format; + GLint num_pixel_formats; + if (CGLChoosePixelFormat(&attribs.front(), + &format, + &num_pixel_formats) != kCGLNoError) { + LOG(ERROR) << "Error choosing pixel format."; + return false; + } + if (!format) { + LOG(ERROR) << "format == 0."; + return false; + } + CGLReleasePixelFormat(format); + DCHECK_NE(num_pixel_formats, 0); + initialized = true; + return true; +} + +void* GLSurfaceCGL::GetPixelFormat() { + return g_pixel_format; +} + +GLSurfaceCGL::~GLSurfaceCGL() {} + +NoOpGLSurfaceCGL::NoOpGLSurfaceCGL(const gfx::Size& size) + : size_(size) { +} + +bool NoOpGLSurfaceCGL::Initialize() { + return true; +} + +void NoOpGLSurfaceCGL::Destroy() { +} + +bool NoOpGLSurfaceCGL::IsOffscreen() { + return true; +} + +bool NoOpGLSurfaceCGL::SwapBuffers() { + NOTREACHED() << "Cannot call SwapBuffers on a NoOpGLSurfaceCGL."; + return false; +} + +gfx::Size NoOpGLSurfaceCGL::GetSize() { + return size_; +} + +void* NoOpGLSurfaceCGL::GetHandle() { + return NULL; +} + +NoOpGLSurfaceCGL::~NoOpGLSurfaceCGL() { + Destroy(); +} + +} // namespace gfx diff --git a/ui/gl/gl_surface_cgl.h b/ui/gl/gl_surface_cgl.h new file mode 100644 index 0000000..00886cf --- /dev/null +++ b/ui/gl/gl_surface_cgl.h @@ -0,0 +1,56 @@ +// 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. + +#ifndef UI_GL_GL_SURFACE_CGL_H_ +#define UI_GL_GL_SURFACE_CGL_H_ +#pragma once + +#include "ui/gfx/size.h" +#include "ui/gl/gl_surface.h" + +namespace gfx { + +// Base class for CGL surfaces. +class GLSurfaceCGL : public GLSurface { + public: + GLSurfaceCGL(); + + static bool InitializeOneOff(); + static void* GetPixelFormat(); + + protected: + virtual ~GLSurfaceCGL(); + + private: + DISALLOW_COPY_AND_ASSIGN(GLSurfaceCGL); +}; + +// A "no-op" surface. It is not required that a CGLContextObj have an +// associated drawable (pbuffer or fullscreen context) in order to be +// made current. Everywhere this surface type is used, we allocate an +// FBO at the user level as the drawable of the associated context. +class GL_EXPORT NoOpGLSurfaceCGL : public GLSurfaceCGL { + public: + explicit NoOpGLSurfaceCGL(const gfx::Size& size); + + // Implement GLSurface. + virtual bool Initialize() OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool IsOffscreen() OVERRIDE; + virtual bool SwapBuffers() OVERRIDE; + virtual gfx::Size GetSize() OVERRIDE; + virtual void* GetHandle() OVERRIDE; + + protected: + virtual ~NoOpGLSurfaceCGL(); + + private: + gfx::Size size_; + + DISALLOW_COPY_AND_ASSIGN(NoOpGLSurfaceCGL); +}; + +} // namespace gfx + +#endif // UI_GL_GL_SURFACE_CGL_H_ diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc new file mode 100644 index 0000000..f3d3e0f --- /dev/null +++ b/ui/gl/gl_surface_egl.cc @@ -0,0 +1,398 @@ +// 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_surface_egl.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "build/build_config.h" +#if !defined(OS_ANDROID) +#include "third_party/angle/include/EGL/egl.h" +#include "third_party/angle/include/EGL/eglext.h" +#endif +#include "ui/gl/egl_util.h" +#include "ui/gl/gl_context.h" + +#if defined(OS_ANDROID) +#include <EGL/egl.h> +#endif + +// This header must come after the above third-party include, as +// it brings in #defines that cause conflicts. +#include "ui/gl/gl_bindings.h" + +#if defined(USE_X11) +extern "C" { +#include <X11/Xlib.h> +} +#endif + +namespace gfx { + +namespace { +EGLConfig g_config; +EGLDisplay g_display; +EGLNativeDisplayType g_native_display; +EGLConfig g_software_config; +EGLDisplay g_software_display; +EGLNativeDisplayType g_software_native_display; +} + +GLSurfaceEGL::GLSurfaceEGL() : software_(false) { +} + +GLSurfaceEGL::~GLSurfaceEGL() { +} + +bool GLSurfaceEGL::InitializeOneOff() { + static bool initialized = false; + if (initialized) + return true; + +#if defined(USE_X11) + g_native_display = base::MessagePumpForUI::GetDefaultXDisplay(); +#else + g_native_display = EGL_DEFAULT_DISPLAY; +#endif + g_display = eglGetDisplay(g_native_display); + if (!g_display) { + LOG(ERROR) << "eglGetDisplay failed with error " << GetLastEGLErrorString(); + return false; + } + + if (!eglInitialize(g_display, NULL, NULL)) { + LOG(ERROR) << "eglInitialize failed with error " << GetLastEGLErrorString(); + return false; + } + + // Choose an EGL configuration. + static const EGLint kConfigAttribs[] = { + EGL_BUFFER_SIZE, 32, + EGL_ALPHA_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_RED_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + EGL_NONE + }; + + EGLint num_configs; + if (!eglChooseConfig(g_display, + kConfigAttribs, + NULL, + 0, + &num_configs)) { + LOG(ERROR) << "eglChooseConfig failed failed with error " + << GetLastEGLErrorString(); + return false; + } + + if (num_configs == 0) { + LOG(ERROR) << "No suitable EGL configs found."; + return false; + } + + if (!eglChooseConfig(g_display, + kConfigAttribs, + &g_config, + 1, + &num_configs)) { + LOG(ERROR) << "eglChooseConfig failed with error " + << GetLastEGLErrorString(); + return false; + } + + initialized = true; + +#if defined(USE_X11) || defined(OS_ANDROID) + return true; +#else + g_software_native_display = EGL_SOFTWARE_DISPLAY_ANGLE; +#endif + g_software_display = eglGetDisplay(g_software_native_display); + if (!g_software_display) { + return true; + } + + if (!eglInitialize(g_software_display, NULL, NULL)) { + return true; + } + + if (!eglChooseConfig(g_software_display, + kConfigAttribs, + NULL, + 0, + &num_configs)) { + g_software_display = NULL; + return true; + } + + if (num_configs == 0) { + g_software_display = NULL; + return true; + } + + if (!eglChooseConfig(g_software_display, + kConfigAttribs, + &g_software_config, + 1, + &num_configs)) { + g_software_display = NULL; + return false; + } + + return true; +} + +EGLDisplay GLSurfaceEGL::GetDisplay() { + return software_ ? g_software_display : g_display; +} + +EGLConfig GLSurfaceEGL::GetConfig() { + return software_ ? g_software_config : g_config; +} + +EGLDisplay GLSurfaceEGL::GetHardwareDisplay() { + return g_display; +} + +EGLDisplay GLSurfaceEGL::GetSoftwareDisplay() { + return g_software_display; +} + +EGLNativeDisplayType GLSurfaceEGL::GetNativeDisplay() { + return g_native_display; +} + +NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(bool software, + gfx::AcceleratedWidget window) + : window_(window), + surface_(NULL), + supports_post_sub_buffer_(false) +{ + software_ = software; +} + +NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() { + Destroy(); +} + +bool NativeViewGLSurfaceEGL::Initialize() { +#if defined(OS_ANDROID) + NOTREACHED(); + return false; +#else + DCHECK(!surface_); + + if (!GetDisplay()) { + LOG(ERROR) << "Trying to create surface with invalid display."; + return false; + } + + static const EGLint egl_window_attributes_sub_buffer[] = { + EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_TRUE, + EGL_NONE + }; + + // Create a surface for the native window. + surface_ = eglCreateWindowSurface(GetDisplay(), + GetConfig(), + window_, + gfx::g_EGL_NV_post_sub_buffer ? + egl_window_attributes_sub_buffer : + NULL); + + if (!surface_) { + LOG(ERROR) << "eglCreateWindowSurface failed with error " + << GetLastEGLErrorString(); + Destroy(); + return false; + } + + EGLint surfaceVal; + EGLBoolean retVal = eglQuerySurface(GetDisplay(), + surface_, + EGL_POST_SUB_BUFFER_SUPPORTED_NV, + &surfaceVal); + supports_post_sub_buffer_ = (surfaceVal && retVal) == EGL_TRUE; + + return true; +#endif +} + +void NativeViewGLSurfaceEGL::Destroy() { + if (surface_) { + if (!eglDestroySurface(GetDisplay(), surface_)) { + LOG(ERROR) << "eglDestroySurface failed with error " + << GetLastEGLErrorString(); + } + surface_ = NULL; + } +} + +bool NativeViewGLSurfaceEGL::IsOffscreen() { + return false; +} + +bool NativeViewGLSurfaceEGL::SwapBuffers() { + if (!eglSwapBuffers(GetDisplay(), surface_)) { + DVLOG(1) << "eglSwapBuffers failed with error " + << GetLastEGLErrorString(); + return false; + } + + return true; +} + +gfx::Size NativeViewGLSurfaceEGL::GetSize() { + EGLint width; + EGLint height; + if (!eglQuerySurface(GetDisplay(), surface_, EGL_WIDTH, &width) || + !eglQuerySurface(GetDisplay(), surface_, EGL_HEIGHT, &height)) { + NOTREACHED() << "eglQuerySurface failed with error " + << GetLastEGLErrorString(); + return gfx::Size(); + } + + return gfx::Size(width, height); +} + +EGLSurface NativeViewGLSurfaceEGL::GetHandle() { + return surface_; +} + +std::string NativeViewGLSurfaceEGL::GetExtensions() { + std::string extensions = GLSurface::GetExtensions(); + if (supports_post_sub_buffer_) { + extensions += extensions.empty() ? "" : " "; + extensions += "GL_CHROMIUM_post_sub_buffer"; + } + return extensions; +} + +bool NativeViewGLSurfaceEGL::PostSubBuffer( + int x, int y, int width, int height) { + DCHECK(supports_post_sub_buffer_); + if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) { + DVLOG(1) << "eglPostSubBufferNV failed with error " + << GetLastEGLErrorString(); + return false; + } + return true; +} + +void NativeViewGLSurfaceEGL::SetHandle(EGLSurface surface) { + surface_ = surface; +} + +PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(bool software, const gfx::Size& size) + : size_(size), + surface_(NULL) { + software_ = software; +} + +PbufferGLSurfaceEGL::~PbufferGLSurfaceEGL() { + Destroy(); +} + +bool PbufferGLSurfaceEGL::Initialize() { + DCHECK(!surface_); + + if (!GetDisplay()) { + LOG(ERROR) << "Trying to create surface with invalid display."; + return false; + } + + const EGLint pbuffer_attribs[] = { + EGL_WIDTH, size_.width(), + EGL_HEIGHT, size_.height(), + EGL_NONE + }; + + surface_ = eglCreatePbufferSurface(GetDisplay(), + GetConfig(), + pbuffer_attribs); + if (!surface_) { + LOG(ERROR) << "eglCreatePbufferSurface failed with error " + << GetLastEGLErrorString(); + Destroy(); + return false; + } + + return true; +} + +void PbufferGLSurfaceEGL::Destroy() { + if (surface_) { + if (!eglDestroySurface(GetDisplay(), surface_)) { + LOG(ERROR) << "eglDestroySurface failed with error " + << GetLastEGLErrorString(); + } + surface_ = NULL; + } +} + +bool PbufferGLSurfaceEGL::IsOffscreen() { + return true; +} + +bool PbufferGLSurfaceEGL::SwapBuffers() { + NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL."; + return false; +} + +gfx::Size PbufferGLSurfaceEGL::GetSize() { + return size_; +} + +bool PbufferGLSurfaceEGL::Resize(const gfx::Size& size) { + if (size == size_) + return true; + + GLContext* current_context = GLContext::GetCurrent(); + bool was_current = current_context && current_context->IsCurrent(this); + if (was_current) + current_context->ReleaseCurrent(this); + + Destroy(); + + size_ = size; + + if (!Initialize()) + return false; + + if (was_current) + return current_context->MakeCurrent(this); + + return true; +} + +EGLSurface PbufferGLSurfaceEGL::GetHandle() { + return surface_; +} + +void* PbufferGLSurfaceEGL::GetShareHandle() { +#if defined(OS_ANDROID) + NOTREACHED(); + return NULL; +#else + const char* extensions = eglQueryString(g_display, EGL_EXTENSIONS); + if (!strstr(extensions, "EGL_ANGLE_query_surface_pointer")) + return NULL; + + void* handle; + if (!eglQuerySurfacePointerANGLE(g_display, + GetHandle(), + EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, + &handle)) { + return NULL; + } + + return handle; +#endif +} + +} // namespace gfx diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h new file mode 100644 index 0000000..423ef06 --- /dev/null +++ b/ui/gl/gl_surface_egl.h @@ -0,0 +1,106 @@ +// 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. + +#ifndef UI_GL_GL_SURFACE_EGL_H_ +#define UI_GL_GL_SURFACE_EGL_H_ +#pragma once + +#if defined(OS_WIN) +#include <windows.h> +#endif + +#include "base/compiler_specific.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/size.h" +#include "ui/gl/gl_surface.h" + +typedef void* EGLConfig; +typedef void* EGLDisplay; +typedef void* EGLSurface; + +#if defined(OS_ANDROID) +typedef void* EGLNativeDisplayType; +#elif defined(OS_WIN) +typedef HDC EGLNativeDisplayType; +#else +typedef struct _XDisplay* EGLNativeDisplayType; +#endif + +namespace gfx { + +// Interface for EGL surface. +class GL_EXPORT GLSurfaceEGL : public GLSurface { + public: + GLSurfaceEGL(); + virtual ~GLSurfaceEGL(); + + // Implement GLSurface. + virtual EGLDisplay GetDisplay() OVERRIDE; + virtual EGLConfig GetConfig() OVERRIDE; + + static bool InitializeOneOff(); + static EGLDisplay GetHardwareDisplay(); + static EGLDisplay GetSoftwareDisplay(); + static EGLNativeDisplayType GetNativeDisplay(); + + protected: + bool software_; + + private: + DISALLOW_COPY_AND_ASSIGN(GLSurfaceEGL); +}; + +// Encapsulates an EGL surface bound to a view. +class NativeViewGLSurfaceEGL : public GLSurfaceEGL { + public: + NativeViewGLSurfaceEGL(bool software, gfx::AcceleratedWidget window); + virtual ~NativeViewGLSurfaceEGL(); + + // Implement GLSurface. + virtual bool Initialize() OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool IsOffscreen() OVERRIDE; + virtual bool SwapBuffers() OVERRIDE; + virtual gfx::Size GetSize() OVERRIDE; + virtual EGLSurface GetHandle() OVERRIDE; + virtual std::string GetExtensions() OVERRIDE; + virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; + + protected: + void SetHandle(EGLSurface surface); + + private: + gfx::AcceleratedWidget window_; + EGLSurface surface_; + bool supports_post_sub_buffer_; + + DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceEGL); +}; + +// Encapsulates a pbuffer EGL surface. +class GL_EXPORT PbufferGLSurfaceEGL : public GLSurfaceEGL { + public: + PbufferGLSurfaceEGL(bool software, const gfx::Size& size); + virtual ~PbufferGLSurfaceEGL(); + + // Implement GLSurface. + virtual bool Initialize() OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool IsOffscreen() OVERRIDE; + virtual bool SwapBuffers() OVERRIDE; + virtual gfx::Size GetSize() OVERRIDE; + virtual bool Resize(const gfx::Size& size) OVERRIDE; + virtual EGLSurface GetHandle() OVERRIDE; + virtual void* GetShareHandle() OVERRIDE; + + private: + gfx::Size size_; + EGLSurface surface_; + + DISALLOW_COPY_AND_ASSIGN(PbufferGLSurfaceEGL); +}; + +} // namespace gfx + +#endif // UI_GL_GL_SURFACE_EGL_H_ diff --git a/ui/gl/gl_surface_glx.cc b/ui/gl/gl_surface_glx.cc new file mode 100644 index 0000000..ba8ce92 --- /dev/null +++ b/ui/gl/gl_surface_glx.cc @@ -0,0 +1,326 @@ +// 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. + +extern "C" { +#include <X11/Xlib.h> +} + +#include "ui/gl/gl_surface_glx.h" + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "base/process_util.h" +#include "third_party/mesa/MesaLib/include/GL/osmesa.h" +#include "ui/base/x/x11_util.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_implementation.h" + +namespace gfx { + +namespace { + +// scoped_ptr functor for XFree(). Use as follows: +// scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...); +// where "XVisualInfo" is any X type that is freed with XFree. +class ScopedPtrXFree { + public: + void operator()(void* x) const { + ::XFree(x); + } +}; + +Display* g_display; +const char* g_glx_extensions = NULL; +bool g_glx_create_context_robustness_supported = false; + +} // namespace anonymous + +GLSurfaceGLX::GLSurfaceGLX() { +} + +GLSurfaceGLX::~GLSurfaceGLX() { +} + +bool GLSurfaceGLX::InitializeOneOff() { + static bool initialized = false; + if (initialized) + return true; + + g_display = base::MessagePumpForUI::GetDefaultXDisplay(); + if (!g_display) { + LOG(ERROR) << "XOpenDisplay failed."; + return false; + } + + int major, minor; + if (!glXQueryVersion(g_display, &major, &minor)) { + LOG(ERROR) << "glxQueryVersion failed"; + return false; + } + + if (major == 1 && minor < 3) { + LOG(ERROR) << "GLX 1.3 or later is required."; + return false; + } + + g_glx_extensions = glXQueryExtensionsString(g_display, 0); + g_glx_create_context_robustness_supported = + HasGLXExtension("GLX_ARB_create_context_robustness"); + + initialized = true; + return true; +} + +// static +const char* GLSurfaceGLX::GetGLXExtensions() { + return g_glx_extensions; +} + +// static +bool GLSurfaceGLX::HasGLXExtension(const char* name) { + DCHECK(name); + const char* c_extensions = GetGLXExtensions(); + if (!c_extensions) + return false; + std::string extensions(c_extensions); + extensions += " "; + + std::string delimited_name(name); + delimited_name += " "; + + return extensions.find(delimited_name) != std::string::npos; +} + +// static +bool GLSurfaceGLX::IsCreateContextRobustnessSupported() { + return g_glx_create_context_robustness_supported; +} + +void* GLSurfaceGLX::GetDisplay() { + return g_display; +} + +NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window) + : window_(window), + config_(NULL) { +} + +NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX() + : window_(0), + config_(NULL) { +} + +NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() { + Destroy(); +} + +bool NativeViewGLSurfaceGLX::Initialize() { + XWindowAttributes attributes; + if (!XGetWindowAttributes(g_display, window_, &attributes)) { + LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; + return false; + } + size_ = gfx::Size(attributes.width, attributes.height); + return true; +} + +void NativeViewGLSurfaceGLX::Destroy() { +} + +bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size) { + // On Intel drivers, the frame buffer won't be resize until the next swap. If + // we only do PostSubBuffer, then we're stuck in the old size. Force a swap + // now. + if (gfx::g_GLX_MESA_copy_sub_buffer && size_ != size) + SwapBuffers(); + size_ = size; + return true; +} + +bool NativeViewGLSurfaceGLX::IsOffscreen() { + return false; +} + +bool NativeViewGLSurfaceGLX::SwapBuffers() { + glXSwapBuffers(g_display, window_); + return true; +} + +gfx::Size NativeViewGLSurfaceGLX::GetSize() { + return size_; +} + +void* NativeViewGLSurfaceGLX::GetHandle() { + return reinterpret_cast<void*>(window_); +} + +std::string NativeViewGLSurfaceGLX::GetExtensions() { + std::string extensions = GLSurface::GetExtensions(); + if (g_GLX_MESA_copy_sub_buffer) { + extensions += extensions.empty() ? "" : " "; + extensions += "GL_CHROMIUM_post_sub_buffer"; + } + return extensions; +} + +void* NativeViewGLSurfaceGLX::GetConfig() { + if (!config_) { + // This code path is expensive, but we only take it when + // attempting to use GLX_ARB_create_context_robustness, in which + // case we need a GLXFBConfig for the window in order to create a + // context for it. + // + // TODO(kbr): this is not a reliable code path. On platforms which + // support it, we should use glXChooseFBConfig in the browser + // process to choose the FBConfig and from there the X Visual to + // use when creating the window in the first place. Then we can + // pass that FBConfig down rather than attempting to reconstitute + // it. + + XWindowAttributes attributes; + if (!XGetWindowAttributes( + g_display, + reinterpret_cast<GLXDrawable>(GetHandle()), + &attributes)) { + LOG(ERROR) << "XGetWindowAttributes failed for window " << + reinterpret_cast<GLXDrawable>(GetHandle()) << "."; + return NULL; + } + + int visual_id = XVisualIDFromVisual(attributes.visual); + + int num_elements = 0; + scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs( + glXGetFBConfigs(g_display, + DefaultScreen(g_display), + &num_elements)); + if (!configs.get()) { + LOG(ERROR) << "glXGetFBConfigs failed."; + return NULL; + } + if (!num_elements) { + LOG(ERROR) << "glXGetFBConfigs returned 0 elements."; + return NULL; + } + bool found = false; + int i; + for (i = 0; i < num_elements; ++i) { + int value; + if (glXGetFBConfigAttrib( + g_display, configs.get()[i], GLX_VISUAL_ID, &value)) { + LOG(ERROR) << "glXGetFBConfigAttrib failed."; + return NULL; + } + if (value == visual_id) { + found = true; + break; + } + } + if (found) { + config_ = configs.get()[i]; + } + } + + return config_; +} + +bool NativeViewGLSurfaceGLX::PostSubBuffer( + int x, int y, int width, int height) { + DCHECK(g_GLX_MESA_copy_sub_buffer); + glXCopySubBufferMESA(g_display, window_, x, y, width, height); + return true; +} + +PbufferGLSurfaceGLX::PbufferGLSurfaceGLX(const gfx::Size& size) + : size_(size), + config_(NULL), + pbuffer_(0) { +} + +PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() { + Destroy(); +} + +bool PbufferGLSurfaceGLX::Initialize() { + DCHECK(!pbuffer_); + + static const int config_attributes[] = { + GLX_BUFFER_SIZE, 32, + GLX_ALPHA_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_RED_SIZE, 8, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, + GLX_DOUBLEBUFFER, False, + 0 + }; + + int num_elements = 0; + scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs( + glXChooseFBConfig(g_display, + DefaultScreen(g_display), + config_attributes, + &num_elements)); + if (!configs.get()) { + LOG(ERROR) << "glXChooseFBConfig failed."; + return false; + } + if (!num_elements) { + LOG(ERROR) << "glXChooseFBConfig returned 0 elements."; + return false; + } + + config_ = configs.get()[0]; + + const int pbuffer_attributes[] = { + GLX_PBUFFER_WIDTH, size_.width(), + GLX_PBUFFER_HEIGHT, size_.height(), + 0 + }; + pbuffer_ = glXCreatePbuffer(g_display, + static_cast<GLXFBConfig>(config_), + pbuffer_attributes); + if (!pbuffer_) { + Destroy(); + LOG(ERROR) << "glXCreatePbuffer failed."; + return false; + } + + return true; +} + +void PbufferGLSurfaceGLX::Destroy() { + if (pbuffer_) { + glXDestroyPbuffer(g_display, pbuffer_); + pbuffer_ = 0; + } + + config_ = NULL; +} + +bool PbufferGLSurfaceGLX::IsOffscreen() { + return true; +} + +bool PbufferGLSurfaceGLX::SwapBuffers() { + NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer."; + return false; +} + +gfx::Size PbufferGLSurfaceGLX::GetSize() { + return size_; +} + +void* PbufferGLSurfaceGLX::GetHandle() { + return reinterpret_cast<void*>(pbuffer_); +} + +void* PbufferGLSurfaceGLX::GetConfig() { + return config_; +} + +} // namespace gfx diff --git a/ui/gl/gl_surface_glx.h b/ui/gl/gl_surface_glx.h new file mode 100644 index 0000000..ac4655e --- /dev/null +++ b/ui/gl/gl_surface_glx.h @@ -0,0 +1,98 @@ +// 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. + +#ifndef UI_GL_GL_SURFACE_GLX_H_ +#define UI_GL_GL_SURFACE_GLX_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "ui/base/x/x11_util.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/size.h" +#include "ui/gl/gl_export.h" +#include "ui/gl/gl_surface.h" + +namespace gfx { + +// Base class for GLX surfaces. +class GL_EXPORT GLSurfaceGLX : public GLSurface { + public: + GLSurfaceGLX(); + virtual ~GLSurfaceGLX(); + + static bool InitializeOneOff(); + + // These aren't particularly tied to surfaces, but since we already + // have the static InitializeOneOff here, it's easiest to reuse its + // initialization guards. + static const char* GetGLXExtensions(); + static bool HasGLXExtension(const char* name); + static bool IsCreateContextRobustnessSupported(); + + virtual void* GetDisplay() OVERRIDE; + + // Get the FB config that the surface was created with or NULL if it is not + // a GLX drawable. + virtual void* GetConfig() = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(GLSurfaceGLX); +}; + +// A surface used to render to a view. +class GL_EXPORT NativeViewGLSurfaceGLX : public GLSurfaceGLX { + public: + explicit NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window); + virtual ~NativeViewGLSurfaceGLX(); + + // Implement GLSurfaceGLX. + virtual bool Initialize() OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool Resize(const gfx::Size& size) OVERRIDE; + virtual bool IsOffscreen() OVERRIDE; + virtual bool SwapBuffers() OVERRIDE; + virtual gfx::Size GetSize() OVERRIDE; + virtual void* GetHandle() OVERRIDE; + virtual std::string GetExtensions() OVERRIDE; + virtual void* GetConfig() OVERRIDE; + virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; + + protected: + NativeViewGLSurfaceGLX(); + + gfx::AcceleratedWidget window_; + + private: + void* config_; + gfx::Size size_; + + DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceGLX); +}; + +// A surface used to render to an offscreen pbuffer. +class GL_EXPORT PbufferGLSurfaceGLX : public GLSurfaceGLX { + public: + explicit PbufferGLSurfaceGLX(const gfx::Size& size); + virtual ~PbufferGLSurfaceGLX(); + + // Implement GLSurfaceGLX. + virtual bool Initialize() OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool IsOffscreen() OVERRIDE; + virtual bool SwapBuffers() OVERRIDE; + virtual gfx::Size GetSize() OVERRIDE; + virtual void* GetHandle() OVERRIDE; + virtual void* GetConfig() OVERRIDE; + + private: + gfx::Size size_; + void* config_; + XID pbuffer_; + + DISALLOW_COPY_AND_ASSIGN(PbufferGLSurfaceGLX); +}; + +} // namespace gfx + +#endif // UI_GL_GL_SURFACE_GLX_H_ diff --git a/ui/gl/gl_surface_linux.cc b/ui/gl/gl_surface_linux.cc new file mode 100644 index 0000000..a7dbdf0 --- /dev/null +++ b/ui/gl/gl_surface_linux.cc @@ -0,0 +1,339 @@ +// 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_surface.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "third_party/mesa/MesaLib/include/GL/osmesa.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface_egl.h" +#include "ui/gl/gl_surface_glx.h" +#include "ui/gl/gl_surface_osmesa.h" +#include "ui/gl/gl_surface_stub.h" + +namespace gfx { + +namespace { +Display* g_osmesa_display; +} // namespace anonymous + +// This OSMesa GL surface can use XLib to swap the contents of the buffer to a +// view. +class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa { + public: + explicit NativeViewGLSurfaceOSMesa(gfx::AcceleratedWidget window); + virtual ~NativeViewGLSurfaceOSMesa(); + + static bool InitializeOneOff(); + + // Implement a subset of GLSurface. + virtual bool Initialize() OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool Resize(const gfx::Size& new_size) OVERRIDE; + virtual bool IsOffscreen() OVERRIDE; + virtual bool SwapBuffers() OVERRIDE; + virtual std::string GetExtensions() OVERRIDE; + virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; + + private: + GC window_graphics_context_; + gfx::AcceleratedWidget window_; + GC pixmap_graphics_context_; + Pixmap pixmap_; + + DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa); +}; + +bool GLSurface::InitializeOneOffInternal() { + switch (GetGLImplementation()) { + case kGLImplementationDesktopGL: + if (!GLSurfaceGLX::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceGLX::InitializeOneOff failed."; + return false; + } + break; + case kGLImplementationOSMesaGL: + if (!NativeViewGLSurfaceOSMesa::InitializeOneOff()) { + LOG(ERROR) << "NativeViewGLSurfaceOSMesa::InitializeOneOff failed."; + return false; + } + break; + case kGLImplementationEGLGLES2: + if (!GLSurfaceEGL::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; + return false; + } + break; + default: + break; + } + + return true; +} + +NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa( + gfx::AcceleratedWidget window) + : GLSurfaceOSMesa(OSMESA_BGRA, gfx::Size(1, 1)), + window_graphics_context_(0), + window_(window), + pixmap_graphics_context_(0), + pixmap_(0) { + DCHECK(window); +} + +NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() { + Destroy(); +} + +bool NativeViewGLSurfaceOSMesa::InitializeOneOff() { + static bool initialized = false; + if (initialized) + return true; + + g_osmesa_display = base::MessagePumpForUI::GetDefaultXDisplay(); + if (!g_osmesa_display) { + LOG(ERROR) << "XOpenDisplay failed."; + return false; + } + + initialized = true; + return true; +} + +bool NativeViewGLSurfaceOSMesa::Initialize() { + if (!GLSurfaceOSMesa::Initialize()) + return false; + + window_graphics_context_ = XCreateGC(g_osmesa_display, + window_, + 0, + NULL); + if (!window_graphics_context_) { + LOG(ERROR) << "XCreateGC failed."; + Destroy(); + return false; + } + + return true; +} + +void NativeViewGLSurfaceOSMesa::Destroy() { + if (pixmap_graphics_context_) { + XFreeGC(g_osmesa_display, pixmap_graphics_context_); + pixmap_graphics_context_ = NULL; + } + + if (pixmap_) { + XFreePixmap(g_osmesa_display, pixmap_); + pixmap_ = 0; + } + + if (window_graphics_context_) { + XFreeGC(g_osmesa_display, window_graphics_context_); + window_graphics_context_ = NULL; + } +} + +bool NativeViewGLSurfaceOSMesa::Resize(const gfx::Size& new_size) { + if (!GLSurfaceOSMesa::Resize(new_size)) + return false; + + XWindowAttributes attributes; + if (!XGetWindowAttributes(g_osmesa_display, window_, &attributes)) { + LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; + return false; + } + + // Destroy the previous pixmap and graphics context. + if (pixmap_graphics_context_) { + XFreeGC(g_osmesa_display, pixmap_graphics_context_); + pixmap_graphics_context_ = NULL; + } + if (pixmap_) { + XFreePixmap(g_osmesa_display, pixmap_); + pixmap_ = 0; + } + + // Recreate a pixmap to hold the frame. + pixmap_ = XCreatePixmap(g_osmesa_display, + window_, + new_size.width(), + new_size.height(), + attributes.depth); + if (!pixmap_) { + LOG(ERROR) << "XCreatePixmap failed."; + return false; + } + + // Recreate a graphics context for the pixmap. + pixmap_graphics_context_ = XCreateGC(g_osmesa_display, pixmap_, 0, NULL); + if (!pixmap_graphics_context_) { + LOG(ERROR) << "XCreateGC failed"; + return false; + } + + return true; +} + +bool NativeViewGLSurfaceOSMesa::IsOffscreen() { + return false; +} + +bool NativeViewGLSurfaceOSMesa::SwapBuffers() { + gfx::Size size = GetSize(); + + XWindowAttributes attributes; + if (!XGetWindowAttributes(g_osmesa_display, window_, &attributes)) { + LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; + return false; + } + + // Copy the frame into the pixmap. + ui::PutARGBImage(g_osmesa_display, + attributes.visual, + attributes.depth, + pixmap_, + pixmap_graphics_context_, + static_cast<const uint8*>(GetHandle()), + size.width(), + size.height()); + + // Copy the pixmap to the window. + XCopyArea(g_osmesa_display, + pixmap_, + window_, + window_graphics_context_, + 0, 0, + size.width(), size.height(), + 0, 0); + + return true; +} + +std::string NativeViewGLSurfaceOSMesa::GetExtensions() { + std::string extensions = gfx::GLSurfaceOSMesa::GetExtensions(); + extensions += extensions.empty() ? "" : " "; + extensions += "GL_CHROMIUM_post_sub_buffer"; + return extensions; +} + +bool NativeViewGLSurfaceOSMesa::PostSubBuffer( + int x, int y, int width, int height) { + gfx::Size size = GetSize(); + + // Move (0,0) from lower-left to upper-left + y = size.height() - y - height; + + XWindowAttributes attributes; + if (!XGetWindowAttributes(g_osmesa_display, window_, &attributes)) { + LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; + return false; + } + + // Copy the frame into the pixmap. + ui::PutARGBImage(g_osmesa_display, + attributes.visual, + attributes.depth, + pixmap_, + pixmap_graphics_context_, + static_cast<const uint8*>(GetHandle()), + size.width(), + size.height(), + x, y, + x, y, + width, + height); + + // Copy the pixmap to the window. + XCopyArea(g_osmesa_display, + pixmap_, + window_, + window_graphics_context_, + x, y, + width, height, + x, y); + + return true; +} + +scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface( + bool software, + gfx::AcceleratedWidget window) { + if (software) + return NULL; + + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_refptr<GLSurface> surface( + new NativeViewGLSurfaceOSMesa(window)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationDesktopGL: { + scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceGLX( + window)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationEGLGLES2: { + scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceEGL( + false, window)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationMockGL: + return new GLSurfaceStub; + default: + NOTREACHED(); + return NULL; + } +} + +scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface( + bool software, + const gfx::Size& size) { + if (software) + return NULL; + + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(OSMESA_RGBA, + size)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationDesktopGL: { + scoped_refptr<GLSurface> surface(new PbufferGLSurfaceGLX(size)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationEGLGLES2: { + scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(false, size)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationMockGL: + return new GLSurfaceStub; + default: + NOTREACHED(); + return NULL; + } +} + +} // namespace gfx diff --git a/ui/gl/gl_surface_mac.cc b/ui/gl/gl_surface_mac.cc new file mode 100644 index 0000000..0431628 --- /dev/null +++ b/ui/gl/gl_surface_mac.cc @@ -0,0 +1,95 @@ +// 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_surface.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/mesa/MesaLib/include/GL/osmesa.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface_cgl.h" +#include "ui/gl/gl_surface_osmesa.h" +#include "ui/gl/gl_surface_stub.h" + +#if defined(USE_AURA) +#include "ui/gl/gl_surface_nsview.h" +#endif + +namespace gfx { + +bool GLSurface::InitializeOneOffInternal() { + switch (GetGLImplementation()) { + case kGLImplementationDesktopGL: + case kGLImplementationAppleGL: + if (!GLSurfaceCGL::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceCGL::InitializeOneOff failed."; + return false; + } + break; + default: + break; + } + return true; +} + +scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface( + bool software, + gfx::AcceleratedWidget window) { +#if defined(USE_AURA) + if (software) + return NULL; + + switch (GetGLImplementation()) { + case kGLImplementationDesktopGL: + case kGLImplementationAppleGL: { + scoped_refptr<GLSurface> surface(new GLSurfaceNSView(window)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationMockGL: + return new GLSurfaceStub; + default: + NOTREACHED(); + return NULL; + } +#else + return CreateOffscreenGLSurface(software, gfx::Size(1,1)); +#endif +} + +scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface( + bool software, + const gfx::Size& size) { + if (software) + return NULL; + + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(OSMESA_RGBA, + size)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationDesktopGL: + case kGLImplementationAppleGL: { + scoped_refptr<GLSurface> surface(new NoOpGLSurfaceCGL(size)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationMockGL: + return new GLSurfaceStub; + default: + NOTREACHED(); + return NULL; + } +} + +} // namespace gfx diff --git a/ui/gl/gl_surface_nsview.h b/ui/gl/gl_surface_nsview.h new file mode 100644 index 0000000..440458b --- /dev/null +++ b/ui/gl/gl_surface_nsview.h @@ -0,0 +1,47 @@ +// 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. + +#ifndef UI_GL_GL_SURFACE_NSVIEW_H_ +#define UI_GL_GL_SURFACE_NSVIEW_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "ui/gfx/size.h" +#include "ui/gl/gl_surface.h" + +namespace gfx { + +class GLContextNSView; + +// GLSurfaceNSView provides an implementation of the the GLSurface interface +// that is backed by an NSView. This interface pairs with the GLContextNSView +// class, and the NSView is expected to use this context for drawing. +class GLSurfaceNSView : public GLSurface { + public: + explicit GLSurfaceNSView(AcceleratedWidget view); + virtual ~GLSurfaceNSView(); + + // GLSurface: + virtual void Destroy() OVERRIDE; + virtual bool IsOffscreen() OVERRIDE; + virtual bool SwapBuffers() OVERRIDE; + virtual gfx::Size GetSize() OVERRIDE; + virtual void* GetHandle() OVERRIDE; + + // Allow the surface to call back to context when in need of |FlushBuffer|. + virtual bool OnMakeCurrent(GLContext* context) OVERRIDE; + + private: + // Weak. An |NSView*|. + AcceleratedWidget view_; + + // Weak. Associated context. + GLContextNSView* context_; + + DISALLOW_COPY_AND_ASSIGN(GLSurfaceNSView); +}; + +} // namespace gfx + +#endif // UI_GL_GL_SURFACE_NSVIEW_H_ diff --git a/ui/gl/gl_surface_nsview.mm b/ui/gl/gl_surface_nsview.mm new file mode 100644 index 0000000..ded0719 --- /dev/null +++ b/ui/gl/gl_surface_nsview.mm @@ -0,0 +1,47 @@ +// 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_surface_nsview.h" + +#import <AppKit/NSOpenGL.h> +#import <AppKit/NSView.h> + +#include "ui/gl/gl_context_nsview.h" + +namespace gfx { + +GLSurfaceNSView::GLSurfaceNSView(AcceleratedWidget view) + : view_(view), + context_(NULL) { +} + +GLSurfaceNSView::~GLSurfaceNSView() { +} + +void GLSurfaceNSView::Destroy() { +} + +bool GLSurfaceNSView::IsOffscreen() { + return false; +} + +bool GLSurfaceNSView::SwapBuffers() { + context_->FlushBuffer(); + return true; +} + +gfx::Size GLSurfaceNSView::GetSize() { + return gfx::Size(NSSizeToCGSize([view_ bounds].size)); +} + +void* GLSurfaceNSView::GetHandle() { + return view_; +} + +bool GLSurfaceNSView::OnMakeCurrent(GLContext* context) { + context_ = static_cast<GLContextNSView *>(context); + return true; +} + +} // namespace gfx diff --git a/ui/gl/gl_surface_osmesa.cc b/ui/gl/gl_surface_osmesa.cc new file mode 100644 index 0000000..a1fd360 --- /dev/null +++ b/ui/gl/gl_surface_osmesa.cc @@ -0,0 +1,82 @@ +// 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 "base/logging.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_surface_osmesa.h" + +namespace gfx { + +GLSurfaceOSMesa::GLSurfaceOSMesa(unsigned format, const gfx::Size& size) + : format_(format), + size_(size) { +} + +bool GLSurfaceOSMesa::Initialize() { + return Resize(size_); +} + +void GLSurfaceOSMesa::Destroy() { + buffer_.reset(); +} + +bool GLSurfaceOSMesa::Resize(const gfx::Size& new_size) { + GLContext* current_context = GLContext::GetCurrent(); + bool was_current = current_context && current_context->IsCurrent(this); + if (was_current) + current_context->ReleaseCurrent(this); + + // Preserve the old buffer. + scoped_array<int32> old_buffer(buffer_.release()); + + // Allocate a new one. + buffer_.reset(new int32[new_size.GetArea()]); + memset(buffer_.get(), 0, new_size.GetArea() * sizeof(buffer_[0])); + + // Copy the old back buffer into the new buffer. + if (old_buffer.get()) { + int copy_width = std::min(size_.width(), new_size.width()); + int copy_height = std::min(size_.height(), new_size.height()); + for (int y = 0; y < copy_height; ++y) { + for (int x = 0; x < copy_width; ++x) { + buffer_[y * new_size.width() + x] = old_buffer[y * size_.width() + x]; + } + } + } + + size_ = new_size; + + if (was_current) + return current_context->MakeCurrent(this); + + return true; +} + +bool GLSurfaceOSMesa::IsOffscreen() { + return true; +} + +bool GLSurfaceOSMesa::SwapBuffers() { + NOTREACHED() << "Should not call SwapBuffers on an GLSurfaceOSMesa."; + return false; +} + +gfx::Size GLSurfaceOSMesa::GetSize() { + return size_; +} + +void* GLSurfaceOSMesa::GetHandle() { + return buffer_.get(); +} + +unsigned GLSurfaceOSMesa::GetFormat() { + return format_; +} + +GLSurfaceOSMesa::~GLSurfaceOSMesa() { + Destroy(); +} + +} // namespace gfx diff --git a/ui/gl/gl_surface_osmesa.h b/ui/gl/gl_surface_osmesa.h new file mode 100644 index 0000000..ab3feec --- /dev/null +++ b/ui/gl/gl_surface_osmesa.h @@ -0,0 +1,45 @@ +// 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. + +#ifndef UI_GL_GL_SURFACE_OSMESA_H_ +#define UI_GL_GL_SURFACE_OSMESA_H_ +#pragma once + +#include "base/memory/scoped_ptr.h" +#include "ui/gfx/size.h" +#include "ui/gl/gl_surface.h" + +namespace gfx { + +// A surface that the Mesa software renderer draws to. This is actually just a +// buffer in system memory. GetHandle returns a pointer to the buffer. These +// surfaces can be resized and resizing preserves the contents. +class GL_EXPORT GLSurfaceOSMesa : public GLSurface { + public: + GLSurfaceOSMesa(unsigned format, const gfx::Size& size); + + // Implement GLSurface. + virtual bool Initialize() OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool Resize(const gfx::Size& new_size) OVERRIDE; + virtual bool IsOffscreen() OVERRIDE; + virtual bool SwapBuffers() OVERRIDE; + virtual gfx::Size GetSize() OVERRIDE; + virtual void* GetHandle() OVERRIDE; + virtual unsigned GetFormat() OVERRIDE; + + protected: + virtual ~GLSurfaceOSMesa(); + + private: + unsigned format_; + gfx::Size size_; + scoped_array<int32> buffer_; + + DISALLOW_COPY_AND_ASSIGN(GLSurfaceOSMesa); +}; + +} // namespace gfx + +#endif // UI_GL_GL_SURFACE_OSMESA_H_ diff --git a/ui/gl/gl_surface_stub.cc b/ui/gl/gl_surface_stub.cc new file mode 100644 index 0000000..a27d2af --- /dev/null +++ b/ui/gl/gl_surface_stub.cc @@ -0,0 +1,30 @@ +// 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_surface_stub.h" + +namespace gfx { + +void GLSurfaceStub::Destroy() { +} + +bool GLSurfaceStub::IsOffscreen() { + return false; +} + +bool GLSurfaceStub::SwapBuffers() { + return true; +} + +gfx::Size GLSurfaceStub::GetSize() { + return size_; +} + +void* GLSurfaceStub::GetHandle() { + return NULL; +} + +GLSurfaceStub::~GLSurfaceStub() {} + +} // namespace gfx diff --git a/ui/gl/gl_surface_stub.h b/ui/gl/gl_surface_stub.h new file mode 100644 index 0000000..86bbd15 --- /dev/null +++ b/ui/gl/gl_surface_stub.h @@ -0,0 +1,34 @@ +// 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. + +#ifndef UI_GL_GL_SURFACE_STUB_H_ +#define UI_GL_GL_SURFACE_STUB_H_ +#pragma once + +#include "ui/gl/gl_surface.h" + +namespace gfx { + +// A GLSurface that does nothing for unit tests. +class GL_EXPORT GLSurfaceStub : public GLSurface { + public: + void SetSize(const gfx::Size& size) { size_ = size; } + + // Implement GLSurface. + virtual void Destroy() OVERRIDE; + virtual bool IsOffscreen() OVERRIDE; + virtual bool SwapBuffers() OVERRIDE; + virtual gfx::Size GetSize() OVERRIDE; + virtual void* GetHandle() OVERRIDE; + + protected: + virtual ~GLSurfaceStub(); + + private: + gfx::Size size_; +}; + +} // namespace gfx + +#endif // UI_GL_GL_SURFACE_STUB_H_ diff --git a/ui/gl/gl_surface_wgl.cc b/ui/gl/gl_surface_wgl.cc new file mode 100644 index 0000000..a72c825 --- /dev/null +++ b/ui/gl/gl_surface_wgl.cc @@ -0,0 +1,366 @@ +// 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_surface_wgl.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "ui/gl/gl_bindings.h" + +namespace gfx { + +namespace { +const PIXELFORMATDESCRIPTOR kPixelFormatDescriptor = { + sizeof(kPixelFormatDescriptor), // Size of structure. + 1, // Default version. + PFD_DRAW_TO_WINDOW | // Window drawing support. + PFD_SUPPORT_OPENGL | // OpenGL support. + PFD_DOUBLEBUFFER, // Double buffering support (not stereo). + PFD_TYPE_RGBA, // RGBA color mode (not indexed). + 24, // 24 bit color mode. + 0, 0, 0, 0, 0, 0, // Don't set RGB bits & shifts. + 8, 0, // 8 bit alpha + 0, // No accumulation buffer. + 0, 0, 0, 0, // Ignore accumulation bits. + 0, // no z-buffer. + 0, // no stencil buffer. + 0, // No aux buffer. + PFD_MAIN_PLANE, // Main drawing plane (not overlay). + 0, // Reserved. + 0, 0, 0, // Layer masks ignored. +}; + +LRESULT CALLBACK IntermediateWindowProc(HWND window, + UINT message, + WPARAM w_param, + LPARAM l_param) { + switch (message) { + case WM_ERASEBKGND: + // Prevent windows from erasing the background. + return 1; + case WM_PAINT: + // Do not paint anything. + PAINTSTRUCT paint; + if (BeginPaint(window, &paint)) + EndPaint(window, &paint); + return 0; + default: + return DefWindowProc(window, message, w_param, l_param); + } +} + +class DisplayWGL { + public: + DisplayWGL() + : module_handle_(0), + window_class_(0), + window_handle_(0), + device_context_(0), + pixel_format_(0) { + } + + ~DisplayWGL() { + if (window_handle_) + DestroyWindow(window_handle_); + if (window_class_) + UnregisterClass(reinterpret_cast<wchar_t*>(window_class_), + module_handle_); + } + + bool Init() { + // We must initialize a GL context before we can bind to extension entry + // points. This requires the device context for a window. + if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + reinterpret_cast<wchar_t*>(IntermediateWindowProc), + &module_handle_)) { + LOG(ERROR) << "GetModuleHandleEx failed."; + return false; + } + + WNDCLASS intermediate_class; + intermediate_class.style = CS_OWNDC; + intermediate_class.lpfnWndProc = IntermediateWindowProc; + intermediate_class.cbClsExtra = 0; + intermediate_class.cbWndExtra = 0; + intermediate_class.hInstance = module_handle_; + intermediate_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); + intermediate_class.hCursor = LoadCursor(NULL, IDC_ARROW); + intermediate_class.hbrBackground = NULL; + intermediate_class.lpszMenuName = NULL; + intermediate_class.lpszClassName = L"Intermediate GL Window"; + window_class_ = RegisterClass(&intermediate_class); + if (!window_class_) { + LOG(ERROR) << "RegisterClass failed."; + return false; + } + + window_handle_ = CreateWindow( + reinterpret_cast<wchar_t*>(window_class_), + L"", + WS_OVERLAPPEDWINDOW, + 0, 0, + 100, 100, + NULL, + NULL, + NULL, + NULL); + if (!window_handle_) { + LOG(ERROR) << "CreateWindow failed."; + return false; + } + + device_context_ = GetDC(window_handle_); + pixel_format_ = ChoosePixelFormat(device_context_, + &kPixelFormatDescriptor); + if (pixel_format_ == 0) { + LOG(ERROR) << "Unable to get the pixel format for GL context."; + return false; + } + if (!SetPixelFormat(device_context_, + pixel_format_, + &kPixelFormatDescriptor)) { + LOG(ERROR) << "Unable to set the pixel format for temporary GL context."; + return false; + } + + return true; + } + + ATOM window_class() const { return window_class_; } + HDC device_context() const { return device_context_; } + int pixel_format() const { return pixel_format_; } + + private: + HINSTANCE module_handle_; + ATOM window_class_; + HWND window_handle_; + HDC device_context_; + int pixel_format_; +}; +DisplayWGL* g_display; +} // namespace + +GLSurfaceWGL::GLSurfaceWGL() { +} + +GLSurfaceWGL::~GLSurfaceWGL() { +} + +void* GLSurfaceWGL::GetDisplay() { + return GetDisplayDC(); +} + +bool GLSurfaceWGL::InitializeOneOff() { + static bool initialized = false; + if (initialized) + return true; + + DCHECK(g_display == NULL); + scoped_ptr<DisplayWGL> wgl_display(new DisplayWGL); + if (!wgl_display->Init()) + return false; + + // Create a temporary GL context to bind to extension entry points. + HGLRC gl_context = wglCreateContext(wgl_display->device_context()); + if (!gl_context) { + LOG(ERROR) << "Failed to create temporary context."; + return false; + } + if (!wglMakeCurrent(wgl_display->device_context(), gl_context)) { + LOG(ERROR) << "Failed to make temporary GL context current."; + wglDeleteContext(gl_context); + return false; + } + // Get bindings to extension functions that cannot be acquired without a + // current context. + InitializeGLBindingsGL(); + InitializeGLBindingsWGL(); + + wglMakeCurrent(NULL, NULL); + wglDeleteContext(gl_context); + + g_display = wgl_display.release(); + initialized = true; + return true; +} + +HDC GLSurfaceWGL::GetDisplayDC() { + return g_display->device_context(); +} + +NativeViewGLSurfaceWGL::NativeViewGLSurfaceWGL(gfx::AcceleratedWidget window) + : window_(window), + child_window_(NULL), + device_context_(NULL) { + DCHECK(window); +} + +NativeViewGLSurfaceWGL::~NativeViewGLSurfaceWGL() { + Destroy(); +} + +bool NativeViewGLSurfaceWGL::Initialize() { + DCHECK(!device_context_); + + RECT rect; + if (!GetClientRect(window_, &rect)) { + LOG(ERROR) << "GetClientRect failed.\n"; + Destroy(); + return false; + } + + // Create a child window. WGL has problems using a window handle owned by + // another process. + child_window_ = CreateWindow( + reinterpret_cast<wchar_t*>(g_display->window_class()), + L"", + WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE, + 0, 0, + rect.right - rect.left, + rect.bottom - rect.top, + window_, + NULL, + NULL, + NULL); + if (!child_window_) { + LOG(ERROR) << "CreateWindow failed.\n"; + Destroy(); + return false; + } + + // The GL context will render to this window. + device_context_ = GetDC(child_window_); + if (!device_context_) { + LOG(ERROR) << "Unable to get device context for window."; + Destroy(); + return false; + } + + if (!SetPixelFormat(device_context_, + g_display->pixel_format(), + &kPixelFormatDescriptor)) { + LOG(ERROR) << "Unable to set the pixel format for GL context."; + Destroy(); + return false; + } + + return true; +} + +void NativeViewGLSurfaceWGL::Destroy() { + if (child_window_ && device_context_) + ReleaseDC(child_window_, device_context_); + + if (child_window_) + DestroyWindow(child_window_); + + child_window_ = NULL; + device_context_ = NULL; +} + +bool NativeViewGLSurfaceWGL::IsOffscreen() { + return false; +} + +bool NativeViewGLSurfaceWGL::SwapBuffers() { + // Resize the child window to match the parent before swapping. Do not repaint + // it as it moves. + RECT rect; + if (!GetClientRect(window_, &rect)) + return false; + if (!MoveWindow(child_window_, + 0, 0, + rect.right - rect.left, + rect.bottom - rect.top, + FALSE)) { + return false; + } + + DCHECK(device_context_); + return ::SwapBuffers(device_context_) == TRUE; +} + +gfx::Size NativeViewGLSurfaceWGL::GetSize() { + RECT rect; + BOOL result = GetClientRect(child_window_, &rect); + DCHECK(result); + return gfx::Size(rect.right - rect.left, rect.bottom - rect.top); +} + +void* NativeViewGLSurfaceWGL::GetHandle() { + return device_context_; +} + +PbufferGLSurfaceWGL::PbufferGLSurfaceWGL(const gfx::Size& size) + : size_(size), + device_context_(NULL), + pbuffer_(NULL) { +} + +PbufferGLSurfaceWGL::~PbufferGLSurfaceWGL() { + Destroy(); +} + +bool PbufferGLSurfaceWGL::Initialize() { + DCHECK(!device_context_); + + if (!wglCreatePbufferARB) { + LOG(ERROR) << "wglCreatePbufferARB not available."; + Destroy(); + return false; + } + + const int kNoAttributes[] = { 0 }; + pbuffer_ = wglCreatePbufferARB(g_display->device_context(), + g_display->pixel_format(), + size_.width(), size_.height(), + kNoAttributes); + + if (!pbuffer_) { + LOG(ERROR) << "Unable to create pbuffer."; + Destroy(); + return false; + } + + device_context_ = wglGetPbufferDCARB(static_cast<HPBUFFERARB>(pbuffer_)); + if (!device_context_) { + LOG(ERROR) << "Unable to get pbuffer device context."; + Destroy(); + return false; + } + + return true; +} + +void PbufferGLSurfaceWGL::Destroy() { + if (pbuffer_ && device_context_) + wglReleasePbufferDCARB(static_cast<HPBUFFERARB>(pbuffer_), device_context_); + + device_context_ = NULL; + + if (pbuffer_) { + wglDestroyPbufferARB(static_cast<HPBUFFERARB>(pbuffer_)); + pbuffer_ = NULL; + } +} + +bool PbufferGLSurfaceWGL::IsOffscreen() { + return true; +} + +bool PbufferGLSurfaceWGL::SwapBuffers() { + NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer."; + return false; +} + +gfx::Size PbufferGLSurfaceWGL::GetSize() { + return size_; +} + +void* PbufferGLSurfaceWGL::GetHandle() { + return device_context_; +} + +} // namespace gfx diff --git a/ui/gl/gl_surface_wgl.h b/ui/gl/gl_surface_wgl.h new file mode 100644 index 0000000..6e4f0cd --- /dev/null +++ b/ui/gl/gl_surface_wgl.h @@ -0,0 +1,77 @@ +// 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. + +#ifndef UI_GL_GL_SURFACE_WGL_H_ +#define UI_GL_GL_SURFACE_WGL_H_ +#pragma once + +#include "ui/gfx/native_widget_types.h" +#include "ui/gl/gl_surface.h" + +namespace gfx { + +// Base interface for WGL surfaces. +class GLSurfaceWGL : public GLSurface { + public: + GLSurfaceWGL(); + virtual ~GLSurfaceWGL(); + + // Implement GLSurface. + virtual void* GetDisplay(); + + static bool InitializeOneOff(); + static HDC GetDisplayDC(); + + private: + DISALLOW_COPY_AND_ASSIGN(GLSurfaceWGL); +}; + +// A surface used to render to a view. +class NativeViewGLSurfaceWGL : public GLSurfaceWGL { + public: + explicit NativeViewGLSurfaceWGL(gfx::AcceleratedWidget window); + virtual ~NativeViewGLSurfaceWGL(); + + // Implement GLSurface. + virtual bool Initialize(); + virtual void Destroy(); + virtual bool IsOffscreen(); + virtual bool SwapBuffers(); + virtual gfx::Size GetSize(); + virtual void* GetHandle(); + + private: + gfx::AcceleratedWidget window_; + gfx::AcceleratedWidget child_window_; + HDC device_context_; + + DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceWGL); +}; + + +// A surface used to render to an offscreen pbuffer. +class PbufferGLSurfaceWGL : public GLSurfaceWGL { + public: + explicit PbufferGLSurfaceWGL(const gfx::Size& size); + virtual ~PbufferGLSurfaceWGL(); + + // Implement GLSurface. + virtual bool Initialize(); + virtual void Destroy(); + virtual bool IsOffscreen(); + virtual bool SwapBuffers(); + virtual gfx::Size GetSize(); + virtual void* GetHandle(); + + private: + gfx::Size size_; + HDC device_context_; + void* pbuffer_; + + DISALLOW_COPY_AND_ASSIGN(PbufferGLSurfaceWGL); +}; + +} // namespace gfx + +#endif // UI_GL_GL_SURFACE_WGL_H_ diff --git a/ui/gl/gl_surface_win.cc b/ui/gl/gl_surface_win.cc new file mode 100644 index 0000000..ae55568 --- /dev/null +++ b/ui/gl/gl_surface_win.cc @@ -0,0 +1,248 @@ +// 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_surface.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/mesa/MesaLib/include/GL/osmesa.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface_egl.h" +#include "ui/gl/gl_surface_osmesa.h" +#include "ui/gl/gl_surface_stub.h" +#include "ui/gl/gl_surface_wgl.h" + +namespace gfx { + +// This OSMesa GL surface can use GDI to swap the contents of the buffer to a +// view. +class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa { + public: + explicit NativeViewGLSurfaceOSMesa(gfx::AcceleratedWidget window); + virtual ~NativeViewGLSurfaceOSMesa(); + + // Implement subset of GLSurface. + virtual bool Initialize() OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual bool IsOffscreen() OVERRIDE; + virtual bool SwapBuffers() OVERRIDE; + virtual std::string GetExtensions() OVERRIDE; + virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; + + private: + gfx::AcceleratedWidget window_; + HDC device_context_; + + DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa); +}; + +// Helper routine that does one-off initialization like determining the +// pixel format and initializing the GL bindings. +bool GLSurface::InitializeOneOffInternal() { + switch (GetGLImplementation()) { + case kGLImplementationDesktopGL: + if (!GLSurfaceWGL::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed."; + return false; + } + break; + case kGLImplementationEGLGLES2: + if (!GLSurfaceEGL::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; + return false; + } + break; + } + return true; +} + +NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa( + gfx::AcceleratedWidget window) + : GLSurfaceOSMesa(OSMESA_RGBA, gfx::Size(1, 1)), + window_(window), + device_context_(NULL) { + DCHECK(window); +} + +NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() { + Destroy(); +} + +bool NativeViewGLSurfaceOSMesa::Initialize() { + if (!GLSurfaceOSMesa::Initialize()) + return false; + + device_context_ = GetDC(window_); + return true; +} + +void NativeViewGLSurfaceOSMesa::Destroy() { + if (window_ && device_context_) + ReleaseDC(window_, device_context_); + + device_context_ = NULL; + + GLSurfaceOSMesa::Destroy(); +} + +bool NativeViewGLSurfaceOSMesa::IsOffscreen() { + return false; +} + +bool NativeViewGLSurfaceOSMesa::SwapBuffers() { + DCHECK(device_context_); + + gfx::Size size = GetSize(); + + // Note: negating the height below causes GDI to treat the bitmap data as row + // 0 being at the top. + BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) }; + info.bV4Width = size.width(); + info.bV4Height = -size.height(); + info.bV4Planes = 1; + info.bV4BitCount = 32; + info.bV4V4Compression = BI_BITFIELDS; + info.bV4RedMask = 0x000000FF; + info.bV4GreenMask = 0x0000FF00; + info.bV4BlueMask = 0x00FF0000; + info.bV4AlphaMask = 0xFF000000; + + // Copy the back buffer to the window's device context. Do not check whether + // StretchDIBits succeeds or not. It will fail if the window has been + // destroyed but it is preferable to allow rendering to silently fail if the + // window is destroyed. This is because the primary application of this + // class of GLContext is for testing and we do not want every GL related ui / + // browser test to become flaky if there is a race condition between GL + // context destruction and window destruction. + StretchDIBits(device_context_, + 0, 0, size.width(), size.height(), + 0, 0, size.width(), size.height(), + GetHandle(), + reinterpret_cast<BITMAPINFO*>(&info), + DIB_RGB_COLORS, + SRCCOPY); + + return true; +} + +std::string NativeViewGLSurfaceOSMesa::GetExtensions() { + std::string extensions = gfx::GLSurfaceOSMesa::GetExtensions(); + extensions += extensions.empty() ? "" : " "; + extensions += "GL_CHROMIUM_post_sub_buffer"; + return extensions; +} + +bool NativeViewGLSurfaceOSMesa::PostSubBuffer( + int x, int y, int width, int height) { + DCHECK(device_context_); + + gfx::Size size = GetSize(); + + // Note: negating the height below causes GDI to treat the bitmap data as row + // 0 being at the top. + BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) }; + info.bV4Width = size.width(); + info.bV4Height = -size.height(); + info.bV4Planes = 1; + info.bV4BitCount = 32; + info.bV4V4Compression = BI_BITFIELDS; + info.bV4RedMask = 0x000000FF; + info.bV4GreenMask = 0x0000FF00; + info.bV4BlueMask = 0x00FF0000; + info.bV4AlphaMask = 0xFF000000; + + // Copy the back buffer to the window's device context. Do not check whether + // StretchDIBits succeeds or not. It will fail if the window has been + // destroyed but it is preferable to allow rendering to silently fail if the + // window is destroyed. This is because the primary application of this + // class of GLContext is for testing and we do not want every GL related ui / + // browser test to become flaky if there is a race condition between GL + // context destruction and window destruction. + StretchDIBits(device_context_, + x, size.height() - y - height, width, height, + x, y, width, height, + GetHandle(), + reinterpret_cast<BITMAPINFO*>(&info), + DIB_RGB_COLORS, + SRCCOPY); + + return true; +} + +scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface( + bool software, + gfx::AcceleratedWidget window) { + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_refptr<GLSurface> surface( + new NativeViewGLSurfaceOSMesa(window)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationEGLGLES2: { + scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceEGL(software, + window)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationDesktopGL: { + if (software) + return NULL; + scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceWGL( + window)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationMockGL: + return new GLSurfaceStub; + default: + NOTREACHED(); + return NULL; + } +} + +scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface( + bool software, + const gfx::Size& size) { + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(OSMESA_RGBA, + size)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationEGLGLES2: { + scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(software, size)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationDesktopGL: { + if (software) + return NULL; + scoped_refptr<GLSurface> surface(new PbufferGLSurfaceWGL(size)); + if (!surface->Initialize()) + return NULL; + + return surface; + } + case kGLImplementationMockGL: + return new GLSurfaceStub; + default: + NOTREACHED(); + return NULL; + } +} + +} // namespace gfx diff --git a/ui/gl/gl_switches.cc b/ui/gl/gl_switches.cc new file mode 100644 index 0000000..d30c958 --- /dev/null +++ b/ui/gl/gl_switches.cc @@ -0,0 +1,55 @@ +// 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_switches.h" + +namespace gfx { + +const char kGLImplementationDesktopName[] = "desktop"; +const char kGLImplementationOSMesaName[] = "osmesa"; +const char kGLImplementationAppleName[] = "apple"; +const char kGLImplementationEGLName[] = "egl"; +const char kGLImplementationSwiftShaderName[] = "swiftshader"; +const char kGLImplementationMockName[] = "mock"; + +} // namespace gfx + +namespace switches { + +// Disable dynamic switching between integrated and discrete GPU on +// systems that would otherwise support it (currently, only a limited +// number of MacBook Pros). +const char kDisableGpuSwitching[] = "disable-gpu-switching"; + +// Stop the GPU from synchronizing on the vsync before presenting. +const char kDisableGpuVsync[] = "disable-gpu-vsync"; + +// Turns on GPU logging (debug build only). +const char kEnableGPUServiceLogging[] = "enable-gpu-service-logging"; +const char kEnableGPUClientLogging[] = "enable-gpu-client-logging"; + +// Select which implementation of GL the GPU process should use. Options are: +// desktop: whatever desktop OpenGL the user has installed (Linux and Mac +// default). +// egl: whatever EGL / GLES2 the user has installed (Windows default - actually +// ANGLE). +// osmesa: The OSMesa software renderer. +const char kUseGL[] = "use-gl"; + +const char kSwiftShaderPath[] = "swiftshader-path"; + +// Inform Chrome that a GPU context will not be lost in power saving mode, +// screen saving mode, etc. Note that this flag does not ensure that a GPU +// context will never be lost in any situations, say, a GPU reset. +const char kGpuNoContextLost[] = "gpu-no-context-lost"; + +// Add a delay in milliseconds to the gpu swap buffer completion signal. +// Simulates a slow GPU. +const char kGpuSwapDelay[] = "gpu-swap-delay"; + +// Flag used for Linux tests: for desktop GL bindings, try to load this GL +// library first, but fall back to regular library if loading fails. +const char kTestGLLib[] = "test-gl-lib"; + +} // namespace switches diff --git a/ui/gl/gl_switches.h b/ui/gl/gl_switches.h new file mode 100644 index 0000000..ffda704 --- /dev/null +++ b/ui/gl/gl_switches.h @@ -0,0 +1,39 @@ +// 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. + +#ifndef UI_GL_GL_SWITCHES_H_ +#define UI_GL_GL_SWITCHES_H_ +#pragma once + +// Defines all the command-line switches used by ui/gl. + +#include "ui/gl/gl_export.h" + +namespace gfx { + +// The GL implementation names that can be passed to --use-gl. +GL_EXPORT extern const char kGLImplementationDesktopName[]; +GL_EXPORT extern const char kGLImplementationOSMesaName[]; +GL_EXPORT extern const char kGLImplementationAppleName[]; +GL_EXPORT extern const char kGLImplementationEGLName[]; +GL_EXPORT extern const char kGLImplementationSwiftShaderName[]; +extern const char kGLImplementationMockName[]; + +} // namespace gfx + +namespace switches { + +GL_EXPORT extern const char kDisableGpuSwitching[]; +GL_EXPORT extern const char kDisableGpuVsync[]; +GL_EXPORT extern const char kEnableGPUServiceLogging[]; +GL_EXPORT extern const char kEnableGPUClientLogging[]; +GL_EXPORT extern const char kGpuNoContextLost[]; +GL_EXPORT extern const char kGpuSwapDelay[]; +GL_EXPORT extern const char kUseGL[]; +GL_EXPORT extern const char kSwiftShaderPath[]; +GL_EXPORT extern const char kTestGLLib[]; + +} // namespace switches + +#endif // UI_GL_GL_SWITCHES_H_ diff --git a/ui/gl/gpu_preference.h b/ui/gl/gpu_preference.h new file mode 100644 index 0000000..54f814a --- /dev/null +++ b/ui/gl/gpu_preference.h @@ -0,0 +1,25 @@ +// 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. + +#ifndef UI_GL_GPU_PREFERENCE_H_ +#define UI_GL_GPU_PREFERENCE_H_ +#pragma once + +namespace gfx { + +// On dual-GPU systems, expresses a preference for using the integrated +// or discrete GPU. On systems that have dual-GPU support (see +// GLContext::SupportsDualGpus), resource sharing only works between +// contexts that are created with the same GPU preference. +// +// This API will likely need to be adjusted as the functionality is +// implemented on more operating systems. +enum GpuPreference { + PreferIntegratedGpu, + PreferDiscreteGpu +}; + +} // namespace gfx + +#endif // UI_GL_GPU_PREFERENCE_H_ diff --git a/ui/gl/scoped_make_current.cc b/ui/gl/scoped_make_current.cc new file mode 100644 index 0000000..54dac6d --- /dev/null +++ b/ui/gl/scoped_make_current.cc @@ -0,0 +1,36 @@ +// 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/scoped_make_current.h" + +#include "base/logging.h" + +namespace gfx { + +ScopedMakeCurrent::ScopedMakeCurrent(GLContext* context, GLSurface* surface) + : previous_context_(GLContext::GetCurrent()) + , previous_surface_(GLSurface::GetCurrent()) + , context_(context) + , surface_(surface) + , succeeded_(false) { + DCHECK(context); + DCHECK(surface); + succeeded_ = context->MakeCurrent(surface); +} + +ScopedMakeCurrent::~ScopedMakeCurrent() { + if (previous_context_.get()) { + DCHECK(previous_surface_.get()); + previous_context_->MakeCurrent(previous_surface_.get()); + } else { + context_->ReleaseCurrent(surface_.get()); + } +} + +bool ScopedMakeCurrent::Succeeded() { + return succeeded_; +} + +} // namespace gfx + diff --git a/ui/gl/scoped_make_current.h b/ui/gl/scoped_make_current.h new file mode 100644 index 0000000..3c336f3 --- /dev/null +++ b/ui/gl/scoped_make_current.h @@ -0,0 +1,33 @@ +// 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. + +#ifndef UI_GL_SCOPED_MAKE_CURRENT_H_ +#define UI_GL_SCOPED_MAKE_CURRENT_H_ +#pragma once + +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_surface.h" + +namespace gfx { + +class GL_EXPORT ScopedMakeCurrent { + public: + explicit ScopedMakeCurrent(GLContext* context, GLSurface* surface); + ~ScopedMakeCurrent(); + + bool Succeeded(); + + private: + scoped_refptr<GLContext> previous_context_; + scoped_refptr<GLSurface> previous_surface_; + scoped_refptr<GLContext> context_; + scoped_refptr<GLSurface> surface_; + bool succeeded_; + + DISALLOW_COPY_AND_ASSIGN(ScopedMakeCurrent); +}; + +} // namespace gfx + +#endif // UI_GL_SCOPED_MAKE_CURRENT_H_ |