Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / gl / gl_surface_egl.cc
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.
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)
27 extern "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
48 #if !defined(EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE)
49 #define EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE 0x3206
50 #endif
51 #endif  // defined(OS_WIN)
52
53 using ui::GetLastEGLErrorString;
54
55 namespace gfx {
56
57 unsigned int NativeViewGLSurfaceEGL::current_swap_generation_ = 0;
58
59 namespace {
60
61 EGLConfig g_config;
62 EGLDisplay g_display;
63 EGLNativeDisplayType g_native_display;
64
65 const char* g_egl_extensions = NULL;
66 bool g_egl_create_context_robustness_supported = false;
67 bool g_egl_sync_control_supported = false;
68 bool g_egl_window_fixed_size_supported = false;
69 bool g_egl_surfaceless_context_supported = false;
70
71 class EGLSyncControlVSyncProvider
72     : public gfx::SyncControlVSyncProvider {
73  public:
74   explicit EGLSyncControlVSyncProvider(EGLSurface surface)
75       : SyncControlVSyncProvider(),
76         surface_(surface) {
77   }
78
79   ~EGLSyncControlVSyncProvider() override {}
80
81  protected:
82   bool GetSyncValues(int64* system_time,
83                      int64* media_stream_counter,
84                      int64* swap_buffer_counter) override {
85     uint64 u_system_time, u_media_stream_counter, u_swap_buffer_counter;
86     bool result = eglGetSyncValuesCHROMIUM(
87         g_display, surface_, &u_system_time,
88         &u_media_stream_counter, &u_swap_buffer_counter) == EGL_TRUE;
89     if (result) {
90       *system_time = static_cast<int64>(u_system_time);
91       *media_stream_counter = static_cast<int64>(u_media_stream_counter);
92       *swap_buffer_counter = static_cast<int64>(u_swap_buffer_counter);
93     }
94     return result;
95   }
96
97   bool GetMscRate(int32* numerator, int32* denominator) override {
98     return false;
99   }
100
101  private:
102   EGLSurface surface_;
103
104   DISALLOW_COPY_AND_ASSIGN(EGLSyncControlVSyncProvider);
105 };
106
107 }  // namespace
108
109 GLSurfaceEGL::GLSurfaceEGL() {}
110
111 bool GLSurfaceEGL::InitializeOneOff() {
112   static bool initialized = false;
113   if (initialized)
114     return true;
115
116   g_native_display = GetPlatformDefaultEGLNativeDisplay();
117
118 #if defined(OS_WIN)
119   g_display = GetPlatformDisplay(g_native_display);
120 #else
121   g_display = eglGetDisplay(g_native_display);
122 #endif
123
124   if (!g_display) {
125     LOG(ERROR) << "eglGetDisplay failed with error " << GetLastEGLErrorString();
126     return false;
127   }
128
129   if (!eglInitialize(g_display, NULL, NULL)) {
130     LOG(ERROR) << "eglInitialize failed with error " << GetLastEGLErrorString();
131     return false;
132   }
133
134   // Choose an EGL configuration.
135   // On X this is only used for PBuffer surfaces.
136   static const EGLint kConfigAttribs[] = {
137     EGL_BUFFER_SIZE, 32,
138     EGL_ALPHA_SIZE, 8,
139     EGL_BLUE_SIZE, 8,
140     EGL_GREEN_SIZE, 8,
141     EGL_RED_SIZE, 8,
142     EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
143     EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
144     EGL_NONE
145   };
146
147 #if defined(USE_OZONE)
148   const EGLint* config_attribs =
149       ui::SurfaceFactoryOzone::GetInstance()->GetEGLSurfaceProperties(
150           kConfigAttribs);
151 #else
152   const EGLint* config_attribs = kConfigAttribs;
153 #endif
154
155   EGLint num_configs;
156   if (!eglChooseConfig(g_display,
157                        config_attribs,
158                        NULL,
159                        0,
160                        &num_configs)) {
161     LOG(ERROR) << "eglChooseConfig failed with error "
162                << GetLastEGLErrorString();
163     return false;
164   }
165
166   if (num_configs == 0) {
167     LOG(ERROR) << "No suitable EGL configs found.";
168     return false;
169   }
170
171   if (!eglChooseConfig(g_display,
172                        config_attribs,
173                        &g_config,
174                        1,
175                        &num_configs)) {
176     LOG(ERROR) << "eglChooseConfig failed with error "
177                << GetLastEGLErrorString();
178     return false;
179   }
180
181   g_egl_extensions = eglQueryString(g_display, EGL_EXTENSIONS);
182   g_egl_create_context_robustness_supported =
183       HasEGLExtension("EGL_EXT_create_context_robustness");
184   g_egl_sync_control_supported =
185       HasEGLExtension("EGL_CHROMIUM_sync_control");
186   g_egl_window_fixed_size_supported =
187       HasEGLExtension("EGL_ANGLE_window_fixed_size");
188
189   // TODO(oetuaho@nvidia.com): Surfaceless is disabled on Android as a temporary
190   // workaround, since code written for Android WebView takes different paths
191   // based on whether GL surface objects have underlying EGL surface handles,
192   // conflicting with the use of surfaceless. See https://crbug.com/382349
193 #if defined(OS_ANDROID)
194   DCHECK(!g_egl_surfaceless_context_supported);
195 #else
196   // Check if SurfacelessEGL is supported.
197   g_egl_surfaceless_context_supported =
198       HasEGLExtension("EGL_KHR_surfaceless_context");
199   if (g_egl_surfaceless_context_supported) {
200     // EGL_KHR_surfaceless_context is supported but ensure
201     // GL_OES_surfaceless_context is also supported. We need a current context
202     // to query for supported GL extensions.
203     scoped_refptr<GLSurface> surface = new SurfacelessEGL(Size(1, 1));
204     scoped_refptr<GLContext> context = GLContext::CreateGLContext(
205       NULL, surface.get(), PreferIntegratedGpu);
206     if (!context->MakeCurrent(surface.get()))
207       g_egl_surfaceless_context_supported = false;
208
209     // Ensure context supports GL_OES_surfaceless_context.
210     if (g_egl_surfaceless_context_supported) {
211       g_egl_surfaceless_context_supported = context->HasExtension(
212           "GL_OES_surfaceless_context");
213       context->ReleaseCurrent(surface.get());
214     }
215   }
216 #endif
217
218   initialized = true;
219
220   return true;
221 }
222
223 EGLDisplay GLSurfaceEGL::GetDisplay() {
224   return g_display;
225 }
226
227 EGLDisplay GLSurfaceEGL::GetHardwareDisplay() {
228   return g_display;
229 }
230
231 EGLNativeDisplayType GLSurfaceEGL::GetNativeDisplay() {
232   return g_native_display;
233 }
234
235 const char* GLSurfaceEGL::GetEGLExtensions() {
236   return g_egl_extensions;
237 }
238
239 bool GLSurfaceEGL::HasEGLExtension(const char* name) {
240   return ExtensionsContain(GetEGLExtensions(), name);
241 }
242
243 bool GLSurfaceEGL::IsCreateContextRobustnessSupported() {
244   return g_egl_create_context_robustness_supported;
245 }
246
247 bool GLSurfaceEGL::IsEGLSurfacelessContextSupported() {
248   return g_egl_surfaceless_context_supported;
249 }
250
251 GLSurfaceEGL::~GLSurfaceEGL() {}
252
253 #if defined(OS_WIN)
254 static const EGLint kDisplayAttribsWarp[] {
255   EGL_PLATFORM_ANGLE_TYPE_ANGLE,
256   EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE,
257   EGL_NONE
258 };
259
260 // static
261 EGLDisplay GLSurfaceEGL::GetPlatformDisplay(
262     EGLNativeDisplayType native_display) {
263   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseWarp)) {
264     // Check for availability of WARP via ANGLE extension.
265     bool supports_warp = false;
266     const char* no_display_extensions = eglQueryString(EGL_NO_DISPLAY,
267         EGL_EXTENSIONS);
268     // If EGL_EXT_client_extensions not supported this call to eglQueryString
269     // will return NULL.
270     if (no_display_extensions)
271       supports_warp =
272           ExtensionsContain(no_display_extensions, "ANGLE_platform_angle") &&
273           ExtensionsContain(no_display_extensions, "ANGLE_platform_angle_d3d");
274
275     if (!supports_warp)
276       return NULL;
277
278     return eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, native_display,
279         kDisplayAttribsWarp);
280   }
281
282   return eglGetDisplay(native_display);
283 }
284 #endif
285
286 NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(EGLNativeWindowType window)
287     : window_(window),
288       surface_(NULL),
289       supports_post_sub_buffer_(false),
290       config_(NULL),
291       size_(1, 1),
292       swap_interval_(1),
293       swap_generation_(0) {
294 #if defined(OS_ANDROID)
295   if (window)
296     ANativeWindow_acquire(window);
297 #endif
298
299 #if defined(OS_WIN)
300   RECT windowRect;
301   if (GetClientRect(window_, &windowRect))
302     size_ = gfx::Rect(windowRect).size();
303 #endif
304 }
305
306 bool NativeViewGLSurfaceEGL::Initialize() {
307   return Initialize(scoped_ptr<VSyncProvider>());
308 }
309
310 bool NativeViewGLSurfaceEGL::Initialize(
311     scoped_ptr<VSyncProvider> sync_provider) {
312   DCHECK(!surface_);
313
314   if (!GetDisplay()) {
315     LOG(ERROR) << "Trying to create surface with invalid display.";
316     return false;
317   }
318
319   std::vector<EGLint> egl_window_attributes;
320
321   if (g_egl_window_fixed_size_supported) {
322     egl_window_attributes.push_back(EGL_FIXED_SIZE_ANGLE);
323     egl_window_attributes.push_back(EGL_TRUE);
324     egl_window_attributes.push_back(EGL_WIDTH);
325     egl_window_attributes.push_back(size_.width());
326     egl_window_attributes.push_back(EGL_HEIGHT);
327     egl_window_attributes.push_back(size_.height());
328   }
329
330   if (gfx::g_driver_egl.ext.b_EGL_NV_post_sub_buffer) {
331     egl_window_attributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
332     egl_window_attributes.push_back(EGL_TRUE);
333   }
334
335   egl_window_attributes.push_back(EGL_NONE);
336   // Create a surface for the native window.
337   surface_ = eglCreateWindowSurface(
338       GetDisplay(), GetConfig(), window_, &egl_window_attributes[0]);
339
340   if (!surface_) {
341     LOG(ERROR) << "eglCreateWindowSurface failed with error "
342                << GetLastEGLErrorString();
343     Destroy();
344     return false;
345   }
346
347   EGLint surfaceVal;
348   EGLBoolean retVal = eglQuerySurface(GetDisplay(),
349                                       surface_,
350                                       EGL_POST_SUB_BUFFER_SUPPORTED_NV,
351                                       &surfaceVal);
352   supports_post_sub_buffer_ = (surfaceVal && retVal) == EGL_TRUE;
353
354   if (sync_provider)
355     vsync_provider_.reset(sync_provider.release());
356   else if (g_egl_sync_control_supported)
357     vsync_provider_.reset(new EGLSyncControlVSyncProvider(surface_));
358   return true;
359 }
360
361 void NativeViewGLSurfaceEGL::Destroy() {
362   if (surface_) {
363     if (!eglDestroySurface(GetDisplay(), surface_)) {
364       LOG(ERROR) << "eglDestroySurface failed with error "
365                  << GetLastEGLErrorString();
366     }
367     surface_ = NULL;
368   }
369 }
370
371 EGLConfig NativeViewGLSurfaceEGL::GetConfig() {
372 #if !defined(USE_X11)
373   return g_config;
374 #else
375   if (!config_) {
376     // Get a config compatible with the window
377     DCHECK(window_);
378     XWindowAttributes win_attribs;
379     if (!XGetWindowAttributes(GetNativeDisplay(), window_, &win_attribs)) {
380       return NULL;
381     }
382
383     // Try matching the window depth with an alpha channel,
384     // because we're worried the destination alpha width could
385     // constrain blending precision.
386     const int kBufferSizeOffset = 1;
387     const int kAlphaSizeOffset = 3;
388     EGLint config_attribs[] = {
389       EGL_BUFFER_SIZE, ~0,
390       EGL_ALPHA_SIZE, 8,
391       EGL_BLUE_SIZE, 8,
392       EGL_GREEN_SIZE, 8,
393       EGL_RED_SIZE, 8,
394       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
395       EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
396       EGL_NONE
397     };
398     config_attribs[kBufferSizeOffset] = win_attribs.depth;
399
400     EGLint num_configs;
401     if (!eglChooseConfig(g_display,
402                          config_attribs,
403                          &config_,
404                          1,
405                          &num_configs)) {
406       LOG(ERROR) << "eglChooseConfig failed with error "
407                  << GetLastEGLErrorString();
408       return NULL;
409     }
410
411     if (num_configs) {
412       EGLint config_depth;
413       if (!eglGetConfigAttrib(g_display,
414                               config_,
415                               EGL_BUFFER_SIZE,
416                               &config_depth)) {
417         LOG(ERROR) << "eglGetConfigAttrib failed with error "
418                    << GetLastEGLErrorString();
419         return NULL;
420       }
421
422       if (config_depth == win_attribs.depth) {
423         return config_;
424       }
425     }
426
427     // Try without an alpha channel.
428     config_attribs[kAlphaSizeOffset] = 0;
429     if (!eglChooseConfig(g_display,
430                          config_attribs,
431                          &config_,
432                          1,
433                          &num_configs)) {
434       LOG(ERROR) << "eglChooseConfig failed with error "
435                  << GetLastEGLErrorString();
436       return NULL;
437     }
438
439     if (num_configs == 0) {
440       LOG(ERROR) << "No suitable EGL configs found.";
441       return NULL;
442     }
443   }
444   return config_;
445 #endif
446 }
447
448 bool NativeViewGLSurfaceEGL::IsOffscreen() {
449   return false;
450 }
451
452 bool NativeViewGLSurfaceEGL::SwapBuffers() {
453   TRACE_EVENT2("gpu", "NativeViewGLSurfaceEGL:RealSwapBuffers",
454       "width", GetSize().width(),
455       "height", GetSize().height());
456
457 #if defined(OS_WIN)
458   bool force_no_vsync = false;
459   if (swap_interval_ != 0) {
460     // This code is a simple way of enforcing that only one surface actually
461     // vsyncs per frame. This provides single window cases a stable refresh
462     // while allowing multi-window cases to not slow down due to multiple syncs
463     // on a single thread. A better way to fix this problem would be to have
464     // each surface present on its own thread.
465     if (current_swap_generation_ == swap_generation_) {
466       current_swap_generation_++;
467     } else {
468       force_no_vsync = true;
469       eglSwapInterval(GetDisplay(), 0);
470     }
471
472     swap_generation_ = current_swap_generation_;
473   }
474 #endif
475
476   if (!eglSwapBuffers(GetDisplay(), surface_)) {
477     DVLOG(1) << "eglSwapBuffers failed with error "
478              << GetLastEGLErrorString();
479     return false;
480   }
481
482 #if defined(OS_WIN)
483   if (force_no_vsync) {
484     eglSwapInterval(GetDisplay(), swap_interval_);
485   }
486 #endif
487
488   return true;
489 }
490
491 gfx::Size NativeViewGLSurfaceEGL::GetSize() {
492   EGLint width;
493   EGLint height;
494   if (!eglQuerySurface(GetDisplay(), surface_, EGL_WIDTH, &width) ||
495       !eglQuerySurface(GetDisplay(), surface_, EGL_HEIGHT, &height)) {
496     NOTREACHED() << "eglQuerySurface failed with error "
497                  << GetLastEGLErrorString();
498     return gfx::Size();
499   }
500
501   return gfx::Size(width, height);
502 }
503
504 bool NativeViewGLSurfaceEGL::Resize(const gfx::Size& size) {
505   if (size == GetSize())
506     return true;
507
508   size_ = size;
509
510   scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
511   GLContext* current_context = GLContext::GetCurrent();
512   bool was_current =
513       current_context && current_context->IsCurrent(this);
514   if (was_current) {
515     scoped_make_current.reset(
516         new ui::ScopedMakeCurrent(current_context, this));
517     current_context->ReleaseCurrent(this);
518   }
519
520   Destroy();
521
522   if (!Initialize()) {
523     LOG(ERROR) << "Failed to resize window.";
524     return false;
525   }
526
527   return true;
528 }
529
530 bool NativeViewGLSurfaceEGL::Recreate() {
531   Destroy();
532   if (!Initialize()) {
533     LOG(ERROR) << "Failed to create surface.";
534     return false;
535   }
536   return true;
537 }
538
539 EGLSurface NativeViewGLSurfaceEGL::GetHandle() {
540   return surface_;
541 }
542
543 bool NativeViewGLSurfaceEGL::SupportsPostSubBuffer() {
544   return supports_post_sub_buffer_;
545 }
546
547 bool NativeViewGLSurfaceEGL::PostSubBuffer(
548     int x, int y, int width, int height) {
549   DCHECK(supports_post_sub_buffer_);
550   if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) {
551     DVLOG(1) << "eglPostSubBufferNV failed with error "
552              << GetLastEGLErrorString();
553     return false;
554   }
555   return true;
556 }
557
558 VSyncProvider* NativeViewGLSurfaceEGL::GetVSyncProvider() {
559   return vsync_provider_.get();
560 }
561
562 void NativeViewGLSurfaceEGL::SetSwapInterval(int interval) {
563   swap_interval_ = interval;
564 }
565
566 NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() {
567   Destroy();
568 #if defined(OS_ANDROID)
569   if (window_)
570     ANativeWindow_release(window_);
571 #endif
572 }
573
574 PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(const gfx::Size& size)
575     : size_(size),
576       surface_(NULL) {
577   // Some implementations of Pbuffer do not support having a 0 size. For such
578   // cases use a (1, 1) surface.
579   if (size_.GetArea() == 0)
580     size_.SetSize(1, 1);
581 }
582
583 bool PbufferGLSurfaceEGL::Initialize() {
584   EGLSurface old_surface = surface_;
585
586   EGLDisplay display = GetDisplay();
587   if (!display) {
588     LOG(ERROR) << "Trying to create surface with invalid display.";
589     return false;
590   }
591
592   // Allocate the new pbuffer surface before freeing the old one to ensure
593   // they have different addresses. If they have the same address then a
594   // future call to MakeCurrent might early out because it appears the current
595   // context and surface have not changed.
596   const EGLint pbuffer_attribs[] = {
597     EGL_WIDTH, size_.width(),
598     EGL_HEIGHT, size_.height(),
599     EGL_NONE
600   };
601
602   EGLSurface new_surface = eglCreatePbufferSurface(display,
603                                                    GetConfig(),
604                                                    pbuffer_attribs);
605   if (!new_surface) {
606     LOG(ERROR) << "eglCreatePbufferSurface failed with error "
607                << GetLastEGLErrorString();
608     return false;
609   }
610
611   if (old_surface)
612     eglDestroySurface(display, old_surface);
613
614   surface_ = new_surface;
615   return true;
616 }
617
618 void PbufferGLSurfaceEGL::Destroy() {
619   if (surface_) {
620     if (!eglDestroySurface(GetDisplay(), surface_)) {
621       LOG(ERROR) << "eglDestroySurface failed with error "
622                  << GetLastEGLErrorString();
623     }
624     surface_ = NULL;
625   }
626 }
627
628 EGLConfig PbufferGLSurfaceEGL::GetConfig() {
629   return g_config;
630 }
631
632 bool PbufferGLSurfaceEGL::IsOffscreen() {
633   return true;
634 }
635
636 bool PbufferGLSurfaceEGL::SwapBuffers() {
637   NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL.";
638   return false;
639 }
640
641 gfx::Size PbufferGLSurfaceEGL::GetSize() {
642   return size_;
643 }
644
645 bool PbufferGLSurfaceEGL::Resize(const gfx::Size& size) {
646   if (size == size_)
647     return true;
648
649   scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
650   GLContext* current_context = GLContext::GetCurrent();
651   bool was_current =
652       current_context && current_context->IsCurrent(this);
653   if (was_current) {
654     scoped_make_current.reset(
655         new ui::ScopedMakeCurrent(current_context, this));
656   }
657
658   size_ = size;
659
660   if (!Initialize()) {
661     LOG(ERROR) << "Failed to resize pbuffer.";
662     return false;
663   }
664
665   return true;
666 }
667
668 EGLSurface PbufferGLSurfaceEGL::GetHandle() {
669   return surface_;
670 }
671
672 void* PbufferGLSurfaceEGL::GetShareHandle() {
673 #if defined(OS_ANDROID)
674   NOTREACHED();
675   return NULL;
676 #else
677   if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_query_surface_pointer)
678     return NULL;
679
680   if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle)
681     return NULL;
682
683   void* handle;
684   if (!eglQuerySurfacePointerANGLE(g_display,
685                                    GetHandle(),
686                                    EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
687                                    &handle)) {
688     return NULL;
689   }
690
691   return handle;
692 #endif
693 }
694
695 PbufferGLSurfaceEGL::~PbufferGLSurfaceEGL() {
696   Destroy();
697 }
698
699 SurfacelessEGL::SurfacelessEGL(const gfx::Size& size)
700     : size_(size) {
701 }
702
703 bool SurfacelessEGL::Initialize() {
704   return true;
705 }
706
707 void SurfacelessEGL::Destroy() {
708 }
709
710 EGLConfig SurfacelessEGL::GetConfig() {
711   return g_config;
712 }
713
714 bool SurfacelessEGL::IsOffscreen() {
715   return true;
716 }
717
718 bool SurfacelessEGL::IsSurfaceless() const {
719   return true;
720 }
721
722 bool SurfacelessEGL::SwapBuffers() {
723   LOG(ERROR) << "Attempted to call SwapBuffers with SurfacelessEGL.";
724   return false;
725 }
726
727 gfx::Size SurfacelessEGL::GetSize() {
728   return size_;
729 }
730
731 bool SurfacelessEGL::Resize(const gfx::Size& size) {
732   size_ = size;
733   return true;
734 }
735
736 EGLSurface SurfacelessEGL::GetHandle() {
737   return EGL_NO_SURFACE;
738 }
739
740 void* SurfacelessEGL::GetShareHandle() {
741   return NULL;
742 }
743
744 SurfacelessEGL::~SurfacelessEGL() {
745 }
746
747 }  // namespace gfx