Allow Windows to use system Vsync if only one window is swapping
[chromium-blink-merge.git] / ui / gl / gl_context_egl.cc
blob076de98635788463d1bbf08f9bd6a8596cc65449
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.
5 #include "ui/gl/gl_context_egl.h"
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"
17 #if defined(USE_X11)
18 extern "C" {
19 #include <X11/Xlib.h>
21 #endif
23 using ui::GetLastEGLErrorString;
25 namespace gfx {
27 GLContextEGL::GLContextEGL(GLShareGroup* share_group)
28 : GLContextReal(share_group),
29 context_(NULL),
30 display_(NULL),
31 config_(NULL),
32 unbind_fbo_on_makecurrent_(false),
33 swap_interval_(1) {
36 bool GLContextEGL::Initialize(
37 GLSurface* compatible_surface, GpuPreference gpu_preference) {
38 DCHECK(compatible_surface);
39 DCHECK(!context_);
41 static const EGLint kContextAttributes[] = {
42 EGL_CONTEXT_CLIENT_VERSION, 2,
43 EGL_NONE
45 static const EGLint kContextRobustnessAttributes[] = {
46 EGL_CONTEXT_CLIENT_VERSION, 2,
47 EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT,
48 EGL_LOSE_CONTEXT_ON_RESET_EXT,
49 EGL_NONE
52 display_ = compatible_surface->GetDisplay();
53 config_ = compatible_surface->GetConfig();
55 const EGLint* context_attributes = NULL;
56 if (GLSurfaceEGL::IsCreateContextRobustnessSupported()) {
57 DVLOG(1) << "EGL_EXT_create_context_robustness supported.";
58 context_attributes = kContextRobustnessAttributes;
59 } else {
60 // At some point we should require the presence of the robustness
61 // extension and remove this code path.
62 DVLOG(1) << "EGL_EXT_create_context_robustness NOT supported.";
63 context_attributes = kContextAttributes;
66 context_ = eglCreateContext(
67 display_,
68 config_,
69 share_group() ? share_group()->GetHandle() : NULL,
70 context_attributes);
72 if (!context_) {
73 LOG(ERROR) << "eglCreateContext failed with error "
74 << GetLastEGLErrorString();
75 return false;
78 return true;
81 void GLContextEGL::Destroy() {
82 if (context_) {
83 if (!eglDestroyContext(display_, context_)) {
84 LOG(ERROR) << "eglDestroyContext failed with error "
85 << GetLastEGLErrorString();
88 context_ = NULL;
92 bool GLContextEGL::MakeCurrent(GLSurface* surface) {
93 DCHECK(context_);
94 if (IsCurrent(surface))
95 return true;
97 ScopedReleaseCurrent release_current;
98 TRACE_EVENT2("gpu", "GLContextEGL::MakeCurrent",
99 "context", context_,
100 "surface", surface);
102 if (unbind_fbo_on_makecurrent_ &&
103 eglGetCurrentContext() != EGL_NO_CONTEXT) {
104 glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
107 if (!eglMakeCurrent(display_,
108 surface->GetHandle(),
109 surface->GetHandle(),
110 context_)) {
111 DVLOG(1) << "eglMakeCurrent failed with error "
112 << GetLastEGLErrorString();
113 return false;
116 // Set this as soon as the context is current, since we might call into GL.
117 SetRealGLApi();
119 SetCurrent(surface);
120 if (!InitializeDynamicBindings()) {
121 return false;
124 if (!surface->OnMakeCurrent(this)) {
125 LOG(ERROR) << "Could not make current.";
126 return false;
129 surface->OnSetSwapInterval(swap_interval_);
131 release_current.Cancel();
132 return true;
135 void GLContextEGL::SetUnbindFboOnMakeCurrent() {
136 unbind_fbo_on_makecurrent_ = true;
139 void GLContextEGL::ReleaseCurrent(GLSurface* surface) {
140 if (!IsCurrent(surface))
141 return;
143 if (unbind_fbo_on_makecurrent_)
144 glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
146 SetCurrent(NULL);
147 eglMakeCurrent(display_,
148 EGL_NO_SURFACE,
149 EGL_NO_SURFACE,
150 EGL_NO_CONTEXT);
153 bool GLContextEGL::IsCurrent(GLSurface* surface) {
154 DCHECK(context_);
156 bool native_context_is_current = context_ == eglGetCurrentContext();
158 // If our context is current then our notion of which GLContext is
159 // current must be correct. On the other hand, third-party code
160 // using OpenGL might change the current context.
161 DCHECK(!native_context_is_current || (GetRealCurrent() == this));
163 if (!native_context_is_current)
164 return false;
166 if (surface) {
167 if (surface->GetHandle() != eglGetCurrentSurface(EGL_DRAW))
168 return false;
171 return true;
174 void* GLContextEGL::GetHandle() {
175 return context_;
178 void GLContextEGL::OnSetSwapInterval(int interval) {
179 DCHECK(IsCurrent(NULL) && GLSurface::GetCurrent());
181 // This is a surfaceless context. eglSwapInterval doesn't take any effect in
182 // this case and will just return EGL_BAD_SURFACE.
183 if (GLSurface::GetCurrent()->IsSurfaceless())
184 return;
186 if (!eglSwapInterval(display_, interval)) {
187 LOG(ERROR) << "eglSwapInterval failed with error "
188 << GetLastEGLErrorString();
189 } else {
190 swap_interval_ = interval;
191 GLSurface::GetCurrent()->OnSetSwapInterval(interval);
195 std::string GLContextEGL::GetExtensions() {
196 const char* extensions = eglQueryString(display_,
197 EGL_EXTENSIONS);
198 if (!extensions)
199 return GLContext::GetExtensions();
201 return GLContext::GetExtensions() + " " + extensions;
204 bool GLContextEGL::WasAllocatedUsingRobustnessExtension() {
205 return GLSurfaceEGL::IsCreateContextRobustnessSupported();
208 GLContextEGL::~GLContextEGL() {
209 Destroy();
212 #if !defined(OS_ANDROID)
213 bool GLContextEGL::GetTotalGpuMemory(size_t* bytes) {
214 DCHECK(bytes);
215 *bytes = 0;
216 return false;
218 #endif
220 } // namespace gfx