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)
18 extern "C" {
19 #include <X11/Xlib.h>
20 }
21 #endif
22
23 using ui::GetLastEGLErrorString;
24
25 namespace gfx {
26
GLContextEGL(GLShareGroup * share_group)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 }
34
Initialize(GLSurface * compatible_surface,GpuPreference gpu_preference)35 bool 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
Destroy()80 void 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
MakeCurrent(GLSurface * surface)91 bool 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
SetUnbindFboOnMakeCurrent()131 void GLContextEGL::SetUnbindFboOnMakeCurrent() {
132 unbind_fbo_on_makecurrent_ = true;
133 }
134
ReleaseCurrent(GLSurface * surface)135 void 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
IsCurrent(GLSurface * surface)149 bool 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
GetHandle()170 void* GLContextEGL::GetHandle() {
171 return context_;
172 }
173
SetSwapInterval(int interval)174 void 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
GetExtensions()182 std::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
WasAllocatedUsingRobustnessExtension()191 bool GLContextEGL::WasAllocatedUsingRobustnessExtension() {
192 return GLSurfaceEGL::IsCreateContextRobustnessSupported();
193 }
194
~GLContextEGL()195 GLContextEGL::~GLContextEGL() {
196 Destroy();
197 }
198
199 #if !defined(OS_ANDROID)
GetTotalGpuMemory(size_t * bytes)200 bool GLContextEGL::GetTotalGpuMemory(size_t* bytes) {
201 DCHECK(bytes);
202 *bytes = 0;
203 return false;
204 }
205 #endif
206
207 } // namespace gfx
208