gpu: InProcessCommandBuffer::DestroyTransferBuffer thread safe
[chromium-blink-merge.git] / ui / gl / gl_surface_egl.cc
blob83f328eec618ec3334a000b189a6a6b76b056eaf
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 #include "base/android/sys_utils.h"
14 #endif
16 #include "base/debug/trace_event.h"
17 #include "base/logging.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "base/message_loop/message_loop.h"
20 #include "build/build_config.h"
21 #include "ui/gfx/geometry/rect.h"
22 #include "ui/gl/egl_util.h"
23 #include "ui/gl/gl_context.h"
24 #include "ui/gl/gl_implementation.h"
25 #include "ui/gl/gl_surface_osmesa.h"
26 #include "ui/gl/gl_surface_stub.h"
27 #include "ui/gl/gl_switches.h"
28 #include "ui/gl/scoped_make_current.h"
29 #include "ui/gl/sync_control_vsync_provider.h"
31 #if defined(USE_X11)
32 extern "C" {
33 #include <X11/Xlib.h>
35 #endif
37 #if defined (USE_OZONE)
38 #include "ui/gfx/ozone/surface_factory_ozone.h"
39 #endif
41 #if !defined(EGL_FIXED_SIZE_ANGLE)
42 #define EGL_FIXED_SIZE_ANGLE 0x3201
43 #endif
45 using ui::GetLastEGLErrorString;
47 namespace gfx {
49 namespace {
51 EGLConfig g_config;
52 EGLDisplay g_display;
53 EGLNativeDisplayType g_native_display;
55 const char* g_egl_extensions = NULL;
56 bool g_egl_create_context_robustness_supported = false;
57 bool g_egl_sync_control_supported = false;
58 bool g_egl_window_fixed_size_supported = false;
59 bool g_egl_surfaceless_context_supported = false;
61 class EGLSyncControlVSyncProvider
62 : public gfx::SyncControlVSyncProvider {
63 public:
64 explicit EGLSyncControlVSyncProvider(EGLSurface surface)
65 : SyncControlVSyncProvider(),
66 surface_(surface) {
69 virtual ~EGLSyncControlVSyncProvider() { }
71 protected:
72 virtual bool GetSyncValues(int64* system_time,
73 int64* media_stream_counter,
74 int64* swap_buffer_counter) OVERRIDE {
75 uint64 u_system_time, u_media_stream_counter, u_swap_buffer_counter;
76 bool result = eglGetSyncValuesCHROMIUM(
77 g_display, surface_, &u_system_time,
78 &u_media_stream_counter, &u_swap_buffer_counter) == EGL_TRUE;
79 if (result) {
80 *system_time = static_cast<int64>(u_system_time);
81 *media_stream_counter = static_cast<int64>(u_media_stream_counter);
82 *swap_buffer_counter = static_cast<int64>(u_swap_buffer_counter);
84 return result;
87 virtual bool GetMscRate(int32* numerator, int32* denominator) OVERRIDE {
88 return false;
91 private:
92 EGLSurface surface_;
94 DISALLOW_COPY_AND_ASSIGN(EGLSyncControlVSyncProvider);
97 bool ValidateEglConfig(EGLDisplay display,
98 const EGLint* config_attribs,
99 EGLint* num_configs) {
100 if (!eglChooseConfig(display,
101 config_attribs,
102 NULL,
104 num_configs)) {
105 LOG(ERROR) << "eglChooseConfig failed with error "
106 << GetLastEGLErrorString();
107 return false;
109 if (*num_configs == 0) {
110 LOG(ERROR) << "No suitable EGL configs found.";
111 return false;
113 return true;
116 } // namespace
118 GLSurfaceEGL::GLSurfaceEGL() {}
120 bool GLSurfaceEGL::InitializeOneOff() {
121 static bool initialized = false;
122 if (initialized)
123 return true;
125 g_native_display = GetPlatformDefaultEGLNativeDisplay();
126 g_display = eglGetDisplay(g_native_display);
127 if (!g_display) {
128 LOG(ERROR) << "eglGetDisplay failed with error " << GetLastEGLErrorString();
129 return false;
132 if (!eglInitialize(g_display, NULL, NULL)) {
133 LOG(ERROR) << "eglInitialize failed with error " << GetLastEGLErrorString();
134 return false;
137 // Choose an EGL configuration.
138 // On X this is only used for PBuffer surfaces.
139 static EGLint config_attribs_8888[] = {
140 EGL_BUFFER_SIZE, 32,
141 EGL_ALPHA_SIZE, 8,
142 EGL_BLUE_SIZE, 8,
143 EGL_GREEN_SIZE, 8,
144 EGL_RED_SIZE, 8,
145 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
146 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
147 EGL_NONE
150 #if defined(OS_ANDROID)
151 static EGLint config_attribs_565[] = {
152 EGL_BUFFER_SIZE, 16,
153 EGL_BLUE_SIZE, 5,
154 EGL_GREEN_SIZE, 6,
155 EGL_RED_SIZE, 5,
156 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
157 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
158 EGL_NONE
160 #endif
161 EGLint* choose_attributes = config_attribs_8888;
163 #if defined(OS_ANDROID)
164 if (base::android::SysUtils::IsLowEndDevice()) {
165 choose_attributes = config_attribs_565;
167 #endif
169 #if defined(USE_OZONE)
170 const EGLint* config_attribs =
171 SurfaceFactoryOzone::GetInstance()->GetEGLSurfaceProperties(
172 choose_attributes);
173 #else
174 const EGLint* config_attribs = choose_attributes;
175 #endif
177 EGLint num_configs;
178 EGLint config_size = 1;
179 EGLConfig* config_data = &g_config;
180 // Validate if there are any configs for given atrribs.
181 if (!ValidateEglConfig(g_display,
182 config_attribs,
183 &num_configs)) {
184 return false;
187 #if defined(OS_ANDROID)
188 scoped_ptr<EGLConfig[]> matching_configs(new EGLConfig[num_configs]);
189 if (base::android::SysUtils::IsLowEndDevice()) {
190 config_size = num_configs;
191 config_data = matching_configs.get();
193 #endif
195 if (!eglChooseConfig(g_display,
196 config_attribs,
197 config_data,
198 config_size,
199 &num_configs)) {
200 LOG(ERROR) << "eglChooseConfig failed with error "
201 << GetLastEGLErrorString();
202 return false;
205 #if defined(OS_ANDROID)
206 if (base::android::SysUtils::IsLowEndDevice()) {
207 // Because of the EGL config sort order, we have to iterate
208 // through all of them (it'll put higher sum(R,G,B) bits
209 // first with the above attribs).
210 bool match_found = false;
211 for (int i = 0; i < num_configs; i++) {
212 EGLBoolean success;
213 EGLint red, green, blue;
214 // Read the relevent attributes of the EGLConfig.
215 success = eglGetConfigAttrib(g_display, matching_configs[i],
216 EGL_RED_SIZE, &red);
217 success &= eglGetConfigAttrib(g_display, matching_configs[i],
218 EGL_BLUE_SIZE, &blue);
219 success &= eglGetConfigAttrib(g_display, matching_configs[i],
220 EGL_GREEN_SIZE, &green);
221 if ((success == EGL_TRUE) && (red == 5) &&
222 (green == 6) && (blue == 5)) {
223 g_config = matching_configs[i];
224 match_found = true;
225 break;
228 if (!match_found) {
229 // To fall back to default 32 bit format, choose with
230 // the right attributes again.
231 if (!ValidateEglConfig(g_display,
232 config_attribs_8888,
233 &num_configs)) {
234 return false;
236 if (!eglChooseConfig(g_display,
237 config_attribs_8888,
238 &g_config,
240 &num_configs)) {
241 LOG(ERROR) << "eglChooseConfig failed with error "
242 << GetLastEGLErrorString();
243 return false;
248 #endif
250 g_egl_extensions = eglQueryString(g_display, EGL_EXTENSIONS);
251 g_egl_create_context_robustness_supported =
252 HasEGLExtension("EGL_EXT_create_context_robustness");
253 g_egl_sync_control_supported =
254 HasEGLExtension("EGL_CHROMIUM_sync_control");
255 g_egl_window_fixed_size_supported =
256 HasEGLExtension("EGL_ANGLE_window_fixed_size");
258 // Check if SurfacelessEGL is supported.
259 g_egl_surfaceless_context_supported =
260 HasEGLExtension("EGL_KHR_surfaceless_context");
261 if (g_egl_surfaceless_context_supported) {
262 // EGL_KHR_surfaceless_context is supported but ensure
263 // GL_OES_surfaceless_context is also supported. We need a current context
264 // to query for supported GL extensions.
265 scoped_refptr<GLSurface> surface = new SurfacelessEGL(Size(1, 1));
266 scoped_refptr<GLContext> context = GLContext::CreateGLContext(
267 NULL, surface.get(), PreferIntegratedGpu);
268 if (!context->MakeCurrent(surface.get()))
269 g_egl_surfaceless_context_supported = false;
271 // Ensure context supports GL_OES_surfaceless_context.
272 if (g_egl_surfaceless_context_supported) {
273 g_egl_surfaceless_context_supported = context->HasExtension(
274 "GL_OES_surfaceless_context");
275 context->ReleaseCurrent(surface.get());
279 initialized = true;
281 return true;
284 EGLDisplay GLSurfaceEGL::GetDisplay() {
285 return g_display;
288 EGLDisplay GLSurfaceEGL::GetHardwareDisplay() {
289 return g_display;
292 EGLNativeDisplayType GLSurfaceEGL::GetNativeDisplay() {
293 return g_native_display;
296 const char* GLSurfaceEGL::GetEGLExtensions() {
297 return g_egl_extensions;
300 bool GLSurfaceEGL::HasEGLExtension(const char* name) {
301 return ExtensionsContain(GetEGLExtensions(), name);
304 bool GLSurfaceEGL::IsCreateContextRobustnessSupported() {
305 return g_egl_create_context_robustness_supported;
308 bool GLSurfaceEGL::IsEGLSurfacelessContextSupported() {
309 return g_egl_surfaceless_context_supported;
312 GLSurfaceEGL::~GLSurfaceEGL() {}
314 NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(EGLNativeWindowType window)
315 : window_(window),
316 surface_(NULL),
317 supports_post_sub_buffer_(false),
318 config_(NULL),
319 size_(1, 1) {
320 #if defined(OS_ANDROID)
321 if (window)
322 ANativeWindow_acquire(window);
323 #endif
325 #if defined(OS_WIN)
326 RECT windowRect;
327 if (GetClientRect(window_, &windowRect))
328 size_ = gfx::Rect(windowRect).size();
329 #endif
332 bool NativeViewGLSurfaceEGL::Initialize() {
333 return Initialize(scoped_ptr<VSyncProvider>());
336 bool NativeViewGLSurfaceEGL::Initialize(
337 scoped_ptr<VSyncProvider> sync_provider) {
338 DCHECK(!surface_);
340 if (!GetDisplay()) {
341 LOG(ERROR) << "Trying to create surface with invalid display.";
342 return false;
345 std::vector<EGLint> egl_window_attributes;
347 if (g_egl_window_fixed_size_supported) {
348 egl_window_attributes.push_back(EGL_FIXED_SIZE_ANGLE);
349 egl_window_attributes.push_back(EGL_TRUE);
350 egl_window_attributes.push_back(EGL_WIDTH);
351 egl_window_attributes.push_back(size_.width());
352 egl_window_attributes.push_back(EGL_HEIGHT);
353 egl_window_attributes.push_back(size_.height());
356 if (gfx::g_driver_egl.ext.b_EGL_NV_post_sub_buffer) {
357 egl_window_attributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
358 egl_window_attributes.push_back(EGL_TRUE);
361 egl_window_attributes.push_back(EGL_NONE);
362 // Create a surface for the native window.
363 surface_ = eglCreateWindowSurface(
364 GetDisplay(), GetConfig(), window_, &egl_window_attributes[0]);
366 if (!surface_) {
367 LOG(ERROR) << "eglCreateWindowSurface failed with error "
368 << GetLastEGLErrorString();
369 Destroy();
370 return false;
373 EGLint surfaceVal;
374 EGLBoolean retVal = eglQuerySurface(GetDisplay(),
375 surface_,
376 EGL_POST_SUB_BUFFER_SUPPORTED_NV,
377 &surfaceVal);
378 supports_post_sub_buffer_ = (surfaceVal && retVal) == EGL_TRUE;
380 if (sync_provider)
381 vsync_provider_.reset(sync_provider.release());
382 else if (g_egl_sync_control_supported)
383 vsync_provider_.reset(new EGLSyncControlVSyncProvider(surface_));
384 return true;
387 void NativeViewGLSurfaceEGL::Destroy() {
388 if (surface_) {
389 if (!eglDestroySurface(GetDisplay(), surface_)) {
390 LOG(ERROR) << "eglDestroySurface failed with error "
391 << GetLastEGLErrorString();
393 surface_ = NULL;
397 EGLConfig NativeViewGLSurfaceEGL::GetConfig() {
398 #if !defined(USE_X11)
399 return g_config;
400 #else
401 if (!config_) {
402 // Get a config compatible with the window
403 DCHECK(window_);
404 XWindowAttributes win_attribs;
405 if (!XGetWindowAttributes(GetNativeDisplay(), window_, &win_attribs)) {
406 return NULL;
409 // Try matching the window depth with an alpha channel,
410 // because we're worried the destination alpha width could
411 // constrain blending precision.
412 const int kBufferSizeOffset = 1;
413 const int kAlphaSizeOffset = 3;
414 EGLint config_attribs[] = {
415 EGL_BUFFER_SIZE, ~0,
416 EGL_ALPHA_SIZE, 8,
417 EGL_BLUE_SIZE, 8,
418 EGL_GREEN_SIZE, 8,
419 EGL_RED_SIZE, 8,
420 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
421 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
422 EGL_NONE
424 config_attribs[kBufferSizeOffset] = win_attribs.depth;
426 EGLint num_configs;
427 if (!eglChooseConfig(g_display,
428 config_attribs,
429 &config_,
431 &num_configs)) {
432 LOG(ERROR) << "eglChooseConfig failed with error "
433 << GetLastEGLErrorString();
434 return NULL;
437 if (num_configs) {
438 EGLint config_depth;
439 if (!eglGetConfigAttrib(g_display,
440 config_,
441 EGL_BUFFER_SIZE,
442 &config_depth)) {
443 LOG(ERROR) << "eglGetConfigAttrib failed with error "
444 << GetLastEGLErrorString();
445 return NULL;
448 if (config_depth == win_attribs.depth) {
449 return config_;
453 // Try without an alpha channel.
454 config_attribs[kAlphaSizeOffset] = 0;
455 if (!eglChooseConfig(g_display,
456 config_attribs,
457 &config_,
459 &num_configs)) {
460 LOG(ERROR) << "eglChooseConfig failed with error "
461 << GetLastEGLErrorString();
462 return NULL;
465 if (num_configs == 0) {
466 LOG(ERROR) << "No suitable EGL configs found.";
467 return NULL;
470 return config_;
471 #endif
474 bool NativeViewGLSurfaceEGL::IsOffscreen() {
475 return false;
478 bool NativeViewGLSurfaceEGL::SwapBuffers() {
479 TRACE_EVENT2("gpu", "NativeViewGLSurfaceEGL:RealSwapBuffers",
480 "width", GetSize().width(),
481 "height", GetSize().height());
483 if (!eglSwapBuffers(GetDisplay(), surface_)) {
484 DVLOG(1) << "eglSwapBuffers failed with error "
485 << GetLastEGLErrorString();
486 return false;
489 return true;
492 gfx::Size NativeViewGLSurfaceEGL::GetSize() {
493 EGLint width;
494 EGLint height;
495 if (!eglQuerySurface(GetDisplay(), surface_, EGL_WIDTH, &width) ||
496 !eglQuerySurface(GetDisplay(), surface_, EGL_HEIGHT, &height)) {
497 NOTREACHED() << "eglQuerySurface failed with error "
498 << GetLastEGLErrorString();
499 return gfx::Size();
502 return gfx::Size(width, height);
505 bool NativeViewGLSurfaceEGL::Resize(const gfx::Size& size) {
506 if (size == GetSize())
507 return true;
509 size_ = size;
511 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
512 GLContext* current_context = GLContext::GetCurrent();
513 bool was_current =
514 current_context && current_context->IsCurrent(this);
515 if (was_current) {
516 scoped_make_current.reset(
517 new ui::ScopedMakeCurrent(current_context, this));
518 current_context->ReleaseCurrent(this);
521 Destroy();
523 if (!Initialize()) {
524 LOG(ERROR) << "Failed to resize window.";
525 return false;
528 return true;
531 bool NativeViewGLSurfaceEGL::Recreate() {
532 Destroy();
533 if (!Initialize()) {
534 LOG(ERROR) << "Failed to create surface.";
535 return false;
537 return true;
540 EGLSurface NativeViewGLSurfaceEGL::GetHandle() {
541 return surface_;
544 bool NativeViewGLSurfaceEGL::SupportsPostSubBuffer() {
545 return supports_post_sub_buffer_;
548 bool NativeViewGLSurfaceEGL::PostSubBuffer(
549 int x, int y, int width, int height) {
550 DCHECK(supports_post_sub_buffer_);
551 if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) {
552 DVLOG(1) << "eglPostSubBufferNV failed with error "
553 << GetLastEGLErrorString();
554 return false;
556 return true;
559 VSyncProvider* NativeViewGLSurfaceEGL::GetVSyncProvider() {
560 return vsync_provider_.get();
563 NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() {
564 Destroy();
565 #if defined(OS_ANDROID)
566 if (window_)
567 ANativeWindow_release(window_);
568 #endif
571 void NativeViewGLSurfaceEGL::SetHandle(EGLSurface surface) {
572 surface_ = surface;
575 PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(const gfx::Size& size)
576 : size_(size),
577 surface_(NULL) {
580 bool PbufferGLSurfaceEGL::Initialize() {
581 EGLSurface old_surface = surface_;
583 EGLDisplay display = GetDisplay();
584 if (!display) {
585 LOG(ERROR) << "Trying to create surface with invalid display.";
586 return false;
589 if (size_.GetArea() == 0) {
590 LOG(ERROR) << "Error: surface has zero area "
591 << size_.width() << " x " << size_.height();
592 return false;
595 // Allocate the new pbuffer surface before freeing the old one to ensure
596 // they have different addresses. If they have the same address then a
597 // future call to MakeCurrent might early out because it appears the current
598 // context and surface have not changed.
599 const EGLint pbuffer_attribs[] = {
600 EGL_WIDTH, size_.width(),
601 EGL_HEIGHT, size_.height(),
602 EGL_NONE
605 EGLSurface new_surface = eglCreatePbufferSurface(display,
606 GetConfig(),
607 pbuffer_attribs);
608 if (!new_surface) {
609 LOG(ERROR) << "eglCreatePbufferSurface failed with error "
610 << GetLastEGLErrorString();
611 return false;
614 if (old_surface)
615 eglDestroySurface(display, old_surface);
617 surface_ = new_surface;
618 return true;
621 void PbufferGLSurfaceEGL::Destroy() {
622 if (surface_) {
623 if (!eglDestroySurface(GetDisplay(), surface_)) {
624 LOG(ERROR) << "eglDestroySurface failed with error "
625 << GetLastEGLErrorString();
627 surface_ = NULL;
631 EGLConfig PbufferGLSurfaceEGL::GetConfig() {
632 return g_config;
635 bool PbufferGLSurfaceEGL::IsOffscreen() {
636 return true;
639 bool PbufferGLSurfaceEGL::SwapBuffers() {
640 NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL.";
641 return false;
644 gfx::Size PbufferGLSurfaceEGL::GetSize() {
645 return size_;
648 bool PbufferGLSurfaceEGL::Resize(const gfx::Size& size) {
649 if (size == size_)
650 return true;
652 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
653 GLContext* current_context = GLContext::GetCurrent();
654 bool was_current =
655 current_context && current_context->IsCurrent(this);
656 if (was_current) {
657 scoped_make_current.reset(
658 new ui::ScopedMakeCurrent(current_context, this));
661 size_ = size;
663 if (!Initialize()) {
664 LOG(ERROR) << "Failed to resize pbuffer.";
665 return false;
668 return true;
671 EGLSurface PbufferGLSurfaceEGL::GetHandle() {
672 return surface_;
675 void* PbufferGLSurfaceEGL::GetShareHandle() {
676 #if defined(OS_ANDROID)
677 NOTREACHED();
678 return NULL;
679 #else
680 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_query_surface_pointer)
681 return NULL;
683 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle)
684 return NULL;
686 void* handle;
687 if (!eglQuerySurfacePointerANGLE(g_display,
688 GetHandle(),
689 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
690 &handle)) {
691 return NULL;
694 return handle;
695 #endif
698 PbufferGLSurfaceEGL::~PbufferGLSurfaceEGL() {
699 Destroy();
702 SurfacelessEGL::SurfacelessEGL(const gfx::Size& size)
703 : size_(size) {
706 bool SurfacelessEGL::Initialize() {
707 return true;
710 void SurfacelessEGL::Destroy() {
713 EGLConfig SurfacelessEGL::GetConfig() {
714 return g_config;
717 bool SurfacelessEGL::IsOffscreen() {
718 return true;
721 bool SurfacelessEGL::SwapBuffers() {
722 LOG(ERROR) << "Attempted to call SwapBuffers with SurfacelessEGL.";
723 return false;
726 gfx::Size SurfacelessEGL::GetSize() {
727 return size_;
730 bool SurfacelessEGL::Resize(const gfx::Size& size) {
731 size_ = size;
732 return true;
735 EGLSurface SurfacelessEGL::GetHandle() {
736 return EGL_NO_SURFACE;
739 void* SurfacelessEGL::GetShareHandle() {
740 return NULL;
743 SurfacelessEGL::~SurfacelessEGL() {
746 } // namespace gfx