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>
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"
36 #if defined (USE_OZONE)
37 #include "ui/gfx/ozone/surface_factory_ozone.h"
40 #if !defined(EGL_FIXED_SIZE_ANGLE)
41 #define EGL_FIXED_SIZE_ANGLE 0x3201
44 using ui::GetLastEGLErrorString
;
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
{
63 explicit EGLSyncControlVSyncProvider(EGLSurface surface
)
64 : SyncControlVSyncProvider(),
68 virtual ~EGLSyncControlVSyncProvider() { }
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
;
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
);
86 virtual bool GetMscRate(int32
* numerator
, int32
* denominator
) OVERRIDE
{
93 DISALLOW_COPY_AND_ASSIGN(EGLSyncControlVSyncProvider
);
98 GLSurfaceEGL::GLSurfaceEGL() {}
100 bool GLSurfaceEGL::InitializeOneOff() {
101 static bool initialized
= false;
105 g_native_display
= GetPlatformDefaultEGLNativeDisplay();
106 g_display
= eglGetDisplay(g_native_display
);
108 LOG(ERROR
) << "eglGetDisplay failed with error " << GetLastEGLErrorString();
112 if (!eglInitialize(g_display
, NULL
, NULL
)) {
113 LOG(ERROR
) << "eglInitialize failed with error " << GetLastEGLErrorString();
117 // Choose an EGL configuration.
118 // On X this is only used for PBuffer surfaces.
119 static const EGLint kConfigAttribs
[] = {
125 EGL_RENDERABLE_TYPE
, EGL_OPENGL_ES2_BIT
,
126 EGL_SURFACE_TYPE
, EGL_WINDOW_BIT
| EGL_PBUFFER_BIT
,
130 #if defined(USE_OZONE)
131 const EGLint
* config_attribs
=
132 SurfaceFactoryOzone::GetInstance()->GetEGLSurfaceProperties(
135 const EGLint
* config_attribs
= kConfigAttribs
;
139 if (!eglChooseConfig(g_display
,
144 LOG(ERROR
) << "eglChooseConfig failed with error "
145 << GetLastEGLErrorString();
149 if (num_configs
== 0) {
150 LOG(ERROR
) << "No suitable EGL configs found.";
154 if (!eglChooseConfig(g_display
,
159 LOG(ERROR
) << "eglChooseConfig failed with error "
160 << GetLastEGLErrorString();
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());
198 EGLDisplay
GLSurfaceEGL::GetDisplay() {
202 EGLDisplay
GLSurfaceEGL::GetHardwareDisplay() {
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
)
231 supports_post_sub_buffer_(false),
234 #if defined(OS_ANDROID)
236 ANativeWindow_acquire(window
);
241 if (GetClientRect(window_
, &windowRect
))
242 size_
= gfx::Rect(windowRect
).size();
246 bool NativeViewGLSurfaceEGL::Initialize() {
247 return Initialize(scoped_ptr
<VSyncProvider
>());
250 bool NativeViewGLSurfaceEGL::Initialize(
251 scoped_ptr
<VSyncProvider
> sync_provider
) {
255 LOG(ERROR
) << "Trying to create surface with invalid display.";
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]);
281 LOG(ERROR
) << "eglCreateWindowSurface failed with error "
282 << GetLastEGLErrorString();
288 EGLBoolean retVal
= eglQuerySurface(GetDisplay(),
290 EGL_POST_SUB_BUFFER_SUPPORTED_NV
,
292 supports_post_sub_buffer_
= (surfaceVal
&& retVal
) == EGL_TRUE
;
295 vsync_provider_
.reset(sync_provider
.release());
296 else if (g_egl_sync_control_supported
)
297 vsync_provider_
.reset(new EGLSyncControlVSyncProvider(surface_
));
301 void NativeViewGLSurfaceEGL::Destroy() {
303 if (!eglDestroySurface(GetDisplay(), surface_
)) {
304 LOG(ERROR
) << "eglDestroySurface failed with error "
305 << GetLastEGLErrorString();
311 EGLConfig
NativeViewGLSurfaceEGL::GetConfig() {
312 #if !defined(USE_X11)
316 // Get a config compatible with the window
318 XWindowAttributes win_attribs
;
319 if (!XGetWindowAttributes(GetNativeDisplay(), window_
, &win_attribs
)) {
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
[] = {
334 EGL_RENDERABLE_TYPE
, EGL_OPENGL_ES2_BIT
,
335 EGL_SURFACE_TYPE
, EGL_WINDOW_BIT
| EGL_PBUFFER_BIT
,
338 config_attribs
[kBufferSizeOffset
] = win_attribs
.depth
;
341 if (!eglChooseConfig(g_display
,
346 LOG(ERROR
) << "eglChooseConfig failed with error "
347 << GetLastEGLErrorString();
353 if (!eglGetConfigAttrib(g_display
,
357 LOG(ERROR
) << "eglGetConfigAttrib failed with error "
358 << GetLastEGLErrorString();
362 if (config_depth
== win_attribs
.depth
) {
367 // Try without an alpha channel.
368 config_attribs
[kAlphaSizeOffset
] = 0;
369 if (!eglChooseConfig(g_display
,
374 LOG(ERROR
) << "eglChooseConfig failed with error "
375 << GetLastEGLErrorString();
379 if (num_configs
== 0) {
380 LOG(ERROR
) << "No suitable EGL configs found.";
388 bool NativeViewGLSurfaceEGL::IsOffscreen() {
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();
406 gfx::Size
NativeViewGLSurfaceEGL::GetSize() {
409 if (!eglQuerySurface(GetDisplay(), surface_
, EGL_WIDTH
, &width
) ||
410 !eglQuerySurface(GetDisplay(), surface_
, EGL_HEIGHT
, &height
)) {
411 NOTREACHED() << "eglQuerySurface failed with error "
412 << GetLastEGLErrorString();
416 return gfx::Size(width
, height
);
419 bool NativeViewGLSurfaceEGL::Resize(const gfx::Size
& size
) {
420 if (size
== GetSize())
425 scoped_ptr
<ui::ScopedMakeCurrent
> scoped_make_current
;
426 GLContext
* current_context
= GLContext::GetCurrent();
428 current_context
&& current_context
->IsCurrent(this);
430 scoped_make_current
.reset(
431 new ui::ScopedMakeCurrent(current_context
, this));
432 current_context
->ReleaseCurrent(this);
438 LOG(ERROR
) << "Failed to resize window.";
445 bool NativeViewGLSurfaceEGL::Recreate() {
448 LOG(ERROR
) << "Failed to create surface.";
454 EGLSurface
NativeViewGLSurfaceEGL::GetHandle() {
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();
473 VSyncProvider
* NativeViewGLSurfaceEGL::GetVSyncProvider() {
474 return vsync_provider_
.get();
477 NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() {
479 #if defined(OS_ANDROID)
481 ANativeWindow_release(window_
);
485 void NativeViewGLSurfaceEGL::SetHandle(EGLSurface surface
) {
489 PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(const gfx::Size
& size
)
494 bool PbufferGLSurfaceEGL::Initialize() {
495 EGLSurface old_surface
= surface_
;
497 EGLDisplay display
= GetDisplay();
499 LOG(ERROR
) << "Trying to create surface with invalid display.";
503 if (size_
.GetArea() == 0) {
504 LOG(ERROR
) << "Error: surface has zero area "
505 << size_
.width() << " x " << size_
.height();
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(),
519 EGLSurface new_surface
= eglCreatePbufferSurface(display
,
523 LOG(ERROR
) << "eglCreatePbufferSurface failed with error "
524 << GetLastEGLErrorString();
529 eglDestroySurface(display
, old_surface
);
531 surface_
= new_surface
;
535 void PbufferGLSurfaceEGL::Destroy() {
537 if (!eglDestroySurface(GetDisplay(), surface_
)) {
538 LOG(ERROR
) << "eglDestroySurface failed with error "
539 << GetLastEGLErrorString();
545 EGLConfig
PbufferGLSurfaceEGL::GetConfig() {
549 bool PbufferGLSurfaceEGL::IsOffscreen() {
553 bool PbufferGLSurfaceEGL::SwapBuffers() {
554 NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL.";
558 gfx::Size
PbufferGLSurfaceEGL::GetSize() {
562 bool PbufferGLSurfaceEGL::Resize(const gfx::Size
& size
) {
566 scoped_ptr
<ui::ScopedMakeCurrent
> scoped_make_current
;
567 GLContext
* current_context
= GLContext::GetCurrent();
569 current_context
&& current_context
->IsCurrent(this);
571 scoped_make_current
.reset(
572 new ui::ScopedMakeCurrent(current_context
, this));
578 LOG(ERROR
) << "Failed to resize pbuffer.";
585 EGLSurface
PbufferGLSurfaceEGL::GetHandle() {
589 void* PbufferGLSurfaceEGL::GetShareHandle() {
590 #if defined(OS_ANDROID)
594 if (!gfx::g_driver_egl
.ext
.b_EGL_ANGLE_query_surface_pointer
)
597 if (!gfx::g_driver_egl
.ext
.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle
)
601 if (!eglQuerySurfacePointerANGLE(g_display
,
603 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE
,
612 PbufferGLSurfaceEGL::~PbufferGLSurfaceEGL() {
616 SurfacelessEGL::SurfacelessEGL(const gfx::Size
& size
)
620 bool SurfacelessEGL::Initialize() {
624 void SurfacelessEGL::Destroy() {
627 EGLConfig
SurfacelessEGL::GetConfig() {
631 bool SurfacelessEGL::IsOffscreen() {
635 bool SurfacelessEGL::SwapBuffers() {
636 LOG(ERROR
) << "Attempted to call SwapBuffers with SurfacelessEGL.";
640 gfx::Size
SurfacelessEGL::GetSize() {
644 bool SurfacelessEGL::Resize(const gfx::Size
& size
) {
649 EGLSurface
SurfacelessEGL::GetHandle() {
650 return EGL_NO_SURFACE
;
653 void* SurfacelessEGL::GetShareHandle() {
657 SurfacelessEGL::~SurfacelessEGL() {