Fix crash on key events in touchview.
[chromium-blink-merge.git] / ui / gl / gl_surface_egl.cc
blob040f8087f92d6a985e19f75d6ea5993914f2ecc3
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 // This include must be here so that the includes provided transitively
6 // by gl_surface_egl.h don't make it impossible to compile this code.
7 #include "third_party/mesa/src/include/GL/osmesa.h"
9 #include "ui/gl/gl_surface_egl.h"
11 #if defined(OS_ANDROID)
12 #include <android/native_window_jni.h>
13 #endif
15 #include "base/debug/trace_event.h"
16 #include "base/logging.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/message_loop/message_loop.h"
19 #include "build/build_config.h"
20 #include "ui/gfx/geometry/rect.h"
21 #include "ui/gl/egl_util.h"
22 #include "ui/gl/gl_context.h"
23 #include "ui/gl/gl_implementation.h"
24 #include "ui/gl/gl_surface_osmesa.h"
25 #include "ui/gl/gl_surface_stub.h"
26 #include "ui/gl/gl_switches.h"
27 #include "ui/gl/scoped_make_current.h"
28 #include "ui/gl/sync_control_vsync_provider.h"
30 #if defined(USE_X11)
31 extern "C" {
32 #include <X11/Xlib.h>
34 #endif
36 #if defined (USE_OZONE)
37 #include "ui/gfx/ozone/surface_factory_ozone.h"
38 #endif
40 #if !defined(EGL_FIXED_SIZE_ANGLE)
41 #define EGL_FIXED_SIZE_ANGLE 0x3201
42 #endif
44 using ui::GetLastEGLErrorString;
46 namespace gfx {
48 namespace {
50 EGLConfig g_config;
51 EGLDisplay g_display;
52 EGLNativeDisplayType g_native_display;
54 const char* g_egl_extensions = NULL;
55 bool g_egl_create_context_robustness_supported = false;
56 bool g_egl_sync_control_supported = false;
57 bool g_egl_window_fixed_size_supported = false;
58 bool g_egl_surfaceless_context_supported = false;
60 class EGLSyncControlVSyncProvider
61 : public gfx::SyncControlVSyncProvider {
62 public:
63 explicit EGLSyncControlVSyncProvider(EGLSurface surface)
64 : SyncControlVSyncProvider(),
65 surface_(surface) {
68 virtual ~EGLSyncControlVSyncProvider() { }
70 protected:
71 virtual bool GetSyncValues(int64* system_time,
72 int64* media_stream_counter,
73 int64* swap_buffer_counter) OVERRIDE {
74 uint64 u_system_time, u_media_stream_counter, u_swap_buffer_counter;
75 bool result = eglGetSyncValuesCHROMIUM(
76 g_display, surface_, &u_system_time,
77 &u_media_stream_counter, &u_swap_buffer_counter) == EGL_TRUE;
78 if (result) {
79 *system_time = static_cast<int64>(u_system_time);
80 *media_stream_counter = static_cast<int64>(u_media_stream_counter);
81 *swap_buffer_counter = static_cast<int64>(u_swap_buffer_counter);
83 return result;
86 virtual bool GetMscRate(int32* numerator, int32* denominator) OVERRIDE {
87 return false;
90 private:
91 EGLSurface surface_;
93 DISALLOW_COPY_AND_ASSIGN(EGLSyncControlVSyncProvider);
96 } // namespace
98 GLSurfaceEGL::GLSurfaceEGL() {}
100 bool GLSurfaceEGL::InitializeOneOff() {
101 static bool initialized = false;
102 if (initialized)
103 return true;
105 g_native_display = GetPlatformDefaultEGLNativeDisplay();
106 g_display = eglGetDisplay(g_native_display);
107 if (!g_display) {
108 LOG(ERROR) << "eglGetDisplay failed with error " << GetLastEGLErrorString();
109 return false;
112 if (!eglInitialize(g_display, NULL, NULL)) {
113 LOG(ERROR) << "eglInitialize failed with error " << GetLastEGLErrorString();
114 return false;
117 // Choose an EGL configuration.
118 // On X this is only used for PBuffer surfaces.
119 static const EGLint kConfigAttribs[] = {
120 EGL_BUFFER_SIZE, 32,
121 EGL_ALPHA_SIZE, 8,
122 EGL_BLUE_SIZE, 8,
123 EGL_GREEN_SIZE, 8,
124 EGL_RED_SIZE, 8,
125 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
126 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
127 EGL_NONE
130 #if defined(USE_OZONE)
131 const EGLint* config_attribs =
132 SurfaceFactoryOzone::GetInstance()->GetEGLSurfaceProperties(
133 kConfigAttribs);
134 #else
135 const EGLint* config_attribs = kConfigAttribs;
136 #endif
138 EGLint num_configs;
139 if (!eglChooseConfig(g_display,
140 config_attribs,
141 NULL,
143 &num_configs)) {
144 LOG(ERROR) << "eglChooseConfig failed with error "
145 << GetLastEGLErrorString();
146 return false;
149 if (num_configs == 0) {
150 LOG(ERROR) << "No suitable EGL configs found.";
151 return false;
154 if (!eglChooseConfig(g_display,
155 config_attribs,
156 &g_config,
158 &num_configs)) {
159 LOG(ERROR) << "eglChooseConfig failed with error "
160 << GetLastEGLErrorString();
161 return false;
164 g_egl_extensions = eglQueryString(g_display, EGL_EXTENSIONS);
165 g_egl_create_context_robustness_supported =
166 HasEGLExtension("EGL_EXT_create_context_robustness");
167 g_egl_sync_control_supported =
168 HasEGLExtension("EGL_CHROMIUM_sync_control");
169 g_egl_window_fixed_size_supported =
170 HasEGLExtension("EGL_ANGLE_window_fixed_size");
172 // Check if SurfacelessEGL is supported.
173 g_egl_surfaceless_context_supported =
174 HasEGLExtension("EGL_KHR_surfaceless_context");
175 if (g_egl_surfaceless_context_supported) {
176 // EGL_KHR_surfaceless_context is supported but ensure
177 // GL_OES_surfaceless_context is also supported. We need a current context
178 // to query for supported GL extensions.
179 scoped_refptr<GLSurface> surface = new SurfacelessEGL(Size(1, 1));
180 scoped_refptr<GLContext> context = GLContext::CreateGLContext(
181 NULL, surface.get(), PreferIntegratedGpu);
182 if (!context->MakeCurrent(surface.get()))
183 g_egl_surfaceless_context_supported = false;
185 // Ensure context supports GL_OES_surfaceless_context.
186 if (g_egl_surfaceless_context_supported) {
187 g_egl_surfaceless_context_supported = context->HasExtension(
188 "GL_OES_surfaceless_context");
189 context->ReleaseCurrent(surface.get());
193 initialized = true;
195 return true;
198 EGLDisplay GLSurfaceEGL::GetDisplay() {
199 return g_display;
202 EGLDisplay GLSurfaceEGL::GetHardwareDisplay() {
203 return g_display;
206 EGLNativeDisplayType GLSurfaceEGL::GetNativeDisplay() {
207 return g_native_display;
210 const char* GLSurfaceEGL::GetEGLExtensions() {
211 return g_egl_extensions;
214 bool GLSurfaceEGL::HasEGLExtension(const char* name) {
215 return ExtensionsContain(GetEGLExtensions(), name);
218 bool GLSurfaceEGL::IsCreateContextRobustnessSupported() {
219 return g_egl_create_context_robustness_supported;
222 bool GLSurfaceEGL::IsEGLSurfacelessContextSupported() {
223 return g_egl_surfaceless_context_supported;
226 GLSurfaceEGL::~GLSurfaceEGL() {}
228 NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(EGLNativeWindowType window)
229 : window_(window),
230 surface_(NULL),
231 supports_post_sub_buffer_(false),
232 config_(NULL),
233 size_(1, 1) {
234 #if defined(OS_ANDROID)
235 if (window)
236 ANativeWindow_acquire(window);
237 #endif
239 #if defined(OS_WIN)
240 RECT windowRect;
241 if (GetClientRect(window_, &windowRect))
242 size_ = gfx::Rect(windowRect).size();
243 #endif
246 bool NativeViewGLSurfaceEGL::Initialize() {
247 return Initialize(scoped_ptr<VSyncProvider>());
250 bool NativeViewGLSurfaceEGL::Initialize(
251 scoped_ptr<VSyncProvider> sync_provider) {
252 DCHECK(!surface_);
254 if (!GetDisplay()) {
255 LOG(ERROR) << "Trying to create surface with invalid display.";
256 return false;
259 std::vector<EGLint> egl_window_attributes;
261 if (g_egl_window_fixed_size_supported) {
262 egl_window_attributes.push_back(EGL_FIXED_SIZE_ANGLE);
263 egl_window_attributes.push_back(EGL_TRUE);
264 egl_window_attributes.push_back(EGL_WIDTH);
265 egl_window_attributes.push_back(size_.width());
266 egl_window_attributes.push_back(EGL_HEIGHT);
267 egl_window_attributes.push_back(size_.height());
270 if (gfx::g_driver_egl.ext.b_EGL_NV_post_sub_buffer) {
271 egl_window_attributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
272 egl_window_attributes.push_back(EGL_TRUE);
275 egl_window_attributes.push_back(EGL_NONE);
276 // Create a surface for the native window.
277 surface_ = eglCreateWindowSurface(
278 GetDisplay(), GetConfig(), window_, &egl_window_attributes[0]);
280 if (!surface_) {
281 LOG(ERROR) << "eglCreateWindowSurface failed with error "
282 << GetLastEGLErrorString();
283 Destroy();
284 return false;
287 EGLint surfaceVal;
288 EGLBoolean retVal = eglQuerySurface(GetDisplay(),
289 surface_,
290 EGL_POST_SUB_BUFFER_SUPPORTED_NV,
291 &surfaceVal);
292 supports_post_sub_buffer_ = (surfaceVal && retVal) == EGL_TRUE;
294 if (sync_provider)
295 vsync_provider_.reset(sync_provider.release());
296 else if (g_egl_sync_control_supported)
297 vsync_provider_.reset(new EGLSyncControlVSyncProvider(surface_));
298 return true;
301 void NativeViewGLSurfaceEGL::Destroy() {
302 if (surface_) {
303 if (!eglDestroySurface(GetDisplay(), surface_)) {
304 LOG(ERROR) << "eglDestroySurface failed with error "
305 << GetLastEGLErrorString();
307 surface_ = NULL;
311 EGLConfig NativeViewGLSurfaceEGL::GetConfig() {
312 #if !defined(USE_X11)
313 return g_config;
314 #else
315 if (!config_) {
316 // Get a config compatible with the window
317 DCHECK(window_);
318 XWindowAttributes win_attribs;
319 if (!XGetWindowAttributes(GetNativeDisplay(), window_, &win_attribs)) {
320 return NULL;
323 // Try matching the window depth with an alpha channel,
324 // because we're worried the destination alpha width could
325 // constrain blending precision.
326 const int kBufferSizeOffset = 1;
327 const int kAlphaSizeOffset = 3;
328 EGLint config_attribs[] = {
329 EGL_BUFFER_SIZE, ~0,
330 EGL_ALPHA_SIZE, 8,
331 EGL_BLUE_SIZE, 8,
332 EGL_GREEN_SIZE, 8,
333 EGL_RED_SIZE, 8,
334 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
335 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
336 EGL_NONE
338 config_attribs[kBufferSizeOffset] = win_attribs.depth;
340 EGLint num_configs;
341 if (!eglChooseConfig(g_display,
342 config_attribs,
343 &config_,
345 &num_configs)) {
346 LOG(ERROR) << "eglChooseConfig failed with error "
347 << GetLastEGLErrorString();
348 return NULL;
351 if (num_configs) {
352 EGLint config_depth;
353 if (!eglGetConfigAttrib(g_display,
354 config_,
355 EGL_BUFFER_SIZE,
356 &config_depth)) {
357 LOG(ERROR) << "eglGetConfigAttrib failed with error "
358 << GetLastEGLErrorString();
359 return NULL;
362 if (config_depth == win_attribs.depth) {
363 return config_;
367 // Try without an alpha channel.
368 config_attribs[kAlphaSizeOffset] = 0;
369 if (!eglChooseConfig(g_display,
370 config_attribs,
371 &config_,
373 &num_configs)) {
374 LOG(ERROR) << "eglChooseConfig failed with error "
375 << GetLastEGLErrorString();
376 return NULL;
379 if (num_configs == 0) {
380 LOG(ERROR) << "No suitable EGL configs found.";
381 return NULL;
384 return config_;
385 #endif
388 bool NativeViewGLSurfaceEGL::IsOffscreen() {
389 return false;
392 bool NativeViewGLSurfaceEGL::SwapBuffers() {
393 TRACE_EVENT2("gpu", "NativeViewGLSurfaceEGL:RealSwapBuffers",
394 "width", GetSize().width(),
395 "height", GetSize().height());
397 if (!eglSwapBuffers(GetDisplay(), surface_)) {
398 DVLOG(1) << "eglSwapBuffers failed with error "
399 << GetLastEGLErrorString();
400 return false;
403 return true;
406 gfx::Size NativeViewGLSurfaceEGL::GetSize() {
407 EGLint width;
408 EGLint height;
409 if (!eglQuerySurface(GetDisplay(), surface_, EGL_WIDTH, &width) ||
410 !eglQuerySurface(GetDisplay(), surface_, EGL_HEIGHT, &height)) {
411 NOTREACHED() << "eglQuerySurface failed with error "
412 << GetLastEGLErrorString();
413 return gfx::Size();
416 return gfx::Size(width, height);
419 bool NativeViewGLSurfaceEGL::Resize(const gfx::Size& size) {
420 if (size == GetSize())
421 return true;
423 size_ = size;
425 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
426 GLContext* current_context = GLContext::GetCurrent();
427 bool was_current =
428 current_context && current_context->IsCurrent(this);
429 if (was_current) {
430 scoped_make_current.reset(
431 new ui::ScopedMakeCurrent(current_context, this));
432 current_context->ReleaseCurrent(this);
435 Destroy();
437 if (!Initialize()) {
438 LOG(ERROR) << "Failed to resize window.";
439 return false;
442 return true;
445 bool NativeViewGLSurfaceEGL::Recreate() {
446 Destroy();
447 if (!Initialize()) {
448 LOG(ERROR) << "Failed to create surface.";
449 return false;
451 return true;
454 EGLSurface NativeViewGLSurfaceEGL::GetHandle() {
455 return surface_;
458 bool NativeViewGLSurfaceEGL::SupportsPostSubBuffer() {
459 return supports_post_sub_buffer_;
462 bool NativeViewGLSurfaceEGL::PostSubBuffer(
463 int x, int y, int width, int height) {
464 DCHECK(supports_post_sub_buffer_);
465 if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) {
466 DVLOG(1) << "eglPostSubBufferNV failed with error "
467 << GetLastEGLErrorString();
468 return false;
470 return true;
473 VSyncProvider* NativeViewGLSurfaceEGL::GetVSyncProvider() {
474 return vsync_provider_.get();
477 NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() {
478 Destroy();
479 #if defined(OS_ANDROID)
480 if (window_)
481 ANativeWindow_release(window_);
482 #endif
485 void NativeViewGLSurfaceEGL::SetHandle(EGLSurface surface) {
486 surface_ = surface;
489 PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(const gfx::Size& size)
490 : size_(size),
491 surface_(NULL) {
494 bool PbufferGLSurfaceEGL::Initialize() {
495 EGLSurface old_surface = surface_;
497 EGLDisplay display = GetDisplay();
498 if (!display) {
499 LOG(ERROR) << "Trying to create surface with invalid display.";
500 return false;
503 if (size_.GetArea() == 0) {
504 LOG(ERROR) << "Error: surface has zero area "
505 << size_.width() << " x " << size_.height();
506 return false;
509 // Allocate the new pbuffer surface before freeing the old one to ensure
510 // they have different addresses. If they have the same address then a
511 // future call to MakeCurrent might early out because it appears the current
512 // context and surface have not changed.
513 const EGLint pbuffer_attribs[] = {
514 EGL_WIDTH, size_.width(),
515 EGL_HEIGHT, size_.height(),
516 EGL_NONE
519 EGLSurface new_surface = eglCreatePbufferSurface(display,
520 GetConfig(),
521 pbuffer_attribs);
522 if (!new_surface) {
523 LOG(ERROR) << "eglCreatePbufferSurface failed with error "
524 << GetLastEGLErrorString();
525 return false;
528 if (old_surface)
529 eglDestroySurface(display, old_surface);
531 surface_ = new_surface;
532 return true;
535 void PbufferGLSurfaceEGL::Destroy() {
536 if (surface_) {
537 if (!eglDestroySurface(GetDisplay(), surface_)) {
538 LOG(ERROR) << "eglDestroySurface failed with error "
539 << GetLastEGLErrorString();
541 surface_ = NULL;
545 EGLConfig PbufferGLSurfaceEGL::GetConfig() {
546 return g_config;
549 bool PbufferGLSurfaceEGL::IsOffscreen() {
550 return true;
553 bool PbufferGLSurfaceEGL::SwapBuffers() {
554 NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL.";
555 return false;
558 gfx::Size PbufferGLSurfaceEGL::GetSize() {
559 return size_;
562 bool PbufferGLSurfaceEGL::Resize(const gfx::Size& size) {
563 if (size == size_)
564 return true;
566 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
567 GLContext* current_context = GLContext::GetCurrent();
568 bool was_current =
569 current_context && current_context->IsCurrent(this);
570 if (was_current) {
571 scoped_make_current.reset(
572 new ui::ScopedMakeCurrent(current_context, this));
575 size_ = size;
577 if (!Initialize()) {
578 LOG(ERROR) << "Failed to resize pbuffer.";
579 return false;
582 return true;
585 EGLSurface PbufferGLSurfaceEGL::GetHandle() {
586 return surface_;
589 void* PbufferGLSurfaceEGL::GetShareHandle() {
590 #if defined(OS_ANDROID)
591 NOTREACHED();
592 return NULL;
593 #else
594 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_query_surface_pointer)
595 return NULL;
597 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle)
598 return NULL;
600 void* handle;
601 if (!eglQuerySurfacePointerANGLE(g_display,
602 GetHandle(),
603 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
604 &handle)) {
605 return NULL;
608 return handle;
609 #endif
612 PbufferGLSurfaceEGL::~PbufferGLSurfaceEGL() {
613 Destroy();
616 SurfacelessEGL::SurfacelessEGL(const gfx::Size& size)
617 : size_(size) {
620 bool SurfacelessEGL::Initialize() {
621 return true;
624 void SurfacelessEGL::Destroy() {
627 EGLConfig SurfacelessEGL::GetConfig() {
628 return g_config;
631 bool SurfacelessEGL::IsOffscreen() {
632 return true;
635 bool SurfacelessEGL::SwapBuffers() {
636 LOG(ERROR) << "Attempted to call SwapBuffers with SurfacelessEGL.";
637 return false;
640 gfx::Size SurfacelessEGL::GetSize() {
641 return size_;
644 bool SurfacelessEGL::Resize(const gfx::Size& size) {
645 size_ = size;
646 return true;
649 EGLSurface SurfacelessEGL::GetHandle() {
650 return EGL_NO_SURFACE;
653 void* SurfacelessEGL::GetShareHandle() {
654 return NULL;
657 SurfacelessEGL::~SurfacelessEGL() {
660 } // namespace gfx