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 33namespace ui { 34 35namespace { 36 37const char kEglplatformShim[] = "EGLPLATFORM_SHIM"; 38const char kEglplatformShimDefault[] = "libeglplatform_shim.so.1"; 39const char kDefaultEglSoname[] = "libEGL.so.1"; 40const char kDefaultGlesSoname[] = "libGLESv2.so.2"; 41 42// Get the library soname to load. 43std::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 51class 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 88EgltestWindow::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 102EgltestWindow::~EgltestWindow() { 103 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); 104 if (window_id_ != SHIM_NO_WINDOW_ID) 105 eglplatform_shim_->ShimDestroyWindow(window_id_); 106} 107 108gfx::Rect EgltestWindow::GetBounds() { 109 return bounds_; 110} 111 112void EgltestWindow::SetBounds(const gfx::Rect& bounds) { 113 bounds_ = bounds; 114 delegate_->OnBoundsChanged(bounds); 115} 116 117void EgltestWindow::Show() { 118} 119 120void EgltestWindow::Hide() { 121} 122 123void EgltestWindow::Close() { 124} 125 126void EgltestWindow::SetCapture() { 127} 128 129void EgltestWindow::ReleaseCapture() { 130} 131 132void EgltestWindow::ToggleFullscreen() { 133} 134 135void EgltestWindow::Maximize() { 136} 137 138void EgltestWindow::Minimize() { 139} 140 141void EgltestWindow::Restore() { 142} 143 144void EgltestWindow::SetCursor(PlatformCursor cursor) { 145} 146 147void EgltestWindow::MoveCursorTo(const gfx::Point& location) { 148 event_factory_->WarpCursorTo(window_id_, location); 149} 150 151bool EgltestWindow::CanDispatchEvent(const ui::PlatformEvent& ne) { 152 return true; 153} 154 155uint32_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. 168class 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. 202class 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 222intptr_t SurfaceFactoryEgltest::GetNativeDisplay() { 223 return eglplatform_shim_->ShimGetNativeDisplay(); 224} 225 226scoped_ptr<SurfaceOzoneEGL> SurfaceFactoryEgltest::CreateEGLSurfaceForWidget( 227 gfx::AcceleratedWidget widget) { 228 return make_scoped_ptr<SurfaceOzoneEGL>( 229 new SurfaceOzoneEgltest(widget, eglplatform_shim_)); 230} 231 232bool 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 276const 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. 292class 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 386OzonePlatform* CreateOzonePlatformEgltest() { 387 OzonePlatformEgltest* platform = new OzonePlatformEgltest; 388 platform->Initialize(); 389 return platform; 390} 391 392} // namespace ui 393