blob: 31f35a6e33f597ee27d6ba05ce9eaf9f9daef6c0 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/egltest/ozone_platform_egltest.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/threading/thread_checker.h"
#include "library_loaders/libeglplatform_shim.h"
#include "third_party/khronos/EGL/egl.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/events/event.h"
#include "ui/events/ozone/device/device_manager.h"
#include "ui/events/ozone/evdev/event_factory_evdev.h"
#include "ui/events/ozone/events_ozone.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/gfx/vsync_provider.h"
#include "ui/ozone/common/egl_util.h"
#include "ui/ozone/common/native_display_delegate_ozone.h"
#include "ui/ozone/common/stub_overlay_manager.h"
#include "ui/ozone/public/cursor_factory_ozone.h"
#include "ui/ozone/public/gpu_platform_support.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/ozone_switches.h"
#include "ui/ozone/public/surface_factory_ozone.h"
#include "ui/ozone/public/surface_ozone_egl.h"
#include "ui/ozone/public/system_input_injector.h"
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_delegate.h"
namespace ui {
namespace {
const char kEglplatformShim[] = "EGLPLATFORM_SHIM";
const char kEglplatformShimDefault[] = "libeglplatform_shim.so.1";
const char kDefaultEglSoname[] = "libEGL.so.1";
const char kDefaultGlesSoname[] = "libGLESv2.so.2";
// Get the library soname to load.
std::string GetShimLibraryName() {
std::string library;
scoped_ptr<base::Environment> env(base::Environment::Create());
if (env->GetVar(kEglplatformShim, &library))
return library;
return kEglplatformShimDefault;
}
// Touch events are reported in device coordinates. This scales the event to the
// window's coordinate space.
void ScaleTouchEvent(TouchEvent* event, const gfx::SizeF& size) {
for (const auto& device :
DeviceDataManager::GetInstance()->touchscreen_devices()) {
if (device.id == event->source_device_id()) {
gfx::SizeF touchscreen_size = device.size;
gfx::PointF location = event->location_f();
location.Scale(size.width() / touchscreen_size.width(),
size.height() / touchscreen_size.height());
double ratio = std::sqrt(size.GetArea() / touchscreen_size.GetArea());
event->set_location(location);
event->set_radius_x(event->radius_x() * ratio);
event->set_radius_y(event->radius_y() * ratio);
return;
}
}
}
class EgltestWindow : public PlatformWindow, public PlatformEventDispatcher {
public:
EgltestWindow(PlatformWindowDelegate* delegate,
LibeglplatformShimLoader* eglplatform_shim,
EventFactoryEvdev* event_factory,
const gfx::Rect& bounds);
~EgltestWindow() override;
// PlatformWindow:
gfx::Rect GetBounds() override;
void SetBounds(const gfx::Rect& bounds) override;
void Show() override;
void Hide() override;
void Close() override;
void SetCapture() override;
void ReleaseCapture() override;
void ToggleFullscreen() override;
void Maximize() override;
void Minimize() override;
void Restore() override;
void SetCursor(PlatformCursor cursor) override;
void MoveCursorTo(const gfx::Point& location) override;
void ConfineCursorToBounds(const gfx::Rect& bounds) override;
// PlatformEventDispatcher:
bool CanDispatchEvent(const PlatformEvent& event) override;
uint32_t DispatchEvent(const PlatformEvent& event) override;
private:
PlatformWindowDelegate* delegate_;
LibeglplatformShimLoader* eglplatform_shim_;
EventFactoryEvdev* event_factory_;
gfx::Rect bounds_;
ShimNativeWindowId window_id_;
DISALLOW_COPY_AND_ASSIGN(EgltestWindow);
};
EgltestWindow::EgltestWindow(PlatformWindowDelegate* delegate,
LibeglplatformShimLoader* eglplatform_shim,
EventFactoryEvdev* event_factory,
const gfx::Rect& bounds)
: delegate_(delegate),
eglplatform_shim_(eglplatform_shim),
event_factory_(event_factory),
bounds_(bounds),
window_id_(SHIM_NO_WINDOW_ID) {
window_id_ = eglplatform_shim_->ShimCreateWindow();
delegate_->OnAcceleratedWidgetAvailable(window_id_);
ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
}
EgltestWindow::~EgltestWindow() {
ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
if (window_id_ != SHIM_NO_WINDOW_ID)
eglplatform_shim_->ShimDestroyWindow(window_id_);
}
gfx::Rect EgltestWindow::GetBounds() {
return bounds_;
}
void EgltestWindow::SetBounds(const gfx::Rect& bounds) {
bounds_ = bounds;
delegate_->OnBoundsChanged(bounds);
}
void EgltestWindow::Show() {
}
void EgltestWindow::Hide() {
}
void EgltestWindow::Close() {
}
void EgltestWindow::SetCapture() {
}
void EgltestWindow::ReleaseCapture() {
}
void EgltestWindow::ToggleFullscreen() {
}
void EgltestWindow::Maximize() {
}
void EgltestWindow::Minimize() {
}
void EgltestWindow::Restore() {
}
void EgltestWindow::SetCursor(PlatformCursor cursor) {
}
void EgltestWindow::MoveCursorTo(const gfx::Point& location) {
event_factory_->WarpCursorTo(window_id_, location);
}
void EgltestWindow::ConfineCursorToBounds(const gfx::Rect& bounds) {
}
bool EgltestWindow::CanDispatchEvent(const ui::PlatformEvent& ne) {
return true;
}
uint32_t EgltestWindow::DispatchEvent(const ui::PlatformEvent& native_event) {
DCHECK(native_event);
Event* event = static_cast<Event*>(native_event);
if (event->IsTouchEvent())
ScaleTouchEvent(static_cast<TouchEvent*>(event), bounds_.size());
DispatchEventFromNativeUiEvent(
native_event, base::Bind(&PlatformWindowDelegate::DispatchEvent,
base::Unretained(delegate_)));
return ui::POST_DISPATCH_STOP_PROPAGATION;
}
// EGL surface wrapper for libeglplatform_shim.
//
// This just manages the native window lifetime using
// ShimGetNativeWindow & ShimReleaseNativeWindow.
class SurfaceOzoneEgltest : public SurfaceOzoneEGL {
public:
SurfaceOzoneEgltest(ShimNativeWindowId window_id,
LibeglplatformShimLoader* eglplatform_shim)
: eglplatform_shim_(eglplatform_shim) {
native_window_ = eglplatform_shim_->ShimGetNativeWindow(window_id);
}
~SurfaceOzoneEgltest() override {
bool ret = eglplatform_shim_->ShimReleaseNativeWindow(native_window_);
DCHECK(ret);
}
intptr_t GetNativeWindow() override { return native_window_; }
bool OnSwapBuffers() override { return true; }
bool OnSwapBuffersAsync(const SwapCompletionCallback& callback) override {
callback.Run(gfx::SwapResult::SWAP_ACK);
return true;
}
bool ResizeNativeWindow(const gfx::Size& viewport_size) override {
return true;
}
scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override {
return nullptr;
}
private:
LibeglplatformShimLoader* eglplatform_shim_;
intptr_t native_window_;
};
// EGL surface factory for libeglplatform_shim.
//
// This finds the right EGL/GLES2 libraries for loading, and creates
// a single native window via ShimCreateWindow for drawing
// into.
class SurfaceFactoryEgltest : public ui::SurfaceFactoryOzone {
public:
SurfaceFactoryEgltest(LibeglplatformShimLoader* eglplatform_shim)
: eglplatform_shim_(eglplatform_shim) {}
~SurfaceFactoryEgltest() override {
DCHECK(thread_checker_.CalledOnValidThread());
}
// SurfaceFactoryOzone:
intptr_t GetNativeDisplay() override;
scoped_ptr<SurfaceOzoneEGL> CreateEGLSurfaceForWidget(
gfx::AcceleratedWidget widget) override;
const int32* GetEGLSurfaceProperties(const int32* desired_list) override;
bool LoadEGLGLES2Bindings(
AddGLLibraryCallback add_gl_library,
SetGLGetProcAddressProcCallback set_gl_get_proc_address) override;
private:
LibeglplatformShimLoader* eglplatform_shim_;
base::ThreadChecker thread_checker_;
};
intptr_t SurfaceFactoryEgltest::GetNativeDisplay() {
DCHECK(thread_checker_.CalledOnValidThread());
return eglplatform_shim_->ShimGetNativeDisplay();
}
scoped_ptr<SurfaceOzoneEGL> SurfaceFactoryEgltest::CreateEGLSurfaceForWidget(
gfx::AcceleratedWidget widget) {
DCHECK(thread_checker_.CalledOnValidThread());
return make_scoped_ptr<SurfaceOzoneEGL>(
new SurfaceOzoneEgltest(widget, eglplatform_shim_));
}
bool SurfaceFactoryEgltest::LoadEGLGLES2Bindings(
AddGLLibraryCallback add_gl_library,
SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
DCHECK(thread_checker_.CalledOnValidThread());
const char* egl_soname = eglplatform_shim_->ShimQueryString(SHIM_EGL_LIBRARY);
const char* gles_soname =
eglplatform_shim_->ShimQueryString(SHIM_GLES_LIBRARY);
if (!egl_soname)
egl_soname = kDefaultEglSoname;
if (!gles_soname)
gles_soname = kDefaultGlesSoname;
return ::ui::LoadEGLGLES2Bindings(add_gl_library, set_gl_get_proc_address,
egl_soname, gles_soname);
}
const int32* SurfaceFactoryEgltest::GetEGLSurfaceProperties(
const int32* desired_list) {
DCHECK(thread_checker_.CalledOnValidThread());
static const int32 broken_props[] = {
EGL_RENDERABLE_TYPE,
EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE,
EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
EGL_NONE,
};
return broken_props;
}
// Test platform for EGL.
//
// This is a tiny EGL-based platform. Creation of the native window is
// handled by a separate library called eglplatform_shim.so.1 because
// this itself is platform specific and we want to test out multiple
// hardware platforms.
class OzonePlatformEgltest : public OzonePlatform {
public:
OzonePlatformEgltest() : shim_initialized_(false) {}
~OzonePlatformEgltest() override {
if (shim_initialized_)
eglplatform_shim_.ShimTerminate();
}
void LoadShim() {
std::string library = GetShimLibraryName();
if (eglplatform_shim_.Load(library))
return;
base::FilePath module_path;
if (!PathService::Get(base::DIR_MODULE, &module_path))
LOG(ERROR) << "failed to get DIR_MODULE from PathService";
base::FilePath library_path = module_path.Append(library);
if (eglplatform_shim_.Load(library_path.value()))
return;
LOG(FATAL) << "failed to load " << library;
}
void Initialize() {
LoadShim();
shim_initialized_ = eglplatform_shim_.ShimInitialize();
}
// OzonePlatform:
ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override {
return surface_factory_ozone_.get();
}
OverlayManagerOzone* GetOverlayManager() override {
return overlay_manager_.get();
}
CursorFactoryOzone* GetCursorFactoryOzone() override {
return cursor_factory_ozone_.get();
}
InputController* GetInputController() override {
return event_factory_ozone_->input_controller();
}
GpuPlatformSupport* GetGpuPlatformSupport() override {
return gpu_platform_support_.get();
}
GpuPlatformSupportHost* GetGpuPlatformSupportHost() override {
return gpu_platform_support_host_.get();
}
scoped_ptr<SystemInputInjector> CreateSystemInputInjector() override {
return nullptr; // no input injection support.
}
scoped_ptr<PlatformWindow> CreatePlatformWindow(
PlatformWindowDelegate* delegate,
const gfx::Rect& bounds) override {
return make_scoped_ptr<PlatformWindow>(new EgltestWindow(
delegate, &eglplatform_shim_, event_factory_ozone_.get(), bounds));
}
scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate() override {
return make_scoped_ptr(new NativeDisplayDelegateOzone());
}
void InitializeUI() override {
device_manager_ = CreateDeviceManager();
overlay_manager_.reset(new StubOverlayManager());
KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
make_scoped_ptr(new StubKeyboardLayoutEngine()));
event_factory_ozone_.reset(new EventFactoryEvdev(
NULL, device_manager_.get(),
KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()));
cursor_factory_ozone_.reset(new CursorFactoryOzone());
gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
}
void InitializeGPU() override {
surface_factory_ozone_.reset(new SurfaceFactoryEgltest(&eglplatform_shim_));
gpu_platform_support_.reset(CreateStubGpuPlatformSupport());
}
private:
LibeglplatformShimLoader eglplatform_shim_;
scoped_ptr<DeviceManager> device_manager_;
scoped_ptr<SurfaceFactoryEgltest> surface_factory_ozone_;
scoped_ptr<EventFactoryEvdev> event_factory_ozone_;
scoped_ptr<CursorFactoryOzone> cursor_factory_ozone_;
scoped_ptr<GpuPlatformSupport> gpu_platform_support_;
scoped_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
scoped_ptr<OverlayManagerOzone> overlay_manager_;
bool shim_initialized_;
DISALLOW_COPY_AND_ASSIGN(OzonePlatformEgltest);
};
} // namespace
OzonePlatform* CreateOzonePlatformEgltest() {
OzonePlatformEgltest* platform = new OzonePlatformEgltest;
platform->Initialize();
return platform;
}
} // namespace ui