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.
5 #include "ui/ozone/platform/egltest/ozone_platform_egltest.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 "base/threading/thread_checker.h"
13 #include "library_loaders/libeglplatform_shim.h"
14 #include "third_party/khronos/EGL/egl.h"
15 #include "ui/events/devices/device_data_manager.h"
16 #include "ui/events/event.h"
17 #include "ui/events/ozone/device/device_manager.h"
18 #include "ui/events/ozone/evdev/event_factory_evdev.h"
19 #include "ui/events/ozone/events_ozone.h"
20 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
21 #include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
22 #include "ui/events/platform/platform_event_dispatcher.h"
23 #include "ui/gfx/vsync_provider.h"
24 #include "ui/ozone/common/egl_util.h"
25 #include "ui/ozone/common/native_display_delegate_ozone.h"
26 #include "ui/ozone/common/stub_overlay_manager.h"
27 #include "ui/ozone/public/cursor_factory_ozone.h"
28 #include "ui/ozone/public/gpu_platform_support.h"
29 #include "ui/ozone/public/gpu_platform_support_host.h"
30 #include "ui/ozone/public/ozone_platform.h"
31 #include "ui/ozone/public/ozone_switches.h"
32 #include "ui/ozone/public/surface_factory_ozone.h"
33 #include "ui/ozone/public/surface_ozone_egl.h"
34 #include "ui/ozone/public/system_input_injector.h"
35 #include "ui/platform_window/platform_window.h"
36 #include "ui/platform_window/platform_window_delegate.h"
42 const char kEglplatformShim
[] = "EGLPLATFORM_SHIM";
43 const char kEglplatformShimDefault
[] = "libeglplatform_shim.so.1";
44 const char kDefaultEglSoname
[] = "libEGL.so.1";
45 const char kDefaultGlesSoname
[] = "libGLESv2.so.2";
47 // Get the library soname to load.
48 std::string
GetShimLibraryName() {
50 scoped_ptr
<base::Environment
> env(base::Environment::Create());
51 if (env
->GetVar(kEglplatformShim
, &library
))
53 return kEglplatformShimDefault
;
56 // Touch events are reported in device coordinates. This scales the event to the
57 // window's coordinate space.
58 void ScaleTouchEvent(TouchEvent
* event
, const gfx::SizeF
& size
) {
59 for (const auto& device
:
60 DeviceDataManager::GetInstance()->touchscreen_devices()) {
61 if (device
.id
== event
->source_device_id()) {
62 gfx::SizeF touchscreen_size
= device
.size
;
63 gfx::PointF location
= event
->location_f();
65 location
.Scale(size
.width() / touchscreen_size
.width(),
66 size
.height() / touchscreen_size
.height());
67 double ratio
= std::sqrt(size
.GetArea() / touchscreen_size
.GetArea());
69 event
->set_location(location
);
70 event
->set_radius_x(event
->pointer_details().radius_x() * ratio
);
71 event
->set_radius_y(event
->pointer_details().radius_y() * ratio
);
77 class EgltestWindow
: public PlatformWindow
, public PlatformEventDispatcher
{
79 EgltestWindow(PlatformWindowDelegate
* delegate
,
80 LibeglplatformShimLoader
* eglplatform_shim
,
81 EventFactoryEvdev
* event_factory
,
82 const gfx::Rect
& bounds
);
83 ~EgltestWindow() override
;
86 gfx::Rect
GetBounds() override
;
87 void SetBounds(const gfx::Rect
& bounds
) override
;
88 void SetTitle(const base::string16
& title
) override
;
91 void Close() override
;
92 void SetCapture() override
;
93 void ReleaseCapture() override
;
94 void ToggleFullscreen() override
;
95 void Maximize() override
;
96 void Minimize() override
;
97 void Restore() override
;
98 void SetCursor(PlatformCursor cursor
) override
;
99 void MoveCursorTo(const gfx::Point
& location
) override
;
100 void ConfineCursorToBounds(const gfx::Rect
& bounds
) override
;
101 PlatformImeController
* GetPlatformImeController() override
;
103 // PlatformEventDispatcher:
104 bool CanDispatchEvent(const PlatformEvent
& event
) override
;
105 uint32_t DispatchEvent(const PlatformEvent
& event
) override
;
108 PlatformWindowDelegate
* delegate_
;
109 LibeglplatformShimLoader
* eglplatform_shim_
;
110 EventFactoryEvdev
* event_factory_
;
112 ShimNativeWindowId window_id_
;
114 DISALLOW_COPY_AND_ASSIGN(EgltestWindow
);
117 EgltestWindow::EgltestWindow(PlatformWindowDelegate
* delegate
,
118 LibeglplatformShimLoader
* eglplatform_shim
,
119 EventFactoryEvdev
* event_factory
,
120 const gfx::Rect
& bounds
)
121 : delegate_(delegate
),
122 eglplatform_shim_(eglplatform_shim
),
123 event_factory_(event_factory
),
125 window_id_(SHIM_NO_WINDOW_ID
) {
126 window_id_
= eglplatform_shim_
->ShimCreateWindow();
127 delegate_
->OnAcceleratedWidgetAvailable(window_id_
, 1.f
);
128 ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
131 EgltestWindow::~EgltestWindow() {
132 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
133 if (window_id_
!= SHIM_NO_WINDOW_ID
)
134 eglplatform_shim_
->ShimDestroyWindow(window_id_
);
137 gfx::Rect
EgltestWindow::GetBounds() {
141 void EgltestWindow::SetBounds(const gfx::Rect
& bounds
) {
143 delegate_
->OnBoundsChanged(bounds
);
146 void EgltestWindow::SetTitle(const base::string16
& title
) {
149 void EgltestWindow::Show() {
152 void EgltestWindow::Hide() {
155 void EgltestWindow::Close() {
158 void EgltestWindow::SetCapture() {
161 void EgltestWindow::ReleaseCapture() {
164 void EgltestWindow::ToggleFullscreen() {
167 void EgltestWindow::Maximize() {
170 void EgltestWindow::Minimize() {
173 void EgltestWindow::Restore() {
176 void EgltestWindow::SetCursor(PlatformCursor cursor
) {
179 void EgltestWindow::MoveCursorTo(const gfx::Point
& location
) {
180 event_factory_
->WarpCursorTo(window_id_
, location
);
183 void EgltestWindow::ConfineCursorToBounds(const gfx::Rect
& bounds
) {
186 PlatformImeController
* EgltestWindow::GetPlatformImeController() {
190 bool EgltestWindow::CanDispatchEvent(const ui::PlatformEvent
& ne
) {
194 uint32_t EgltestWindow::DispatchEvent(const ui::PlatformEvent
& native_event
) {
195 DCHECK(native_event
);
196 Event
* event
= static_cast<Event
*>(native_event
);
197 if (event
->IsTouchEvent())
198 ScaleTouchEvent(static_cast<TouchEvent
*>(event
), bounds_
.size());
200 DispatchEventFromNativeUiEvent(
201 native_event
, base::Bind(&PlatformWindowDelegate::DispatchEvent
,
202 base::Unretained(delegate_
)));
204 return ui::POST_DISPATCH_STOP_PROPAGATION
;
207 // EGL surface wrapper for libeglplatform_shim.
209 // This just manages the native window lifetime using
210 // ShimGetNativeWindow & ShimReleaseNativeWindow.
211 class SurfaceOzoneEgltest
: public SurfaceOzoneEGL
{
213 SurfaceOzoneEgltest(ShimNativeWindowId window_id
,
214 LibeglplatformShimLoader
* eglplatform_shim
)
215 : eglplatform_shim_(eglplatform_shim
) {
216 native_window_
= eglplatform_shim_
->ShimGetNativeWindow(window_id
);
218 ~SurfaceOzoneEgltest() override
{
219 bool ret
= eglplatform_shim_
->ShimReleaseNativeWindow(native_window_
);
223 intptr_t GetNativeWindow() override
{ return native_window_
; }
225 bool OnSwapBuffers() override
{ return true; }
227 bool OnSwapBuffersAsync(const SwapCompletionCallback
& callback
) override
{
228 callback
.Run(gfx::SwapResult::SWAP_ACK
);
232 bool ResizeNativeWindow(const gfx::Size
& viewport_size
) override
{
236 scoped_ptr
<gfx::VSyncProvider
> CreateVSyncProvider() override
{
241 LibeglplatformShimLoader
* eglplatform_shim_
;
242 intptr_t native_window_
;
245 // EGL surface factory for libeglplatform_shim.
247 // This finds the right EGL/GLES2 libraries for loading, and creates
248 // a single native window via ShimCreateWindow for drawing
250 class SurfaceFactoryEgltest
: public ui::SurfaceFactoryOzone
{
252 SurfaceFactoryEgltest(LibeglplatformShimLoader
* eglplatform_shim
)
253 : eglplatform_shim_(eglplatform_shim
) {}
254 ~SurfaceFactoryEgltest() override
{
255 DCHECK(thread_checker_
.CalledOnValidThread());
258 // SurfaceFactoryOzone:
259 intptr_t GetNativeDisplay() override
;
260 scoped_ptr
<SurfaceOzoneEGL
> CreateEGLSurfaceForWidget(
261 gfx::AcceleratedWidget widget
) override
;
262 const int32
* GetEGLSurfaceProperties(const int32
* desired_list
) override
;
263 bool LoadEGLGLES2Bindings(
264 AddGLLibraryCallback add_gl_library
,
265 SetGLGetProcAddressProcCallback set_gl_get_proc_address
) override
;
268 LibeglplatformShimLoader
* eglplatform_shim_
;
269 base::ThreadChecker thread_checker_
;
272 intptr_t SurfaceFactoryEgltest::GetNativeDisplay() {
273 DCHECK(thread_checker_
.CalledOnValidThread());
274 return eglplatform_shim_
->ShimGetNativeDisplay();
277 scoped_ptr
<SurfaceOzoneEGL
> SurfaceFactoryEgltest::CreateEGLSurfaceForWidget(
278 gfx::AcceleratedWidget widget
) {
279 DCHECK(thread_checker_
.CalledOnValidThread());
280 return make_scoped_ptr
<SurfaceOzoneEGL
>(
281 new SurfaceOzoneEgltest(widget
, eglplatform_shim_
));
284 bool SurfaceFactoryEgltest::LoadEGLGLES2Bindings(
285 AddGLLibraryCallback add_gl_library
,
286 SetGLGetProcAddressProcCallback set_gl_get_proc_address
) {
287 DCHECK(thread_checker_
.CalledOnValidThread());
288 const char* egl_soname
= eglplatform_shim_
->ShimQueryString(SHIM_EGL_LIBRARY
);
289 const char* gles_soname
=
290 eglplatform_shim_
->ShimQueryString(SHIM_GLES_LIBRARY
);
292 egl_soname
= kDefaultEglSoname
;
294 gles_soname
= kDefaultGlesSoname
;
296 return ::ui::LoadEGLGLES2Bindings(add_gl_library
, set_gl_get_proc_address
,
297 egl_soname
, gles_soname
);
300 const int32
* SurfaceFactoryEgltest::GetEGLSurfaceProperties(
301 const int32
* desired_list
) {
302 DCHECK(thread_checker_
.CalledOnValidThread());
303 static const int32 broken_props
[] = {
307 EGL_WINDOW_BIT
| EGL_PBUFFER_BIT
,
313 // Test platform for EGL.
315 // This is a tiny EGL-based platform. Creation of the native window is
316 // handled by a separate library called eglplatform_shim.so.1 because
317 // this itself is platform specific and we want to test out multiple
318 // hardware platforms.
319 class OzonePlatformEgltest
: public OzonePlatform
{
321 OzonePlatformEgltest() : shim_initialized_(false) {}
322 ~OzonePlatformEgltest() override
{
323 if (shim_initialized_
)
324 eglplatform_shim_
.ShimTerminate();
328 std::string library
= GetShimLibraryName();
330 if (eglplatform_shim_
.Load(library
))
333 base::FilePath module_path
;
334 if (!PathService::Get(base::DIR_MODULE
, &module_path
))
335 LOG(ERROR
) << "failed to get DIR_MODULE from PathService";
336 base::FilePath library_path
= module_path
.Append(library
);
338 if (eglplatform_shim_
.Load(library_path
.value()))
341 LOG(FATAL
) << "failed to load " << library
;
346 shim_initialized_
= eglplatform_shim_
.ShimInitialize();
350 ui::SurfaceFactoryOzone
* GetSurfaceFactoryOzone() override
{
351 return surface_factory_ozone_
.get();
353 OverlayManagerOzone
* GetOverlayManager() override
{
354 return overlay_manager_
.get();
356 CursorFactoryOzone
* GetCursorFactoryOzone() override
{
357 return cursor_factory_ozone_
.get();
359 InputController
* GetInputController() override
{
360 return event_factory_ozone_
->input_controller();
362 GpuPlatformSupport
* GetGpuPlatformSupport() override
{
363 return gpu_platform_support_
.get();
365 GpuPlatformSupportHost
* GetGpuPlatformSupportHost() override
{
366 return gpu_platform_support_host_
.get();
368 scoped_ptr
<SystemInputInjector
> CreateSystemInputInjector() override
{
369 return nullptr; // no input injection support.
371 scoped_ptr
<PlatformWindow
> CreatePlatformWindow(
372 PlatformWindowDelegate
* delegate
,
373 const gfx::Rect
& bounds
) override
{
374 return make_scoped_ptr
<PlatformWindow
>(new EgltestWindow(
375 delegate
, &eglplatform_shim_
, event_factory_ozone_
.get(), bounds
));
377 scoped_ptr
<NativeDisplayDelegate
> CreateNativeDisplayDelegate() override
{
378 return make_scoped_ptr(new NativeDisplayDelegateOzone());
380 base::ScopedFD
OpenClientNativePixmapDevice() const override
{
381 return base::ScopedFD();
384 void InitializeUI() override
{
385 device_manager_
= CreateDeviceManager();
386 overlay_manager_
.reset(new StubOverlayManager());
387 KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
388 make_scoped_ptr(new StubKeyboardLayoutEngine()));
389 event_factory_ozone_
.reset(new EventFactoryEvdev(
390 NULL
, device_manager_
.get(),
391 KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()));
392 cursor_factory_ozone_
.reset(new CursorFactoryOzone());
393 gpu_platform_support_host_
.reset(CreateStubGpuPlatformSupportHost());
396 void InitializeGPU() override
{
397 surface_factory_ozone_
.reset(new SurfaceFactoryEgltest(&eglplatform_shim_
));
398 gpu_platform_support_
.reset(CreateStubGpuPlatformSupport());
402 LibeglplatformShimLoader eglplatform_shim_
;
403 scoped_ptr
<DeviceManager
> device_manager_
;
404 scoped_ptr
<SurfaceFactoryEgltest
> surface_factory_ozone_
;
405 scoped_ptr
<EventFactoryEvdev
> event_factory_ozone_
;
406 scoped_ptr
<CursorFactoryOzone
> cursor_factory_ozone_
;
407 scoped_ptr
<GpuPlatformSupport
> gpu_platform_support_
;
408 scoped_ptr
<GpuPlatformSupportHost
> gpu_platform_support_host_
;
409 scoped_ptr
<OverlayManagerOzone
> overlay_manager_
;
411 bool shim_initialized_
;
413 DISALLOW_COPY_AND_ASSIGN(OzonePlatformEgltest
);
418 OzonePlatform
* CreateOzonePlatformEgltest() {
419 OzonePlatformEgltest
* platform
= new OzonePlatformEgltest
;
420 platform
->Initialize();