Blink roll 25b6bd3a7a131ffe68d809546ad1a20707915cdc:3a503f41ae42e5b79cfcd2ff10e65afde...
[chromium-blink-merge.git] / ui / gl / gl_surface_egl.cc
blob19119a9bb0badfc69be76465e8488636a8b4f3d5
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_surface_egl.h"
7 #if defined(OS_ANDROID)
8 #include <android/native_window_jni.h>
9 #endif
11 #include "base/command_line.h"
12 #include "base/debug/trace_event.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "build/build_config.h"
17 #include "ui/gfx/geometry/rect.h"
18 #include "ui/gl/egl_util.h"
19 #include "ui/gl/gl_context.h"
20 #include "ui/gl/gl_implementation.h"
21 #include "ui/gl/gl_surface_stub.h"
22 #include "ui/gl/gl_switches.h"
23 #include "ui/gl/scoped_make_current.h"
24 #include "ui/gl/sync_control_vsync_provider.h"
26 #if defined(USE_X11)
27 extern "C" {
28 #include <X11/Xlib.h>
30 #endif
32 #if defined (USE_OZONE)
33 #include "ui/ozone/public/surface_factory_ozone.h"
34 #endif
36 #if !defined(EGL_FIXED_SIZE_ANGLE)
37 #define EGL_FIXED_SIZE_ANGLE 0x3201
38 #endif
40 #if defined(OS_WIN)
41 // From ANGLE's egl/eglext.h.
42 #if !defined(EGL_PLATFORM_ANGLE_ANGLE)
43 #define EGL_PLATFORM_ANGLE_ANGLE 0x3201
44 #endif
45 #if !defined(EGL_PLATFORM_ANGLE_TYPE_ANGLE)
46 #define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202
47 #endif
48 #if !defined(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
49 #define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3207
50 #endif
51 #if !defined(EGL_PLATFORM_ANGLE_USE_WARP_ANGLE)
52 #define EGL_PLATFORM_ANGLE_USE_WARP_ANGLE 0x3208
53 #endif
54 #endif // defined(OS_WIN)
56 using ui::GetLastEGLErrorString;
58 namespace gfx {
60 namespace {
62 EGLConfig g_config;
63 EGLDisplay g_display;
64 EGLNativeDisplayType g_native_display;
66 const char* g_egl_extensions = NULL;
67 bool g_egl_create_context_robustness_supported = false;
68 bool g_egl_sync_control_supported = false;
69 bool g_egl_window_fixed_size_supported = false;
70 bool g_egl_surfaceless_context_supported = false;
72 class EGLSyncControlVSyncProvider
73 : public gfx::SyncControlVSyncProvider {
74 public:
75 explicit EGLSyncControlVSyncProvider(EGLSurface surface)
76 : SyncControlVSyncProvider(),
77 surface_(surface) {
80 ~EGLSyncControlVSyncProvider() override {}
82 protected:
83 bool GetSyncValues(int64* system_time,
84 int64* media_stream_counter,
85 int64* swap_buffer_counter) override {
86 uint64 u_system_time, u_media_stream_counter, u_swap_buffer_counter;
87 bool result = eglGetSyncValuesCHROMIUM(
88 g_display, surface_, &u_system_time,
89 &u_media_stream_counter, &u_swap_buffer_counter) == EGL_TRUE;
90 if (result) {
91 *system_time = static_cast<int64>(u_system_time);
92 *media_stream_counter = static_cast<int64>(u_media_stream_counter);
93 *swap_buffer_counter = static_cast<int64>(u_swap_buffer_counter);
95 return result;
98 bool GetMscRate(int32* numerator, int32* denominator) override {
99 return false;
102 private:
103 EGLSurface surface_;
105 DISALLOW_COPY_AND_ASSIGN(EGLSyncControlVSyncProvider);
108 } // namespace
110 GLSurfaceEGL::GLSurfaceEGL() {}
112 bool GLSurfaceEGL::InitializeOneOff() {
113 static bool initialized = false;
114 if (initialized)
115 return true;
117 g_native_display = GetPlatformDefaultEGLNativeDisplay();
119 #if defined(OS_WIN)
120 g_display = GetPlatformDisplay(g_native_display);
121 #else
122 g_display = eglGetDisplay(g_native_display);
123 #endif
125 if (!g_display) {
126 LOG(ERROR) << "eglGetDisplay failed with error " << GetLastEGLErrorString();
127 return false;
130 if (!eglInitialize(g_display, NULL, NULL)) {
131 LOG(ERROR) << "eglInitialize failed with error " << GetLastEGLErrorString();
132 return false;
135 // Choose an EGL configuration.
136 // On X this is only used for PBuffer surfaces.
137 static const EGLint kConfigAttribs[] = {
138 EGL_BUFFER_SIZE, 32,
139 EGL_ALPHA_SIZE, 8,
140 EGL_BLUE_SIZE, 8,
141 EGL_GREEN_SIZE, 8,
142 EGL_RED_SIZE, 8,
143 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
144 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
145 EGL_NONE
148 #if defined(USE_OZONE)
149 const EGLint* config_attribs =
150 ui::SurfaceFactoryOzone::GetInstance()->GetEGLSurfaceProperties(
151 kConfigAttribs);
152 #else
153 const EGLint* config_attribs = kConfigAttribs;
154 #endif
156 EGLint num_configs;
157 if (!eglChooseConfig(g_display,
158 config_attribs,
159 NULL,
161 &num_configs)) {
162 LOG(ERROR) << "eglChooseConfig failed with error "
163 << GetLastEGLErrorString();
164 return false;
167 if (num_configs == 0) {
168 LOG(ERROR) << "No suitable EGL configs found.";
169 return false;
172 if (!eglChooseConfig(g_display,
173 config_attribs,
174 &g_config,
176 &num_configs)) {
177 LOG(ERROR) << "eglChooseConfig failed with error "
178 << GetLastEGLErrorString();
179 return false;
182 g_egl_extensions = eglQueryString(g_display, EGL_EXTENSIONS);
183 g_egl_create_context_robustness_supported =
184 HasEGLExtension("EGL_EXT_create_context_robustness");
185 g_egl_sync_control_supported =
186 HasEGLExtension("EGL_CHROMIUM_sync_control");
187 g_egl_window_fixed_size_supported =
188 HasEGLExtension("EGL_ANGLE_window_fixed_size");
190 // TODO(oetuaho@nvidia.com): Surfaceless is disabled on Android as a temporary
191 // workaround, since code written for Android WebView takes different paths
192 // based on whether GL surface objects have underlying EGL surface handles,
193 // conflicting with the use of surfaceless. See https://crbug.com/382349
194 #if defined(OS_ANDROID)
195 DCHECK(!g_egl_surfaceless_context_supported);
196 #else
197 // Check if SurfacelessEGL is supported.
198 g_egl_surfaceless_context_supported =
199 HasEGLExtension("EGL_KHR_surfaceless_context");
200 if (g_egl_surfaceless_context_supported) {
201 // EGL_KHR_surfaceless_context is supported but ensure
202 // GL_OES_surfaceless_context is also supported. We need a current context
203 // to query for supported GL extensions.
204 scoped_refptr<GLSurface> surface = new SurfacelessEGL(Size(1, 1));
205 scoped_refptr<GLContext> context = GLContext::CreateGLContext(
206 NULL, surface.get(), PreferIntegratedGpu);
207 if (!context->MakeCurrent(surface.get()))
208 g_egl_surfaceless_context_supported = false;
210 // Ensure context supports GL_OES_surfaceless_context.
211 if (g_egl_surfaceless_context_supported) {
212 g_egl_surfaceless_context_supported = context->HasExtension(
213 "GL_OES_surfaceless_context");
214 context->ReleaseCurrent(surface.get());
217 #endif
219 initialized = true;
221 return true;
224 EGLDisplay GLSurfaceEGL::GetDisplay() {
225 return g_display;
228 EGLDisplay GLSurfaceEGL::GetHardwareDisplay() {
229 return g_display;
232 EGLNativeDisplayType GLSurfaceEGL::GetNativeDisplay() {
233 return g_native_display;
236 const char* GLSurfaceEGL::GetEGLExtensions() {
237 return g_egl_extensions;
240 bool GLSurfaceEGL::HasEGLExtension(const char* name) {
241 return ExtensionsContain(GetEGLExtensions(), name);
244 bool GLSurfaceEGL::IsCreateContextRobustnessSupported() {
245 return g_egl_create_context_robustness_supported;
248 bool GLSurfaceEGL::IsEGLSurfacelessContextSupported() {
249 return g_egl_surfaceless_context_supported;
252 GLSurfaceEGL::~GLSurfaceEGL() {}
254 #if defined(OS_WIN)
255 static const EGLint kDisplayAttribsWarp[] {
256 EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
257 EGL_PLATFORM_ANGLE_USE_WARP_ANGLE, EGL_TRUE,
258 EGL_NONE
261 // static
262 EGLDisplay GLSurfaceEGL::GetPlatformDisplay(
263 EGLNativeDisplayType native_display) {
264 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseWarp)) {
265 // Check for availability of WARP via ANGLE extension.
266 bool supports_warp = false;
267 const char* no_display_extensions = eglQueryString(EGL_NO_DISPLAY,
268 EGL_EXTENSIONS);
269 // If EGL_EXT_client_extensions not supported this call to eglQueryString
270 // will return NULL.
271 if (no_display_extensions)
272 supports_warp =
273 ExtensionsContain(no_display_extensions, "ANGLE_platform_angle") &&
274 ExtensionsContain(no_display_extensions, "ANGLE_platform_angle_d3d");
276 if (!supports_warp)
277 return NULL;
279 return eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, native_display,
280 kDisplayAttribsWarp);
283 return eglGetDisplay(native_display);
285 #endif
287 NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(EGLNativeWindowType window)
288 : window_(window),
289 surface_(NULL),
290 supports_post_sub_buffer_(false),
291 config_(NULL),
292 size_(1, 1) {
293 #if defined(OS_ANDROID)
294 if (window)
295 ANativeWindow_acquire(window);
296 #endif
298 #if defined(OS_WIN)
299 RECT windowRect;
300 if (GetClientRect(window_, &windowRect))
301 size_ = gfx::Rect(windowRect).size();
302 #endif
305 bool NativeViewGLSurfaceEGL::Initialize() {
306 return Initialize(scoped_ptr<VSyncProvider>());
309 bool NativeViewGLSurfaceEGL::Initialize(
310 scoped_ptr<VSyncProvider> sync_provider) {
311 DCHECK(!surface_);
313 if (!GetDisplay()) {
314 LOG(ERROR) << "Trying to create surface with invalid display.";
315 return false;
318 std::vector<EGLint> egl_window_attributes;
320 if (g_egl_window_fixed_size_supported) {
321 egl_window_attributes.push_back(EGL_FIXED_SIZE_ANGLE);
322 egl_window_attributes.push_back(EGL_TRUE);
323 egl_window_attributes.push_back(EGL_WIDTH);
324 egl_window_attributes.push_back(size_.width());
325 egl_window_attributes.push_back(EGL_HEIGHT);
326 egl_window_attributes.push_back(size_.height());
329 if (gfx::g_driver_egl.ext.b_EGL_NV_post_sub_buffer) {
330 egl_window_attributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
331 egl_window_attributes.push_back(EGL_TRUE);
334 egl_window_attributes.push_back(EGL_NONE);
335 // Create a surface for the native window.
336 surface_ = eglCreateWindowSurface(
337 GetDisplay(), GetConfig(), window_, &egl_window_attributes[0]);
339 if (!surface_) {
340 LOG(ERROR) << "eglCreateWindowSurface failed with error "
341 << GetLastEGLErrorString();
342 Destroy();
343 return false;
346 EGLint surfaceVal;
347 EGLBoolean retVal = eglQuerySurface(GetDisplay(),
348 surface_,
349 EGL_POST_SUB_BUFFER_SUPPORTED_NV,
350 &surfaceVal);
351 supports_post_sub_buffer_ = (surfaceVal && retVal) == EGL_TRUE;
353 if (sync_provider)
354 vsync_provider_.reset(sync_provider.release());
355 else if (g_egl_sync_control_supported)
356 vsync_provider_.reset(new EGLSyncControlVSyncProvider(surface_));
357 return true;
360 void NativeViewGLSurfaceEGL::Destroy() {
361 if (surface_) {
362 if (!eglDestroySurface(GetDisplay(), surface_)) {
363 LOG(ERROR) << "eglDestroySurface failed with error "
364 << GetLastEGLErrorString();
366 surface_ = NULL;
370 EGLConfig NativeViewGLSurfaceEGL::GetConfig() {
371 #if !defined(USE_X11)
372 return g_config;
373 #else
374 if (!config_) {
375 // Get a config compatible with the window
376 DCHECK(window_);
377 XWindowAttributes win_attribs;
378 if (!XGetWindowAttributes(GetNativeDisplay(), window_, &win_attribs)) {
379 return NULL;
382 // Try matching the window depth with an alpha channel,
383 // because we're worried the destination alpha width could
384 // constrain blending precision.
385 const int kBufferSizeOffset = 1;
386 const int kAlphaSizeOffset = 3;
387 EGLint config_attribs[] = {
388 EGL_BUFFER_SIZE, ~0,
389 EGL_ALPHA_SIZE, 8,
390 EGL_BLUE_SIZE, 8,
391 EGL_GREEN_SIZE, 8,
392 EGL_RED_SIZE, 8,
393 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
394 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
395 EGL_NONE
397 config_attribs[kBufferSizeOffset] = win_attribs.depth;
399 EGLint num_configs;
400 if (!eglChooseConfig(g_display,
401 config_attribs,
402 &config_,
404 &num_configs)) {
405 LOG(ERROR) << "eglChooseConfig failed with error "
406 << GetLastEGLErrorString();
407 return NULL;
410 if (num_configs) {
411 EGLint config_depth;
412 if (!eglGetConfigAttrib(g_display,
413 config_,
414 EGL_BUFFER_SIZE,
415 &config_depth)) {
416 LOG(ERROR) << "eglGetConfigAttrib failed with error "
417 << GetLastEGLErrorString();
418 return NULL;
421 if (config_depth == win_attribs.depth) {
422 return config_;
426 // Try without an alpha channel.
427 config_attribs[kAlphaSizeOffset] = 0;
428 if (!eglChooseConfig(g_display,
429 config_attribs,
430 &config_,
432 &num_configs)) {
433 LOG(ERROR) << "eglChooseConfig failed with error "
434 << GetLastEGLErrorString();
435 return NULL;
438 if (num_configs == 0) {
439 LOG(ERROR) << "No suitable EGL configs found.";
440 return NULL;
443 return config_;
444 #endif
447 bool NativeViewGLSurfaceEGL::IsOffscreen() {
448 return false;
451 bool NativeViewGLSurfaceEGL::SwapBuffers() {
452 TRACE_EVENT2("gpu", "NativeViewGLSurfaceEGL:RealSwapBuffers",
453 "width", GetSize().width(),
454 "height", GetSize().height());
456 if (!eglSwapBuffers(GetDisplay(), surface_)) {
457 DVLOG(1) << "eglSwapBuffers failed with error "
458 << GetLastEGLErrorString();
459 return false;
462 return true;
465 gfx::Size NativeViewGLSurfaceEGL::GetSize() {
466 EGLint width;
467 EGLint height;
468 if (!eglQuerySurface(GetDisplay(), surface_, EGL_WIDTH, &width) ||
469 !eglQuerySurface(GetDisplay(), surface_, EGL_HEIGHT, &height)) {
470 NOTREACHED() << "eglQuerySurface failed with error "
471 << GetLastEGLErrorString();
472 return gfx::Size();
475 return gfx::Size(width, height);
478 bool NativeViewGLSurfaceEGL::Resize(const gfx::Size& size) {
479 if (size == GetSize())
480 return true;
482 size_ = size;
484 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
485 GLContext* current_context = GLContext::GetCurrent();
486 bool was_current =
487 current_context && current_context->IsCurrent(this);
488 if (was_current) {
489 scoped_make_current.reset(
490 new ui::ScopedMakeCurrent(current_context, this));
491 current_context->ReleaseCurrent(this);
494 Destroy();
496 if (!Initialize()) {
497 LOG(ERROR) << "Failed to resize window.";
498 return false;
501 return true;
504 bool NativeViewGLSurfaceEGL::Recreate() {
505 Destroy();
506 if (!Initialize()) {
507 LOG(ERROR) << "Failed to create surface.";
508 return false;
510 return true;
513 EGLSurface NativeViewGLSurfaceEGL::GetHandle() {
514 return surface_;
517 bool NativeViewGLSurfaceEGL::SupportsPostSubBuffer() {
518 return supports_post_sub_buffer_;
521 bool NativeViewGLSurfaceEGL::PostSubBuffer(
522 int x, int y, int width, int height) {
523 DCHECK(supports_post_sub_buffer_);
524 if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) {
525 DVLOG(1) << "eglPostSubBufferNV failed with error "
526 << GetLastEGLErrorString();
527 return false;
529 return true;
532 VSyncProvider* NativeViewGLSurfaceEGL::GetVSyncProvider() {
533 return vsync_provider_.get();
536 NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() {
537 Destroy();
538 #if defined(OS_ANDROID)
539 if (window_)
540 ANativeWindow_release(window_);
541 #endif
544 PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(const gfx::Size& size)
545 : size_(size),
546 surface_(NULL) {
547 // Some implementations of Pbuffer do not support having a 0 size. For such
548 // cases use a (1, 1) surface.
549 if (size_.GetArea() == 0)
550 size_.SetSize(1, 1);
553 bool PbufferGLSurfaceEGL::Initialize() {
554 EGLSurface old_surface = surface_;
556 EGLDisplay display = GetDisplay();
557 if (!display) {
558 LOG(ERROR) << "Trying to create surface with invalid display.";
559 return false;
562 // Allocate the new pbuffer surface before freeing the old one to ensure
563 // they have different addresses. If they have the same address then a
564 // future call to MakeCurrent might early out because it appears the current
565 // context and surface have not changed.
566 const EGLint pbuffer_attribs[] = {
567 EGL_WIDTH, size_.width(),
568 EGL_HEIGHT, size_.height(),
569 EGL_NONE
572 EGLSurface new_surface = eglCreatePbufferSurface(display,
573 GetConfig(),
574 pbuffer_attribs);
575 if (!new_surface) {
576 LOG(ERROR) << "eglCreatePbufferSurface failed with error "
577 << GetLastEGLErrorString();
578 return false;
581 if (old_surface)
582 eglDestroySurface(display, old_surface);
584 surface_ = new_surface;
585 return true;
588 void PbufferGLSurfaceEGL::Destroy() {
589 if (surface_) {
590 if (!eglDestroySurface(GetDisplay(), surface_)) {
591 LOG(ERROR) << "eglDestroySurface failed with error "
592 << GetLastEGLErrorString();
594 surface_ = NULL;
598 EGLConfig PbufferGLSurfaceEGL::GetConfig() {
599 return g_config;
602 bool PbufferGLSurfaceEGL::IsOffscreen() {
603 return true;
606 bool PbufferGLSurfaceEGL::SwapBuffers() {
607 NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL.";
608 return false;
611 gfx::Size PbufferGLSurfaceEGL::GetSize() {
612 return size_;
615 bool PbufferGLSurfaceEGL::Resize(const gfx::Size& size) {
616 if (size == size_)
617 return true;
619 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
620 GLContext* current_context = GLContext::GetCurrent();
621 bool was_current =
622 current_context && current_context->IsCurrent(this);
623 if (was_current) {
624 scoped_make_current.reset(
625 new ui::ScopedMakeCurrent(current_context, this));
628 size_ = size;
630 if (!Initialize()) {
631 LOG(ERROR) << "Failed to resize pbuffer.";
632 return false;
635 return true;
638 EGLSurface PbufferGLSurfaceEGL::GetHandle() {
639 return surface_;
642 void* PbufferGLSurfaceEGL::GetShareHandle() {
643 #if defined(OS_ANDROID)
644 NOTREACHED();
645 return NULL;
646 #else
647 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_query_surface_pointer)
648 return NULL;
650 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle)
651 return NULL;
653 void* handle;
654 if (!eglQuerySurfacePointerANGLE(g_display,
655 GetHandle(),
656 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
657 &handle)) {
658 return NULL;
661 return handle;
662 #endif
665 PbufferGLSurfaceEGL::~PbufferGLSurfaceEGL() {
666 Destroy();
669 SurfacelessEGL::SurfacelessEGL(const gfx::Size& size)
670 : size_(size) {
673 bool SurfacelessEGL::Initialize() {
674 return true;
677 void SurfacelessEGL::Destroy() {
680 EGLConfig SurfacelessEGL::GetConfig() {
681 return g_config;
684 bool SurfacelessEGL::IsOffscreen() {
685 return true;
688 bool SurfacelessEGL::IsSurfaceless() const {
689 return true;
692 bool SurfacelessEGL::SwapBuffers() {
693 LOG(ERROR) << "Attempted to call SwapBuffers with SurfacelessEGL.";
694 return false;
697 gfx::Size SurfacelessEGL::GetSize() {
698 return size_;
701 bool SurfacelessEGL::Resize(const gfx::Size& size) {
702 size_ = size;
703 return true;
706 EGLSurface SurfacelessEGL::GetHandle() {
707 return EGL_NO_SURFACE;
710 void* SurfacelessEGL::GetShareHandle() {
711 return NULL;
714 SurfacelessEGL::~SurfacelessEGL() {
717 } // namespace gfx