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"
16 #include "base/command_line.h"
17 #include "base/debug/trace_event.h"
18 #include "base/logging.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "base/message_loop/message_loop.h"
21 #include "build/build_config.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"
37 #if defined (USE_OZONE)
38 #include "ui/gfx/ozone/surface_factory_ozone.h"
41 // From ANGLE's egl/eglext.h.
42 #if !defined(EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE)
43 #define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE \
44 reinterpret_cast<EGLNativeDisplayType>(-2)
46 #if !defined(EGL_FIXED_SIZE_ANGLE)
47 #define EGL_FIXED_SIZE_ANGLE 0x3201
50 using ui::GetLastEGLErrorString;
58 EGLNativeDisplayType g_native_display;
60 const char* g_egl_extensions = NULL;
61 bool g_egl_create_context_robustness_supported = false;
62 bool g_egl_sync_control_supported = false;
63 bool g_egl_window_fixed_size_supported = false;
64 bool g_egl_surfaceless_context_supported = false;
66 class EGLSyncControlVSyncProvider
67 : public gfx::SyncControlVSyncProvider {
69 explicit EGLSyncControlVSyncProvider(EGLSurface surface)
70 : SyncControlVSyncProvider(),
74 virtual ~EGLSyncControlVSyncProvider() { }
77 virtual bool GetSyncValues(int64* system_time,
78 int64* media_stream_counter,
79 int64* swap_buffer_counter) OVERRIDE {
80 uint64 u_system_time, u_media_stream_counter, u_swap_buffer_counter;
81 bool result = eglGetSyncValuesCHROMIUM(
82 g_display, surface_, &u_system_time,
83 &u_media_stream_counter, &u_swap_buffer_counter) == EGL_TRUE;
85 *system_time = static_cast<int64>(u_system_time);
86 *media_stream_counter = static_cast<int64>(u_media_stream_counter);
87 *swap_buffer_counter = static_cast<int64>(u_swap_buffer_counter);
92 virtual bool GetMscRate(int32* numerator, int32* denominator) OVERRIDE {
99 DISALLOW_COPY_AND_ASSIGN(EGLSyncControlVSyncProvider);
102 bool ValidateEglConfig(EGLDisplay display,
103 const EGLint* config_attribs,
104 EGLint* num_configs) {
105 if (!eglChooseConfig(display,
110 LOG(ERROR) << "eglChooseConfig failed with error "
111 << GetLastEGLErrorString();
114 if (*num_configs == 0) {
115 LOG(ERROR) << "No suitable EGL configs found.";
123 GLSurfaceEGL::GLSurfaceEGL() {}
125 bool GLSurfaceEGL::InitializeOneOff() {
126 static bool initialized = false;
131 g_native_display = base::MessagePumpForUI::GetDefaultXDisplay();
132 #elif defined(OS_WIN)
133 g_native_display = EGL_DEFAULT_DISPLAY;
134 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableD3D11) &&
135 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableD3D11)) {
136 g_native_display = EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE;
138 #elif defined(USE_OZONE)
139 gfx::SurfaceFactoryOzone* surface_factory =
140 gfx::SurfaceFactoryOzone::GetInstance();
141 if (surface_factory->InitializeHardware() !=
142 gfx::SurfaceFactoryOzone::INITIALIZED) {
143 LOG(ERROR) << "OZONE failed to initialize hardware";
146 g_native_display = surface_factory->GetNativeDisplay();
148 g_native_display = EGL_DEFAULT_DISPLAY;
150 g_display = eglGetDisplay(g_native_display);
152 LOG(ERROR) << "eglGetDisplay failed with error " << GetLastEGLErrorString();
156 if (!eglInitialize(g_display, NULL, NULL)) {
157 LOG(ERROR) << "eglInitialize failed with error " << GetLastEGLErrorString();
161 // Choose an EGL configuration.
162 // On X this is only used for PBuffer surfaces.
163 static EGLint config_attribs_8888[] = {
169 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
170 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
174 #if defined(OS_ANDROID)
175 static EGLint config_attribs_565[] = {
180 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
181 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
185 EGLint* choose_attributes = config_attribs_8888;
187 #if defined(OS_ANDROID)
188 if (base::android::SysUtils::IsLowEndDevice()) {
189 choose_attributes = config_attribs_565;
193 #if defined(USE_OZONE)
194 const EGLint* config_attribs =
195 surface_factory->GetEGLSurfaceProperties(choose_attributes);
197 const EGLint* config_attribs = choose_attributes;
201 EGLint config_size = 1;
202 EGLConfig* config_data = &g_config;
203 // Validate if there are any configs for given atrribs.
204 if (!ValidateEglConfig(g_display,
210 #if defined(OS_ANDROID)
211 scoped_ptr<EGLConfig[]> matching_configs(new EGLConfig[num_configs]);
212 if (base::android::SysUtils::IsLowEndDevice()) {
213 config_size = num_configs;
214 config_data = matching_configs.get();
218 if (!eglChooseConfig(g_display,
223 LOG(ERROR) << "eglChooseConfig failed with error "
224 << GetLastEGLErrorString();
228 #if defined(OS_ANDROID)
229 if (base::android::SysUtils::IsLowEndDevice()) {
230 // Because of the EGL config sort order, we have to iterate
231 // through all of them (it'll put higher sum(R,G,B) bits
232 // first with the above attribs).
233 bool match_found = false;
234 for (int i = 0; i < num_configs; i++) {
236 EGLint red, green, blue;
237 // Read the relevent attributes of the EGLConfig.
238 success = eglGetConfigAttrib(g_display, matching_configs[i],
240 success &= eglGetConfigAttrib(g_display, matching_configs[i],
241 EGL_BLUE_SIZE, &blue);
242 success &= eglGetConfigAttrib(g_display, matching_configs[i],
243 EGL_GREEN_SIZE, &green);
244 if ((success == EGL_TRUE) && (red == 5) &&
245 (green == 6) && (blue == 5)) {
246 g_config = matching_configs[i];
252 // To fall back to default 32 bit format, choose with
253 // the right attributes again.
254 if (!ValidateEglConfig(g_display,
259 if (!eglChooseConfig(g_display,
264 LOG(ERROR) << "eglChooseConfig failed with error "
265 << GetLastEGLErrorString();
273 g_egl_extensions = eglQueryString(g_display, EGL_EXTENSIONS);
274 g_egl_create_context_robustness_supported =
275 HasEGLExtension("EGL_EXT_create_context_robustness");
276 g_egl_sync_control_supported =
277 HasEGLExtension("EGL_CHROMIUM_sync_control");
278 g_egl_window_fixed_size_supported =
279 HasEGLExtension("EGL_ANGLE_window_fixed_size");
281 // Check if SurfacelessEGL is supported.
282 g_egl_surfaceless_context_supported =
283 HasEGLExtension("EGL_KHR_surfaceless_context");
284 if (g_egl_surfaceless_context_supported) {
285 // EGL_KHR_surfaceless_context is supported but ensure
286 // GL_OES_surfaceless_context is also supported. We need a current context
287 // to query for supported GL extensions.
288 scoped_refptr<GLSurface> surface = new SurfacelessEGL(Size(1, 1));
289 scoped_refptr<GLContext> context = GLContext::CreateGLContext(
290 NULL, surface.get(), PreferIntegratedGpu);
291 if (!context->MakeCurrent(surface.get()))
292 g_egl_surfaceless_context_supported = false;
294 // Ensure context supports GL_OES_surfaceless_context.
295 if (g_egl_surfaceless_context_supported) {
296 g_egl_surfaceless_context_supported = context->HasExtension(
297 "GL_OES_surfaceless_context");
298 context->ReleaseCurrent(surface.get());
307 EGLDisplay GLSurfaceEGL::GetDisplay() {
311 EGLDisplay GLSurfaceEGL::GetHardwareDisplay() {
315 EGLNativeDisplayType GLSurfaceEGL::GetNativeDisplay() {
316 return g_native_display;
319 const char* GLSurfaceEGL::GetEGLExtensions() {
320 return g_egl_extensions;
323 bool GLSurfaceEGL::HasEGLExtension(const char* name) {
324 return ExtensionsContain(GetEGLExtensions(), name);
327 bool GLSurfaceEGL::IsCreateContextRobustnessSupported() {
328 return g_egl_create_context_robustness_supported;
331 GLSurfaceEGL::~GLSurfaceEGL() {}
333 NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(gfx::AcceleratedWidget window)
336 supports_post_sub_buffer_(false),
339 #if defined(OS_ANDROID)
341 ANativeWindow_acquire(window);
345 bool NativeViewGLSurfaceEGL::Initialize() {
346 return Initialize(scoped_ptr<VSyncProvider>());
349 bool NativeViewGLSurfaceEGL::Initialize(
350 scoped_ptr<VSyncProvider> sync_provider) {
353 if (window_ == kNullAcceleratedWidget) {
354 LOG(ERROR) << "Trying to create surface without window.";
359 LOG(ERROR) << "Trying to create surface with invalid display.";
363 std::vector<EGLint> egl_window_attributes;
365 if (g_egl_window_fixed_size_supported) {
366 egl_window_attributes.push_back(EGL_FIXED_SIZE_ANGLE);
367 egl_window_attributes.push_back(EGL_TRUE);
368 egl_window_attributes.push_back(EGL_WIDTH);
369 egl_window_attributes.push_back(size_.width());
370 egl_window_attributes.push_back(EGL_HEIGHT);
371 egl_window_attributes.push_back(size_.height());
374 if (gfx::g_driver_egl.ext.b_EGL_NV_post_sub_buffer) {
375 egl_window_attributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
376 egl_window_attributes.push_back(EGL_TRUE);
379 egl_window_attributes.push_back(EGL_NONE);
380 // Create a surface for the native window.
381 surface_ = eglCreateWindowSurface(
382 GetDisplay(), GetConfig(), window_, &egl_window_attributes[0]);
385 LOG(ERROR) << "eglCreateWindowSurface failed with error "
386 << GetLastEGLErrorString();
392 EGLBoolean retVal = eglQuerySurface(GetDisplay(),
394 EGL_POST_SUB_BUFFER_SUPPORTED_NV,
396 supports_post_sub_buffer_ = (surfaceVal && retVal) == EGL_TRUE;
399 vsync_provider_.reset(sync_provider.release());
400 else if (g_egl_sync_control_supported)
401 vsync_provider_.reset(new EGLSyncControlVSyncProvider(surface_));
405 void NativeViewGLSurfaceEGL::Destroy() {
407 if (!eglDestroySurface(GetDisplay(), surface_)) {
408 LOG(ERROR) << "eglDestroySurface failed with error "
409 << GetLastEGLErrorString();
415 EGLConfig NativeViewGLSurfaceEGL::GetConfig() {
416 #if !defined(USE_X11)
420 // Get a config compatible with the window
422 XWindowAttributes win_attribs;
423 if (!XGetWindowAttributes(GetNativeDisplay(), window_, &win_attribs)) {
427 // Try matching the window depth with an alpha channel,
428 // because we're worried the destination alpha width could
429 // constrain blending precision.
430 const int kBufferSizeOffset = 1;
431 const int kAlphaSizeOffset = 3;
432 EGLint config_attribs[] = {
438 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
439 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
442 config_attribs[kBufferSizeOffset] = win_attribs.depth;
445 if (!eglChooseConfig(g_display,
450 LOG(ERROR) << "eglChooseConfig failed with error "
451 << GetLastEGLErrorString();
457 if (!eglGetConfigAttrib(g_display,
461 LOG(ERROR) << "eglGetConfigAttrib failed with error "
462 << GetLastEGLErrorString();
466 if (config_depth == win_attribs.depth) {
471 // Try without an alpha channel.
472 config_attribs[kAlphaSizeOffset] = 0;
473 if (!eglChooseConfig(g_display,
478 LOG(ERROR) << "eglChooseConfig failed with error "
479 << GetLastEGLErrorString();
483 if (num_configs == 0) {
484 LOG(ERROR) << "No suitable EGL configs found.";
492 bool NativeViewGLSurfaceEGL::IsOffscreen() {
496 bool NativeViewGLSurfaceEGL::SwapBuffers() {
497 TRACE_EVENT2("gpu", "NativeViewGLSurfaceEGL:RealSwapBuffers",
498 "width", GetSize().width(),
499 "height", GetSize().height());
501 if (!eglSwapBuffers(GetDisplay(), surface_)) {
502 DVLOG(1) << "eglSwapBuffers failed with error "
503 << GetLastEGLErrorString();
510 gfx::Size NativeViewGLSurfaceEGL::GetSize() {
513 if (!eglQuerySurface(GetDisplay(), surface_, EGL_WIDTH, &width) ||
514 !eglQuerySurface(GetDisplay(), surface_, EGL_HEIGHT, &height)) {
515 NOTREACHED() << "eglQuerySurface failed with error "
516 << GetLastEGLErrorString();
520 return gfx::Size(width, height);
523 bool NativeViewGLSurfaceEGL::Resize(const gfx::Size& size) {
524 if (size == GetSize())
529 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
530 GLContext* current_context = GLContext::GetCurrent();
532 current_context && current_context->IsCurrent(this);
534 scoped_make_current.reset(
535 new ui::ScopedMakeCurrent(current_context, this));
536 current_context->ReleaseCurrent(this);
542 LOG(ERROR) << "Failed to resize window.";
549 bool NativeViewGLSurfaceEGL::Recreate() {
552 LOG(ERROR) << "Failed to create surface.";
558 EGLSurface NativeViewGLSurfaceEGL::GetHandle() {
562 std::string NativeViewGLSurfaceEGL::GetExtensions() {
563 std::string extensions = GLSurface::GetExtensions();
564 if (supports_post_sub_buffer_) {
565 extensions += extensions.empty() ? "" : " ";
566 extensions += "GL_CHROMIUM_post_sub_buffer";
571 bool NativeViewGLSurfaceEGL::PostSubBuffer(
572 int x, int y, int width, int height) {
573 DCHECK(supports_post_sub_buffer_);
574 if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) {
575 DVLOG(1) << "eglPostSubBufferNV failed with error "
576 << GetLastEGLErrorString();
582 VSyncProvider* NativeViewGLSurfaceEGL::GetVSyncProvider() {
583 return vsync_provider_.get();
586 NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() {
588 #if defined(OS_ANDROID)
590 ANativeWindow_release(window_);
594 void NativeViewGLSurfaceEGL::SetHandle(EGLSurface surface) {
598 PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(const gfx::Size& size)
603 bool PbufferGLSurfaceEGL::Initialize() {
604 EGLSurface old_surface = surface_;
606 EGLDisplay display = GetDisplay();
608 LOG(ERROR) << "Trying to create surface with invalid display.";
612 if (size_.GetArea() == 0) {
613 LOG(ERROR) << "Error: surface has zero area "
614 << size_.width() << " x " << size_.height();
618 // Allocate the new pbuffer surface before freeing the old one to ensure
619 // they have different addresses. If they have the same address then a
620 // future call to MakeCurrent might early out because it appears the current
621 // context and surface have not changed.
622 const EGLint pbuffer_attribs[] = {
623 EGL_WIDTH, size_.width(),
624 EGL_HEIGHT, size_.height(),
628 EGLSurface new_surface = eglCreatePbufferSurface(display,
632 LOG(ERROR) << "eglCreatePbufferSurface failed with error "
633 << GetLastEGLErrorString();
638 eglDestroySurface(display, old_surface);
640 surface_ = new_surface;
644 void PbufferGLSurfaceEGL::Destroy() {
646 if (!eglDestroySurface(GetDisplay(), surface_)) {
647 LOG(ERROR) << "eglDestroySurface failed with error "
648 << GetLastEGLErrorString();
654 EGLConfig PbufferGLSurfaceEGL::GetConfig() {
658 bool PbufferGLSurfaceEGL::IsOffscreen() {
662 bool PbufferGLSurfaceEGL::SwapBuffers() {
663 NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL.";
667 gfx::Size PbufferGLSurfaceEGL::GetSize() {
671 bool PbufferGLSurfaceEGL::Resize(const gfx::Size& size) {
675 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
676 GLContext* current_context = GLContext::GetCurrent();
678 current_context && current_context->IsCurrent(this);
680 scoped_make_current.reset(
681 new ui::ScopedMakeCurrent(current_context, this));
687 LOG(ERROR) << "Failed to resize pbuffer.";
694 EGLSurface PbufferGLSurfaceEGL::GetHandle() {
698 void* PbufferGLSurfaceEGL::GetShareHandle() {
699 #if defined(OS_ANDROID)
703 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_query_surface_pointer)
706 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle)
710 if (!eglQuerySurfacePointerANGLE(g_display,
712 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
721 PbufferGLSurfaceEGL::~PbufferGLSurfaceEGL() {
725 SurfacelessEGL::SurfacelessEGL(const gfx::Size& size)
729 bool SurfacelessEGL::Initialize() {
733 void SurfacelessEGL::Destroy() {
736 EGLConfig SurfacelessEGL::GetConfig() {
740 bool SurfacelessEGL::IsOffscreen() {
744 bool SurfacelessEGL::SwapBuffers() {
745 LOG(ERROR) << "Attempted to call SwapBuffers with SurfacelessEGL.";
749 gfx::Size SurfacelessEGL::GetSize() {
753 bool SurfacelessEGL::Resize(const gfx::Size& size) {
758 EGLSurface SurfacelessEGL::GetHandle() {
759 return EGL_NO_SURFACE;
762 void* SurfacelessEGL::GetShareHandle() {
766 SurfacelessEGL::~SurfacelessEGL() {
769 #if defined(ANDROID) || defined(USE_OZONE)
771 // A thin subclass of |GLSurfaceOSMesa| that can be used in place
772 // of a native hardware-provided surface when a native surface
773 // provider is not available.
774 class GLSurfaceOSMesaHeadless : public GLSurfaceOSMesa {
776 explicit GLSurfaceOSMesaHeadless(gfx::AcceleratedWidget window);
778 virtual bool IsOffscreen() OVERRIDE;
779 virtual bool SwapBuffers() OVERRIDE;
782 virtual ~GLSurfaceOSMesaHeadless();
786 DISALLOW_COPY_AND_ASSIGN(GLSurfaceOSMesaHeadless);
789 bool GLSurfaceOSMesaHeadless::IsOffscreen() { return false; }
791 bool GLSurfaceOSMesaHeadless::SwapBuffers() { return true; }
793 GLSurfaceOSMesaHeadless::GLSurfaceOSMesaHeadless(gfx::AcceleratedWidget window)
794 : GLSurfaceOSMesa(OSMESA_BGRA, gfx::Size(1, 1)) {
798 GLSurfaceOSMesaHeadless::~GLSurfaceOSMesaHeadless() { Destroy(); }
801 bool GLSurface::InitializeOneOffInternal() {
802 switch (GetGLImplementation()) {
803 case kGLImplementationEGLGLES2:
804 if (!GLSurfaceEGL::InitializeOneOff()) {
805 LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
815 scoped_refptr<GLSurface>
816 GLSurface::CreateViewGLSurface(gfx::AcceleratedWidget window) {
818 if (GetGLImplementation() == kGLImplementationOSMesaGL) {
819 scoped_refptr<GLSurface> surface(new GLSurfaceOSMesaHeadless(window));
820 if (!surface->Initialize())
824 DCHECK(GetGLImplementation() == kGLImplementationEGLGLES2);
826 scoped_refptr<NativeViewGLSurfaceEGL> surface;
827 scoped_ptr<VSyncProvider> sync_provider;
828 #if defined(USE_OZONE)
829 window = gfx::SurfaceFactoryOzone::GetInstance()->RealizeAcceleratedWidget(
832 gfx::SurfaceFactoryOzone::GetInstance()->CreateVSyncProvider(window);
834 surface = new NativeViewGLSurfaceEGL(window);
835 if(surface->Initialize(sync_provider.Pass()))
838 scoped_refptr<GLSurface> surface = new GLSurfaceStub();
839 if (surface->Initialize())
846 scoped_refptr<GLSurface>
847 GLSurface::CreateOffscreenGLSurface(const gfx::Size& size) {
848 switch (GetGLImplementation()) {
849 case kGLImplementationOSMesaGL: {
850 scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(1, size));
851 if (!surface->Initialize())
856 case kGLImplementationEGLGLES2: {
857 scoped_refptr<GLSurface> surface;
858 if (g_egl_surfaceless_context_supported &&
859 (size.width() == 1 && size.height() == 1)) {
860 surface = new SurfacelessEGL(size);
862 surface = new PbufferGLSurfaceEGL(size);
864 if (!surface->Initialize())