Home | History | Annotate | Download | only in egltest
      1 // Copyright 2014 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/ozone/platform/egltest/ozone_platform_egltest.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/environment.h"
     10 #include "base/files/file_path.h"
     11 #include "base/path_service.h"
     12 #include "library_loaders/libeglplatform_shim.h"
     13 #include "third_party/khronos/EGL/egl.h"
     14 #include "ui/events/ozone/device/device_manager.h"
     15 #include "ui/events/ozone/evdev/event_factory_evdev.h"
     16 #include "ui/events/ozone/events_ozone.h"
     17 #include "ui/events/platform/platform_event_dispatcher.h"
     18 #include "ui/gfx/vsync_provider.h"
     19 #include "ui/ozone/public/cursor_factory_ozone.h"
     20 #include "ui/ozone/public/gpu_platform_support.h"
     21 #include "ui/ozone/public/gpu_platform_support_host.h"
     22 #include "ui/ozone/public/ozone_platform.h"
     23 #include "ui/ozone/public/ozone_switches.h"
     24 #include "ui/ozone/public/surface_factory_ozone.h"
     25 #include "ui/ozone/public/surface_ozone_egl.h"
     26 #include "ui/platform_window/platform_window.h"
     27 #include "ui/platform_window/platform_window_delegate.h"
     28 
     29 #if defined(OS_CHROMEOS)
     30 #include "ui/ozone/common/chromeos/native_display_delegate_ozone.h"
     31 #endif
     32 
     33 namespace ui {
     34 
     35 namespace {
     36 
     37 const char kEglplatformShim[] = "EGLPLATFORM_SHIM";
     38 const char kEglplatformShimDefault[] = "libeglplatform_shim.so.1";
     39 const char kDefaultEglSoname[] = "libEGL.so.1";
     40 const char kDefaultGlesSoname[] = "libGLESv2.so.2";
     41 
     42 // Get the library soname to load.
     43 std::string GetShimLibraryName() {
     44   std::string library;
     45   scoped_ptr<base::Environment> env(base::Environment::Create());
     46   if (env->GetVar(kEglplatformShim, &library))
     47     return library;
     48   return kEglplatformShimDefault;
     49 }
     50 
     51 class EgltestWindow : public PlatformWindow, public PlatformEventDispatcher {
     52  public:
     53   EgltestWindow(PlatformWindowDelegate* delegate,
     54                 LibeglplatformShimLoader* eglplatform_shim,
     55                 EventFactoryEvdev* event_factory,
     56                 const gfx::Rect& bounds);
     57   virtual ~EgltestWindow();
     58 
     59   // PlatformWindow:
     60   virtual gfx::Rect GetBounds() OVERRIDE;
     61   virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
     62   virtual void Show() OVERRIDE;
     63   virtual void Hide() OVERRIDE;
     64   virtual void Close() OVERRIDE;
     65   virtual void SetCapture() OVERRIDE;
     66   virtual void ReleaseCapture() OVERRIDE;
     67   virtual void ToggleFullscreen() OVERRIDE;
     68   virtual void Maximize() OVERRIDE;
     69   virtual void Minimize() OVERRIDE;
     70   virtual void Restore() OVERRIDE;
     71   virtual void SetCursor(PlatformCursor cursor) OVERRIDE;
     72   virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
     73 
     74   // PlatformEventDispatcher:
     75   virtual bool CanDispatchEvent(const PlatformEvent& event) OVERRIDE;
     76   virtual uint32_t DispatchEvent(const PlatformEvent& event) OVERRIDE;
     77 
     78  private:
     79   PlatformWindowDelegate* delegate_;
     80   LibeglplatformShimLoader* eglplatform_shim_;
     81   EventFactoryEvdev* event_factory_;
     82   gfx::Rect bounds_;
     83   ShimNativeWindowId window_id_;
     84 
     85   DISALLOW_COPY_AND_ASSIGN(EgltestWindow);
     86 };
     87 
     88 EgltestWindow::EgltestWindow(PlatformWindowDelegate* delegate,
     89                              LibeglplatformShimLoader* eglplatform_shim,
     90                              EventFactoryEvdev* event_factory,
     91                              const gfx::Rect& bounds)
     92     : delegate_(delegate),
     93       eglplatform_shim_(eglplatform_shim),
     94       event_factory_(event_factory),
     95       bounds_(bounds),
     96       window_id_(SHIM_NO_WINDOW_ID) {
     97   window_id_ = eglplatform_shim_->ShimCreateWindow();
     98   delegate_->OnAcceleratedWidgetAvailable(window_id_);
     99   ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
    100 }
    101 
    102 EgltestWindow::~EgltestWindow() {
    103   ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
    104   if (window_id_ != SHIM_NO_WINDOW_ID)
    105     eglplatform_shim_->ShimDestroyWindow(window_id_);
    106 }
    107 
    108 gfx::Rect EgltestWindow::GetBounds() {
    109   return bounds_;
    110 }
    111 
    112 void EgltestWindow::SetBounds(const gfx::Rect& bounds) {
    113   bounds_ = bounds;
    114   delegate_->OnBoundsChanged(bounds);
    115 }
    116 
    117 void EgltestWindow::Show() {
    118 }
    119 
    120 void EgltestWindow::Hide() {
    121 }
    122 
    123 void EgltestWindow::Close() {
    124 }
    125 
    126 void EgltestWindow::SetCapture() {
    127 }
    128 
    129 void EgltestWindow::ReleaseCapture() {
    130 }
    131 
    132 void EgltestWindow::ToggleFullscreen() {
    133 }
    134 
    135 void EgltestWindow::Maximize() {
    136 }
    137 
    138 void EgltestWindow::Minimize() {
    139 }
    140 
    141 void EgltestWindow::Restore() {
    142 }
    143 
    144 void EgltestWindow::SetCursor(PlatformCursor cursor) {
    145 }
    146 
    147 void EgltestWindow::MoveCursorTo(const gfx::Point& location) {
    148   event_factory_->WarpCursorTo(window_id_, location);
    149 }
    150 
    151 bool EgltestWindow::CanDispatchEvent(const ui::PlatformEvent& ne) {
    152   return true;
    153 }
    154 
    155 uint32_t EgltestWindow::DispatchEvent(const ui::PlatformEvent& native_event) {
    156   DispatchEventFromNativeUiEvent(
    157       native_event,
    158       base::Bind(&PlatformWindowDelegate::DispatchEvent,
    159                  base::Unretained(delegate_)));
    160 
    161   return ui::POST_DISPATCH_STOP_PROPAGATION;
    162 }
    163 
    164 // EGL surface wrapper for libeglplatform_shim.
    165 //
    166 // This just manages the native window lifetime using
    167 // ShimGetNativeWindow & ShimReleaseNativeWindow.
    168 class SurfaceOzoneEgltest : public SurfaceOzoneEGL {
    169  public:
    170   SurfaceOzoneEgltest(ShimNativeWindowId window_id,
    171                       LibeglplatformShimLoader* eglplatform_shim)
    172       : eglplatform_shim_(eglplatform_shim) {
    173     native_window_ = eglplatform_shim_->ShimGetNativeWindow(window_id);
    174   }
    175   virtual ~SurfaceOzoneEgltest() {
    176     bool ret = eglplatform_shim_->ShimReleaseNativeWindow(native_window_);
    177     DCHECK(ret);
    178   }
    179 
    180   virtual intptr_t GetNativeWindow() OVERRIDE { return native_window_; }
    181 
    182   virtual bool OnSwapBuffers() OVERRIDE { return true; }
    183 
    184   virtual bool ResizeNativeWindow(const gfx::Size& viewport_size) OVERRIDE {
    185     return true;
    186   }
    187 
    188   virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE {
    189     return scoped_ptr<gfx::VSyncProvider>();
    190   }
    191 
    192  private:
    193   LibeglplatformShimLoader* eglplatform_shim_;
    194   intptr_t native_window_;
    195 };
    196 
    197 // EGL surface factory for libeglplatform_shim.
    198 //
    199 // This finds the right EGL/GLES2 libraries for loading, and creates
    200 // a single native window via ShimCreateWindow for drawing
    201 // into.
    202 class SurfaceFactoryEgltest : public ui::SurfaceFactoryOzone {
    203  public:
    204   SurfaceFactoryEgltest(LibeglplatformShimLoader* eglplatform_shim)
    205       : eglplatform_shim_(eglplatform_shim) {}
    206   virtual ~SurfaceFactoryEgltest() {}
    207 
    208   // SurfaceFactoryOzone:
    209   virtual intptr_t GetNativeDisplay() OVERRIDE;
    210   virtual scoped_ptr<SurfaceOzoneEGL> CreateEGLSurfaceForWidget(
    211       gfx::AcceleratedWidget widget) OVERRIDE;
    212   virtual const int32* GetEGLSurfaceProperties(
    213       const int32* desired_list) OVERRIDE;
    214   virtual bool LoadEGLGLES2Bindings(
    215       AddGLLibraryCallback add_gl_library,
    216       SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
    217 
    218  private:
    219   LibeglplatformShimLoader* eglplatform_shim_;
    220 };
    221 
    222 intptr_t SurfaceFactoryEgltest::GetNativeDisplay() {
    223   return eglplatform_shim_->ShimGetNativeDisplay();
    224 }
    225 
    226 scoped_ptr<SurfaceOzoneEGL> SurfaceFactoryEgltest::CreateEGLSurfaceForWidget(
    227     gfx::AcceleratedWidget widget) {
    228   return make_scoped_ptr<SurfaceOzoneEGL>(
    229       new SurfaceOzoneEgltest(widget, eglplatform_shim_));
    230 }
    231 
    232 bool SurfaceFactoryEgltest::LoadEGLGLES2Bindings(
    233     AddGLLibraryCallback add_gl_library,
    234     SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
    235   const char* egl_soname = eglplatform_shim_->ShimQueryString(SHIM_EGL_LIBRARY);
    236   const char* gles_soname =
    237       eglplatform_shim_->ShimQueryString(SHIM_GLES_LIBRARY);
    238   if (!egl_soname)
    239     egl_soname = kDefaultEglSoname;
    240   if (!gles_soname)
    241     gles_soname = kDefaultGlesSoname;
    242 
    243   base::NativeLibraryLoadError error;
    244   base::NativeLibrary egl_library =
    245       base::LoadNativeLibrary(base::FilePath(egl_soname), &error);
    246   if (!egl_library) {
    247     LOG(WARNING) << "Failed to load EGL library: " << error.ToString();
    248     return false;
    249   }
    250 
    251   base::NativeLibrary gles_library =
    252       base::LoadNativeLibrary(base::FilePath(gles_soname), &error);
    253   if (!gles_library) {
    254     LOG(WARNING) << "Failed to load GLES library: " << error.ToString();
    255     base::UnloadNativeLibrary(egl_library);
    256     return false;
    257   }
    258 
    259   GLGetProcAddressProc get_proc_address =
    260       reinterpret_cast<GLGetProcAddressProc>(
    261           base::GetFunctionPointerFromNativeLibrary(egl_library,
    262                                                     "eglGetProcAddress"));
    263   if (!get_proc_address) {
    264     LOG(ERROR) << "eglGetProcAddress not found.";
    265     base::UnloadNativeLibrary(egl_library);
    266     base::UnloadNativeLibrary(gles_library);
    267     return false;
    268   }
    269 
    270   set_gl_get_proc_address.Run(get_proc_address);
    271   add_gl_library.Run(egl_library);
    272   add_gl_library.Run(gles_library);
    273   return true;
    274 }
    275 
    276 const int32* SurfaceFactoryEgltest::GetEGLSurfaceProperties(
    277     const int32* desired_list) {
    278   static const int32 broken_props[] = {
    279       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    280       EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
    281       EGL_NONE,
    282   };
    283   return broken_props;
    284 }
    285 
    286 // Test platform for EGL.
    287 //
    288 // This is a tiny EGL-based platform. Creation of the native window is
    289 // handled by a separate library called eglplatform_shim.so.1 because
    290 // this itself is platform specific and we want to test out multiple
    291 // hardware platforms.
    292 class OzonePlatformEgltest : public OzonePlatform {
    293  public:
    294   OzonePlatformEgltest() : shim_initialized_(false) {}
    295   virtual ~OzonePlatformEgltest() {
    296     if (shim_initialized_)
    297       eglplatform_shim_.ShimTerminate();
    298   }
    299 
    300   void LoadShim() {
    301     std::string library = GetShimLibraryName();
    302 
    303     if (eglplatform_shim_.Load(library))
    304       return;
    305 
    306     base::FilePath module_path;
    307     if (!PathService::Get(base::DIR_MODULE, &module_path))
    308       LOG(ERROR) << "failed to get DIR_MODULE from PathService";
    309     base::FilePath library_path = module_path.Append(library);
    310 
    311     if (eglplatform_shim_.Load(library_path.value()))
    312       return;
    313 
    314     LOG(FATAL) << "failed to load " << library;
    315   }
    316 
    317   void Initialize() {
    318     LoadShim();
    319     shim_initialized_ = eglplatform_shim_.ShimInitialize();
    320   }
    321 
    322   // OzonePlatform:
    323   virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE {
    324     return surface_factory_ozone_.get();
    325   }
    326   virtual CursorFactoryOzone* GetCursorFactoryOzone() OVERRIDE {
    327     return cursor_factory_ozone_.get();
    328   }
    329   virtual GpuPlatformSupport* GetGpuPlatformSupport() OVERRIDE {
    330     return gpu_platform_support_.get();
    331   }
    332   virtual GpuPlatformSupportHost* GetGpuPlatformSupportHost() OVERRIDE {
    333     return gpu_platform_support_host_.get();
    334   }
    335   virtual scoped_ptr<PlatformWindow> CreatePlatformWindow(
    336       PlatformWindowDelegate* delegate,
    337       const gfx::Rect& bounds) OVERRIDE {
    338     return make_scoped_ptr<PlatformWindow>(
    339         new EgltestWindow(delegate,
    340                           &eglplatform_shim_,
    341                           event_factory_ozone_.get(),
    342                           bounds));
    343   }
    344 
    345 #if defined(OS_CHROMEOS)
    346   virtual scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate()
    347       OVERRIDE {
    348     return scoped_ptr<NativeDisplayDelegate>(new NativeDisplayDelegateOzone());
    349   }
    350 #endif
    351 
    352   virtual void InitializeUI() OVERRIDE {
    353     device_manager_ = CreateDeviceManager();
    354     if (!surface_factory_ozone_)
    355       surface_factory_ozone_.reset(
    356           new SurfaceFactoryEgltest(&eglplatform_shim_));
    357     event_factory_ozone_.reset(
    358         new EventFactoryEvdev(NULL, device_manager_.get()));
    359     cursor_factory_ozone_.reset(new CursorFactoryOzone());
    360     gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
    361   }
    362 
    363   virtual void InitializeGPU() OVERRIDE {
    364     if (!surface_factory_ozone_)
    365       surface_factory_ozone_.reset(
    366           new SurfaceFactoryEgltest(&eglplatform_shim_));
    367     gpu_platform_support_.reset(CreateStubGpuPlatformSupport());
    368   }
    369 
    370  private:
    371   LibeglplatformShimLoader eglplatform_shim_;
    372   scoped_ptr<DeviceManager> device_manager_;
    373   scoped_ptr<SurfaceFactoryEgltest> surface_factory_ozone_;
    374   scoped_ptr<EventFactoryEvdev> event_factory_ozone_;
    375   scoped_ptr<CursorFactoryOzone> cursor_factory_ozone_;
    376   scoped_ptr<GpuPlatformSupport> gpu_platform_support_;
    377   scoped_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
    378 
    379   bool shim_initialized_;
    380 
    381   DISALLOW_COPY_AND_ASSIGN(OzonePlatformEgltest);
    382 };
    383 
    384 }  // namespace
    385 
    386 OzonePlatform* CreateOzonePlatformEgltest() {
    387   OzonePlatformEgltest* platform = new OzonePlatformEgltest;
    388   platform->Initialize();
    389   return platform;
    390 }
    391 
    392 }  // namespace ui
    393