blob: 3a453b6e20fdf19816f6bfea3e8ff63516221262 [file] [log] [blame]
James Robinson646469d2014-10-03 15:33:28 -07001// 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.
4
5#include "ui/gl/gl_surface_egl.h"
6
7#if defined(OS_ANDROID)
8#include <android/native_window_jni.h>
9#endif
10
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"
25
26#if defined(USE_X11)
27extern "C" {
28#include <X11/Xlib.h>
29}
30#endif
31
32#if defined (USE_OZONE)
33#include "ui/ozone/public/surface_factory_ozone.h"
34#endif
35
36#if !defined(EGL_FIXED_SIZE_ANGLE)
37#define EGL_FIXED_SIZE_ANGLE 0x3201
38#endif
39
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
James Robinson6e9a1c92014-11-13 17:05:42 -080048#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
James Robinson646469d2014-10-03 15:33:28 -070053#endif
54#endif // defined(OS_WIN)
55
56using ui::GetLastEGLErrorString;
57
58namespace gfx {
59
60namespace {
61
62EGLConfig g_config;
63EGLDisplay g_display;
James Robinsonc4c1c592014-11-21 18:27:04 -080064EGLNativeDisplayType g_native_display_type;
65
66// In the Cast environment, we need to destroy the EGLNativeDisplayType and
67// EGLDisplay returned by the GPU platform when we switch to an external app
68// which will temporarily own all screen and GPU resources.
69// Even though Chromium is still in the background.
70// As such, it must be reinitialized each time we come back to the foreground.
71bool g_initialized = false;
72int g_num_surfaces = 0;
73bool g_terminate_pending = false;
James Robinson646469d2014-10-03 15:33:28 -070074
75const char* g_egl_extensions = NULL;
76bool g_egl_create_context_robustness_supported = false;
77bool g_egl_sync_control_supported = false;
78bool g_egl_window_fixed_size_supported = false;
79bool g_egl_surfaceless_context_supported = false;
80
81class EGLSyncControlVSyncProvider
82 : public gfx::SyncControlVSyncProvider {
83 public:
84 explicit EGLSyncControlVSyncProvider(EGLSurface surface)
85 : SyncControlVSyncProvider(),
86 surface_(surface) {
87 }
88
James Robinson7f480212014-10-31 10:28:08 -070089 ~EGLSyncControlVSyncProvider() override {}
James Robinson646469d2014-10-03 15:33:28 -070090
91 protected:
James Robinson7f480212014-10-31 10:28:08 -070092 bool GetSyncValues(int64* system_time,
93 int64* media_stream_counter,
94 int64* swap_buffer_counter) override {
James Robinson646469d2014-10-03 15:33:28 -070095 uint64 u_system_time, u_media_stream_counter, u_swap_buffer_counter;
96 bool result = eglGetSyncValuesCHROMIUM(
97 g_display, surface_, &u_system_time,
98 &u_media_stream_counter, &u_swap_buffer_counter) == EGL_TRUE;
99 if (result) {
100 *system_time = static_cast<int64>(u_system_time);
101 *media_stream_counter = static_cast<int64>(u_media_stream_counter);
102 *swap_buffer_counter = static_cast<int64>(u_swap_buffer_counter);
103 }
104 return result;
105 }
106
James Robinson7f480212014-10-31 10:28:08 -0700107 bool GetMscRate(int32* numerator, int32* denominator) override {
James Robinson646469d2014-10-03 15:33:28 -0700108 return false;
109 }
110
111 private:
112 EGLSurface surface_;
113
114 DISALLOW_COPY_AND_ASSIGN(EGLSyncControlVSyncProvider);
115};
116
James Robinsonc4c1c592014-11-21 18:27:04 -0800117void DeinitializeEgl() {
118 if (g_initialized) {
119 g_initialized = false;
120 eglTerminate(g_display);
121 }
122}
123
James Robinson646469d2014-10-03 15:33:28 -0700124} // namespace
125
James Robinsonc4c1c592014-11-21 18:27:04 -0800126GLSurfaceEGL::GLSurfaceEGL() {
127 ++g_num_surfaces;
128 if (!g_initialized) {
129 bool result = GLSurfaceEGL::InitializeOneOff();
130 DCHECK(result);
131 DCHECK(g_initialized);
132 }
133}
James Robinson646469d2014-10-03 15:33:28 -0700134
135bool GLSurfaceEGL::InitializeOneOff() {
James Robinsonc4c1c592014-11-21 18:27:04 -0800136 if (g_initialized)
James Robinson646469d2014-10-03 15:33:28 -0700137 return true;
138
James Robinsonc4c1c592014-11-21 18:27:04 -0800139 g_native_display_type = GetPlatformDefaultEGLNativeDisplay();
James Robinson646469d2014-10-03 15:33:28 -0700140
141#if defined(OS_WIN)
James Robinsonc4c1c592014-11-21 18:27:04 -0800142 g_display = GetPlatformDisplay(g_native_display_type);
James Robinson646469d2014-10-03 15:33:28 -0700143#else
James Robinsonc4c1c592014-11-21 18:27:04 -0800144 g_display = eglGetDisplay(g_native_display_type);
James Robinson646469d2014-10-03 15:33:28 -0700145#endif
146
147 if (!g_display) {
148 LOG(ERROR) << "eglGetDisplay failed with error " << GetLastEGLErrorString();
149 return false;
150 }
151
152 if (!eglInitialize(g_display, NULL, NULL)) {
153 LOG(ERROR) << "eglInitialize failed with error " << GetLastEGLErrorString();
154 return false;
155 }
156
157 // Choose an EGL configuration.
158 // On X this is only used for PBuffer surfaces.
159 static const EGLint kConfigAttribs[] = {
160 EGL_BUFFER_SIZE, 32,
161 EGL_ALPHA_SIZE, 8,
162 EGL_BLUE_SIZE, 8,
163 EGL_GREEN_SIZE, 8,
164 EGL_RED_SIZE, 8,
165 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
166 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
167 EGL_NONE
168 };
169
170#if defined(USE_OZONE)
171 const EGLint* config_attribs =
172 ui::SurfaceFactoryOzone::GetInstance()->GetEGLSurfaceProperties(
173 kConfigAttribs);
174#else
175 const EGLint* config_attribs = kConfigAttribs;
176#endif
177
178 EGLint num_configs;
179 if (!eglChooseConfig(g_display,
180 config_attribs,
181 NULL,
182 0,
183 &num_configs)) {
184 LOG(ERROR) << "eglChooseConfig failed with error "
185 << GetLastEGLErrorString();
186 return false;
187 }
188
189 if (num_configs == 0) {
190 LOG(ERROR) << "No suitable EGL configs found.";
191 return false;
192 }
193
194 if (!eglChooseConfig(g_display,
195 config_attribs,
196 &g_config,
197 1,
198 &num_configs)) {
199 LOG(ERROR) << "eglChooseConfig failed with error "
200 << GetLastEGLErrorString();
201 return false;
202 }
203
204 g_egl_extensions = eglQueryString(g_display, EGL_EXTENSIONS);
205 g_egl_create_context_robustness_supported =
206 HasEGLExtension("EGL_EXT_create_context_robustness");
207 g_egl_sync_control_supported =
208 HasEGLExtension("EGL_CHROMIUM_sync_control");
209 g_egl_window_fixed_size_supported =
210 HasEGLExtension("EGL_ANGLE_window_fixed_size");
211
James Robinsonc4c1c592014-11-21 18:27:04 -0800212 // We always succeed beyond this point so set g_initialized here to avoid
213 // infinite recursion through CreateGLContext and GetDisplay
214 // if g_egl_surfaceless_context_supported.
215 g_initialized = true;
216 g_terminate_pending = false;
217
James Robinson646469d2014-10-03 15:33:28 -0700218 // TODO(oetuaho@nvidia.com): Surfaceless is disabled on Android as a temporary
219 // workaround, since code written for Android WebView takes different paths
220 // based on whether GL surface objects have underlying EGL surface handles,
221 // conflicting with the use of surfaceless. See https://crbug.com/382349
222#if defined(OS_ANDROID)
223 DCHECK(!g_egl_surfaceless_context_supported);
224#else
225 // Check if SurfacelessEGL is supported.
226 g_egl_surfaceless_context_supported =
227 HasEGLExtension("EGL_KHR_surfaceless_context");
228 if (g_egl_surfaceless_context_supported) {
229 // EGL_KHR_surfaceless_context is supported but ensure
230 // GL_OES_surfaceless_context is also supported. We need a current context
231 // to query for supported GL extensions.
232 scoped_refptr<GLSurface> surface = new SurfacelessEGL(Size(1, 1));
233 scoped_refptr<GLContext> context = GLContext::CreateGLContext(
234 NULL, surface.get(), PreferIntegratedGpu);
235 if (!context->MakeCurrent(surface.get()))
236 g_egl_surfaceless_context_supported = false;
237
238 // Ensure context supports GL_OES_surfaceless_context.
239 if (g_egl_surfaceless_context_supported) {
240 g_egl_surfaceless_context_supported = context->HasExtension(
241 "GL_OES_surfaceless_context");
242 context->ReleaseCurrent(surface.get());
243 }
244 }
245#endif
246
James Robinson646469d2014-10-03 15:33:28 -0700247 return true;
248}
249
250EGLDisplay GLSurfaceEGL::GetDisplay() {
James Robinsonc4c1c592014-11-21 18:27:04 -0800251 DCHECK(g_initialized);
James Robinson646469d2014-10-03 15:33:28 -0700252 return g_display;
253}
254
James Robinsonc4c1c592014-11-21 18:27:04 -0800255// static
James Robinson646469d2014-10-03 15:33:28 -0700256EGLDisplay GLSurfaceEGL::GetHardwareDisplay() {
James Robinsonc4c1c592014-11-21 18:27:04 -0800257 if (!g_initialized) {
258 bool result = GLSurfaceEGL::InitializeOneOff();
259 DCHECK(result);
260 }
James Robinson646469d2014-10-03 15:33:28 -0700261 return g_display;
262}
263
James Robinsonc4c1c592014-11-21 18:27:04 -0800264// static
James Robinson646469d2014-10-03 15:33:28 -0700265EGLNativeDisplayType GLSurfaceEGL::GetNativeDisplay() {
James Robinsonc4c1c592014-11-21 18:27:04 -0800266 if (!g_initialized) {
267 bool result = GLSurfaceEGL::InitializeOneOff();
268 DCHECK(result);
269 }
270 return g_native_display_type;
James Robinson646469d2014-10-03 15:33:28 -0700271}
272
273const char* GLSurfaceEGL::GetEGLExtensions() {
James Robinsonc4c1c592014-11-21 18:27:04 -0800274 // No need for InitializeOneOff. Assume that extensions will not change
275 // after the first initialization.
James Robinson646469d2014-10-03 15:33:28 -0700276 return g_egl_extensions;
277}
278
279bool GLSurfaceEGL::HasEGLExtension(const char* name) {
280 return ExtensionsContain(GetEGLExtensions(), name);
281}
282
283bool GLSurfaceEGL::IsCreateContextRobustnessSupported() {
284 return g_egl_create_context_robustness_supported;
285}
286
287bool GLSurfaceEGL::IsEGLSurfacelessContextSupported() {
288 return g_egl_surfaceless_context_supported;
289}
290
James Robinsonc4c1c592014-11-21 18:27:04 -0800291void GLSurfaceEGL::DestroyAndTerminateDisplay() {
292 DCHECK(g_initialized);
293 DCHECK_EQ(g_num_surfaces, 1);
294 Destroy();
295 g_terminate_pending = true;
296}
297
298GLSurfaceEGL::~GLSurfaceEGL() {
299 DCHECK_GT(g_num_surfaces, 0) << "Bad surface count";
300 if (--g_num_surfaces == 0 && g_terminate_pending) {
301 DeinitializeEgl();
302 g_terminate_pending = false;
303 }
304}
James Robinson646469d2014-10-03 15:33:28 -0700305
306#if defined(OS_WIN)
307static const EGLint kDisplayAttribsWarp[] {
James Robinson6e9a1c92014-11-13 17:05:42 -0800308 EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
309 EGL_PLATFORM_ANGLE_USE_WARP_ANGLE, EGL_TRUE,
James Robinson646469d2014-10-03 15:33:28 -0700310 EGL_NONE
311};
312
313// static
314EGLDisplay GLSurfaceEGL::GetPlatformDisplay(
315 EGLNativeDisplayType native_display) {
316 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseWarp)) {
317 // Check for availability of WARP via ANGLE extension.
318 bool supports_warp = false;
319 const char* no_display_extensions = eglQueryString(EGL_NO_DISPLAY,
320 EGL_EXTENSIONS);
321 // If EGL_EXT_client_extensions not supported this call to eglQueryString
322 // will return NULL.
323 if (no_display_extensions)
324 supports_warp =
325 ExtensionsContain(no_display_extensions, "ANGLE_platform_angle") &&
326 ExtensionsContain(no_display_extensions, "ANGLE_platform_angle_d3d");
327
328 if (!supports_warp)
329 return NULL;
330
331 return eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, native_display,
332 kDisplayAttribsWarp);
333 }
334
335 return eglGetDisplay(native_display);
336}
337#endif
338
339NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(EGLNativeWindowType window)
340 : window_(window),
341 surface_(NULL),
342 supports_post_sub_buffer_(false),
343 config_(NULL),
James Robinson6e9a1c92014-11-13 17:05:42 -0800344 size_(1, 1) {
James Robinson646469d2014-10-03 15:33:28 -0700345#if defined(OS_ANDROID)
346 if (window)
347 ANativeWindow_acquire(window);
348#endif
349
350#if defined(OS_WIN)
351 RECT windowRect;
352 if (GetClientRect(window_, &windowRect))
353 size_ = gfx::Rect(windowRect).size();
354#endif
355}
356
357bool NativeViewGLSurfaceEGL::Initialize() {
358 return Initialize(scoped_ptr<VSyncProvider>());
359}
360
361bool NativeViewGLSurfaceEGL::Initialize(
362 scoped_ptr<VSyncProvider> sync_provider) {
363 DCHECK(!surface_);
364
365 if (!GetDisplay()) {
366 LOG(ERROR) << "Trying to create surface with invalid display.";
367 return false;
368 }
369
370 std::vector<EGLint> egl_window_attributes;
371
372 if (g_egl_window_fixed_size_supported) {
373 egl_window_attributes.push_back(EGL_FIXED_SIZE_ANGLE);
374 egl_window_attributes.push_back(EGL_TRUE);
375 egl_window_attributes.push_back(EGL_WIDTH);
376 egl_window_attributes.push_back(size_.width());
377 egl_window_attributes.push_back(EGL_HEIGHT);
378 egl_window_attributes.push_back(size_.height());
379 }
380
381 if (gfx::g_driver_egl.ext.b_EGL_NV_post_sub_buffer) {
382 egl_window_attributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
383 egl_window_attributes.push_back(EGL_TRUE);
384 }
385
386 egl_window_attributes.push_back(EGL_NONE);
387 // Create a surface for the native window.
388 surface_ = eglCreateWindowSurface(
389 GetDisplay(), GetConfig(), window_, &egl_window_attributes[0]);
390
391 if (!surface_) {
392 LOG(ERROR) << "eglCreateWindowSurface failed with error "
393 << GetLastEGLErrorString();
394 Destroy();
395 return false;
396 }
397
398 EGLint surfaceVal;
399 EGLBoolean retVal = eglQuerySurface(GetDisplay(),
400 surface_,
401 EGL_POST_SUB_BUFFER_SUPPORTED_NV,
402 &surfaceVal);
403 supports_post_sub_buffer_ = (surfaceVal && retVal) == EGL_TRUE;
404
405 if (sync_provider)
406 vsync_provider_.reset(sync_provider.release());
407 else if (g_egl_sync_control_supported)
408 vsync_provider_.reset(new EGLSyncControlVSyncProvider(surface_));
409 return true;
410}
411
412void NativeViewGLSurfaceEGL::Destroy() {
413 if (surface_) {
414 if (!eglDestroySurface(GetDisplay(), surface_)) {
415 LOG(ERROR) << "eglDestroySurface failed with error "
416 << GetLastEGLErrorString();
417 }
418 surface_ = NULL;
419 }
420}
421
422EGLConfig NativeViewGLSurfaceEGL::GetConfig() {
423#if !defined(USE_X11)
424 return g_config;
425#else
426 if (!config_) {
427 // Get a config compatible with the window
428 DCHECK(window_);
429 XWindowAttributes win_attribs;
430 if (!XGetWindowAttributes(GetNativeDisplay(), window_, &win_attribs)) {
431 return NULL;
432 }
433
434 // Try matching the window depth with an alpha channel,
435 // because we're worried the destination alpha width could
436 // constrain blending precision.
437 const int kBufferSizeOffset = 1;
438 const int kAlphaSizeOffset = 3;
439 EGLint config_attribs[] = {
440 EGL_BUFFER_SIZE, ~0,
441 EGL_ALPHA_SIZE, 8,
442 EGL_BLUE_SIZE, 8,
443 EGL_GREEN_SIZE, 8,
444 EGL_RED_SIZE, 8,
445 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
446 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
447 EGL_NONE
448 };
449 config_attribs[kBufferSizeOffset] = win_attribs.depth;
450
451 EGLint num_configs;
452 if (!eglChooseConfig(g_display,
453 config_attribs,
454 &config_,
455 1,
456 &num_configs)) {
457 LOG(ERROR) << "eglChooseConfig failed with error "
458 << GetLastEGLErrorString();
459 return NULL;
460 }
461
462 if (num_configs) {
463 EGLint config_depth;
464 if (!eglGetConfigAttrib(g_display,
465 config_,
466 EGL_BUFFER_SIZE,
467 &config_depth)) {
468 LOG(ERROR) << "eglGetConfigAttrib failed with error "
469 << GetLastEGLErrorString();
470 return NULL;
471 }
472
473 if (config_depth == win_attribs.depth) {
474 return config_;
475 }
476 }
477
478 // Try without an alpha channel.
479 config_attribs[kAlphaSizeOffset] = 0;
480 if (!eglChooseConfig(g_display,
481 config_attribs,
482 &config_,
483 1,
484 &num_configs)) {
485 LOG(ERROR) << "eglChooseConfig failed with error "
486 << GetLastEGLErrorString();
487 return NULL;
488 }
489
490 if (num_configs == 0) {
491 LOG(ERROR) << "No suitable EGL configs found.";
492 return NULL;
493 }
494 }
495 return config_;
496#endif
497}
498
499bool NativeViewGLSurfaceEGL::IsOffscreen() {
500 return false;
501}
502
503bool NativeViewGLSurfaceEGL::SwapBuffers() {
504 TRACE_EVENT2("gpu", "NativeViewGLSurfaceEGL:RealSwapBuffers",
505 "width", GetSize().width(),
506 "height", GetSize().height());
507
508 if (!eglSwapBuffers(GetDisplay(), surface_)) {
509 DVLOG(1) << "eglSwapBuffers failed with error "
510 << GetLastEGLErrorString();
511 return false;
512 }
513
514 return true;
515}
516
517gfx::Size NativeViewGLSurfaceEGL::GetSize() {
518 EGLint width;
519 EGLint height;
520 if (!eglQuerySurface(GetDisplay(), surface_, EGL_WIDTH, &width) ||
521 !eglQuerySurface(GetDisplay(), surface_, EGL_HEIGHT, &height)) {
522 NOTREACHED() << "eglQuerySurface failed with error "
523 << GetLastEGLErrorString();
524 return gfx::Size();
525 }
526
527 return gfx::Size(width, height);
528}
529
530bool NativeViewGLSurfaceEGL::Resize(const gfx::Size& size) {
531 if (size == GetSize())
532 return true;
533
534 size_ = size;
535
536 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
537 GLContext* current_context = GLContext::GetCurrent();
538 bool was_current =
539 current_context && current_context->IsCurrent(this);
540 if (was_current) {
541 scoped_make_current.reset(
542 new ui::ScopedMakeCurrent(current_context, this));
543 current_context->ReleaseCurrent(this);
544 }
545
546 Destroy();
547
548 if (!Initialize()) {
549 LOG(ERROR) << "Failed to resize window.";
550 return false;
551 }
552
553 return true;
554}
555
556bool NativeViewGLSurfaceEGL::Recreate() {
557 Destroy();
558 if (!Initialize()) {
559 LOG(ERROR) << "Failed to create surface.";
560 return false;
561 }
562 return true;
563}
564
565EGLSurface NativeViewGLSurfaceEGL::GetHandle() {
566 return surface_;
567}
568
569bool NativeViewGLSurfaceEGL::SupportsPostSubBuffer() {
570 return supports_post_sub_buffer_;
571}
572
573bool NativeViewGLSurfaceEGL::PostSubBuffer(
574 int x, int y, int width, int height) {
575 DCHECK(supports_post_sub_buffer_);
576 if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) {
577 DVLOG(1) << "eglPostSubBufferNV failed with error "
578 << GetLastEGLErrorString();
579 return false;
580 }
581 return true;
582}
583
584VSyncProvider* NativeViewGLSurfaceEGL::GetVSyncProvider() {
585 return vsync_provider_.get();
586}
587
588NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() {
589 Destroy();
590#if defined(OS_ANDROID)
591 if (window_)
592 ANativeWindow_release(window_);
593#endif
594}
595
596PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(const gfx::Size& size)
597 : size_(size),
598 surface_(NULL) {
599 // Some implementations of Pbuffer do not support having a 0 size. For such
600 // cases use a (1, 1) surface.
601 if (size_.GetArea() == 0)
602 size_.SetSize(1, 1);
603}
604
605bool PbufferGLSurfaceEGL::Initialize() {
606 EGLSurface old_surface = surface_;
607
608 EGLDisplay display = GetDisplay();
609 if (!display) {
610 LOG(ERROR) << "Trying to create surface with invalid display.";
611 return false;
612 }
613
614 // Allocate the new pbuffer surface before freeing the old one to ensure
615 // they have different addresses. If they have the same address then a
616 // future call to MakeCurrent might early out because it appears the current
617 // context and surface have not changed.
618 const EGLint pbuffer_attribs[] = {
619 EGL_WIDTH, size_.width(),
620 EGL_HEIGHT, size_.height(),
621 EGL_NONE
622 };
623
624 EGLSurface new_surface = eglCreatePbufferSurface(display,
625 GetConfig(),
626 pbuffer_attribs);
627 if (!new_surface) {
628 LOG(ERROR) << "eglCreatePbufferSurface failed with error "
629 << GetLastEGLErrorString();
630 return false;
631 }
632
633 if (old_surface)
634 eglDestroySurface(display, old_surface);
635
636 surface_ = new_surface;
637 return true;
638}
639
640void PbufferGLSurfaceEGL::Destroy() {
641 if (surface_) {
642 if (!eglDestroySurface(GetDisplay(), surface_)) {
643 LOG(ERROR) << "eglDestroySurface failed with error "
644 << GetLastEGLErrorString();
645 }
646 surface_ = NULL;
647 }
648}
649
650EGLConfig PbufferGLSurfaceEGL::GetConfig() {
651 return g_config;
652}
653
654bool PbufferGLSurfaceEGL::IsOffscreen() {
655 return true;
656}
657
658bool PbufferGLSurfaceEGL::SwapBuffers() {
659 NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL.";
660 return false;
661}
662
663gfx::Size PbufferGLSurfaceEGL::GetSize() {
664 return size_;
665}
666
667bool PbufferGLSurfaceEGL::Resize(const gfx::Size& size) {
668 if (size == size_)
669 return true;
670
671 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
672 GLContext* current_context = GLContext::GetCurrent();
673 bool was_current =
674 current_context && current_context->IsCurrent(this);
675 if (was_current) {
676 scoped_make_current.reset(
677 new ui::ScopedMakeCurrent(current_context, this));
678 }
679
680 size_ = size;
681
682 if (!Initialize()) {
683 LOG(ERROR) << "Failed to resize pbuffer.";
684 return false;
685 }
686
687 return true;
688}
689
690EGLSurface PbufferGLSurfaceEGL::GetHandle() {
691 return surface_;
692}
693
694void* PbufferGLSurfaceEGL::GetShareHandle() {
695#if defined(OS_ANDROID)
696 NOTREACHED();
697 return NULL;
698#else
699 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_query_surface_pointer)
700 return NULL;
701
702 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle)
703 return NULL;
704
705 void* handle;
706 if (!eglQuerySurfacePointerANGLE(g_display,
707 GetHandle(),
708 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
709 &handle)) {
710 return NULL;
711 }
712
713 return handle;
714#endif
715}
716
717PbufferGLSurfaceEGL::~PbufferGLSurfaceEGL() {
718 Destroy();
719}
720
721SurfacelessEGL::SurfacelessEGL(const gfx::Size& size)
722 : size_(size) {
723}
724
725bool SurfacelessEGL::Initialize() {
726 return true;
727}
728
729void SurfacelessEGL::Destroy() {
730}
731
732EGLConfig SurfacelessEGL::GetConfig() {
733 return g_config;
734}
735
736bool SurfacelessEGL::IsOffscreen() {
737 return true;
738}
739
James Robinson74f9f1f2014-11-04 11:17:49 -0800740bool SurfacelessEGL::IsSurfaceless() const {
741 return true;
742}
743
James Robinson646469d2014-10-03 15:33:28 -0700744bool SurfacelessEGL::SwapBuffers() {
745 LOG(ERROR) << "Attempted to call SwapBuffers with SurfacelessEGL.";
746 return false;
747}
748
749gfx::Size SurfacelessEGL::GetSize() {
750 return size_;
751}
752
753bool SurfacelessEGL::Resize(const gfx::Size& size) {
754 size_ = size;
755 return true;
756}
757
758EGLSurface SurfacelessEGL::GetHandle() {
759 return EGL_NO_SURFACE;
760}
761
762void* SurfacelessEGL::GetShareHandle() {
763 return NULL;
764}
765
766SurfacelessEGL::~SurfacelessEGL() {
767}
768
769} // namespace gfx