| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gfx/gl/gl_context_egl.h" |
| 5 | 6 |
| 6 #include "build/build_config.h" | 7 #include "build/build_config.h" |
| 7 #include "base/logging.h" | 8 #include "base/logging.h" |
| 8 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
| 9 #include "third_party/angle/include/EGL/egl.h" | 10 #include "third_party/angle/include/EGL/egl.h" |
| 10 #include "ui/gfx/gl/gl_context_egl.h" | 11 #include "ui/gfx/gl/gl_surface_egl.h" |
| 12 #include "ui/gfx/gl/egl_util.h" |
| 11 | 13 |
| 12 // This header must come after the above third-party include, as | 14 // This header must come after the above third-party include, as |
| 13 // it brings in #defines that cause conflicts. | 15 // it brings in #defines that cause conflicts. |
| 14 #include "ui/gfx/gl/gl_bindings.h" | 16 #include "ui/gfx/gl/gl_bindings.h" |
| 15 | 17 |
| 16 #if defined(OS_LINUX) | 18 #if defined(OS_LINUX) |
| 17 extern "C" { | 19 extern "C" { |
| 18 #include <X11/Xlib.h> | 20 #include <X11/Xlib.h> |
| 19 } | 21 } |
| 20 #define EGL_HAS_PBUFFERS 1 | 22 #define EGL_HAS_PBUFFERS 1 |
| 21 #endif | 23 #endif |
| 22 | 24 |
| 23 namespace gfx { | 25 namespace gfx { |
| 24 | 26 |
| 25 namespace { | 27 std::string GLContextEGL::GetExtensions() { |
| 26 | 28 const char* extensions = eglQueryString(GLSurfaceEGL::GetDisplay(), |
| 27 // The EGL configuration to use. | 29 EGL_EXTENSIONS); |
| 28 EGLDisplay g_display; | |
| 29 EGLConfig g_config; | |
| 30 | |
| 31 // Returns the last EGL error as a string. | |
| 32 const char* GetLastEGLErrorString() { | |
| 33 EGLint error = eglGetError(); | |
| 34 switch (error) { | |
| 35 case EGL_SUCCESS: | |
| 36 return "EGL_SUCCESS"; | |
| 37 case EGL_BAD_ACCESS: | |
| 38 return "EGL_BAD_ACCESS"; | |
| 39 case EGL_BAD_ALLOC: | |
| 40 return "EGL_BAD_ALLOC"; | |
| 41 case EGL_BAD_ATTRIBUTE: | |
| 42 return "EGL_BAD_ATTRIBUTE"; | |
| 43 case EGL_BAD_CONTEXT: | |
| 44 return "EGL_BAD_CONTEXT"; | |
| 45 case EGL_BAD_CONFIG: | |
| 46 return "EGL_BAD_CONFIG"; | |
| 47 case EGL_BAD_CURRENT_SURFACE: | |
| 48 return "EGL_BAD_CURRENT_SURFACE"; | |
| 49 case EGL_BAD_DISPLAY: | |
| 50 return "EGL_BAD_DISPLAY"; | |
| 51 case EGL_BAD_SURFACE: | |
| 52 return "EGL_BAD_SURFACE"; | |
| 53 case EGL_BAD_MATCH: | |
| 54 return "EGL_BAD_MATCH"; | |
| 55 case EGL_BAD_PARAMETER: | |
| 56 return "EGL_BAD_PARAMETER"; | |
| 57 case EGL_BAD_NATIVE_PIXMAP: | |
| 58 return "EGL_BAD_NATIVE_PIXMAP"; | |
| 59 case EGL_BAD_NATIVE_WINDOW: | |
| 60 return "EGL_BAD_NATIVE_WINDOW"; | |
| 61 default: | |
| 62 return "UNKNOWN"; | |
| 63 } | |
| 64 } | |
| 65 } // namespace anonymous | |
| 66 | |
| 67 SharedEGLSurface::SharedEGLSurface(EGLSurface surface) : surface_(surface) { | |
| 68 } | |
| 69 | |
| 70 SharedEGLSurface::~SharedEGLSurface() { | |
| 71 if (surface_) { | |
| 72 if (!eglDestroySurface(g_display, surface_)) { | |
| 73 LOG(ERROR) << "eglDestroySurface failed with error " | |
| 74 << GetLastEGLErrorString(); | |
| 75 } | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 EGLSurface SharedEGLSurface::egl_surface() const { | |
| 80 return surface_; | |
| 81 } | |
| 82 | |
| 83 bool BaseEGLContext::InitializeOneOff() { | |
| 84 static bool initialized = false; | |
| 85 if (initialized) | |
| 86 return true; | |
| 87 | |
| 88 #ifdef OS_LINUX | |
| 89 EGLNativeDisplayType native_display = XOpenDisplay(NULL); | |
| 90 #else | |
| 91 EGLNativeDisplayType native_display = EGL_DEFAULT_DISPLAY; | |
| 92 #endif | |
| 93 g_display = eglGetDisplay(native_display); | |
| 94 if (!g_display) { | |
| 95 LOG(ERROR) << "eglGetDisplay failed with error " << GetLastEGLErrorString(); | |
| 96 return false; | |
| 97 } | |
| 98 | |
| 99 if (!eglInitialize(g_display, NULL, NULL)) { | |
| 100 LOG(ERROR) << "eglInitialize failed with error " << GetLastEGLErrorString(); | |
| 101 return false; | |
| 102 } | |
| 103 | |
| 104 // Choose an EGL configuration. | |
| 105 static const EGLint kConfigAttribs[] = { | |
| 106 EGL_BUFFER_SIZE, 32, | |
| 107 EGL_ALPHA_SIZE, 8, | |
| 108 EGL_BLUE_SIZE, 8, | |
| 109 EGL_RED_SIZE, 8, | |
| 110 EGL_DEPTH_SIZE, 16, | |
| 111 EGL_STENCIL_SIZE, 8, | |
| 112 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, | |
| 113 #ifdef EGL_HAS_PBUFFERS | |
| 114 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, | |
| 115 #else | |
| 116 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, | |
| 117 #endif | |
| 118 EGL_NONE | |
| 119 }; | |
| 120 | |
| 121 EGLint num_configs; | |
| 122 if (!eglChooseConfig(g_display, | |
| 123 kConfigAttribs, | |
| 124 NULL, | |
| 125 0, | |
| 126 &num_configs)) { | |
| 127 LOG(ERROR) << "eglChooseConfig failed failed with error " | |
| 128 << GetLastEGLErrorString(); | |
| 129 return false; | |
| 130 } | |
| 131 | |
| 132 if (num_configs == 0) { | |
| 133 LOG(ERROR) << "No suitable EGL configs found."; | |
| 134 return false; | |
| 135 } | |
| 136 | |
| 137 scoped_array<EGLConfig> configs(new EGLConfig[num_configs]); | |
| 138 if (!eglChooseConfig(g_display, | |
| 139 kConfigAttribs, | |
| 140 configs.get(), | |
| 141 num_configs, | |
| 142 &num_configs)) { | |
| 143 LOG(ERROR) << "eglChooseConfig failed with error " | |
| 144 << GetLastEGLErrorString(); | |
| 145 return false; | |
| 146 } | |
| 147 | |
| 148 g_config = configs[0]; | |
| 149 | |
| 150 initialized = true; | |
| 151 return true; | |
| 152 } | |
| 153 | |
| 154 EGLDisplay BaseEGLContext::GetDisplay() { | |
| 155 return g_display; | |
| 156 } | |
| 157 | |
| 158 std::string BaseEGLContext::GetExtensions() { | |
| 159 const char* extensions = eglQueryString(g_display, EGL_EXTENSIONS); | |
| 160 if (!extensions) | 30 if (!extensions) |
| 161 return GLContext::GetExtensions(); | 31 return GLContext::GetExtensions(); |
| 162 | 32 |
| 163 return GLContext::GetExtensions() + " " + extensions; | 33 return GLContext::GetExtensions() + " " + extensions; |
| 164 } | 34 } |
| 165 | 35 |
| 166 NativeViewEGLContext::NativeViewEGLContext(void* window) | 36 GLContextEGL::GLContextEGL(GLSurfaceEGL* surface) |
| 167 : window_(window), | 37 : surface_(surface), |
| 168 context_(NULL) | 38 context_(NULL) |
| 169 { | 39 { |
| 170 } | 40 } |
| 171 | 41 |
| 172 NativeViewEGLContext::~NativeViewEGLContext() { | 42 GLContextEGL::~GLContextEGL() { |
| 173 } | 43 } |
| 174 | 44 |
| 175 bool NativeViewEGLContext::Initialize() { | 45 bool GLContextEGL::Initialize(GLContext* shared_context) { |
| 176 DCHECK(!context_); | 46 DCHECK(!context_); |
| 177 | 47 |
| 178 // Create a surface for the native window. | |
| 179 EGLNativeWindowType native_window = | |
| 180 reinterpret_cast<EGLNativeWindowType>(window_); | |
| 181 surface_ = new SharedEGLSurface(eglCreateWindowSurface(g_display, | |
| 182 g_config, | |
| 183 native_window, | |
| 184 NULL)); | |
| 185 | |
| 186 if (!surface_->egl_surface()) { | |
| 187 LOG(ERROR) << "eglCreateWindowSurface failed with error " | |
| 188 << GetLastEGLErrorString(); | |
| 189 Destroy(); | |
| 190 return false; | |
| 191 } | |
| 192 | |
| 193 static const EGLint kContextAttributes[] = { | 48 static const EGLint kContextAttributes[] = { |
| 194 EGL_CONTEXT_CLIENT_VERSION, 2, | 49 EGL_CONTEXT_CLIENT_VERSION, 2, |
| 195 EGL_NONE | 50 EGL_NONE |
| 196 }; | 51 }; |
| 197 | 52 |
| 198 context_ = eglCreateContext(g_display, g_config, NULL, kContextAttributes); | 53 context_ = eglCreateContext( |
| 54 GLSurfaceEGL::GetDisplay(), |
| 55 GLSurfaceEGL::GetConfig(), |
| 56 shared_context ? shared_context->GetHandle() : NULL, |
| 57 kContextAttributes); |
| 199 if (!context_) { | 58 if (!context_) { |
| 200 LOG(ERROR) << "eglCreateContext failed with error " | 59 LOG(ERROR) << "eglCreateContext failed with error " |
| 201 << GetLastEGLErrorString(); | 60 << GetLastEGLErrorString(); |
| 202 Destroy(); | 61 Destroy(); |
| 203 return false; | 62 return false; |
| 204 } | 63 } |
| 205 | 64 |
| 206 if (!MakeCurrent()) { | 65 if (!MakeCurrent()) { |
| 207 LOG(ERROR) << "MakeCurrent failed."; | 66 LOG(ERROR) << "MakeCurrent failed."; |
| 208 Destroy(); | 67 Destroy(); |
| 209 return false; | 68 return false; |
| 210 } | 69 } |
| 211 | 70 |
| 212 if (!InitializeCommon()) { | 71 if (!InitializeCommon()) { |
| 213 LOG(ERROR) << "GLContext::InitializeCommon failed."; | 72 LOG(ERROR) << "GLContext::InitializeCommon failed."; |
| 214 Destroy(); | 73 Destroy(); |
| 215 return false; | 74 return false; |
| 216 } | 75 } |
| 217 | 76 |
| 218 return true; | 77 return true; |
| 219 } | 78 } |
| 220 | 79 |
| 221 void NativeViewEGLContext::Destroy() { | 80 void GLContextEGL::Destroy() { |
| 222 if (context_) { | 81 if (context_) { |
| 223 if (!eglDestroyContext(g_display, context_)) { | 82 if (!eglDestroyContext(GLSurfaceEGL::GetDisplay(), context_)) { |
| 224 LOG(ERROR) << "eglDestroyContext failed with error " | 83 LOG(ERROR) << "eglDestroyContext failed with error " |
| 225 << GetLastEGLErrorString(); | 84 << GetLastEGLErrorString(); |
| 226 } | 85 } |
| 227 | 86 |
| 228 context_ = NULL; | 87 context_ = NULL; |
| 229 } | 88 } |
| 230 | |
| 231 surface_ = NULL; | |
| 232 } | 89 } |
| 233 | 90 |
| 234 bool NativeViewEGLContext::MakeCurrent() { | 91 bool GLContextEGL::MakeCurrent() { |
| 235 DCHECK(context_); | 92 DCHECK(context_); |
| 236 if (context_ == eglGetCurrentContext()) | 93 if (IsCurrent()) |
| 237 return true; | 94 return true; |
| 238 if (!eglMakeCurrent(g_display, | 95 |
| 239 surface_->egl_surface(), | 96 if (!eglMakeCurrent(GLSurfaceEGL::GetDisplay(), |
| 240 surface_->egl_surface(), | 97 surface_->GetHandle(), |
| 98 surface_->GetHandle(), |
| 241 context_)) { | 99 context_)) { |
| 242 VLOG(1) << "eglMakeCurrent failed with error " | 100 VLOG(1) << "eglMakeCurrent failed with error " |
| 243 << GetLastEGLErrorString(); | 101 << GetLastEGLErrorString(); |
| 244 return false; | 102 return false; |
| 245 } | 103 } |
| 246 | 104 |
| 247 return true; | 105 return true; |
| 248 } | 106 } |
| 249 | 107 |
| 250 bool NativeViewEGLContext::IsCurrent() { | 108 bool GLContextEGL::IsCurrent() { |
| 251 DCHECK(context_); | 109 DCHECK(context_); |
| 252 return context_ == eglGetCurrentContext(); | 110 return context_ == eglGetCurrentContext(); |
| 253 } | 111 } |
| 254 | 112 |
| 255 bool NativeViewEGLContext::IsOffscreen() { | 113 bool GLContextEGL::IsOffscreen() { |
| 256 return false; | 114 // TODO(apatrick): remove this from GLContext interface. |
| 115 return surface_->IsOffscreen(); |
| 257 } | 116 } |
| 258 | 117 |
| 259 bool NativeViewEGLContext::SwapBuffers() { | 118 bool GLContextEGL::SwapBuffers() { |
| 260 if (!eglSwapBuffers(g_display, surface_->egl_surface())) { | 119 // TODO(apatrick): remove this from GLContext interface. |
| 261 VLOG(1) << "eglSwapBuffers failed with error " | 120 return surface_->SwapBuffers(); |
| 262 << GetLastEGLErrorString(); | |
| 263 return false; | |
| 264 } | |
| 265 | |
| 266 return true; | |
| 267 } | 121 } |
| 268 | 122 |
| 269 gfx::Size NativeViewEGLContext::GetSize() { | 123 gfx::Size GLContextEGL::GetSize() { |
| 270 #if defined(OS_WIN) | 124 // TODO(apatrick): remove this from GLContext interface. |
| 271 RECT rect; | 125 return surface_->GetSize(); |
| 272 if (!GetClientRect(static_cast<HWND>(window_), &rect)) { | |
| 273 DCHECK(false) << "GetClientRect failed."; | |
| 274 return gfx::Size(); | |
| 275 } | |
| 276 | |
| 277 return gfx::Size(rect.right - rect.left, rect.bottom - rect.top); | |
| 278 #else | |
| 279 // TODO(piman): This doesn't work correctly on Windows yet, the size doesn't | |
| 280 // get updated on resize. When it does, we can share the code. | |
| 281 EGLint width; | |
| 282 EGLint height; | |
| 283 if (!eglQuerySurface( | |
| 284 g_display, surface_->egl_surface(), EGL_WIDTH, &width) || | |
| 285 !eglQuerySurface( | |
| 286 g_display, surface_->egl_surface(), EGL_HEIGHT, &height)) { | |
| 287 NOTREACHED() << "eglQuerySurface failed with error " | |
| 288 << GetLastEGLErrorString(); | |
| 289 return gfx::Size(); | |
| 290 } | |
| 291 | |
| 292 return gfx::Size(width, height); | |
| 293 #endif | |
| 294 } | 126 } |
| 295 | 127 |
| 296 void* NativeViewEGLContext::GetHandle() { | 128 void* GLContextEGL::GetHandle() { |
| 297 return context_; | 129 return context_; |
| 298 } | 130 } |
| 299 | 131 |
| 300 void NativeViewEGLContext::SetSwapInterval(int interval) { | 132 void GLContextEGL::SetSwapInterval(int interval) { |
| 301 DCHECK(IsCurrent()); | 133 DCHECK(IsCurrent()); |
| 302 if (!eglSwapInterval(g_display, interval)) { | 134 if (!eglSwapInterval(GLSurfaceEGL::GetDisplay(), interval)) { |
| 303 LOG(ERROR) << "eglSwapInterval failed with error " | 135 LOG(ERROR) << "eglSwapInterval failed with error " |
| 304 << GetLastEGLErrorString(); | 136 << GetLastEGLErrorString(); |
| 305 } | 137 } |
| 306 } | 138 } |
| 307 | 139 |
| 308 SharedEGLSurface* NativeViewEGLContext::GetSurface() { | |
| 309 return surface_; | |
| 310 } | |
| 311 | |
| 312 SecondaryEGLContext::SecondaryEGLContext() | |
| 313 : context_(NULL) | |
| 314 { | |
| 315 } | |
| 316 | |
| 317 SecondaryEGLContext::~SecondaryEGLContext() { | |
| 318 } | |
| 319 | |
| 320 bool SecondaryEGLContext::Initialize(GLContext* shared_context) { | |
| 321 DCHECK(!context_); | |
| 322 | |
| 323 static const EGLint kContextAttributes[] = { | |
| 324 EGL_CONTEXT_CLIENT_VERSION, 2, | |
| 325 EGL_NONE | |
| 326 }; | |
| 327 | |
| 328 if (shared_context) { | |
| 329 surface_ = static_cast<BaseEGLContext*>(shared_context)->GetSurface(); | |
| 330 | |
| 331 // Create a context. | |
| 332 context_ = eglCreateContext(g_display, | |
| 333 g_config, | |
| 334 shared_context->GetHandle(), | |
| 335 kContextAttributes); | |
| 336 } else { | |
| 337 #ifdef EGL_HAS_PBUFFERS | |
| 338 static const EGLint kPbufferAttribs[] = { | |
| 339 EGL_WIDTH, 1, | |
| 340 EGL_HEIGHT, 1, | |
| 341 EGL_NONE | |
| 342 }; | |
| 343 | |
| 344 surface_ = new SharedEGLSurface(eglCreatePbufferSurface(g_display, | |
| 345 g_config, | |
| 346 kPbufferAttribs)); | |
| 347 if (!surface_->egl_surface()) { | |
| 348 LOG(ERROR) << "eglCreatePbufferSurface failed with error " | |
| 349 << GetLastEGLErrorString(); | |
| 350 Destroy(); | |
| 351 return false; | |
| 352 } | |
| 353 | |
| 354 context_ = eglCreateContext(g_display, g_config, NULL, kContextAttributes); | |
| 355 #else | |
| 356 NOTIMPLEMENTED() << "Offscreen non-shared GLES context"; | |
| 357 return false; | |
| 358 #endif | |
| 359 } | |
| 360 | |
| 361 if (!context_) { | |
| 362 LOG(ERROR) << "eglCreateContext failed with error " | |
| 363 << GetLastEGLErrorString(); | |
| 364 Destroy(); | |
| 365 return false; | |
| 366 } | |
| 367 | |
| 368 return true; | |
| 369 } | |
| 370 | |
| 371 void SecondaryEGLContext::Destroy() { | |
| 372 if (context_) { | |
| 373 if (!eglDestroyContext(g_display, context_)) { | |
| 374 LOG(ERROR) << "eglDestroyContext failed with error " | |
| 375 << GetLastEGLErrorString(); | |
| 376 } | |
| 377 | |
| 378 context_ = NULL; | |
| 379 } | |
| 380 | |
| 381 surface_ = NULL; | |
| 382 } | |
| 383 | |
| 384 bool SecondaryEGLContext::MakeCurrent() { | |
| 385 DCHECK(context_); | |
| 386 if (context_ == eglGetCurrentContext()) | |
| 387 return true; | |
| 388 if (!eglMakeCurrent(g_display, | |
| 389 surface_->egl_surface(), | |
| 390 surface_->egl_surface(), | |
| 391 context_)) { | |
| 392 VLOG(1) << "eglMakeCurrent failed with error " | |
| 393 << GetLastEGLErrorString(); | |
| 394 return false; | |
| 395 } | |
| 396 | |
| 397 return true; | |
| 398 } | |
| 399 | |
| 400 bool SecondaryEGLContext::IsCurrent() { | |
| 401 DCHECK(context_); | |
| 402 return context_ == eglGetCurrentContext(); | |
| 403 } | |
| 404 | |
| 405 bool SecondaryEGLContext::IsOffscreen() { | |
| 406 return true; | |
| 407 } | |
| 408 | |
| 409 bool SecondaryEGLContext::SwapBuffers() { | |
| 410 NOTREACHED() << "Attempted to call SwapBuffers on a SecondaryEGLContext."; | |
| 411 return false; | |
| 412 } | |
| 413 | |
| 414 gfx::Size SecondaryEGLContext::GetSize() { | |
| 415 NOTREACHED() << "Should not be requesting size of this SecondaryEGLContext."; | |
| 416 return gfx::Size(1, 1); | |
| 417 } | |
| 418 | |
| 419 void* SecondaryEGLContext::GetHandle() { | |
| 420 return context_; | |
| 421 } | |
| 422 | |
| 423 void SecondaryEGLContext::SetSwapInterval(int interval) { | |
| 424 DCHECK(IsCurrent()); | |
| 425 NOTREACHED() << "Attempt to call SetSwapInterval on a SecondaryEGLContext."; | |
| 426 } | |
| 427 | |
| 428 SharedEGLSurface* SecondaryEGLContext::GetSurface() { | |
| 429 return surface_; | |
| 430 } | |
| 431 | |
| 432 } // namespace gfx | 140 } // namespace gfx |
| OLD | NEW |