Home | History | Annotate | Download | only in gl
      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 // 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"
      8 
      9 #include "ui/gl/gl_surface_egl.h"
     10 
     11 #if defined(OS_ANDROID)
     12 #include <android/native_window_jni.h>
     13 #endif
     14 
     15 #include "base/command_line.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/gl/egl_util.h"
     21 #include "ui/gl/gl_context.h"
     22 #include "ui/gl/gl_implementation.h"
     23 #include "ui/gl/gl_surface_osmesa.h"
     24 #include "ui/gl/gl_surface_stub.h"
     25 #include "ui/gl/gl_switches.h"
     26 #include "ui/gl/scoped_make_current.h"
     27 
     28 #if defined(USE_X11)
     29 extern "C" {
     30 #include <X11/Xlib.h>
     31 }
     32 #endif
     33 
     34 #if defined (USE_OZONE)
     35 #include "ui/base/ozone/surface_factory_ozone.h"
     36 #endif
     37 
     38 // From ANGLE's egl/eglext.h.
     39 #if !defined(EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE)
     40 #define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE \
     41     reinterpret_cast<EGLNativeDisplayType>(-2)
     42 #endif
     43 
     44 using ui::GetLastEGLErrorString;
     45 
     46 namespace gfx {
     47 
     48 namespace {
     49 
     50 EGLConfig g_config;
     51 EGLDisplay g_display;
     52 EGLNativeDisplayType g_native_display;
     53 
     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 
     58 class EGLSyncControlVSyncProvider
     59     : public gfx::SyncControlVSyncProvider {
     60  public:
     61   explicit EGLSyncControlVSyncProvider(EGLSurface surface)
     62       : SyncControlVSyncProvider(),
     63         surface_(surface) {
     64   }
     65 
     66   virtual ~EGLSyncControlVSyncProvider() { }
     67 
     68  protected:
     69   virtual bool GetSyncValues(int64* system_time,
     70                              int64* media_stream_counter,
     71                              int64* swap_buffer_counter) OVERRIDE {
     72     uint64 u_system_time, u_media_stream_counter, u_swap_buffer_counter;
     73     bool result = eglGetSyncValuesCHROMIUM(
     74         g_display, surface_, &u_system_time,
     75         &u_media_stream_counter, &u_swap_buffer_counter) == EGL_TRUE;
     76     if (result) {
     77       *system_time = static_cast<int64>(u_system_time);
     78       *media_stream_counter = static_cast<int64>(u_media_stream_counter);
     79       *swap_buffer_counter = static_cast<int64>(u_swap_buffer_counter);
     80     }
     81     return result;
     82   }
     83 
     84   virtual bool GetMscRate(int32* numerator, int32* denominator) OVERRIDE {
     85     return false;
     86   }
     87 
     88  private:
     89   EGLSurface surface_;
     90 
     91   DISALLOW_COPY_AND_ASSIGN(EGLSyncControlVSyncProvider);
     92 };
     93 
     94 }  // namespace
     95 
     96 GLSurfaceEGL::GLSurfaceEGL() {}
     97 
     98 bool GLSurfaceEGL::InitializeOneOff() {
     99   static bool initialized = false;
    100   if (initialized)
    101     return true;
    102 
    103 #if defined (USE_OZONE)
    104   ui::SurfaceFactoryOzone::GetInstance()->InitializeHardware();
    105 #endif
    106 
    107 #if defined(USE_X11)
    108   g_native_display = base::MessagePumpForUI::GetDefaultXDisplay();
    109 #elif defined(OS_WIN)
    110   g_native_display = EGL_DEFAULT_DISPLAY;
    111   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableD3D11)) {
    112     g_native_display = EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE;
    113   }
    114 #else
    115   g_native_display = EGL_DEFAULT_DISPLAY;
    116 #endif
    117   g_display = eglGetDisplay(g_native_display);
    118   if (!g_display) {
    119     LOG(ERROR) << "eglGetDisplay failed with error " << GetLastEGLErrorString();
    120     return false;
    121   }
    122 
    123   if (!eglInitialize(g_display, NULL, NULL)) {
    124     LOG(ERROR) << "eglInitialize failed with error " << GetLastEGLErrorString();
    125     return false;
    126   }
    127 
    128   // Choose an EGL configuration.
    129   // On X this is only used for PBuffer surfaces.
    130   static const EGLint kConfigAttribs[] = {
    131     EGL_BUFFER_SIZE, 32,
    132     EGL_ALPHA_SIZE, 8,
    133     EGL_BLUE_SIZE, 8,
    134     EGL_GREEN_SIZE, 8,
    135     EGL_RED_SIZE, 8,
    136     EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    137     EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
    138     EGL_NONE
    139   };
    140 
    141   EGLint num_configs;
    142   if (!eglChooseConfig(g_display,
    143                        kConfigAttribs,
    144                        NULL,
    145                        0,
    146                        &num_configs)) {
    147     LOG(ERROR) << "eglChooseConfig failed with error "
    148                << GetLastEGLErrorString();
    149     return false;
    150   }
    151 
    152   if (num_configs == 0) {
    153     LOG(ERROR) << "No suitable EGL configs found.";
    154     return false;
    155   }
    156 
    157   if (!eglChooseConfig(g_display,
    158                        kConfigAttribs,
    159                        &g_config,
    160                        1,
    161                        &num_configs)) {
    162     LOG(ERROR) << "eglChooseConfig failed with error "
    163                << GetLastEGLErrorString();
    164     return false;
    165   }
    166 
    167   g_egl_extensions = eglQueryString(g_display, EGL_EXTENSIONS);
    168   g_egl_create_context_robustness_supported =
    169       HasEGLExtension("EGL_EXT_create_context_robustness");
    170   g_egl_sync_control_supported =
    171       HasEGLExtension("EGL_CHROMIUM_sync_control");
    172 
    173   initialized = true;
    174 
    175   return true;
    176 }
    177 
    178 EGLDisplay GLSurfaceEGL::GetDisplay() {
    179   return g_display;
    180 }
    181 
    182 EGLDisplay GLSurfaceEGL::GetHardwareDisplay() {
    183   return g_display;
    184 }
    185 
    186 EGLNativeDisplayType GLSurfaceEGL::GetNativeDisplay() {
    187   return g_native_display;
    188 }
    189 
    190 const char* GLSurfaceEGL::GetEGLExtensions() {
    191   return g_egl_extensions;
    192 }
    193 
    194 bool GLSurfaceEGL::HasEGLExtension(const char* name) {
    195   return ExtensionsContain(GetEGLExtensions(), name);
    196 }
    197 
    198 bool GLSurfaceEGL::IsCreateContextRobustnessSupported() {
    199   return g_egl_create_context_robustness_supported;
    200 }
    201 
    202 GLSurfaceEGL::~GLSurfaceEGL() {}
    203 
    204 NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(gfx::AcceleratedWidget window)
    205     : window_(window),
    206       surface_(NULL),
    207       supports_post_sub_buffer_(false),
    208       config_(NULL) {
    209 #if defined(OS_ANDROID)
    210   if (window)
    211     ANativeWindow_acquire(window);
    212 #endif
    213 }
    214 
    215 bool NativeViewGLSurfaceEGL::Initialize() {
    216   return Initialize(NULL);
    217 }
    218 
    219 bool NativeViewGLSurfaceEGL::Initialize(VSyncProvider* sync_provider) {
    220   DCHECK(!surface_);
    221 
    222   if (window_ == kNullAcceleratedWidget) {
    223     LOG(ERROR) << "Trying to create surface without window.";
    224     return false;
    225   }
    226 
    227   if (!GetDisplay()) {
    228     LOG(ERROR) << "Trying to create surface with invalid display.";
    229     return false;
    230   }
    231 
    232   static const EGLint egl_window_attributes_sub_buffer[] = {
    233     EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_TRUE,
    234     EGL_NONE
    235   };
    236 
    237   // Create a surface for the native window.
    238   surface_ = eglCreateWindowSurface(
    239       GetDisplay(),
    240       GetConfig(),
    241       window_,
    242       gfx::g_driver_egl.ext.b_EGL_NV_post_sub_buffer ?
    243           egl_window_attributes_sub_buffer :
    244           NULL);
    245 
    246   if (!surface_) {
    247     LOG(ERROR) << "eglCreateWindowSurface failed with error "
    248                << GetLastEGLErrorString();
    249     Destroy();
    250     return false;
    251   }
    252 
    253   EGLint surfaceVal;
    254   EGLBoolean retVal = eglQuerySurface(GetDisplay(),
    255                                       surface_,
    256                                       EGL_POST_SUB_BUFFER_SUPPORTED_NV,
    257                                       &surfaceVal);
    258   supports_post_sub_buffer_ = (surfaceVal && retVal) == EGL_TRUE;
    259 
    260   if (sync_provider)
    261     vsync_provider_.reset(sync_provider);
    262   else if (g_egl_sync_control_supported)
    263     vsync_provider_.reset(new EGLSyncControlVSyncProvider(surface_));
    264   return true;
    265 }
    266 
    267 void NativeViewGLSurfaceEGL::Destroy() {
    268   if (surface_) {
    269     if (!eglDestroySurface(GetDisplay(), surface_)) {
    270       LOG(ERROR) << "eglDestroySurface failed with error "
    271                  << GetLastEGLErrorString();
    272     }
    273     surface_ = NULL;
    274   }
    275 }
    276 
    277 EGLConfig NativeViewGLSurfaceEGL::GetConfig() {
    278 #if !defined(USE_X11)
    279   return g_config;
    280 #else
    281   if (!config_) {
    282     // Get a config compatible with the window
    283     DCHECK(window_);
    284     XWindowAttributes win_attribs;
    285     if (!XGetWindowAttributes(GetNativeDisplay(), window_, &win_attribs)) {
    286       return NULL;
    287     }
    288 
    289     // Try matching the window depth with an alpha channel,
    290     // because we're worried the destination alpha width could
    291     // constrain blending precision.
    292     const int kBufferSizeOffset = 1;
    293     const int kAlphaSizeOffset = 3;
    294     EGLint config_attribs[] = {
    295       EGL_BUFFER_SIZE, ~0,
    296       EGL_ALPHA_SIZE, 8,
    297       EGL_BLUE_SIZE, 8,
    298       EGL_GREEN_SIZE, 8,
    299       EGL_RED_SIZE, 8,
    300       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    301       EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
    302       EGL_NONE
    303     };
    304     config_attribs[kBufferSizeOffset] = win_attribs.depth;
    305 
    306     EGLint num_configs;
    307     if (!eglChooseConfig(g_display,
    308                          config_attribs,
    309                          &config_,
    310                          1,
    311                          &num_configs)) {
    312       LOG(ERROR) << "eglChooseConfig failed with error "
    313                  << GetLastEGLErrorString();
    314       return NULL;
    315     }
    316 
    317     if (num_configs) {
    318       EGLint config_depth;
    319       if (!eglGetConfigAttrib(g_display,
    320                               config_,
    321                               EGL_BUFFER_SIZE,
    322                               &config_depth)) {
    323         LOG(ERROR) << "eglGetConfigAttrib failed with error "
    324                    << GetLastEGLErrorString();
    325         return NULL;
    326       }
    327 
    328       if (config_depth == win_attribs.depth) {
    329         return config_;
    330       }
    331     }
    332 
    333     // Try without an alpha channel.
    334     config_attribs[kAlphaSizeOffset] = 0;
    335     if (!eglChooseConfig(g_display,
    336                          config_attribs,
    337                          &config_,
    338                          1,
    339                          &num_configs)) {
    340       LOG(ERROR) << "eglChooseConfig failed with error "
    341                  << GetLastEGLErrorString();
    342       return NULL;
    343     }
    344 
    345     if (num_configs == 0) {
    346       LOG(ERROR) << "No suitable EGL configs found.";
    347       return NULL;
    348     }
    349   }
    350   return config_;
    351 #endif
    352 }
    353 
    354 bool NativeViewGLSurfaceEGL::IsOffscreen() {
    355   return false;
    356 }
    357 
    358 bool NativeViewGLSurfaceEGL::SwapBuffers() {
    359   if (!eglSwapBuffers(GetDisplay(), surface_)) {
    360     DVLOG(1) << "eglSwapBuffers failed with error "
    361              << GetLastEGLErrorString();
    362     return false;
    363   }
    364 
    365   return true;
    366 }
    367 
    368 gfx::Size NativeViewGLSurfaceEGL::GetSize() {
    369   EGLint width;
    370   EGLint height;
    371   if (!eglQuerySurface(GetDisplay(), surface_, EGL_WIDTH, &width) ||
    372       !eglQuerySurface(GetDisplay(), surface_, EGL_HEIGHT, &height)) {
    373     NOTREACHED() << "eglQuerySurface failed with error "
    374                  << GetLastEGLErrorString();
    375     return gfx::Size();
    376   }
    377 
    378   return gfx::Size(width, height);
    379 }
    380 
    381 bool NativeViewGLSurfaceEGL::Resize(const gfx::Size& size) {
    382   if (size == GetSize())
    383     return true;
    384 
    385   scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
    386   GLContext* current_context = GLContext::GetCurrent();
    387   bool was_current =
    388       current_context && current_context->IsCurrent(this);
    389   if (was_current) {
    390     scoped_make_current.reset(
    391         new ui::ScopedMakeCurrent(current_context, this));
    392     current_context->ReleaseCurrent(this);
    393   }
    394 
    395   Destroy();
    396 
    397   if (!Initialize()) {
    398     LOG(ERROR) << "Failed to resize window.";
    399     return false;
    400   }
    401 
    402   return true;
    403 }
    404 
    405 bool NativeViewGLSurfaceEGL::Recreate() {
    406   Destroy();
    407   if (!Initialize()) {
    408     LOG(ERROR) << "Failed to create surface.";
    409     return false;
    410   }
    411   return true;
    412 }
    413 
    414 EGLSurface NativeViewGLSurfaceEGL::GetHandle() {
    415   return surface_;
    416 }
    417 
    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";
    423   }
    424   return extensions;
    425 }
    426 
    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();
    433     return false;
    434   }
    435   return true;
    436 }
    437 
    438 VSyncProvider* NativeViewGLSurfaceEGL::GetVSyncProvider() {
    439   return vsync_provider_.get();
    440 }
    441 
    442 NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() {
    443   Destroy();
    444 #if defined(OS_ANDROID)
    445   if (window_)
    446     ANativeWindow_release(window_);
    447 #endif
    448 }
    449 
    450 void NativeViewGLSurfaceEGL::SetHandle(EGLSurface surface) {
    451   surface_ = surface;
    452 }
    453 
    454 PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(const gfx::Size& size)
    455     : size_(size),
    456       surface_(NULL) {
    457 }
    458 
    459 bool PbufferGLSurfaceEGL::Initialize() {
    460   EGLSurface old_surface = surface_;
    461 
    462   EGLDisplay display = GetDisplay();
    463   if (!display) {
    464     LOG(ERROR) << "Trying to create surface with invalid display.";
    465     return false;
    466   }
    467 
    468   if (size_.GetArea() == 0) {
    469     LOG(ERROR) << "Error: surface has zero area "
    470                << size_.width() << " x " << size_.height();
    471     return false;
    472   }
    473 
    474   // Allocate the new pbuffer surface before freeing the old one to ensure
    475   // they have different addresses. If they have the same address then a
    476   // future call to MakeCurrent might early out because it appears the current
    477   // context and surface have not changed.
    478   const EGLint pbuffer_attribs[] = {
    479     EGL_WIDTH, size_.width(),
    480     EGL_HEIGHT, size_.height(),
    481     EGL_NONE
    482   };
    483 
    484   EGLSurface new_surface = eglCreatePbufferSurface(display,
    485                                                    GetConfig(),
    486                                                    pbuffer_attribs);
    487   if (!new_surface) {
    488     LOG(ERROR) << "eglCreatePbufferSurface failed with error "
    489                << GetLastEGLErrorString();
    490     return false;
    491   }
    492 
    493   if (old_surface)
    494     eglDestroySurface(display, old_surface);
    495 
    496   surface_ = new_surface;
    497   return true;
    498 }
    499 
    500 void PbufferGLSurfaceEGL::Destroy() {
    501   if (surface_) {
    502     if (!eglDestroySurface(GetDisplay(), surface_)) {
    503       LOG(ERROR) << "eglDestroySurface failed with error "
    504                  << GetLastEGLErrorString();
    505     }
    506     surface_ = NULL;
    507   }
    508 }
    509 
    510 EGLConfig PbufferGLSurfaceEGL::GetConfig() {
    511   return g_config;
    512 }
    513 
    514 bool PbufferGLSurfaceEGL::IsOffscreen() {
    515   return true;
    516 }
    517 
    518 bool PbufferGLSurfaceEGL::SwapBuffers() {
    519   NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL.";
    520   return false;
    521 }
    522 
    523 gfx::Size PbufferGLSurfaceEGL::GetSize() {
    524   return size_;
    525 }
    526 
    527 bool PbufferGLSurfaceEGL::Resize(const gfx::Size& size) {
    528   if (size == size_)
    529     return true;
    530 
    531   scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
    532   GLContext* current_context = GLContext::GetCurrent();
    533   bool was_current =
    534       current_context && current_context->IsCurrent(this);
    535   if (was_current) {
    536     scoped_make_current.reset(
    537         new ui::ScopedMakeCurrent(current_context, this));
    538   }
    539 
    540   size_ = size;
    541 
    542   if (!Initialize()) {
    543     LOG(ERROR) << "Failed to resize pbuffer.";
    544     return false;
    545   }
    546 
    547   return true;
    548 }
    549 
    550 EGLSurface PbufferGLSurfaceEGL::GetHandle() {
    551   return surface_;
    552 }
    553 
    554 void* PbufferGLSurfaceEGL::GetShareHandle() {
    555 #if defined(OS_ANDROID)
    556   NOTREACHED();
    557   return NULL;
    558 #else
    559   if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_query_surface_pointer)
    560     return NULL;
    561 
    562   if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle)
    563     return NULL;
    564 
    565   void* handle;
    566   if (!eglQuerySurfacePointerANGLE(g_display,
    567                                    GetHandle(),
    568                                    EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
    569                                    &handle)) {
    570     return NULL;
    571   }
    572 
    573   return handle;
    574 #endif
    575 }
    576 
    577 PbufferGLSurfaceEGL::~PbufferGLSurfaceEGL() {
    578   Destroy();
    579 }
    580 
    581 #if defined(ANDROID) || defined(USE_OZONE)
    582 
    583 // A thin subclass of |GLSurfaceOSMesa| that can be used in place
    584 // of a native hardware-provided surface when a native surface
    585 // provider is not available.
    586 class GLSurfaceOSMesaHeadless : public GLSurfaceOSMesa {
    587  public:
    588   explicit GLSurfaceOSMesaHeadless(gfx::AcceleratedWidget window);
    589 
    590   virtual bool IsOffscreen() OVERRIDE;
    591   virtual bool SwapBuffers() OVERRIDE;
    592 
    593  protected:
    594   virtual ~GLSurfaceOSMesaHeadless();
    595 
    596  private:
    597 
    598   DISALLOW_COPY_AND_ASSIGN(GLSurfaceOSMesaHeadless);
    599 };
    600 
    601 bool GLSurfaceOSMesaHeadless::IsOffscreen() { return false; }
    602 
    603 bool GLSurfaceOSMesaHeadless::SwapBuffers() { return true; }
    604 
    605 GLSurfaceOSMesaHeadless::GLSurfaceOSMesaHeadless(gfx::AcceleratedWidget window)
    606     : GLSurfaceOSMesa(OSMESA_BGRA, gfx::Size(1, 1)) {
    607   DCHECK(window);
    608 }
    609 
    610 GLSurfaceOSMesaHeadless::~GLSurfaceOSMesaHeadless() { Destroy(); }
    611 
    612 // static
    613 bool GLSurface::InitializeOneOffInternal() {
    614   if (GetGLImplementation() == kGLImplementationOSMesaGL) {
    615     return true;
    616   }
    617   DCHECK(GetGLImplementation() == kGLImplementationEGLGLES2);
    618 
    619   if (!GLSurfaceEGL::InitializeOneOff()) {
    620     LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
    621     return false;
    622   }
    623   return true;
    624 }
    625 
    626 // static
    627 scoped_refptr<GLSurface>
    628 GLSurface::CreateViewGLSurface(gfx::AcceleratedWidget window) {
    629 
    630   if (GetGLImplementation() == kGLImplementationOSMesaGL) {
    631     scoped_refptr<GLSurface> surface(new GLSurfaceOSMesaHeadless(window));
    632     if (!surface->Initialize())
    633       return NULL;
    634     return surface;
    635   }
    636   DCHECK(GetGLImplementation() == kGLImplementationEGLGLES2);
    637   if (window) {
    638     scoped_refptr<NativeViewGLSurfaceEGL> surface;
    639     VSyncProvider* sync_provider = NULL;
    640 #if defined(USE_OZONE)
    641     window = ui::SurfaceFactoryOzone::GetInstance()->RealizeAcceleratedWidget(
    642         window);
    643     sync_provider =
    644         ui::SurfaceFactoryOzone::GetInstance()->GetVSyncProvider(window);
    645 #endif
    646     surface = new NativeViewGLSurfaceEGL(window);
    647     if(surface->Initialize(sync_provider))
    648       return surface;
    649   } else {
    650     scoped_refptr<GLSurface> surface = new GLSurfaceStub();
    651     if (surface->Initialize())
    652       return surface;
    653   }
    654   return NULL;
    655 }
    656 
    657 // static
    658 scoped_refptr<GLSurface>
    659 GLSurface::CreateOffscreenGLSurface(const gfx::Size& size) {
    660   switch (GetGLImplementation()) {
    661     case kGLImplementationOSMesaGL: {
    662       scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(1, size));
    663       if (!surface->Initialize())
    664         return NULL;
    665 
    666       return surface;
    667     }
    668     case kGLImplementationEGLGLES2: {
    669       scoped_refptr<PbufferGLSurfaceEGL> surface(
    670           new PbufferGLSurfaceEGL(size));
    671       if (!surface->Initialize())
    672         return NULL;
    673       return surface;
    674     }
    675     default:
    676       NOTREACHED();
    677       return NULL;
    678   }
    679 }
    680 
    681 #endif
    682 
    683 }  // namespace gfx
    684