1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "ui/gl/gl_context_egl.h" 6 7#include "base/debug/trace_event.h" 8#include "base/logging.h" 9#include "base/memory/scoped_ptr.h" 10#include "build/build_config.h" 11#include "third_party/khronos/EGL/egl.h" 12#include "third_party/khronos/EGL/eglext.h" 13#include "ui/gl/egl_util.h" 14#include "ui/gl/gl_bindings.h" 15#include "ui/gl/gl_surface_egl.h" 16 17#if defined(USE_X11) 18extern "C" { 19#include <X11/Xlib.h> 20} 21#endif 22 23using ui::GetLastEGLErrorString; 24 25namespace gfx { 26 27GLContextEGL::GLContextEGL(GLShareGroup* share_group) 28 : GLContextReal(share_group), 29 context_(NULL), 30 display_(NULL), 31 config_(NULL), 32 unbind_fbo_on_makecurrent_(false) { 33} 34 35bool GLContextEGL::Initialize( 36 GLSurface* compatible_surface, GpuPreference gpu_preference) { 37 DCHECK(compatible_surface); 38 DCHECK(!context_); 39 40 static const EGLint kContextAttributes[] = { 41 EGL_CONTEXT_CLIENT_VERSION, 2, 42 EGL_NONE 43 }; 44 static const EGLint kContextRobustnessAttributes[] = { 45 EGL_CONTEXT_CLIENT_VERSION, 2, 46 EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, 47 EGL_LOSE_CONTEXT_ON_RESET_EXT, 48 EGL_NONE 49 }; 50 51 display_ = compatible_surface->GetDisplay(); 52 config_ = compatible_surface->GetConfig(); 53 54 const EGLint* context_attributes = NULL; 55 if (GLSurfaceEGL::IsCreateContextRobustnessSupported()) { 56 DVLOG(1) << "EGL_EXT_create_context_robustness supported."; 57 context_attributes = kContextRobustnessAttributes; 58 } else { 59 // At some point we should require the presence of the robustness 60 // extension and remove this code path. 61 DVLOG(1) << "EGL_EXT_create_context_robustness NOT supported."; 62 context_attributes = kContextAttributes; 63 } 64 65 context_ = eglCreateContext( 66 display_, 67 config_, 68 share_group() ? share_group()->GetHandle() : NULL, 69 context_attributes); 70 71 if (!context_) { 72 LOG(ERROR) << "eglCreateContext failed with error " 73 << GetLastEGLErrorString(); 74 Destroy(); 75 return false; 76 } 77 78 return true; 79} 80 81void GLContextEGL::Destroy() { 82 if (context_) { 83 if (!eglDestroyContext(display_, context_)) { 84 LOG(ERROR) << "eglDestroyContext failed with error " 85 << GetLastEGLErrorString(); 86 } 87 88 context_ = NULL; 89 } 90} 91 92bool GLContextEGL::MakeCurrent(GLSurface* surface) { 93 DCHECK(context_); 94 if (IsCurrent(surface)) 95 return true; 96 97 TRACE_EVENT2("gpu", "GLContextEGL::MakeCurrent", 98 "context", context_, 99 "surface", surface); 100 101 if (unbind_fbo_on_makecurrent_ && 102 eglGetCurrentContext() != EGL_NO_CONTEXT) { 103 glBindFramebufferEXT(GL_FRAMEBUFFER, 0); 104 } 105 106 if (!eglMakeCurrent(display_, 107 surface->GetHandle(), 108 surface->GetHandle(), 109 context_)) { 110 DVLOG(1) << "eglMakeCurrent failed with error " 111 << GetLastEGLErrorString(); 112 return false; 113 } 114 115 // Set this as soon as the context is current, since we might call into GL. 116 SetRealGLApi(); 117 118 SetCurrent(surface); 119 if (!InitializeExtensionBindings()) { 120 ReleaseCurrent(surface); 121 return false; 122 } 123 124 if (!surface->OnMakeCurrent(this)) { 125 LOG(ERROR) << "Could not make current."; 126 return false; 127 } 128 129 return true; 130} 131 132void GLContextEGL::SetUnbindFboOnMakeCurrent() { 133 unbind_fbo_on_makecurrent_ = true; 134} 135 136void GLContextEGL::ReleaseCurrent(GLSurface* surface) { 137 if (!IsCurrent(surface)) 138 return; 139 140 if (unbind_fbo_on_makecurrent_) 141 glBindFramebufferEXT(GL_FRAMEBUFFER, 0); 142 143 SetCurrent(NULL); 144 eglMakeCurrent(display_, 145 EGL_NO_SURFACE, 146 EGL_NO_SURFACE, 147 EGL_NO_CONTEXT); 148} 149 150bool GLContextEGL::IsCurrent(GLSurface* surface) { 151 DCHECK(context_); 152 153 bool native_context_is_current = context_ == eglGetCurrentContext(); 154 155 // If our context is current then our notion of which GLContext is 156 // current must be correct. On the other hand, third-party code 157 // using OpenGL might change the current context. 158 DCHECK(!native_context_is_current || (GetRealCurrent() == this)); 159 160 if (!native_context_is_current) 161 return false; 162 163 if (surface) { 164 if (surface->GetHandle() != eglGetCurrentSurface(EGL_DRAW)) 165 return false; 166 } 167 168 return true; 169} 170 171void* GLContextEGL::GetHandle() { 172 return context_; 173} 174 175void GLContextEGL::SetSwapInterval(int interval) { 176 DCHECK(IsCurrent(NULL)); 177 if (!eglSwapInterval(display_, interval)) { 178 LOG(ERROR) << "eglSwapInterval failed with error " 179 << GetLastEGLErrorString(); 180 } 181} 182 183std::string GLContextEGL::GetExtensions() { 184 const char* extensions = eglQueryString(display_, 185 EGL_EXTENSIONS); 186 if (!extensions) 187 return GLContext::GetExtensions(); 188 189 return GLContext::GetExtensions() + " " + extensions; 190} 191 192bool GLContextEGL::WasAllocatedUsingRobustnessExtension() { 193 return GLSurfaceEGL::IsCreateContextRobustnessSupported(); 194} 195 196GLContextEGL::~GLContextEGL() { 197 Destroy(); 198} 199 200#if !defined(OS_ANDROID) 201bool GLContextEGL::GetTotalGpuMemory(size_t* bytes) { 202 DCHECK(bytes); 203 *bytes = 0; 204 return false; 205} 206#endif 207 208} // namespace gfx 209