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>
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop.h"
14 #include "build/build_config.h"
15 #include "ui/gl/egl_util.h"
16 #include "ui/gl/gl_context.h"
24 using ui::GetLastEGLErrorString
;
32 EGLNativeDisplayType g_native_display
;
33 EGLConfig g_software_config
;
34 EGLDisplay g_software_display
;
35 EGLNativeDisplayType g_software_native_display
;
37 const char* g_egl_extensions
= NULL
;
38 bool g_egl_create_context_robustness_supported
= false;
39 bool g_egl_sync_control_supported
= false;
41 class EGLSyncControlVSyncProvider
42 : public gfx::SyncControlVSyncProvider
{
44 explicit EGLSyncControlVSyncProvider(EGLSurface surface
)
45 : SyncControlVSyncProvider(),
49 virtual ~EGLSyncControlVSyncProvider() { }
52 virtual bool GetSyncValues(int64
* system_time
,
53 int64
* media_stream_counter
,
54 int64
* swap_buffer_counter
) OVERRIDE
{
55 uint64 u_system_time
, u_media_stream_counter
, u_swap_buffer_counter
;
56 bool result
= eglGetSyncValuesCHROMIUM(
57 g_display
, surface_
, &u_system_time
,
58 &u_media_stream_counter
, &u_swap_buffer_counter
) == EGL_TRUE
;
60 *system_time
= static_cast<int64
>(u_system_time
);
61 *media_stream_counter
= static_cast<int64
>(u_media_stream_counter
);
62 *swap_buffer_counter
= static_cast<int64
>(u_swap_buffer_counter
);
67 virtual bool GetMscRate(int32
* numerator
, int32
* denominator
) OVERRIDE
{
74 DISALLOW_COPY_AND_ASSIGN(EGLSyncControlVSyncProvider
);
79 GLSurfaceEGL::GLSurfaceEGL() : software_(false) {}
81 bool GLSurfaceEGL::InitializeOneOff() {
82 static bool initialized
= false;
87 g_native_display
= base::MessagePumpForUI::GetDefaultXDisplay();
89 g_native_display
= EGL_DEFAULT_DISPLAY
;
91 g_display
= eglGetDisplay(g_native_display
);
93 LOG(ERROR
) << "eglGetDisplay failed with error " << GetLastEGLErrorString();
97 if (!eglInitialize(g_display
, NULL
, NULL
)) {
98 LOG(ERROR
) << "eglInitialize failed with error " << GetLastEGLErrorString();
102 // Choose an EGL configuration.
103 // On X this is only used for PBuffer surfaces.
104 static const EGLint kConfigAttribs
[] = {
110 EGL_RENDERABLE_TYPE
, EGL_OPENGL_ES2_BIT
,
111 EGL_SURFACE_TYPE
, EGL_WINDOW_BIT
| EGL_PBUFFER_BIT
,
116 if (!eglChooseConfig(g_display
,
121 LOG(ERROR
) << "eglChooseConfig failed with error "
122 << GetLastEGLErrorString();
126 if (num_configs
== 0) {
127 LOG(ERROR
) << "No suitable EGL configs found.";
131 if (!eglChooseConfig(g_display
,
136 LOG(ERROR
) << "eglChooseConfig failed with error "
137 << GetLastEGLErrorString();
141 g_egl_extensions
= eglQueryString(g_display
, EGL_EXTENSIONS
);
142 g_egl_create_context_robustness_supported
=
143 HasEGLExtension("EGL_EXT_create_context_robustness");
144 g_egl_sync_control_supported
=
145 HasEGLExtension("EGL_CHROMIUM_sync_control");
149 #if defined(USE_X11) || defined(OS_ANDROID)
152 g_software_native_display
= EGL_SOFTWARE_DISPLAY_ANGLE
;
154 g_software_display
= eglGetDisplay(g_software_native_display
);
155 if (!g_software_display
) {
159 if (!eglInitialize(g_software_display
, NULL
, NULL
)) {
163 if (!eglChooseConfig(g_software_display
,
168 g_software_display
= NULL
;
172 if (num_configs
== 0) {
173 g_software_display
= NULL
;
177 if (!eglChooseConfig(g_software_display
,
182 g_software_display
= NULL
;
189 EGLDisplay
GLSurfaceEGL::GetDisplay() {
190 return software_
? g_software_display
: g_display
;
193 EGLDisplay
GLSurfaceEGL::GetHardwareDisplay() {
197 EGLDisplay
GLSurfaceEGL::GetSoftwareDisplay() {
198 return g_software_display
;
201 EGLNativeDisplayType
GLSurfaceEGL::GetNativeDisplay() {
202 return g_native_display
;
205 const char* GLSurfaceEGL::GetEGLExtensions() {
206 return g_egl_extensions
;
209 bool GLSurfaceEGL::HasEGLExtension(const char* name
) {
210 return ExtensionsContain(GetEGLExtensions(), name
);
213 bool GLSurfaceEGL::IsCreateContextRobustnessSupported() {
214 return g_egl_create_context_robustness_supported
;
217 GLSurfaceEGL::~GLSurfaceEGL() {}
219 NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(bool software
,
220 gfx::AcceleratedWidget window
)
223 supports_post_sub_buffer_(false),
225 software_
= software
;
226 #if defined(OS_ANDROID)
228 ANativeWindow_acquire(window
);
232 bool NativeViewGLSurfaceEGL::Initialize() {
235 if (window_
== kNullAcceleratedWidget
) {
236 LOG(ERROR
) << "Trying to create surface without window.";
241 LOG(ERROR
) << "Trying to create surface with invalid display.";
245 static const EGLint egl_window_attributes_sub_buffer
[] = {
246 EGL_POST_SUB_BUFFER_SUPPORTED_NV
, EGL_TRUE
,
250 // Create a surface for the native window.
251 surface_
= eglCreateWindowSurface(
255 gfx::g_driver_egl
.ext
.b_EGL_NV_post_sub_buffer
?
256 egl_window_attributes_sub_buffer
:
260 LOG(ERROR
) << "eglCreateWindowSurface failed with error "
261 << GetLastEGLErrorString();
267 EGLBoolean retVal
= eglQuerySurface(GetDisplay(),
269 EGL_POST_SUB_BUFFER_SUPPORTED_NV
,
271 supports_post_sub_buffer_
= (surfaceVal
&& retVal
) == EGL_TRUE
;
273 if (g_egl_sync_control_supported
)
274 vsync_provider_
.reset(new EGLSyncControlVSyncProvider(surface_
));
279 void NativeViewGLSurfaceEGL::Destroy() {
281 if (!eglDestroySurface(GetDisplay(), surface_
)) {
282 LOG(ERROR
) << "eglDestroySurface failed with error "
283 << GetLastEGLErrorString();
289 EGLConfig
NativeViewGLSurfaceEGL::GetConfig() {
290 #if !defined(USE_X11)
291 return software_
? g_software_config
: g_config
;
294 // Get a config compatible with the window
296 XWindowAttributes win_attribs
;
297 if (!XGetWindowAttributes(GetNativeDisplay(), window_
, &win_attribs
)) {
301 // Try matching the window depth with an alpha channel,
302 // because we're worried the destination alpha width could
303 // constrain blending precision.
304 const int kBufferSizeOffset
= 1;
305 const int kAlphaSizeOffset
= 3;
306 EGLint config_attribs
[] = {
312 EGL_RENDERABLE_TYPE
, EGL_OPENGL_ES2_BIT
,
313 EGL_SURFACE_TYPE
, EGL_WINDOW_BIT
| EGL_PBUFFER_BIT
,
316 config_attribs
[kBufferSizeOffset
] = win_attribs
.depth
;
319 if (!eglChooseConfig(g_display
,
324 LOG(ERROR
) << "eglChooseConfig failed with error "
325 << GetLastEGLErrorString();
331 if (!eglGetConfigAttrib(g_display
,
335 LOG(ERROR
) << "eglGetConfigAttrib failed with error "
336 << GetLastEGLErrorString();
340 if (config_depth
== win_attribs
.depth
) {
345 // Try without an alpha channel.
346 config_attribs
[kAlphaSizeOffset
] = 0;
347 if (!eglChooseConfig(g_display
,
352 LOG(ERROR
) << "eglChooseConfig failed with error "
353 << GetLastEGLErrorString();
357 if (num_configs
== 0) {
358 LOG(ERROR
) << "No suitable EGL configs found.";
366 bool NativeViewGLSurfaceEGL::IsOffscreen() {
370 bool NativeViewGLSurfaceEGL::SwapBuffers() {
371 if (!eglSwapBuffers(GetDisplay(), surface_
)) {
372 DVLOG(1) << "eglSwapBuffers failed with error "
373 << GetLastEGLErrorString();
380 gfx::Size
NativeViewGLSurfaceEGL::GetSize() {
383 if (!eglQuerySurface(GetDisplay(), surface_
, EGL_WIDTH
, &width
) ||
384 !eglQuerySurface(GetDisplay(), surface_
, EGL_HEIGHT
, &height
)) {
385 NOTREACHED() << "eglQuerySurface failed with error "
386 << GetLastEGLErrorString();
390 return gfx::Size(width
, height
);
393 bool NativeViewGLSurfaceEGL::Resize(const gfx::Size
& size
) {
394 if (size
== GetSize())
397 GLContext
* current_context
= GLContext::GetCurrent();
398 bool was_current
= current_context
&& current_context
->IsCurrent(this);
400 current_context
->ReleaseCurrent(this);
405 LOG(ERROR
) << "Failed to resize pbuffer.";
410 return current_context
->MakeCurrent(this);
414 EGLSurface
NativeViewGLSurfaceEGL::GetHandle() {
418 std::string
NativeViewGLSurfaceEGL::GetExtensions() {
419 std::string extensions
= GLSurface::GetExtensions();
420 if (supports_post_sub_buffer_
) {
421 extensions
+= extensions
.empty() ? "" : " ";
422 extensions
+= "GL_CHROMIUM_post_sub_buffer";
427 bool NativeViewGLSurfaceEGL::PostSubBuffer(
428 int x
, int y
, int width
, int height
) {
429 DCHECK(supports_post_sub_buffer_
);
430 if (!eglPostSubBufferNV(GetDisplay(), surface_
, x
, y
, width
, height
)) {
431 DVLOG(1) << "eglPostSubBufferNV failed with error "
432 << GetLastEGLErrorString();
438 VSyncProvider
* NativeViewGLSurfaceEGL::GetVSyncProvider() {
439 return vsync_provider_
.get();
442 NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() {
444 #if defined(OS_ANDROID)
446 ANativeWindow_release(window_
);
450 void NativeViewGLSurfaceEGL::SetHandle(EGLSurface surface
) {
454 PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(bool software
, const gfx::Size
& size
)
457 software_
= software
;
460 bool PbufferGLSurfaceEGL::Initialize() {
461 EGLSurface old_surface
= surface_
;
463 EGLDisplay display
= GetDisplay();
465 LOG(ERROR
) << "Trying to create surface with invalid display.";
469 if (size_
.GetArea() == 0) {
470 LOG(ERROR
) << "Error: surface has zero area "
471 << size_
.width() << " x " << size_
.height();
475 // Allocate the new pbuffer surface before freeing the old one to ensure
476 // they have different addresses. If they have the same address then a
477 // future call to MakeCurrent might early out because it appears the current
478 // context and surface have not changed.
479 const EGLint pbuffer_attribs
[] = {
480 EGL_WIDTH
, size_
.width(),
481 EGL_HEIGHT
, size_
.height(),
485 EGLSurface new_surface
= eglCreatePbufferSurface(display
,
489 LOG(ERROR
) << "eglCreatePbufferSurface failed with error "
490 << GetLastEGLErrorString();
495 eglDestroySurface(display
, old_surface
);
497 surface_
= new_surface
;
501 void PbufferGLSurfaceEGL::Destroy() {
503 if (!eglDestroySurface(GetDisplay(), surface_
)) {
504 LOG(ERROR
) << "eglDestroySurface failed with error "
505 << GetLastEGLErrorString();
511 EGLConfig
PbufferGLSurfaceEGL::GetConfig() {
512 return software_
? g_software_config
: g_config
;
515 bool PbufferGLSurfaceEGL::IsOffscreen() {
519 bool PbufferGLSurfaceEGL::SwapBuffers() {
520 NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL.";
524 gfx::Size
PbufferGLSurfaceEGL::GetSize() {
528 bool PbufferGLSurfaceEGL::Resize(const gfx::Size
& size
) {
532 GLContext
* current_context
= GLContext::GetCurrent();
533 bool was_current
= current_context
&& current_context
->IsCurrent(this);
538 LOG(ERROR
) << "Failed to resize pbuffer.";
543 return current_context
->MakeCurrent(this);
548 EGLSurface
PbufferGLSurfaceEGL::GetHandle() {
552 void* PbufferGLSurfaceEGL::GetShareHandle() {
553 #if defined(OS_ANDROID)
557 if (!gfx::g_driver_egl
.ext
.b_EGL_ANGLE_query_surface_pointer
)
560 if (!gfx::g_driver_egl
.ext
.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle
)
564 if (!eglQuerySurfacePointerANGLE(g_display
,
566 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE
,
575 PbufferGLSurfaceEGL::~PbufferGLSurfaceEGL() {