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 return false; 75 } 76 77 return true; 78} 79 80void GLContextEGL::Destroy() { 81 if (context_) { 82 if (!eglDestroyContext(display_, context_)) { 83 LOG(ERROR) << "eglDestroyContext failed with error " 84 << GetLastEGLErrorString(); 85 } 86 87 context_ = NULL; 88 } 89} 90 91bool GLContextEGL::MakeCurrent(GLSurface* surface) { 92 DCHECK(context_); 93 if (IsCurrent(surface)) 94 return true; 95 96 TRACE_EVENT2("gpu", "GLContextEGL::MakeCurrent", 97 "context", context_, 98 "surface", surface); 99 100 if (unbind_fbo_on_makecurrent_ && 101 eglGetCurrentContext() != EGL_NO_CONTEXT) { 102 glBindFramebufferEXT(GL_FRAMEBUFFER, 0); 103 } 104 105 if (!eglMakeCurrent(display_, 106 surface->GetHandle(), 107 surface->GetHandle(), 108 context_)) { 109 DVLOG(1) << "eglMakeCurrent failed with error " 110 << GetLastEGLErrorString(); 111 return false; 112 } 113 114 // Set this as soon as the context is current, since we might call into GL. 115 SetRealGLApi(); 116 117 SetCurrent(surface); 118 if (!InitializeExtensionBindings()) { 119 ReleaseCurrent(surface); 120 return false; 121 } 122 123 if (!surface->OnMakeCurrent(this)) { 124 LOG(ERROR) << "Could not make current."; 125 return false; 126 } 127 128 return true; 129} 130 131void GLContextEGL::SetUnbindFboOnMakeCurrent() { 132 unbind_fbo_on_makecurrent_ = true; 133} 134 135void GLContextEGL::ReleaseCurrent(GLSurface* surface) { 136 if (!IsCurrent(surface)) 137 return; 138 139 if (unbind_fbo_on_makecurrent_) 140 glBindFramebufferEXT(GL_FRAMEBUFFER, 0); 141 142 SetCurrent(NULL); 143 eglMakeCurrent(display_, 144 EGL_NO_SURFACE, 145 EGL_NO_SURFACE, 146 EGL_NO_CONTEXT); 147} 148 149bool GLContextEGL::IsCurrent(GLSurface* surface) { 150 DCHECK(context_); 151 152 bool native_context_is_current = context_ == eglGetCurrentContext(); 153 154 // If our context is current then our notion of which GLContext is 155 // current must be correct. On the other hand, third-party code 156 // using OpenGL might change the current context. 157 DCHECK(!native_context_is_current || (GetRealCurrent() == this)); 158 159 if (!native_context_is_current) 160 return false; 161 162 if (surface) { 163 if (surface->GetHandle() != eglGetCurrentSurface(EGL_DRAW)) 164 return false; 165 } 166 167 return true; 168} 169 170void* GLContextEGL::GetHandle() { 171 return context_; 172} 173 174void GLContextEGL::SetSwapInterval(int interval) { 175 DCHECK(IsCurrent(NULL)); 176 if (!eglSwapInterval(display_, interval)) { 177 LOG(ERROR) << "eglSwapInterval failed with error " 178 << GetLastEGLErrorString(); 179 } 180} 181 182std::string GLContextEGL::GetExtensions() { 183 const char* extensions = eglQueryString(display_, 184 EGL_EXTENSIONS); 185 if (!extensions) 186 return GLContext::GetExtensions(); 187 188 return GLContext::GetExtensions() + " " + extensions; 189} 190 191bool GLContextEGL::WasAllocatedUsingRobustnessExtension() { 192 return GLSurfaceEGL::IsCreateContextRobustnessSupported(); 193} 194 195GLContextEGL::~GLContextEGL() { 196 Destroy(); 197} 198 199#if !defined(OS_ANDROID) 200bool GLContextEGL::GetTotalGpuMemory(size_t* bytes) { 201 DCHECK(bytes); 202 *bytes = 0; 203 return false; 204} 205#endif 206 207} // namespace gfx 208