Ozone integration from chromium @ https://crrev.com/336230
Adds linux direct rendering capability via mesa gbm.
Refactored gpu_platform_support (and _host) to allow different
implementations of messaging transport between host and gpu.
drm_cursor is stubbed out.
Removed ScopedAllowIO in drm_host_display_manager and added
header documentation indicating where IO is performed.
Removed unused files:
ui/ozone/common/gpu/ozone_gpu_message_generator*
ui/ozone/common/gpu/ozone_gpu_messages.h
BUG=
R=jamesr@chromium.org, spang@chromium.org
Review URL: https://codereview.chromium.org/1285183008 .
diff --git a/device/udev_linux/BUILD.gn b/device/udev_linux/BUILD.gn
new file mode 100644
index 0000000..6a3c831
--- /dev/null
+++ b/device/udev_linux/BUILD.gn
@@ -0,0 +1,26 @@
+# 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.
+
+import("//build/config/features.gni")
+
+if (use_udev) {
+ source_set("udev_linux") {
+ sources = [
+ "scoped_udev.h",
+ "udev.cc",
+ "udev.h",
+ "udev0_loader.cc",
+ "udev0_loader.h",
+ "udev1_loader.cc",
+ "udev1_loader.h",
+ "udev_loader.cc",
+ "udev_loader.h",
+ ]
+
+ deps = [
+ "//base",
+ "//build/config/linux:udev",
+ ]
+ }
+}
diff --git a/device/udev_linux/scoped_udev.h b/device/udev_linux/scoped_udev.h
new file mode 100644
index 0000000..06e3926
--- /dev/null
+++ b/device/udev_linux/scoped_udev.h
@@ -0,0 +1,45 @@
+// 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.
+
+#ifndef DEVICE_UDEV_LINUX_SCOPED_UDEV_H_
+#define DEVICE_UDEV_LINUX_SCOPED_UDEV_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "device/udev_linux/udev.h"
+
+#if !defined(USE_UDEV)
+#error "USE_UDEV not defined"
+#endif
+
+namespace device {
+
+struct UdevDeleter {
+ void operator()(udev* dev) const {
+ udev_unref(dev);
+ }
+};
+struct UdevEnumerateDeleter {
+ void operator()(udev_enumerate* enumerate) const {
+ udev_enumerate_unref(enumerate);
+ }
+};
+struct UdevDeviceDeleter {
+ void operator()(udev_device* device) const {
+ udev_device_unref(device);
+ }
+};
+struct UdevMonitorDeleter {
+ void operator()(udev_monitor* monitor) const {
+ udev_monitor_unref(monitor);
+ }
+};
+
+typedef scoped_ptr<udev, UdevDeleter> ScopedUdevPtr;
+typedef scoped_ptr<udev_enumerate, UdevEnumerateDeleter> ScopedUdevEnumeratePtr;
+typedef scoped_ptr<udev_device, UdevDeviceDeleter> ScopedUdevDevicePtr;
+typedef scoped_ptr<udev_monitor, UdevMonitorDeleter> ScopedUdevMonitorPtr;
+
+} // namespace device
+
+#endif // DEVICE_UDEV_LINUX_SCOPED_UDEV_H_
diff --git a/device/udev_linux/udev.cc b/device/udev_linux/udev.cc
new file mode 100644
index 0000000..e2b93d2
--- /dev/null
+++ b/device/udev_linux/udev.cc
@@ -0,0 +1,183 @@
+// 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 "device/udev_linux/udev.h"
+
+#include "base/strings/string_util.h"
+#include "device/udev_linux/udev_loader.h"
+
+namespace device {
+
+namespace {
+
+std::string StringOrEmptyIfNull(const char* value) {
+ return value ? value : std::string();
+}
+
+} // namespace
+
+const char* udev_device_get_action(udev_device* udev_device) {
+ return UdevLoader::Get()->udev_device_get_action(udev_device);
+}
+
+const char* udev_device_get_devnode(udev_device* udev_device) {
+ return UdevLoader::Get()->udev_device_get_devnode(udev_device);
+}
+
+udev_device* udev_device_get_parent(udev_device* udev_device) {
+ return UdevLoader::Get()->udev_device_get_parent(udev_device);
+}
+
+udev_device* udev_device_get_parent_with_subsystem_devtype(
+ udev_device* udev_device,
+ const char* subsystem,
+ const char* devtype) {
+ return UdevLoader::Get()->udev_device_get_parent_with_subsystem_devtype(
+ udev_device, subsystem, devtype);
+}
+
+const char* udev_device_get_property_value(udev_device* udev_device,
+ const char* key) {
+ return UdevLoader::Get()->udev_device_get_property_value(udev_device, key);
+}
+
+const char* udev_device_get_subsystem(udev_device* udev_device) {
+ return UdevLoader::Get()->udev_device_get_subsystem(udev_device);
+}
+
+const char* udev_device_get_sysattr_value(udev_device* udev_device,
+ const char* sysattr) {
+ return UdevLoader::Get()->udev_device_get_sysattr_value(udev_device, sysattr);
+}
+
+const char* udev_device_get_sysname(udev_device* udev_device) {
+ return UdevLoader::Get()->udev_device_get_sysname(udev_device);
+}
+
+const char* udev_device_get_syspath(udev_device* udev_device) {
+ return UdevLoader::Get()->udev_device_get_syspath(udev_device);
+}
+
+udev_device* udev_device_new_from_devnum(udev* udev, char type, dev_t devnum) {
+ return UdevLoader::Get()->udev_device_new_from_devnum(udev, type, devnum);
+}
+
+udev_device* udev_device_new_from_subsystem_sysname(
+ udev* udev,
+ const char* subsystem,
+ const char* sysname) {
+ return UdevLoader::Get()->udev_device_new_from_subsystem_sysname(
+ udev, subsystem, sysname);
+}
+
+udev_device* udev_device_new_from_syspath(udev* udev, const char* syspath) {
+ return UdevLoader::Get()->udev_device_new_from_syspath(udev, syspath);
+}
+
+void udev_device_unref(udev_device* udev_device) {
+ UdevLoader::Get()->udev_device_unref(udev_device);
+}
+
+int udev_enumerate_add_match_subsystem(udev_enumerate* udev_enumerate,
+ const char* subsystem) {
+ return UdevLoader::Get()->udev_enumerate_add_match_subsystem(udev_enumerate,
+ subsystem);
+}
+
+udev_list_entry* udev_enumerate_get_list_entry(udev_enumerate* udev_enumerate) {
+ return UdevLoader::Get()->udev_enumerate_get_list_entry(udev_enumerate);
+}
+
+udev_enumerate* udev_enumerate_new(udev* udev) {
+ return UdevLoader::Get()->udev_enumerate_new(udev);
+}
+
+int udev_enumerate_scan_devices(udev_enumerate* udev_enumerate) {
+ return UdevLoader::Get()->udev_enumerate_scan_devices(udev_enumerate);
+}
+
+void udev_enumerate_unref(udev_enumerate* udev_enumerate) {
+ UdevLoader::Get()->udev_enumerate_unref(udev_enumerate);
+}
+
+udev_list_entry* udev_list_entry_get_next(udev_list_entry* list_entry) {
+ return UdevLoader::Get()->udev_list_entry_get_next(list_entry);
+}
+
+const char* udev_list_entry_get_name(udev_list_entry* list_entry) {
+ return UdevLoader::Get()->udev_list_entry_get_name(list_entry);
+}
+
+int udev_monitor_enable_receiving(udev_monitor* udev_monitor) {
+ return UdevLoader::Get()->udev_monitor_enable_receiving(udev_monitor);
+}
+
+int udev_monitor_filter_add_match_subsystem_devtype(udev_monitor* udev_monitor,
+ const char* subsystem,
+ const char* devtype) {
+ return UdevLoader::Get()->udev_monitor_filter_add_match_subsystem_devtype(
+ udev_monitor, subsystem, devtype);
+}
+
+int udev_monitor_get_fd(udev_monitor* udev_monitor) {
+ return UdevLoader::Get()->udev_monitor_get_fd(udev_monitor);
+}
+
+udev_monitor* udev_monitor_new_from_netlink(udev* udev, const char* name) {
+ return UdevLoader::Get()->udev_monitor_new_from_netlink(udev, name);
+}
+
+udev_device* udev_monitor_receive_device(udev_monitor* udev_monitor) {
+ return UdevLoader::Get()->udev_monitor_receive_device(udev_monitor);
+}
+
+void udev_monitor_unref(udev_monitor* udev_monitor) {
+ UdevLoader::Get()->udev_monitor_unref(udev_monitor);
+}
+
+udev* udev_new() {
+ return UdevLoader::Get()->udev_new();
+}
+
+void udev_set_log_fn(
+ struct udev* udev,
+ void (*log_fn)(struct udev* udev, int priority, const char* file, int line,
+ const char* fn, const char* format, va_list args)) {
+ return UdevLoader::Get()->udev_set_log_fn(udev, log_fn);
+}
+
+void udev_set_log_priority(struct udev* udev, int priority) {
+ return UdevLoader::Get()->udev_set_log_priority(udev, priority);
+}
+
+void udev_unref(udev* udev) {
+ UdevLoader::Get()->udev_unref(udev);
+}
+
+std::string UdevDeviceGetPropertyValue(udev_device* udev_device,
+ const char* key) {
+ return StringOrEmptyIfNull(udev_device_get_property_value(udev_device, key));
+}
+
+std::string UdevDeviceGetSysattrValue(udev_device* udev_device,
+ const char* key) {
+ return StringOrEmptyIfNull(udev_device_get_sysattr_value(udev_device, key));
+}
+
+std::string UdevDecodeString(const std::string& encoded) {
+ std::string decoded;
+ const size_t size = encoded.size();
+ for (size_t i = 0; i < size; ++i) {
+ char c = encoded[i];
+ if ((i + 3 < size) && c == '\\' && encoded[i + 1] == 'x') {
+ c = (HexDigitToInt(encoded[i + 2]) << 4) +
+ HexDigitToInt(encoded[i + 3]);
+ i += 3;
+ }
+ decoded.push_back(c);
+ }
+ return decoded;
+}
+
+} // namespace device
diff --git a/device/udev_linux/udev.h b/device/udev_linux/udev.h
new file mode 100644
index 0000000..c40603d
--- /dev/null
+++ b/device/udev_linux/udev.h
@@ -0,0 +1,92 @@
+// 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.
+
+#ifndef DEVICE_UDEV_LINUX_UDEV_H_
+#define DEVICE_UDEV_LINUX_UDEV_H_
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <string>
+
+#if !defined(USE_UDEV)
+#error "USE_UDEV not defined"
+#endif
+
+// Adapted from libudev.h.
+#define udev_list_entry_foreach(list_entry, first_entry) \
+ for (list_entry = first_entry; list_entry != NULL; \
+ list_entry = ::device::udev_list_entry_get_next(list_entry))
+
+// Forward declarations of opaque structs.
+struct udev;
+struct udev_device;
+struct udev_enumerate;
+struct udev_list_entry;
+struct udev_monitor;
+
+namespace device {
+
+const char* udev_device_get_action(udev_device* udev_device);
+const char* udev_device_get_devnode(udev_device* udev_device);
+udev_device* udev_device_get_parent(udev_device* udev_device);
+udev_device* udev_device_get_parent_with_subsystem_devtype(
+ udev_device* udev_device,
+ const char* subsystem,
+ const char* devtype);
+const char* udev_device_get_property_value(udev_device* udev_device,
+ const char* key);
+const char* udev_device_get_subsystem(udev_device* udev_device);
+const char* udev_device_get_sysattr_value(udev_device* udev_device,
+ const char* sysattr);
+const char* udev_device_get_sysname(udev_device* udev_device);
+const char* udev_device_get_syspath(udev_device* udev_device);
+udev_device* udev_device_new_from_devnum(udev* udev, char type, dev_t devnum);
+udev_device* udev_device_new_from_subsystem_sysname(
+ udev* udev,
+ const char* subsystem,
+ const char* sysname);
+udev_device* udev_device_new_from_syspath(udev* udev, const char* syspath);
+void udev_device_unref(udev_device* udev_device);
+int udev_enumerate_add_match_subsystem(udev_enumerate* udev_enumerate,
+ const char* subsystem);
+udev_list_entry* udev_enumerate_get_list_entry(udev_enumerate* udev_enumerate);
+udev_enumerate* udev_enumerate_new(udev* udev);
+int udev_enumerate_scan_devices(udev_enumerate* udev_enumerate);
+void udev_enumerate_unref(udev_enumerate* udev_enumerate);
+udev_list_entry* udev_list_entry_get_next(udev_list_entry* list_entry);
+const char* udev_list_entry_get_name(udev_list_entry* list_entry);
+int udev_monitor_enable_receiving(udev_monitor* udev_monitor);
+int udev_monitor_filter_add_match_subsystem_devtype(udev_monitor* udev_monitor,
+ const char* subsystem,
+ const char* devtype);
+int udev_monitor_get_fd(udev_monitor* udev_monitor);
+udev_monitor* udev_monitor_new_from_netlink(udev* udev, const char* name);
+udev_device* udev_monitor_receive_device(udev_monitor* udev_monitor);
+void udev_monitor_unref(udev_monitor* udev_monitor);
+udev* udev_new();
+void udev_set_log_fn(
+ struct udev* udev,
+ void (*log_fn)(struct udev* udev, int priority, const char* file, int line,
+ const char* fn, const char* format, va_list args));
+void udev_set_log_priority(struct udev* udev, int priority);
+void udev_unref(udev* udev);
+
+// Calls udev_device_get_property_value() and replaces missing values with
+// the empty string.
+std::string UdevDeviceGetPropertyValue(udev_device* udev_device,
+ const char* key);
+
+// Calls udev_device_get_sysattr_value() and replaces missing values with
+// the empty string.
+std::string UdevDeviceGetSysattrValue(udev_device* udev_device,
+ const char* key);
+
+// Decodes udev-encoded string. Useful for decoding "*_ENC" udev properties.
+std::string UdevDecodeString(const std::string& encoded);
+
+} // namespace device
+
+#endif // DEVICE_UDEV_LINUX_UDEV_H_
diff --git a/device/udev_linux/udev0_loader.cc b/device/udev_linux/udev0_loader.cc
new file mode 100644
index 0000000..9b0276c
--- /dev/null
+++ b/device/udev_linux/udev0_loader.cc
@@ -0,0 +1,173 @@
+// 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 "device/udev_linux/udev0_loader.h"
+
+#include "library_loaders/libudev0.h"
+
+namespace device {
+
+Udev0Loader::Udev0Loader() {
+}
+
+Udev0Loader::~Udev0Loader() {
+}
+
+bool Udev0Loader::Init() {
+ if (lib_loader_)
+ return lib_loader_->loaded();
+ lib_loader_.reset(new LibUdev0Loader);
+ return lib_loader_->Load("libudev.so.0");
+}
+
+const char* Udev0Loader::udev_device_get_action(udev_device* udev_device) {
+ return lib_loader_->udev_device_get_action(udev_device);
+}
+
+const char* Udev0Loader::udev_device_get_devnode(udev_device* udev_device) {
+ return lib_loader_->udev_device_get_devnode(udev_device);
+}
+
+udev_device* Udev0Loader::udev_device_get_parent(udev_device* udev_device) {
+ return lib_loader_->udev_device_get_parent(udev_device);
+}
+
+udev_device* Udev0Loader::udev_device_get_parent_with_subsystem_devtype(
+ udev_device* udev_device,
+ const char* subsystem,
+ const char* devtype) {
+ return lib_loader_->udev_device_get_parent_with_subsystem_devtype(
+ udev_device, subsystem, devtype);
+}
+
+const char* Udev0Loader::udev_device_get_property_value(
+ udev_device* udev_device,
+ const char* key) {
+ return lib_loader_->udev_device_get_property_value(udev_device, key);
+}
+
+const char* Udev0Loader::udev_device_get_subsystem(udev_device* udev_device) {
+ return lib_loader_->udev_device_get_subsystem(udev_device);
+}
+
+const char* Udev0Loader::udev_device_get_sysattr_value(udev_device* udev_device,
+ const char* sysattr) {
+ return lib_loader_->udev_device_get_sysattr_value(udev_device, sysattr);
+}
+
+const char* Udev0Loader::udev_device_get_sysname(udev_device* udev_device) {
+ return lib_loader_->udev_device_get_sysname(udev_device);
+}
+
+const char* Udev0Loader::udev_device_get_syspath(udev_device* udev_device) {
+ return lib_loader_->udev_device_get_syspath(udev_device);
+}
+
+udev_device* Udev0Loader::udev_device_new_from_devnum(udev* udev,
+ char type,
+ dev_t devnum) {
+ return lib_loader_->udev_device_new_from_devnum(udev, type, devnum);
+}
+
+udev_device* Udev0Loader::udev_device_new_from_subsystem_sysname(
+ udev* udev,
+ const char* subsystem,
+ const char* sysname) {
+ return lib_loader_->udev_device_new_from_subsystem_sysname(
+ udev, subsystem, sysname);
+}
+
+udev_device* Udev0Loader::udev_device_new_from_syspath(udev* udev,
+ const char* syspath) {
+ return lib_loader_->udev_device_new_from_syspath(udev, syspath);
+}
+
+void Udev0Loader::udev_device_unref(udev_device* udev_device) {
+ lib_loader_->udev_device_unref(udev_device);
+}
+
+int Udev0Loader::udev_enumerate_add_match_subsystem(
+ udev_enumerate* udev_enumerate,
+ const char* subsystem) {
+ return lib_loader_->udev_enumerate_add_match_subsystem(udev_enumerate,
+ subsystem);
+}
+
+udev_list_entry* Udev0Loader::udev_enumerate_get_list_entry(
+ udev_enumerate* udev_enumerate) {
+ return lib_loader_->udev_enumerate_get_list_entry(udev_enumerate);
+}
+
+udev_enumerate* Udev0Loader::udev_enumerate_new(udev* udev) {
+ return lib_loader_->udev_enumerate_new(udev);
+}
+
+int Udev0Loader::udev_enumerate_scan_devices(udev_enumerate* udev_enumerate) {
+ return lib_loader_->udev_enumerate_scan_devices(udev_enumerate);
+}
+
+void Udev0Loader::udev_enumerate_unref(udev_enumerate* udev_enumerate) {
+ lib_loader_->udev_enumerate_unref(udev_enumerate);
+}
+
+udev_list_entry* Udev0Loader::udev_list_entry_get_next(
+ udev_list_entry* list_entry) {
+ return lib_loader_->udev_list_entry_get_next(list_entry);
+}
+
+const char* Udev0Loader::udev_list_entry_get_name(udev_list_entry* list_entry) {
+ return lib_loader_->udev_list_entry_get_name(list_entry);
+}
+
+int Udev0Loader::udev_monitor_enable_receiving(udev_monitor* udev_monitor) {
+ return lib_loader_->udev_monitor_enable_receiving(udev_monitor);
+}
+
+int Udev0Loader::udev_monitor_filter_add_match_subsystem_devtype(
+ udev_monitor* udev_monitor,
+ const char* subsystem,
+ const char* devtype) {
+ return lib_loader_->udev_monitor_filter_add_match_subsystem_devtype(
+ udev_monitor, subsystem, devtype);
+}
+
+int Udev0Loader::udev_monitor_get_fd(udev_monitor* udev_monitor) {
+ return lib_loader_->udev_monitor_get_fd(udev_monitor);
+}
+
+udev_monitor* Udev0Loader::udev_monitor_new_from_netlink(udev* udev,
+ const char* name) {
+ return lib_loader_->udev_monitor_new_from_netlink(udev, name);
+}
+
+udev_device* Udev0Loader::udev_monitor_receive_device(
+ udev_monitor* udev_monitor) {
+ return lib_loader_->udev_monitor_receive_device(udev_monitor);
+}
+
+void Udev0Loader::udev_monitor_unref(udev_monitor* udev_monitor) {
+ lib_loader_->udev_monitor_unref(udev_monitor);
+}
+
+udev* Udev0Loader::udev_new() {
+ return lib_loader_->udev_new();
+}
+
+void Udev0Loader::udev_set_log_fn(
+ struct udev* udev,
+ void (*log_fn)(struct udev* udev, int priority,
+ const char* file, int line,
+ const char* fn, const char* format, va_list args)) {
+ return lib_loader_->udev_set_log_fn(udev, log_fn);
+}
+
+void Udev0Loader::udev_set_log_priority(struct udev* udev, int priority) {
+ return lib_loader_->udev_set_log_priority(udev, priority);
+}
+
+void Udev0Loader::udev_unref(udev* udev) {
+ lib_loader_->udev_unref(udev);
+}
+
+} // namespace device
diff --git a/device/udev_linux/udev0_loader.h b/device/udev_linux/udev0_loader.h
new file mode 100644
index 0000000..8108ff9
--- /dev/null
+++ b/device/udev_linux/udev0_loader.h
@@ -0,0 +1,83 @@
+// 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.
+
+#ifndef DEVICE_UDEV_LINUX_UDEV0_LOADER_H_
+#define DEVICE_UDEV_LINUX_UDEV0_LOADER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "device/udev_linux/udev_loader.h"
+
+class LibUdev0Loader;
+
+namespace device {
+
+class Udev0Loader : public UdevLoader {
+ public:
+ Udev0Loader();
+ ~Udev0Loader() override;
+
+ private:
+ bool Init() override;
+ const char* udev_device_get_action(udev_device* udev_device) override;
+ const char* udev_device_get_devnode(udev_device* udev_device) override;
+ udev_device* udev_device_get_parent(udev_device* udev_device) override;
+ udev_device* udev_device_get_parent_with_subsystem_devtype(
+ udev_device* udev_device,
+ const char* subsystem,
+ const char* devtype) override;
+ const char* udev_device_get_property_value(udev_device* udev_device,
+ const char* key) override;
+ const char* udev_device_get_subsystem(udev_device* udev_device) override;
+ const char* udev_device_get_sysattr_value(udev_device* udev_device,
+ const char* sysattr) override;
+ const char* udev_device_get_sysname(udev_device* udev_device) override;
+ const char* udev_device_get_syspath(udev_device* udev_device) override;
+ udev_device* udev_device_new_from_devnum(udev* udev,
+ char type,
+ dev_t devnum) override;
+ udev_device* udev_device_new_from_subsystem_sysname(
+ udev* udev,
+ const char* subsystem,
+ const char* sysname) override;
+ udev_device* udev_device_new_from_syspath(udev* udev,
+ const char* syspath) override;
+ void udev_device_unref(udev_device* udev_device) override;
+ int udev_enumerate_add_match_subsystem(udev_enumerate* udev_enumerate,
+ const char* subsystem) override;
+ udev_list_entry* udev_enumerate_get_list_entry(
+ udev_enumerate* udev_enumerate) override;
+ udev_enumerate* udev_enumerate_new(udev* udev) override;
+ int udev_enumerate_scan_devices(udev_enumerate* udev_enumerate) override;
+ void udev_enumerate_unref(udev_enumerate* udev_enumerate) override;
+ udev_list_entry* udev_list_entry_get_next(
+ udev_list_entry* list_entry) override;
+ const char* udev_list_entry_get_name(udev_list_entry* list_entry) override;
+ int udev_monitor_enable_receiving(udev_monitor* udev_monitor) override;
+ int udev_monitor_filter_add_match_subsystem_devtype(
+ udev_monitor* udev_monitor,
+ const char* subsystem,
+ const char* devtype) override;
+ int udev_monitor_get_fd(udev_monitor* udev_monitor) override;
+ udev_monitor* udev_monitor_new_from_netlink(udev* udev,
+ const char* name) override;
+ udev_device* udev_monitor_receive_device(udev_monitor* udev_monitor) override;
+ void udev_monitor_unref(udev_monitor* udev_monitor) override;
+ udev* udev_new() override;
+ void udev_set_log_fn(
+ struct udev* udev,
+ void (*log_fn)(struct udev* udev, int priority,
+ const char* file, int line,
+ const char* fn, const char* format,
+ va_list args)) override;
+ void udev_set_log_priority(struct udev* udev, int priority) override;
+ void udev_unref(udev* udev) override;
+
+ scoped_ptr<LibUdev0Loader> lib_loader_;
+
+ DISALLOW_COPY_AND_ASSIGN(Udev0Loader);
+};
+
+} // namespace device
+
+#endif // DEVICE_UDEV_LINUX_UDEV0_LOADER_H_
diff --git a/device/udev_linux/udev1_loader.cc b/device/udev_linux/udev1_loader.cc
new file mode 100644
index 0000000..34c2848
--- /dev/null
+++ b/device/udev_linux/udev1_loader.cc
@@ -0,0 +1,173 @@
+// 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 "device/udev_linux/udev1_loader.h"
+
+#include "library_loaders/libudev1.h"
+
+namespace device {
+
+Udev1Loader::Udev1Loader() {
+}
+
+Udev1Loader::~Udev1Loader() {
+}
+
+bool Udev1Loader::Init() {
+ if (lib_loader_)
+ return lib_loader_->loaded();
+ lib_loader_.reset(new LibUdev1Loader);
+ return lib_loader_->Load("libudev.so.1");
+}
+
+const char* Udev1Loader::udev_device_get_action(udev_device* udev_device) {
+ return lib_loader_->udev_device_get_action(udev_device);
+}
+
+const char* Udev1Loader::udev_device_get_devnode(udev_device* udev_device) {
+ return lib_loader_->udev_device_get_devnode(udev_device);
+}
+
+udev_device* Udev1Loader::udev_device_get_parent(udev_device* udev_device) {
+ return lib_loader_->udev_device_get_parent(udev_device);
+}
+
+udev_device* Udev1Loader::udev_device_get_parent_with_subsystem_devtype(
+ udev_device* udev_device,
+ const char* subsystem,
+ const char* devtype) {
+ return lib_loader_->udev_device_get_parent_with_subsystem_devtype(
+ udev_device, subsystem, devtype);
+}
+
+const char* Udev1Loader::udev_device_get_property_value(
+ udev_device* udev_device,
+ const char* key) {
+ return lib_loader_->udev_device_get_property_value(udev_device, key);
+}
+
+const char* Udev1Loader::udev_device_get_subsystem(udev_device* udev_device) {
+ return lib_loader_->udev_device_get_subsystem(udev_device);
+}
+
+const char* Udev1Loader::udev_device_get_sysattr_value(udev_device* udev_device,
+ const char* sysattr) {
+ return lib_loader_->udev_device_get_sysattr_value(udev_device, sysattr);
+}
+
+const char* Udev1Loader::udev_device_get_sysname(udev_device* udev_device) {
+ return lib_loader_->udev_device_get_sysname(udev_device);
+}
+
+const char* Udev1Loader::udev_device_get_syspath(udev_device* udev_device) {
+ return lib_loader_->udev_device_get_syspath(udev_device);
+}
+
+udev_device* Udev1Loader::udev_device_new_from_devnum(udev* udev,
+ char type,
+ dev_t devnum) {
+ return lib_loader_->udev_device_new_from_devnum(udev, type, devnum);
+}
+
+udev_device* Udev1Loader::udev_device_new_from_subsystem_sysname(
+ udev* udev,
+ const char* subsystem,
+ const char* sysname) {
+ return lib_loader_->udev_device_new_from_subsystem_sysname(
+ udev, subsystem, sysname);
+}
+
+udev_device* Udev1Loader::udev_device_new_from_syspath(udev* udev,
+ const char* syspath) {
+ return lib_loader_->udev_device_new_from_syspath(udev, syspath);
+}
+
+void Udev1Loader::udev_device_unref(udev_device* udev_device) {
+ lib_loader_->udev_device_unref(udev_device);
+}
+
+int Udev1Loader::udev_enumerate_add_match_subsystem(
+ udev_enumerate* udev_enumerate,
+ const char* subsystem) {
+ return lib_loader_->udev_enumerate_add_match_subsystem(udev_enumerate,
+ subsystem);
+}
+
+udev_list_entry* Udev1Loader::udev_enumerate_get_list_entry(
+ udev_enumerate* udev_enumerate) {
+ return lib_loader_->udev_enumerate_get_list_entry(udev_enumerate);
+}
+
+udev_enumerate* Udev1Loader::udev_enumerate_new(udev* udev) {
+ return lib_loader_->udev_enumerate_new(udev);
+}
+
+int Udev1Loader::udev_enumerate_scan_devices(udev_enumerate* udev_enumerate) {
+ return lib_loader_->udev_enumerate_scan_devices(udev_enumerate);
+}
+
+void Udev1Loader::udev_enumerate_unref(udev_enumerate* udev_enumerate) {
+ lib_loader_->udev_enumerate_unref(udev_enumerate);
+}
+
+udev_list_entry* Udev1Loader::udev_list_entry_get_next(
+ udev_list_entry* list_entry) {
+ return lib_loader_->udev_list_entry_get_next(list_entry);
+}
+
+const char* Udev1Loader::udev_list_entry_get_name(udev_list_entry* list_entry) {
+ return lib_loader_->udev_list_entry_get_name(list_entry);
+}
+
+int Udev1Loader::udev_monitor_enable_receiving(udev_monitor* udev_monitor) {
+ return lib_loader_->udev_monitor_enable_receiving(udev_monitor);
+}
+
+int Udev1Loader::udev_monitor_filter_add_match_subsystem_devtype(
+ udev_monitor* udev_monitor,
+ const char* subsystem,
+ const char* devtype) {
+ return lib_loader_->udev_monitor_filter_add_match_subsystem_devtype(
+ udev_monitor, subsystem, devtype);
+}
+
+int Udev1Loader::udev_monitor_get_fd(udev_monitor* udev_monitor) {
+ return lib_loader_->udev_monitor_get_fd(udev_monitor);
+}
+
+udev_monitor* Udev1Loader::udev_monitor_new_from_netlink(udev* udev,
+ const char* name) {
+ return lib_loader_->udev_monitor_new_from_netlink(udev, name);
+}
+
+udev_device* Udev1Loader::udev_monitor_receive_device(
+ udev_monitor* udev_monitor) {
+ return lib_loader_->udev_monitor_receive_device(udev_monitor);
+}
+
+void Udev1Loader::udev_monitor_unref(udev_monitor* udev_monitor) {
+ lib_loader_->udev_monitor_unref(udev_monitor);
+}
+
+udev* Udev1Loader::udev_new() {
+ return lib_loader_->udev_new();
+}
+
+void Udev1Loader::udev_set_log_fn(
+ struct udev* udev,
+ void (*log_fn)(struct udev* udev, int priority,
+ const char* file, int line,
+ const char* fn, const char* format, va_list args)) {
+ return lib_loader_->udev_set_log_fn(udev, log_fn);
+}
+
+void Udev1Loader::udev_set_log_priority(struct udev* udev, int priority) {
+ return lib_loader_->udev_set_log_priority(udev, priority);
+}
+
+void Udev1Loader::udev_unref(udev* udev) {
+ lib_loader_->udev_unref(udev);
+}
+
+} // namespace device
diff --git a/device/udev_linux/udev1_loader.h b/device/udev_linux/udev1_loader.h
new file mode 100644
index 0000000..c765671
--- /dev/null
+++ b/device/udev_linux/udev1_loader.h
@@ -0,0 +1,83 @@
+// 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.
+
+#ifndef DEVICE_UDEV_LINUX_UDEV1_LOADER_H_
+#define DEVICE_UDEV_LINUX_UDEV1_LOADER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "device/udev_linux/udev_loader.h"
+
+class LibUdev1Loader;
+
+namespace device {
+
+class Udev1Loader : public UdevLoader {
+ public:
+ Udev1Loader();
+ ~Udev1Loader() override;
+
+ private:
+ bool Init() override;
+ const char* udev_device_get_action(udev_device* udev_device) override;
+ const char* udev_device_get_devnode(udev_device* udev_device) override;
+ udev_device* udev_device_get_parent(udev_device* udev_device) override;
+ udev_device* udev_device_get_parent_with_subsystem_devtype(
+ udev_device* udev_device,
+ const char* subsystem,
+ const char* devtype) override;
+ const char* udev_device_get_property_value(udev_device* udev_device,
+ const char* key) override;
+ const char* udev_device_get_subsystem(udev_device* udev_device) override;
+ const char* udev_device_get_sysattr_value(udev_device* udev_device,
+ const char* sysattr) override;
+ const char* udev_device_get_sysname(udev_device* udev_device) override;
+ const char* udev_device_get_syspath(udev_device* udev_device) override;
+ udev_device* udev_device_new_from_devnum(udev* udev,
+ char type,
+ dev_t devnum) override;
+ udev_device* udev_device_new_from_subsystem_sysname(
+ udev* udev,
+ const char* subsystem,
+ const char* sysname) override;
+ udev_device* udev_device_new_from_syspath(udev* udev,
+ const char* syspath) override;
+ void udev_device_unref(udev_device* udev_device) override;
+ int udev_enumerate_add_match_subsystem(udev_enumerate* udev_enumerate,
+ const char* subsystem) override;
+ udev_list_entry* udev_enumerate_get_list_entry(
+ udev_enumerate* udev_enumerate) override;
+ udev_enumerate* udev_enumerate_new(udev* udev) override;
+ int udev_enumerate_scan_devices(udev_enumerate* udev_enumerate) override;
+ void udev_enumerate_unref(udev_enumerate* udev_enumerate) override;
+ udev_list_entry* udev_list_entry_get_next(
+ udev_list_entry* list_entry) override;
+ const char* udev_list_entry_get_name(udev_list_entry* list_entry) override;
+ int udev_monitor_enable_receiving(udev_monitor* udev_monitor) override;
+ int udev_monitor_filter_add_match_subsystem_devtype(
+ udev_monitor* udev_monitor,
+ const char* subsystem,
+ const char* devtype) override;
+ int udev_monitor_get_fd(udev_monitor* udev_monitor) override;
+ udev_monitor* udev_monitor_new_from_netlink(udev* udev,
+ const char* name) override;
+ udev_device* udev_monitor_receive_device(udev_monitor* udev_monitor) override;
+ void udev_monitor_unref(udev_monitor* udev_monitor) override;
+ udev* udev_new() override;
+ void udev_set_log_fn(
+ struct udev* udev,
+ void (*log_fn)(struct udev* udev, int priority,
+ const char* file, int line,
+ const char* fn, const char* format,
+ va_list args)) override;
+ void udev_set_log_priority(struct udev* udev, int priority) override;
+ void udev_unref(udev* udev) override;
+
+ scoped_ptr<LibUdev1Loader> lib_loader_;
+
+ DISALLOW_COPY_AND_ASSIGN(Udev1Loader);
+};
+
+} // namespace device
+
+#endif // DEVICE_UDEV_LINUX_UDEV1_LOADER_H_
diff --git a/device/udev_linux/udev_loader.cc b/device/udev_linux/udev_loader.cc
new file mode 100644
index 0000000..88b64e1
--- /dev/null
+++ b/device/udev_linux/udev_loader.cc
@@ -0,0 +1,43 @@
+// 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 "device/udev_linux/udev_loader.h"
+
+#include "base/logging.h"
+#include "device/udev_linux/udev0_loader.h"
+#include "device/udev_linux/udev1_loader.h"
+
+namespace device {
+
+namespace {
+
+UdevLoader* g_udev_loader = NULL;
+
+} // namespace
+
+// static
+UdevLoader* UdevLoader::Get() {
+ if (g_udev_loader)
+ return g_udev_loader;
+
+ scoped_ptr<UdevLoader> udev_loader;
+ udev_loader.reset(new Udev1Loader);
+ if (udev_loader->Init()) {
+ g_udev_loader = udev_loader.release();
+ return g_udev_loader;
+ }
+
+ udev_loader.reset(new Udev0Loader);
+ if (udev_loader->Init()) {
+ g_udev_loader = udev_loader.release();
+ return g_udev_loader;
+ }
+ CHECK(false);
+ return NULL;
+}
+
+UdevLoader::~UdevLoader() {
+}
+
+} // namespace device
diff --git a/device/udev_linux/udev_loader.h b/device/udev_linux/udev_loader.h
new file mode 100644
index 0000000..9d3837d
--- /dev/null
+++ b/device/udev_linux/udev_loader.h
@@ -0,0 +1,95 @@
+// 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.
+
+#ifndef DEVICE_UDEV_LINUX_UDEV_LOADER_H_
+#define DEVICE_UDEV_LINUX_UDEV_LOADER_H_
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if !defined(USE_UDEV)
+#error "USE_UDEV not defined"
+#endif
+
+struct udev;
+struct udev_device;
+struct udev_enumerate;
+struct udev_list_entry;
+struct udev_monitor;
+
+namespace device {
+
+// Interface to libudev. Accessed through the static Get() function, which
+// will try to load libudev1 first and then libudev0 on first use. If neither
+// libraries load successfully, the program will fail with a crash.
+//
+// All the methods have the same signatures as libudev's functions. e.g.
+// udev_monitor_get_fd(mon) simply becomes device::udev_monitor_get_fd(mon).
+class UdevLoader {
+ public:
+ static UdevLoader* Get();
+
+ virtual ~UdevLoader();
+
+ virtual bool Init() = 0;
+
+ virtual const char* udev_device_get_action(udev_device* udev_device) = 0;
+ virtual const char* udev_device_get_devnode(udev_device* udev_device) = 0;
+ virtual udev_device* udev_device_get_parent(udev_device* udev_device) = 0;
+ virtual udev_device* udev_device_get_parent_with_subsystem_devtype(
+ udev_device* udev_device,
+ const char* subsystem,
+ const char* devtype) = 0;
+ virtual const char* udev_device_get_property_value(udev_device* udev_device,
+ const char* key) = 0;
+ virtual const char* udev_device_get_subsystem(udev_device* udev_device) = 0;
+ virtual const char* udev_device_get_sysattr_value(udev_device* udev_device,
+ const char* sysattr) = 0;
+ virtual const char* udev_device_get_sysname(udev_device* udev_device) = 0;
+ virtual const char* udev_device_get_syspath(udev_device* udev_device) = 0;
+ virtual udev_device* udev_device_new_from_devnum(udev* udev,
+ char type,
+ dev_t devnum) = 0;
+ virtual udev_device* udev_device_new_from_subsystem_sysname(
+ udev* udev,
+ const char* subsystem,
+ const char* sysname) = 0;
+ virtual udev_device* udev_device_new_from_syspath(udev* udev,
+ const char* syspath) = 0;
+ virtual void udev_device_unref(udev_device* udev_device) = 0;
+ virtual int udev_enumerate_add_match_subsystem(udev_enumerate* udev_enumerate,
+ const char* subsystem) = 0;
+ virtual udev_list_entry* udev_enumerate_get_list_entry(
+ udev_enumerate* udev_enumerate) = 0;
+ virtual udev_enumerate* udev_enumerate_new(udev* udev) = 0;
+ virtual int udev_enumerate_scan_devices(udev_enumerate* udev_enumerate) = 0;
+ virtual void udev_enumerate_unref(udev_enumerate* udev_enumerate) = 0;
+ virtual udev_list_entry* udev_list_entry_get_next(
+ udev_list_entry* list_entry) = 0;
+ virtual const char* udev_list_entry_get_name(udev_list_entry* list_entry) = 0;
+ virtual int udev_monitor_enable_receiving(udev_monitor* udev_monitor) = 0;
+ virtual int udev_monitor_filter_add_match_subsystem_devtype(
+ udev_monitor* udev_monitor,
+ const char* subsystem,
+ const char* devtype) = 0;
+ virtual int udev_monitor_get_fd(udev_monitor* udev_monitor) = 0;
+ virtual udev_monitor* udev_monitor_new_from_netlink(udev* udev,
+ const char* name) = 0;
+ virtual udev_device* udev_monitor_receive_device(
+ udev_monitor* udev_monitor) = 0;
+ virtual void udev_monitor_unref(udev_monitor* udev_monitor) = 0;
+ virtual udev* udev_new() = 0;
+ virtual void udev_set_log_fn(
+ struct udev* udev,
+ void (*log_fn)(struct udev* udev, int priority,
+ const char* file, int line,
+ const char* fn, const char* format, va_list args)) = 0;
+ virtual void udev_set_log_priority(struct udev* udev, int priority) = 0;
+ virtual void udev_unref(udev* udev) = 0;
+};
+
+} // namespace device
+
+#endif // DEVICE_UDEV_LINUX_UDEV_LOADER_H_
diff --git a/device/udev_linux/udev_unittest.cc b/device/udev_linux/udev_unittest.cc
new file mode 100644
index 0000000..244cd8e
--- /dev/null
+++ b/device/udev_linux/udev_unittest.cc
@@ -0,0 +1,21 @@
+// Copyright 2015 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 "device/udev_linux/udev.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+
+TEST(UdevTest, DecodeString) {
+ ASSERT_EQ("", UdevDecodeString(""));
+ ASSERT_EQ("\\", UdevDecodeString("\\x5c"));
+ ASSERT_EQ("\\x5", UdevDecodeString("\\x5"));
+ ASSERT_EQ("049f", UdevDecodeString("049f"));
+ ASSERT_EQ(
+ "HD Pro Webcam C920", UdevDecodeString("HD\\x20Pro\\x20Webcam\\x20C920"));
+ ASSERT_EQ("E-MU Systems,Inc.", UdevDecodeString("E-MU\\x20Systems\\x2cInc."));
+}
+
+} // namespace device
diff --git a/gpu/command_buffer/service/gl_surface_mock.h b/gpu/command_buffer/service/gl_surface_mock.h
index 0652be6..97c8a09 100644
--- a/gpu/command_buffer/service/gl_surface_mock.h
+++ b/gpu/command_buffer/service/gl_surface_mock.h
@@ -5,8 +5,9 @@
#ifndef GPU_COMMAND_BUFFER_SERVICE_GL_SURFACE_MOCK_H_
#define GPU_COMMAND_BUFFER_SERVICE_GL_SURFACE_MOCK_H_
-#include "ui/gl/gl_surface.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/gfx/swap_result.h"
+#include "ui/gl/gl_surface.h"
namespace gpu {
@@ -18,8 +19,8 @@
MOCK_METHOD0(Destroy, void());
MOCK_METHOD1(Resize, bool(const gfx::Size& size));
MOCK_METHOD0(IsOffscreen, bool());
- MOCK_METHOD0(SwapBuffers, bool());
- MOCK_METHOD4(PostSubBuffer, bool(int x, int y, int width, int height));
+ MOCK_METHOD0(SwapBuffers, gfx::SwapResult());
+ MOCK_METHOD4(PostSubBuffer, gfx::SwapResult(int x, int y, int width, int height));
MOCK_METHOD0(SupportsPostSubBuffer, bool());
MOCK_METHOD0(GetSize, gfx::Size());
MOCK_METHOD0(GetHandle, void*());
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index f782d52..61ad037 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -8222,7 +8222,8 @@
gpu_state_tracer_->TakeSnapshotWithCurrentFramebuffer(
is_offscreen ? offscreen_size_ : surface_->GetSize());
}
- if (surface_->PostSubBuffer(c.x, c.y, c.width, c.height)) {
+ if (surface_->PostSubBuffer(c.x, c.y, c.width, c.height) !=
+ gfx::SwapResult::SWAP_FAILED) {
return error::kNoError;
} else {
LOG(ERROR) << "Context lost because PostSubBuffer failed.";
@@ -10347,7 +10348,7 @@
glFlush();
}
} else {
- if (!surface_->SwapBuffers()) {
+ if (surface_->SwapBuffers() == gfx::SwapResult::SWAP_FAILED) {
LOG(ERROR) << "Context lost because SwapBuffers failed.";
if (!CheckResetStatus()) {
MarkContextLost(error::kUnknown);
diff --git a/mojo/BUILD.gn b/mojo/BUILD.gn
index 5556860..bbfa7ea 100644
--- a/mojo/BUILD.gn
+++ b/mojo/BUILD.gn
@@ -50,6 +50,13 @@
"//mojo/nacl:mojo_nacl_tests",
]
}
+
+ if (use_ozone) {
+ deps += [
+ "//ui/ozone",
+ "//ui/ozone/demo",
+ ]
+ }
}
group("tests") {
diff --git a/services/native_viewport/BUILD.gn b/services/native_viewport/BUILD.gn
index e3147d1..b07fc20 100644
--- a/services/native_viewport/BUILD.gn
+++ b/services/native_viewport/BUILD.gn
@@ -119,6 +119,11 @@
sources -= [ "platform_viewport_x11.cc" ]
}
+ if (use_ozone) {
+ sources += [ "platform_viewport_ozone.cc" ]
+ deps += [ "//ui/ozone" ]
+ }
+
if (is_win) {
deps += [ "//ui/platform_window/win" ]
}
diff --git a/services/native_viewport/platform_viewport_ozone.cc b/services/native_viewport/platform_viewport_ozone.cc
new file mode 100644
index 0000000..69cba34
--- /dev/null
+++ b/services/native_viewport/platform_viewport_ozone.cc
@@ -0,0 +1,136 @@
+// 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 "services/native_viewport/platform_viewport.h"
+
+#include "mojo/converters/geometry/geometry_type_converters.h"
+#include "mojo/converters/input_events/input_events_type_converters.h"
+#include "mojo/converters/input_events/mojo_extended_key_event_data.h"
+#include "ui/events/event.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/ozone/public/cursor_factory_ozone.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+#include "ui/platform_window/platform_window.h"
+#include "ui/platform_window/platform_window_delegate.h"
+
+namespace native_viewport {
+namespace {
+
+float ConvertUIWheelValueToMojoValue(int offset) {
+ // Mojo's event type takes a value between -1 and 1. Normalize by allowing
+ // up to 20 of ui's offset. This is a bit arbitrary.
+ return std::max(
+ -1.0f, std::min(1.0f, static_cast<float>(offset) /
+ (20 * static_cast<float>(
+ ui::MouseWheelEvent::kWheelDelta))));
+}
+} // namespace
+
+// TODO(spang): Deduplicate with PlatformViewportX11.. but there's a hack
+// in there that prevents this.
+class PlatformViewportOzone : public PlatformViewport,
+ public ui::PlatformWindowDelegate {
+ public:
+ explicit PlatformViewportOzone(Delegate* delegate) : delegate_(delegate) {
+ ui::OzonePlatform::InitializeForUI();
+ }
+
+ ~PlatformViewportOzone() override {
+ // Destroy the platform-window while |this| is still alive.
+ platform_window_.reset();
+ }
+
+ private:
+ // Overridden from PlatformViewport:
+ void Init(const gfx::Rect& bounds) override {
+ platform_window_ =
+ ui::OzonePlatform::GetInstance()->CreatePlatformWindow(this, bounds);
+
+ metrics_ = mojo::ViewportMetrics::New();
+ metrics_->size = mojo::Size::From(bounds.size());
+ }
+
+ void Show() override { platform_window_->Show(); }
+
+ void Hide() override { platform_window_->Hide(); }
+
+ void Close() override { platform_window_->Close(); }
+
+ gfx::Size GetSize() override {
+ return platform_window_->GetBounds().size();
+ }
+
+ void SetBounds(const gfx::Rect& bounds) override {
+ platform_window_->SetBounds(bounds);
+ }
+
+ // ui::PlatformWindowDelegate:
+ void OnBoundsChanged(const gfx::Rect& new_bounds) override {
+ metrics_->size = mojo::Size::From(new_bounds.size());
+ delegate_->OnMetricsChanged(metrics_.Clone());
+ }
+
+ void OnDamageRect(const gfx::Rect& damaged_region) override {}
+
+ void DispatchEvent(ui::Event* event) override {
+ mojo::EventPtr mojo_event(mojo::Event::From(*event));
+ if (event->IsMouseWheelEvent()) {
+ // Mojo's event type has a different meaning for wheel events. Convert
+ // between the two.
+ ui::MouseWheelEvent* wheel_event =
+ static_cast<ui::MouseWheelEvent*>(event);
+ DCHECK(mojo_event->pointer_data);
+ mojo_event->pointer_data->horizontal_wheel =
+ ConvertUIWheelValueToMojoValue(wheel_event->x_offset());
+ mojo_event->pointer_data->horizontal_wheel =
+ ConvertUIWheelValueToMojoValue(wheel_event->y_offset());
+ }
+ delegate_->OnEvent(mojo_event.Pass());
+
+ switch (event->type()) {
+ case ui::ET_MOUSE_PRESSED:
+ case ui::ET_TOUCH_PRESSED:
+ platform_window_->SetCapture();
+ break;
+ case ui::ET_MOUSE_RELEASED:
+ case ui::ET_TOUCH_RELEASED:
+ platform_window_->ReleaseCapture();
+ break;
+ default:
+ break;
+ }
+ }
+
+ void OnCloseRequest() override { platform_window_->Close(); }
+
+ void OnClosed() override { delegate_->OnDestroyed(); }
+
+ void OnWindowStateChanged(ui::PlatformWindowState state) override {}
+
+ void OnLostCapture() override {}
+
+ void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) override {
+ delegate_->OnAcceleratedWidgetAvailable(widget);
+ }
+
+ void OnActivationChanged(bool active) override {}
+
+ scoped_ptr<ui::PlatformWindow> platform_window_;
+ Delegate* delegate_;
+ mojo::ViewportMetricsPtr metrics_;
+
+ DISALLOW_COPY_AND_ASSIGN(PlatformViewportOzone);
+};
+
+// static
+scoped_ptr<PlatformViewport> PlatformViewport::Create(
+ mojo::ApplicationImpl* application_,
+ Delegate* delegate) {
+ return scoped_ptr<PlatformViewport>(
+ new PlatformViewportOzone(delegate)).Pass();
+}
+
+} // namespace native_viewport
diff --git a/third_party/libudev/LICENSE b/third_party/libudev/LICENSE
new file mode 100644
index 0000000..4362b49
--- /dev/null
+++ b/third_party/libudev/LICENSE
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/third_party/libudev/OWNERS b/third_party/libudev/OWNERS
new file mode 100644
index 0000000..3a04629
--- /dev/null
+++ b/third_party/libudev/OWNERS
@@ -0,0 +1,2 @@
+reillyg@chromium.org
+thestig@chromium.org
diff --git a/third_party/libudev/README.chromium b/third_party/libudev/README.chromium
new file mode 100644
index 0000000..aede7ab
--- /dev/null
+++ b/third_party/libudev/README.chromium
@@ -0,0 +1,8 @@
+Name: libudev
+URL: http://www.freedesktop.org/software/systemd/libudev/
+Version: Varies
+Security Critical: no
+License: LGPL 2.1
+
+Description:
+Just the headers from libudev0 and libudev1.
diff --git a/third_party/libudev/libudev0.h b/third_party/libudev/libudev0.h
new file mode 100644
index 0000000..10e098d
--- /dev/null
+++ b/third_party/libudev/libudev0.h
@@ -0,0 +1,189 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2011 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LIBUDEV_H_
+#define _LIBUDEV_H_
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * udev - library context
+ *
+ * reads the udev config and system environment
+ * allows custom logging
+ */
+struct udev;
+struct udev *udev_ref(struct udev *udev);
+void udev_unref(struct udev *udev);
+struct udev *udev_new(void);
+void udev_set_log_fn(struct udev *udev,
+ void (*log_fn)(struct udev *udev,
+ int priority, const char *file, int line, const char *fn,
+ const char *format, va_list args));
+int udev_get_log_priority(struct udev *udev);
+void udev_set_log_priority(struct udev *udev, int priority);
+const char *udev_get_sys_path(struct udev *udev);
+const char *udev_get_dev_path(struct udev *udev);
+const char *udev_get_run_path(struct udev *udev);
+void *udev_get_userdata(struct udev *udev);
+void udev_set_userdata(struct udev *udev, void *userdata);
+
+/*
+ * udev_list
+ *
+ * access to libudev generated lists
+ */
+struct udev_list_entry;
+struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry);
+struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name);
+const char *udev_list_entry_get_name(struct udev_list_entry *list_entry);
+const char *udev_list_entry_get_value(struct udev_list_entry *list_entry);
+/**
+ * udev_list_entry_foreach:
+ * @list_entry: entry to store the current position
+ * @first_entry: first entry to start with
+ *
+ * Helper to iterate over all entries of a list.
+ */
+#define udev_list_entry_foreach(list_entry, first_entry) \
+ for (list_entry = first_entry; \
+ list_entry != NULL; \
+ list_entry = udev_list_entry_get_next(list_entry))
+
+/*
+ * udev_device
+ *
+ * access to sysfs/kernel devices
+ */
+struct udev_device;
+struct udev_device *udev_device_ref(struct udev_device *udev_device);
+void udev_device_unref(struct udev_device *udev_device);
+struct udev *udev_device_get_udev(struct udev_device *udev_device);
+struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath);
+struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum);
+struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname);
+struct udev_device *udev_device_new_from_environment(struct udev *udev);
+/* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */
+struct udev_device *udev_device_get_parent(struct udev_device *udev_device);
+struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device,
+ const char *subsystem, const char *devtype);
+/* retrieve device properties */
+const char *udev_device_get_devpath(struct udev_device *udev_device);
+const char *udev_device_get_subsystem(struct udev_device *udev_device);
+const char *udev_device_get_devtype(struct udev_device *udev_device);
+const char *udev_device_get_syspath(struct udev_device *udev_device);
+const char *udev_device_get_sysname(struct udev_device *udev_device);
+const char *udev_device_get_sysnum(struct udev_device *udev_device);
+const char *udev_device_get_devnode(struct udev_device *udev_device);
+int udev_device_get_is_initialized(struct udev_device *udev_device);
+struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device);
+struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device);
+struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device);
+struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device);
+const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key);
+const char *udev_device_get_driver(struct udev_device *udev_device);
+dev_t udev_device_get_devnum(struct udev_device *udev_device);
+const char *udev_device_get_action(struct udev_device *udev_device);
+unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device);
+unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device);
+const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr);
+int udev_device_has_tag(struct udev_device *udev_device, const char *tag);
+
+/*
+ * udev_monitor
+ *
+ * access to kernel uevents and udev events
+ */
+struct udev_monitor;
+struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor);
+void udev_monitor_unref(struct udev_monitor *udev_monitor);
+struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor);
+/* kernel and udev generated events over netlink */
+struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name);
+/* custom socket (use netlink and filters instead) */
+struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path);
+/* bind socket */
+int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor);
+int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size);
+int udev_monitor_get_fd(struct udev_monitor *udev_monitor);
+struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor);
+/* in-kernel socket filters to select messages that get delivered to a listener */
+int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
+ const char *subsystem, const char *devtype);
+int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag);
+int udev_monitor_filter_update(struct udev_monitor *udev_monitor);
+int udev_monitor_filter_remove(struct udev_monitor *udev_monitor);
+
+/*
+ * udev_enumerate
+ *
+ * search sysfs for specific devices and provide a sorted list
+ */
+struct udev_enumerate;
+struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate);
+void udev_enumerate_unref(struct udev_enumerate *udev_enumerate);
+struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate);
+struct udev_enumerate *udev_enumerate_new(struct udev *udev);
+/* device properties filter */
+int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
+int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
+int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
+int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
+int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value);
+int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname);
+int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag);
+int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent);
+int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate);
+int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath);
+/* run enumeration with active filters */
+int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate);
+int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate);
+/* return device list */
+struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate);
+
+/*
+ * udev_queue
+ *
+ * access to the currently running udev events
+ */
+struct udev_queue;
+struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue);
+void udev_queue_unref(struct udev_queue *udev_queue);
+struct udev *udev_queue_get_udev(struct udev_queue *udev_queue);
+struct udev_queue *udev_queue_new(struct udev *udev);
+unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue);
+unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue);
+int udev_queue_get_udev_is_active(struct udev_queue *udev_queue);
+int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue);
+int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum);
+int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
+ unsigned long long int start, unsigned long long int end);
+struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue);
+
+/*
+ * udev_util
+ *
+ * udev specific utilities
+ */
+int udev_util_encode_string(const char *str, char *str_enc, size_t len);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/third_party/libudev/libudev1.h b/third_party/libudev/libudev1.h
new file mode 100644
index 0000000..799f470
--- /dev/null
+++ b/third_party/libudev/libudev1.h
@@ -0,0 +1,185 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2011 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LIBUDEV_H_
+#define _LIBUDEV_H_
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * udev - library context
+ *
+ * reads the udev config and system environment
+ * allows custom logging
+ */
+struct udev;
+struct udev *udev_ref(struct udev *udev);
+struct udev *udev_unref(struct udev *udev);
+struct udev *udev_new(void);
+void udev_set_log_fn(struct udev *udev,
+ void (*log_fn)(struct udev *udev,
+ int priority, const char *file, int line, const char *fn,
+ const char *format, va_list args));
+int udev_get_log_priority(struct udev *udev);
+void udev_set_log_priority(struct udev *udev, int priority);
+void *udev_get_userdata(struct udev *udev);
+void udev_set_userdata(struct udev *udev, void *userdata);
+
+/*
+ * udev_list
+ *
+ * access to libudev generated lists
+ */
+struct udev_list_entry;
+struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry);
+struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name);
+const char *udev_list_entry_get_name(struct udev_list_entry *list_entry);
+const char *udev_list_entry_get_value(struct udev_list_entry *list_entry);
+/**
+ * udev_list_entry_foreach:
+ * @list_entry: entry to store the current position
+ * @first_entry: first entry to start with
+ *
+ * Helper to iterate over all entries of a list.
+ */
+#define udev_list_entry_foreach(list_entry, first_entry) \
+ for (list_entry = first_entry; \
+ list_entry != NULL; \
+ list_entry = udev_list_entry_get_next(list_entry))
+
+/*
+ * udev_device
+ *
+ * access to sysfs/kernel devices
+ */
+struct udev_device;
+struct udev_device *udev_device_ref(struct udev_device *udev_device);
+struct udev_device *udev_device_unref(struct udev_device *udev_device);
+struct udev *udev_device_get_udev(struct udev_device *udev_device);
+struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath);
+struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum);
+struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname);
+struct udev_device *udev_device_new_from_device_id(struct udev *udev, char *id);
+struct udev_device *udev_device_new_from_environment(struct udev *udev);
+/* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */
+struct udev_device *udev_device_get_parent(struct udev_device *udev_device);
+struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device,
+ const char *subsystem, const char *devtype);
+/* retrieve device properties */
+const char *udev_device_get_devpath(struct udev_device *udev_device);
+const char *udev_device_get_subsystem(struct udev_device *udev_device);
+const char *udev_device_get_devtype(struct udev_device *udev_device);
+const char *udev_device_get_syspath(struct udev_device *udev_device);
+const char *udev_device_get_sysname(struct udev_device *udev_device);
+const char *udev_device_get_sysnum(struct udev_device *udev_device);
+const char *udev_device_get_devnode(struct udev_device *udev_device);
+int udev_device_get_is_initialized(struct udev_device *udev_device);
+struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device);
+struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device);
+struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device);
+struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device);
+const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key);
+const char *udev_device_get_driver(struct udev_device *udev_device);
+dev_t udev_device_get_devnum(struct udev_device *udev_device);
+const char *udev_device_get_action(struct udev_device *udev_device);
+unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device);
+unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device);
+const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr);
+int udev_device_has_tag(struct udev_device *udev_device, const char *tag);
+
+/*
+ * udev_monitor
+ *
+ * access to kernel uevents and udev events
+ */
+struct udev_monitor;
+struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor);
+struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor);
+struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor);
+/* kernel and udev generated events over netlink */
+struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name);
+/* bind socket */
+int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor);
+int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size);
+int udev_monitor_get_fd(struct udev_monitor *udev_monitor);
+struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor);
+/* in-kernel socket filters to select messages that get delivered to a listener */
+int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
+ const char *subsystem, const char *devtype);
+int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag);
+int udev_monitor_filter_update(struct udev_monitor *udev_monitor);
+int udev_monitor_filter_remove(struct udev_monitor *udev_monitor);
+
+/*
+ * udev_enumerate
+ *
+ * search sysfs for specific devices and provide a sorted list
+ */
+struct udev_enumerate;
+struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate);
+struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate);
+struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate);
+struct udev_enumerate *udev_enumerate_new(struct udev *udev);
+/* device properties filter */
+int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
+int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
+int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
+int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
+int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value);
+int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname);
+int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag);
+int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent);
+int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate);
+int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath);
+/* run enumeration with active filters */
+int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate);
+int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate);
+/* return device list */
+struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate);
+
+/*
+ * udev_queue
+ *
+ * access to the currently running udev events
+ */
+struct udev_queue;
+struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue);
+struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue);
+struct udev *udev_queue_get_udev(struct udev_queue *udev_queue);
+struct udev_queue *udev_queue_new(struct udev *udev);
+unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue);
+unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue);
+int udev_queue_get_udev_is_active(struct udev_queue *udev_queue);
+int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue);
+int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum);
+int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
+ unsigned long long int start, unsigned long long int end);
+struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue);
+
+/*
+ * udev_util
+ *
+ * udev specific utilities
+ */
+int udev_util_encode_string(const char *str, char *str_enc, size_t len);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/ui/display/BUILD.gn b/ui/display/BUILD.gn
deleted file mode 100644
index df0f49d..0000000
--- a/ui/display/BUILD.gn
+++ /dev/null
@@ -1,83 +0,0 @@
-# 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.
-
-import("//build/config/ui.gni")
-
-component("display") {
- sources = [
- "chromeos/display_configurator.cc",
- "chromeos/display_configurator.h",
- "chromeos/x11/display_configurator_x11.cc",
- "chromeos/x11/display_mode_x11.cc",
- "chromeos/x11/display_mode_x11.h",
- "chromeos/x11/display_snapshot_x11.cc",
- "chromeos/x11/display_snapshot_x11.h",
- "chromeos/x11/display_util_x11.cc",
- "chromeos/x11/display_util_x11.h",
- "chromeos/x11/native_display_delegate_x11.cc",
- "chromeos/x11/native_display_delegate_x11.h",
- "chromeos/x11/native_display_event_dispatcher_x11.cc",
- "chromeos/x11/native_display_event_dispatcher_x11.h",
- "display_export.h",
- "display_switches.cc",
- "display_switches.h",
- ]
-
- defines = [ "DISPLAY_IMPLEMENTATION" ]
-
- deps = [
- "//base",
- "//ui/display/util",
- "//ui/gfx",
- "//ui/gfx/geometry",
- ]
-
- if (use_x11) {
- configs += [
- "//build/config/linux:x11",
- "//build/config/linux:xext",
- "//build/config/linux:xi",
- "//build/config/linux:xrandr",
- ]
- deps += [ "//ui/events/platform" ]
- }
-}
-
-component("test_util") {
- output_name = "display_test_util"
- sources = [
- "chromeos/test/test_display_snapshot.cc",
- "chromeos/test/test_display_snapshot.h",
- ]
-
- defines = [ "DISPLAY_IMPLEMENTATION" ]
-
- public_deps = [
- ":display",
- ]
- deps = [
- "//base",
- "//ui/gfx",
- "//ui/gfx/geometry",
- ]
-}
-
-test("display_unittests") {
- sources = [
- "chromeos/display_configurator_unittest.cc",
- "chromeos/x11/display_util_x11_unittest.cc",
- "chromeos/x11/native_display_event_dispatcher_x11_unittest.cc",
- "util/display_util_unittest.cc",
- "util/edid_parser_unittest.cc",
- ]
-
- deps = [
- ":test_util",
- "//base",
- "//base/test:run_all_unittests",
- "//testing/gtest",
- "//ui/display/util",
- "//ui/gfx/geometry",
- ]
-}
diff --git a/ui/display/types/BUILD.gn b/ui/display/types/BUILD.gn
index 4613119..6b5d1e3 100644
--- a/ui/display/types/BUILD.gn
+++ b/ui/display/types/BUILD.gn
@@ -11,6 +11,7 @@
"display_snapshot.cc",
"display_snapshot.h",
"display_types_export.h",
+ "gamma_ramp_rgb_entry.h",
"native_display_delegate.h",
"native_display_observer.h",
]
diff --git a/ui/display/types/display_snapshot.cc b/ui/display/types/display_snapshot.cc
index efe401b..f19961d 100644
--- a/ui/display/types/display_snapshot.cc
+++ b/ui/display/types/display_snapshot.cc
@@ -7,7 +7,6 @@
namespace ui {
DisplaySnapshot::DisplaySnapshot(int64_t display_id,
- bool has_proper_display_id,
const gfx::Point& origin,
const gfx::Size& physical_size,
DisplayConnectionType type,
@@ -18,7 +17,6 @@
const DisplayMode* current_mode,
const DisplayMode* native_mode)
: display_id_(display_id),
- has_proper_display_id_(has_proper_display_id),
origin_(origin),
physical_size_(physical_size),
type_(type),
@@ -27,7 +25,9 @@
display_name_(display_name),
modes_(modes),
current_mode_(current_mode),
- native_mode_(native_mode) {}
+ native_mode_(native_mode),
+ product_id_(kInvalidProductID) {
+}
DisplaySnapshot::~DisplaySnapshot() {}
diff --git a/ui/display/types/display_snapshot.h b/ui/display/types/display_snapshot.h
index 7019208..c59ecde 100644
--- a/ui/display/types/display_snapshot.h
+++ b/ui/display/types/display_snapshot.h
@@ -20,7 +20,6 @@
class DISPLAY_TYPES_EXPORT DisplaySnapshot {
public:
DisplaySnapshot(int64_t display_id,
- bool has_proper_display_id,
const gfx::Point& origin,
const gfx::Size& physical_size,
DisplayConnectionType type,
@@ -42,10 +41,10 @@
std::string display_name() const { return display_name_; }
int64_t display_id() const { return display_id_; }
- bool has_proper_display_id() const { return has_proper_display_id_; }
const DisplayMode* current_mode() const { return current_mode_; }
const DisplayMode* native_mode() const { return native_mode_; }
+ int64_t product_id() const { return product_id_; }
const std::vector<const DisplayMode*>& modes() const { return modes_; }
@@ -56,10 +55,12 @@
// Returns a textual representation of this display state.
virtual std::string ToString() const = 0;
+ // Used when no product id known.
+ static const int64_t kInvalidProductID = -1;
+
protected:
// Display id for this output.
int64_t display_id_;
- bool has_proper_display_id_;
// Display's origin on the framebuffer.
gfx::Point origin_;
@@ -82,6 +83,9 @@
// "Best" mode supported by the output.
const DisplayMode* native_mode_;
+ // Combination of manufacturer and product code.
+ int64_t product_id_;
+
DISALLOW_COPY_AND_ASSIGN(DisplaySnapshot);
};
diff --git a/ui/display/types/gamma_ramp_rgb_entry.h b/ui/display/types/gamma_ramp_rgb_entry.h
new file mode 100644
index 0000000..70405e1
--- /dev/null
+++ b/ui/display/types/gamma_ramp_rgb_entry.h
@@ -0,0 +1,23 @@
+// Copyright 2015 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.
+
+#ifndef UI_DISPLAY_TYPES_GAMMA_RAMP_RGB_ENTRY_H_
+#define UI_DISPLAY_TYPES_GAMMA_RAMP_RGB_ENTRY_H_
+
+#include <stdint.h>
+
+#include "ui/display/types/display_types_export.h"
+
+namespace ui {
+
+// Provides a single entry for a gamma correction table in a GPU.
+struct DISPLAY_TYPES_EXPORT GammaRampRGBEntry {
+ uint16_t r;
+ uint16_t g;
+ uint16_t b;
+};
+
+} // namespace ui
+
+#endif // UI_DISPLAY_TYPES_GAMMA_RAMP_RGB_ENTRY_H_
diff --git a/ui/display/types/native_display_delegate.h b/ui/display/types/native_display_delegate.h
index 28c70e0..bf59dca 100644
--- a/ui/display/types/native_display_delegate.h
+++ b/ui/display/types/native_display_delegate.h
@@ -9,6 +9,7 @@
#include <vector>
+#include "base/callback.h"
#include "ui/display/types/display_constants.h"
#include "ui/display/types/display_types_export.h"
@@ -23,8 +24,21 @@
class NativeDisplayObserver;
+struct GammaRampRGBEntry;
+
+typedef base::Callback<void(const std::vector<ui::DisplaySnapshot*>&)>
+ GetDisplaysCallback;
+typedef base::Callback<void(bool)> ConfigureCallback;
+typedef base::Callback<void(bool, ui::HDCPState)> GetHDCPStateCallback;
+typedef base::Callback<void(bool)> SetHDCPStateCallback;
+typedef base::Callback<void(bool)> DisplayControlCallback;
+
// Interface for classes that perform display configuration actions on behalf
// of DisplayConfigurator.
+// Implementations may perform calls asynchronously. In the case of functions
+// taking callbacks, the callbacks may be called asynchronously when the results
+// are available. The implementations must provide a strong guarantee that the
+// callbacks are always called.
class DISPLAY_TYPES_EXPORT NativeDisplayDelegate {
public:
virtual ~NativeDisplayDelegate() {}
@@ -38,6 +52,13 @@
// Released the display server and any resources allocated by GrabServer().
virtual void UngrabServer() = 0;
+ // Take control of the display from any other controlling process.
+ virtual void TakeDisplayControl(const DisplayControlCallback& callback) = 0;
+
+ // Let others control the display.
+ virtual void RelinquishDisplayControl(
+ const DisplayControlCallback& callback) = 0;
+
// Flushes all pending requests and waits for replies.
virtual void SyncWithServer() = 0;
@@ -47,11 +68,9 @@
// Enables DPMS and forces it to the "on" state.
virtual void ForceDPMSOn() = 0;
- // Returns information about the current outputs. This method may block for
- // 60 milliseconds or more.
- // NativeDisplayDelegate maintains ownership of the ui::DisplaySnapshot
- // pointers.
- virtual std::vector<ui::DisplaySnapshot*> GetDisplays() = 0;
+ // Queries for a list of fresh displays and returns them via |callback|.
+ // Note the query operation may be expensive and take over 60 milliseconds.
+ virtual void GetDisplays(const GetDisplaysCallback& callback) = 0;
// Adds |mode| to |output|. |mode| must be a valid display mode pointer.
virtual void AddMode(const ui::DisplaySnapshot& output,
@@ -59,21 +78,24 @@
// Configures the display represented by |output| to use |mode| and positions
// the display to |origin| in the framebuffer. |mode| can be NULL, which
- // represents disabling the display. Returns true on success.
- virtual bool Configure(const ui::DisplaySnapshot& output,
+ // represents disabling the display. The callback will return the status of
+ // the operation.
+ virtual void Configure(const ui::DisplaySnapshot& output,
const ui::DisplayMode* mode,
- const gfx::Point& origin) = 0;
+ const gfx::Point& origin,
+ const ConfigureCallback& callback) = 0;
// Called to set the frame buffer (underlying XRR "screen") size.
virtual void CreateFrameBuffer(const gfx::Size& size) = 0;
// Gets HDCP state of output.
- virtual bool GetHDCPState(const ui::DisplaySnapshot& output,
- ui::HDCPState* state) = 0;
+ virtual void GetHDCPState(const ui::DisplaySnapshot& output,
+ const GetHDCPStateCallback& callback) = 0;
// Sets HDCP state of output.
- virtual bool SetHDCPState(const ui::DisplaySnapshot& output,
- ui::HDCPState state) = 0;
+ virtual void SetHDCPState(const ui::DisplaySnapshot& output,
+ ui::HDCPState state,
+ const SetHDCPStateCallback& callback) = 0;
// Gets the available list of color calibrations.
virtual std::vector<ui::ColorCalibrationProfile>
@@ -85,6 +107,10 @@
const ui::DisplaySnapshot& output,
ui::ColorCalibrationProfile new_profile) = 0;
+ // Set the gamma ramp for the display.
+ virtual bool SetGammaRamp(const ui::DisplaySnapshot& output,
+ const std::vector<GammaRampRGBEntry>& lut) = 0;
+
virtual void AddObserver(NativeDisplayObserver* observer) = 0;
virtual void RemoveObserver(NativeDisplayObserver* observer) = 0;
diff --git a/ui/display/util/edid_parser.cc b/ui/display/util/edid_parser.cc
index b95eef4..2156c73 100644
--- a/ui/display/util/edid_parser.cc
+++ b/ui/display/util/edid_parser.cc
@@ -9,6 +9,7 @@
#include "base/hash.h"
#include "base/strings/string_util.h"
#include "base/sys_byteorder.h"
+#include "ui/gfx/geometry/size.h"
namespace ui {
@@ -28,26 +29,41 @@
(static_cast<int64_t>(product_code_hash) << 8) | output_index);
}
+// Returns a 32-bit identifier for this model of display, using
+// |manufacturer_id| and |product_code|.
+uint32_t GetProductID(uint16_t manufacturer_id, uint16_t product_code) {
+ return ((static_cast<uint32_t>(manufacturer_id) << 16) |
+ (static_cast<uint32_t>(product_code)));
+}
+
} // namespace
bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid,
uint8_t output_index,
- int64_t* display_id_out) {
+ int64_t* display_id_out,
+ int64_t* product_id_out) {
uint16_t manufacturer_id = 0;
+ uint16_t product_code = 0;
std::string product_name;
// ParseOutputDeviceData fails if it doesn't have product_name.
- ParseOutputDeviceData(edid, &manufacturer_id, &product_name);
+ ParseOutputDeviceData(edid, &manufacturer_id, &product_code, &product_name,
+ nullptr, nullptr);
- // Generates product specific value from product_name instead of product code.
- // See crbug.com/240341
- uint32_t product_code_hash = product_name.empty() ?
- 0 : base::Hash(product_name);
if (manufacturer_id != 0) {
+ // Generates product specific value from product_name instead of product
+ // code.
+ // See crbug.com/240341
+ uint32_t product_code_hash =
+ product_name.empty() ? 0 : base::Hash(product_name);
// An ID based on display's index will be assigned later if this call
// fails.
*display_id_out = GetID(
manufacturer_id, product_code_hash, output_index);
+ // product_id is 64-bit signed so it can store -1 as kInvalidProductID and
+ // not match a valid product id which will all be in the lowest 32-bits.
+ if (product_id_out)
+ *product_id_out = GetProductID(manufacturer_id, product_code);
return true;
}
return false;
@@ -55,14 +71,20 @@
bool ParseOutputDeviceData(const std::vector<uint8_t>& edid,
uint16_t* manufacturer_id,
- std::string* human_readable_name) {
+ uint16_t* product_code,
+ std::string* human_readable_name,
+ gfx::Size* active_pixel_out,
+ gfx::Size* physical_display_size_out) {
// See http://en.wikipedia.org/wiki/Extended_display_identification_data
// for the details of EDID data format. We use the following data:
// bytes 8-9: manufacturer EISA ID, in big-endian
+ // bytes 10-11: manufacturer product code, in little-endian
// bytes 54-125: four descriptors (18-bytes each) which may contain
// the display name.
const unsigned int kManufacturerOffset = 8;
const unsigned int kManufacturerLength = 2;
+ const unsigned int kProductCodeOffset = 10;
+ const unsigned int kProductCodeLength = 2;
const unsigned int kDescriptorOffset = 54;
const unsigned int kNumDescriptors = 4;
const unsigned int kDescriptorLength = 18;
@@ -71,7 +93,7 @@
if (manufacturer_id) {
if (edid.size() < kManufacturerOffset + kManufacturerLength) {
- LOG(ERROR) << "too short EDID data: manifacturer id";
+ LOG(ERROR) << "too short EDID data: manufacturer id";
return false;
}
@@ -82,15 +104,67 @@
#endif
}
- if (!human_readable_name)
- return true;
+ if (product_code) {
+ if (edid.size() < kProductCodeOffset + kProductCodeLength) {
+ LOG(ERROR) << "too short EDID data: manufacturer product code";
+ return false;
+ }
- human_readable_name->clear();
+ *product_code =
+ *reinterpret_cast<const uint16_t*>(&edid[kProductCodeOffset]);
+ }
+
+ if (human_readable_name)
+ human_readable_name->clear();
+
for (unsigned int i = 0; i < kNumDescriptors; ++i) {
if (edid.size() < kDescriptorOffset + (i + 1) * kDescriptorLength)
break;
size_t offset = kDescriptorOffset + i * kDescriptorLength;
+
+ // Detailed Timing Descriptor:
+ if (edid[offset] != 0 && edid[offset + 1] != 0) {
+ const int kMaxResolution = 10080; // 8k display.
+
+ if (active_pixel_out) {
+ const int kHorizontalPixelLsbOffset = 2;
+ const int kHorizontalPixelMsbOffset = 4;
+ const int kVerticalPixelLsbOffset = 5;
+ const int kVerticalPixelMsbOffset = 7;
+
+ int h_lsb = edid[offset + kHorizontalPixelLsbOffset];
+ int h_msb = edid[offset + kHorizontalPixelMsbOffset];
+ int h_pixel = std::min(h_lsb + ((h_msb & 0xF0) << 4), kMaxResolution);
+
+ int v_lsb = edid[offset + kVerticalPixelLsbOffset];
+ int v_msb = edid[offset + kVerticalPixelMsbOffset];
+ int v_pixel = std::min(v_lsb + ((v_msb & 0xF0) << 4), kMaxResolution);
+
+ active_pixel_out->SetSize(h_pixel, v_pixel);
+ // EDID may contain multiple DTD. Use first one that
+ // contains the highest resolution.
+ active_pixel_out = nullptr;
+ }
+
+ if (physical_display_size_out) {
+ const int kHorizontalSizeLsbOffset = 12;
+ const int kVerticalSizeLsbOffset = 13;
+ const int kSizeMsbOffset = 14;
+
+ int h_lsb = edid[offset + kHorizontalSizeLsbOffset];
+ int v_lsb = edid[offset + kVerticalSizeLsbOffset];
+
+ int msb = edid[offset + kSizeMsbOffset];
+ int h_size = h_lsb + ((msb & 0xF0) << 4);
+ int v_size = v_lsb + ((msb & 0x0F) << 8);
+ physical_display_size_out->SetSize(h_size, v_size);
+ physical_display_size_out = nullptr;
+ }
+ continue;
+ }
+
+ // EDID Other Monitor Descriptors:
// If the descriptor contains the display name, it has the following
// structure:
// bytes 0-2, 4: \0
@@ -99,22 +173,26 @@
// we should check bytes 0-2 and 4, since it may have other values in
// case that the descriptor contains other type of data.
if (edid[offset] == 0 && edid[offset + 1] == 0 && edid[offset + 2] == 0 &&
- edid[offset + 3] == kMonitorNameDescriptor && edid[offset + 4] == 0) {
+ edid[offset + 3] == kMonitorNameDescriptor && edid[offset + 4] == 0 &&
+ human_readable_name) {
std::string found_name(reinterpret_cast<const char*>(&edid[offset + 5]),
kDescriptorLength - 5);
base::TrimWhitespaceASCII(
found_name, base::TRIM_TRAILING, human_readable_name);
- break;
+ continue;
}
}
// Verify if the |human_readable_name| consists of printable characters only.
- for (size_t i = 0; i < human_readable_name->size(); ++i) {
- char c = (*human_readable_name)[i];
- if (!isascii(c) || !isprint(c)) {
- human_readable_name->clear();
- LOG(ERROR) << "invalid EDID: human unreadable char in name";
- return false;
+ // TODO(oshima|muka): Consider replacing unprintable chars with white space.
+ if (human_readable_name) {
+ for (size_t i = 0; i < human_readable_name->size(); ++i) {
+ char c = (*human_readable_name)[i];
+ if (!isascii(c) || !isprint(c)) {
+ human_readable_name->clear();
+ LOG(ERROR) << "invalid EDID: human unreadable char in name";
+ return false;
+ }
}
}
diff --git a/ui/display/util/edid_parser.h b/ui/display/util/edid_parser.h
index 4f12d40..385abe9 100644
--- a/ui/display/util/edid_parser.h
+++ b/ui/display/util/edid_parser.h
@@ -12,26 +12,36 @@
#include "ui/display/util/display_util_export.h"
+namespace gfx {
+class Size;
+}
+
// EDID (Extended Display Identification Data) is a format for monitor
// metadata. This provides a parser for the data.
namespace ui {
-// Generates the display id for the pair of |edid| and |index|, and store in
-// |display_id_out|. Returns true if the display id is successfully generated,
-// or false otherwise.
+// Generates the display id and product id for the pair of |edid| and |index|,
+// and store in |display_id_out| and |product_id_out|. Returns true if the
+// display id is successfully generated, or false otherwise.
DISPLAY_UTIL_EXPORT bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid,
uint8_t index,
- int64_t* display_id_out);
+ int64_t* display_id_out,
+ int64_t* product_id_out);
-// Parses |edid| as EDID data and stores extracted data into |manufacturer_id|
-// and |human_readable_name| and returns true. NULL can be passed for unwanted
-// output parameters. Some devices (especially internal displays) may not have
-// the field for |human_readable_name|, and it will return true in that case.
+// Parses |edid| as EDID data and stores extracted data into |manufacturer_id|,
+// |product_code|, |human_readable_name|, |active_pixel_out| and
+// |physical_display_size_out|, then returns true. nullptr can be passed for
+// unwanted output parameters. Some devices (especially internal displays) may
+// not have the field for |human_readable_name|, and it will return true in
+// that case.
DISPLAY_UTIL_EXPORT bool ParseOutputDeviceData(
const std::vector<uint8_t>& edid,
uint16_t* manufacturer_id,
- std::string* human_readable_name);
+ uint16_t* product_code,
+ std::string* human_readable_name,
+ gfx::Size* active_pixel_out,
+ gfx::Size* physical_display_size_out);
DISPLAY_UTIL_EXPORT bool ParseOutputOverscanFlag(
const std::vector<uint8_t>& edid,
diff --git a/ui/display/util/edid_parser_unittest.cc b/ui/display/util/edid_parser_unittest.cc
index ef55bd6..2e77cac 100644
--- a/ui/display/util/edid_parser_unittest.cc
+++ b/ui/display/util/edid_parser_unittest.cc
@@ -6,6 +6,7 @@
#include "base/memory/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/size.h"
namespace ui {
@@ -93,6 +94,11 @@
"\x50\x20\x4C\x50\x32\x34\x36\x35\x0A\x20\x20\x20\x00\x00\x00\xFF"
"\x00\x43\x4E\x4B\x38\x30\x32\x30\x34\x48\x4D\x0A\x20\x20\x00\x45";
+void Reset(gfx::Size* pixel, gfx::Size* size) {
+ pixel->SetSize(0, 0);
+ size->SetSize(0, 0);
+}
+
} // namespace
TEST(EDIDParserTest, ParseOverscanFlag) {
@@ -146,42 +152,64 @@
TEST(EDIDParserTest, ParseEDID) {
uint16_t manufacturer_id = 0;
+ uint16_t product_code = 0;
std::string human_readable_name;
std::vector<uint8_t> edid(
kNormalDisplay, kNormalDisplay + charsize(kNormalDisplay));
- EXPECT_TRUE(ParseOutputDeviceData(
- edid, &manufacturer_id, &human_readable_name));
+ gfx::Size pixel;
+ gfx::Size size;
+ EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, &product_code,
+ &human_readable_name, &pixel, &size));
EXPECT_EQ(0x22f0u, manufacturer_id);
+ EXPECT_EQ(0x286cu, product_code);
EXPECT_EQ("HP ZR30w", human_readable_name);
+ EXPECT_EQ("2560x1600", pixel.ToString());
+ EXPECT_EQ("641x400", size.ToString());
manufacturer_id = 0;
+ product_code = 0;
human_readable_name.clear();
+ Reset(&pixel, &size);
edid.assign(kInternalDisplay, kInternalDisplay + charsize(kInternalDisplay));
- EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, NULL));
+
+ EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, &product_code,
+ nullptr, &pixel, &size));
EXPECT_EQ(0x4ca3u, manufacturer_id);
+ EXPECT_EQ(0x3142u, product_code);
EXPECT_EQ("", human_readable_name);
+ EXPECT_EQ("1280x800", pixel.ToString());
+ EXPECT_EQ("261x163", size.ToString());
// Internal display doesn't have name.
- EXPECT_TRUE(ParseOutputDeviceData(edid, NULL, &human_readable_name));
+ EXPECT_TRUE(ParseOutputDeviceData(edid, nullptr, nullptr,
+ &human_readable_name, &pixel, &size));
EXPECT_TRUE(human_readable_name.empty());
manufacturer_id = 0;
+ product_code = 0;
human_readable_name.clear();
+ Reset(&pixel, &size);
edid.assign(kOverscanDisplay, kOverscanDisplay + charsize(kOverscanDisplay));
- EXPECT_TRUE(ParseOutputDeviceData(
- edid, &manufacturer_id, &human_readable_name));
+ EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, &product_code,
+ &human_readable_name, &pixel, &size));
EXPECT_EQ(0x4c2du, manufacturer_id);
+ EXPECT_EQ(0x08feu, product_code);
EXPECT_EQ("SAMSUNG", human_readable_name);
+ EXPECT_EQ("1920x1080", pixel.ToString());
+ EXPECT_EQ("160x90", size.ToString());
}
TEST(EDIDParserTest, ParseBrokenEDID) {
uint16_t manufacturer_id = 0;
+ uint16_t product_code = 0;
std::string human_readable_name;
std::vector<uint8_t> edid;
+ gfx::Size dummy;
+
// length == 0
- EXPECT_FALSE(ParseOutputDeviceData(
- edid, &manufacturer_id, &human_readable_name));
+ EXPECT_FALSE(ParseOutputDeviceData(edid, &manufacturer_id, &product_code,
+ &human_readable_name, &dummy, &dummy));
// name is broken. Copying kNormalDisplay and substitute its name data by
// some control code.
@@ -190,40 +218,54 @@
// display's name data is embedded in byte 95-107 in this specific example.
// Fix here too when the contents of kNormalDisplay is altered.
edid[97] = '\x1b';
- EXPECT_FALSE(ParseOutputDeviceData(
- edid, &manufacturer_id, &human_readable_name));
+ EXPECT_FALSE(ParseOutputDeviceData(edid, &manufacturer_id, nullptr,
+ &human_readable_name, &dummy, &dummy));
// If |human_readable_name| isn't specified, it skips parsing the name.
manufacturer_id = 0;
- EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, NULL));
+ product_code = 0;
+ EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, &product_code,
+ nullptr, &dummy, &dummy));
EXPECT_EQ(0x22f0u, manufacturer_id);
+ EXPECT_EQ(0x286cu, product_code);
}
TEST(EDIDParserTest, GetDisplayId) {
// EDID of kLP2565A and B are slightly different but actually the same device.
int64_t id1 = -1;
int64_t id2 = -1;
+ int64_t product_id1 = -1;
+ int64_t product_id2 = -1;
std::vector<uint8_t> edid(kLP2565A, kLP2565A + charsize(kLP2565A));
- EXPECT_TRUE(GetDisplayIdFromEDID(edid, 0, &id1));
+ EXPECT_TRUE(GetDisplayIdFromEDID(edid, 0, &id1, &product_id1));
edid.assign(kLP2565B, kLP2565B + charsize(kLP2565B));
- EXPECT_TRUE(GetDisplayIdFromEDID(edid, 0, &id2));
+ EXPECT_TRUE(GetDisplayIdFromEDID(edid, 0, &id2, &product_id2));
EXPECT_EQ(id1, id2);
+ // The product code in the two EDIDs varies.
+ EXPECT_NE(product_id1, product_id2);
+ EXPECT_EQ(0x22f02676, product_id1);
+ EXPECT_EQ(0x22f02675, product_id2);
EXPECT_NE(-1, id1);
+ EXPECT_NE(-1, product_id1);
}
TEST(EDIDParserTest, GetDisplayIdFromInternal) {
int64_t id = -1;
+ int64_t product_id = -1;
std::vector<uint8_t> edid(
kInternalDisplay, kInternalDisplay + charsize(kInternalDisplay));
- EXPECT_TRUE(GetDisplayIdFromEDID(edid, 0, &id));
+ EXPECT_TRUE(GetDisplayIdFromEDID(edid, 0, &id, &product_id));
EXPECT_NE(-1, id);
+ EXPECT_NE(-1, product_id);
}
TEST(EDIDParserTest, GetDisplayIdFailure) {
int64_t id = -1;
+ int64_t product_id = -1;
std::vector<uint8_t> edid;
- EXPECT_FALSE(GetDisplayIdFromEDID(edid, 0, &id));
+ EXPECT_FALSE(GetDisplayIdFromEDID(edid, 0, &id, &product_id));
EXPECT_EQ(-1, id);
+ EXPECT_EQ(-1, product_id);
}
} // namespace ui
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index 536fd64..19513ef 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -4,6 +4,7 @@
import("//build/config/ui.gni")
import("//testing/test.gni")
+import("//ui/events/xkb.gni")
static_library("dom_keycode_converter") {
sources = [
@@ -71,7 +72,7 @@
deps += [ "//ui/gfx/x" ]
}
- if (use_x11 || use_ozone) {
+ if (use_x11 || use_xkbcommon) {
sources += [
"keycodes/keyboard_code_conversion_xkb.cc",
"keycodes/keyboard_code_conversion_xkb.h",
@@ -293,6 +294,7 @@
"//ui/events/devices",
"//ui/events/platform",
"//ui/gfx:test_support",
+ "//testing/gmock:gmock",
]
include_dirs = [ "//testing/gmock/include" ]
@@ -318,8 +320,10 @@
"ozone/evdev/tablet_event_converter_evdev_unittest.cc",
"ozone/evdev/touch_event_converter_evdev_unittest.cc",
"ozone/evdev/touch_noise/touch_noise_finder_unittest.cc",
- "ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc",
]
+ if (use_x11 || use_xkbcommon) {
+ sources += [ "ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc" ]
+ }
deps += [
"//ui/events/ozone:events_ozone",
"//ui/events/ozone:events_ozone_evdev",
diff --git a/ui/events/event.cc b/ui/events/event.cc
index 953220d..84b58bc 100644
--- a/ui/events/event.cc
+++ b/ui/events/event.cc
@@ -30,8 +30,8 @@
#if defined(USE_X11)
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
#elif defined(USE_OZONE)
-#include "ui/events/ozone/layout/keyboard_layout_engine.h"
-#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
+#include "ui/events/ozone/layout/keyboard_layout_engine.h" // nogncheck
+#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" // nogncheck
#endif
namespace {
diff --git a/ui/events/ozone/BUILD.gn b/ui/events/ozone/BUILD.gn
index 4ddc579..7ee8ce4 100644
--- a/ui/events/ozone/BUILD.gn
+++ b/ui/events/ozone/BUILD.gn
@@ -5,11 +5,7 @@
import("//build/config/features.gni")
import("//build/config/linux/pkg_config.gni")
import("//build/config/ui.gni")
-
-declare_args() {
- # Optional system libraries.
- use_xkbcommon = false
-}
+import("//ui/events/xkb.gni")
if (use_xkbcommon) {
pkg_config("xkbcommon") {
@@ -122,6 +118,7 @@
"//ui/events/devices",
"//ui/events/platform",
"//ui/gfx",
+ "//ui/ozone:ozone_base",
]
public_configs = [ ":evdev" ]
@@ -153,6 +150,7 @@
"//base",
"//ui/events:dom_keycode_converter",
"//ui/events:events_base",
+ "//ui/ozone:ozone_base",
]
public_configs = [ ":events_ozone_layout_config" ]
diff --git a/ui/events/ozone/device/udev/device_manager_udev.cc b/ui/events/ozone/device/udev/device_manager_udev.cc
index ca7daa2..4e28e39 100644
--- a/ui/events/ozone/device/udev/device_manager_udev.cc
+++ b/ui/events/ozone/device/udev/device_manager_udev.cc
@@ -162,10 +162,10 @@
DeviceEvent::DeviceType device_type;
if (!strcmp(subsystem, "input") &&
- base::StartsWithASCII(path, "/dev/input/event", true))
+ StartsWithASCII(path, "/dev/input/event", true))
device_type = DeviceEvent::INPUT;
else if (!strcmp(subsystem, "drm") &&
- base::StartsWithASCII(path, "/dev/dri/card", true))
+ StartsWithASCII(path, "/dev/dri/card", true))
device_type = DeviceEvent::DISPLAY;
else
return nullptr;
diff --git a/ui/events/ozone/evdev/event_factory_evdev.cc b/ui/events/ozone/evdev/event_factory_evdev.cc
index 9d79b14..5350c0c 100644
--- a/ui/events/ozone/evdev/event_factory_evdev.cc
+++ b/ui/events/ozone/evdev/event_factory_evdev.cc
@@ -12,6 +12,7 @@
#include "base/trace_event/trace_event.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/events/devices/input_device.h"
+#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/ozone/device/device_event.h"
#include "ui/events/ozone/device/device_manager.h"
diff --git a/ui/events/ozone/evdev/input_injector_evdev_unittest.cc b/ui/events/ozone/evdev/input_injector_evdev_unittest.cc
index 88040c2..e57b5a9 100644
--- a/ui/events/ozone/evdev/input_injector_evdev_unittest.cc
+++ b/ui/events/ozone/evdev/input_injector_evdev_unittest.cc
@@ -8,6 +8,7 @@
#include "base/run_loop.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event.h"
#include "ui/events/ozone/device/device_manager.h"
#include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
#include "ui/events/ozone/evdev/event_converter_test_util.h"
diff --git a/ui/events/ozone/layout/stub/stub_keyboard_layout_engine.cc b/ui/events/ozone/layout/stub/stub_keyboard_layout_engine.cc
index 83310a7..deeb36d 100644
--- a/ui/events/ozone/layout/stub/stub_keyboard_layout_engine.cc
+++ b/ui/events/ozone/layout/stub/stub_keyboard_layout_engine.cc
@@ -7,7 +7,6 @@
#include <algorithm>
#include "base/strings/string16.h"
-#include "ui/events/event.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
diff --git a/ui/events/xkb.gni b/ui/events/xkb.gni
new file mode 100644
index 0000000..1bd10d4
--- /dev/null
+++ b/ui/events/xkb.gni
@@ -0,0 +1,8 @@
+# Copyright 2015 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.
+
+declare_args() {
+ # Optional system libraries.
+ use_xkbcommon = false
+}
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index b66f0ec..521042f 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -76,6 +76,7 @@
"shadow_value.h",
"skia_util.cc",
"skia_util.h",
+ "swap_result.h",
"transform.cc",
"transform.h",
"transform_util.cc",
diff --git a/ui/gfx/gpu_memory_buffer.cc b/ui/gfx/gpu_memory_buffer.cc
index be23d51..da80107 100644
--- a/ui/gfx/gpu_memory_buffer.cc
+++ b/ui/gfx/gpu_memory_buffer.cc
@@ -8,10 +8,11 @@
GpuMemoryBufferHandle::GpuMemoryBufferHandle()
: type(EMPTY_BUFFER),
+ id(0),
handle(base::SharedMemory::NULLHandle())
-#if defined(USE_X11)
+#if defined(OS_MACOSX)
,
- pixmap(0)
+ io_surface_id(0)
#endif
{
}
diff --git a/ui/gfx/gpu_memory_buffer.h b/ui/gfx/gpu_memory_buffer.h
index 51731d9..829865e 100644
--- a/ui/gfx/gpu_memory_buffer.h
+++ b/ui/gfx/gpu_memory_buffer.h
@@ -9,10 +9,6 @@
#include "build/build_config.h"
#include "ui/gfx/gfx_export.h"
-#if defined(USE_X11)
-#include "ui/gfx/x/x11_types.h"
-#endif
-
extern "C" typedef struct _ClientBuffer* ClientBuffer;
namespace gfx {
@@ -22,27 +18,20 @@
SHARED_MEMORY_BUFFER,
IO_SURFACE_BUFFER,
SURFACE_TEXTURE_BUFFER,
- X11_PIXMAP_BUFFER,
OZONE_NATIVE_BUFFER,
GPU_MEMORY_BUFFER_TYPE_LAST = OZONE_NATIVE_BUFFER
};
-struct GpuMemoryBufferId {
- GpuMemoryBufferId() : primary_id(0), secondary_id(0) {}
- GpuMemoryBufferId(int32 primary_id, int32 secondary_id)
- : primary_id(primary_id), secondary_id(secondary_id) {}
- int32 primary_id;
- int32 secondary_id;
-};
+using GpuMemoryBufferId = int32;
struct GFX_EXPORT GpuMemoryBufferHandle {
GpuMemoryBufferHandle();
bool is_null() const { return type == EMPTY_BUFFER; }
GpuMemoryBufferType type;
+ GpuMemoryBufferId id;
base::SharedMemoryHandle handle;
- GpuMemoryBufferId global_id;
-#if defined(USE_X11)
- XID pixmap;
+#if defined(OS_MACOSX)
+ uint32 io_surface_id;
#endif
};
@@ -67,7 +56,10 @@
// The usage mode affects how a buffer can be used. Only buffers created with
// MAP can be mapped into the client's address space and accessed by the CPU.
- enum Usage { MAP, SCANOUT, USAGE_LAST = SCANOUT };
+ // PERSISTENT_MAP adds the additional condition that successive Map() calls
+ // (with Unmap() calls between) will return a pointer to the same memory
+ // contents.
+ enum Usage { MAP, PERSISTENT_MAP, SCANOUT, USAGE_LAST = SCANOUT };
virtual ~GpuMemoryBuffer() {}
diff --git a/ui/gfx/swap_result.h b/ui/gfx/swap_result.h
new file mode 100644
index 0000000..32a6c5a
--- /dev/null
+++ b/ui/gfx/swap_result.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2012 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.
+
+#ifndef UI_GFX_SWAP_RESULT_H_
+#define UI_GFX_SWAP_RESULT_H_
+
+namespace gfx {
+
+enum class SwapResult {
+ SWAP_ACK,
+ SWAP_FAILED,
+ SWAP_NAK_RECREATE_BUFFERS,
+ SWAP_RESULT_LAST = SWAP_NAK_RECREATE_BUFFERS,
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_SWAP_RESULT_H_
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index a5ed5cc..e190b4d 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -181,8 +181,8 @@
sources += [
"gl_egl_api_implementation.cc",
"gl_egl_api_implementation.h",
- "gl_image_surface_texture.cc",
- "gl_image_surface_texture.h",
+ "gl_image_linux_dma_buffer.cc",
+ "gl_image_linux_dma_buffer.h",
]
defines += [
@@ -195,6 +195,12 @@
deps += [ ":gl_jni_headers" ]
}
if (use_ozone) {
+ if (is_android) {
+ sources -= [
+ "gl_implementation_android.cc",
+ "gl_surface_android.cc",
+ ]
+ }
sources += [
"gl_context_ozone.cc",
"gl_egl_api_implementation.cc",
diff --git a/ui/gl/gl_image_memory.cc b/ui/gl/gl_image_memory.cc
index 13e9d71..d5d54a3 100644
--- a/ui/gl/gl_image_memory.cc
+++ b/ui/gl/gl_image_memory.cc
@@ -7,9 +7,13 @@
#include "base/logging.h"
#include "base/trace_event/trace_event.h"
#include "ui/gl/gl_bindings.h"
-#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/scoped_binders.h"
+#if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
+ defined(USE_OZONE)
+#include "ui/gl/gl_surface_egl.h"
+#endif
+
namespace gfx {
namespace {
diff --git a/ui/gl/gl_image_surface_texture.cc b/ui/gl/gl_image_surface_texture.cc
deleted file mode 100644
index a321c4d..0000000
--- a/ui/gl/gl_image_surface_texture.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// 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/gl/gl_image_surface_texture.h"
-
-#include "base/trace_event/trace_event.h"
-#include "ui/gl/android/surface_texture.h"
-
-namespace gfx {
-
-GLImageSurfaceTexture::GLImageSurfaceTexture(const gfx::Size& size)
- : size_(size), texture_id_(0) {
-}
-
-GLImageSurfaceTexture::~GLImageSurfaceTexture() {
- DCHECK(!surface_texture_.get());
- DCHECK_EQ(0, texture_id_);
-}
-
-bool GLImageSurfaceTexture::Initialize(SurfaceTexture* surface_texture) {
- DCHECK(!surface_texture_.get());
- surface_texture_ = surface_texture;
- return true;
-}
-
-void GLImageSurfaceTexture::Destroy(bool have_context) {
- surface_texture_ = NULL;
- texture_id_ = 0;
-}
-
-gfx::Size GLImageSurfaceTexture::GetSize() { return size_; }
-
-bool GLImageSurfaceTexture::BindTexImage(unsigned target) {
- TRACE_EVENT0("gpu", "GLImageSurfaceTexture::BindTexImage");
-
- if (target != GL_TEXTURE_EXTERNAL_OES) {
- LOG(ERROR)
- << "Surface texture can only be bound to TEXTURE_EXTERNAL_OES target";
- return false;
- }
-
- GLint texture_id;
- glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_id);
- DCHECK(texture_id);
-
- if (texture_id_ && texture_id_ != texture_id) {
- LOG(ERROR) << "Surface texture can only be bound to one texture ID";
- return false;
- }
-
- DCHECK(surface_texture_.get());
- if (texture_id != texture_id_) {
- // Note: Surface textures used as gpu memory buffers are created with an
- // initial dummy texture id of 0. We need to call DetachFromGLContext() here
- // to detach from the dummy texture before we can attach to a real texture
- // id. DetachFromGLContext() will delete the texture for the current
- // attachment point so it's important that this is never called when
- // attached to a real texture id. Detaching from the dummy texture id should
- // not cause any problems as the GL should silently ignore 0 when passed to
- // glDeleteTextures.
- DCHECK_EQ(0, texture_id_);
- surface_texture_->DetachFromGLContext();
-
- // This will attach the surface texture to the texture currently bound to
- // GL_TEXTURE_EXTERNAL_OES target.
- surface_texture_->AttachToGLContext();
- texture_id_ = texture_id;
- }
-
- surface_texture_->UpdateTexImage();
- return true;
-}
-
-bool GLImageSurfaceTexture::CopyTexImage(unsigned target) {
- return false;
-}
-
-bool GLImageSurfaceTexture::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
- int z_order,
- OverlayTransform transform,
- const Rect& bounds_rect,
- const RectF& crop_rect) {
- return false;
-}
-
-} // namespace gfx
diff --git a/ui/gl/gl_image_surface_texture.h b/ui/gl/gl_image_surface_texture.h
deleted file mode 100644
index d2ff5b7..0000000
--- a/ui/gl/gl_image_surface_texture.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-
-#ifndef UI_GL_GL_IMAGE_SURFACE_TEXTURE_H_
-#define UI_GL_GL_IMAGE_SURFACE_TEXTURE_H_
-
-#include "base/memory/ref_counted.h"
-#include "ui/gl/gl_bindings.h"
-#include "ui/gl/gl_image.h"
-
-namespace gfx {
-class SurfaceTexture;
-
-class GL_EXPORT GLImageSurfaceTexture : public GLImage {
- public:
- explicit GLImageSurfaceTexture(const gfx::Size& size);
-
- bool Initialize(SurfaceTexture* surface_texture);
-
- // Overridden from GLImage:
- void Destroy(bool have_context) override;
- gfx::Size GetSize() override;
- bool BindTexImage(unsigned target) override;
- void ReleaseTexImage(unsigned target) override {}
- bool CopyTexImage(unsigned target) override;
- void WillUseTexImage() override {}
- void DidUseTexImage() override {}
- void WillModifyTexImage() override {}
- void DidModifyTexImage() override {}
- bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
- int z_order,
- OverlayTransform transform,
- const Rect& bounds_rect,
- const RectF& crop_rect) override;
-
- protected:
- ~GLImageSurfaceTexture() override;
-
- private:
- scoped_refptr<SurfaceTexture> surface_texture_;
- const gfx::Size size_;
- GLint texture_id_;
-
- DISALLOW_COPY_AND_ASSIGN(GLImageSurfaceTexture);
-};
-
-} // namespace gfx
-
-#endif // UI_GL_GL_IMAGE_SURFACE_TEXTURE_H_
diff --git a/ui/gl/gl_implementation_ozone.cc b/ui/gl/gl_implementation_ozone.cc
index 2a85720..715084f 100644
--- a/ui/gl/gl_implementation_ozone.cc
+++ b/ui/gl/gl_implementation_ozone.cc
@@ -44,9 +44,10 @@
case kGLImplementationOSMesaGL:
return InitializeStaticGLBindingsOSMesaGL();
case kGLImplementationEGLGLES2:
- if (!ui::SurfaceFactoryOzone::GetInstance()->LoadEGLGLES2Bindings(
- base::Bind(&AddGLNativeLibrary),
- base::Bind(&SetGLGetProcAddressProc)))
+ if (!ui::OzonePlatform::GetInstance()
+ ->GetSurfaceFactoryOzone()
+ ->LoadEGLGLES2Bindings(base::Bind(&AddGLNativeLibrary),
+ base::Bind(&SetGLGetProcAddressProc)))
return false;
SetGLImplementation(kGLImplementationEGLGLES2);
InitializeStaticGLBindingsGL();
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc
index 007bcaf..e5ac99d 100644
--- a/ui/gl/gl_surface.cc
+++ b/ui/gl/gl_surface.cc
@@ -197,13 +197,13 @@
bool GLSurface::SwapBuffersAsync(const SwapCompletionCallback& callback) {
DCHECK(!IsSurfaceless());
- bool success = SwapBuffers();
- callback.Run();
- return success;
+ gfx::SwapResult result = SwapBuffers();
+ callback.Run(result);
+ return result == gfx::SwapResult::SWAP_ACK;
}
-bool GLSurface::PostSubBuffer(int x, int y, int width, int height) {
- return false;
+gfx::SwapResult GLSurface::PostSubBuffer(int x, int y, int width, int height) {
+ return gfx::SwapResult::SWAP_FAILED;
}
bool GLSurface::PostSubBufferAsync(int x,
@@ -211,9 +211,9 @@
int width,
int height,
const SwapCompletionCallback& callback) {
- bool success = PostSubBuffer(x, y, width, height);
- callback.Run();
- return success;
+ gfx::SwapResult result = PostSubBuffer(x, y, width, height);
+ callback.Run(result);
+ return result == gfx::SwapResult::SWAP_ACK;
}
bool GLSurface::OnMakeCurrent(GLContext* context) {
@@ -324,7 +324,7 @@
return surface_->IsOffscreen();
}
-bool GLSurfaceAdapter::SwapBuffers() {
+gfx::SwapResult GLSurfaceAdapter::SwapBuffers() {
return surface_->SwapBuffers();
}
@@ -333,7 +333,8 @@
return surface_->SwapBuffersAsync(callback);
}
-bool GLSurfaceAdapter::PostSubBuffer(int x, int y, int width, int height) {
+gfx::SwapResult GLSurfaceAdapter::PostSubBuffer(
+ int x, int y, int width, int height) {
return surface_->PostSubBuffer(x, y, width, height);
}
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h
index 73c085d..f6bba1b 100644
--- a/ui/gl/gl_surface.h
+++ b/ui/gl/gl_surface.h
@@ -15,6 +15,7 @@
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/overlay_transform.h"
+#include "ui/gfx/swap_result.h"
#include "ui/gl/gl_export.h"
#include "ui/gl/gl_implementation.h"
@@ -67,7 +68,7 @@
// Swaps front and back buffers. This has no effect for off-screen
// contexts.
- virtual bool SwapBuffers() = 0;
+ virtual gfx::SwapResult SwapBuffers() = 0;
// Get the size of the surface.
virtual gfx::Size GetSize() = 0;
@@ -82,7 +83,7 @@
// FBO. Otherwise returns 0.
virtual unsigned int GetBackingFrameBufferObject();
- typedef base::Callback<void()> SwapCompletionCallback;
+ typedef base::Callback<void(gfx::SwapResult)> SwapCompletionCallback;
// Swaps front and back buffers. This has no effect for off-screen
// contexts. On some platforms, we want to send SwapBufferAck only after the
// surface is displayed on screen. The callback can be used to delay sending
@@ -91,7 +92,7 @@
virtual bool SwapBuffersAsync(const SwapCompletionCallback& callback);
// Copy part of the backbuffer to the frontbuffer.
- virtual bool PostSubBuffer(int x, int y, int width, int height);
+ virtual gfx::SwapResult PostSubBuffer(int x, int y, int width, int height);
// Copy part of the backbuffer to the frontbuffer. On some platforms, we want
// to send SwapBufferAck only after the surface is displayed on screen. The
@@ -222,9 +223,9 @@
bool Recreate() override;
bool DeferDraws() override;
bool IsOffscreen() override;
- bool SwapBuffers() override;
+ gfx::SwapResult SwapBuffers() override;
bool SwapBuffersAsync(const SwapCompletionCallback& callback) override;
- bool PostSubBuffer(int x, int y, int width, int height) override;
+ gfx::SwapResult PostSubBuffer(int x, int y, int width, int height) override;
bool PostSubBufferAsync(int x,
int y,
int width,
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc
index 9e67979..23e1851 100644
--- a/ui/gl/gl_surface_egl.cc
+++ b/ui/gl/gl_surface_egl.cc
@@ -30,7 +30,8 @@
#endif
#if defined (USE_OZONE)
-#include "ui/ozone/public/surface_factory_ozone.h"
+#include "ui/ozone/public/ozone_platform.h" // nogncheck
+#include "ui/ozone/public/surface_factory_ozone.h" // nogncheck
#endif
#if !defined(EGL_FIXED_SIZE_ANGLE)
@@ -142,7 +143,7 @@
switches::kEnableUnsafeES3APIs)) {
renderable_type = EGL_OPENGL_ES3_BIT;
}
- EGLint config_attribs[] = {
+ EGLint kConfigAttribs[] = {
EGL_BUFFER_SIZE, configuration.alpha_bits +
configuration.red_bits +
configuration.green_bits +
@@ -161,16 +162,19 @@
};
#if defined(USE_OZONE)
- config_attribs =
- ui::SurfaceFactoryOzone::GetInstance()->GetEGLSurfaceProperties(
- config_attribs);
+ const EGLint* config_attribs = ui::OzonePlatform::GetInstance()
+ ->GetSurfaceFactoryOzone()
+ ->GetEGLSurfaceProperties(kConfigAttribs);
#elif defined(USE_X11)
+ EGLint* config_attribs = kConfigAttribs;
// Try matching the window depth with an alpha channel,
// because we're worried the destination alpha width could
// constrain blending precision.
const int kBufferSizeOffset = 1;
const int kAlphaSizeOffset = 3;
config_attribs[kBufferSizeOffset] = win_attribs.depth;
+#else
+ const EGLint* config_attribs = kConfigAttribs;
#endif
EGLint num_configs;
@@ -446,7 +450,7 @@
return false;
}
-bool NativeViewGLSurfaceEGL::SwapBuffers() {
+gfx::SwapResult NativeViewGLSurfaceEGL::SwapBuffers() {
TRACE_EVENT2("gpu", "NativeViewGLSurfaceEGL:RealSwapBuffers",
"width", GetSize().width(),
"height", GetSize().height());
@@ -454,10 +458,10 @@
if (!eglSwapBuffers(GetDisplay(), surface_)) {
DVLOG(1) << "eglSwapBuffers failed with error "
<< GetLastEGLErrorString();
- return false;
+ return gfx::SwapResult::SWAP_FAILED;
}
- return true;
+ return gfx::SwapResult::SWAP_ACK;
}
gfx::Size NativeViewGLSurfaceEGL::GetSize() {
@@ -516,15 +520,15 @@
return supports_post_sub_buffer_;
}
-bool NativeViewGLSurfaceEGL::PostSubBuffer(
+gfx::SwapResult NativeViewGLSurfaceEGL::PostSubBuffer(
int x, int y, int width, int height) {
DCHECK(supports_post_sub_buffer_);
if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) {
DVLOG(1) << "eglPostSubBufferNV failed with error "
<< GetLastEGLErrorString();
- return false;
+ return gfx::SwapResult::SWAP_FAILED;
}
- return true;
+ return gfx::SwapResult::SWAP_ACK;
}
VSyncProvider* NativeViewGLSurfaceEGL::GetVSyncProvider() {
@@ -614,9 +618,9 @@
return true;
}
-bool PbufferGLSurfaceEGL::SwapBuffers() {
+gfx::SwapResult PbufferGLSurfaceEGL::SwapBuffers() {
NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL.";
- return false;
+ return gfx::SwapResult::SWAP_FAILED;
}
gfx::Size PbufferGLSurfaceEGL::GetSize() {
@@ -702,9 +706,9 @@
return true;
}
-bool SurfacelessEGL::SwapBuffers() {
+gfx::SwapResult SurfacelessEGL::SwapBuffers() {
LOG(ERROR) << "Attempted to call SwapBuffers with SurfacelessEGL.";
- return false;
+ return gfx::SwapResult::SWAP_FAILED;
}
gfx::Size SurfacelessEGL::GetSize() {
diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h
index 9bf2a2d..a18e6e0 100644
--- a/ui/gl/gl_surface_egl.h
+++ b/ui/gl/gl_surface_egl.h
@@ -62,11 +62,11 @@
bool Resize(const gfx::Size& size) override;
bool Recreate() override;
bool IsOffscreen() override;
- bool SwapBuffers() override;
+ gfx::SwapResult SwapBuffers() override;
gfx::Size GetSize() override;
EGLSurface GetHandle() override;
bool SupportsPostSubBuffer() override;
- bool PostSubBuffer(int x, int y, int width, int height) override;
+ gfx::SwapResult PostSubBuffer(int x, int y, int width, int height) override;
VSyncProvider* GetVSyncProvider() override;
// Create a NativeViewGLSurfaceEGL with an externally provided VSyncProvider.
@@ -104,7 +104,7 @@
bool Initialize() override;
void Destroy() override;
bool IsOffscreen() override;
- bool SwapBuffers() override;
+ gfx::SwapResult SwapBuffers() override;
gfx::Size GetSize() override;
bool Resize(const gfx::Size& size) override;
EGLSurface GetHandle() override;
@@ -135,7 +135,7 @@
void Destroy() override;
bool IsOffscreen() override;
bool IsSurfaceless() const override;
- bool SwapBuffers() override;
+ gfx::SwapResult SwapBuffers() override;
gfx::Size GetSize() override;
bool Resize(const gfx::Size& size) override;
EGLSurface GetHandle() override;
diff --git a/ui/gl/gl_surface_glx.cc b/ui/gl/gl_surface_glx.cc
index 2a52fc7..2740138 100644
--- a/ui/gl/gl_surface_glx.cc
+++ b/ui/gl/gl_surface_glx.cc
@@ -501,13 +501,13 @@
return false;
}
-bool NativeViewGLSurfaceGLX::SwapBuffers() {
+gfx::SwapResult NativeViewGLSurfaceGLX::SwapBuffers() {
TRACE_EVENT2("gpu", "NativeViewGLSurfaceGLX:RealSwapBuffers",
"width", GetSize().width(),
"height", GetSize().height());
glXSwapBuffers(g_display, GetDrawableHandle());
- return true;
+ return gfx::SwapResult::SWAP_ACK;
}
gfx::Size NativeViewGLSurfaceGLX::GetSize() {
@@ -586,11 +586,11 @@
return config_;
}
-bool NativeViewGLSurfaceGLX::PostSubBuffer(
+gfx::SwapResult NativeViewGLSurfaceGLX::PostSubBuffer(
int x, int y, int width, int height) {
DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer);
glXCopySubBufferMESA(g_display, GetDrawableHandle(), x, y, width, height);
- return true;
+ return gfx::SwapResult::SWAP_ACK;
}
VSyncProvider* NativeViewGLSurfaceGLX::GetVSyncProvider() {
@@ -673,9 +673,9 @@
return true;
}
-bool PbufferGLSurfaceGLX::SwapBuffers() {
+gfx::SwapResult PbufferGLSurfaceGLX::SwapBuffers() {
NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
- return false;
+ return gfx::SwapResult::SWAP_FAILED;
}
gfx::Size PbufferGLSurfaceGLX::GetSize() {
diff --git a/ui/gl/gl_surface_glx.h b/ui/gl/gl_surface_glx.h
index d8fa9a4..aa09418 100644
--- a/ui/gl/gl_surface_glx.h
+++ b/ui/gl/gl_surface_glx.h
@@ -62,12 +62,12 @@
void Destroy() override;
bool Resize(const gfx::Size& size) override;
bool IsOffscreen() override;
- bool SwapBuffers() override;
+ gfx::SwapResult SwapBuffers() override;
gfx::Size GetSize() override;
void* GetHandle() override;
bool SupportsPostSubBuffer() override;
void* GetConfig() override;
- bool PostSubBuffer(int x, int y, int width, int height) override;
+ gfx::SwapResult PostSubBuffer(int x, int y, int width, int height) override;
VSyncProvider* GetVSyncProvider() override;
protected:
@@ -106,7 +106,7 @@
bool Initialize() override;
void Destroy() override;
bool IsOffscreen() override;
- bool SwapBuffers() override;
+ gfx::SwapResult SwapBuffers() override;
gfx::Size GetSize() override;
void* GetHandle() override;
void* GetConfig() override;
diff --git a/ui/gl/gl_surface_osmesa.cc b/ui/gl/gl_surface_osmesa.cc
index 2efe12b..b695224 100644
--- a/ui/gl/gl_surface_osmesa.cc
+++ b/ui/gl/gl_surface_osmesa.cc
@@ -94,9 +94,9 @@
return true;
}
-bool GLSurfaceOSMesa::SwapBuffers() {
+gfx::SwapResult GLSurfaceOSMesa::SwapBuffers() {
NOTREACHED() << "Should not call SwapBuffers on an GLSurfaceOSMesa.";
- return false;
+ return gfx::SwapResult::SWAP_FAILED;
}
gfx::Size GLSurfaceOSMesa::GetSize() {
@@ -117,7 +117,9 @@
bool GLSurfaceOSMesaHeadless::IsOffscreen() { return false; }
-bool GLSurfaceOSMesaHeadless::SwapBuffers() { return true; }
+gfx::SwapResult GLSurfaceOSMesaHeadless::SwapBuffers() {
+ return gfx::SwapResult::SWAP_ACK;
+}
GLSurfaceOSMesaHeadless::GLSurfaceOSMesaHeadless(
const gfx::SurfaceConfiguration requested_configuration)
diff --git a/ui/gl/gl_surface_osmesa.h b/ui/gl/gl_surface_osmesa.h
index 7484063..b812d96 100644
--- a/ui/gl/gl_surface_osmesa.h
+++ b/ui/gl/gl_surface_osmesa.h
@@ -27,7 +27,7 @@
void Destroy() override;
bool Resize(const gfx::Size& new_size) override;
bool IsOffscreen() override;
- bool SwapBuffers() override;
+ gfx::SwapResult SwapBuffers() override;
gfx::Size GetSize() override;
void* GetHandle() override;
unsigned GetFormat() override;
@@ -53,7 +53,7 @@
const gfx::SurfaceConfiguration requested_configuration);
bool IsOffscreen() override;
- bool SwapBuffers() override;
+ SwapResult SwapBuffers() override;
void* GetConfig() override;
protected:
diff --git a/ui/gl/gl_surface_ozone.cc b/ui/gl/gl_surface_ozone.cc
index 800be17..c513e5f 100644
--- a/ui/gl/gl_surface_ozone.cc
+++ b/ui/gl/gl_surface_ozone.cc
@@ -9,6 +9,7 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/worker_pool.h"
#include "ui/gfx/native_widget_types.h"
@@ -22,6 +23,7 @@
#include "ui/gl/scoped_binders.h"
#include "ui/gl/scoped_make_current.h"
#include "ui/ozone/public/native_pixmap.h"
+#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/surface_factory_ozone.h"
#include "ui/ozone/public/surface_ozone_egl.h"
@@ -38,72 +40,25 @@
class GL_EXPORT GLSurfaceOzoneEGL : public NativeViewGLSurfaceEGL {
public:
GLSurfaceOzoneEGL(scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
- AcceleratedWidget widget)
- : NativeViewGLSurfaceEGL(ozone_surface->GetNativeWindow()),
- ozone_surface_(ozone_surface.Pass()),
- widget_(widget) {}
+ AcceleratedWidget widget,
+ const gfx::SurfaceConfiguration& requested_configuration);
- bool Initialize() override {
- return Initialize(ozone_surface_->CreateVSyncProvider());
- }
- bool Resize(const gfx::Size& size) override {
- if (!ozone_surface_->ResizeNativeWindow(size)) {
- if (!ReinitializeNativeSurface() ||
- !ozone_surface_->ResizeNativeWindow(size))
- return false;
- }
-
- return NativeViewGLSurfaceEGL::Resize(size);
- }
- bool SwapBuffers() override {
- if (!NativeViewGLSurfaceEGL::SwapBuffers())
- return false;
-
- return ozone_surface_->OnSwapBuffers();
- }
+ // GLSurface:
+ bool Initialize() override;
+ bool Resize(const gfx::Size& size) override;
+ gfx::SwapResult SwapBuffers() override;
bool ScheduleOverlayPlane(int z_order,
OverlayTransform transform,
GLImage* image,
const Rect& bounds_rect,
- const RectF& crop_rect) override {
- return image->ScheduleOverlayPlane(
- widget_, z_order, transform, bounds_rect, crop_rect);
- }
+ const RectF& crop_rect) override;
private:
using NativeViewGLSurfaceEGL::Initialize;
- ~GLSurfaceOzoneEGL() override {
- Destroy(); // EGL surface must be destroyed before SurfaceOzone
- }
+ ~GLSurfaceOzoneEGL() override;
- bool ReinitializeNativeSurface() {
- scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
- GLContext* current_context = GLContext::GetCurrent();
- bool was_current =
- current_context && current_context->IsCurrent(this);
- if (was_current) {
- scoped_make_current.reset(
- new ui::ScopedMakeCurrent(current_context, this));
- }
-
- Destroy();
- ozone_surface_ =
- ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
- widget_).Pass();
- if (!ozone_surface_) {
- LOG(ERROR) << "Failed to create native surface.";
- return false;
- }
-
- window_ = ozone_surface_->GetNativeWindow();
- if (!Initialize()) {
- LOG(ERROR) << "Failed to initialize.";
- return false;
- }
-
- return true;
- }
+ bool ReinitializeNativeSurface();
// The native surface. Deleting this is allowed to free the EGLNativeWindow.
scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface_;
@@ -112,133 +67,354 @@
DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneEGL);
};
+GLSurfaceOzoneEGL::GLSurfaceOzoneEGL(
+ scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
+ AcceleratedWidget widget,
+ const gfx::SurfaceConfiguration& requested_configuration)
+ : NativeViewGLSurfaceEGL(ozone_surface->GetNativeWindow(),
+ requested_configuration),
+ ozone_surface_(ozone_surface.Pass()),
+ widget_(widget) {
+}
+
+bool GLSurfaceOzoneEGL::Initialize() {
+ return Initialize(ozone_surface_->CreateVSyncProvider());
+}
+
+bool GLSurfaceOzoneEGL::Resize(const gfx::Size& size) {
+ if (!ozone_surface_->ResizeNativeWindow(size)) {
+ if (!ReinitializeNativeSurface() ||
+ !ozone_surface_->ResizeNativeWindow(size))
+ return false;
+ }
+
+ return NativeViewGLSurfaceEGL::Resize(size);
+}
+
+gfx::SwapResult GLSurfaceOzoneEGL::SwapBuffers() {
+ gfx::SwapResult result = NativeViewGLSurfaceEGL::SwapBuffers();
+ if (result != gfx::SwapResult::SWAP_ACK)
+ return result;
+
+ return ozone_surface_->OnSwapBuffers() ? gfx::SwapResult::SWAP_ACK
+ : gfx::SwapResult::SWAP_FAILED;
+}
+
+bool GLSurfaceOzoneEGL::ScheduleOverlayPlane(int z_order,
+ OverlayTransform transform,
+ GLImage* image,
+ const Rect& bounds_rect,
+ const RectF& crop_rect) {
+ return image->ScheduleOverlayPlane(widget_, z_order, transform, bounds_rect,
+ crop_rect);
+}
+
+GLSurfaceOzoneEGL::~GLSurfaceOzoneEGL() {
+ Destroy(); // EGL surface must be destroyed before SurfaceOzone
+}
+
+bool GLSurfaceOzoneEGL::ReinitializeNativeSurface() {
+ scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
+ GLContext* current_context = GLContext::GetCurrent();
+ bool was_current = current_context && current_context->IsCurrent(this);
+ if (was_current) {
+ scoped_make_current.reset(new ui::ScopedMakeCurrent(current_context, this));
+ }
+
+ Destroy();
+ ozone_surface_ = ui::OzonePlatform::GetInstance()
+ ->GetSurfaceFactoryOzone()
+ ->CreateEGLSurfaceForWidget(widget_)
+ .Pass();
+ if (!ozone_surface_) {
+ LOG(ERROR) << "Failed to create native surface.";
+ return false;
+ }
+
+ window_ = ozone_surface_->GetNativeWindow();
+ if (!Initialize()) {
+ LOG(ERROR) << "Failed to initialize.";
+ return false;
+ }
+
+ return true;
+}
+
class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL {
public:
- GLSurfaceOzoneSurfaceless(scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
- AcceleratedWidget widget)
- : SurfacelessEGL(gfx::Size()),
- ozone_surface_(ozone_surface.Pass()),
- widget_(widget),
- has_implicit_external_sync_(
- HasEGLExtension("EGL_ARM_implicit_external_sync")),
- last_swap_buffers_result_(true),
- weak_factory_(this) {}
+ GLSurfaceOzoneSurfaceless(
+ scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
+ AcceleratedWidget widget,
+ const gfx::SurfaceConfiguration& requested_configuration);
- bool Initialize() override {
- if (!SurfacelessEGL::Initialize())
- return false;
- vsync_provider_ = ozone_surface_->CreateVSyncProvider();
- if (!vsync_provider_)
- return false;
- return true;
- }
- bool Resize(const gfx::Size& size) override {
- if (!ozone_surface_->ResizeNativeWindow(size))
- return false;
-
- return SurfacelessEGL::Resize(size);
- }
- bool SwapBuffers() override {
- glFlush();
- // TODO: the following should be replaced by a per surface flush as it gets
- // implemented in GL drivers.
- if (has_implicit_external_sync_) {
- EGLSyncKHR fence = InsertFence();
- if (!fence)
- return false;
-
- EGLDisplay display = GetDisplay();
- WaitForFence(display, fence);
- eglDestroySyncKHR(display, fence);
- } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) {
- glFinish();
- }
-
- return ozone_surface_->OnSwapBuffers();
- }
+ // GLSurface:
+ bool Initialize() override;
+ bool Resize(const gfx::Size& size) override;
+ gfx::SwapResult SwapBuffers() override;
bool ScheduleOverlayPlane(int z_order,
OverlayTransform transform,
GLImage* image,
const Rect& bounds_rect,
- const RectF& crop_rect) override {
- return image->ScheduleOverlayPlane(
- widget_, z_order, transform, bounds_rect, crop_rect);
- }
- bool IsOffscreen() override { return false; }
- VSyncProvider* GetVSyncProvider() override { return vsync_provider_.get(); }
- bool SupportsPostSubBuffer() override { return true; }
- bool PostSubBuffer(int x, int y, int width, int height) override {
- // The actual sub buffer handling is handled at higher layers.
- SwapBuffers();
- return true;
- }
- bool SwapBuffersAsync(const SwapCompletionCallback& callback) override {
- glFlush();
- // TODO: the following should be replaced by a per surface flush as it gets
- // implemented in GL drivers.
- if (has_implicit_external_sync_) {
- // If last swap failed, don't try to schedule new ones.
- if (!last_swap_buffers_result_) {
- last_swap_buffers_result_ = true;
- return false;
- }
-
- EGLSyncKHR fence = InsertFence();
- if (!fence)
- return false;
-
- base::Closure fence_wait_task =
- base::Bind(&WaitForFence, GetDisplay(), fence);
-
- base::Closure fence_retired_callback =
- base::Bind(&GLSurfaceOzoneSurfaceless::FenceRetired,
- weak_factory_.GetWeakPtr(), fence, callback);
-
- base::WorkerPool::PostTaskAndReply(FROM_HERE, fence_wait_task,
- fence_retired_callback, false);
- return true;
- } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) {
- glFinish();
- }
- return ozone_surface_->OnSwapBuffersAsync(callback);
- }
+ const RectF& crop_rect) override;
+ bool IsOffscreen() override;
+ VSyncProvider* GetVSyncProvider() override;
+ bool SupportsPostSubBuffer() override;
+ gfx::SwapResult PostSubBuffer(int x, int y, int width, int height) override;
+ bool SwapBuffersAsync(const SwapCompletionCallback& callback) override;
bool PostSubBufferAsync(int x,
int y,
int width,
int height,
- const SwapCompletionCallback& callback) override {
- return SwapBuffersAsync(callback);
- }
+ const SwapCompletionCallback& callback) override;
protected:
- ~GLSurfaceOzoneSurfaceless() override {
- Destroy(); // EGL surface must be destroyed before SurfaceOzone
- }
+ struct Overlay {
+ Overlay(int z_order,
+ OverlayTransform transform,
+ GLImage* image,
+ const Rect& bounds_rect,
+ const RectF& crop_rect);
- EGLSyncKHR InsertFence() {
- const EGLint attrib_list[] = {EGL_SYNC_CONDITION_KHR,
- EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM,
- EGL_NONE};
- return eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR, attrib_list);
- }
+ bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget) const;
- void FenceRetired(EGLSyncKHR fence, const SwapCompletionCallback& callback) {
- eglDestroySyncKHR(GetDisplay(), fence);
- last_swap_buffers_result_ = ozone_surface_->OnSwapBuffersAsync(callback);
- }
+ int z_order;
+ OverlayTransform transform;
+ scoped_refptr<GLImage> image;
+ Rect bounds_rect;
+ RectF crop_rect;
+ };
+
+ struct PendingFrame {
+ PendingFrame();
+
+ bool ScheduleOverlayPlanes(gfx::AcceleratedWidget widget);
+
+ bool ready;
+ std::vector<Overlay> overlays;
+ SwapCompletionCallback callback;
+ };
+
+ ~GLSurfaceOzoneSurfaceless() override;
+
+ void SubmitFrame();
+
+ EGLSyncKHR InsertFence();
+ void FenceRetired(EGLSyncKHR fence, PendingFrame* frame);
+
+ void SwapCompleted(const SwapCompletionCallback& callback,
+ gfx::SwapResult result);
// The native surface. Deleting this is allowed to free the EGLNativeWindow.
scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface_;
AcceleratedWidget widget_;
scoped_ptr<VSyncProvider> vsync_provider_;
+ ScopedVector<PendingFrame> unsubmitted_frames_;
bool has_implicit_external_sync_;
bool last_swap_buffers_result_;
+ bool swap_buffers_pending_;
base::WeakPtrFactory<GLSurfaceOzoneSurfaceless> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfaceless);
};
+GLSurfaceOzoneSurfaceless::Overlay::Overlay(int z_order,
+ OverlayTransform transform,
+ GLImage* image,
+ const Rect& bounds_rect,
+ const RectF& crop_rect)
+ : z_order(z_order),
+ transform(transform),
+ image(image),
+ bounds_rect(bounds_rect),
+ crop_rect(crop_rect) {
+}
+
+bool GLSurfaceOzoneSurfaceless::Overlay::ScheduleOverlayPlane(
+ gfx::AcceleratedWidget widget) const {
+ return image->ScheduleOverlayPlane(widget, z_order, transform, bounds_rect,
+ crop_rect);
+}
+
+GLSurfaceOzoneSurfaceless::PendingFrame::PendingFrame() : ready(false) {
+}
+
+bool GLSurfaceOzoneSurfaceless::PendingFrame::ScheduleOverlayPlanes(
+ gfx::AcceleratedWidget widget) {
+ for (const auto& overlay : overlays)
+ if (!overlay.ScheduleOverlayPlane(widget))
+ return false;
+ return true;
+}
+
+GLSurfaceOzoneSurfaceless::GLSurfaceOzoneSurfaceless(
+ scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
+ AcceleratedWidget widget,
+ const gfx::SurfaceConfiguration& requested_configuration)
+ : SurfacelessEGL(gfx::Size(), requested_configuration),
+ ozone_surface_(ozone_surface.Pass()),
+ widget_(widget),
+ has_implicit_external_sync_(
+ HasEGLExtension("EGL_ARM_implicit_external_sync")),
+ last_swap_buffers_result_(true),
+ swap_buffers_pending_(false),
+ weak_factory_(this) {
+ unsubmitted_frames_.push_back(new PendingFrame());
+}
+
+bool GLSurfaceOzoneSurfaceless::Initialize() {
+ if (!SurfacelessEGL::Initialize())
+ return false;
+ vsync_provider_ = ozone_surface_->CreateVSyncProvider();
+ if (!vsync_provider_)
+ return false;
+ return true;
+}
+bool GLSurfaceOzoneSurfaceless::Resize(const gfx::Size& size) {
+ if (!ozone_surface_->ResizeNativeWindow(size))
+ return false;
+
+ return SurfacelessEGL::Resize(size);
+}
+gfx::SwapResult GLSurfaceOzoneSurfaceless::SwapBuffers() {
+ glFlush();
+ // TODO: the following should be replaced by a per surface flush as it gets
+ // implemented in GL drivers.
+ if (has_implicit_external_sync_) {
+ EGLSyncKHR fence = InsertFence();
+ if (!fence)
+ return SwapResult::SWAP_FAILED;
+
+ EGLDisplay display = GetDisplay();
+ WaitForFence(display, fence);
+ eglDestroySyncKHR(display, fence);
+ } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) {
+ glFinish();
+ }
+
+ unsubmitted_frames_.back()->ScheduleOverlayPlanes(widget_);
+ unsubmitted_frames_.back()->overlays.clear();
+
+ return ozone_surface_->OnSwapBuffers() ? gfx::SwapResult::SWAP_ACK
+ : gfx::SwapResult::SWAP_FAILED;
+}
+bool GLSurfaceOzoneSurfaceless::ScheduleOverlayPlane(int z_order,
+ OverlayTransform transform,
+ GLImage* image,
+ const Rect& bounds_rect,
+ const RectF& crop_rect) {
+ unsubmitted_frames_.back()->overlays.push_back(
+ Overlay(z_order, transform, image, bounds_rect, crop_rect));
+ return true;
+}
+bool GLSurfaceOzoneSurfaceless::IsOffscreen() {
+ return false;
+}
+VSyncProvider* GLSurfaceOzoneSurfaceless::GetVSyncProvider() {
+ return vsync_provider_.get();
+}
+bool GLSurfaceOzoneSurfaceless::SupportsPostSubBuffer() {
+ return true;
+}
+gfx::SwapResult GLSurfaceOzoneSurfaceless::PostSubBuffer(int x,
+ int y,
+ int width,
+ int height) {
+ // The actual sub buffer handling is handled at higher layers.
+ SwapBuffers();
+ return gfx::SwapResult::SWAP_ACK;
+}
+bool GLSurfaceOzoneSurfaceless::SwapBuffersAsync(
+ const SwapCompletionCallback& callback) {
+ // If last swap failed, don't try to schedule new ones.
+ if (!last_swap_buffers_result_)
+ return false;
+
+ glFlush();
+
+ SwapCompletionCallback surface_swap_callback =
+ base::Bind(&GLSurfaceOzoneSurfaceless::SwapCompleted,
+ weak_factory_.GetWeakPtr(), callback);
+
+ PendingFrame* frame = unsubmitted_frames_.back();
+ frame->callback = surface_swap_callback;
+ unsubmitted_frames_.push_back(new PendingFrame());
+
+ // TODO: the following should be replaced by a per surface flush as it gets
+ // implemented in GL drivers.
+ if (has_implicit_external_sync_) {
+ EGLSyncKHR fence = InsertFence();
+ if (!fence)
+ return false;
+
+ base::Closure fence_wait_task =
+ base::Bind(&WaitForFence, GetDisplay(), fence);
+
+ base::Closure fence_retired_callback =
+ base::Bind(&GLSurfaceOzoneSurfaceless::FenceRetired,
+ weak_factory_.GetWeakPtr(), fence, frame);
+
+ base::WorkerPool::PostTaskAndReply(FROM_HERE, fence_wait_task,
+ fence_retired_callback, false);
+ return true;
+ } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) {
+ glFinish();
+ }
+
+ frame->ready = true;
+ SubmitFrame();
+ return last_swap_buffers_result_;
+}
+bool GLSurfaceOzoneSurfaceless::PostSubBufferAsync(
+ int x,
+ int y,
+ int width,
+ int height,
+ const SwapCompletionCallback& callback) {
+ return SwapBuffersAsync(callback);
+}
+
+GLSurfaceOzoneSurfaceless::~GLSurfaceOzoneSurfaceless() {
+ Destroy(); // EGL surface must be destroyed before SurfaceOzone
+}
+
+void GLSurfaceOzoneSurfaceless::SubmitFrame() {
+ DCHECK(!unsubmitted_frames_.empty());
+
+ if (unsubmitted_frames_.front()->ready && !swap_buffers_pending_) {
+ scoped_ptr<PendingFrame> frame(unsubmitted_frames_.front());
+ unsubmitted_frames_.weak_erase(unsubmitted_frames_.begin());
+ swap_buffers_pending_ = true;
+
+ last_swap_buffers_result_ =
+ frame->ScheduleOverlayPlanes(widget_) &&
+ ozone_surface_->OnSwapBuffersAsync(frame->callback);
+ }
+}
+
+EGLSyncKHR GLSurfaceOzoneSurfaceless::InsertFence() {
+ const EGLint attrib_list[] = {EGL_SYNC_CONDITION_KHR,
+ EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM,
+ EGL_NONE};
+ return eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR, attrib_list);
+}
+
+void GLSurfaceOzoneSurfaceless::FenceRetired(EGLSyncKHR fence,
+ PendingFrame* frame) {
+ eglDestroySyncKHR(GetDisplay(), fence);
+ frame->ready = true;
+ SubmitFrame();
+}
+
+void GLSurfaceOzoneSurfaceless::SwapCompleted(
+ const SwapCompletionCallback& callback,
+ gfx::SwapResult result) {
+ callback.Run(result);
+ swap_buffers_pending_ = false;
+
+ SubmitFrame();
+}
+
// This provides surface-like semantics implemented through surfaceless.
// A framebuffer is bound automatically.
class GL_EXPORT GLSurfaceOzoneSurfacelessSurfaceImpl
@@ -246,142 +422,41 @@
public:
GLSurfaceOzoneSurfacelessSurfaceImpl(
scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
- AcceleratedWidget widget)
- : GLSurfaceOzoneSurfaceless(ozone_surface.Pass(), widget),
- fbo_(0),
- current_surface_(0) {
- for (auto& texture : textures_)
- texture = 0;
- }
+ AcceleratedWidget widget,
+ const gfx::SurfaceConfiguration& requested_configuration);
- unsigned int GetBackingFrameBufferObject() override { return fbo_; }
-
- bool OnMakeCurrent(GLContext* context) override {
- if (!fbo_) {
- glGenFramebuffersEXT(1, &fbo_);
- if (!fbo_)
- return false;
- glGenTextures(arraysize(textures_), textures_);
- if (!CreatePixmaps())
- return false;
- }
- BindFramebuffer();
- glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_);
- return SurfacelessEGL::OnMakeCurrent(context);
- }
-
- bool Resize(const gfx::Size& size) override {
- if (size == GetSize())
- return true;
- return GLSurfaceOzoneSurfaceless::Resize(size) && CreatePixmaps();
- }
-
- bool SupportsPostSubBuffer() override { return false; }
-
- bool SwapBuffers() override {
- if (!images_[current_surface_]->ScheduleOverlayPlane(
- widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE,
- gfx::Rect(GetSize()), gfx::RectF(1, 1)))
- return false;
- if (!GLSurfaceOzoneSurfaceless::SwapBuffers())
- return false;
- current_surface_ ^= 1;
- BindFramebuffer();
- return true;
- }
-
- bool SwapBuffersAsync(const SwapCompletionCallback& callback) override {
- if (!images_[current_surface_]->ScheduleOverlayPlane(
- widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE,
- gfx::Rect(GetSize()), gfx::RectF(1, 1)))
- return false;
- if (!GLSurfaceOzoneSurfaceless::SwapBuffersAsync(callback))
- return false;
- current_surface_ ^= 1;
- BindFramebuffer();
- return true;
- }
-
- void Destroy() override {
- GLContext* current_context = GLContext::GetCurrent();
- DCHECK(current_context && current_context->IsCurrent(this));
- glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
- if (fbo_) {
- glDeleteTextures(arraysize(textures_), textures_);
- for (auto& texture : textures_)
- texture = 0;
- glDeleteFramebuffersEXT(1, &fbo_);
- fbo_ = 0;
- }
- for (auto image : images_) {
- if (image)
- image->Destroy(true);
- }
- }
+ // GLSurface:
+ unsigned int GetBackingFrameBufferObject() override;
+ bool OnMakeCurrent(GLContext* context) override;
+ bool Resize(const gfx::Size& size) override;
+ bool SupportsPostSubBuffer() override;
+ gfx::SwapResult SwapBuffers() override;
+ bool SwapBuffersAsync(const SwapCompletionCallback& callback) override;
+ void Destroy() override;
private:
class SurfaceImage : public GLImageLinuxDMABuffer {
public:
- SurfaceImage(const gfx::Size& size, unsigned internalformat)
- : GLImageLinuxDMABuffer(size, internalformat) {}
+ SurfaceImage(const gfx::Size& size, unsigned internalformat);
bool Initialize(scoped_refptr<ui::NativePixmap> pixmap,
- gfx::GpuMemoryBuffer::Format format) {
- base::FileDescriptor handle(pixmap->GetDmaBufFd(), false);
- if (!GLImageLinuxDMABuffer::Initialize(handle, format,
- pixmap->GetDmaBufPitch()))
- return false;
- pixmap_ = pixmap;
- return true;
- }
+ gfx::GpuMemoryBuffer::Format format);
bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
int z_order,
gfx::OverlayTransform transform,
const gfx::Rect& bounds_rect,
- const gfx::RectF& crop_rect) override {
- return ui::SurfaceFactoryOzone::GetInstance()->ScheduleOverlayPlane(
- widget, z_order, transform, pixmap_, bounds_rect, crop_rect);
- }
+ const gfx::RectF& crop_rect) override;
private:
- ~SurfaceImage() override {}
+ ~SurfaceImage() override;
scoped_refptr<ui::NativePixmap> pixmap_;
};
- ~GLSurfaceOzoneSurfacelessSurfaceImpl() override {
- DCHECK(!fbo_);
- for (size_t i = 0; i < arraysize(textures_); i++)
- DCHECK(!textures_[i]) << "texture " << i << " not released";
- }
+ ~GLSurfaceOzoneSurfacelessSurfaceImpl() override;
- void BindFramebuffer() {
- ScopedFrameBufferBinder fb(fbo_);
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, textures_[current_surface_], 0);
- }
-
- bool CreatePixmaps() {
- if (!fbo_)
- return true;
- for (size_t i = 0; i < arraysize(textures_); i++) {
- scoped_refptr<ui::NativePixmap> pixmap =
- ui::SurfaceFactoryOzone::GetInstance()->CreateNativePixmap(
- widget_, GetSize(), ui::SurfaceFactoryOzone::RGBA_8888,
- ui::SurfaceFactoryOzone::SCANOUT);
- if (!pixmap)
- return false;
- scoped_refptr<SurfaceImage> image = new SurfaceImage(GetSize(), GL_RGBA);
- if (!image->Initialize(pixmap, gfx::GpuMemoryBuffer::Format::BGRA_8888))
- return false;
- images_[i] = image;
- // Bind image to texture.
- ScopedTextureBinder binder(GL_TEXTURE_2D, textures_[i]);
- if (!images_[i]->BindTexImage(GL_TEXTURE_2D))
- return false;
- }
- return true;
- }
+ void BindFramebuffer();
+ bool CreatePixmaps();
GLuint fbo_;
GLuint textures_[2];
@@ -390,6 +465,156 @@
DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfacelessSurfaceImpl);
};
+GLSurfaceOzoneSurfacelessSurfaceImpl::SurfaceImage::SurfaceImage(
+ const gfx::Size& size,
+ unsigned internalformat)
+ : GLImageLinuxDMABuffer(size, internalformat) {
+}
+
+bool GLSurfaceOzoneSurfacelessSurfaceImpl::SurfaceImage::Initialize(
+ scoped_refptr<ui::NativePixmap> pixmap,
+ gfx::GpuMemoryBuffer::Format format) {
+ base::FileDescriptor handle(pixmap->GetDmaBufFd(), false);
+ if (!GLImageLinuxDMABuffer::Initialize(handle, format,
+ pixmap->GetDmaBufPitch()))
+ return false;
+ pixmap_ = pixmap;
+ return true;
+}
+bool GLSurfaceOzoneSurfacelessSurfaceImpl::SurfaceImage::ScheduleOverlayPlane(
+ gfx::AcceleratedWidget widget,
+ int z_order,
+ gfx::OverlayTransform transform,
+ const gfx::Rect& bounds_rect,
+ const gfx::RectF& crop_rect) {
+ return pixmap_->ScheduleOverlayPlane(widget, z_order, transform, bounds_rect,
+ crop_rect);
+}
+
+GLSurfaceOzoneSurfacelessSurfaceImpl::SurfaceImage::~SurfaceImage() {
+}
+
+GLSurfaceOzoneSurfacelessSurfaceImpl::GLSurfaceOzoneSurfacelessSurfaceImpl(
+ scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
+ AcceleratedWidget widget,
+ const gfx::SurfaceConfiguration& requested_configuration)
+ : GLSurfaceOzoneSurfaceless(
+ ozone_surface.Pass(), widget, requested_configuration),
+ fbo_(0),
+ current_surface_(0) {
+ for (auto& texture : textures_)
+ texture = 0;
+}
+
+unsigned int
+GLSurfaceOzoneSurfacelessSurfaceImpl::GetBackingFrameBufferObject() {
+ return fbo_;
+}
+
+bool GLSurfaceOzoneSurfacelessSurfaceImpl::OnMakeCurrent(GLContext* context) {
+ if (!fbo_) {
+ glGenFramebuffersEXT(1, &fbo_);
+ if (!fbo_)
+ return false;
+ glGenTextures(arraysize(textures_), textures_);
+ if (!CreatePixmaps())
+ return false;
+ }
+ BindFramebuffer();
+ glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_);
+ return SurfacelessEGL::OnMakeCurrent(context);
+}
+
+bool GLSurfaceOzoneSurfacelessSurfaceImpl::Resize(const gfx::Size& size) {
+ if (size == GetSize())
+ return true;
+ return GLSurfaceOzoneSurfaceless::Resize(size) && CreatePixmaps();
+}
+
+bool GLSurfaceOzoneSurfacelessSurfaceImpl::SupportsPostSubBuffer() {
+ return false;
+}
+
+gfx::SwapResult GLSurfaceOzoneSurfacelessSurfaceImpl::SwapBuffers() {
+ if (!images_[current_surface_]->ScheduleOverlayPlane(
+ widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(GetSize()), gfx::RectF(1, 1)))
+ return gfx::SwapResult::SWAP_FAILED;
+ gfx::SwapResult result = GLSurfaceOzoneSurfaceless::SwapBuffers();
+ if (result != gfx::SwapResult::SWAP_ACK)
+ return result;
+ current_surface_ ^= 1;
+ BindFramebuffer();
+ return gfx::SwapResult::SWAP_ACK;
+}
+
+bool GLSurfaceOzoneSurfacelessSurfaceImpl::SwapBuffersAsync(
+ const SwapCompletionCallback& callback) {
+ if (!images_[current_surface_]->ScheduleOverlayPlane(
+ widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(GetSize()), gfx::RectF(1, 1)))
+ return false;
+ if (!GLSurfaceOzoneSurfaceless::SwapBuffersAsync(callback))
+ return false;
+ current_surface_ ^= 1;
+ BindFramebuffer();
+ return true;
+}
+
+void GLSurfaceOzoneSurfacelessSurfaceImpl::Destroy() {
+ GLContext* current_context = GLContext::GetCurrent();
+ DCHECK(current_context && current_context->IsCurrent(this));
+ glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
+ if (fbo_) {
+ glDeleteTextures(arraysize(textures_), textures_);
+ for (auto& texture : textures_)
+ texture = 0;
+ glDeleteFramebuffersEXT(1, &fbo_);
+ fbo_ = 0;
+ }
+ for (auto image : images_) {
+ if (image)
+ image->Destroy(true);
+ }
+}
+
+GLSurfaceOzoneSurfacelessSurfaceImpl::~GLSurfaceOzoneSurfacelessSurfaceImpl() {
+ DCHECK(!fbo_);
+ for (size_t i = 0; i < arraysize(textures_); i++)
+ DCHECK(!textures_[i]) << "texture " << i << " not released";
+}
+
+void GLSurfaceOzoneSurfacelessSurfaceImpl::BindFramebuffer() {
+ ScopedFrameBufferBinder fb(fbo_);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ textures_[current_surface_], 0);
+}
+
+bool GLSurfaceOzoneSurfacelessSurfaceImpl::CreatePixmaps() {
+ if (!fbo_)
+ return true;
+ for (size_t i = 0; i < arraysize(textures_); i++) {
+ scoped_refptr<ui::NativePixmap> pixmap =
+ ui::OzonePlatform::GetInstance()
+ ->GetSurfaceFactoryOzone()
+ ->CreateNativePixmap(widget_, GetSize(),
+ ui::SurfaceFactoryOzone::BGRA_8888,
+ ui::SurfaceFactoryOzone::SCANOUT);
+ if (!pixmap)
+ return false;
+ scoped_refptr<SurfaceImage> image =
+ new SurfaceImage(GetSize(), GL_BGRA_EXT);
+ if (!image->Initialize(pixmap, gfx::GpuMemoryBuffer::Format::BGRA_8888))
+ return false;
+ images_[i] = image;
+ // Bind image to texture.
+ ScopedTextureBinder binder(GL_TEXTURE_2D, textures_[i]);
+ if (!images_[i]->BindTexImage(GL_TEXTURE_2D))
+ return false;
+ }
+ return true;
+}
+
} // namespace
// static
@@ -412,18 +637,24 @@
// static
scoped_refptr<GLSurface> GLSurface::CreateSurfacelessViewGLSurface(
- gfx::AcceleratedWidget window) {
+ gfx::AcceleratedWidget window,
+ const gfx::SurfaceConfiguration& requested_configuration) {
if (GetGLImplementation() == kGLImplementationEGLGLES2 &&
window != kNullAcceleratedWidget &&
GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
- ui::SurfaceFactoryOzone::GetInstance()->CanShowPrimaryPlaneAsOverlay()) {
+ ui::OzonePlatform::GetInstance()
+ ->GetSurfaceFactoryOzone()
+ ->CanShowPrimaryPlaneAsOverlay()) {
scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
- ui::SurfaceFactoryOzone::GetInstance()
+ ui::OzonePlatform::GetInstance()
+ ->GetSurfaceFactoryOzone()
->CreateSurfacelessEGLSurfaceForWidget(window);
if (!surface_ozone)
return nullptr;
scoped_refptr<GLSurface> surface;
- surface = new GLSurfaceOzoneSurfaceless(surface_ozone.Pass(), window);
+ surface = new GLSurfaceOzoneSurfaceless(surface_ozone.Pass(),
+ window,
+ requested_configuration);
if (surface->Initialize())
return surface;
}
@@ -433,9 +664,11 @@
// static
scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
- gfx::AcceleratedWidget window) {
+ gfx::AcceleratedWidget window,
+ const gfx::SurfaceConfiguration& requested_configuration) {
if (GetGLImplementation() == kGLImplementationOSMesaGL) {
- scoped_refptr<GLSurface> surface(new GLSurfaceOSMesaHeadless());
+ scoped_refptr<GLSurface> surface(
+ new GLSurfaceOSMesaHeadless(requested_configuration));
if (!surface->Initialize())
return NULL;
return surface;
@@ -444,29 +677,34 @@
if (window != kNullAcceleratedWidget) {
scoped_refptr<GLSurface> surface;
if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
- ui::SurfaceFactoryOzone::GetInstance()
+ ui::OzonePlatform::GetInstance()
+ ->GetSurfaceFactoryOzone()
->CanShowPrimaryPlaneAsOverlay()) {
scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
- ui::SurfaceFactoryOzone::GetInstance()
+ ui::OzonePlatform::GetInstance()
+ ->GetSurfaceFactoryOzone()
->CreateSurfacelessEGLSurfaceForWidget(window);
if (!surface_ozone)
return NULL;
- surface = new GLSurfaceOzoneSurfacelessSurfaceImpl(surface_ozone.Pass(),
- window);
+ surface = new GLSurfaceOzoneSurfacelessSurfaceImpl(
+ surface_ozone.Pass(), window, requested_configuration);
} else {
scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
- ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
- window);
+ ui::OzonePlatform::GetInstance()
+ ->GetSurfaceFactoryOzone()
+ ->CreateEGLSurfaceForWidget(window);
if (!surface_ozone)
return NULL;
- surface = new GLSurfaceOzoneEGL(surface_ozone.Pass(), window);
+ surface = new GLSurfaceOzoneEGL(
+ surface_ozone.Pass(), window, requested_configuration);
}
if (!surface->Initialize())
return NULL;
return surface;
} else {
- scoped_refptr<GLSurface> surface = new GLSurfaceStub();
+ scoped_refptr<GLSurface> surface = new GLSurfaceStub(
+ requested_configuration);
if (surface->Initialize())
return surface;
}
@@ -475,11 +713,12 @@
// static
scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
- const gfx::Size& size) {
+ const gfx::Size& size,
+ const gfx::SurfaceConfiguration& requested_configuration) {
switch (GetGLImplementation()) {
case kGLImplementationOSMesaGL: {
- scoped_refptr<GLSurface> surface(
- new GLSurfaceOSMesa(OSMesaSurfaceFormatBGRA, size));
+ scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(
+ OSMesaSurfaceFormatBGRA, size, requested_configuration));
if (!surface->Initialize())
return NULL;
@@ -489,14 +728,16 @@
scoped_refptr<GLSurface> surface;
if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
(size.width() == 0 && size.height() == 0)) {
- surface = new SurfacelessEGL(size);
+ surface = new SurfacelessEGL(size, requested_configuration);
} else
- surface = new PbufferGLSurfaceEGL(size);
+ surface = new PbufferGLSurfaceEGL(size, requested_configuration);
if (!surface->Initialize())
return NULL;
return surface;
}
+ case kGLImplementationMockGL:
+ return new GLSurfaceStub(requested_configuration);
default:
NOTREACHED();
return NULL;
@@ -504,7 +745,9 @@
}
EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
- return ui::SurfaceFactoryOzone::GetInstance()->GetNativeDisplay();
+ return ui::OzonePlatform::GetInstance()
+ ->GetSurfaceFactoryOzone()
+ ->GetNativeDisplay();
}
} // namespace gfx
diff --git a/ui/gl/gl_surface_stub.cc b/ui/gl/gl_surface_stub.cc
index 70230fc..9c44023 100644
--- a/ui/gl/gl_surface_stub.cc
+++ b/ui/gl/gl_surface_stub.cc
@@ -18,8 +18,8 @@
return false;
}
-bool GLSurfaceStub::SwapBuffers() {
- return true;
+gfx::SwapResult GLSurfaceStub::SwapBuffers() {
+ return gfx::SwapResult::SWAP_ACK;
}
gfx::Size GLSurfaceStub::GetSize() {
diff --git a/ui/gl/gl_surface_stub.h b/ui/gl/gl_surface_stub.h
index f35e716..70a8936 100644
--- a/ui/gl/gl_surface_stub.h
+++ b/ui/gl/gl_surface_stub.h
@@ -20,7 +20,7 @@
// Implement GLSurface.
void Destroy() override;
bool IsOffscreen() override;
- bool SwapBuffers() override;
+ gfx::SwapResult SwapBuffers() override;
gfx::Size GetSize() override;
void* GetHandle() override;
diff --git a/ui/gl/gl_surface_x11.cc b/ui/gl/gl_surface_x11.cc
index efbaf60..8255a08 100644
--- a/ui/gl/gl_surface_x11.cc
+++ b/ui/gl/gl_surface_x11.cc
@@ -34,9 +34,9 @@
void Destroy() override;
bool Resize(const gfx::Size& new_size) override;
bool IsOffscreen() override;
- bool SwapBuffers() override;
+ gfx::SwapResult SwapBuffers() override;
bool SupportsPostSubBuffer() override;
- bool PostSubBuffer(int x, int y, int width, int height) override;
+ gfx::SwapResult PostSubBuffer(int x, int y, int width, int height) override;
protected:
~NativeViewGLSurfaceOSMesa() override;
@@ -186,7 +186,7 @@
return false;
}
-bool NativeViewGLSurfaceOSMesa::SwapBuffers() {
+gfx::SwapResult NativeViewGLSurfaceOSMesa::SwapBuffers() {
TRACE_EVENT2("gpu", "NativeViewGLSurfaceOSMesa:RealSwapBuffers",
"width", GetSize().width(),
"height", GetSize().height());
@@ -196,7 +196,7 @@
XWindowAttributes attributes;
if (!XGetWindowAttributes(xdisplay_, window_, &attributes)) {
LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << ".";
- return false;
+ return gfx::SwapResult::SWAP_FAILED;
}
// Copy the frame into the pixmap.
@@ -221,14 +221,14 @@
0,
0);
- return true;
+ return gfx::SwapResult::SWAP_ACK;
}
bool NativeViewGLSurfaceOSMesa::SupportsPostSubBuffer() {
return true;
}
-bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
+gfx::SwapResult NativeViewGLSurfaceOSMesa::PostSubBuffer(
int x, int y, int width, int height) {
gfx::Size size = GetSize();
@@ -238,7 +238,7 @@
XWindowAttributes attributes;
if (!XGetWindowAttributes(xdisplay_, window_, &attributes)) {
LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << ".";
- return false;
+ return gfx::SwapResult::SWAP_FAILED;
}
// Copy the frame into the pixmap.
@@ -269,7 +269,7 @@
x,
y);
- return true;
+ return gfx::SwapResult::SWAP_ACK;
}
NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() {
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn
new file mode 100644
index 0000000..117988b
--- /dev/null
+++ b/ui/ozone/BUILD.gn
@@ -0,0 +1,201 @@
+# 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.
+
+import("//ui/ozone/ozone.gni")
+import("//testing/test.gni")
+
+# The list of platforms that will be built.
+ozone_platforms = []
+
+# Extra dependencies to pull into ui/ozone for built platforms.
+ozone_platform_deps = []
+
+# Extra dependencies to pull into ozone_unittests for built platforms.
+ozone_platform_test_deps = []
+
+if (ozone_platform_egltest) {
+ ozone_platforms += [ "egltest" ]
+ ozone_platform_deps += [ "platform/egltest" ]
+}
+
+if (ozone_platform_test) {
+ ozone_platforms += [ "test" ]
+ ozone_platform_deps += [ "platform/test" ]
+}
+
+if (ozone_platform_caca) {
+ ozone_platforms += [ "caca" ]
+ ozone_platform_deps += [ "platform/caca" ]
+}
+
+if (ozone_platform_dri || ozone_platform_drm) {
+ ozone_platforms += [
+ "dri",
+ "drm",
+ ]
+ ozone_platform_deps += [
+ "platform/drm",
+ "platform/drm:drm_common",
+ ]
+ ozone_platform_test_deps += [ "platform/drm:drm_unittests" ]
+}
+
+if (ozone_platform_gbm) {
+ ozone_platforms += [ "gbm" ]
+ ozone_platform_deps += [
+ "platform/drm:drm_common",
+ "platform/drm:gbm",
+ ]
+}
+
+platform_list_cc_file = "$target_gen_dir/platform_list.cc"
+platform_list_h_file = "$target_gen_dir/platform_list.h"
+platform_list_txt_file = "$target_gen_dir/platform_list.txt"
+constructor_list_cc_file = "$target_gen_dir/constructor_list.cc"
+
+# GYP version: ui/ozone/ozone.gyp:ozone_base
+component("ozone_base") {
+ sources = [
+ "public/cursor_factory_ozone.cc",
+ "public/cursor_factory_ozone.h",
+ "public/gpu_platform_support.cc",
+ "public/gpu_platform_support.h",
+ "public/gpu_platform_support_host.cc",
+ "public/gpu_platform_support_host.h",
+ "public/input_controller.cc",
+ "public/input_controller.h",
+ "public/overlay_candidates_ozone.cc",
+ "public/overlay_candidates_ozone.h",
+ "public/overlay_manager_ozone.h",
+ "public/surface_factory_ozone.cc",
+ "public/surface_factory_ozone.h",
+ "public/surface_ozone_canvas.h",
+ "public/surface_ozone_egl.cc",
+ "public/surface_ozone_egl.h",
+ "public/system_input_injector.h",
+ ]
+
+ defines = [ "OZONE_BASE_IMPLEMENTATION" ]
+
+ deps = [
+ "//base",
+ "//skia",
+ "//ui/events:events_base",
+ "//ui/events:dom_keycode_converter",
+ "//ui/gfx/geometry",
+ "//ui/gfx",
+ ]
+}
+
+component("ozone") {
+ sources = [
+ "common/display_mode_proxy.cc",
+ "common/display_mode_proxy.h",
+ "common/display_snapshot_proxy.cc",
+ "common/display_snapshot_proxy.h",
+ "common/display_util.cc",
+ "common/display_util.h",
+ "common/egl_util.cc",
+ "common/egl_util.h",
+ "common/gpu/ozone_gpu_message_params.cc",
+ "common/gpu/ozone_gpu_message_params.h",
+ "common/native_display_delegate_ozone.cc",
+ "common/native_display_delegate_ozone.h",
+ "common/stub_overlay_manager.cc",
+ "common/stub_overlay_manager.h",
+ "platform_selection.cc",
+ "platform_selection.h",
+ "public/ozone_platform.cc",
+ "public/ozone_platform.h",
+ "public/ozone_switches.cc",
+ "public/ozone_switches.h",
+ constructor_list_cc_file,
+ platform_list_cc_file,
+ platform_list_h_file,
+ ]
+
+ defines = [ "OZONE_IMPLEMENTATION" ]
+
+ deps =
+ [
+ ":generate_constructor_list",
+ ":generate_ozone_platform_list",
+ ":ozone_base",
+ "//base",
+ "//skia",
+ "//ui/display/types",
+ "//ui/display/util",
+ "//ui/events",
+ "//ui/events/devices",
+ "//ui/events/ozone:events_ozone",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+
+ # TODO(GYP) the GYP version has a way to add additional dependencies via
+ # build flags.
+ ] + ozone_platform_deps
+
+ allow_circular_includes_from = [
+ "platform/egltest",
+
+ #"platform/drm",
+ "platform/drm:drm_common",
+ "platform/drm:gbm",
+ "//ui/events/ozone:events_ozone",
+ ]
+}
+
+# GYP version: ui/ozone/ozone.gyp:generate_ozone_platform_list
+action("generate_ozone_platform_list") {
+ script = "generate_ozone_platform_list.py"
+ outputs = [
+ platform_list_cc_file,
+ platform_list_h_file,
+ platform_list_txt_file,
+ ]
+
+ args =
+ [
+ "--output_cc=" + rebase_path(platform_list_cc_file, root_build_dir),
+ "--output_h=" + rebase_path(platform_list_h_file, root_build_dir),
+ "--output_txt=" + rebase_path(platform_list_txt_file, root_build_dir),
+ "--default=$ozone_platform",
+ ] + ozone_platforms
+}
+
+# GYP version: ui/ozone/ozone.gyp:generate_constructor_list
+action("generate_constructor_list") {
+ script = "generate_constructor_list.py"
+
+ inputs = [
+ platform_list_txt_file,
+ ]
+ outputs = [
+ constructor_list_cc_file,
+ ]
+
+ args = [
+ "--platform_list=" + rebase_path(platform_list_txt_file, root_build_dir),
+ "--output_cc=" + rebase_path(constructor_list_cc_file, root_build_dir),
+ "--namespace=ui",
+ "--typename=OzonePlatform",
+ "--include=\"ui/ozone/public/ozone_platform.h\"",
+ ]
+
+ deps = [
+ ":generate_ozone_platform_list",
+ ]
+}
+
+test("ozone_unittests") {
+ sources = [
+ "run_all_unittests.cc",
+ ]
+
+ deps = [
+ "//base/test:test_support",
+ "//testing/gtest",
+ "//ui/gfx/geometry",
+ ] + ozone_platform_test_deps
+}
diff --git a/ui/ozone/PRESUBMIT.py b/ui/ozone/PRESUBMIT.py
new file mode 100644
index 0000000..6b822c9
--- /dev/null
+++ b/ui/ozone/PRESUBMIT.py
@@ -0,0 +1,14 @@
+# 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.
+
+"""Presubmit script for ozone.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def CheckChangeOnUpload(input_api, output_api):
+ results = []
+ results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
+ return results
diff --git a/ui/ozone/common/README b/ui/ozone/common/README
new file mode 100644
index 0000000..1ab9e67
--- /dev/null
+++ b/ui/ozone/common/README
@@ -0,0 +1,2 @@
+This directory contains code that is used by multiple platforms, but is not part
+of the public platform API. This code should not be used outside of ui/ozone.
diff --git a/ui/ozone/common/display_mode_proxy.cc b/ui/ozone/common/display_mode_proxy.cc
new file mode 100644
index 0000000..6890b33
--- /dev/null
+++ b/ui/ozone/common/display_mode_proxy.cc
@@ -0,0 +1,18 @@
+// 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/common/display_mode_proxy.h"
+
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+
+namespace ui {
+
+DisplayModeProxy::DisplayModeProxy(const DisplayMode_Params& params)
+ : DisplayMode(params.size, params.is_interlaced, params.refresh_rate) {
+}
+
+DisplayModeProxy::~DisplayModeProxy() {
+}
+
+} // namespace ui
diff --git a/ui/ozone/common/display_mode_proxy.h b/ui/ozone/common/display_mode_proxy.h
new file mode 100644
index 0000000..f9211c1
--- /dev/null
+++ b/ui/ozone/common/display_mode_proxy.h
@@ -0,0 +1,25 @@
+// 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.
+
+#ifndef UI_OZONE_COMMON_DISPLAY_MODE_PROXY_H_
+#define UI_OZONE_COMMON_DISPLAY_MODE_PROXY_H_
+
+#include "ui/display/types/display_mode.h"
+
+namespace ui {
+
+struct DisplayMode_Params;
+
+class DisplayModeProxy : public DisplayMode {
+ public:
+ DisplayModeProxy(const DisplayMode_Params& params);
+ ~DisplayModeProxy() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DisplayModeProxy);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_COMMON_DISPLAY_MODE_PROXY_H_
diff --git a/ui/ozone/common/display_snapshot_proxy.cc b/ui/ozone/common/display_snapshot_proxy.cc
new file mode 100644
index 0000000..4f6556c
--- /dev/null
+++ b/ui/ozone/common/display_snapshot_proxy.cc
@@ -0,0 +1,65 @@
+// 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/common/display_snapshot_proxy.h"
+
+#include "ui/ozone/common/display_mode_proxy.h"
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+
+namespace ui {
+
+namespace {
+
+bool SameModes(const DisplayMode_Params& lhs, const DisplayMode_Params& rhs) {
+ return lhs.size == rhs.size && lhs.is_interlaced == rhs.is_interlaced &&
+ lhs.refresh_rate == rhs.refresh_rate;
+}
+
+// Exclude 4K@60kHz becaseu this doesn't work in most devices/configuration now.
+// TODO(marcheu|oshima): Revisit this. crbug.com/39397
+bool IsModeBlackListed(const DisplayMode_Params& mode_params) {
+ return mode_params.size.width() >= 3840 && mode_params.size.width() >= 2160 &&
+ mode_params.refresh_rate >= 60.0f;
+}
+
+} // namespace
+
+DisplaySnapshotProxy::DisplaySnapshotProxy(const DisplaySnapshot_Params& params)
+ : DisplaySnapshot(params.display_id,
+ params.origin,
+ params.physical_size,
+ params.type,
+ params.is_aspect_preserving_scaling,
+ params.has_overscan,
+ params.display_name,
+ std::vector<const DisplayMode*>(),
+ NULL,
+ NULL),
+ string_representation_(params.string_representation) {
+ for (size_t i = 0; i < params.modes.size(); ++i) {
+ const DisplayMode_Params& mode_params = params.modes[i];
+ if (IsModeBlackListed(mode_params))
+ continue;
+ modes_.push_back(new DisplayModeProxy(mode_params));
+
+ if (params.has_current_mode &&
+ SameModes(params.modes[i], params.current_mode))
+ current_mode_ = modes_.back();
+
+ if (params.has_native_mode &&
+ SameModes(params.modes[i], params.native_mode))
+ native_mode_ = modes_.back();
+ }
+
+ product_id_ = params.product_id;
+}
+
+DisplaySnapshotProxy::~DisplaySnapshotProxy() {
+}
+
+std::string DisplaySnapshotProxy::ToString() const {
+ return string_representation_;
+}
+
+} // namespace ui
diff --git a/ui/ozone/common/display_snapshot_proxy.h b/ui/ozone/common/display_snapshot_proxy.h
new file mode 100644
index 0000000..158f584
--- /dev/null
+++ b/ui/ozone/common/display_snapshot_proxy.h
@@ -0,0 +1,30 @@
+// 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.
+
+#ifndef UI_OZONE_COMMON_DISPLAY_SNAPSHOT_PROXY_H_
+#define UI_OZONE_COMMON_DISPLAY_SNAPSHOT_PROXY_H_
+
+#include "ui/display/types/display_snapshot.h"
+
+namespace ui {
+
+struct DisplaySnapshot_Params;
+
+class DisplaySnapshotProxy : public DisplaySnapshot {
+ public:
+ DisplaySnapshotProxy(const DisplaySnapshot_Params& params);
+ ~DisplaySnapshotProxy() override;
+
+ // DisplaySnapshot override:
+ std::string ToString() const override;
+
+ private:
+ std::string string_representation_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplaySnapshotProxy);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_COMMON_DISPLAY_SNAPSHOT_PROXY_H_
diff --git a/ui/ozone/common/display_util.cc b/ui/ozone/common/display_util.cc
new file mode 100644
index 0000000..ffa4670
--- /dev/null
+++ b/ui/ozone/common/display_util.cc
@@ -0,0 +1,102 @@
+// 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/common/display_util.h"
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "ui/display/types/display_mode.h"
+#include "ui/display/types/display_snapshot.h"
+#include "ui/display/util/edid_parser.h"
+#include "ui/display/util/edid_parser.h"
+#include "ui/ozone/public/ozone_switches.h"
+
+namespace ui {
+
+namespace {
+
+const int64_t kDummyDisplayId = 1;
+const int64_t kDummyProductId = 1;
+
+} // namespace
+
+FindDisplayById::FindDisplayById(int64_t display_id) : display_id_(display_id) {
+}
+
+bool FindDisplayById::operator()(const DisplaySnapshot_Params& display) const {
+ return display.display_id == display_id_;
+}
+
+DisplayMode_Params GetDisplayModeParams(const DisplayMode& mode) {
+ DisplayMode_Params params;
+ params.size = mode.size();
+ params.is_interlaced = mode.is_interlaced();
+ params.refresh_rate = mode.refresh_rate();
+
+ return params;
+}
+
+DisplaySnapshot_Params GetDisplaySnapshotParams(
+ const DisplaySnapshot& display) {
+ DisplaySnapshot_Params params;
+ params.display_id = display.display_id();
+ params.origin = display.origin();
+ params.physical_size = display.physical_size();
+ params.type = display.type();
+ params.is_aspect_preserving_scaling = display.is_aspect_preserving_scaling();
+ params.has_overscan = display.has_overscan();
+ params.display_name = display.display_name();
+ for (size_t i = 0; i < display.modes().size(); ++i)
+ params.modes.push_back(GetDisplayModeParams(*display.modes()[i]));
+
+ params.has_current_mode = display.current_mode() != NULL;
+ if (params.has_current_mode)
+ params.current_mode = GetDisplayModeParams(*display.current_mode());
+
+ params.has_native_mode = display.native_mode() != NULL;
+ if (params.has_native_mode)
+ params.native_mode = GetDisplayModeParams(*display.native_mode());
+
+ params.product_id = display.product_id();
+ params.string_representation = display.ToString();
+
+ return params;
+}
+
+bool CreateSnapshotFromCommandLine(DisplaySnapshot_Params* snapshot_out) {
+ base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
+ std::string spec =
+ cmd->GetSwitchValueASCII(switches::kOzoneInitialDisplayBounds);
+ std::string physical_spec =
+ cmd->GetSwitchValueASCII(switches::kOzoneInitialDisplayPhysicalSizeMm);
+
+ int width = 0;
+ int height = 0;
+ if (spec.empty() || sscanf(spec.c_str(), "%dx%d", &width, &height) < 2 ||
+ width == 0 || height == 0) {
+ return false;
+ }
+
+ int physical_width = 0;
+ int physical_height = 0;
+ sscanf(physical_spec.c_str(), "%dx%d", &physical_width, &physical_height);
+
+ DisplayMode_Params mode_param;
+ mode_param.size = gfx::Size(width, height);
+ mode_param.refresh_rate = 60;
+
+ snapshot_out->display_id = kDummyDisplayId;
+ snapshot_out->modes.push_back(mode_param);
+ snapshot_out->type = DISPLAY_CONNECTION_TYPE_INTERNAL;
+ snapshot_out->physical_size = gfx::Size(physical_width, physical_height);
+ snapshot_out->has_current_mode = true;
+ snapshot_out->current_mode = mode_param;
+ snapshot_out->has_native_mode = true;
+ snapshot_out->native_mode = mode_param;
+ snapshot_out->product_id = kDummyProductId;
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/ozone/common/display_util.h b/ui/ozone/common/display_util.h
new file mode 100644
index 0000000..6289fdd
--- /dev/null
+++ b/ui/ozone/common/display_util.h
@@ -0,0 +1,42 @@
+// 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.
+
+#ifndef UI_OZONE_COMMON_DISPLAY_UTIL_H_
+#define UI_OZONE_COMMON_DISPLAY_UTIL_H_
+
+#include <vector>
+
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace ui {
+
+class DisplayMode;
+class DisplaySnapshot;
+
+// Conforms to the std::UnaryPredicate interface such that it can be used to
+// find a display with |display_id| in std:: containers (ie: std::vector).
+class FindDisplayById {
+ public:
+ explicit FindDisplayById(int64_t display_id);
+
+ bool operator()(const DisplaySnapshot_Params& display) const;
+
+ private:
+ int64_t display_id_;
+};
+
+DisplayMode_Params GetDisplayModeParams(const DisplayMode& mode);
+DisplaySnapshot_Params GetDisplaySnapshotParams(const DisplaySnapshot& display);
+
+// Create a display using the Ozone command line parameters.
+// Return false if the command line flags are not specified.
+bool CreateSnapshotFromCommandLine(DisplaySnapshot_Params* snapshot_out);
+
+} // namespace ui
+
+#endif // UI_OZONE_COMMON_DISPLAY_UTIL_H_
diff --git a/ui/ozone/common/egl_util.cc b/ui/ozone/common/egl_util.cc
new file mode 100644
index 0000000..8000360
--- /dev/null
+++ b/ui/ozone/common/egl_util.cc
@@ -0,0 +1,65 @@
+// 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/common/egl_util.h"
+
+#include "base/files/file_path.h"
+
+namespace ui {
+namespace {
+
+const char kDefaultEglSoname[] = "libEGL.so.1";
+const char kDefaultGlesSoname[] = "libGLESv2.so.2";
+
+} // namespace
+
+bool LoadDefaultEGLGLES2Bindings(
+ SurfaceFactoryOzone::AddGLLibraryCallback add_gl_library,
+ SurfaceFactoryOzone::SetGLGetProcAddressProcCallback
+ set_gl_get_proc_address) {
+ return LoadEGLGLES2Bindings(add_gl_library, set_gl_get_proc_address,
+ kDefaultEglSoname, kDefaultGlesSoname);
+}
+
+bool LoadEGLGLES2Bindings(
+ SurfaceFactoryOzone::AddGLLibraryCallback add_gl_library,
+ SurfaceFactoryOzone::SetGLGetProcAddressProcCallback
+ set_gl_get_proc_address,
+ const char* egl_library_name,
+ const char* gles_library_name) {
+ base::NativeLibraryLoadError error;
+ base::NativeLibrary gles_library =
+ base::LoadNativeLibrary(base::FilePath(gles_library_name), &error);
+ if (!gles_library) {
+ LOG(WARNING) << "Failed to load GLES library: " << error.ToString();
+ return false;
+ }
+
+ base::NativeLibrary egl_library =
+ base::LoadNativeLibrary(base::FilePath(egl_library_name), &error);
+ if (!egl_library) {
+ LOG(WARNING) << "Failed to load EGL library: " << error.ToString();
+ base::UnloadNativeLibrary(gles_library);
+ return false;
+ }
+
+ SurfaceFactoryOzone::GLGetProcAddressProc get_proc_address =
+ reinterpret_cast<SurfaceFactoryOzone::GLGetProcAddressProc>(
+ base::GetFunctionPointerFromNativeLibrary(egl_library,
+ "eglGetProcAddress"));
+ if (!get_proc_address) {
+ LOG(ERROR) << "eglGetProcAddress not found.";
+ base::UnloadNativeLibrary(egl_library);
+ base::UnloadNativeLibrary(gles_library);
+ return false;
+ }
+
+ set_gl_get_proc_address.Run(get_proc_address);
+ add_gl_library.Run(egl_library);
+ add_gl_library.Run(gles_library);
+
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/ozone/common/egl_util.h b/ui/ozone/common/egl_util.h
new file mode 100644
index 0000000..5cdfa42
--- /dev/null
+++ b/ui/ozone/common/egl_util.h
@@ -0,0 +1,26 @@
+// 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.
+
+#ifndef UI_OZONE_COMMON_EGL_UTIL_H_
+#define UI_OZONE_COMMON_EGL_UTIL_H_
+
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace ui {
+
+bool LoadDefaultEGLGLES2Bindings(
+ SurfaceFactoryOzone::AddGLLibraryCallback add_gl_library,
+ SurfaceFactoryOzone::SetGLGetProcAddressProcCallback
+ set_gl_get_proc_address);
+
+bool LoadEGLGLES2Bindings(
+ SurfaceFactoryOzone::AddGLLibraryCallback add_gl_library,
+ SurfaceFactoryOzone::SetGLGetProcAddressProcCallback
+ set_gl_get_proc_address,
+ const char* egl_library_name,
+ const char* gles_library_name);
+
+} // namespace ui
+
+#endif // UI_OZONE_COMMON_EGL_UTIL_H_
diff --git a/ui/ozone/common/gpu/ozone_gpu_message_params.cc b/ui/ozone/common/gpu/ozone_gpu_message_params.cc
new file mode 100644
index 0000000..8460b53
--- /dev/null
+++ b/ui/ozone/common/gpu/ozone_gpu_message_params.cc
@@ -0,0 +1,36 @@
+// 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/common/gpu/ozone_gpu_message_params.h"
+
+#include "ui/gfx/geometry/rect_conversions.h"
+
+namespace ui {
+
+DisplayMode_Params::DisplayMode_Params() {
+}
+
+DisplayMode_Params::~DisplayMode_Params() {}
+
+DisplaySnapshot_Params::DisplaySnapshot_Params() {
+}
+
+DisplaySnapshot_Params::~DisplaySnapshot_Params() {}
+
+OverlayCheck_Params::OverlayCheck_Params() {
+}
+
+OverlayCheck_Params::OverlayCheck_Params(
+ const OverlayCandidatesOzone::OverlaySurfaceCandidate& candidate)
+ : buffer_size(candidate.buffer_size),
+ transform(candidate.transform),
+ format(candidate.format),
+ display_rect(gfx::ToNearestRect(candidate.display_rect)),
+ plane_z_order(candidate.plane_z_order) {
+}
+
+OverlayCheck_Params::~OverlayCheck_Params() {
+}
+
+} // namespace ui
diff --git a/ui/ozone/common/gpu/ozone_gpu_message_params.h b/ui/ozone/common/gpu/ozone_gpu_message_params.h
new file mode 100644
index 0000000..3c87890
--- /dev/null
+++ b/ui/ozone/common/gpu/ozone_gpu_message_params.h
@@ -0,0 +1,65 @@
+// 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.
+
+#ifndef UI_OZONE_COMMON_GPU_OZONE_GPU_MESSAGE_PARAMS_H_
+#define UI_OZONE_COMMON_GPU_OZONE_GPU_MESSAGE_PARAMS_H_
+
+#include <string>
+#include <vector>
+
+#include "ui/display/types/display_constants.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/overlay_transform.h"
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/public/overlay_candidates_ozone.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace ui {
+
+struct OZONE_EXPORT DisplayMode_Params {
+ DisplayMode_Params();
+ ~DisplayMode_Params();
+
+ gfx::Size size;
+ bool is_interlaced = false;
+ float refresh_rate = 0.0f;
+};
+
+struct OZONE_EXPORT DisplaySnapshot_Params {
+ DisplaySnapshot_Params();
+ ~DisplaySnapshot_Params();
+
+ int64_t display_id = 0;
+ gfx::Point origin;
+ gfx::Size physical_size;
+ DisplayConnectionType type = DISPLAY_CONNECTION_TYPE_NONE;
+ bool is_aspect_preserving_scaling = false;
+ bool has_overscan = false;
+ std::string display_name;
+ std::vector<DisplayMode_Params> modes;
+ bool has_current_mode = false;
+ DisplayMode_Params current_mode;
+ bool has_native_mode = false;
+ DisplayMode_Params native_mode;
+ int64_t product_id = 0;
+ std::string string_representation;
+};
+
+struct OZONE_EXPORT OverlayCheck_Params {
+ OverlayCheck_Params();
+ OverlayCheck_Params(
+ const OverlayCandidatesOzone::OverlaySurfaceCandidate& candidate);
+ ~OverlayCheck_Params();
+
+ gfx::Size buffer_size;
+ gfx::OverlayTransform transform = gfx::OVERLAY_TRANSFORM_INVALID;
+ SurfaceFactoryOzone::BufferFormat format = SurfaceFactoryOzone::UNKNOWN;
+ gfx::Rect display_rect;
+ int plane_z_order = 0;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_COMMON_GPU_OZONE_GPU_MESSAGE_PARAMS_H_
diff --git a/ui/ozone/common/native_display_delegate_ozone.cc b/ui/ozone/common/native_display_delegate_ozone.cc
new file mode 100644
index 0000000..a7f7d1f
--- /dev/null
+++ b/ui/ozone/common/native_display_delegate_ozone.cc
@@ -0,0 +1,126 @@
+// 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/common/native_display_delegate_ozone.h"
+
+#include "base/logging.h"
+#include "ui/ozone/common/display_snapshot_proxy.h"
+#include "ui/ozone/common/display_util.h"
+
+namespace ui {
+
+NativeDisplayDelegateOzone::NativeDisplayDelegateOzone() {
+}
+
+NativeDisplayDelegateOzone::~NativeDisplayDelegateOzone() {
+}
+
+void NativeDisplayDelegateOzone::Initialize() {
+ DisplaySnapshot_Params params;
+ if (CreateSnapshotFromCommandLine(¶ms)) {
+ DCHECK_NE(DISPLAY_CONNECTION_TYPE_NONE, params.type);
+ displays_.push_back(new DisplaySnapshotProxy(params));
+ }
+}
+
+void NativeDisplayDelegateOzone::GrabServer() {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateOzone::UngrabServer() {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateOzone::TakeDisplayControl(
+ const DisplayControlCallback& callback) {
+ NOTIMPLEMENTED();
+ callback.Run(false);
+}
+
+void NativeDisplayDelegateOzone::RelinquishDisplayControl(
+ const DisplayControlCallback& callback) {
+ NOTIMPLEMENTED();
+ callback.Run(false);
+}
+
+void NativeDisplayDelegateOzone::SyncWithServer() {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateOzone::SetBackgroundColor(uint32_t color_argb) {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateOzone::ForceDPMSOn() {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateOzone::GetDisplays(
+ const GetDisplaysCallback& callback) {
+ callback.Run(displays_.get());
+}
+
+void NativeDisplayDelegateOzone::AddMode(const ui::DisplaySnapshot& output,
+ const ui::DisplayMode* mode) {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateOzone::Configure(const ui::DisplaySnapshot& output,
+ const ui::DisplayMode* mode,
+ const gfx::Point& origin,
+ const ConfigureCallback& callback) {
+ NOTIMPLEMENTED();
+ callback.Run(true);
+}
+
+void NativeDisplayDelegateOzone::CreateFrameBuffer(const gfx::Size& size) {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateOzone::GetHDCPState(
+ const ui::DisplaySnapshot& output,
+ const GetHDCPStateCallback& callback) {
+ NOTIMPLEMENTED();
+ callback.Run(false, HDCP_STATE_UNDESIRED);
+}
+
+void NativeDisplayDelegateOzone::SetHDCPState(
+ const ui::DisplaySnapshot& output,
+ ui::HDCPState state,
+ const SetHDCPStateCallback& callback) {
+ NOTIMPLEMENTED();
+ callback.Run(false);
+}
+
+std::vector<ui::ColorCalibrationProfile>
+NativeDisplayDelegateOzone::GetAvailableColorCalibrationProfiles(
+ const ui::DisplaySnapshot& output) {
+ NOTIMPLEMENTED();
+ return std::vector<ui::ColorCalibrationProfile>();
+}
+
+bool NativeDisplayDelegateOzone::SetColorCalibrationProfile(
+ const ui::DisplaySnapshot& output,
+ ui::ColorCalibrationProfile new_profile) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool NativeDisplayDelegateOzone::SetGammaRamp(
+ const ui::DisplaySnapshot& output,
+ const std::vector<GammaRampRGBEntry>& lut) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void NativeDisplayDelegateOzone::AddObserver(NativeDisplayObserver* observer) {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateOzone::RemoveObserver(
+ NativeDisplayObserver* observer) {
+ NOTIMPLEMENTED();
+}
+
+} // namespace ui
diff --git a/ui/ozone/common/native_display_delegate_ozone.h b/ui/ozone/common/native_display_delegate_ozone.h
new file mode 100644
index 0000000..e057ea0
--- /dev/null
+++ b/ui/ozone/common/native_display_delegate_ozone.h
@@ -0,0 +1,61 @@
+// 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.
+
+#ifndef UI_OZONE_COMMON_NATIVE_DISPLAY_DELEGATE_OZONE_H_
+#define UI_OZONE_COMMON_NATIVE_DISPLAY_DELEGATE_OZONE_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "ui/display/types/native_display_delegate.h"
+
+namespace ui {
+
+class NativeDisplayDelegateOzone : public NativeDisplayDelegate {
+ public:
+ NativeDisplayDelegateOzone();
+ ~NativeDisplayDelegateOzone() override;
+
+ // NativeDisplayDelegate overrides:
+ void Initialize() override;
+ void GrabServer() override;
+ void UngrabServer() override;
+ void TakeDisplayControl(const DisplayControlCallback& callback) override;
+ void RelinquishDisplayControl(
+ const DisplayControlCallback& callback) override;
+ void SyncWithServer() override;
+ void SetBackgroundColor(uint32_t color_argb) override;
+ void ForceDPMSOn() override;
+ void GetDisplays(const GetDisplaysCallback& callback) override;
+ void AddMode(const ui::DisplaySnapshot& output,
+ const ui::DisplayMode* mode) override;
+ void Configure(const ui::DisplaySnapshot& output,
+ const ui::DisplayMode* mode,
+ const gfx::Point& origin,
+ const ConfigureCallback& callback) override;
+ void CreateFrameBuffer(const gfx::Size& size) override;
+ void GetHDCPState(const ui::DisplaySnapshot& output,
+ const GetHDCPStateCallback& callback) override;
+ void SetHDCPState(const ui::DisplaySnapshot& output,
+ ui::HDCPState state,
+ const SetHDCPStateCallback& callback) override;
+ std::vector<ui::ColorCalibrationProfile> GetAvailableColorCalibrationProfiles(
+ const ui::DisplaySnapshot& output) override;
+ bool SetColorCalibrationProfile(
+ const ui::DisplaySnapshot& output,
+ ui::ColorCalibrationProfile new_profile) override;
+ bool SetGammaRamp(const ui::DisplaySnapshot& output,
+ const std::vector<GammaRampRGBEntry>& lut) override;
+
+ void AddObserver(NativeDisplayObserver* observer) override;
+ void RemoveObserver(NativeDisplayObserver* observer) override;
+
+ private:
+ ScopedVector<DisplaySnapshot> displays_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeDisplayDelegateOzone);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_COMMON_NATIVE_DISPLAY_DELEGATE_OZONE_H_
diff --git a/ui/ozone/common/stub_overlay_manager.cc b/ui/ozone/common/stub_overlay_manager.cc
new file mode 100644
index 0000000..45f8a5f
--- /dev/null
+++ b/ui/ozone/common/stub_overlay_manager.cc
@@ -0,0 +1,25 @@
+// Copyright 2015 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/common/stub_overlay_manager.h"
+#include "ui/ozone/public/overlay_candidates_ozone.h"
+
+namespace ui {
+
+StubOverlayManager::StubOverlayManager() {
+}
+
+StubOverlayManager::~StubOverlayManager() {
+}
+
+scoped_ptr<OverlayCandidatesOzone> StubOverlayManager::CreateOverlayCandidates(
+ gfx::AcceleratedWidget w) {
+ return nullptr;
+}
+
+bool StubOverlayManager::CanShowPrimaryPlaneAsOverlay() {
+ return false;
+}
+
+} // namespace ui
diff --git a/ui/ozone/common/stub_overlay_manager.h b/ui/ozone/common/stub_overlay_manager.h
new file mode 100644
index 0000000..ba72ba0
--- /dev/null
+++ b/ui/ozone/common/stub_overlay_manager.h
@@ -0,0 +1,28 @@
+// Copyright 2015 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.
+
+#ifndef UI_OZONE_COMMON_STUB_OVERLAY_MANAGER_H_
+#define UI_OZONE_COMMON_STUB_OVERLAY_MANAGER_H_
+
+#include "ui/ozone/public/overlay_manager_ozone.h"
+
+namespace ui {
+
+class StubOverlayManager : public OverlayManagerOzone {
+ public:
+ StubOverlayManager();
+ ~StubOverlayManager() override;
+
+ // OverlayManagerOzone:
+ scoped_ptr<OverlayCandidatesOzone> CreateOverlayCandidates(
+ gfx::AcceleratedWidget w) override;
+ bool CanShowPrimaryPlaneAsOverlay() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StubOverlayManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_COMMON_STUB_OVERLAY_MANAGER_H_
diff --git a/ui/ozone/demo/BUILD.gn b/ui/ozone/demo/BUILD.gn
new file mode 100644
index 0000000..ad78f75
--- /dev/null
+++ b/ui/ozone/demo/BUILD.gn
@@ -0,0 +1,39 @@
+# 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.
+
+group("demo") {
+ deps = [
+ ":ozone_demo",
+ ]
+}
+
+executable("ozone_demo") {
+ sources = [
+ "gl_renderer.cc",
+ "gl_renderer.h",
+ "ozone_demo.cc",
+ "renderer.h",
+ "renderer_base.cc",
+ "renderer_base.h",
+ "software_renderer.cc",
+ "software_renderer.h",
+ "surfaceless_gl_renderer.cc",
+ "surfaceless_gl_renderer.h",
+ ]
+
+ deps = [
+ "//base",
+ "//skia",
+ "//ui/events",
+ "//ui/events:dom_keycode_converter",
+ "//ui/events/ozone:events_ozone_layout",
+ "//ui/gfx/geometry",
+ "//ui/gl",
+ "//ui/ozone",
+ "//ui/ozone/gpu",
+ "//ui/ozone:ozone_base",
+ "//ui/display/types",
+ "//ui/platform_window",
+ ]
+}
diff --git a/ui/ozone/demo/gl_renderer.cc b/ui/ozone/demo/gl_renderer.cc
new file mode 100644
index 0000000..73592e4
--- /dev/null
+++ b/ui/ozone/demo/gl_renderer.cc
@@ -0,0 +1,75 @@
+// 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/demo/gl_renderer.h"
+
+#include "base/location.h"
+#include "base/thread_task_runner_handle.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_surface.h"
+
+namespace ui {
+
+GlRenderer::GlRenderer(gfx::AcceleratedWidget widget, const gfx::Size& size)
+ : RendererBase(widget, size), weak_ptr_factory_(this) {
+}
+
+GlRenderer::~GlRenderer() {
+}
+
+bool GlRenderer::Initialize() {
+ surface_ = CreateSurface();
+ if (!surface_.get()) {
+ LOG(ERROR) << "Failed to create GL surface";
+ return false;
+ }
+
+ context_ = gfx::GLContext::CreateGLContext(NULL, surface_.get(),
+ gfx::PreferIntegratedGpu);
+ if (!context_.get()) {
+ LOG(ERROR) << "Failed to create GL context";
+ return false;
+ }
+
+ if (!surface_->Resize(size_)) {
+ LOG(ERROR) << "Failed to resize GL surface";
+ return false;
+ }
+
+ if (!context_->MakeCurrent(surface_.get())) {
+ LOG(ERROR) << "Failed to make GL context current";
+ return false;
+ }
+
+ PostRenderFrameTask(gfx::SwapResult::SWAP_ACK);
+ return true;
+}
+
+void GlRenderer::RenderFrame() {
+ float fraction = NextFraction();
+
+ context_->MakeCurrent(surface_.get());
+
+ glViewport(0, 0, size_.width(), size_.height());
+ glClearColor(1 - fraction, fraction, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ if (!surface_->SwapBuffersAsync(base::Bind(&GlRenderer::PostRenderFrameTask,
+ weak_ptr_factory_.GetWeakPtr())))
+ LOG(FATAL) << "Failed to swap buffers";
+}
+
+void GlRenderer::PostRenderFrameTask(gfx::SwapResult result) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&GlRenderer::RenderFrame, weak_ptr_factory_.GetWeakPtr()));
+}
+
+scoped_refptr<gfx::GLSurface> GlRenderer::CreateSurface() {
+ gfx::SurfaceConfiguration config;
+ return gfx::GLSurface::CreateViewGLSurface(widget_, config);
+}
+
+} // namespace ui
diff --git a/ui/ozone/demo/gl_renderer.h b/ui/ozone/demo/gl_renderer.h
new file mode 100644
index 0000000..80e556b
--- /dev/null
+++ b/ui/ozone/demo/gl_renderer.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef UI_OZONE_DEMO_GL_RENDERER_H_
+#define UI_OZONE_DEMO_GL_RENDERER_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/gfx/swap_result.h"
+#include "ui/ozone/demo/renderer_base.h"
+
+namespace gfx {
+class GLContext;
+class GLSurface;
+} // namespace gfx
+
+namespace ui {
+
+class GlRenderer : public RendererBase {
+ public:
+ GlRenderer(gfx::AcceleratedWidget widget, const gfx::Size& size);
+ ~GlRenderer() override;
+
+ void PostRenderFrameTask(gfx::SwapResult result);
+
+ // Renderer:
+ bool Initialize() override;
+
+ protected:
+ virtual void RenderFrame();
+ virtual scoped_refptr<gfx::GLSurface> CreateSurface();
+
+ scoped_refptr<gfx::GLSurface> surface_;
+ scoped_refptr<gfx::GLContext> context_;
+
+ private:
+ base::WeakPtrFactory<GlRenderer> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(GlRenderer);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_DEMO_GL_RENDERER_H_
diff --git a/ui/ozone/demo/ozone_demo.cc b/ui/ozone/demo/ozone_demo.cc
new file mode 100644
index 0000000..534b914
--- /dev/null
+++ b/ui/ozone/demo/ozone_demo.cc
@@ -0,0 +1,346 @@
+// 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 "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
+#include "ui/display/types/display_snapshot.h"
+#include "ui/display/types/native_display_delegate.h"
+#include "ui/display/types/native_display_observer.h"
+#include "ui/events/event.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/ozone/layout/keyboard_layout_engine.h"
+#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/ozone/demo/gl_renderer.h"
+#include "ui/ozone/demo/software_renderer.h"
+#include "ui/ozone/demo/surfaceless_gl_renderer.h"
+#include "ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h"
+#include "ui/ozone/public/ozone_gpu_test_helper.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/ozone_switches.h"
+#include "ui/platform_window/platform_window.h"
+#include "ui/platform_window/platform_window_delegate.h"
+
+const int kTestWindowWidth = 800;
+const int kTestWindowHeight = 600;
+
+const char kDisableGpu[] = "disable-gpu";
+
+const char kWindowSize[] = "window-size";
+
+class DemoWindow;
+
+class RendererFactory {
+ public:
+ enum RendererType {
+ GL,
+ SURFACELESS_GL,
+ SOFTWARE,
+ };
+
+ RendererFactory();
+ ~RendererFactory();
+
+ bool Initialize();
+ scoped_ptr<ui::Renderer> CreateRenderer(gfx::AcceleratedWidget widget,
+ const gfx::Size& size);
+
+ private:
+ RendererType type_ = SOFTWARE;
+
+ // Helper for applications that do GL on main thread.
+ ui::OzoneGpuTestHelper gpu_helper_;
+
+ // Used by the surfaceless renderers to allocate buffers.
+ ui::GpuMemoryBufferFactoryOzoneNativeBuffer buffer_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(RendererFactory);
+};
+
+class WindowManager : public ui::NativeDisplayObserver {
+ public:
+ WindowManager(const base::Closure& quit_closure);
+ ~WindowManager() override;
+
+ void Quit();
+
+ void AddWindow(DemoWindow* window);
+ void RemoveWindow(DemoWindow* window);
+
+ private:
+ void OnDisplaysAquired(const std::vector<ui::DisplaySnapshot*>& displays);
+ void OnDisplayConfigured(const gfx::Rect& bounds, bool success);
+
+ // ui::NativeDisplayDelegate:
+ void OnConfigurationChanged() override;
+
+ scoped_ptr<ui::NativeDisplayDelegate> delegate_;
+ base::Closure quit_closure_;
+ RendererFactory renderer_factory_;
+ ScopedVector<DemoWindow> windows_;
+
+ // Flags used to keep track of the current state of display configuration.
+ //
+ // True if configuring the displays. In this case a new display configuration
+ // isn't started.
+ bool is_configuring_ = false;
+
+ // If |is_configuring_| is true and another display configuration event
+ // happens, the event is deferred. This is set to true and a display
+ // configuration will be scheduled after the current one finishes.
+ bool should_configure_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowManager);
+};
+
+class DemoWindow : public ui::PlatformWindowDelegate {
+ public:
+ DemoWindow(WindowManager* window_manager,
+ RendererFactory* renderer_factory,
+ const gfx::Rect& bounds)
+ : window_manager_(window_manager),
+ renderer_factory_(renderer_factory),
+ weak_ptr_factory_(this) {
+ platform_window_ =
+ ui::OzonePlatform::GetInstance()->CreatePlatformWindow(this, bounds);
+ }
+ ~DemoWindow() override {}
+
+ gfx::AcceleratedWidget GetAcceleratedWidget() {
+ // TODO(spang): We should start rendering asynchronously.
+ DCHECK_NE(widget_, gfx::kNullAcceleratedWidget)
+ << "Widget not available synchronously";
+ return widget_;
+ }
+
+ gfx::Size GetSize() { return platform_window_->GetBounds().size(); }
+
+ void Start() {
+ LOG(INFO) << "DemoWindow::Start";
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&DemoWindow::StartOnGpu, weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ void Quit() {
+ window_manager_->Quit();
+ }
+
+ // PlatformWindowDelegate:
+ void OnBoundsChanged(const gfx::Rect& new_bounds) override {}
+ void OnDamageRect(const gfx::Rect& damaged_region) override {}
+ void DispatchEvent(ui::Event* event) override {
+ if (event->IsKeyEvent() &&
+ static_cast<ui::KeyEvent*>(event)->code() == ui::DomCode::KEY_Q)
+ Quit();
+ }
+ void OnCloseRequest() override { Quit(); }
+ void OnClosed() override {}
+ void OnWindowStateChanged(ui::PlatformWindowState new_state) override {}
+ void OnLostCapture() override {}
+ void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) override {
+ LOG(INFO) << "OnAcceleratedWidgetAvailable " << widget;
+ DCHECK_NE(widget, gfx::kNullAcceleratedWidget);
+ widget_ = widget;
+ }
+ void OnActivationChanged(bool active) override {}
+
+ private:
+ // Since we pretend to have a GPU process, we should also pretend to
+ // initialize the GPU resources via a posted task.
+ void StartOnGpu() {
+ LOG(INFO) << "StartOnGPU";
+ gfx::GLSurface::InitializeOneOff();
+
+ renderer_ =
+ renderer_factory_->CreateRenderer(GetAcceleratedWidget(), GetSize());
+ renderer_->Initialize();
+ }
+
+ WindowManager* window_manager_; // Not owned.
+ RendererFactory* renderer_factory_; // Not owned.
+
+ scoped_ptr<ui::Renderer> renderer_;
+
+ // Window-related state.
+ scoped_ptr<ui::PlatformWindow> platform_window_;
+ gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget;
+
+ base::WeakPtrFactory<DemoWindow> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DemoWindow);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// RendererFactory implementation:
+
+RendererFactory::RendererFactory() {
+}
+
+RendererFactory::~RendererFactory() {
+}
+
+bool RendererFactory::Initialize() {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (!command_line->HasSwitch(kDisableGpu) &&
+ gpu_helper_.Initialize(base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get())) {
+ if (command_line->HasSwitch(switches::kOzoneUseSurfaceless)) {
+ type_ = SURFACELESS_GL;
+ } else {
+ type_ = GL;
+ }
+ } else {
+ type_ = SOFTWARE;
+ }
+
+ return true;
+}
+
+scoped_ptr<ui::Renderer> RendererFactory::CreateRenderer(
+ gfx::AcceleratedWidget widget,
+ const gfx::Size& size) {
+ switch (type_) {
+ case GL:
+ return make_scoped_ptr(new ui::GlRenderer(widget, size));
+ case SURFACELESS_GL:
+ return make_scoped_ptr(
+ new ui::SurfacelessGlRenderer(widget, size, &buffer_factory_));
+ case SOFTWARE:
+ return make_scoped_ptr(new ui::SoftwareRenderer(widget, size));
+ }
+
+ return nullptr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowManager implementation:
+
+WindowManager::WindowManager(const base::Closure& quit_closure)
+ : delegate_(
+ ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate()),
+ quit_closure_(quit_closure) {
+ if (!renderer_factory_.Initialize())
+ LOG(FATAL) << "Failed to initialize renderer factory";
+
+ LOG(INFO) << "WindowManager() " << delegate_;
+
+ if (delegate_) {
+ delegate_->AddObserver(this);
+ delegate_->Initialize();
+ OnConfigurationChanged();
+ } else {
+ LOG(WARNING) << "No display delegate; falling back to test window";
+ int width = kTestWindowWidth;
+ int height = kTestWindowHeight;
+ sscanf(base::CommandLine::ForCurrentProcess()
+ ->GetSwitchValueASCII(kWindowSize)
+ .c_str(),
+ "%dx%d", &width, &height);
+
+ DemoWindow* window = new DemoWindow(this, &renderer_factory_,
+ gfx::Rect(gfx::Size(width, height)));
+ window->Start();
+ }
+}
+
+WindowManager::~WindowManager() {
+ if (delegate_)
+ delegate_->RemoveObserver(this);
+}
+
+void WindowManager::Quit() {
+ quit_closure_.Run();
+}
+
+void WindowManager::OnConfigurationChanged() {
+ if (is_configuring_) {
+ should_configure_ = true;
+ return;
+ }
+
+ is_configuring_ = true;
+ delegate_->GrabServer();
+ delegate_->GetDisplays(
+ base::Bind(&WindowManager::OnDisplaysAquired, base::Unretained(this)));
+}
+
+void WindowManager::OnDisplaysAquired(
+ const std::vector<ui::DisplaySnapshot*>& displays) {
+ windows_.clear();
+
+ gfx::Point origin;
+ for (auto display : displays) {
+ if (!display->native_mode()) {
+ LOG(ERROR) << "Display " << display->display_id()
+ << " doesn't have a native mode";
+ continue;
+ }
+
+ delegate_->Configure(
+ *display, display->native_mode(), origin,
+ base::Bind(&WindowManager::OnDisplayConfigured, base::Unretained(this),
+ gfx::Rect(origin, display->native_mode()->size())));
+ origin.Offset(display->native_mode()->size().width(), 0);
+ }
+ delegate_->UngrabServer();
+ is_configuring_ = false;
+
+ if (should_configure_) {
+ should_configure_ = false;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&WindowManager::OnConfigurationChanged,
+ base::Unretained(this)));
+ }
+}
+
+void WindowManager::OnDisplayConfigured(const gfx::Rect& bounds, bool success) {
+ LOG(INFO) << "OnDisplayConfigured " << success;
+ if (success) {
+ scoped_ptr<DemoWindow> window(
+ new DemoWindow(this, &renderer_factory_, bounds));
+ window->Start();
+ windows_.push_back(window.Pass());
+ } else {
+ LOG(ERROR) << "Failed to configure display at " << bounds.ToString();
+ }
+}
+
+int main(int argc, char** argv) {
+ base::CommandLine::Init(argc, argv);
+ base::AtExitManager exit_manager;
+
+ // Initialize logging so we can enable VLOG messages.
+ logging::LoggingSettings settings;
+ logging::InitLogging(settings);
+
+ // Build UI thread message loop. This is used by platform
+ // implementations for event polling & running background tasks.
+ base::MessageLoopForUI message_loop;
+
+ ui::OzonePlatform::InitializeForUI();
+ LOG(INFO) << "InitializeForUI complete";
+
+ ui::OzonePlatform::InitializeForGPU();
+ LOG(INFO) << "InitializeForGPU complete";
+
+ ui::KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()
+ ->SetCurrentLayoutByName("us");
+
+ base::RunLoop run_loop;
+
+ WindowManager window_manager(run_loop.QuitClosure());
+
+ LOG(INFO) << "demo entering run loop";
+ run_loop.Run();
+ LOG(INFO) << "demo returning from run loop";
+
+ return 0;
+}
diff --git a/ui/ozone/demo/renderer.h b/ui/ozone/demo/renderer.h
new file mode 100644
index 0000000..30d86af
--- /dev/null
+++ b/ui/ozone/demo/renderer.h
@@ -0,0 +1,19 @@
+// 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.
+
+#ifndef UI_OZONE_DEMO_RENDERER_H_
+#define UI_OZONE_DEMO_RENDERER_H_
+
+namespace ui {
+
+class Renderer {
+ public:
+ virtual ~Renderer() {}
+
+ virtual bool Initialize() = 0;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_DEMO_RENDERER_H_
diff --git a/ui/ozone/demo/renderer_base.cc b/ui/ozone/demo/renderer_base.cc
new file mode 100644
index 0000000..9d7d6e2
--- /dev/null
+++ b/ui/ozone/demo/renderer_base.cc
@@ -0,0 +1,29 @@
+// 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/demo/renderer_base.h"
+
+namespace ui {
+
+namespace {
+const int kAnimationSteps = 240;
+} // namespace
+
+RendererBase::RendererBase(gfx::AcceleratedWidget widget, const gfx::Size& size)
+ : widget_(widget), size_(size) {
+}
+
+RendererBase::~RendererBase() {
+}
+
+float RendererBase::NextFraction() {
+ float fraction = (sinf(iteration_ * 2 * M_PI / kAnimationSteps) + 1) / 2;
+
+ iteration_++;
+ iteration_ %= kAnimationSteps;
+
+ return fraction;
+}
+
+} // namespace ui
diff --git a/ui/ozone/demo/renderer_base.h b/ui/ozone/demo/renderer_base.h
new file mode 100644
index 0000000..8d7acd5
--- /dev/null
+++ b/ui/ozone/demo/renderer_base.h
@@ -0,0 +1,30 @@
+// 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.
+
+#ifndef UI_OZONE_DEMO_RENDERER_BASE_H_
+#define UI_OZONE_DEMO_RENDERER_BASE_H_
+
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/demo/renderer.h"
+
+namespace ui {
+
+class RendererBase : public Renderer {
+ public:
+ RendererBase(gfx::AcceleratedWidget widget, const gfx::Size& size);
+ ~RendererBase() override;
+
+ protected:
+ float NextFraction();
+
+ gfx::AcceleratedWidget widget_;
+ gfx::Size size_;
+
+ int iteration_ = 0;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_DEMO_RENDERER_BASE_H_
diff --git a/ui/ozone/demo/software_renderer.cc b/ui/ozone/demo/software_renderer.cc
new file mode 100644
index 0000000..162d5e0
--- /dev/null
+++ b/ui/ozone/demo/software_renderer.cc
@@ -0,0 +1,72 @@
+// 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/demo/software_renderer.h"
+
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/gfx/vsync_provider.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+
+namespace ui {
+namespace {
+
+const int kFrameDelayMilliseconds = 16;
+
+} // namespace
+
+SoftwareRenderer::SoftwareRenderer(gfx::AcceleratedWidget widget,
+ const gfx::Size& size)
+ : RendererBase(widget, size),
+ vsync_period_(base::TimeDelta::FromMilliseconds(kFrameDelayMilliseconds)),
+ weak_ptr_factory_(this) {
+}
+
+SoftwareRenderer::~SoftwareRenderer() {
+}
+
+bool SoftwareRenderer::Initialize() {
+ software_surface_ = ui::OzonePlatform::GetInstance()
+ ->GetSurfaceFactoryOzone()
+ ->CreateCanvasForWidget(widget_);
+ if (!software_surface_) {
+ LOG(ERROR) << "Failed to create software surface";
+ return false;
+ }
+
+ software_surface_->ResizeCanvas(size_);
+ vsync_provider_ = software_surface_->CreateVSyncProvider();
+ RenderFrame();
+ return true;
+}
+
+void SoftwareRenderer::RenderFrame() {
+ float fraction = NextFraction();
+
+ skia::RefPtr<SkSurface> surface = software_surface_->GetSurface();
+
+ SkColor color =
+ SkColorSetARGB(0xff, 0, 0xff * fraction, 0xff * (1 - fraction));
+
+ surface->getCanvas()->clear(color);
+
+ software_surface_->PresentCanvas(gfx::Rect(size_));
+
+ if (vsync_provider_) {
+ vsync_provider_->GetVSyncParameters(
+ base::Bind(&SoftwareRenderer::UpdateVSyncParameters,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ timer_.Start(FROM_HERE, vsync_period_, this, &SoftwareRenderer::RenderFrame);
+}
+
+void SoftwareRenderer::UpdateVSyncParameters(const base::TimeTicks timebase,
+ const base::TimeDelta interval) {
+ vsync_period_ = interval;
+}
+
+} // namespace ui
diff --git a/ui/ozone/demo/software_renderer.h b/ui/ozone/demo/software_renderer.h
new file mode 100644
index 0000000..dcb4645
--- /dev/null
+++ b/ui/ozone/demo/software_renderer.h
@@ -0,0 +1,52 @@
+// 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.
+
+#ifndef UI_OZONE_DEMO_SOFTWARE_RENDERER_H_
+#define UI_OZONE_DEMO_SOFTWARE_RENDERER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "ui/ozone/demo/renderer_base.h"
+
+namespace gfx {
+class VSyncProvider;
+} // namespace gfx
+
+namespace ui {
+
+class SurfaceOzoneCanvas;
+
+class SoftwareRenderer : public RendererBase {
+ public:
+ SoftwareRenderer(gfx::AcceleratedWidget widget, const gfx::Size& size);
+ ~SoftwareRenderer() override;
+
+ // Renderer:
+ bool Initialize() override;
+
+ private:
+ void RenderFrame();
+
+ void UpdateVSyncParameters(const base::TimeTicks timebase,
+ const base::TimeDelta interval);
+
+ scoped_ptr<SurfaceOzoneCanvas> software_surface_;
+
+ scoped_ptr<gfx::VSyncProvider> vsync_provider_;
+
+ // Timer for animation.
+ base::RepeatingTimer<SoftwareRenderer> timer_;
+
+ base::TimeDelta vsync_period_;
+
+ base::WeakPtrFactory<SoftwareRenderer> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SoftwareRenderer);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_DEMO_SOFTWARE_RENDERER_H_
diff --git a/ui/ozone/demo/surfaceless_gl_renderer.cc b/ui/ozone/demo/surfaceless_gl_renderer.cc
new file mode 100644
index 0000000..f6f7060
--- /dev/null
+++ b/ui/ozone/demo/surfaceless_gl_renderer.cc
@@ -0,0 +1,130 @@
+// 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/demo/surfaceless_gl_renderer.h"
+
+#include "base/bind.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_image.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h"
+
+namespace ui {
+
+SurfacelessGlRenderer::BufferWrapper::BufferWrapper() {
+}
+
+SurfacelessGlRenderer::BufferWrapper::~BufferWrapper() {
+ if (gl_fb_)
+ glDeleteFramebuffersEXT(1, &gl_fb_);
+
+ if (gl_tex_) {
+ image_->ReleaseTexImage(GL_TEXTURE_2D);
+ glDeleteTextures(1, &gl_tex_);
+ image_->Destroy(true);
+ }
+}
+
+bool SurfacelessGlRenderer::BufferWrapper::Initialize(
+ GpuMemoryBufferFactoryOzoneNativeBuffer* buffer_factory,
+ gfx::AcceleratedWidget widget,
+ const gfx::Size& size) {
+ glGenFramebuffersEXT(1, &gl_fb_);
+ glGenTextures(1, &gl_tex_);
+
+ static int buffer_id_generator = 1;
+ int id = buffer_id_generator++;
+
+ buffer_factory->CreateGpuMemoryBuffer(
+ id, size, gfx::GpuMemoryBuffer::RGBX_8888, gfx::GpuMemoryBuffer::SCANOUT,
+ 1, widget);
+ image_ = buffer_factory->CreateImageForGpuMemoryBuffer(
+ id, size, gfx::GpuMemoryBuffer::RGBX_8888, GL_RGB, 1);
+ // Now that we have a reference to |image_|; we can just remove it from the
+ // factory mapping.
+ buffer_factory->DestroyGpuMemoryBuffer(id, widget);
+
+ if (!image_) {
+ LOG(ERROR) << "Failed to create GL image";
+ return false;
+ }
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER, gl_fb_);
+ glBindTexture(GL_TEXTURE_2D, gl_tex_);
+ image_->BindTexImage(GL_TEXTURE_2D);
+
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ gl_tex_, 0);
+ if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+ LOG(ERROR) << "Failed to create framebuffer "
+ << glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
+ return false;
+ }
+
+ widget_ = widget;
+ size_ = size;
+
+ return true;
+}
+
+void SurfacelessGlRenderer::BufferWrapper::BindFramebuffer() {
+ glBindFramebufferEXT(GL_FRAMEBUFFER, gl_fb_);
+}
+
+void SurfacelessGlRenderer::BufferWrapper::SchedulePlane() {
+ image_->ScheduleOverlayPlane(widget_, 0, gfx::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(size_), gfx::RectF(0, 0, 1, 1));
+}
+
+SurfacelessGlRenderer::SurfacelessGlRenderer(
+ gfx::AcceleratedWidget widget,
+ const gfx::Size& size,
+ GpuMemoryBufferFactoryOzoneNativeBuffer* buffer_factory)
+ : GlRenderer(widget, size),
+ buffer_factory_(buffer_factory),
+ weak_ptr_factory_(this) {
+}
+
+SurfacelessGlRenderer::~SurfacelessGlRenderer() {
+ // Need to make current when deleting the framebuffer resources allocated in
+ // the buffers.
+ context_->MakeCurrent(surface_.get());
+}
+
+bool SurfacelessGlRenderer::Initialize() {
+ if (!GlRenderer::Initialize())
+ return false;
+
+ for (size_t i = 0; i < arraysize(buffers_); ++i)
+ if (!buffers_[i].Initialize(buffer_factory_, widget_, size_))
+ return false;
+
+ PostRenderFrameTask(gfx::SwapResult::SWAP_ACK);
+ return true;
+}
+
+void SurfacelessGlRenderer::RenderFrame() {
+ float fraction = NextFraction();
+
+ context_->MakeCurrent(surface_.get());
+ buffers_[back_buffer_].BindFramebuffer();
+
+ glViewport(0, 0, size_.width(), size_.height());
+ glClearColor(1 - fraction, fraction, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ buffers_[back_buffer_].SchedulePlane();
+ back_buffer_ ^= 1;
+ if (!surface_->SwapBuffersAsync(base::Bind(&GlRenderer::PostRenderFrameTask,
+ weak_ptr_factory_.GetWeakPtr())))
+ LOG(FATAL) << "Failed to swap buffers";
+}
+
+scoped_refptr<gfx::GLSurface> SurfacelessGlRenderer::CreateSurface() {
+ gfx::SurfaceConfiguration config;
+ return gfx::GLSurface::CreateSurfacelessViewGLSurface(widget_, config);
+}
+
+} // namespace ui
diff --git a/ui/ozone/demo/surfaceless_gl_renderer.h b/ui/ozone/demo/surfaceless_gl_renderer.h
new file mode 100644
index 0000000..de5a689
--- /dev/null
+++ b/ui/ozone/demo/surfaceless_gl_renderer.h
@@ -0,0 +1,66 @@
+// 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.
+
+#ifndef UI_OZONE_DEMO_SURFACELESS_GL_RENDERER_H_
+#define UI_OZONE_DEMO_SURFACELESS_GL_RENDERER_H_
+
+#include "ui/ozone/demo/gl_renderer.h"
+
+namespace gfx {
+class GLImage;
+} // namespace gfx
+
+namespace ui {
+
+class GpuMemoryBufferFactoryOzoneNativeBuffer;
+
+class SurfacelessGlRenderer : public GlRenderer {
+ public:
+ SurfacelessGlRenderer(
+ gfx::AcceleratedWidget widget,
+ const gfx::Size& size,
+ GpuMemoryBufferFactoryOzoneNativeBuffer* buffer_factory);
+ ~SurfacelessGlRenderer() override;
+
+ // Renderer:
+ bool Initialize() override;
+
+ private:
+ // GlRenderer:
+ void RenderFrame() override;
+ scoped_refptr<gfx::GLSurface> CreateSurface() override;
+
+ class BufferWrapper {
+ public:
+ BufferWrapper();
+ ~BufferWrapper();
+
+ bool Initialize(GpuMemoryBufferFactoryOzoneNativeBuffer* buffer_factory,
+ gfx::AcceleratedWidget widget,
+ const gfx::Size& size);
+ void BindFramebuffer();
+ void SchedulePlane();
+
+ private:
+ gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget;
+ gfx::Size size_;
+
+ scoped_refptr<gfx::GLImage> image_;
+ unsigned int gl_fb_ = 0;
+ unsigned int gl_tex_ = 0;
+ };
+
+ GpuMemoryBufferFactoryOzoneNativeBuffer* buffer_factory_;
+
+ BufferWrapper buffers_[2];
+ int back_buffer_ = 0;
+
+ base::WeakPtrFactory<SurfacelessGlRenderer> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SurfacelessGlRenderer);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_DEMO_SURFACELESS_GL_RENDERER_H_
diff --git a/ui/ozone/generate_constructor_list.py b/ui/ozone/generate_constructor_list.py
new file mode 100755
index 0000000..02945b3
--- /dev/null
+++ b/ui/ozone/generate_constructor_list.py
@@ -0,0 +1,173 @@
+#!/usr/bin/env python
+# 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.
+
+"""Code generator for PlatformObject<> constructor list.
+
+This script takes as arguments a list of platform names as a text file and
+a list of types and generates a C++ source file containing a list of
+the constructors for that object in platform order.
+
+Example Output: ./ui/ozone/generate_constructor_list.py \
+ --platform test \
+ --platform dri \
+ --export OZONE_EXPORT \
+ --namespace ui \
+ --typename OzonePlatform \
+ --include '"ui/ozone/ozone_platform.h"'
+
+ // DO NOT MODIFY. GENERATED BY generate_constructor_list.py
+
+ #include "ui/ozone/platform_object_internal.h"
+
+ #include "ui/ozone/ozone_platform.h"
+
+ namespace ui {
+
+ OzonePlatform* CreateOzonePlatformTest();
+ OzonePlatform* CreateOzonePlatformDri();
+
+ } // namespace ui
+
+ namespace ui {
+
+ typedef ui::OzonePlatform* (*OzonePlatformConstructor)();
+
+ template <> const OzonePlatformConstructor
+ PlatformConstructorList<ui::OzonePlatform>::kConstructors[] = {
+ &ui::CreateOzonePlatformTest,
+ &ui::CreateOzonePlatformDri,
+ };
+
+ template class OZONE_EXPORT PlatformObject<ui::OzonePlatform>;
+
+ } // namespace ui
+"""
+
+import optparse
+import os
+import collections
+import re
+import sys
+import string
+
+
+def GetTypedefName(typename):
+ """Determine typedef name of constructor for typename.
+
+ This is just typename + "Constructor".
+ """
+
+ return typename + 'Constructor'
+
+
+def GetConstructorName(typename, platform):
+ """Determine name of static constructor function from platform name.
+
+ This is just "Create" + typename + platform.
+ """
+
+ return 'Create' + typename + string.capitalize(platform)
+
+
+def GenerateConstructorList(out, namespace, export, typenames, platforms,
+ includes):
+ """Generate static array containing a list of constructors."""
+
+ out.write('// DO NOT MODIFY. GENERATED BY generate_constructor_list.py\n')
+ out.write('\n')
+
+ out.write('#include "ui/ozone/platform_object_internal.h"\n')
+ out.write('\n')
+
+ for include in includes:
+ out.write('#include %(include)s\n' % {'include': include})
+ out.write('\n')
+
+ out.write('namespace %(namespace)s {\n' % {'namespace': namespace})
+ out.write('\n')
+
+ # Declarations of constructor functions.
+ for typename in typenames:
+ for platform in platforms:
+ constructor = GetConstructorName(typename, platform)
+ out.write('%(typename)s* %(constructor)s();\n'
+ % {'typename': typename,
+ 'constructor': constructor})
+ out.write('\n')
+
+ out.write('} // namespace %(namespace)s\n' % {'namespace': namespace})
+ out.write('\n')
+
+ out.write('namespace ui {\n')
+ out.write('\n')
+
+ # Handy typedefs for constructor types.
+ for typename in typenames:
+ out.write('typedef %(typename)s* (*%(typedef)s)();\n'
+ % {'typename': namespace + '::' + typename,
+ 'typedef': GetTypedefName(typename)})
+ out.write('\n')
+
+ # The actual constructor lists.
+ for typename in typenames:
+ out.write('template <> const %(typedef)s\n'
+ % {'typedef': GetTypedefName(typename)})
+ out.write('PlatformConstructorList<%(typename)s>::kConstructors[] = {\n'
+ % {'typename': namespace + '::' + typename})
+ for platform in platforms:
+ constructor = GetConstructorName(typename, platform)
+ out.write(' &%(namespace)s::%(constructor)s,\n'
+ % {'namespace': namespace, 'constructor': constructor})
+ out.write('};\n')
+ out.write('\n')
+
+ # Exported template instantiation.
+ for typename in typenames:
+ out.write('template class %(export)s PlatformObject<%(typename)s>;\n'
+ % {'export': export, 'typename': namespace + '::' + typename})
+ out.write('\n')
+
+ out.write('} // namespace ui\n')
+ out.write('\n')
+
+
+def main(argv):
+ parser = optparse.OptionParser()
+ parser.add_option('--namespace', default='ozone')
+ parser.add_option('--export', default='OZONE_EXPORT')
+ parser.add_option('--platform_list')
+ parser.add_option('--output_cc')
+ parser.add_option('--include', action='append', default=[])
+ parser.add_option('--platform', action='append', default=[])
+ parser.add_option('--typename', action='append', default=[])
+ options, _ = parser.parse_args(argv)
+
+ platforms = list(options.platform)
+ typenames = list(options.typename)
+ includes = list(options.include)
+
+ if options.platform_list:
+ platforms = open(options.platform_list, 'r').read().strip().split('\n')
+
+ if not platforms:
+ sys.stderr.write('No platforms are selected!')
+ sys.exit(1)
+
+ # Write to standard output or file specified by --output_cc.
+ out_cc = sys.stdout
+ if options.output_cc:
+ out_cc = open(options.output_cc, 'wb')
+
+ GenerateConstructorList(out_cc, options.namespace, options.export,
+ typenames, platforms, includes)
+
+ if options.output_cc:
+ out_cc.close()
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
diff --git a/ui/ozone/generate_ozone_platform_list.py b/ui/ozone/generate_ozone_platform_list.py
new file mode 100755
index 0000000..d47c398
--- /dev/null
+++ b/ui/ozone/generate_ozone_platform_list.py
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+# Copyright 2013 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.
+
+"""Code generator for Ozone platform list.
+
+This script takes as arguments a list of platform names and generates a C++
+source file containing a list of those platforms.
+
+Each platform gets an integer identifier that is used to find objects for that
+platform (particularly constructors for platform-specific objects).
+
+Example Output: ./generate_ozone_platform_list.py --default wayland dri wayland
+
+ // platform_list.txt
+
+ wayland
+ dri
+
+ // platform_list.h
+
+ #ifndef UI_OZONE_PLATFORM_LIST_H_
+ #define UI_OZONE_PLATFORM_LIST_H_
+
+ namespace ui {
+
+ const int kPlatformWayland = 0;
+ const int kPlatformDri = 1;
+
+ extern const char *kPlatformNames[kPlatformCount];
+
+ } // namespace ui
+
+ // platform_list.cc
+
+ #include "ui/ozone/platform_list.h"
+
+ namespace ui {
+
+ const char *kPlatformNames[] = {
+ "wayland", // kPlatformWayland
+ "dri", // kPlatformDri
+ };
+
+ } // namespace ui
+
+ #endif // UI_OZONE_PLATFORM_LIST_H_
+
+"""
+
+import optparse
+import os
+import collections
+import re
+import sys
+import string
+
+
+def GetConstantName(name):
+ """Determine name of static constructor function from platform name.
+
+ We just capitalize the platform name and prepend "CreateOzonePlatform".
+ """
+
+ return 'kPlatform' + string.capitalize(name)
+
+
+def GeneratePlatformListText(out, platforms):
+ """Generate text file with list of platform names, in platform id order."""
+
+ for platform in platforms:
+ out.write(platform)
+ out.write('\n')
+
+ out.write('\n')
+
+
+def GeneratePlatformListHeader(out, platforms):
+ """Generate ids of ozone platforms & declaration of static names array."""
+
+ out.write('// DO NOT MODIFY. GENERATED BY generate_ozone_platform_list.py\n')
+ out.write('\n')
+
+ out.write('#ifndef UI_OZONE_PLATFORM_LIST_H_\n')
+ out.write('#define UI_OZONE_PLATFORM_LIST_H_\n')
+ out.write('\n')
+
+ out.write('namespace ui {\n')
+ out.write('\n')
+
+ # Prototypes for platform initializers.
+ for plat_id, plat_name in enumerate(platforms):
+ out.write('const int %s = %d;\n' % (GetConstantName(plat_name), plat_id))
+ out.write('\n')
+
+ # Platform count.
+ out.write('const int kPlatformCount = %d;\n' % len(platforms))
+ out.write('\n')
+
+ # Declaration for names list.
+ out.write('extern const char* kPlatformNames[kPlatformCount];\n')
+ out.write('\n')
+
+ out.write('} // namespace ui\n')
+ out.write('\n')
+
+ out.write('#endif // UI_OZONE_PLATFORM_LIST_H_\n')
+ out.write('\n')
+
+
+def GeneratePlatformListSource(out, platforms):
+ """Generate static array containing a list of ozone platforms."""
+
+ out.write('// DO NOT MODIFY. GENERATED BY generate_ozone_platform_list.py\n')
+ out.write('\n')
+
+ out.write('#include "ui/ozone/platform_list.h"\n')
+ out.write('\n')
+
+ out.write('namespace ui {\n')
+ out.write('\n')
+
+ # Definition of names list.
+ out.write('const char* kPlatformNames[] = {\n')
+
+ # Prototypes for platform initializers.
+ for plat_name in platforms:
+ out.write(' "%s", // %s\n' % (plat_name, GetConstantName(plat_name)))
+ out.write('};\n')
+ out.write('\n')
+
+ out.write('} // namespace ui\n')
+ out.write('\n')
+
+
+def main(argv):
+ parser = optparse.OptionParser()
+ parser.add_option('--output_cc')
+ parser.add_option('--output_h')
+ parser.add_option('--output_txt')
+ parser.add_option('--default')
+ options, platforms = parser.parse_args(argv)
+
+ # Reorder the platforms when --default is specified.
+ # The default platform must appear first in the platform list.
+ if options.default and options.default in platforms:
+ platforms.remove(options.default)
+ platforms.insert(0, options.default)
+
+ # Write to standard output or file specified by --output_{cc,h}.
+ out_cc = sys.stdout
+ out_h = sys.stdout
+ out_txt = sys.stdout
+ if options.output_cc:
+ out_cc = open(options.output_cc, 'wb')
+ if options.output_h:
+ out_h = open(options.output_h, 'wb')
+ if options.output_txt:
+ out_txt = open(options.output_txt, 'wb')
+
+ GeneratePlatformListText(out_txt, platforms)
+ GeneratePlatformListHeader(out_h, platforms)
+ GeneratePlatformListSource(out_cc, platforms)
+
+ if options.output_cc:
+ out_cc.close()
+ if options.output_h:
+ out_h.close()
+ if options.output_txt:
+ out_txt.close()
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
diff --git a/ui/ozone/gpu/BUILD.gn b/ui/ozone/gpu/BUILD.gn
new file mode 100644
index 0000000..90e06bc
--- /dev/null
+++ b/ui/ozone/gpu/BUILD.gn
@@ -0,0 +1,23 @@
+# 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.
+
+component("gpu") {
+ output_name = "ozone_gpu"
+
+ sources = [
+ "gpu_memory_buffer_factory_ozone_native_buffer.cc",
+ "gpu_memory_buffer_factory_ozone_native_buffer.h",
+ ]
+
+ defines = [ "OZONE_GPU_IMPLEMENTATION" ]
+
+ deps = [
+ "//base",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ "//ui/gl",
+ "//ui/ozone",
+ "//ui/ozone:ozone_base",
+ ]
+}
diff --git a/ui/ozone/gpu/README b/ui/ozone/gpu/README
new file mode 100644
index 0000000..7f96a44
--- /dev/null
+++ b/ui/ozone/gpu/README
@@ -0,0 +1 @@
+This component contains support code for content/common/gpu.
diff --git a/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc b/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc
new file mode 100644
index 0000000..0a08873
--- /dev/null
+++ b/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc
@@ -0,0 +1,211 @@
+// 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/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h"
+
+#include "base/logging.h"
+#include "ui/gl/gl_image_egl.h"
+#include "ui/gl/gl_image_linux_dma_buffer.h"
+#include "ui/ozone/public/native_pixmap.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+namespace ui {
+namespace {
+class GLImageOzoneNativePixmap : public gfx::GLImageEGL {
+ public:
+ explicit GLImageOzoneNativePixmap(const gfx::Size& size) : GLImageEGL(size) {}
+
+ void Destroy(bool have_context) override {
+ gfx::GLImageEGL::Destroy(have_context);
+ pixmap_ = nullptr;
+ }
+
+ bool Initialize(NativePixmap* pixmap) {
+ EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+ if (!Initialize(EGL_NATIVE_PIXMAP_KHR, pixmap->GetEGLClientBuffer(), attrs))
+ return false;
+ pixmap_ = pixmap;
+ return true;
+ }
+
+ bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
+ int z_order,
+ gfx::OverlayTransform transform,
+ const gfx::Rect& bounds_rect,
+ const gfx::RectF& crop_rect) override {
+ return pixmap_->ScheduleOverlayPlane(widget, z_order, transform,
+ bounds_rect, crop_rect);
+ }
+
+ protected:
+ ~GLImageOzoneNativePixmap() override {}
+
+ private:
+ using gfx::GLImageEGL::Initialize;
+ scoped_refptr<NativePixmap> pixmap_;
+};
+
+class GLImageOzoneNativePixmapDmaBuf : public gfx::GLImageLinuxDMABuffer {
+ public:
+ explicit GLImageOzoneNativePixmapDmaBuf(const gfx::Size& size,
+ unsigned internalformat)
+ : GLImageLinuxDMABuffer(size, internalformat) {}
+
+ void Destroy(bool have_context) override {
+ gfx::GLImageLinuxDMABuffer::Destroy(have_context);
+ pixmap_ = nullptr;
+ }
+
+ bool Initialize(NativePixmap* pixmap, gfx::GpuMemoryBuffer::Format format) {
+ base::FileDescriptor handle(pixmap->GetDmaBufFd(), false);
+ if (!GLImageLinuxDMABuffer::Initialize(handle, format,
+ pixmap->GetDmaBufPitch()))
+ return false;
+ pixmap_ = pixmap;
+ return true;
+ }
+
+ bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
+ int z_order,
+ gfx::OverlayTransform transform,
+ const gfx::Rect& bounds_rect,
+ const gfx::RectF& crop_rect) override {
+ return pixmap_->ScheduleOverlayPlane(widget, z_order, transform,
+ bounds_rect, crop_rect);
+ }
+
+ protected:
+ ~GLImageOzoneNativePixmapDmaBuf() override {}
+
+ private:
+ scoped_refptr<NativePixmap> pixmap_;
+};
+
+SurfaceFactoryOzone::BufferFormat GetOzoneFormatFor(
+ gfx::GpuMemoryBuffer::Format format) {
+ switch (format) {
+ case gfx::GpuMemoryBuffer::BGRA_8888:
+ return SurfaceFactoryOzone::BGRA_8888;
+ case gfx::GpuMemoryBuffer::RGBX_8888:
+ return SurfaceFactoryOzone::RGBX_8888;
+ case gfx::GpuMemoryBuffer::ATC:
+ case gfx::GpuMemoryBuffer::ATCIA:
+ case gfx::GpuMemoryBuffer::DXT1:
+ case gfx::GpuMemoryBuffer::DXT5:
+ case gfx::GpuMemoryBuffer::ETC1:
+ case gfx::GpuMemoryBuffer::RGBA_8888:
+ NOTREACHED();
+ return SurfaceFactoryOzone::BGRA_8888;
+ }
+
+ NOTREACHED();
+ return SurfaceFactoryOzone::BGRA_8888;
+}
+
+SurfaceFactoryOzone::BufferUsage GetOzoneUsageFor(
+ gfx::GpuMemoryBuffer::Usage usage) {
+ switch (usage) {
+ case gfx::GpuMemoryBuffer::MAP:
+ return SurfaceFactoryOzone::MAP;
+ case gfx::GpuMemoryBuffer::PERSISTENT_MAP:
+ return SurfaceFactoryOzone::PERSISTENT_MAP;
+ case gfx::GpuMemoryBuffer::SCANOUT:
+ return SurfaceFactoryOzone::SCANOUT;
+ }
+
+ NOTREACHED();
+ return SurfaceFactoryOzone::MAP;
+}
+
+std::pair<uint32_t, uint32_t> GetIndex(gfx::GpuMemoryBufferId id,
+ int client_id) {
+ return std::pair<uint32_t, uint32_t>(id, client_id);
+}
+} // namespace
+
+GpuMemoryBufferFactoryOzoneNativeBuffer::
+ GpuMemoryBufferFactoryOzoneNativeBuffer() {
+}
+
+GpuMemoryBufferFactoryOzoneNativeBuffer::
+ ~GpuMemoryBufferFactoryOzoneNativeBuffer() {
+}
+
+bool GpuMemoryBufferFactoryOzoneNativeBuffer::CreateGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
+ gfx::PluginWindowHandle surface_handle) {
+ scoped_refptr<NativePixmap> pixmap =
+ OzonePlatform::GetInstance()
+ ->GetSurfaceFactoryOzone()
+ ->CreateNativePixmap(surface_handle, size, GetOzoneFormatFor(format),
+ GetOzoneUsageFor(usage));
+ if (!pixmap.get()) {
+ LOG(ERROR) << "Failed to create pixmap " << size.width() << "x"
+ << size.height() << " format " << format << ", usage " << usage;
+ return false;
+ }
+ base::AutoLock lock(native_pixmap_map_lock_);
+ native_pixmap_map_[GetIndex(id, client_id)] = pixmap;
+ return true;
+}
+
+void GpuMemoryBufferFactoryOzoneNativeBuffer::DestroyGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ int client_id) {
+ base::AutoLock lock(native_pixmap_map_lock_);
+ native_pixmap_map_.erase(GetIndex(id, client_id));
+}
+
+scoped_refptr<gfx::GLImage>
+GpuMemoryBufferFactoryOzoneNativeBuffer::CreateImageForGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ unsigned internalformat,
+ int client_id) {
+ NativePixmap* pixmap = nullptr;
+ {
+ base::AutoLock lock(native_pixmap_map_lock_);
+ BufferToPixmapMap::iterator it =
+ native_pixmap_map_.find(GetIndex(id, client_id));
+ if (it == native_pixmap_map_.end()) {
+ return scoped_refptr<gfx::GLImage>();
+ }
+ pixmap = it->second.get();
+ }
+ return CreateImageForPixmap(pixmap, size, format, internalformat);
+}
+
+scoped_refptr<gfx::GLImage>
+GpuMemoryBufferFactoryOzoneNativeBuffer::CreateImageForPixmap(
+ scoped_refptr<NativePixmap> pixmap,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ unsigned internalformat) {
+ if (pixmap->GetEGLClientBuffer()) {
+ scoped_refptr<GLImageOzoneNativePixmap> image =
+ new GLImageOzoneNativePixmap(size);
+ if (!image->Initialize(pixmap.get())) {
+ return scoped_refptr<gfx::GLImage>();
+ }
+ return image;
+ }
+ if (pixmap->GetDmaBufFd() > 0) {
+ scoped_refptr<GLImageOzoneNativePixmapDmaBuf> image =
+ new GLImageOzoneNativePixmapDmaBuf(size, internalformat);
+ if (!image->Initialize(pixmap.get(), format)) {
+ return scoped_refptr<gfx::GLImage>();
+ }
+ return image;
+ }
+ return scoped_refptr<gfx::GLImage>();
+}
+
+} // namespace ui
diff --git a/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h b/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h
new file mode 100644
index 0000000..c24dbb9
--- /dev/null
+++ b/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h
@@ -0,0 +1,67 @@
+// 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.
+
+#ifndef UI_OZONE_GPU_GPU_MEMORY_BUFFER_FACTORY_OZONE_NATIVE_BUFFER_H_
+#define UI_OZONE_GPU_GPU_MEMORY_BUFFER_FACTORY_OZONE_NATIVE_BUFFER_H_
+
+#include <map>
+
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/gpu/ozone_gpu_export.h"
+#include "ui/ozone/public/native_pixmap.h"
+
+namespace gfx {
+class GLImage;
+}
+
+namespace ui {
+class NativePixmap;
+
+class OZONE_GPU_EXPORT GpuMemoryBufferFactoryOzoneNativeBuffer {
+ typedef std::map<std::pair<uint32_t, uint32_t>, scoped_refptr<NativePixmap> >
+ BufferToPixmapMap;
+
+ public:
+ GpuMemoryBufferFactoryOzoneNativeBuffer();
+ virtual ~GpuMemoryBufferFactoryOzoneNativeBuffer();
+
+ // Creates a GPU memory buffer identified by |id|.
+ // It can be called on any thread.
+ bool CreateGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
+ gfx::PluginWindowHandle surface_handle);
+
+ // Destroys GPU memory buffer identified by |id|.
+ // It can be called on any thread.
+ void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, int client_id);
+
+ // Creates a GLImage instance for GPU memory buffer identified by |id|.
+ scoped_refptr<gfx::GLImage> CreateImageForGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ unsigned internalformat,
+ int client_id);
+
+ static scoped_refptr<gfx::GLImage> CreateImageForPixmap(
+ scoped_refptr<NativePixmap> pixmap,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ unsigned internalformat);
+
+ private:
+ BufferToPixmapMap native_pixmap_map_;
+ base::Lock native_pixmap_map_lock_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_GPU_GPU_MEMORY_BUFFER_FACTORY_OZONE_NATIVE_BUFFER_H_
diff --git a/ui/ozone/gpu/ozone_gpu_export.h b/ui/ozone/gpu/ozone_gpu_export.h
new file mode 100644
index 0000000..cc4a7bc
--- /dev/null
+++ b/ui/ozone/gpu/ozone_gpu_export.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef UI_OZONE_GPU_OZONE_GPU_EXPORT_H_
+#define UI_OZONE_GPU_OZONE_GPU_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(OZONE_GPU_IMPLEMENTATION)
+#define OZONE_GPU_EXPORT __declspec(dllexport)
+#else
+#define OZONE_GPU_EXPORT __declspec(dllimport)
+#endif // defined(OZONE_GPU_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(OZONE_GPU_IMPLEMENTATION)
+#define OZONE_GPU_EXPORT __attribute__((visibility("default")))
+#else
+#define OZONE_GPU_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define OZONE_GPU_EXPORT
+#endif
+
+#endif // UI_OZONE_GPU_OZONE_GPU_EXPORT_H_
diff --git a/ui/ozone/ozone.gni b/ui/ozone/ozone.gni
new file mode 100644
index 0000000..92b1dee
--- /dev/null
+++ b/ui/ozone/ozone.gni
@@ -0,0 +1,33 @@
+# 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.
+
+declare_args() {
+ # Select platforms automatically. Turn this off for manual control.
+ ozone_auto_platforms = false
+}
+
+declare_args() {
+ # The platform that will be active by default.
+ ozone_platform = ""
+
+ # Enable individual platforms.
+ ozone_platform_caca = false
+ ozone_platform_dri = false
+ ozone_platform_drm = false
+ ozone_platform_egltest = true
+ ozone_platform_gbm = true
+ ozone_platform_test = false
+
+ if (ozone_auto_platforms) {
+ # Use test as the default platform.
+ ozone_platform = "test"
+
+ # Build all platforms whose deps are in install-build-deps.sh.
+ # Only these platforms will be compile tested by buildbots.
+ ozone_platform_dri = true
+ ozone_platform_drm = true
+ ozone_platform_test = true
+ ozone_platform_egltest = true
+ }
+}
diff --git a/ui/ozone/ozone_base_export.h b/ui/ozone/ozone_base_export.h
new file mode 100644
index 0000000..d3df39b
--- /dev/null
+++ b/ui/ozone/ozone_base_export.h
@@ -0,0 +1,29 @@
+// Copyright 2013 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.
+
+#ifndef UI_OZONE_OZONE_BASE_EXPORT_H_
+#define UI_OZONE_OZONE_BASE_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(OZONE_BASE_IMPLEMENTATION)
+#define OZONE_BASE_EXPORT __declspec(dllexport)
+#else
+#define OZONE_BASE_EXPORT __declspec(dllimport)
+#endif // defined(OZONE_BASE_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(OZONE_BASE_IMPLEMENTATION)
+#define OZONE_BASE_EXPORT __attribute__((visibility("default")))
+#else
+#define OZONE_BASE_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define OZONE_BASE_EXPORT
+#endif
+
+#endif // UI_OZONE_OZONE_BASE_EXPORT_H_
diff --git a/ui/ozone/ozone_export.h b/ui/ozone/ozone_export.h
new file mode 100644
index 0000000..cc587a5
--- /dev/null
+++ b/ui/ozone/ozone_export.h
@@ -0,0 +1,29 @@
+// Copyright 2013 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.
+
+#ifndef UI_OZONE_OZONE_EXPORT_H_
+#define UI_OZONE_OZONE_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(OZONE_IMPLEMENTATION)
+#define OZONE_EXPORT __declspec(dllexport)
+#else
+#define OZONE_EXPORT __declspec(dllimport)
+#endif // defined(OZONE_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(OZONE_IMPLEMENTATION)
+#define OZONE_EXPORT __attribute__((visibility("default")))
+#else
+#define OZONE_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define OZONE_EXPORT
+#endif
+
+#endif // UI_OZONE_OZONE_EXPORT_H_
diff --git a/ui/ozone/platform/README b/ui/ozone/platform/README
new file mode 100644
index 0000000..cc91d3b
--- /dev/null
+++ b/ui/ozone/platform/README
@@ -0,0 +1,2 @@
+This directory contains implementations of platforms. Each platform implements
+the interfaces from ui/ozone/public for the rest of chromium.
diff --git a/ui/ozone/platform/drm/BUILD.gn b/ui/ozone/platform/drm/BUILD.gn
new file mode 100644
index 0000000..ef0d786
--- /dev/null
+++ b/ui/ozone/platform/drm/BUILD.gn
@@ -0,0 +1,212 @@
+# 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.
+
+import("//build/config/linux/pkg_config.gni")
+import("//ui/ozone/ozone.gni")
+
+declare_args() {
+ use_mesa_platform_null = false
+ use_drm_atomic = false
+}
+
+pkg_config("libdrm") {
+ packages = [ "libdrm" ]
+}
+
+source_set("drm_common") {
+ sources = [
+ "common/drm_gpu_test_helper_inprocess.cc",
+ "common/drm_util.cc",
+ "common/drm_util.h",
+ "common/inprocess_messages.cc",
+ "common/inprocess_messages.h",
+ "common/scoped_drm_types.cc",
+ "common/scoped_drm_types.h",
+ "gpu/crtc_controller.cc",
+ "gpu/crtc_controller.h",
+ "gpu/drm_buffer.cc",
+ "gpu/drm_buffer.h",
+ "gpu/drm_console_buffer.cc",
+ "gpu/drm_console_buffer.h",
+ "gpu/drm_device.cc",
+ "gpu/drm_device.h",
+ "gpu/drm_device_generator.cc",
+ "gpu/drm_device_generator.h",
+ "gpu/drm_device_manager.cc",
+ "gpu/drm_device_manager.h",
+ "gpu/drm_display.cc",
+ "gpu/drm_display.h",
+ "gpu/drm_gpu_display_manager.cc",
+ "gpu/drm_gpu_display_manager.h",
+ "gpu/drm_gpu_platform_support.cc",
+ "gpu/drm_gpu_platform_support.h",
+ "gpu/drm_gpu_platform_support_inprocess.cc",
+ "gpu/drm_surface.cc",
+ "gpu/drm_surface.h",
+ "gpu/drm_surface_factory.cc",
+ "gpu/drm_surface_factory.h",
+ "gpu/drm_vsync_provider.cc",
+ "gpu/drm_vsync_provider.h",
+ "gpu/drm_window.cc",
+ "gpu/drm_window.h",
+ "gpu/hardware_display_controller.cc",
+ "gpu/hardware_display_controller.h",
+ "gpu/hardware_display_plane.cc",
+ "gpu/hardware_display_plane.h",
+ "gpu/hardware_display_plane_manager.cc",
+ "gpu/hardware_display_plane_manager.h",
+ "gpu/hardware_display_plane_manager_legacy.cc",
+ "gpu/hardware_display_plane_manager_legacy.h",
+ "gpu/overlay_plane.cc",
+ "gpu/overlay_plane.h",
+ "gpu/page_flip_request.cc",
+ "gpu/page_flip_request.h",
+ "gpu/scanout_buffer.h",
+ "gpu/screen_manager.cc",
+ "gpu/screen_manager.h",
+ "host/channel_observer.h",
+ "host/drm_cursor.cc",
+ "host/drm_cursor.h",
+ "host/drm_device_handle.cc",
+ "host/drm_device_handle.h",
+ "host/drm_display_host.cc",
+ "host/drm_display_host.h",
+ "host/drm_display_host_manager.cc",
+ "host/drm_display_host_manager.h",
+ "host/drm_gpu_platform_support_host.cc",
+ "host/drm_gpu_platform_support_host.h",
+ "host/drm_gpu_platform_support_host_inprocess.cc",
+ "host/drm_native_display_delegate.cc",
+ "host/drm_native_display_delegate.h",
+ "host/drm_overlay_candidates_host.cc",
+ "host/drm_overlay_candidates_host.h",
+ "host/drm_overlay_manager.cc",
+ "host/drm_overlay_manager.h",
+ "host/drm_window_host.cc",
+ "host/drm_window_host.h",
+ "host/drm_window_host_manager.cc",
+ "host/drm_window_host_manager.h",
+ ]
+
+ defines = [ "OZONE_IMPLEMENTATION" ]
+
+ if (use_drm_atomic) {
+ defines += [ "USE_DRM_ATOMIC" ]
+ sources += [
+ "gpu/hardware_display_plane_atomic.cc",
+ "gpu/hardware_display_plane_atomic.h",
+ "gpu/hardware_display_plane_manager_atomic.cc",
+ "gpu/hardware_display_plane_manager_atomic.h",
+ ]
+ }
+
+ deps = [
+ "//base",
+ "//skia",
+ "//ui/base",
+ "//ui/display/types",
+ "//ui/display/util",
+ "//ui/events",
+ "//ui/events/devices",
+ "//ui/events/ozone:events_ozone",
+ "//ui/events/ozone:events_ozone_evdev",
+ "//ui/events/ozone:events_ozone_layout",
+ "//ui/events/platform",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ "//ui/ozone:ozone_base",
+ "//ui/platform_window",
+ ]
+
+ public_configs = [ ":libdrm" ]
+}
+
+if (ozone_platform_dri || ozone_platform_drm) {
+ source_set("drm") {
+ sources = [
+ "ozone_platform_drm.cc",
+ "ozone_platform_drm.h",
+ ]
+
+ deps = [
+ ":drm_common",
+ "//base",
+ "//skia",
+ "//ui/base",
+ "//ui/ozone:ozone_base",
+ "//ui/events/ozone:events_ozone",
+ "//ui/events/ozone:events_ozone_evdev",
+ "//ui/events/ozone:events_ozone_layout",
+ ]
+ }
+
+ source_set("drm_unittests") {
+ testonly = true
+ sources = [
+ "gpu/drm_surface_unittest.cc",
+ "gpu/drm_window_unittest.cc",
+ "gpu/hardware_display_controller_unittest.cc",
+ "gpu/hardware_display_plane_manager_unittest.cc",
+ "gpu/screen_manager_unittest.cc",
+ "test/mock_drm_device.cc",
+ "test/mock_drm_device.h",
+ ]
+
+ deps = [
+ "//base",
+ "//skia",
+ "//testing/gtest",
+ "//ui/ozone:ozone_base",
+ "//ui/ozone/platform/drm:drm_common",
+ ]
+
+ public_configs = [ ":libdrm" ]
+ }
+}
+
+if (ozone_platform_gbm) {
+ pkg_config("libgbm") {
+ packages = [ "gbm" ]
+ }
+
+ source_set("gbm") {
+ sources = [
+ "gpu/gbm_buffer.cc",
+ "gpu/gbm_buffer.h",
+ "gpu/gbm_buffer_base.cc",
+ "gpu/gbm_buffer_base.h",
+ "gpu/gbm_device.cc",
+ "gpu/gbm_device.h",
+ "gpu/gbm_surface.cc",
+ "gpu/gbm_surface.h",
+ "gpu/gbm_surface_factory.cc",
+ "gpu/gbm_surface_factory.h",
+ "gpu/gbm_surfaceless.cc",
+ "gpu/gbm_surfaceless.h",
+ "ozone_platform_gbm.cc",
+ "ozone_platform_gbm.h",
+ ]
+
+ deps = [
+ ":drm_common",
+ "//base",
+ "//skia",
+ "//ui/base",
+ "//ui/events/ozone:events_ozone",
+ "//ui/events/ozone:events_ozone_evdev",
+ "//ui/events/ozone:events_ozone_layout",
+ "//ui/gfx/geometry",
+ "//ui/ozone:ozone_base",
+ ]
+
+ public_configs = [
+ ":libgbm",
+ "//third_party/khronos:khronos_headers",
+ ]
+
+ if (use_mesa_platform_null) {
+ defines += [ "USE_MESA_PLATFORM_NULL" ]
+ }
+ }
+}
diff --git a/ui/ozone/platform/drm/common/drm_gpu_test_helper_inprocess.cc b/ui/ozone/platform/drm/common/drm_gpu_test_helper_inprocess.cc
new file mode 100644
index 0000000..06ec8d4
--- /dev/null
+++ b/ui/ozone/platform/drm/common/drm_gpu_test_helper_inprocess.cc
@@ -0,0 +1,99 @@
+// 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 "base/bind.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "ui/ozone/platform/drm/gpu/drm_gpu_platform_support_inprocess.h"
+#include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host_inprocess.h"
+#include "ui/ozone/public/gpu_platform_support.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
+#include "ui/ozone/public/ozone_gpu_test_helper.h"
+#include "ui/ozone/public/ozone_platform.h"
+
+namespace ui {
+
+namespace {
+
+const int kGpuProcessHostId = 1;
+
+} // namespace
+
+static void DispatchToGpuPlatformSupportHostTask(Message* msg) {
+ auto support = static_cast<DrmGpuPlatformSupportHost*>(
+ ui::OzonePlatform::GetInstance()->GetGpuPlatformSupportHost());
+ auto inprocess = static_cast<DrmGpuPlatformSupportHostInprocess*>(
+ support->get_delegate());
+ inprocess->OnMessageReceived(*msg);
+ delete msg;
+}
+
+class FakeGpuProcess {
+ public:
+ FakeGpuProcess(
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
+ : ui_task_runner_(ui_task_runner) {}
+ ~FakeGpuProcess() {}
+
+ void Init() {
+ base::Callback<void(Message*)> sender =
+ base::Bind(&DispatchToGpuPlatformSupportHostTask);
+
+ auto delegate = new DrmGpuPlatformSupportInprocess();
+ delegate->OnChannelEstablished(ui_task_runner_, sender);
+ }
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
+};
+
+static void DispatchToGpuPlatformSupportTask(Message* msg) {
+ auto support = static_cast<DrmGpuPlatformSupport*>(
+ ui::OzonePlatform::GetInstance()->GetGpuPlatformSupport());
+ auto inprocess = static_cast<DrmGpuPlatformSupportInprocess*>(
+ support->get_delegate());
+ inprocess->OnMessageReceived(*msg);
+ delete msg;
+}
+
+class FakeGpuProcessHost {
+ public:
+ FakeGpuProcessHost(
+ const scoped_refptr<base::SingleThreadTaskRunner>& gpu_task_runner)
+ : gpu_task_runner_(gpu_task_runner) {}
+ ~FakeGpuProcessHost() {}
+
+ void Init() {
+ base::Callback<void(Message*)> sender =
+ base::Bind(&DispatchToGpuPlatformSupportTask);
+
+ auto host_support_inprocess = new DrmGpuPlatformSupportHostInprocess();
+ host_support_inprocess->OnChannelEstablished(
+ kGpuProcessHostId, gpu_task_runner_, sender);
+ }
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
+};
+
+OzoneGpuTestHelper::OzoneGpuTestHelper() {
+}
+
+OzoneGpuTestHelper::~OzoneGpuTestHelper() {
+}
+
+bool OzoneGpuTestHelper::Initialize(
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>& gpu_task_runner) {
+
+ fake_gpu_process_.reset(new FakeGpuProcess(ui_task_runner));
+ fake_gpu_process_->Init();
+
+ fake_gpu_process_host_.reset(new FakeGpuProcessHost(gpu_task_runner));
+ fake_gpu_process_host_->Init();
+
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/common/drm_util.cc b/ui/ozone/platform/drm/common/drm_util.cc
new file mode 100644
index 0000000..3e0804e
--- /dev/null
+++ b/ui/ozone/platform/drm/common/drm_util.cc
@@ -0,0 +1,268 @@
+// 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/drm/common/drm_util.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <xf86drmMode.h>
+
+#include "ui/display/types/display_constants.h"
+#include "ui/display/util/edid_parser.h"
+
+#if !defined(DRM_MODE_CONNECTOR_DSI)
+#define DRM_MODE_CONNECTOR_DSI 16
+#endif
+
+namespace ui {
+
+namespace {
+
+bool IsCrtcInUse(uint32_t crtc,
+ const ScopedVector<HardwareDisplayControllerInfo>& displays) {
+ for (size_t i = 0; i < displays.size(); ++i) {
+ if (crtc == displays[i]->crtc()->crtc_id)
+ return true;
+ }
+
+ return false;
+}
+
+uint32_t GetCrtc(int fd,
+ drmModeConnector* connector,
+ drmModeRes* resources,
+ const ScopedVector<HardwareDisplayControllerInfo>& displays) {
+ // If the connector already has an encoder try to re-use.
+ if (connector->encoder_id) {
+ ScopedDrmEncoderPtr encoder(drmModeGetEncoder(fd, connector->encoder_id));
+ if (encoder && encoder->crtc_id && !IsCrtcInUse(encoder->crtc_id, displays))
+ return encoder->crtc_id;
+ }
+
+ // Try to find an encoder for the connector.
+ for (int i = 0; i < connector->count_encoders; ++i) {
+ ScopedDrmEncoderPtr encoder(drmModeGetEncoder(fd, connector->encoders[i]));
+ if (!encoder)
+ continue;
+
+ for (int j = 0; j < resources->count_crtcs; ++j) {
+ // Check if the encoder is compatible with this CRTC
+ if (!(encoder->possible_crtcs & (1 << j)) ||
+ IsCrtcInUse(resources->crtcs[j], displays))
+ continue;
+
+ return resources->crtcs[j];
+ }
+ }
+
+ return 0;
+}
+
+// Computes the refresh rate for the specific mode. If we have enough
+// information use the mode timings to compute a more exact value otherwise
+// fallback to using the mode's vertical refresh rate (the kernel computes this
+// the same way, however there is a loss in precision since |vrefresh| is sent
+// as an integer).
+float GetRefreshRate(const drmModeModeInfo& mode) {
+ if (!mode.htotal || !mode.vtotal)
+ return mode.vrefresh;
+
+ float clock = mode.clock;
+ float htotal = mode.htotal;
+ float vtotal = mode.vtotal;
+
+ return (clock * 1000.0f) / (htotal * vtotal);
+}
+
+DisplayConnectionType GetDisplayType(drmModeConnector* connector) {
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_VGA:
+ return DISPLAY_CONNECTION_TYPE_VGA;
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_DVID:
+ case DRM_MODE_CONNECTOR_DVIA:
+ return DISPLAY_CONNECTION_TYPE_DVI;
+ case DRM_MODE_CONNECTOR_LVDS:
+ case DRM_MODE_CONNECTOR_eDP:
+ case DRM_MODE_CONNECTOR_DSI:
+ return DISPLAY_CONNECTION_TYPE_INTERNAL;
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ return DISPLAY_CONNECTION_TYPE_DISPLAYPORT;
+ case DRM_MODE_CONNECTOR_HDMIA:
+ case DRM_MODE_CONNECTOR_HDMIB:
+ return DISPLAY_CONNECTION_TYPE_HDMI;
+ default:
+ return DISPLAY_CONNECTION_TYPE_UNKNOWN;
+ }
+}
+
+int GetDrmProperty(int fd,
+ drmModeConnector* connector,
+ const std::string& name,
+ ScopedDrmPropertyPtr* property) {
+ for (int i = 0; i < connector->count_props; ++i) {
+ ScopedDrmPropertyPtr tmp(drmModeGetProperty(fd, connector->props[i]));
+ if (!tmp)
+ continue;
+
+ if (name == tmp->name) {
+ *property = tmp.Pass();
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+std::string GetNameForEnumValue(drmModePropertyRes* property, uint32_t value) {
+ for (int i = 0; i < property->count_enums; ++i)
+ if (property->enums[i].value == value)
+ return property->enums[i].name;
+
+ return std::string();
+}
+
+ScopedDrmPropertyBlobPtr GetDrmPropertyBlob(int fd,
+ drmModeConnector* connector,
+ const std::string& name) {
+ ScopedDrmPropertyPtr property;
+ int index = GetDrmProperty(fd, connector, name, &property);
+ if (index < 0)
+ return nullptr;
+
+ if (property->flags & DRM_MODE_PROP_BLOB) {
+ return ScopedDrmPropertyBlobPtr(
+ drmModeGetPropertyBlob(fd, connector->prop_values[index]));
+ }
+
+ return nullptr;
+}
+
+bool IsAspectPreserving(int fd, drmModeConnector* connector) {
+ ScopedDrmPropertyPtr property;
+ int index = GetDrmProperty(fd, connector, "scaling mode", &property);
+ if (index < 0)
+ return false;
+
+ return (GetNameForEnumValue(property.get(), connector->prop_values[index]) ==
+ "Full aspect");
+}
+
+} // namespace
+
+HardwareDisplayControllerInfo::HardwareDisplayControllerInfo(
+ ScopedDrmConnectorPtr connector,
+ ScopedDrmCrtcPtr crtc)
+ : connector_(connector.Pass()), crtc_(crtc.Pass()) {
+}
+
+HardwareDisplayControllerInfo::~HardwareDisplayControllerInfo() {
+}
+
+ScopedVector<HardwareDisplayControllerInfo> GetAvailableDisplayControllerInfos(
+ int fd) {
+ ScopedDrmResourcesPtr resources(drmModeGetResources(fd));
+ DCHECK(resources) << "Failed to get DRM resources";
+ ScopedVector<HardwareDisplayControllerInfo> displays;
+
+ for (int i = 0; i < resources->count_connectors; ++i) {
+ ScopedDrmConnectorPtr connector(
+ drmModeGetConnector(fd, resources->connectors[i]));
+
+ if (!connector || connector->connection != DRM_MODE_CONNECTED ||
+ connector->count_modes == 0)
+ continue;
+
+ uint32_t crtc_id = GetCrtc(fd, connector.get(), resources.get(), displays);
+ if (!crtc_id)
+ continue;
+
+ ScopedDrmCrtcPtr crtc(drmModeGetCrtc(fd, crtc_id));
+ displays.push_back(
+ new HardwareDisplayControllerInfo(connector.Pass(), crtc.Pass()));
+ }
+
+ return displays.Pass();
+}
+
+bool SameMode(const drmModeModeInfo& lhs, const drmModeModeInfo& rhs) {
+ return lhs.clock == rhs.clock && lhs.hdisplay == rhs.hdisplay &&
+ lhs.vdisplay == rhs.vdisplay && lhs.vrefresh == rhs.vrefresh &&
+ lhs.hsync_start == rhs.hsync_start && lhs.hsync_end == rhs.hsync_end &&
+ lhs.htotal == rhs.htotal && lhs.hskew == rhs.hskew &&
+ lhs.vsync_start == rhs.vsync_start && lhs.vsync_end == rhs.vsync_end &&
+ lhs.vtotal == rhs.vtotal && lhs.vscan == rhs.vscan &&
+ lhs.flags == rhs.flags && strcmp(lhs.name, rhs.name) == 0;
+}
+
+DisplayMode_Params CreateDisplayModeParams(const drmModeModeInfo& mode) {
+ DisplayMode_Params params;
+ params.size = gfx::Size(mode.hdisplay, mode.vdisplay);
+ params.is_interlaced = mode.flags & DRM_MODE_FLAG_INTERLACE;
+ params.refresh_rate = GetRefreshRate(mode);
+
+ return params;
+}
+
+DisplaySnapshot_Params CreateDisplaySnapshotParams(
+ HardwareDisplayControllerInfo* info,
+ int fd,
+ size_t display_index,
+ const gfx::Point& origin) {
+ DisplaySnapshot_Params params;
+ params.display_id = display_index;
+ params.origin = origin;
+ params.physical_size =
+ gfx::Size(info->connector()->mmWidth, info->connector()->mmHeight);
+ params.type = GetDisplayType(info->connector());
+ params.is_aspect_preserving_scaling =
+ IsAspectPreserving(fd, info->connector());
+
+ ScopedDrmPropertyBlobPtr edid_blob(
+ GetDrmPropertyBlob(fd, info->connector(), "EDID"));
+
+ if (edid_blob) {
+ std::vector<uint8_t> edid(
+ static_cast<uint8_t*>(edid_blob->data),
+ static_cast<uint8_t*>(edid_blob->data) + edid_blob->length);
+
+ if (!GetDisplayIdFromEDID(edid, display_index, ¶ms.display_id,
+ ¶ms.product_id))
+ params.display_id = display_index;
+
+ ParseOutputDeviceData(edid, nullptr, nullptr, ¶ms.display_name, nullptr,
+ nullptr);
+ ParseOutputOverscanFlag(edid, ¶ms.has_overscan);
+ } else {
+ VLOG(1) << "Failed to get EDID blob for connector "
+ << info->connector()->connector_id;
+ }
+
+ for (int i = 0; i < info->connector()->count_modes; ++i) {
+ const drmModeModeInfo& mode = info->connector()->modes[i];
+ params.modes.push_back(CreateDisplayModeParams(mode));
+
+ if (info->crtc()->mode_valid && SameMode(info->crtc()->mode, mode)) {
+ params.has_current_mode = true;
+ params.current_mode = params.modes.back();
+ }
+
+ if (mode.type & DRM_MODE_TYPE_PREFERRED) {
+ params.has_native_mode = true;
+ params.native_mode = params.modes.back();
+ }
+ }
+
+ // If no preferred mode is found then use the first one. Using the first one
+ // since it should be the best mode.
+ if (!params.has_native_mode && !params.modes.empty()) {
+ params.has_native_mode = true;
+ params.native_mode = params.modes.front();
+ }
+
+ return params;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/common/drm_util.h b/ui/ozone/platform/drm/common/drm_util.h
new file mode 100644
index 0000000..e761aba
--- /dev/null
+++ b/ui/ozone/platform/drm/common/drm_util.h
@@ -0,0 +1,61 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_COMMON_DRM_UTIL_H_
+#define UI_OZONE_PLATFORM_DRM_COMMON_DRM_UTIL_H_
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+#include "ui/ozone/platform/drm/common/scoped_drm_types.h"
+
+typedef struct _drmModeModeInfo drmModeModeInfo;
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+
+// Representation of the information required to initialize and configure a
+// native display.
+class HardwareDisplayControllerInfo {
+ public:
+ HardwareDisplayControllerInfo(ScopedDrmConnectorPtr connector,
+ ScopedDrmCrtcPtr crtc);
+ ~HardwareDisplayControllerInfo();
+
+ drmModeConnector* connector() const { return connector_.get(); }
+ drmModeCrtc* crtc() const { return crtc_.get(); }
+
+ private:
+ ScopedDrmConnectorPtr connector_;
+ ScopedDrmCrtcPtr crtc_;
+
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayControllerInfo);
+};
+
+// Looks-up and parses the native display configurations returning all available
+// displays.
+ScopedVector<HardwareDisplayControllerInfo> GetAvailableDisplayControllerInfos(
+ int fd);
+
+bool SameMode(const drmModeModeInfo& lhs, const drmModeModeInfo& rhs);
+
+DisplayMode_Params CreateDisplayModeParams(const drmModeModeInfo& mode);
+
+// |info| provides the DRM information related to the display, |fd| is the
+// connection to the DRM device and |index| provides a unique identifier for the
+// display. |index| will be used to generate the display id (it may be the id if
+// the monitor's EDID lacks the necessary identifiers).
+DisplaySnapshot_Params CreateDisplaySnapshotParams(
+ HardwareDisplayControllerInfo* info,
+ int fd,
+ size_t display_index,
+ const gfx::Point& origin);
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_COMMON_DRM_UTIL_H_
diff --git a/ui/ozone/platform/drm/common/inprocess_messages.cc b/ui/ozone/platform/drm/common/inprocess_messages.cc
new file mode 100644
index 0000000..43642f6
--- /dev/null
+++ b/ui/ozone/platform/drm/common/inprocess_messages.cc
@@ -0,0 +1,18 @@
+// Copyright 2015 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/drm/common/inprocess_messages.h"
+
+namespace ui {
+
+OzoneHostMsg_UpdateNativeDisplays::OzoneHostMsg_UpdateNativeDisplays(
+ const std::vector<DisplaySnapshot_Params>& _displays)
+ : Message(OZONE_HOST_MSG__UPDATE_NATIVE_DISPLAYS),
+ displays(_displays) {
+}
+
+OzoneHostMsg_UpdateNativeDisplays::~OzoneHostMsg_UpdateNativeDisplays() {
+}
+
+} // namespace
diff --git a/ui/ozone/platform/drm/common/inprocess_messages.h b/ui/ozone/platform/drm/common/inprocess_messages.h
new file mode 100644
index 0000000..f31fc7a
--- /dev/null
+++ b/ui/ozone/platform/drm/common/inprocess_messages.h
@@ -0,0 +1,109 @@
+// Copyright 2015 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_HOST_DRM_GPU_COMMON_INPROCESS_MESSAGES_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_DRM_GPU_COMMON_INPROCESS_MESSAGES_H_
+
+#include "base/file_descriptor_posix.h"
+#include "base/files/file_path.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+
+namespace ui {
+
+enum MessageId {
+ OZONE_GPU_MSG__CREATE_WINDOW = 1000,
+ OZONE_GPU_MSG__WINDOW_BOUNDS_CHANGED,
+ OZONE_GPU_MSG__ADD_GRAPHICS_DEVICE,
+ OZONE_GPU_MSG__REFRESH_NATIVE_DISPLAYS,
+ OZONE_GPU_MSG__CONFIGURE_NATIVE_DISPLAY,
+
+ OZONE_HOST_MSG__UPDATE_NATIVE_DISPLAYS = 2000,
+ OZONE_HOST_MSG__DISPLAY_CONFIGURED,
+ OZONE_HOST_MSG__HDCP_STATE_RECEIVED,
+};
+
+class Message {
+ public:
+ Message(MessageId _id)
+ : id(_id) {
+ }
+ const MessageId id;
+};
+
+class OzoneGpuMsg_CreateWindow : public Message {
+ public:
+ OzoneGpuMsg_CreateWindow(const gfx::AcceleratedWidget& _widget)
+ : Message(OZONE_GPU_MSG__CREATE_WINDOW),
+ widget(_widget) {
+ }
+ const gfx::AcceleratedWidget widget;
+};
+
+class OzoneGpuMsg_WindowBoundsChanged : public Message {
+ public:
+ OzoneGpuMsg_WindowBoundsChanged(const gfx::AcceleratedWidget& _widget,
+ const gfx::Rect& _bounds)
+ : Message(OZONE_GPU_MSG__WINDOW_BOUNDS_CHANGED),
+ widget(_widget), bounds(_bounds) {
+ }
+ const gfx::AcceleratedWidget widget;
+ const gfx::Rect bounds;
+};
+
+class OzoneGpuMsg_AddGraphicsDevice : public Message {
+ public:
+ OzoneGpuMsg_AddGraphicsDevice(const base::FilePath& _path,
+ const base::FileDescriptor& _fd)
+ : Message(OZONE_GPU_MSG__ADD_GRAPHICS_DEVICE),
+ path(_path), fd(_fd) {
+ }
+ const base::FilePath path;
+ const base::FileDescriptor fd;
+};
+
+class OzoneGpuMsg_RefreshNativeDisplays : public Message {
+ public:
+ OzoneGpuMsg_RefreshNativeDisplays()
+ : Message(OZONE_GPU_MSG__REFRESH_NATIVE_DISPLAYS) {
+ }
+};
+
+class OzoneGpuMsg_ConfigureNativeDisplay : public Message {
+ public:
+ OzoneGpuMsg_ConfigureNativeDisplay(int64_t _id,
+ const DisplayMode_Params& _mode,
+ const gfx::Point& _originhost)
+ : Message(OZONE_GPU_MSG__CONFIGURE_NATIVE_DISPLAY)
+ , id(_id), mode(_mode), originhost(_originhost) {
+ }
+ const int64_t id;
+ const DisplayMode_Params mode;
+ const gfx::Point originhost;
+};
+
+
+class OzoneHostMsg_UpdateNativeDisplays : public Message {
+ public:
+ OzoneHostMsg_UpdateNativeDisplays(
+ const std::vector<DisplaySnapshot_Params>& _displays);
+ ~OzoneHostMsg_UpdateNativeDisplays();
+
+ const std::vector<DisplaySnapshot_Params> displays;
+};
+
+class OzoneHostMsg_DisplayConfigured : public Message {
+ public:
+ OzoneHostMsg_DisplayConfigured(int64_t _id, bool _result)
+ : Message(OZONE_HOST_MSG__DISPLAY_CONFIGURED)
+ , id(_id), result(_result) {
+ }
+ const int64_t id;
+ const bool result;
+};
+
+} // namespace
+
+#endif
diff --git a/ui/ozone/platform/drm/common/scoped_drm_types.cc b/ui/ozone/platform/drm/common/scoped_drm_types.cc
new file mode 100644
index 0000000..9a1456e
--- /dev/null
+++ b/ui/ozone/platform/drm/common/scoped_drm_types.cc
@@ -0,0 +1,59 @@
+// 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/drm/common/scoped_drm_types.h"
+
+#include <xf86drmMode.h>
+
+namespace ui {
+
+void DrmResourcesDeleter::operator()(drmModeRes* resources) const {
+ drmModeFreeResources(resources);
+}
+
+void DrmConnectorDeleter::operator()(drmModeConnector* connector) const {
+ drmModeFreeConnector(connector);
+}
+
+void DrmCrtcDeleter::operator()(drmModeCrtc* crtc) const {
+ drmModeFreeCrtc(crtc);
+}
+
+void DrmEncoderDeleter::operator()(drmModeEncoder* encoder) const {
+ drmModeFreeEncoder(encoder);
+}
+
+void DrmObjectPropertiesDeleter::operator()(
+ drmModeObjectProperties* properties) const {
+ drmModeFreeObjectProperties(properties);
+}
+
+void DrmPlaneDeleter::operator()(drmModePlane* plane) const {
+ drmModeFreePlane(plane);
+}
+
+void DrmPlaneResDeleter::operator()(drmModePlaneRes* plane) const {
+ drmModeFreePlaneResources(plane);
+}
+
+void DrmPropertyDeleter::operator()(drmModePropertyRes* property) const {
+ drmModeFreeProperty(property);
+}
+
+#if defined(USE_DRM_ATOMIC)
+void DrmPropertySetDeleter::operator()(drmModePropertySet* property) const {
+ drmModePropertySetFree(property);
+}
+#endif // defined(USE_DRM_ATOMIC)
+
+void DrmPropertyBlobDeleter::operator()(
+ drmModePropertyBlobRes* property) const {
+ drmModeFreePropertyBlob(property);
+}
+
+void DrmFramebufferDeleter::operator()(drmModeFB* framebuffer) const {
+ drmModeFreeFB(framebuffer);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/common/scoped_drm_types.h b/ui/ozone/platform/drm/common/scoped_drm_types.h
new file mode 100644
index 0000000..02f1eb5
--- /dev/null
+++ b/ui/ozone/platform/drm/common/scoped_drm_types.h
@@ -0,0 +1,80 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_COMMON_SCOPED_DRM_TYPES_H_
+#define UI_OZONE_PLATFORM_DRM_COMMON_SCOPED_DRM_TYPES_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/ozone/ozone_export.h"
+
+typedef struct _drmModeConnector drmModeConnector;
+typedef struct _drmModeCrtc drmModeCrtc;
+typedef struct _drmModeEncoder drmModeEncoder;
+typedef struct _drmModeFB drmModeFB;
+typedef struct _drmModeObjectProperties drmModeObjectProperties;
+typedef struct _drmModePlane drmModePlane;
+typedef struct _drmModePlaneRes drmModePlaneRes;
+typedef struct _drmModeProperty drmModePropertyRes;
+typedef struct _drmModePropertySet drmModePropertySet;
+typedef struct _drmModePropertyBlob drmModePropertyBlobRes;
+typedef struct _drmModeRes drmModeRes;
+
+namespace ui {
+
+struct OZONE_EXPORT DrmResourcesDeleter {
+ void operator()(drmModeRes* resources) const;
+};
+struct OZONE_EXPORT DrmConnectorDeleter {
+ void operator()(drmModeConnector* connector) const;
+};
+struct OZONE_EXPORT DrmCrtcDeleter {
+ void operator()(drmModeCrtc* crtc) const;
+};
+struct OZONE_EXPORT DrmEncoderDeleter {
+ void operator()(drmModeEncoder* encoder) const;
+};
+struct OZONE_EXPORT DrmObjectPropertiesDeleter {
+ void operator()(drmModeObjectProperties* properties) const;
+};
+struct OZONE_EXPORT DrmPlaneDeleter {
+ void operator()(drmModePlane* plane) const;
+};
+struct OZONE_EXPORT DrmPlaneResDeleter {
+ void operator()(drmModePlaneRes* plane_res) const;
+};
+struct OZONE_EXPORT DrmPropertyDeleter {
+ void operator()(drmModePropertyRes* property) const;
+};
+#if defined(USE_DRM_ATOMIC)
+struct OZONE_EXPORT DrmPropertySetDeleter {
+ void operator()(drmModePropertySet* property) const;
+};
+#endif // defined(USE_DRM_ATOMIC)
+struct OZONE_EXPORT DrmPropertyBlobDeleter {
+ void operator()(drmModePropertyBlobRes* property) const;
+};
+struct OZONE_EXPORT DrmFramebufferDeleter {
+ void operator()(drmModeFB* framebuffer) const;
+};
+
+typedef scoped_ptr<drmModeRes, DrmResourcesDeleter> ScopedDrmResourcesPtr;
+typedef scoped_ptr<drmModeConnector, DrmConnectorDeleter> ScopedDrmConnectorPtr;
+typedef scoped_ptr<drmModeCrtc, DrmCrtcDeleter> ScopedDrmCrtcPtr;
+typedef scoped_ptr<drmModeEncoder, DrmEncoderDeleter> ScopedDrmEncoderPtr;
+typedef scoped_ptr<drmModeObjectProperties, DrmObjectPropertiesDeleter>
+ ScopedDrmObjectPropertyPtr;
+typedef scoped_ptr<drmModePlane, DrmPlaneDeleter> ScopedDrmPlanePtr;
+typedef scoped_ptr<drmModePlaneRes, DrmPlaneResDeleter> ScopedDrmPlaneResPtr;
+typedef scoped_ptr<drmModePropertyRes, DrmPropertyDeleter> ScopedDrmPropertyPtr;
+#if defined(USE_DRM_ATOMIC)
+typedef scoped_ptr<drmModePropertySet, DrmPropertySetDeleter>
+ ScopedDrmPropertySetPtr;
+#endif // defined(USE_DRM_ATOMIC)
+typedef scoped_ptr<drmModePropertyBlobRes, DrmPropertyBlobDeleter>
+ ScopedDrmPropertyBlobPtr;
+typedef scoped_ptr<drmModeFB, DrmFramebufferDeleter> ScopedDrmFramebufferPtr;
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_COMMON_SCOPED_DRM_TYPES_H_
diff --git a/ui/ozone/platform/drm/gpu/crtc_controller.cc b/ui/ozone/platform/drm/gpu/crtc_controller.cc
new file mode 100644
index 0000000..34390a2
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/crtc_controller.cc
@@ -0,0 +1,167 @@
+// 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/drm/gpu/crtc_controller.h"
+
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/page_flip_request.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
+
+namespace ui {
+
+CrtcController::CrtcController(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector)
+ : drm_(drm), crtc_(crtc), connector_(connector) {
+}
+
+CrtcController::~CrtcController() {
+ if (!is_disabled_) {
+ SetCursor(nullptr);
+ drm_->DisableCrtc(crtc_);
+ SignalPageFlipRequest();
+ }
+}
+
+bool CrtcController::Modeset(const OverlayPlane& plane, drmModeModeInfo mode) {
+ if (!drm_->SetCrtc(crtc_, plane.buffer->GetFramebufferId(),
+ std::vector<uint32_t>(1, connector_), &mode)) {
+ PLOG(ERROR) << "Failed to modeset: crtc=" << crtc_
+ << " connector=" << connector_
+ << " framebuffer_id=" << plane.buffer->GetFramebufferId()
+ << " mode=" << mode.hdisplay << "x" << mode.vdisplay << "@"
+ << mode.vrefresh;
+ return false;
+ }
+
+ mode_ = mode;
+ pending_planes_.clear();
+ is_disabled_ = false;
+
+ // drmModeSetCrtc has an immediate effect, so we can assume that the current
+ // planes have been updated. However if a page flip is still pending, set the
+ // pending planes to the same values so that the callback keeps the correct
+ // state.
+ current_planes_ = std::vector<OverlayPlane>(1, plane);
+ if (page_flip_request_.get())
+ pending_planes_ = current_planes_;
+
+ ResetCursor();
+
+ return true;
+}
+
+bool CrtcController::Disable() {
+ if (is_disabled_)
+ return true;
+
+ is_disabled_ = true;
+ return drm_->DisableCrtc(crtc_);
+}
+
+bool CrtcController::SchedulePageFlip(
+ HardwareDisplayPlaneList* plane_list,
+ const OverlayPlaneList& overlays,
+ bool test_only,
+ scoped_refptr<PageFlipRequest> page_flip_request) {
+ DCHECK(!page_flip_request_.get() || test_only);
+ DCHECK(!is_disabled_);
+ const OverlayPlane* primary = OverlayPlane::GetPrimaryPlane(overlays);
+ if (!primary) {
+ LOG(ERROR) << "No primary plane to display on crtc " << crtc_;
+ page_flip_request->Signal(gfx::SwapResult::SWAP_ACK);
+ return true;
+ }
+ DCHECK(primary->buffer.get());
+
+ if (primary->buffer->GetSize() != gfx::Size(mode_.hdisplay, mode_.vdisplay)) {
+ VLOG(2) << "Trying to pageflip a buffer with the wrong size. Expected "
+ << mode_.hdisplay << "x" << mode_.vdisplay << " got "
+ << primary->buffer->GetSize().ToString() << " for"
+ << " crtc=" << crtc_ << " connector=" << connector_;
+ page_flip_request->Signal(gfx::SwapResult::SWAP_ACK);
+ return true;
+ }
+
+ if (!drm_->plane_manager()->AssignOverlayPlanes(plane_list, overlays, crtc_,
+ this)) {
+ PLOG(ERROR) << "Failed to assign overlay planes for crtc " << crtc_;
+ page_flip_request->Signal(gfx::SwapResult::SWAP_FAILED);
+ return false;
+ }
+
+ if (test_only) {
+ page_flip_request->Signal(gfx::SwapResult::SWAP_ACK);
+ } else {
+ pending_planes_ = overlays;
+ page_flip_request_ = page_flip_request;
+ }
+
+ return true;
+}
+
+void CrtcController::PageFlipFailed() {
+ pending_planes_.clear();
+ SignalPageFlipRequest();
+}
+
+void CrtcController::OnPageFlipEvent(unsigned int frame,
+ unsigned int seconds,
+ unsigned int useconds) {
+ time_of_last_flip_ =
+ static_cast<uint64_t>(seconds) * base::Time::kMicrosecondsPerSecond +
+ useconds;
+
+ current_planes_.clear();
+ current_planes_.swap(pending_planes_);
+
+ SignalPageFlipRequest();
+}
+
+bool CrtcController::SetCursor(const scoped_refptr<ScanoutBuffer>& buffer) {
+ DCHECK(!is_disabled_ || !buffer);
+ cursor_buffer_ = buffer;
+
+ return ResetCursor();
+}
+
+bool CrtcController::MoveCursor(const gfx::Point& location) {
+ DCHECK(!is_disabled_);
+ return drm_->MoveCursor(crtc_, location);
+}
+
+bool CrtcController::ResetCursor() {
+ uint32_t handle = 0;
+ gfx::Size size;
+
+ if (cursor_buffer_) {
+ handle = cursor_buffer_->GetHandle();
+ size = cursor_buffer_->GetSize();
+ }
+
+ bool status = drm_->SetCursor(crtc_, handle, size);
+ if (!status) {
+ PLOG(ERROR) << "drmModeSetCursor: device " << drm_->device_path().value()
+ << " crtc " << crtc_ << " handle " << handle << " size "
+ << size.ToString();
+ }
+
+ return status;
+}
+
+void CrtcController::SignalPageFlipRequest() {
+ if (page_flip_request_.get()) {
+ // If another frame is queued up and available immediately, calling Signal()
+ // may result in a call to SchedulePageFlip(), which will override
+ // page_flip_request_ and possibly release the ref. Stash previous request
+ // locally to avoid deleting the object we are making a call on.
+ scoped_refptr<PageFlipRequest> last_request;
+ last_request.swap(page_flip_request_);
+ last_request->Signal(gfx::SwapResult::SWAP_ACK);
+ }
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/crtc_controller.h b/ui/ozone/platform/drm/gpu/crtc_controller.h
new file mode 100644
index 0000000..636fe89
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/crtc_controller.h
@@ -0,0 +1,108 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_CRTC_CONTROLLER_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_CRTC_CONTROLLER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <xf86drmMode.h>
+
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform/drm/common/scoped_drm_types.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
+#include "ui/ozone/platform/drm/gpu/overlay_plane.h"
+
+namespace ui {
+
+class DrmDevice;
+class PageFlipRequest;
+
+// Wrapper around a CRTC.
+//
+// One CRTC can be paired up with one or more connectors. The simplest
+// configuration represents one CRTC driving one monitor, while pairing up a
+// CRTC with multiple connectors results in hardware mirroring.
+class OZONE_EXPORT CrtcController
+ : public base::SupportsWeakPtr<CrtcController> {
+ public:
+ CrtcController(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector);
+ ~CrtcController();
+
+ drmModeModeInfo mode() const { return mode_; }
+ uint32_t crtc() const { return crtc_; }
+ uint32_t connector() const { return connector_; }
+ const scoped_refptr<DrmDevice>& drm() const { return drm_; }
+ bool is_disabled() const { return is_disabled_; }
+ uint64_t time_of_last_flip() const { return time_of_last_flip_; }
+
+ // Perform the initial modesetting operation using |plane| as the buffer for
+ // the primary plane. The CRTC configuration is specified by |mode|.
+ bool Modeset(const OverlayPlane& plane, drmModeModeInfo mode);
+
+ // Disables the controller.
+ bool Disable();
+
+ // Schedule a page flip event and present the overlays in |planes|.
+ bool SchedulePageFlip(HardwareDisplayPlaneList* plane_list,
+ const OverlayPlaneList& planes,
+ bool test_only,
+ scoped_refptr<PageFlipRequest> page_flip_request);
+
+ // Called if the page flip for this CRTC fails after being scheduled.
+ void PageFlipFailed();
+
+ // Called when the page flip event occurred. The event is provided by the
+ // kernel when a VBlank event finished. This allows the controller to
+ // update internal state and propagate the update to the surface.
+ // The tuple (seconds, useconds) represents the event timestamp. |seconds|
+ // represents the number of seconds while |useconds| represents the
+ // microseconds (< 1 second) in the timestamp.
+ void OnPageFlipEvent(unsigned int frame,
+ unsigned int seconds,
+ unsigned int useconds);
+
+ bool SetCursor(const scoped_refptr<ScanoutBuffer>& buffer);
+ bool MoveCursor(const gfx::Point& location);
+
+ private:
+ bool ResetCursor();
+
+ void SignalPageFlipRequest();
+
+ scoped_refptr<DrmDevice> drm_;
+
+ HardwareDisplayPlaneManager* overlay_plane_manager_; // Not owned.
+
+ // Buffers need to be declared first so that they are destroyed last. Needed
+ // since the controllers may reference the buffers.
+ OverlayPlaneList current_planes_;
+ OverlayPlaneList pending_planes_;
+ scoped_refptr<ScanoutBuffer> cursor_buffer_;
+ scoped_refptr<PageFlipRequest> page_flip_request_;
+
+ uint32_t crtc_;
+
+ // TODO(dnicoara) Add support for hardware mirroring (multiple connectors).
+ uint32_t connector_;
+
+ drmModeModeInfo mode_;
+
+ // Keeps track of the CRTC state. If a surface has been bound, then the value
+ // is set to false. Otherwise it is true.
+ bool is_disabled_ = true;
+
+ // The time of the last page flip event as reported by the kernel callback.
+ uint64_t time_of_last_flip_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(CrtcController);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_CRTC_CONTROLLER_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_buffer.cc b/ui/ozone/platform/drm/gpu/drm_buffer.cc
new file mode 100644
index 0000000..0ab1f61
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_buffer.cc
@@ -0,0 +1,118 @@
+// 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/drm/gpu/drm_buffer.h"
+
+#include "base/logging.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+
+namespace ui {
+
+namespace {
+
+// Modesetting cannot happen from a buffer with transparencies. Return the size
+// of a pixel without alpha.
+uint8_t GetColorDepth(SkColorType type) {
+ switch (type) {
+ case kUnknown_SkColorType:
+ case kAlpha_8_SkColorType:
+ return 0;
+ case kIndex_8_SkColorType:
+ return 8;
+ case kRGB_565_SkColorType:
+ return 16;
+ case kARGB_4444_SkColorType:
+ return 12;
+ case kN32_SkColorType:
+ return 24;
+ default:
+ NOTREACHED();
+ return 0;
+ }
+}
+
+} // namespace
+
+DrmBuffer::DrmBuffer(const scoped_refptr<DrmDevice>& drm) : drm_(drm) {
+}
+
+DrmBuffer::~DrmBuffer() {
+ surface_.clear();
+
+ if (framebuffer_ && !drm_->RemoveFramebuffer(framebuffer_))
+ PLOG(ERROR) << "DrmBuffer: RemoveFramebuffer: fb " << framebuffer_;
+
+ if (mmap_base_ && !drm_->UnmapDumbBuffer(mmap_base_, mmap_size_))
+ PLOG(ERROR) << "DrmBuffer: UnmapDumbBuffer: handle " << handle_;
+
+ if (handle_ && !drm_->DestroyDumbBuffer(handle_))
+ PLOG(ERROR) << "DrmBuffer: DestroyDumbBuffer: handle " << handle_;
+}
+
+bool DrmBuffer::Initialize(const SkImageInfo& info,
+ bool should_register_framebuffer) {
+ if (!drm_->CreateDumbBuffer(info, &handle_, &stride_)) {
+ PLOG(ERROR) << "DrmBuffer: CreateDumbBuffer: width " << info.width()
+ << " height " << info.height();
+ return false;
+ }
+
+ mmap_size_ = info.getSafeSize(stride_);
+ if (!drm_->MapDumbBuffer(handle_, mmap_size_, &mmap_base_)) {
+ PLOG(ERROR) << "DrmBuffer: MapDumbBuffer: handle " << handle_;
+ return false;
+ }
+
+ if (should_register_framebuffer &&
+ !drm_->AddFramebuffer(
+ info.width(), info.height(), GetColorDepth(info.colorType()),
+ info.bytesPerPixel() << 3, stride_, handle_, &framebuffer_)) {
+ PLOG(ERROR) << "DrmBuffer: AddFramebuffer: handle " << handle_;
+ return false;
+ }
+
+ surface_ =
+ skia::AdoptRef(SkSurface::NewRasterDirect(info, mmap_base_, stride_));
+ if (!surface_) {
+ LOG(ERROR) << "DrmBuffer: Failed to create SkSurface: handle " << handle_;
+ return false;
+ }
+
+ return true;
+}
+
+SkCanvas* DrmBuffer::GetCanvas() const {
+ return surface_->getCanvas();
+}
+
+uint32_t DrmBuffer::GetFramebufferId() const {
+ return framebuffer_;
+}
+
+uint32_t DrmBuffer::GetHandle() const {
+ return handle_;
+}
+
+gfx::Size DrmBuffer::GetSize() const {
+ return gfx::Size(surface_->width(), surface_->height());
+}
+
+DrmBufferGenerator::DrmBufferGenerator() {
+}
+
+DrmBufferGenerator::~DrmBufferGenerator() {
+}
+
+scoped_refptr<ScanoutBuffer> DrmBufferGenerator::Create(
+ const scoped_refptr<DrmDevice>& drm,
+ const gfx::Size& size) {
+ scoped_refptr<DrmBuffer> buffer(new DrmBuffer(drm));
+ SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
+ if (!buffer->Initialize(info, true /* should_register_framebuffer */))
+ return NULL;
+
+ return buffer;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_buffer.h b/ui/ozone/platform/drm/gpu/drm_buffer.h
new file mode 100644
index 0000000..84556ad
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_buffer.h
@@ -0,0 +1,80 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_BUFFER_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_DRM_BUFFER_H_
+
+#include "base/macros.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
+
+namespace ui {
+
+class DrmDevice;
+
+// Wrapper for a DRM allocated buffer. Keeps track of the native properties of
+// the buffer and wraps the pixel memory into a SkSurface which can be used to
+// draw into using Skia.
+class OZONE_EXPORT DrmBuffer : public ScanoutBuffer {
+ public:
+ DrmBuffer(const scoped_refptr<DrmDevice>& drm);
+
+ // Allocates the backing pixels and wraps them in |surface_|. |info| is used
+ // to describe the buffer characteristics (size, color format).
+ // |should_register_framebuffer| is used to distinguish the buffers that are
+ // used for modesetting.
+ bool Initialize(const SkImageInfo& info, bool should_register_framebuffer);
+
+ SkCanvas* GetCanvas() const;
+
+ // ScanoutBuffer:
+ uint32_t GetFramebufferId() const override;
+ uint32_t GetHandle() const override;
+ gfx::Size GetSize() const override;
+
+ protected:
+ ~DrmBuffer() override;
+
+ scoped_refptr<DrmDevice> drm_;
+
+ // Length of a row of pixels.
+ uint32_t stride_ = 0;
+
+ // Buffer handle used by the DRM allocator.
+ uint32_t handle_ = 0;
+
+ // Base address for memory mapping.
+ void* mmap_base_ = 0;
+
+ // Size for memory mapping.
+ size_t mmap_size_ = 0;
+
+ // Buffer ID used by the DRM modesettings API. This is set when the buffer is
+ // registered with the CRTC.
+ uint32_t framebuffer_ = 0;
+
+ // Wrapper around the native pixel memory.
+ skia::RefPtr<SkSurface> surface_;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmBuffer);
+};
+
+class OZONE_EXPORT DrmBufferGenerator : public ScanoutBufferGenerator {
+ public:
+ DrmBufferGenerator();
+ ~DrmBufferGenerator() override;
+
+ // ScanoutBufferGenerator:
+ scoped_refptr<ScanoutBuffer> Create(const scoped_refptr<DrmDevice>& drm,
+ const gfx::Size& size) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DrmBufferGenerator);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_BUFFER_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_console_buffer.cc b/ui/ozone/platform/drm/gpu/drm_console_buffer.cc
new file mode 100644
index 0000000..464c380
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_console_buffer.cc
@@ -0,0 +1,55 @@
+// 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/drm/gpu/drm_console_buffer.h"
+
+#include <sys/mman.h>
+#include <xf86drmMode.h>
+
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/ozone/platform/drm/common/scoped_drm_types.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+
+namespace ui {
+
+DrmConsoleBuffer::DrmConsoleBuffer(const scoped_refptr<DrmDevice>& drm,
+ uint32_t framebuffer)
+ : drm_(drm), framebuffer_(framebuffer) {
+}
+
+DrmConsoleBuffer::~DrmConsoleBuffer() {
+ if (mmap_base_)
+ if (munmap(mmap_base_, mmap_size_))
+ PLOG(ERROR) << "munmap";
+
+ if (handle_ && !drm_->CloseBufferHandle(handle_))
+ PLOG(ERROR) << "DrmConsoleBuffer: CloseBufferHandle: handle " << handle_;
+}
+
+bool DrmConsoleBuffer::Initialize() {
+ ScopedDrmFramebufferPtr fb(drm_->GetFramebuffer(framebuffer_));
+
+ if (!fb)
+ return false;
+
+ handle_ = fb->handle;
+ stride_ = fb->pitch;
+ SkImageInfo info = SkImageInfo::MakeN32Premul(fb->width, fb->height);
+
+ mmap_size_ = info.getSafeSize(stride_);
+
+ if (!drm_->MapDumbBuffer(fb->handle, mmap_size_, &mmap_base_)) {
+ mmap_base_ = NULL;
+ return false;
+ }
+
+ surface_ =
+ skia::AdoptRef(SkSurface::NewRasterDirect(info, mmap_base_, stride_));
+ if (!surface_)
+ return false;
+
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_console_buffer.h b/ui/ozone/platform/drm/gpu/drm_console_buffer.h
new file mode 100644
index 0000000..27dc038
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_console_buffer.h
@@ -0,0 +1,62 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_CONSOLE_BUFFER_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_DRM_CONSOLE_BUFFER_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkSurface.h"
+
+class SkCanvas;
+
+namespace ui {
+
+class DrmDevice;
+
+// Wrapper for the console buffer. This is the buffer that is allocated by
+// default by the system and is used when no application is controlling the
+// CRTC. Keeps track of the native properties of the buffer and wraps the pixel
+// memory into a SkSurface which can be used to draw into using Skia.
+class DrmConsoleBuffer {
+ public:
+ DrmConsoleBuffer(const scoped_refptr<DrmDevice>& drm, uint32_t framebuffer);
+ ~DrmConsoleBuffer();
+
+ SkCanvas* canvas() { return surface_->getCanvas(); }
+ skia::RefPtr<SkImage> image() {
+ return skia::AdoptRef(surface_->newImageSnapshot());
+ }
+
+ // Memory map the backing pixels and wrap them in |surface_|.
+ bool Initialize();
+
+ protected:
+ scoped_refptr<DrmDevice> drm_;
+
+ // Wrapper around the native pixel memory.
+ skia::RefPtr<SkSurface> surface_;
+
+ // Length of a row of pixels.
+ uint32_t stride_ = 0;
+
+ // Buffer handle used by the DRM allocator.
+ uint32_t handle_ = 0;
+
+ // Buffer ID used by the DRM modesettings API.
+ uint32_t framebuffer_ = 0;
+
+ // Memory map base address.
+ void* mmap_base_ = nullptr;
+
+ // Memory map size.
+ size_t mmap_size_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmConsoleBuffer);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_CONSOLE_BUFFER_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_device.cc b/ui/ozone/platform/drm/gpu/drm_device.cc
new file mode 100644
index 0000000..1d80b68
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_device.cc
@@ -0,0 +1,618 @@
+// 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/drm/gpu/drm_device.h"
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/stl_util.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
+#include "ui/display/types/gamma_ramp_rgb_entry.h"
+#include "ui/ozone/platform/drm/common/drm_util.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h"
+
+#if defined(USE_DRM_ATOMIC)
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h"
+#endif
+
+namespace ui {
+
+namespace {
+
+typedef base::Callback<void(uint32_t /* frame */,
+ uint32_t /* seconds */,
+ uint32_t /* useconds */,
+ uint64_t /* id */)> DrmEventHandler;
+
+bool DrmCreateDumbBuffer(int fd,
+ const SkImageInfo& info,
+ uint32_t* handle,
+ uint32_t* stride) {
+ struct drm_mode_create_dumb request;
+ memset(&request, 0, sizeof(request));
+ request.width = info.width();
+ request.height = info.height();
+ request.bpp = info.bytesPerPixel() << 3;
+ request.flags = 0;
+
+ if (drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &request) < 0) {
+ VPLOG(2) << "Cannot create dumb buffer";
+ return false;
+ }
+
+ // The driver may choose to align the last row as well. We don't care about
+ // the last alignment bits since they aren't used for display purposes, so
+ // just check that the expected size is <= to what the driver allocated.
+ DCHECK_LE(info.getSafeSize(request.pitch), request.size);
+
+ *handle = request.handle;
+ *stride = request.pitch;
+ return true;
+}
+
+bool DrmDestroyDumbBuffer(int fd, uint32_t handle) {
+ struct drm_mode_destroy_dumb destroy_request;
+ memset(&destroy_request, 0, sizeof(destroy_request));
+ destroy_request.handle = handle;
+ return !drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request);
+}
+
+bool ProcessDrmEvent(int fd, const DrmEventHandler& callback) {
+ char buffer[1024];
+ int len = read(fd, buffer, sizeof(buffer));
+ if (len == 0)
+ return false;
+
+ if (len < static_cast<int>(sizeof(drm_event))) {
+ PLOG(ERROR) << "Failed to read DRM event";
+ return false;
+ }
+
+ int idx = 0;
+ while (idx < len) {
+ DCHECK_LE(static_cast<int>(sizeof(drm_event)), len - idx);
+ drm_event event;
+ memcpy(&event, &buffer[idx], sizeof(event));
+ switch (event.type) {
+ case DRM_EVENT_FLIP_COMPLETE: {
+ DCHECK_LE(static_cast<int>(sizeof(drm_event_vblank)), len - idx);
+ drm_event_vblank vblank;
+ memcpy(&vblank, &buffer[idx], sizeof(vblank));
+ callback.Run(vblank.sequence, vblank.tv_sec, vblank.tv_usec,
+ vblank.user_data);
+ } break;
+ case DRM_EVENT_VBLANK:
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ idx += event.length;
+ }
+
+ return true;
+}
+
+bool CanQueryForResources(int fd) {
+ drm_mode_card_res resources;
+ memset(&resources, 0, sizeof(resources));
+ // If there is no error getting DRM resources then assume this is a
+ // modesetting device.
+ return !drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &resources);
+}
+
+} // namespace
+
+class DrmDevice::PageFlipManager
+ : public base::RefCountedThreadSafe<DrmDevice::PageFlipManager> {
+ public:
+ PageFlipManager() : next_id_(0) {}
+
+ void OnPageFlip(uint32_t frame,
+ uint32_t seconds,
+ uint32_t useconds,
+ uint64_t id) {
+ auto it =
+ std::find_if(callbacks_.begin(), callbacks_.end(), FindCallback(id));
+ if (it == callbacks_.end()) {
+ LOG(WARNING) << "Could not find callback for page flip id=" << id;
+ return;
+ }
+
+ DrmDevice::PageFlipCallback callback = it->callback;
+ callbacks_.erase(it);
+ callback.Run(frame, seconds, useconds);
+ }
+
+ uint64_t GetNextId() { return next_id_++; }
+
+ void RegisterCallback(uint64_t id,
+ const DrmDevice::PageFlipCallback& callback) {
+ callbacks_.push_back({id, callback});
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<DrmDevice::PageFlipManager>;
+ ~PageFlipManager() {}
+
+ struct PageFlip {
+ uint64_t id;
+ DrmDevice::PageFlipCallback callback;
+ };
+
+ struct FindCallback {
+ FindCallback(uint64_t id) : id(id) {}
+
+ bool operator()(const PageFlip& flip) const { return flip.id == id; }
+
+ uint64_t id;
+ };
+
+ uint64_t next_id_;
+
+ std::vector<PageFlip> callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(PageFlipManager);
+};
+
+class DrmDevice::IOWatcher
+ : public base::RefCountedThreadSafe<DrmDevice::IOWatcher>,
+ public base::MessagePumpLibevent::Watcher {
+ public:
+ IOWatcher(int fd,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
+ const scoped_refptr<DrmDevice::PageFlipManager>& page_flip_manager)
+ : main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ io_task_runner_(io_task_runner),
+ page_flip_manager_(page_flip_manager),
+ paused_(true),
+ fd_(fd) {}
+
+ void SetPaused(bool paused) {
+ if (paused_ == paused)
+ return;
+
+ paused_ = paused;
+ base::WaitableEvent done(false, false);
+ io_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&IOWatcher::SetPausedOnIO, this, &done));
+ done.Wait();
+ }
+
+ void Shutdown() {
+ if (!paused_)
+ io_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&IOWatcher::UnregisterOnIO, this));
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<IOWatcher>;
+
+ ~IOWatcher() override {}
+
+ void RegisterOnIO() {
+ DCHECK(base::MessageLoopForIO::IsCurrent());
+ base::MessageLoopForIO::current()->WatchFileDescriptor(
+ fd_, true, base::MessageLoopForIO::WATCH_READ, &controller_, this);
+ }
+
+ void UnregisterOnIO() {
+ DCHECK(base::MessageLoopForIO::IsCurrent());
+ controller_.StopWatchingFileDescriptor();
+ }
+
+ void SetPausedOnIO(base::WaitableEvent* done) {
+ DCHECK(base::MessageLoopForIO::IsCurrent());
+ if (paused_)
+ UnregisterOnIO();
+ else
+ RegisterOnIO();
+ done->Signal();
+ }
+
+ void OnPageFlipOnIO(uint32_t frame,
+ uint32_t seconds,
+ uint32_t useconds,
+ uint64_t id) {
+ main_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DrmDevice::PageFlipManager::OnPageFlip, page_flip_manager_,
+ frame, seconds, useconds, id));
+ }
+
+ // base::MessagePumpLibevent::Watcher overrides:
+ void OnFileCanReadWithoutBlocking(int fd) override {
+ DCHECK(base::MessageLoopForIO::IsCurrent());
+ TRACE_EVENT1("drm", "OnDrmEvent", "socket", fd);
+
+ if (!ProcessDrmEvent(
+ fd, base::Bind(&DrmDevice::IOWatcher::OnPageFlipOnIO, this)))
+ UnregisterOnIO();
+ }
+
+ void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); }
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+ scoped_refptr<DrmDevice::PageFlipManager> page_flip_manager_;
+
+ base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+
+ bool paused_;
+ int fd_;
+
+ DISALLOW_COPY_AND_ASSIGN(IOWatcher);
+};
+
+DrmDevice::DrmDevice(const base::FilePath& device_path, base::File file)
+ : device_path_(device_path),
+ file_(file.Pass()),
+ page_flip_manager_(new PageFlipManager()) {
+}
+
+DrmDevice::~DrmDevice() {
+ if (watcher_)
+ watcher_->Shutdown();
+}
+
+bool DrmDevice::Initialize(bool use_atomic) {
+ // Ignore devices that cannot perform modesetting.
+ if (!CanQueryForResources(file_.GetPlatformFile())) {
+ VLOG(2) << "Cannot query for resources for '" << device_path_.value()
+ << "'";
+ return false;
+ }
+
+#if defined(USE_DRM_ATOMIC)
+ // Use atomic only if the build, kernel & flags all allow it.
+ if (use_atomic && SetCapability(DRM_CLIENT_CAP_ATOMIC, 1))
+ plane_manager_.reset(new HardwareDisplayPlaneManagerAtomic());
+#endif // defined(USE_DRM_ATOMIC)
+
+ if (!plane_manager_)
+ plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy());
+ if (!plane_manager_->Initialize(this)) {
+ LOG(ERROR) << "Failed to initialize the plane manager for "
+ << device_path_.value();
+ plane_manager_.reset();
+ return false;
+ }
+
+ return true;
+}
+
+void DrmDevice::InitializeTaskRunner(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
+ DCHECK(!task_runner_);
+ task_runner_ = task_runner;
+ watcher_ =
+ new IOWatcher(file_.GetPlatformFile(), task_runner_, page_flip_manager_);
+}
+
+ScopedDrmCrtcPtr DrmDevice::GetCrtc(uint32_t crtc_id) {
+ DCHECK(file_.IsValid());
+ return ScopedDrmCrtcPtr(drmModeGetCrtc(file_.GetPlatformFile(), crtc_id));
+}
+
+bool DrmDevice::SetCrtc(uint32_t crtc_id,
+ uint32_t framebuffer,
+ std::vector<uint32_t> connectors,
+ drmModeModeInfo* mode) {
+ DCHECK(file_.IsValid());
+ DCHECK(!connectors.empty());
+ DCHECK(mode);
+
+ TRACE_EVENT2("drm", "DrmDevice::SetCrtc", "crtc", crtc_id, "size",
+ gfx::Size(mode->hdisplay, mode->vdisplay).ToString());
+ return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, framebuffer, 0, 0,
+ vector_as_array(&connectors), connectors.size(), mode);
+}
+
+bool DrmDevice::SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) {
+ DCHECK(file_.IsValid());
+ // If there's no buffer then the CRTC was disabled.
+ if (!crtc->buffer_id)
+ return DisableCrtc(crtc->crtc_id);
+
+ DCHECK(!connectors.empty());
+
+ TRACE_EVENT1("drm", "DrmDevice::RestoreCrtc", "crtc", crtc->crtc_id);
+ return !drmModeSetCrtc(file_.GetPlatformFile(), crtc->crtc_id,
+ crtc->buffer_id, crtc->x, crtc->y,
+ vector_as_array(&connectors), connectors.size(),
+ &crtc->mode);
+}
+
+bool DrmDevice::DisableCrtc(uint32_t crtc_id) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT1("drm", "DrmDevice::DisableCrtc", "crtc", crtc_id);
+ return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, 0, 0, 0, NULL, 0,
+ NULL);
+}
+
+ScopedDrmConnectorPtr DrmDevice::GetConnector(uint32_t connector_id) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT1("drm", "DrmDevice::GetConnector", "connector", connector_id);
+ return ScopedDrmConnectorPtr(
+ drmModeGetConnector(file_.GetPlatformFile(), connector_id));
+}
+
+bool DrmDevice::AddFramebuffer(uint32_t width,
+ uint32_t height,
+ uint8_t depth,
+ uint8_t bpp,
+ uint32_t stride,
+ uint32_t handle,
+ uint32_t* framebuffer) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT1("drm", "DrmDevice::AddFramebuffer", "handle", handle);
+ return !drmModeAddFB(file_.GetPlatformFile(), width, height, depth, bpp,
+ stride, handle, framebuffer);
+}
+
+bool DrmDevice::RemoveFramebuffer(uint32_t framebuffer) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT1("drm", "DrmDevice::RemoveFramebuffer", "framebuffer",
+ framebuffer);
+ return !drmModeRmFB(file_.GetPlatformFile(), framebuffer);
+}
+
+bool DrmDevice::PageFlip(uint32_t crtc_id,
+ uint32_t framebuffer,
+ bool is_sync,
+ const PageFlipCallback& callback) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT2("drm", "DrmDevice::PageFlip", "crtc", crtc_id, "framebuffer",
+ framebuffer);
+
+ if (watcher_)
+ watcher_->SetPaused(is_sync);
+
+ // NOTE: Calling drmModeSetCrtc will immediately update the state, though
+ // callbacks to already scheduled page flips will be honored by the kernel.
+ uint64_t id = page_flip_manager_->GetNextId();
+ if (!drmModePageFlip(file_.GetPlatformFile(), crtc_id, framebuffer,
+ DRM_MODE_PAGE_FLIP_EVENT, reinterpret_cast<void*>(id))) {
+ // If successful the payload will be removed by a PageFlip event.
+ page_flip_manager_->RegisterCallback(id, callback);
+
+ // If the flip was requested synchronous or if no watcher has been installed
+ // yet, then synchronously handle the page flip events.
+ if (is_sync || !watcher_) {
+ TRACE_EVENT1("drm", "OnDrmEvent", "socket", file_.GetPlatformFile());
+
+ ProcessDrmEvent(
+ file_.GetPlatformFile(),
+ base::Bind(&PageFlipManager::OnPageFlip, page_flip_manager_));
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool DrmDevice::PageFlipOverlay(uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& location,
+ const gfx::Rect& source,
+ int overlay_plane) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT2("drm", "DrmDevice::PageFlipOverlay", "crtc", crtc_id,
+ "framebuffer", framebuffer);
+ return !drmModeSetPlane(file_.GetPlatformFile(), overlay_plane, crtc_id,
+ framebuffer, 0, location.x(), location.y(),
+ location.width(), location.height(), source.x(),
+ source.y(), source.width(), source.height());
+}
+
+ScopedDrmFramebufferPtr DrmDevice::GetFramebuffer(uint32_t framebuffer) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT1("drm", "DrmDevice::GetFramebuffer", "framebuffer", framebuffer);
+ return ScopedDrmFramebufferPtr(
+ drmModeGetFB(file_.GetPlatformFile(), framebuffer));
+}
+
+ScopedDrmPropertyPtr DrmDevice::GetProperty(drmModeConnector* connector,
+ const char* name) {
+ TRACE_EVENT2("drm", "DrmDevice::GetProperty", "connector",
+ connector->connector_id, "name", name);
+ for (int i = 0; i < connector->count_props; ++i) {
+ ScopedDrmPropertyPtr property(
+ drmModeGetProperty(file_.GetPlatformFile(), connector->props[i]));
+ if (!property)
+ continue;
+
+ if (strcmp(property->name, name) == 0)
+ return property.Pass();
+ }
+
+ return ScopedDrmPropertyPtr();
+}
+
+bool DrmDevice::SetProperty(uint32_t connector_id,
+ uint32_t property_id,
+ uint64_t value) {
+ DCHECK(file_.IsValid());
+ return !drmModeConnectorSetProperty(file_.GetPlatformFile(), connector_id,
+ property_id, value);
+}
+
+bool DrmDevice::GetCapability(uint64_t capability, uint64_t* value) {
+ DCHECK(file_.IsValid());
+ return !drmGetCap(file_.GetPlatformFile(), capability, value);
+}
+
+ScopedDrmPropertyBlobPtr DrmDevice::GetPropertyBlob(drmModeConnector* connector,
+ const char* name) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT2("drm", "DrmDevice::GetPropertyBlob", "connector",
+ connector->connector_id, "name", name);
+ for (int i = 0; i < connector->count_props; ++i) {
+ ScopedDrmPropertyPtr property(
+ drmModeGetProperty(file_.GetPlatformFile(), connector->props[i]));
+ if (!property)
+ continue;
+
+ if (strcmp(property->name, name) == 0 &&
+ property->flags & DRM_MODE_PROP_BLOB)
+ return ScopedDrmPropertyBlobPtr(drmModeGetPropertyBlob(
+ file_.GetPlatformFile(), connector->prop_values[i]));
+ }
+
+ return ScopedDrmPropertyBlobPtr();
+}
+
+bool DrmDevice::SetCursor(uint32_t crtc_id,
+ uint32_t handle,
+ const gfx::Size& size) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT1("drm", "DrmDevice::SetCursor", "handle", handle);
+ return !drmModeSetCursor(file_.GetPlatformFile(), crtc_id, handle,
+ size.width(), size.height());
+}
+
+bool DrmDevice::MoveCursor(uint32_t crtc_id, const gfx::Point& point) {
+ DCHECK(file_.IsValid());
+ return !drmModeMoveCursor(file_.GetPlatformFile(), crtc_id, point.x(),
+ point.y());
+}
+
+bool DrmDevice::CreateDumbBuffer(const SkImageInfo& info,
+ uint32_t* handle,
+ uint32_t* stride) {
+ DCHECK(file_.IsValid());
+
+ TRACE_EVENT0("drm", "DrmDevice::CreateDumbBuffer");
+ return DrmCreateDumbBuffer(file_.GetPlatformFile(), info, handle, stride);
+}
+
+bool DrmDevice::DestroyDumbBuffer(uint32_t handle) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT1("drm", "DrmDevice::DestroyDumbBuffer", "handle", handle);
+ return DrmDestroyDumbBuffer(file_.GetPlatformFile(), handle);
+}
+
+bool DrmDevice::MapDumbBuffer(uint32_t handle, size_t size, void** pixels) {
+ struct drm_mode_map_dumb map_request;
+ memset(&map_request, 0, sizeof(map_request));
+ map_request.handle = handle;
+ if (drmIoctl(file_.GetPlatformFile(), DRM_IOCTL_MODE_MAP_DUMB,
+ &map_request)) {
+ PLOG(ERROR) << "Cannot prepare dumb buffer for mapping";
+ return false;
+ }
+
+ *pixels = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ file_.GetPlatformFile(), map_request.offset);
+ if (*pixels == MAP_FAILED) {
+ PLOG(ERROR) << "Cannot mmap dumb buffer";
+ return false;
+ }
+
+ return true;
+}
+
+bool DrmDevice::UnmapDumbBuffer(void* pixels, size_t size) {
+ return !munmap(pixels, size);
+}
+
+bool DrmDevice::CloseBufferHandle(uint32_t handle) {
+ struct drm_gem_close close_request;
+ memset(&close_request, 0, sizeof(close_request));
+ close_request.handle = handle;
+ return !drmIoctl(file_.GetPlatformFile(), DRM_IOCTL_GEM_CLOSE,
+ &close_request);
+}
+
+bool DrmDevice::CommitProperties(drmModePropertySet* properties,
+ uint32_t flags,
+ bool is_sync,
+ bool test_only,
+ const PageFlipCallback& callback) {
+#if defined(USE_DRM_ATOMIC)
+ if (test_only)
+ flags |= DRM_MODE_ATOMIC_TEST_ONLY;
+ else
+ flags |= DRM_MODE_PAGE_FLIP_EVENT;
+ uint64_t id = page_flip_manager_->GetNextId();
+ if (!drmModePropertySetCommit(file_.GetPlatformFile(), flags,
+ reinterpret_cast<void*>(id), properties)) {
+ if (test_only)
+ return true;
+ page_flip_manager_->RegisterCallback(id, callback);
+
+ // If the flip was requested synchronous or if no watcher has been installed
+ // yet, then synchronously handle the page flip events.
+ if (is_sync || !watcher_) {
+ TRACE_EVENT1("drm", "OnDrmEvent", "socket", file_.GetPlatformFile());
+
+ ProcessDrmEvent(
+ file_.GetPlatformFile(),
+ base::Bind(&PageFlipManager::OnPageFlip, page_flip_manager_));
+ }
+ return true;
+ }
+#endif // defined(USE_DRM_ATOMIC)
+ return false;
+}
+
+bool DrmDevice::SetCapability(uint64_t capability, uint64_t value) {
+ DCHECK(file_.IsValid());
+ return !drmSetClientCap(file_.GetPlatformFile(), capability, value);
+}
+
+bool DrmDevice::SetMaster() {
+ TRACE_EVENT1("drm", "DrmDevice::SetMaster", "path", device_path_.value());
+ DCHECK(file_.IsValid());
+ return (drmSetMaster(file_.GetPlatformFile()) == 0);
+}
+
+bool DrmDevice::DropMaster() {
+ TRACE_EVENT1("drm", "DrmDevice::DropMaster", "path", device_path_.value());
+ DCHECK(file_.IsValid());
+ return (drmDropMaster(file_.GetPlatformFile()) == 0);
+}
+
+bool DrmDevice::SetGammaRamp(uint32_t crtc_id,
+ const std::vector<GammaRampRGBEntry>& lut) {
+ ScopedDrmCrtcPtr crtc = GetCrtc(crtc_id);
+
+ // TODO(robert.bradford) resample the incoming ramp to match what the kernel
+ // expects.
+ if (static_cast<size_t>(crtc->gamma_size) != lut.size()) {
+ LOG(ERROR) << "Gamma table size mismatch: supplied " << lut.size()
+ << " expected " << crtc->gamma_size;
+ }
+
+ std::vector<uint16_t> r, g, b;
+ r.reserve(lut.size());
+ g.reserve(lut.size());
+ b.reserve(lut.size());
+
+ for (size_t i = 0; i < lut.size(); ++i) {
+ r.push_back(lut[i].r);
+ g.push_back(lut[i].g);
+ b.push_back(lut[i].b);
+ }
+
+ DCHECK(file_.IsValid());
+ TRACE_EVENT0("drm", "DrmDevice::SetGamma");
+ return (drmModeCrtcSetGamma(file_.GetPlatformFile(), crtc_id, r.size(), &r[0],
+ &g[0], &b[0]) == 0);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_device.h b/ui/ozone/platform/drm/gpu/drm_device.h
new file mode 100644
index 0000000..012dde7
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_device.h
@@ -0,0 +1,211 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_DEVICE_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_DRM_DEVICE_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/overlay_transform.h"
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform/drm/common/scoped_drm_types.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
+
+typedef struct _drmEventContext drmEventContext;
+typedef struct _drmModeModeInfo drmModeModeInfo;
+
+struct SkImageInfo;
+
+namespace base {
+class SingleThreadTaskRunner;
+} // namespace base
+
+namespace ui {
+
+class HardwareDisplayPlaneManager;
+struct GammaRampRGBEntry;
+
+// Wraps DRM calls into a nice interface. Used to provide different
+// implementations of the DRM calls. For the actual implementation the DRM API
+// would be called. In unit tests this interface would be stubbed.
+class OZONE_EXPORT DrmDevice : public base::RefCountedThreadSafe<DrmDevice> {
+ public:
+ typedef base::Callback<void(unsigned int /* frame */,
+ unsigned int /* seconds */,
+ unsigned int /* useconds */)> PageFlipCallback;
+
+ DrmDevice(const base::FilePath& device_path, base::File file);
+
+ // Open device.
+ virtual bool Initialize(bool use_atomic);
+
+ // |task_runner| will be used to asynchronously page flip.
+ virtual void InitializeTaskRunner(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+
+ // Get the CRTC state. This is generally used to save state before using the
+ // CRTC. When the user finishes using the CRTC, the user should restore the
+ // CRTC to it's initial state. Use |SetCrtc| to restore the state.
+ virtual ScopedDrmCrtcPtr GetCrtc(uint32_t crtc_id);
+
+ // Used to configure CRTC with ID |crtc_id| to use the connector in
+ // |connectors|. The CRTC will be configured with mode |mode| and will display
+ // the framebuffer with ID |framebuffer|. Before being able to display the
+ // framebuffer, it should be registered with the CRTC using |AddFramebuffer|.
+ virtual bool SetCrtc(uint32_t crtc_id,
+ uint32_t framebuffer,
+ std::vector<uint32_t> connectors,
+ drmModeModeInfo* mode);
+
+ // Used to set a specific configuration to the CRTC. Normally this function
+ // would be called with a CRTC saved state (from |GetCrtc|) to restore it to
+ // its original configuration.
+ virtual bool SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors);
+
+ virtual bool DisableCrtc(uint32_t crtc_id);
+
+ // Returns the connector properties for |connector_id|.
+ virtual ScopedDrmConnectorPtr GetConnector(uint32_t connector_id);
+
+ // Register a buffer with the CRTC. On successful registration, the CRTC will
+ // assign a framebuffer ID to |framebuffer|.
+ virtual bool AddFramebuffer(uint32_t width,
+ uint32_t height,
+ uint8_t depth,
+ uint8_t bpp,
+ uint32_t stride,
+ uint32_t handle,
+ uint32_t* framebuffer);
+
+ // Deregister the given |framebuffer|.
+ virtual bool RemoveFramebuffer(uint32_t framebuffer);
+
+ // Get the DRM details associated with |framebuffer|.
+ virtual ScopedDrmFramebufferPtr GetFramebuffer(uint32_t framebuffer);
+
+ // Schedules a pageflip for CRTC |crtc_id|. This function will return
+ // immediately. Upon completion of the pageflip event, the CRTC will be
+ // displaying the buffer with ID |framebuffer| and will have a DRM event
+ // queued on |fd_|.
+ virtual bool PageFlip(uint32_t crtc_id,
+ uint32_t framebuffer,
+ bool is_sync,
+ const PageFlipCallback& callback);
+
+ // Schedule an overlay to be show during the page flip for CRTC |crtc_id|.
+ // |source| location from |framebuffer| will be shown on overlay
+ // |overlay_plane|, in the bounds specified by |location| on the screen.
+ virtual bool PageFlipOverlay(uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& location,
+ const gfx::Rect& source,
+ int overlay_plane);
+
+ // Returns the property with name |name| associated with |connector|. Returns
+ // NULL if property not found. If the returned value is valid, it must be
+ // released using FreeProperty().
+ virtual ScopedDrmPropertyPtr GetProperty(drmModeConnector* connector,
+ const char* name);
+
+ // Sets the value of property with ID |property_id| to |value|. The property
+ // is applied to the connector with ID |connector_id|.
+ virtual bool SetProperty(uint32_t connector_id,
+ uint32_t property_id,
+ uint64_t value);
+
+ // Can be used to query device/driver |capability|. Sets the value of
+ // |capability to |value|. Returns true in case of a succesful query.
+ virtual bool GetCapability(uint64_t capability, uint64_t* value);
+
+ // Return a binary blob associated with |connector|. The binary blob is
+ // associated with the property with name |name|. Return NULL if the property
+ // could not be found or if the property does not have a binary blob. If valid
+ // the returned object must be freed using FreePropertyBlob().
+ virtual ScopedDrmPropertyBlobPtr GetPropertyBlob(drmModeConnector* connector,
+ const char* name);
+
+ // Set the cursor to be displayed in CRTC |crtc_id|. (width, height) is the
+ // cursor size pointed by |handle|.
+ virtual bool SetCursor(uint32_t crtc_id,
+ uint32_t handle,
+ const gfx::Size& size);
+
+ // Move the cursor on CRTC |crtc_id| to (x, y);
+ virtual bool MoveCursor(uint32_t crtc_id, const gfx::Point& point);
+
+ virtual bool CreateDumbBuffer(const SkImageInfo& info,
+ uint32_t* handle,
+ uint32_t* stride);
+
+ virtual bool DestroyDumbBuffer(uint32_t handle);
+
+ virtual bool MapDumbBuffer(uint32_t handle, size_t size, void** pixels);
+
+ virtual bool UnmapDumbBuffer(void* pixels, size_t size);
+
+ virtual bool CloseBufferHandle(uint32_t handle);
+
+ virtual bool CommitProperties(drmModePropertySet* properties,
+ uint32_t flags,
+ bool is_sync,
+ bool test_only,
+ const PageFlipCallback& callback);
+
+ // Set the gamma ramp for |crtc_id| to reflect the ramps in |lut|.
+ virtual bool SetGammaRamp(uint32_t crtc_id,
+ const std::vector<GammaRampRGBEntry>& lut);
+
+ virtual bool SetCapability(uint64_t capability, uint64_t value);
+
+ // Drm master related
+ virtual bool SetMaster();
+ virtual bool DropMaster();
+
+ int get_fd() const { return file_.GetPlatformFile(); }
+
+ base::FilePath device_path() const { return device_path_; }
+
+ HardwareDisplayPlaneManager* plane_manager() { return plane_manager_.get(); }
+
+ protected:
+ friend class base::RefCountedThreadSafe<DrmDevice>;
+
+ virtual ~DrmDevice();
+
+ scoped_ptr<HardwareDisplayPlaneManager> plane_manager_;
+
+ private:
+ class IOWatcher;
+ class PageFlipManager;
+
+ // Path to DRM device.
+ const base::FilePath device_path_;
+
+ // DRM device.
+ base::File file_;
+
+ // Helper thread to perform IO listener operations.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ // Watcher for |fd_| listening for page flip events.
+ scoped_refptr<IOWatcher> watcher_;
+
+ scoped_refptr<PageFlipManager> page_flip_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmDevice);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_DEVICE_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_device_generator.cc b/ui/ozone/platform/drm/gpu/drm_device_generator.cc
new file mode 100644
index 0000000..205269f
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_device_generator.cc
@@ -0,0 +1,27 @@
+// Copyright 2015 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/drm/gpu/drm_device_generator.h"
+
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+
+namespace ui {
+
+DrmDeviceGenerator::DrmDeviceGenerator() {
+}
+
+DrmDeviceGenerator::~DrmDeviceGenerator() {
+}
+
+scoped_refptr<DrmDevice> DrmDeviceGenerator::CreateDevice(
+ const base::FilePath& device_path,
+ base::File file) {
+ scoped_refptr<DrmDevice> drm = new DrmDevice(device_path, file.Pass());
+ if (drm->Initialize(false))
+ return drm;
+
+ return nullptr;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_device_generator.h b/ui/ozone/platform/drm/gpu/drm_device_generator.h
new file mode 100644
index 0000000..aebf9b8
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_device_generator.h
@@ -0,0 +1,32 @@
+// Copyright 2015 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_DEVICE_GENERATOR_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_DRM_DEVICE_GENERATOR_H_
+
+#include "base/files/file.h"
+#include "base/memory/ref_counted.h"
+
+namespace ui {
+
+class DrmDevice;
+
+class DrmDeviceGenerator {
+ public:
+ DrmDeviceGenerator();
+ virtual ~DrmDeviceGenerator();
+
+ // Creates a DRM device for |file|. |device_path| describes the location of
+ // the DRM device.
+ virtual scoped_refptr<DrmDevice> CreateDevice(
+ const base::FilePath& device_path,
+ base::File file);
+
+ public:
+ DISALLOW_COPY_AND_ASSIGN(DrmDeviceGenerator);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_DEVICE_GENERATOR_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_device_manager.cc b/ui/ozone/platform/drm/gpu/drm_device_manager.cc
new file mode 100644
index 0000000..b01664a
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_device_manager.cc
@@ -0,0 +1,126 @@
+// Copyright 2015 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/drm/gpu/drm_device_manager.h"
+
+#include "base/file_descriptor_posix.h"
+#include "base/single_thread_task_runner.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
+
+namespace ui {
+
+namespace {
+
+class FindByDevicePath {
+ public:
+ explicit FindByDevicePath(const base::FilePath& path) : path_(path) {}
+
+ bool operator()(const scoped_refptr<DrmDevice>& device) {
+ return device->device_path() == path_;
+ }
+
+ private:
+ base::FilePath path_;
+};
+
+} // namespace
+
+DrmDeviceManager::DrmDeviceManager(
+ scoped_ptr<DrmDeviceGenerator> drm_device_generator)
+ : drm_device_generator_(drm_device_generator.Pass()) {
+}
+
+DrmDeviceManager::~DrmDeviceManager() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(drm_device_map_.empty());
+}
+
+bool DrmDeviceManager::AddDrmDevice(const base::FilePath& path,
+ const base::FileDescriptor& fd) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ base::File file(fd.fd);
+ auto it =
+ std::find_if(devices_.begin(), devices_.end(), FindByDevicePath(path));
+ if (it != devices_.end()) {
+ VLOG(2) << "Got request to add existing device: " << path.value();
+ return false;
+ }
+
+ scoped_refptr<DrmDevice> device =
+ drm_device_generator_->CreateDevice(path, file.Pass());
+ if (!device) {
+ LOG(ERROR) << "Could not initialize DRM device for " << path.value();
+ return false;
+ }
+
+ if (io_task_runner_)
+ device->InitializeTaskRunner(io_task_runner_);
+
+ if (!primary_device_)
+ primary_device_ = device;
+
+ devices_.push_back(device);
+ return true;
+}
+
+void DrmDeviceManager::RemoveDrmDevice(const base::FilePath& path) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ auto it =
+ std::find_if(devices_.begin(), devices_.end(), FindByDevicePath(path));
+ if (it == devices_.end()) {
+ VLOG(2) << "Got request to remove non-existent device: " << path.value();
+ return;
+ }
+
+ DCHECK_NE(primary_device_, *it);
+ devices_.erase(it);
+}
+
+void DrmDeviceManager::InitializeIOTaskRunner(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!io_task_runner_);
+ io_task_runner_ = task_runner;
+ for (const auto& device : devices_)
+ device->InitializeTaskRunner(io_task_runner_);
+}
+
+void DrmDeviceManager::UpdateDrmDevice(gfx::AcceleratedWidget widget,
+ const scoped_refptr<DrmDevice>& device) {
+ base::AutoLock lock(lock_);
+ drm_device_map_[widget] = device;
+}
+
+void DrmDeviceManager::RemoveDrmDevice(gfx::AcceleratedWidget widget) {
+ base::AutoLock lock(lock_);
+ auto it = drm_device_map_.find(widget);
+ if (it != drm_device_map_.end())
+ drm_device_map_.erase(it);
+}
+
+scoped_refptr<DrmDevice> DrmDeviceManager::GetDrmDevice(
+ gfx::AcceleratedWidget widget) {
+ base::AutoLock lock(lock_);
+ if (widget == gfx::kNullAcceleratedWidget)
+ return primary_device_;
+
+ auto it = drm_device_map_.find(widget);
+ DCHECK(it != drm_device_map_.end())
+ << "Attempting to get device for unknown widget " << widget;
+ // If the widget isn't associated with a display (headless mode) we can
+ // allocate buffers from any controller since they will never be scanned out.
+ // Use the primary DRM device as a fallback when allocating these buffers.
+ if (!it->second)
+ return primary_device_;
+
+ return it->second;
+}
+
+const DrmDeviceVector& DrmDeviceManager::GetDrmDevices() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return devices_;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_device_manager.h b/ui/ozone/platform/drm/gpu/drm_device_manager.h
new file mode 100644
index 0000000..34fe613
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_device_manager.h
@@ -0,0 +1,90 @@
+// Copyright 2015 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_DEVICE_MANAGER_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_DRM_DEVICE_MANAGER_H_
+
+#include <map>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/ozone_export.h"
+
+namespace base {
+class FilePath;
+struct FileDescriptor;
+class SingleThreadTaskRunner;
+}
+
+namespace ui {
+
+class DrmDevice;
+class DrmDeviceGenerator;
+
+typedef std::vector<scoped_refptr<DrmDevice>> DrmDeviceVector;
+
+// Tracks the mapping between widgets and the DRM devices used to allocate
+// buffers for the window represented by the widget.
+// Note: All calls are protected by a lock since
+// GetDrmDevice(gfx::AcceleratedWidget) may be called on the IO thread.
+class OZONE_EXPORT DrmDeviceManager {
+ public:
+ DrmDeviceManager(scoped_ptr<DrmDeviceGenerator> drm_device_generator);
+ ~DrmDeviceManager();
+
+ // The first device registered is assumed to be the primary device.
+ bool AddDrmDevice(const base::FilePath& path, const base::FileDescriptor& fd);
+ void RemoveDrmDevice(const base::FilePath& path);
+
+ void InitializeIOTaskRunner(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+
+ // Updates the device associated with |widget|.
+ void UpdateDrmDevice(gfx::AcceleratedWidget widget,
+ const scoped_refptr<DrmDevice>& device);
+
+ // Removes the device associated with |widget|.
+ void RemoveDrmDevice(gfx::AcceleratedWidget widget);
+
+ // Returns the device associated with |widget|. If there is no association
+ // returns |primary_device_|.
+ scoped_refptr<DrmDevice> GetDrmDevice(gfx::AcceleratedWidget widget);
+
+ const DrmDeviceVector& GetDrmDevices() const;
+
+ private:
+ // With the exception of GetDrmDevice() all functions must be called on GPU
+ // main.
+ base::ThreadChecker thread_checker_;
+
+ scoped_ptr<DrmDeviceGenerator> drm_device_generator_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+ DrmDeviceVector devices_;
+
+ std::map<gfx::AcceleratedWidget, scoped_refptr<DrmDevice>> drm_device_map_;
+
+ // This device represents the primary graphics device and is used when:
+ // 1) 'widget == kNullAcceleratedWidget' when the API requesting a buffer has
+ // no knowledge of the surface/display it belongs to (currently this happens
+ // for video buffers), or
+ // 2) in order to allocate buffers for unmatched surfaces (surfaces without a
+ // display; ie: when in headless mode).
+ scoped_refptr<DrmDevice> primary_device_;
+
+ // This class is accessed from the main thread and the IO thread. This lock
+ // protects access to the device map.
+ base::Lock lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmDeviceManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_DEVICE_MANAGER_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_display.cc b/ui/ozone/platform/drm/gpu/drm_display.cc
new file mode 100644
index 0000000..4e949ec
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_display.cc
@@ -0,0 +1,179 @@
+// Copyright 2015 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/drm/gpu/drm_display.h"
+
+#include <xf86drmMode.h>
+
+#include "ui/display/types/gamma_ramp_rgb_entry.h"
+#include "ui/ozone/platform/drm/common/drm_util.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/screen_manager.h"
+
+namespace ui {
+
+namespace {
+
+const char kContentProtection[] = "Content Protection";
+
+struct ContentProtectionMapping {
+ const char* name;
+ HDCPState state;
+};
+
+const ContentProtectionMapping kContentProtectionStates[] = {
+ {"Undesired", HDCP_STATE_UNDESIRED},
+ {"Desired", HDCP_STATE_DESIRED},
+ {"Enabled", HDCP_STATE_ENABLED}};
+
+// Converts |state| to the DRM value associated with the it.
+uint32_t GetContentProtectionValue(drmModePropertyRes* property,
+ HDCPState state) {
+ std::string name;
+ for (size_t i = 0; i < arraysize(kContentProtectionStates); ++i) {
+ if (kContentProtectionStates[i].state == state) {
+ name = kContentProtectionStates[i].name;
+ break;
+ }
+ }
+
+ for (int i = 0; i < property->count_enums; ++i)
+ if (name == property->enums[i].name)
+ return i;
+
+ NOTREACHED();
+ return 0;
+}
+
+std::string GetEnumNameForProperty(drmModeConnector* connector,
+ drmModePropertyRes* property) {
+ for (int prop_idx = 0; prop_idx < connector->count_props; ++prop_idx) {
+ if (connector->props[prop_idx] != property->prop_id)
+ continue;
+
+ for (int enum_idx = 0; enum_idx < property->count_enums; ++enum_idx) {
+ const drm_mode_property_enum& property_enum = property->enums[enum_idx];
+ if (property_enum.value == connector->prop_values[prop_idx])
+ return property_enum.name;
+ }
+ }
+
+ NOTREACHED();
+ return std::string();
+}
+
+gfx::Size GetDrmModeSize(const drmModeModeInfo& mode) {
+ return gfx::Size(mode.hdisplay, mode.vdisplay);
+}
+
+std::vector<drmModeModeInfo> GetDrmModeVector(drmModeConnector* connector) {
+ std::vector<drmModeModeInfo> modes;
+ for (int i = 0; i < connector->count_modes; ++i)
+ modes.push_back(connector->modes[i]);
+
+ return modes;
+}
+
+} // namespace
+
+DrmDisplay::DrmDisplay(ScreenManager* screen_manager,
+ const scoped_refptr<DrmDevice>& drm)
+ : screen_manager_(screen_manager), drm_(drm) {
+}
+
+DrmDisplay::~DrmDisplay() {
+}
+
+DisplaySnapshot_Params DrmDisplay::Update(HardwareDisplayControllerInfo* info,
+ size_t display_index) {
+ DisplaySnapshot_Params params =
+ CreateDisplaySnapshotParams(info, drm_->get_fd(), display_index, origin_);
+ crtc_ = info->crtc()->crtc_id;
+ connector_ = info->connector()->connector_id;
+ display_id_ = params.display_id;
+ modes_ = GetDrmModeVector(info->connector());
+ return params;
+}
+
+bool DrmDisplay::Configure(const drmModeModeInfo* mode,
+ const gfx::Point& origin) {
+ VLOG(1) << "DRM configuring: device=" << drm_->device_path().value()
+ << " crtc=" << crtc_ << " connector=" << connector_
+ << " origin=" << origin.ToString()
+ << " size=" << (mode ? GetDrmModeSize(*mode).ToString() : "0x0");
+
+ if (mode) {
+ if (!screen_manager_->ConfigureDisplayController(drm_, crtc_, connector_,
+ origin, *mode)) {
+ VLOG(1) << "Failed to configure: device=" << drm_->device_path().value()
+ << " crtc=" << crtc_ << " connector=" << connector_;
+ return false;
+ }
+ } else {
+ if (!screen_manager_->DisableDisplayController(drm_, crtc_)) {
+ VLOG(1) << "Failed to disable device=" << drm_->device_path().value()
+ << " crtc=" << crtc_;
+ return false;
+ }
+ }
+
+ origin_ = origin;
+ return true;
+}
+
+bool DrmDisplay::GetHDCPState(HDCPState* state) {
+ ScopedDrmConnectorPtr connector(drm_->GetConnector(connector_));
+ if (!connector) {
+ PLOG(ERROR) << "Failed to get connector " << connector_;
+ return false;
+ }
+
+ ScopedDrmPropertyPtr hdcp_property(
+ drm_->GetProperty(connector.get(), kContentProtection));
+ if (!hdcp_property) {
+ PLOG(ERROR) << "'" << kContentProtection << "' property doesn't exist.";
+ return false;
+ }
+
+ std::string name =
+ GetEnumNameForProperty(connector.get(), hdcp_property.get());
+ for (size_t i = 0; i < arraysize(kContentProtectionStates); ++i) {
+ if (name == kContentProtectionStates[i].name) {
+ *state = kContentProtectionStates[i].state;
+ VLOG(3) << "HDCP state: " << *state << " (" << name << ")";
+ return true;
+ }
+ }
+
+ LOG(ERROR) << "Unknown content protection value '" << name << "'";
+ return false;
+}
+
+bool DrmDisplay::SetHDCPState(HDCPState state) {
+ ScopedDrmConnectorPtr connector(drm_->GetConnector(connector_));
+ if (!connector) {
+ PLOG(ERROR) << "Failed to get connector " << connector_;
+ return false;
+ }
+
+ ScopedDrmPropertyPtr hdcp_property(
+ drm_->GetProperty(connector.get(), kContentProtection));
+ if (!hdcp_property) {
+ LOG(ERROR) << "'" << kContentProtection << "' property doesn't exist.";
+ return false;
+ }
+
+ return drm_->SetProperty(
+ connector_, hdcp_property->prop_id,
+ GetContentProtectionValue(hdcp_property.get(), state));
+}
+
+void DrmDisplay::SetGammaRamp(const std::vector<GammaRampRGBEntry>& lut) {
+ if (!drm_->SetGammaRamp(crtc_, lut)) {
+ LOG(ERROR) << "Failed to set gamma ramp for display: crtc_id = " << crtc_
+ << " size = " << lut.size();
+ }
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_display.h b/ui/ozone/platform/drm/gpu/drm_display.h
new file mode 100644
index 0000000..40cd343
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_display.h
@@ -0,0 +1,60 @@
+// Copyright 2015 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_DISPLAY_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_DRM_DISPLAY_H_
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "ui/display/types/display_constants.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+
+typedef struct _drmModeModeInfo drmModeModeInfo;
+
+namespace ui {
+
+class DrmDevice;
+class HardwareDisplayControllerInfo;
+class ScreenManager;
+
+struct GammaRampRGBEntry;
+
+class DrmDisplay {
+ public:
+ DrmDisplay(ScreenManager* screen_manager,
+ const scoped_refptr<DrmDevice>& drm);
+ ~DrmDisplay();
+
+ int64_t display_id() const { return display_id_; }
+ scoped_refptr<DrmDevice> drm() const { return drm_; }
+ uint32_t crtc() const { return crtc_; }
+ uint32_t connector() const { return connector_; }
+ const std::vector<drmModeModeInfo>& modes() const { return modes_; }
+
+ DisplaySnapshot_Params Update(HardwareDisplayControllerInfo* info,
+ size_t display_index);
+
+ bool Configure(const drmModeModeInfo* mode, const gfx::Point& origin);
+ bool GetHDCPState(HDCPState* state);
+ bool SetHDCPState(HDCPState state);
+ void SetGammaRamp(const std::vector<GammaRampRGBEntry>& lut);
+
+ private:
+ ScreenManager* screen_manager_; // Not owned.
+
+ int64_t display_id_ = -1;
+ scoped_refptr<DrmDevice> drm_;
+ uint32_t crtc_ = 0;
+ uint32_t connector_ = 0;
+ std::vector<drmModeModeInfo> modes_;
+ gfx::Point origin_;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmDisplay);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_DISPLAY_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
new file mode 100644
index 0000000..7d7bba4
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
@@ -0,0 +1,230 @@
+// 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/drm/gpu/drm_gpu_display_manager.h"
+
+#include "ui/display/types/gamma_ramp_rgb_entry.h"
+#include "ui/ozone/common/display_util.h"
+#include "ui/ozone/platform/drm/common/drm_util.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
+#include "ui/ozone/platform/drm/gpu/drm_display.h"
+#include "ui/ozone/platform/drm/gpu/screen_manager.h"
+
+namespace ui {
+
+namespace {
+
+class DisplayComparator {
+ public:
+ explicit DisplayComparator(const DrmDisplay* display)
+ : drm_(display->drm()),
+ crtc_(display->crtc()),
+ connector_(display->connector()) {}
+
+ DisplayComparator(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector)
+ : drm_(drm), crtc_(crtc), connector_(connector) {}
+
+ bool operator()(const DrmDisplay* other) const {
+ return drm_ == other->drm() && connector_ == other->connector() &&
+ crtc_ == other->crtc();
+ }
+
+ private:
+ scoped_refptr<DrmDevice> drm_;
+ uint32_t crtc_;
+ uint32_t connector_;
+};
+
+bool FindMatchingMode(const std::vector<drmModeModeInfo> modes,
+ const DisplayMode_Params& mode_params,
+ drmModeModeInfo* mode) {
+ for (const drmModeModeInfo& m : modes) {
+ DisplayMode_Params params = CreateDisplayModeParams(m);
+ if (mode_params.size == params.size &&
+ mode_params.refresh_rate == params.refresh_rate &&
+ mode_params.is_interlaced == params.is_interlaced) {
+ *mode = m;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace
+
+DrmGpuDisplayManager::DrmGpuDisplayManager(ScreenManager* screen_manager,
+ DrmDeviceManager* drm_device_manager)
+ : screen_manager_(screen_manager), drm_device_manager_(drm_device_manager) {
+}
+
+DrmGpuDisplayManager::~DrmGpuDisplayManager() {
+}
+
+std::vector<DisplaySnapshot_Params> DrmGpuDisplayManager::GetDisplays() {
+ ScopedVector<DrmDisplay> old_displays(displays_.Pass());
+ std::vector<DisplaySnapshot_Params> params_list;
+
+ const DrmDeviceVector& devices = drm_device_manager_->GetDrmDevices();
+ // Unique identifier used to create the display id.
+ size_t index = 0;
+ for (const auto& drm : devices) {
+ ScopedVector<HardwareDisplayControllerInfo> display_infos =
+ GetAvailableDisplayControllerInfos(drm->get_fd());
+ for (auto* display_info : display_infos) {
+ auto it = std::find_if(
+ old_displays.begin(), old_displays.end(),
+ DisplayComparator(drm, display_info->crtc()->crtc_id,
+ display_info->connector()->connector_id));
+ if (it != old_displays.end()) {
+ displays_.push_back(*it);
+ old_displays.weak_erase(it);
+ } else {
+ displays_.push_back(new DrmDisplay(screen_manager_, drm));
+ }
+
+ params_list.push_back(displays_.back()->Update(display_info, index++));
+ }
+ }
+
+ NotifyScreenManager(displays_.get(), old_displays.get());
+ return params_list;
+}
+
+bool DrmGpuDisplayManager::TakeDisplayControl() {
+ const DrmDeviceVector& devices = drm_device_manager_->GetDrmDevices();
+ bool status = true;
+ for (const auto& drm : devices)
+ status &= drm->SetMaster();
+
+ // Roll-back any successful operation.
+ if (!status) {
+ LOG(ERROR) << "Failed to take control of the display";
+ RelinquishDisplayControl();
+ }
+
+ return status;
+}
+
+void DrmGpuDisplayManager::RelinquishDisplayControl() {
+ const DrmDeviceVector& devices = drm_device_manager_->GetDrmDevices();
+ for (const auto& drm : devices)
+ drm->DropMaster();
+}
+
+bool DrmGpuDisplayManager::ConfigureDisplay(
+ int64_t display_id,
+ const DisplayMode_Params& mode_param,
+ const gfx::Point& origin) {
+ DrmDisplay* display = FindDisplay(display_id);
+ if (!display) {
+ LOG(ERROR) << "There is no display with ID " << display_id;
+ return false;
+ }
+
+ drmModeModeInfo mode;
+ bool mode_found = FindMatchingMode(display->modes(), mode_param, &mode);
+ if (!mode_found) {
+ // If the display doesn't have the mode natively, then lookup the mode from
+ // other displays and try using it on the current display (some displays
+ // support panel fitting and they can use different modes even if the mode
+ // isn't explicitly declared).
+ for (DrmDisplay* other : displays_) {
+ mode_found = FindMatchingMode(other->modes(), mode_param, &mode);
+ if (mode_found)
+ break;
+ }
+ }
+
+ if (!mode_found) {
+ LOG(ERROR) << "Failed to find mode: size=" << mode_param.size.ToString()
+ << " is_interlaced=" << mode_param.is_interlaced
+ << " refresh_rate=" << mode_param.refresh_rate;
+ return false;
+ }
+
+ return display->Configure(&mode, origin);
+}
+
+bool DrmGpuDisplayManager::DisableDisplay(int64_t display_id) {
+ DrmDisplay* display = FindDisplay(display_id);
+ if (!display) {
+ LOG(ERROR) << "There is no display with ID " << display_id;
+ return false;
+ }
+
+ return display->Configure(nullptr, gfx::Point());
+}
+
+bool DrmGpuDisplayManager::GetHDCPState(int64_t display_id, HDCPState* state) {
+ DrmDisplay* display = FindDisplay(display_id);
+ if (!display) {
+ LOG(ERROR) << "There is no display with ID " << display_id;
+ return false;
+ }
+
+ return display->GetHDCPState(state);
+}
+
+bool DrmGpuDisplayManager::SetHDCPState(int64_t display_id, HDCPState state) {
+ DrmDisplay* display = FindDisplay(display_id);
+ if (!display) {
+ LOG(ERROR) << "There is no display with ID " << display_id;
+ return false;
+ }
+
+ return display->SetHDCPState(state);
+}
+
+void DrmGpuDisplayManager::SetGammaRamp(
+ int64_t display_id,
+ const std::vector<GammaRampRGBEntry>& lut) {
+ DrmDisplay* display = FindDisplay(display_id);
+ if (!display) {
+ LOG(ERROR) << "There is no display with ID " << display_id;
+ return;
+ }
+
+ display->SetGammaRamp(lut);
+}
+
+DrmDisplay* DrmGpuDisplayManager::FindDisplay(int64_t display_id) {
+ for (DrmDisplay* display : displays_)
+ if (display->display_id() == display_id)
+ return display;
+
+ return nullptr;
+}
+
+void DrmGpuDisplayManager::NotifyScreenManager(
+ const std::vector<DrmDisplay*>& new_displays,
+ const std::vector<DrmDisplay*>& old_displays) const {
+ for (size_t i = 0; i < old_displays.size(); ++i) {
+ const std::vector<DrmDisplay*>::const_iterator it =
+ std::find_if(new_displays.begin(), new_displays.end(),
+ DisplayComparator(old_displays[i]));
+
+ if (it == new_displays.end()) {
+ screen_manager_->RemoveDisplayController(old_displays[i]->drm(),
+ old_displays[i]->crtc());
+ }
+ }
+
+ for (size_t i = 0; i < new_displays.size(); ++i) {
+ const std::vector<DrmDisplay*>::const_iterator it =
+ std::find_if(old_displays.begin(), old_displays.end(),
+ DisplayComparator(new_displays[i]));
+
+ if (it == old_displays.end()) {
+ screen_manager_->AddDisplayController(new_displays[i]->drm(),
+ new_displays[i]->crtc(),
+ new_displays[i]->connector());
+ }
+ }
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
new file mode 100644
index 0000000..97ebaa7
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
@@ -0,0 +1,60 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_GPU_DISPLAY_MANAGER_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_DRM_GPU_DISPLAY_MANAGER_H_
+
+#include "base/memory/scoped_vector.h"
+#include "ui/display/types/display_constants.h"
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+
+namespace ui {
+
+class DrmDeviceManager;
+class DrmDisplay;
+class ScreenManager;
+
+struct GammaRampRGBEntry;
+
+class DrmGpuDisplayManager {
+ public:
+ DrmGpuDisplayManager(ScreenManager* screen_manager,
+ DrmDeviceManager* drm_device_manager);
+ ~DrmGpuDisplayManager();
+
+ // Returns a list of the connected displays. When this is called the list of
+ // displays is refreshed.
+ std::vector<DisplaySnapshot_Params> GetDisplays();
+
+ // Takes/releases the control of the DRM devices.
+ bool TakeDisplayControl();
+ void RelinquishDisplayControl();
+
+ bool ConfigureDisplay(int64_t id,
+ const DisplayMode_Params& mode,
+ const gfx::Point& origin);
+ bool DisableDisplay(int64_t id);
+ bool GetHDCPState(int64_t display_id, HDCPState* state);
+ bool SetHDCPState(int64_t display_id, HDCPState state);
+ void SetGammaRamp(int64_t id, const std::vector<GammaRampRGBEntry>& lut);
+
+ private:
+ DrmDisplay* FindDisplay(int64_t display_id);
+
+ // Notify ScreenManager of all the displays that were present before the
+ // update but are gone after the update.
+ void NotifyScreenManager(const std::vector<DrmDisplay*>& new_displays,
+ const std::vector<DrmDisplay*>& old_displays) const;
+
+ ScreenManager* screen_manager_; // Not owned.
+ DrmDeviceManager* drm_device_manager_; // Not owned.
+
+ ScopedVector<DrmDisplay> displays_;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmGpuDisplayManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_GPU_DISPLAY_MANAGER_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_platform_support.cc b/ui/ozone/platform/drm/gpu/drm_gpu_platform_support.cc
new file mode 100644
index 0000000..680749b
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_gpu_platform_support.cc
@@ -0,0 +1,139 @@
+// 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/drm/gpu/drm_gpu_platform_support.h"
+
+#include "base/bind.h"
+#include "base/thread_task_runner_handle.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
+#include "ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h"
+#include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
+#include "ui/ozone/platform/drm/gpu/screen_manager.h"
+
+namespace ui {
+
+DrmGpuPlatformSupport::DrmGpuPlatformSupport(
+ DrmDeviceManager* drm_device_manager,
+ ScreenManager* screen_manager,
+ ScanoutBufferGenerator* buffer_generator,
+ scoped_ptr<DrmGpuDisplayManager> display_manager)
+ : drm_device_manager_(drm_device_manager),
+ screen_manager_(screen_manager),
+ display_manager_(display_manager.Pass()),
+ delegate_(nullptr) {
+}
+
+DrmGpuPlatformSupport::~DrmGpuPlatformSupport() {
+}
+
+void DrmGpuPlatformSupport::SetDelegate(
+ DrmGpuPlatformSupportDelegate* delegate) {
+ DCHECK(!delegate_);
+ delegate_ = delegate;
+}
+
+void DrmGpuPlatformSupport::AddHandler(scoped_ptr<GpuPlatformSupport> handler) {
+ handlers_.push_back(handler.Pass());
+}
+
+void DrmGpuPlatformSupport::OnChannelEstablished() {
+ for (size_t i = 0; i < handlers_.size(); ++i)
+ handlers_[i]->OnChannelEstablished();
+}
+
+void DrmGpuPlatformSupport::OnCreateWindow(gfx::AcceleratedWidget widget) {
+ scoped_ptr<DrmWindow> delegate(
+ new DrmWindow(widget, drm_device_manager_, screen_manager_));
+ delegate->Initialize();
+ screen_manager_->AddWindow(widget, delegate.Pass());
+}
+
+void DrmGpuPlatformSupport::OnDestroyWindow(gfx::AcceleratedWidget widget) {
+ scoped_ptr<DrmWindow> delegate = screen_manager_->RemoveWindow(widget);
+ delegate->Shutdown();
+}
+
+void DrmGpuPlatformSupport::OnWindowBoundsChanged(gfx::AcceleratedWidget widget,
+ const gfx::Rect& bounds) {
+ screen_manager_->GetWindow(widget)->OnBoundsChanged(bounds);
+}
+
+void DrmGpuPlatformSupport::OnRefreshNativeDisplays() {
+ DCHECK(delegate_);
+ delegate_->UpdateNativeDisplays(display_manager()->GetDisplays());
+}
+
+void DrmGpuPlatformSupport::OnCursorSet(gfx::AcceleratedWidget widget,
+ const std::vector<SkBitmap>& bitmaps,
+ const gfx::Point& location,
+ int frame_delay_ms) {
+ screen_manager_->GetWindow(widget)
+ ->SetCursor(bitmaps, location, frame_delay_ms);
+}
+
+void DrmGpuPlatformSupport::OnCursorMove(gfx::AcceleratedWidget widget,
+ const gfx::Point& location) {
+ screen_manager_->GetWindow(widget)->MoveCursor(location);
+}
+
+void DrmGpuPlatformSupport::OnCheckOverlayCapabilities(
+ gfx::AcceleratedWidget widget,
+ const std::vector<OverlayCheck_Params>& overlays) {
+ NOTIMPLEMENTED();
+}
+
+void DrmGpuPlatformSupport::OnConfigureNativeDisplay(
+ int64_t id,
+ const DisplayMode_Params& mode_param,
+ const gfx::Point& origin) {
+ DCHECK(delegate_);
+ delegate_->DisplayConfigured(
+ id, display_manager_->ConfigureDisplay(id, mode_param, origin));
+}
+
+void DrmGpuPlatformSupport::OnDisableNativeDisplay(int64_t id) {
+ NOTIMPLEMENTED();
+}
+
+void DrmGpuPlatformSupport::OnTakeDisplayControl() {
+ NOTIMPLEMENTED();
+}
+
+void DrmGpuPlatformSupport::OnRelinquishDisplayControl() {
+ NOTIMPLEMENTED();
+}
+
+void DrmGpuPlatformSupport::OnAddGraphicsDevice(
+ const base::FilePath& path,
+ const base::FileDescriptor& fd) {
+ drm_device_manager_->AddDrmDevice(path, fd);
+}
+
+void DrmGpuPlatformSupport::OnRemoveGraphicsDevice(const base::FilePath& path) {
+ drm_device_manager_->RemoveDrmDevice(path);
+}
+
+void DrmGpuPlatformSupport::OnSetGammaRamp(
+ int64_t id,
+ const std::vector<GammaRampRGBEntry>& lut) {
+ display_manager_->SetGammaRamp(id, lut);
+}
+
+void DrmGpuPlatformSupport::OnGetHDCPState(int64_t display_id) {
+ NOTIMPLEMENTED();
+}
+
+void DrmGpuPlatformSupport::OnSetHDCPState(int64_t display_id,
+ HDCPState state) {
+ NOTIMPLEMENTED();
+}
+
+void DrmGpuPlatformSupport::SetIOTaskRunner(
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) {
+ drm_device_manager_->InitializeIOTaskRunner(io_task_runner);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_platform_support.h b/ui/ozone/platform/drm/gpu/drm_gpu_platform_support.h
new file mode 100644
index 0000000..27eb819
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_gpu_platform_support.h
@@ -0,0 +1,115 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_GPU_PLATFORM_SUPPORT_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_DRM_GPU_PLATFORM_SUPPORT_H_
+
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "ui/display/types/display_constants.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/public/gpu_platform_support.h"
+
+class SkBitmap;
+
+namespace base {
+class FilePath;
+class SingleThreadTaskRunner;
+struct FileDescriptor;
+}
+
+namespace gfx {
+class Point;
+class Rect;
+}
+
+namespace ui {
+
+class DrmDeviceManager;
+class DrmGpuDisplayManager;
+class DrmSurfaceFactory;
+class DrmWindow;
+class ScreenManager;
+class ScanoutBufferGenerator;
+
+struct DisplayMode_Params;
+struct DisplaySnapshot_Params;
+struct OverlayCheck_Params;
+struct GammaRampRGBEntry;
+
+class DrmGpuPlatformSupportDelegate {
+public:
+ DrmGpuPlatformSupportDelegate() {};
+ virtual ~DrmGpuPlatformSupportDelegate() {};
+
+ virtual void UpdateNativeDisplays(
+ const std::vector<DisplaySnapshot_Params>& displays) = 0;
+ virtual void DisplayConfigured(int64_t id, bool result) = 0;
+};
+
+class DrmGpuPlatformSupport : public GpuPlatformSupport {
+ public:
+ DrmGpuPlatformSupport(DrmDeviceManager* drm_device_manager,
+ ScreenManager* screen_manager,
+ ScanoutBufferGenerator* buffer_generator,
+ scoped_ptr<DrmGpuDisplayManager> display_manager);
+ ~DrmGpuPlatformSupport() override;
+
+ void SetDelegate(DrmGpuPlatformSupportDelegate* delegate);
+
+ DrmGpuPlatformSupportDelegate* get_delegate() const {
+ return delegate_;
+ }
+
+ void AddHandler(scoped_ptr<GpuPlatformSupport> handler);
+
+ // GpuPlatformSupport:
+ void OnChannelEstablished() override;
+
+ void OnCreateWindow(gfx::AcceleratedWidget widget);
+ void OnDestroyWindow(gfx::AcceleratedWidget widget);
+ void OnWindowBoundsChanged(gfx::AcceleratedWidget widget,
+ const gfx::Rect& bounds);
+ void OnCursorSet(gfx::AcceleratedWidget widget,
+ const std::vector<SkBitmap>& bitmaps,
+ const gfx::Point& location,
+ int frame_delay_ms);
+ void OnCursorMove(gfx::AcceleratedWidget widget, const gfx::Point& location);
+ void OnCheckOverlayCapabilities(
+ gfx::AcceleratedWidget widget,
+ const std::vector<OverlayCheck_Params>& overlays);
+
+ DrmGpuDisplayManager* display_manager() {
+ return display_manager_.get();
+ }
+
+ void OnRefreshNativeDisplays();
+ void OnConfigureNativeDisplay(int64_t id,
+ const DisplayMode_Params& mode,
+ const gfx::Point& origin);
+ void OnDisableNativeDisplay(int64_t id);
+ void OnTakeDisplayControl();
+ void OnRelinquishDisplayControl();
+ void OnAddGraphicsDevice(const base::FilePath& path,
+ const base::FileDescriptor& fd);
+ void OnRemoveGraphicsDevice(const base::FilePath& path);
+ void OnGetHDCPState(int64_t display_id);
+ void OnSetHDCPState(int64_t display_id, HDCPState state);
+ void OnSetGammaRamp(int64_t id, const std::vector<GammaRampRGBEntry>& lut);
+
+ void SetIOTaskRunner(
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
+
+ DrmDeviceManager* drm_device_manager_; // Not owned.
+ ScreenManager* screen_manager_; // Not owned.
+
+ scoped_ptr<DrmGpuDisplayManager> display_manager_;
+ ScopedVector<GpuPlatformSupport> handlers_;
+ DrmGpuPlatformSupportDelegate* delegate_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_GPU_PLATFORM_SUPPORT_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_platform_support_inprocess.cc b/ui/ozone/platform/drm/gpu/drm_gpu_platform_support_inprocess.cc
new file mode 100644
index 0000000..a467480
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_gpu_platform_support_inprocess.cc
@@ -0,0 +1,94 @@
+// 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 "base/bind.h"
+#include "base/location.h"
+#include "ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h"
+#include "ui/ozone/platform/drm/gpu/drm_gpu_platform_support_inprocess.h"
+#include "ui/ozone/public/ozone_platform.h"
+
+namespace ui {
+
+DrmGpuPlatformSupportInprocess::DrmGpuPlatformSupportInprocess()
+ : platform_support_(static_cast<ui::DrmGpuPlatformSupport*>(
+ ui::OzonePlatform::GetInstance()->GetGpuPlatformSupport())) {
+ platform_support_->SetDelegate(this);
+}
+
+DrmGpuPlatformSupportInprocess::~DrmGpuPlatformSupportInprocess() {
+}
+
+void DrmGpuPlatformSupportInprocess::OnChannelEstablished(
+ scoped_refptr<base::SingleThreadTaskRunner> send_runner,
+ base::Callback<void(Message*)> send_callback) {
+
+ send_runner_ = send_runner;
+ send_callback_ = send_callback;
+
+ platform_support_->OnChannelEstablished();
+}
+
+bool DrmGpuPlatformSupportInprocess::OnMessageReceived(const Message& message) {
+ bool handled = true;
+
+ switch (message.id) {
+ case OZONE_GPU_MSG__CREATE_WINDOW:
+ platform_support_->OnCreateWindow(
+ static_cast<const OzoneGpuMsg_CreateWindow*>(&message)->widget);
+ break;
+
+ case OZONE_GPU_MSG__WINDOW_BOUNDS_CHANGED: {
+ auto message_params = static_cast<
+ const OzoneGpuMsg_WindowBoundsChanged*>(&message);
+ platform_support_->OnWindowBoundsChanged(message_params->widget,
+ message_params->bounds);
+ break;
+ }
+
+ case OZONE_GPU_MSG__ADD_GRAPHICS_DEVICE: {
+ auto message_params = static_cast<
+ const OzoneGpuMsg_AddGraphicsDevice*>(&message);
+ platform_support_->OnAddGraphicsDevice(message_params->path,
+ message_params->fd);
+ break;
+ }
+
+ case OZONE_GPU_MSG__REFRESH_NATIVE_DISPLAYS:
+ platform_support_->OnRefreshNativeDisplays();
+ break;
+
+ case OZONE_GPU_MSG__CONFIGURE_NATIVE_DISPLAY: {
+ auto message_params = static_cast<
+ const OzoneGpuMsg_ConfigureNativeDisplay*>(&message);
+ platform_support_->OnConfigureNativeDisplay(
+ message_params->id, message_params->mode, message_params->originhost);
+ break;
+ }
+
+ default:
+ handled = false;
+ }
+
+ return handled;
+}
+
+void DrmGpuPlatformSupportInprocess::UpdateNativeDisplays(
+ const std::vector<DisplaySnapshot_Params>& displays) {
+ Send(new OzoneHostMsg_UpdateNativeDisplays(displays));
+}
+
+void DrmGpuPlatformSupportInprocess::DisplayConfigured(int64_t id,
+ bool result) {
+ Send(new OzoneHostMsg_DisplayConfigured(id, result));
+}
+
+bool DrmGpuPlatformSupportInprocess::Send(Message* message) {
+ if (send_runner_->PostTask(FROM_HERE, base::Bind(send_callback_, message)))
+ return true;
+
+ delete message;
+ return false;
+}
+
+} // namespace
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_platform_support_inprocess.h b/ui/ozone/platform/drm/gpu/drm_gpu_platform_support_inprocess.h
new file mode 100644
index 0000000..45692e3
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_gpu_platform_support_inprocess.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_GPU_PLATFORM_SUPPORT_INPROCESS_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_DRM_GPU_PLATFORM_SUPPORT_INPROCESS_H_
+
+#include "base/callback.h"
+#include "base/single_thread_task_runner.h"
+#include "ui/ozone/platform/drm/common/inprocess_messages.h"
+#include "ui/ozone/platform/drm/gpu/drm_gpu_platform_support.h"
+
+namespace ui {
+
+class DrmGpuPlatformSupportInprocess : public DrmGpuPlatformSupportDelegate {
+ public:
+ DrmGpuPlatformSupportInprocess();
+ ~DrmGpuPlatformSupportInprocess() override;
+
+ void OnChannelEstablished(
+ scoped_refptr<base::SingleThreadTaskRunner> send_runner,
+ base::Callback<void(Message*)> send_callback);
+
+ bool OnMessageReceived(const Message& message);
+ bool Send(Message* message);
+
+ void UpdateNativeDisplays(
+ const std::vector<DisplaySnapshot_Params>& displays) override;
+ void DisplayConfigured(int64_t id, bool result) override;
+
+ private:
+ DrmGpuPlatformSupport* platform_support_;
+ scoped_refptr<base::SingleThreadTaskRunner> send_runner_;
+ base::Callback<void(Message*)> send_callback_;
+};
+
+} // namespace
+
+#endif
diff --git a/ui/ozone/platform/drm/gpu/drm_surface.cc b/ui/ozone/platform/drm/gpu/drm_surface.cc
new file mode 100644
index 0000000..707f3c9
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_surface.cc
@@ -0,0 +1,116 @@
+// 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/drm/gpu/drm_surface.h"
+
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/ozone/platform/drm/gpu/drm_buffer.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/drm_vsync_provider.h"
+#include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+
+namespace ui {
+
+namespace {
+
+scoped_refptr<DrmBuffer> AllocateBuffer(const scoped_refptr<DrmDevice>& drm,
+ const gfx::Size& size) {
+ scoped_refptr<DrmBuffer> buffer(new DrmBuffer(drm));
+ SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
+
+ bool initialized =
+ buffer->Initialize(info, true /* should_register_framebuffer */);
+ DCHECK(initialized) << "Failed to create drm buffer.";
+
+ return buffer;
+}
+
+} // namespace
+
+DrmSurface::DrmSurface(DrmWindow* window_delegate)
+ : window_delegate_(window_delegate),
+ weak_ptr_factory_(this) {
+}
+
+DrmSurface::~DrmSurface() {
+}
+
+skia::RefPtr<SkSurface> DrmSurface::GetSurface() {
+ return surface_;
+}
+
+void DrmSurface::ResizeCanvas(const gfx::Size& viewport_size) {
+ SkImageInfo info = SkImageInfo::MakeN32(
+ viewport_size.width(), viewport_size.height(), kOpaque_SkAlphaType);
+ surface_ = skia::AdoptRef(SkSurface::NewRaster(info));
+
+ HardwareDisplayController* controller = window_delegate_->GetController();
+ if (!controller)
+ return;
+
+ // For the display buffers use the mode size since a |viewport_size| smaller
+ // than the display size will not scanout.
+ front_buffer_ = AllocateBuffer(controller->GetAllocationDrmDevice(),
+ controller->GetModeSize());
+ back_buffer_ = AllocateBuffer(controller->GetAllocationDrmDevice(),
+ controller->GetModeSize());
+}
+
+void DrmSurface::PresentCanvas(const gfx::Rect& damage) {
+ DCHECK(base::MessageLoopForUI::IsCurrent());
+
+ // Create a snapshot of the requested drawing. If we get here again before
+ // presenting, just add the additional damage.
+ pending_image_damage_.Union(damage);
+ pending_image_ = skia::AdoptRef(surface_->newImageSnapshot());
+
+ if (!pending_pageflip_)
+ SchedulePageFlip();
+}
+
+scoped_ptr<gfx::VSyncProvider> DrmSurface::CreateVSyncProvider() {
+ return make_scoped_ptr(new DrmVSyncProvider(window_delegate_));
+}
+
+void DrmSurface::SchedulePageFlip() {
+ DCHECK(back_buffer_);
+ SkCanvas* canvas = back_buffer_->GetCanvas();
+
+ // The DrmSurface is double buffered, so the current back buffer is
+ // missing the previous update. Expand damage region.
+ SkRect real_damage =
+ RectToSkRect(UnionRects(pending_image_damage_, last_damage_));
+
+ // Copy damage region.
+ canvas->drawImageRect(pending_image_.get(), &real_damage, real_damage, NULL);
+ last_damage_ = pending_image_damage_;
+
+ pending_image_.clear();
+ pending_image_damage_ = gfx::Rect();
+
+ window_delegate_->QueueOverlayPlane(OverlayPlane(back_buffer_));
+
+ // Update our front buffer pointer.
+ std::swap(front_buffer_, back_buffer_);
+ pending_pageflip_ = window_delegate_->SchedulePageFlip(
+ false /* is_sync */,
+ base::Bind(&DrmSurface::OnPageFlip, weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DrmSurface::OnPageFlip(gfx::SwapResult result) {
+ pending_pageflip_ = false;
+ if (!pending_image_)
+ return;
+
+ SchedulePageFlip();
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_surface.h b/ui/ozone/platform/drm/gpu/drm_surface.h
new file mode 100644
index 0000000..65fe969
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_surface.h
@@ -0,0 +1,67 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_SURFACE_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_DRM_SURFACE_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/gfx/swap_result.h"
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+
+class SkImage;
+class SkSurface;
+
+namespace ui {
+
+class DrmBuffer;
+class DrmWindow;
+class HardwareDisplayController;
+
+class OZONE_EXPORT DrmSurface : public SurfaceOzoneCanvas {
+ public:
+ DrmSurface(DrmWindow* window_delegate);
+ ~DrmSurface() override;
+
+ // SurfaceOzoneCanvas:
+ skia::RefPtr<SkSurface> GetSurface() override;
+ void ResizeCanvas(const gfx::Size& viewport_size) override;
+ void PresentCanvas(const gfx::Rect& damage) override;
+ scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override;
+
+ private:
+ void SchedulePageFlip();
+
+ // Callback for SchedulePageFlip(). This will signal when the page flip event
+ // has completed.
+ void OnPageFlip(gfx::SwapResult result);
+
+ DrmWindow* window_delegate_;
+
+ // The actual buffers used for painting.
+ scoped_refptr<DrmBuffer> front_buffer_;
+ scoped_refptr<DrmBuffer> back_buffer_;
+
+ skia::RefPtr<SkSurface> surface_;
+ gfx::Rect last_damage_;
+
+ // Keep track of the requested image and damage for the last presentation.
+ // This will be used to update the scanout buffers once the previous page flip
+ // events completes.
+ skia::RefPtr<SkImage> pending_image_;
+ gfx::Rect pending_image_damage_;
+ bool pending_pageflip_ = false;
+
+ base::WeakPtrFactory<DrmSurface> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmSurface);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_SURFACE_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_surface_factory.cc b/ui/ozone/platform/drm/gpu/drm_surface_factory.cc
new file mode 100644
index 0000000..fc64d25
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_surface_factory.cc
@@ -0,0 +1,39 @@
+// 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/drm/gpu/drm_surface_factory.h"
+
+#include <errno.h>
+
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/drm/common/drm_util.h"
+#include "ui/ozone/platform/drm/gpu/drm_surface.h"
+#include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+#include "ui/ozone/platform/drm/gpu/screen_manager.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+
+namespace ui {
+
+DrmSurfaceFactory::DrmSurfaceFactory(ScreenManager* screen_manager)
+ : screen_manager_(screen_manager) {
+}
+
+DrmSurfaceFactory::~DrmSurfaceFactory() {
+}
+
+scoped_ptr<ui::SurfaceOzoneCanvas> DrmSurfaceFactory::CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return make_scoped_ptr(new DrmSurface(screen_manager_->GetWindow(widget)));
+}
+
+bool DrmSurfaceFactory::LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return false;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_surface_factory.h b/ui/ozone/platform/drm/gpu/drm_surface_factory.h
new file mode 100644
index 0000000..223a7b9
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_surface_factory.h
@@ -0,0 +1,41 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_SURFACE_FACTORY_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_DRM_SURFACE_FACTORY_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace ui {
+
+class ScreenManager;
+class SurfaceOzoneCanvas;
+
+// SurfaceFactoryOzone implementation on top of DRM/KMS using dumb buffers.
+// This implementation is used in conjunction with the software rendering
+// path.
+class DrmSurfaceFactory : public SurfaceFactoryOzone {
+ public:
+ DrmSurfaceFactory(ScreenManager* screen_manager);
+ ~DrmSurfaceFactory() override;
+
+ // SurfaceFactoryOzone:
+ scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget) override;
+ bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) override;
+
+ protected:
+ ScreenManager* screen_manager_; // Not owned.
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmSurfaceFactory);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_SURFACE_FACTORY_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_surface_unittest.cc b/ui/ozone/platform/drm/gpu/drm_surface_unittest.cc
new file mode 100644
index 0000000..4498f1f
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_surface_unittest.cc
@@ -0,0 +1,191 @@
+// 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 "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkDevice.h"
+#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
+#include "ui/ozone/platform/drm/gpu/drm_buffer.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
+#include "ui/ozone/platform/drm/gpu/drm_surface.h"
+#include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+#include "ui/ozone/platform/drm/gpu/screen_manager.h"
+#include "ui/ozone/platform/drm/test/mock_drm_device.h"
+
+namespace {
+
+// Create a basic mode for a 6x4 screen.
+const drmModeModeInfo kDefaultMode =
+ {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
+
+const gfx::AcceleratedWidget kDefaultWidgetHandle = 1;
+const uint32_t kDefaultCrtc = 1;
+const uint32_t kDefaultConnector = 2;
+const size_t kPlanesPerCrtc = 1;
+const uint32_t kDefaultCursorSize = 64;
+
+} // namespace
+
+class DrmSurfaceTest : public testing::Test {
+ public:
+ DrmSurfaceTest() {}
+
+ void SetUp() override;
+ void TearDown() override;
+
+ protected:
+ scoped_ptr<base::MessageLoop> message_loop_;
+ scoped_refptr<ui::MockDrmDevice> drm_;
+ scoped_ptr<ui::DrmBufferGenerator> buffer_generator_;
+ scoped_ptr<ui::ScreenManager> screen_manager_;
+ scoped_ptr<ui::DrmDeviceManager> drm_device_manager_;
+ scoped_ptr<ui::DrmSurface> surface_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DrmSurfaceTest);
+};
+
+void DrmSurfaceTest::SetUp() {
+ message_loop_.reset(new base::MessageLoopForUI);
+ std::vector<uint32_t> crtcs;
+ crtcs.push_back(kDefaultCrtc);
+ drm_ = new ui::MockDrmDevice(false, crtcs, kPlanesPerCrtc);
+ buffer_generator_.reset(new ui::DrmBufferGenerator());
+ screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get()));
+ screen_manager_->AddDisplayController(drm_, kDefaultCrtc, kDefaultConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kDefaultCrtc, kDefaultConnector, gfx::Point(), kDefaultMode);
+
+ drm_device_manager_.reset(new ui::DrmDeviceManager(nullptr));
+ scoped_ptr<ui::DrmWindow> window(new ui::DrmWindow(
+ kDefaultWidgetHandle, drm_device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->OnBoundsChanged(
+ gfx::Rect(gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay)));
+ screen_manager_->AddWindow(kDefaultWidgetHandle, window.Pass());
+
+ surface_.reset(
+ new ui::DrmSurface(screen_manager_->GetWindow(kDefaultWidgetHandle)));
+ surface_->ResizeCanvas(
+ gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay));
+}
+
+void DrmSurfaceTest::TearDown() {
+ surface_.reset();
+ scoped_ptr<ui::DrmWindow> window =
+ screen_manager_->RemoveWindow(kDefaultWidgetHandle);
+ window->Shutdown();
+ drm_ = nullptr;
+ message_loop_.reset();
+}
+
+TEST_F(DrmSurfaceTest, CheckFBIDOnSwap) {
+ surface_->PresentCanvas(gfx::Rect());
+ drm_->RunCallbacks();
+ // Framebuffer ID 1 is allocated in SetUp for the buffer used to modeset.
+ EXPECT_EQ(3u, drm_->current_framebuffer());
+ surface_->PresentCanvas(gfx::Rect());
+ drm_->RunCallbacks();
+ EXPECT_EQ(2u, drm_->current_framebuffer());
+}
+
+TEST_F(DrmSurfaceTest, CheckSurfaceContents) {
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ SkRect rect =
+ SkRect::MakeWH(kDefaultMode.hdisplay / 2, kDefaultMode.vdisplay / 2);
+ surface_->GetSurface()->getCanvas()->drawRect(rect, paint);
+ surface_->PresentCanvas(
+ gfx::Rect(0, 0, kDefaultMode.hdisplay / 2, kDefaultMode.vdisplay / 2));
+ drm_->RunCallbacks();
+
+ SkBitmap image;
+ std::vector<skia::RefPtr<SkSurface>> framebuffers;
+ for (const auto& buffer : drm_->buffers()) {
+ // Skip cursor buffers.
+ if (buffer->width() == kDefaultCursorSize &&
+ buffer->height() == kDefaultCursorSize)
+ continue;
+
+ framebuffers.push_back(buffer);
+ }
+
+ // Buffer 0 is the modesetting buffer, buffer 1 is the frontbuffer and buffer
+ // 2 is the backbuffer.
+ EXPECT_EQ(3u, framebuffers.size());
+
+ image.setInfo(framebuffers[2]->getCanvas()->imageInfo());
+ EXPECT_TRUE(framebuffers[2]->getCanvas()->readPixels(&image, 0, 0));
+
+ EXPECT_EQ(kDefaultMode.hdisplay, image.width());
+ EXPECT_EQ(kDefaultMode.vdisplay, image.height());
+
+ // Make sure the updates are correctly propagated to the native surface.
+ for (int i = 0; i < image.height(); ++i) {
+ for (int j = 0; j < image.width(); ++j) {
+ if (j < kDefaultMode.hdisplay / 2 && i < kDefaultMode.vdisplay / 2)
+ EXPECT_EQ(SK_ColorWHITE, image.getColor(j, i));
+ else
+ EXPECT_EQ(SK_ColorBLACK, image.getColor(j, i));
+ }
+ }
+}
+
+TEST_F(DrmSurfaceTest, CheckSurfaceContentsAfter2QueuedPresents) {
+ gfx::Rect rect;
+ // Present an empty buffer but don't respond with the page flip event since we
+ // want to make sure the following presents will aggregate correctly.
+ surface_->PresentCanvas(rect);
+
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ rect.SetRect(0, 0, kDefaultMode.hdisplay / 2, kDefaultMode.vdisplay / 2);
+ surface_->GetSurface()->getCanvas()->drawRect(RectToSkRect(rect), paint);
+ surface_->PresentCanvas(rect);
+
+ paint.setColor(SK_ColorRED);
+ rect.SetRect(0, kDefaultMode.vdisplay / 2, kDefaultMode.hdisplay / 2,
+ kDefaultMode.vdisplay / 2);
+ surface_->GetSurface()->getCanvas()->drawRect(RectToSkRect(rect), paint);
+ surface_->PresentCanvas(rect);
+
+ drm_->RunCallbacks();
+
+ SkBitmap image;
+ std::vector<skia::RefPtr<SkSurface>> framebuffers;
+ for (const auto& buffer : drm_->buffers()) {
+ // Skip cursor buffers.
+ if (buffer->width() == kDefaultCursorSize &&
+ buffer->height() == kDefaultCursorSize)
+ continue;
+
+ framebuffers.push_back(buffer);
+ }
+
+ // Buffer 0 is the modesetting buffer, buffer 1 is the backbuffer and buffer
+ // 2 is the frontbuffer.
+ EXPECT_EQ(3u, framebuffers.size());
+
+ image.setInfo(framebuffers[1]->getCanvas()->imageInfo());
+ EXPECT_TRUE(framebuffers[1]->getCanvas()->readPixels(&image, 0, 0));
+
+ EXPECT_EQ(kDefaultMode.hdisplay, image.width());
+ EXPECT_EQ(kDefaultMode.vdisplay, image.height());
+
+ // Make sure the updates are correctly propagated to the native surface.
+ for (int i = 0; i < image.height(); ++i) {
+ for (int j = 0; j < image.width(); ++j) {
+ if (j < kDefaultMode.hdisplay / 2 && i < kDefaultMode.vdisplay / 2)
+ EXPECT_EQ(SK_ColorWHITE, image.getColor(j, i));
+ else if (j < kDefaultMode.hdisplay / 2)
+ EXPECT_EQ(SK_ColorRED, image.getColor(j, i));
+ else
+ EXPECT_EQ(SK_ColorBLACK, image.getColor(j, i));
+ }
+ }
+}
diff --git a/ui/ozone/platform/drm/gpu/drm_vsync_provider.cc b/ui/ozone/platform/drm/gpu/drm_vsync_provider.cc
new file mode 100644
index 0000000..bb846b5
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_vsync_provider.cc
@@ -0,0 +1,40 @@
+// 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/drm/gpu/drm_vsync_provider.h"
+
+#include "base/time/time.h"
+#include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+
+namespace ui {
+
+DrmVSyncProvider::DrmVSyncProvider(DrmWindow* window_delegate)
+ : window_delegate_(window_delegate) {
+}
+
+DrmVSyncProvider::~DrmVSyncProvider() {
+}
+
+void DrmVSyncProvider::GetVSyncParameters(const UpdateVSyncCallback& callback) {
+ HardwareDisplayController* controller = window_delegate_->GetController();
+ if (!controller)
+ return;
+
+ // The value is invalid, so we can't update the parameters.
+ if (controller->GetTimeOfLastFlip() == 0 ||
+ controller->get_mode().vrefresh == 0)
+ return;
+
+ // Stores the time of the last refresh.
+ base::TimeTicks timebase =
+ base::TimeTicks::FromInternalValue(controller->GetTimeOfLastFlip());
+ // Stores the refresh rate.
+ base::TimeDelta interval =
+ base::TimeDelta::FromSeconds(1) / controller->get_mode().vrefresh;
+
+ callback.Run(timebase, interval);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_vsync_provider.h b/ui/ozone/platform/drm/gpu/drm_vsync_provider.h
new file mode 100644
index 0000000..dba2980
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_vsync_provider.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_IMPL_DRM_VSYNC_PROVIDER_H_
+#define UI_OZONE_PLATFORM_IMPL_DRM_VSYNC_PROVIDER_H_
+
+#include "ui/gfx/vsync_provider.h"
+
+namespace ui {
+
+class DrmWindow;
+
+class DrmVSyncProvider : public gfx::VSyncProvider {
+ public:
+ DrmVSyncProvider(DrmWindow* window_delegate);
+ ~DrmVSyncProvider() override;
+
+ void GetVSyncParameters(const UpdateVSyncCallback& callback) override;
+
+ private:
+ DrmWindow* window_delegate_; // Not owned.
+
+ DISALLOW_COPY_AND_ASSIGN(DrmVSyncProvider);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_IMPL_DRM_VSYNC_PROVIDER_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_window.cc b/ui/ozone/platform/drm/gpu/drm_window.cc
new file mode 100644
index 0000000..3dda06c
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_window.cc
@@ -0,0 +1,244 @@
+// 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/drm/gpu/drm_window.h"
+
+#include "base/trace_event/trace_event.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkDevice.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+#include "ui/ozone/platform/drm/gpu/drm_buffer.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
+#include "ui/ozone/platform/drm/gpu/screen_manager.h"
+
+namespace ui {
+
+namespace {
+
+#ifndef DRM_CAP_CURSOR_WIDTH
+#define DRM_CAP_CURSOR_WIDTH 0x8
+#endif
+
+#ifndef DRM_CAP_CURSOR_HEIGHT
+#define DRM_CAP_CURSOR_HEIGHT 0x9
+#endif
+
+void EmptyFlipCallback(gfx::SwapResult) {
+}
+
+void UpdateCursorImage(DrmBuffer* cursor, const SkBitmap& image) {
+ SkRect damage;
+ image.getBounds(&damage);
+
+ // Clear to transparent in case |image| is smaller than the canvas.
+ SkCanvas* canvas = cursor->GetCanvas();
+ canvas->clear(SK_ColorTRANSPARENT);
+
+ SkRect clip;
+ clip.set(0, 0, canvas->getDeviceSize().width(),
+ canvas->getDeviceSize().height());
+ canvas->clipRect(clip, SkRegion::kReplace_Op);
+ canvas->drawBitmapRectToRect(image, &damage, damage);
+}
+
+} // namespace
+
+DrmWindow::DrmWindow(gfx::AcceleratedWidget widget,
+ DrmDeviceManager* device_manager,
+ ScreenManager* screen_manager)
+ : widget_(widget),
+ device_manager_(device_manager),
+ screen_manager_(screen_manager) {
+}
+
+DrmWindow::~DrmWindow() {
+}
+
+void DrmWindow::Initialize() {
+ TRACE_EVENT1("drm", "DrmWindow::Initialize", "widget", widget_);
+
+ device_manager_->UpdateDrmDevice(widget_, nullptr);
+}
+
+void DrmWindow::Shutdown() {
+ TRACE_EVENT1("drm", "DrmWindow::Shutdown", "widget", widget_);
+ device_manager_->RemoveDrmDevice(widget_);
+}
+
+gfx::AcceleratedWidget DrmWindow::GetAcceleratedWidget() {
+ return widget_;
+}
+
+HardwareDisplayController* DrmWindow::GetController() {
+ return controller_;
+}
+
+void DrmWindow::OnBoundsChanged(const gfx::Rect& bounds) {
+ TRACE_EVENT2("drm", "DrmWindow::OnBoundsChanged", "widget", widget_, "bounds",
+ bounds.ToString());
+ bounds_ = bounds;
+ if (bounds_.size() != bounds.size())
+ last_submitted_planes_.clear();
+
+ screen_manager_->UpdateControllerToWindowMapping();
+}
+
+void DrmWindow::SetCursor(const std::vector<SkBitmap>& bitmaps,
+ const gfx::Point& location,
+ int frame_delay_ms) {
+ cursor_bitmaps_ = bitmaps;
+ cursor_location_ = location;
+ cursor_frame_ = 0;
+ cursor_frame_delay_ms_ = frame_delay_ms;
+ cursor_timer_.Stop();
+
+ if (cursor_frame_delay_ms_)
+ cursor_timer_.Start(
+ FROM_HERE, base::TimeDelta::FromMilliseconds(cursor_frame_delay_ms_),
+ this, &DrmWindow::OnCursorAnimationTimeout);
+
+ ResetCursor(false);
+}
+
+void DrmWindow::SetCursorWithoutAnimations(const std::vector<SkBitmap>& bitmaps,
+ const gfx::Point& location) {
+ cursor_bitmaps_ = bitmaps;
+ cursor_location_ = location;
+ cursor_frame_ = 0;
+ cursor_frame_delay_ms_ = 0;
+ ResetCursor(false);
+}
+
+void DrmWindow::MoveCursor(const gfx::Point& location) {
+ cursor_location_ = location;
+
+ if (controller_)
+ controller_->MoveCursor(location);
+}
+
+void DrmWindow::QueueOverlayPlane(const OverlayPlane& plane) {
+ pending_planes_.push_back(plane);
+}
+
+bool DrmWindow::SchedulePageFlip(bool is_sync,
+ const SwapCompletionCallback& callback) {
+ last_submitted_planes_.clear();
+ last_submitted_planes_.swap(pending_planes_);
+ last_swap_sync_ = is_sync;
+
+ if (controller_) {
+ return controller_->SchedulePageFlip(last_submitted_planes_, is_sync, false,
+ callback);
+ }
+
+ callback.Run(gfx::SwapResult::SWAP_ACK);
+ return true;
+}
+
+bool DrmWindow::TestPageFlip(const std::vector<OverlayCheck_Params>& overlays,
+ ScanoutBufferGenerator* buffer_generator) {
+ if (!controller_)
+ return true;
+ for (const auto& overlay : overlays) {
+ // It is possible that the cc rect we get actually falls off the edge of
+ // the screen. Usually this is prevented via things like status bars
+ // blocking overlaying or cc clipping it, but in case it wasn't properly
+ // clipped (since GL will render this situation fine) just ignore it here.
+ // This should be an extremely rare occurrance.
+ if (overlay.plane_z_order != 0 && !bounds().Contains(overlay.display_rect))
+ return false;
+ }
+
+ scoped_refptr<DrmDevice> drm = controller_->GetAllocationDrmDevice();
+ OverlayPlaneList planes;
+ for (const auto& overlay : overlays) {
+ gfx::Size size =
+ (overlay.plane_z_order == 0) ? bounds().size() : overlay.buffer_size;
+ scoped_refptr<ScanoutBuffer> buffer = buffer_generator->Create(drm, size);
+ if (!buffer)
+ return false;
+ planes.push_back(OverlayPlane(buffer, overlay.plane_z_order,
+ overlay.transform, overlay.display_rect,
+ gfx::RectF(gfx::Size(1, 1))));
+ }
+ return controller_->SchedulePageFlip(planes, true, true,
+ base::Bind(&EmptyFlipCallback));
+}
+
+const OverlayPlane* DrmWindow::GetLastModesetBuffer() {
+ return OverlayPlane::GetPrimaryPlane(last_submitted_planes_);
+}
+
+void DrmWindow::ResetCursor(bool bitmap_only) {
+ if (!controller_)
+ return;
+
+ if (cursor_bitmaps_.size()) {
+ // Draw new cursor into backbuffer.
+ UpdateCursorImage(cursor_buffers_[cursor_frontbuffer_ ^ 1].get(),
+ cursor_bitmaps_[cursor_frame_]);
+
+ // Reset location & buffer.
+ if (!bitmap_only)
+ controller_->MoveCursor(cursor_location_);
+ controller_->SetCursor(cursor_buffers_[cursor_frontbuffer_ ^ 1]);
+ cursor_frontbuffer_ ^= 1;
+ } else {
+ // No cursor set.
+ controller_->UnsetCursor();
+ }
+}
+
+void DrmWindow::OnCursorAnimationTimeout() {
+ cursor_frame_++;
+ cursor_frame_ %= cursor_bitmaps_.size();
+
+ ResetCursor(true);
+}
+
+void DrmWindow::SetController(HardwareDisplayController* controller) {
+ if (controller_ == controller)
+ return;
+
+ controller_ = controller;
+ device_manager_->UpdateDrmDevice(
+ widget_, controller ? controller->GetAllocationDrmDevice() : nullptr);
+
+ UpdateCursorBuffers();
+ // We changed displays, so we want to update the cursor as well.
+ ResetCursor(false /* bitmap_only */);
+}
+
+void DrmWindow::UpdateCursorBuffers() {
+ if (!controller_) {
+ for (size_t i = 0; i < arraysize(cursor_buffers_); ++i) {
+ cursor_buffers_[i] = nullptr;
+ }
+ } else {
+ scoped_refptr<DrmDevice> drm = controller_->GetAllocationDrmDevice();
+
+ uint64_t cursor_width = 64;
+ uint64_t cursor_height = 64;
+ drm->GetCapability(DRM_CAP_CURSOR_WIDTH, &cursor_width);
+ drm->GetCapability(DRM_CAP_CURSOR_HEIGHT, &cursor_height);
+
+ SkImageInfo info = SkImageInfo::MakeN32Premul(cursor_width, cursor_height);
+ for (size_t i = 0; i < arraysize(cursor_buffers_); ++i) {
+ cursor_buffers_[i] = new DrmBuffer(drm);
+ // Don't register a framebuffer for cursors since they are special (they
+ // aren't modesetting buffers and drivers may fail to register them due to
+ // their small sizes).
+ if (!cursor_buffers_[i]->Initialize(
+ info, false /* should_register_framebuffer */)) {
+ LOG(FATAL) << "Failed to initialize cursor buffer";
+ return;
+ }
+ }
+ }
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_window.h b/ui/ozone/platform/drm/gpu/drm_window.h
new file mode 100644
index 0000000..fa5e5bd
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_window.h
@@ -0,0 +1,139 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_WINDOW_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_DRM_WINDOW_H_
+
+#include <vector>
+
+#include "base/timer/timer.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/swap_result.h"
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform/drm/gpu/overlay_plane.h"
+#include "ui/ozone/platform/drm/gpu/page_flip_request.h"
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+class SkBitmap;
+
+namespace gfx {
+class Point;
+class Rect;
+} // namespace gfx
+
+namespace ui {
+
+class DrmBuffer;
+class DrmDeviceManager;
+class HardwareDisplayController;
+struct OverlayCheck_Params;
+class ScanoutBufferGenerator;
+class ScreenManager;
+
+// A delegate of the platform window (DrmWindow) on the GPU process. This is
+// used to keep track of window state changes such that each platform window is
+// correctly associated with a display.
+// A window is associated with the display whose bounds contains the window
+// bounds. If there's no suitable display, the window is disconnected and its
+// contents will not be visible.
+class OZONE_EXPORT DrmWindow {
+ public:
+ DrmWindow(gfx::AcceleratedWidget widget,
+ DrmDeviceManager* device_manager,
+ ScreenManager* screen_manager);
+
+ ~DrmWindow();
+
+ gfx::Rect bounds() const { return bounds_; }
+
+ void Initialize();
+
+ void Shutdown();
+
+ // Returns the accelerated widget associated with the delegate.
+ gfx::AcceleratedWidget GetAcceleratedWidget();
+
+ // Returns the current controller the window is displaying on. Callers should
+ // not cache the result as the controller may change as the window is moved.
+ HardwareDisplayController* GetController();
+
+ void SetController(HardwareDisplayController* controller);
+
+ // Called when the window is resized/moved.
+ void OnBoundsChanged(const gfx::Rect& bounds);
+
+ // Update the HW cursor bitmap & move to specified location. If
+ // the bitmap is empty, the cursor is hidden.
+ void SetCursor(const std::vector<SkBitmap>& bitmaps,
+ const gfx::Point& location,
+ int frame_delay_ms);
+
+ // Update the HW cursor bitmap & move to specified location. If
+ // the bitmap is empty, the cursor is hidden.
+ void SetCursorWithoutAnimations(const std::vector<SkBitmap>& bitmaps,
+ const gfx::Point& location);
+
+ // Move the HW cursor to the specified location.
+ void MoveCursor(const gfx::Point& location);
+
+ // Queue overlay planes and page flips.
+ // If hardware display controller is available, forward the information
+ // immediately, otherwise queue up on the window and forward when the hardware
+ // is once again ready.
+ void QueueOverlayPlane(const OverlayPlane& plane);
+
+ bool SchedulePageFlip(bool is_sync, const SwapCompletionCallback& callback);
+ bool TestPageFlip(const std::vector<OverlayCheck_Params>& planes,
+ ScanoutBufferGenerator* buffer_generator);
+
+ // Returns the last buffer associated with this window.
+ const OverlayPlane* GetLastModesetBuffer();
+
+ private:
+ // Draw the last set cursor & update the cursor plane.
+ void ResetCursor(bool bitmap_only);
+
+ // Draw next frame in an animated cursor.
+ void OnCursorAnimationTimeout();
+
+ // When |controller_| changes this is called to reallocate the cursor buffers
+ // since the allocation DRM device may have changed.
+ void UpdateCursorBuffers();
+
+ gfx::AcceleratedWidget widget_;
+
+ DrmDeviceManager* device_manager_; // Not owned.
+ ScreenManager* screen_manager_; // Not owned.
+
+ // The current bounds of the window.
+ gfx::Rect bounds_;
+
+ // The controller associated with the current window. This may be nullptr if
+ // the window isn't over an active display.
+ HardwareDisplayController* controller_ = nullptr;
+
+ base::RepeatingTimer<DrmWindow> cursor_timer_;
+
+ scoped_refptr<DrmBuffer> cursor_buffers_[2];
+ int cursor_frontbuffer_ = 0;
+
+ std::vector<SkBitmap> cursor_bitmaps_;
+ gfx::Point cursor_location_;
+ int cursor_frame_ = 0;
+ int cursor_frame_delay_ms_ = 0;
+
+ // Planes and flips currently being queued in the absence of hardware display
+ // controller.
+ OverlayPlaneList pending_planes_;
+ OverlayPlaneList last_submitted_planes_;
+ bool last_swap_sync_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmWindow);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_WINDOW_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_window_unittest.cc b/ui/ozone/platform/drm/gpu/drm_window_unittest.cc
new file mode 100644
index 0000000..abb3129
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_window_unittest.cc
@@ -0,0 +1,151 @@
+// 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 <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
+#include "ui/ozone/platform/drm/gpu/drm_buffer.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
+#include "ui/ozone/platform/drm/gpu/drm_surface.h"
+#include "ui/ozone/platform/drm/gpu/drm_surface_factory.h"
+#include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+#include "ui/ozone/platform/drm/gpu/screen_manager.h"
+#include "ui/ozone/platform/drm/test/mock_drm_device.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+
+namespace {
+
+// Mode of size 6x4.
+const drmModeModeInfo kDefaultMode =
+ {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
+
+const gfx::AcceleratedWidget kDefaultWidgetHandle = 1;
+const uint32_t kDefaultCrtc = 1;
+const uint32_t kDefaultConnector = 2;
+const int kDefaultCursorSize = 64;
+
+std::vector<skia::RefPtr<SkSurface>> GetCursorBuffers(
+ const scoped_refptr<ui::MockDrmDevice> drm) {
+ std::vector<skia::RefPtr<SkSurface>> cursor_buffers;
+ for (const skia::RefPtr<SkSurface>& cursor_buffer : drm->buffers()) {
+ if (cursor_buffer->width() == kDefaultCursorSize &&
+ cursor_buffer->height() == kDefaultCursorSize) {
+ cursor_buffers.push_back(cursor_buffer);
+ }
+ }
+
+ return cursor_buffers;
+}
+
+SkBitmap AllocateBitmap(const gfx::Size& size) {
+ SkBitmap image;
+ SkImageInfo info = SkImageInfo::Make(size.width(), size.height(),
+ kN32_SkColorType, kPremul_SkAlphaType);
+ image.allocPixels(info);
+ image.eraseColor(SK_ColorWHITE);
+ return image;
+}
+
+} // namespace
+
+class DrmWindowTest : public testing::Test {
+ public:
+ DrmWindowTest() {}
+
+ void SetUp() override;
+ void TearDown() override;
+
+ protected:
+ scoped_ptr<base::MessageLoop> message_loop_;
+ scoped_refptr<ui::MockDrmDevice> drm_;
+ scoped_ptr<ui::DrmBufferGenerator> buffer_generator_;
+ scoped_ptr<ui::ScreenManager> screen_manager_;
+ scoped_ptr<ui::DrmDeviceManager> drm_device_manager_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DrmWindowTest);
+};
+
+void DrmWindowTest::SetUp() {
+ message_loop_.reset(new base::MessageLoopForUI);
+ drm_ = new ui::MockDrmDevice();
+ buffer_generator_.reset(new ui::DrmBufferGenerator());
+ screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get()));
+ screen_manager_->AddDisplayController(drm_, kDefaultCrtc, kDefaultConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kDefaultCrtc, kDefaultConnector, gfx::Point(), kDefaultMode);
+
+ drm_device_manager_.reset(new ui::DrmDeviceManager(nullptr));
+
+ scoped_ptr<ui::DrmWindow> window_delegate(new ui::DrmWindow(
+ kDefaultWidgetHandle, drm_device_manager_.get(), screen_manager_.get()));
+ window_delegate->Initialize();
+ window_delegate->OnBoundsChanged(
+ gfx::Rect(gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay)));
+ screen_manager_->AddWindow(kDefaultWidgetHandle, window_delegate.Pass());
+}
+
+void DrmWindowTest::TearDown() {
+ scoped_ptr<ui::DrmWindow> delegate =
+ screen_manager_->RemoveWindow(kDefaultWidgetHandle);
+ delegate->Shutdown();
+ message_loop_.reset();
+}
+
+TEST_F(DrmWindowTest, SetCursorImage) {
+ const gfx::Size cursor_size(6, 4);
+ screen_manager_->GetWindow(kDefaultWidgetHandle)
+ ->SetCursor(std::vector<SkBitmap>(1, AllocateBitmap(cursor_size)),
+ gfx::Point(4, 2), 0);
+
+ SkBitmap cursor;
+ std::vector<skia::RefPtr<SkSurface>> cursor_buffers = GetCursorBuffers(drm_);
+ EXPECT_EQ(2u, cursor_buffers.size());
+
+ // Buffers 1 is the cursor backbuffer we just drew in.
+ cursor.setInfo(cursor_buffers[1]->getCanvas()->imageInfo());
+ EXPECT_TRUE(cursor_buffers[1]->getCanvas()->readPixels(&cursor, 0, 0));
+
+ // Check that the frontbuffer is displaying the right image as set above.
+ for (int i = 0; i < cursor.height(); ++i) {
+ for (int j = 0; j < cursor.width(); ++j) {
+ if (j < cursor_size.width() && i < cursor_size.height())
+ EXPECT_EQ(SK_ColorWHITE, cursor.getColor(j, i));
+ else
+ EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
+ cursor.getColor(j, i));
+ }
+ }
+}
+
+TEST_F(DrmWindowTest, CheckCursorSurfaceAfterChangingDevice) {
+ const gfx::Size cursor_size(6, 4);
+ screen_manager_->GetWindow(kDefaultWidgetHandle)
+ ->SetCursor(std::vector<SkBitmap>(1, AllocateBitmap(cursor_size)),
+ gfx::Point(4, 2), 0);
+
+ // Add another device.
+ scoped_refptr<ui::MockDrmDevice> drm = new ui::MockDrmDevice();
+ screen_manager_->AddDisplayController(drm, kDefaultCrtc, kDefaultConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm, kDefaultCrtc, kDefaultConnector,
+ gfx::Point(0, kDefaultMode.vdisplay), kDefaultMode);
+
+ // Move window to the display on the new device.
+ screen_manager_->GetWindow(kDefaultWidgetHandle)
+ ->OnBoundsChanged(gfx::Rect(0, kDefaultMode.vdisplay,
+ kDefaultMode.hdisplay,
+ kDefaultMode.vdisplay));
+
+ EXPECT_EQ(2u, GetCursorBuffers(drm).size());
+ // Make sure the cursor is showing on the new display.
+ EXPECT_NE(0u, drm->get_cursor_handle_for_crtc(kDefaultCrtc));
+}
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer.cc b/ui/ozone/platform/drm/gpu/gbm_buffer.cc
new file mode 100644
index 0000000..8da5e5d
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer.cc
@@ -0,0 +1,113 @@
+// 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/drm/gpu/gbm_buffer.h"
+
+#include <drm.h>
+#include <fcntl.h>
+#include <gbm.h>
+#include <xf86drm.h>
+
+#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
+#include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/gbm_device.h"
+
+namespace ui {
+
+namespace {
+
+int GetGbmFormatFromBufferFormat(SurfaceFactoryOzone::BufferFormat fmt) {
+ switch (fmt) {
+ case SurfaceFactoryOzone::BGRA_8888:
+ return GBM_BO_FORMAT_ARGB8888;
+ case SurfaceFactoryOzone::RGBX_8888:
+ return GBM_BO_FORMAT_XRGB8888;
+ default:
+ NOTREACHED();
+ return 0;
+ }
+}
+
+} // namespace
+
+GbmBuffer::GbmBuffer(const scoped_refptr<GbmDevice>& gbm,
+ gbm_bo* bo,
+ bool scanout)
+ : GbmBufferBase(gbm, bo, scanout) {
+}
+
+GbmBuffer::~GbmBuffer() {
+ if (bo())
+ gbm_bo_destroy(bo());
+}
+
+// static
+scoped_refptr<GbmBuffer> GbmBuffer::CreateBuffer(
+ const scoped_refptr<GbmDevice>& gbm,
+ SurfaceFactoryOzone::BufferFormat format,
+ const gfx::Size& size,
+ bool scanout) {
+ TRACE_EVENT2("drm", "GbmBuffer::CreateBuffer", "device",
+ gbm->device_path().value(), "size", size.ToString());
+ unsigned flags = GBM_BO_USE_RENDERING;
+ if (scanout)
+ flags |= GBM_BO_USE_SCANOUT;
+ gbm_bo* bo = gbm_bo_create(gbm->device(), size.width(), size.height(),
+ GetGbmFormatFromBufferFormat(format), flags);
+ if (!bo)
+ return NULL;
+
+ scoped_refptr<GbmBuffer> buffer(new GbmBuffer(gbm, bo, scanout));
+ if (scanout && !buffer->GetFramebufferId())
+ return NULL;
+
+ return buffer;
+}
+
+GbmPixmap::GbmPixmap(const scoped_refptr<GbmBuffer>& buffer,
+ ScreenManager* screen_manager)
+ : buffer_(buffer), screen_manager_(screen_manager) {
+}
+
+bool GbmPixmap::Initialize() {
+ // We want to use the GBM API because it's going to call into libdrm
+ // which might do some optimizations on buffer allocation,
+ // especially when sharing buffers via DMABUF.
+ dma_buf_ = gbm_bo_get_fd(buffer_->bo());
+ if (dma_buf_ < 0) {
+ PLOG(ERROR) << "Failed to export buffer to dma_buf";
+ return false;
+ }
+ return true;
+}
+
+GbmPixmap::~GbmPixmap() {
+ if (dma_buf_ > 0)
+ close(dma_buf_);
+}
+
+void* GbmPixmap::GetEGLClientBuffer() {
+ return nullptr;
+}
+
+int GbmPixmap::GetDmaBufFd() {
+ return dma_buf_;
+}
+
+int GbmPixmap::GetDmaBufPitch() {
+ return gbm_bo_get_stride(buffer_->bo());
+}
+
+bool GbmPixmap::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
+ int plane_z_order,
+ gfx::OverlayTransform plane_transform,
+ const gfx::Rect& display_bounds,
+ const gfx::RectF& crop_rect) {
+ screen_manager_->GetWindow(widget)->QueueOverlayPlane(OverlayPlane(
+ buffer_, plane_z_order, plane_transform, display_bounds, crop_rect));
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer.h b/ui/ozone/platform/drm/gpu/gbm_buffer.h
new file mode 100644
index 0000000..3f0c5d7
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer.h
@@ -0,0 +1,68 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_GBM_BUFFER_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_GBM_BUFFER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/drm/gpu/gbm_buffer_base.h"
+#include "ui/ozone/platform/drm/gpu/screen_manager.h"
+#include "ui/ozone/public/native_pixmap.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+struct gbm_bo;
+
+namespace ui {
+
+class GbmDevice;
+
+class GbmBuffer : public GbmBufferBase {
+ public:
+ static scoped_refptr<GbmBuffer> CreateBuffer(
+ const scoped_refptr<GbmDevice>& gbm,
+ SurfaceFactoryOzone::BufferFormat format,
+ const gfx::Size& size,
+ bool scanout);
+
+ private:
+ GbmBuffer(const scoped_refptr<GbmDevice>& gbm, gbm_bo* bo, bool scanout);
+ ~GbmBuffer() override;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmBuffer);
+};
+
+class GbmPixmap : public NativePixmap {
+ public:
+ GbmPixmap(const scoped_refptr<GbmBuffer>& buffer,
+ ScreenManager* screen_manager);
+ bool Initialize();
+
+ // NativePixmap:
+ void* GetEGLClientBuffer() override;
+ int GetDmaBufFd() override;
+ int GetDmaBufPitch() override;
+ bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
+ int plane_z_order,
+ gfx::OverlayTransform plane_transform,
+ const gfx::Rect& display_bounds,
+ const gfx::RectF& crop_rect) override;
+
+ scoped_refptr<GbmBuffer> buffer() { return buffer_; }
+
+ private:
+ ~GbmPixmap() override;
+
+ scoped_refptr<GbmBuffer> buffer_;
+ int dma_buf_ = -1;
+
+ ScreenManager* screen_manager_; // Not owned.
+
+ DISALLOW_COPY_AND_ASSIGN(GbmPixmap);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_GBM_BUFFER_H_
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer_base.cc b/ui/ozone/platform/drm/gpu/gbm_buffer_base.cc
new file mode 100644
index 0000000..c283a64
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer_base.cc
@@ -0,0 +1,52 @@
+// 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/drm/gpu/gbm_buffer_base.h"
+
+#include <gbm.h>
+
+#include "base/logging.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+
+namespace ui {
+
+namespace {
+
+// Pixel configuration for the current buffer format.
+// TODO(dnicoara) These will need to change once we query the hardware for
+// supported configurations.
+const uint8_t kColorDepth = 24;
+const uint8_t kPixelDepth = 32;
+
+} // namespace
+
+GbmBufferBase::GbmBufferBase(const scoped_refptr<DrmDevice>& drm,
+ gbm_bo* bo,
+ bool scanout)
+ : drm_(drm), bo_(bo) {
+ if (scanout &&
+ !drm_->AddFramebuffer(gbm_bo_get_width(bo), gbm_bo_get_height(bo),
+ kColorDepth, kPixelDepth, gbm_bo_get_stride(bo),
+ gbm_bo_get_handle(bo).u32, &framebuffer_))
+ PLOG(ERROR) << "Failed to register buffer";
+}
+
+GbmBufferBase::~GbmBufferBase() {
+ if (framebuffer_)
+ drm_->RemoveFramebuffer(framebuffer_);
+}
+
+uint32_t GbmBufferBase::GetFramebufferId() const {
+ return framebuffer_;
+}
+
+uint32_t GbmBufferBase::GetHandle() const {
+ return gbm_bo_get_handle(bo_).u32;
+}
+
+gfx::Size GbmBufferBase::GetSize() const {
+ return gfx::Size(gbm_bo_get_width(bo_), gbm_bo_get_height(bo_));
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer_base.h b/ui/ozone/platform/drm/gpu/gbm_buffer_base.h
new file mode 100644
index 0000000..d0872fa
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer_base.h
@@ -0,0 +1,43 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_GBM_BUFFER_BASE_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_GBM_BUFFER_BASE_H_
+
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
+
+struct gbm_bo;
+
+namespace ui {
+
+class DrmDevice;
+
+// Wrapper for a GBM buffer. The base class provides common functionality
+// required to prepare the buffer for scanout. It does not provide any ownership
+// of the buffer. Implementations of this base class should deal with buffer
+// ownership.
+class GbmBufferBase : public ScanoutBuffer {
+ public:
+ gbm_bo* bo() const { return bo_; }
+
+ // ScanoutBuffer:
+ uint32_t GetFramebufferId() const override;
+ uint32_t GetHandle() const override;
+ gfx::Size GetSize() const override;
+
+ protected:
+ GbmBufferBase(const scoped_refptr<DrmDevice>& drm, gbm_bo* bo, bool scanout);
+ ~GbmBufferBase() override;
+
+ private:
+ scoped_refptr<DrmDevice> drm_;
+ gbm_bo* bo_;
+ uint32_t framebuffer_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmBufferBase);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_GBM_BUFFER_BASE_H_
diff --git a/ui/ozone/platform/drm/gpu/gbm_device.cc b/ui/ozone/platform/drm/gpu/gbm_device.cc
new file mode 100644
index 0000000..dc36ba3
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/gbm_device.cc
@@ -0,0 +1,33 @@
+// Copyright 2015 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/drm/gpu/gbm_device.h"
+
+#include <gbm.h>
+
+namespace ui {
+
+GbmDevice::GbmDevice(const base::FilePath& device_path, base::File file)
+ : DrmDevice(device_path, file.Pass()) {
+}
+
+GbmDevice::~GbmDevice() {
+ if (device_)
+ gbm_device_destroy(device_);
+}
+
+bool GbmDevice::Initialize(bool use_atomic) {
+ if (!DrmDevice::Initialize(use_atomic))
+ return false;
+
+ device_ = gbm_create_device(get_fd());
+ if (!device_) {
+ PLOG(ERROR) << "Unable to initialize GBM for " << device_path().value();
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/gbm_device.h b/ui/ozone/platform/drm/gpu/gbm_device.h
new file mode 100644
index 0000000..29cb9df
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/gbm_device.h
@@ -0,0 +1,33 @@
+// Copyright 2015 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_GBM_DEVICE_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_GBM_DEVICE_H_
+
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+
+struct gbm_device;
+
+namespace ui {
+
+class GbmDevice : public DrmDevice {
+ public:
+ GbmDevice(const base::FilePath& device_path, base::File file);
+
+ gbm_device* device() const { return device_; }
+
+ // DrmDevice implementation:
+ bool Initialize(bool use_atomic) override;
+
+ private:
+ ~GbmDevice() override;
+
+ gbm_device* device_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmDevice);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_GBM_DEVICE_H_
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface.cc b/ui/ozone/platform/drm/gpu/gbm_surface.cc
new file mode 100644
index 0000000..08a32f4
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/gbm_surface.cc
@@ -0,0 +1,179 @@
+// 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/drm/gpu/gbm_surface.h"
+
+#include <gbm.h>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "ui/ozone/platform/drm/gpu/drm_buffer.h"
+#include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/gbm_buffer_base.h"
+#include "ui/ozone/platform/drm/gpu/gbm_device.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
+
+namespace ui {
+
+namespace {
+
+void DoNothing(gfx::SwapResult) {
+}
+
+class GbmSurfaceBuffer : public GbmBufferBase {
+ public:
+ static scoped_refptr<GbmSurfaceBuffer> CreateBuffer(
+ const scoped_refptr<DrmDevice>& drm,
+ gbm_bo* buffer);
+ static scoped_refptr<GbmSurfaceBuffer> GetBuffer(gbm_bo* buffer);
+
+ private:
+ GbmSurfaceBuffer(const scoped_refptr<DrmDevice>& drm, gbm_bo* bo);
+ ~GbmSurfaceBuffer() override;
+
+ static void Destroy(gbm_bo* buffer, void* data);
+
+ // This buffer is special and is released by GBM at any point in time (as
+ // long as it isn't being used). Since GBM should be the only one to
+ // release this buffer, keep a self-reference in order to keep this alive.
+ // When GBM calls Destroy(..) the self-reference will dissapear and this will
+ // be destroyed.
+ scoped_refptr<GbmSurfaceBuffer> self_;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmSurfaceBuffer);
+};
+
+GbmSurfaceBuffer::GbmSurfaceBuffer(const scoped_refptr<DrmDevice>& drm,
+ gbm_bo* bo)
+ : GbmBufferBase(drm, bo, true) {
+ if (GetFramebufferId()) {
+ self_ = this;
+ gbm_bo_set_user_data(bo, this, GbmSurfaceBuffer::Destroy);
+ }
+}
+
+GbmSurfaceBuffer::~GbmSurfaceBuffer() {
+}
+
+// static
+scoped_refptr<GbmSurfaceBuffer> GbmSurfaceBuffer::CreateBuffer(
+ const scoped_refptr<DrmDevice>& drm,
+ gbm_bo* buffer) {
+ scoped_refptr<GbmSurfaceBuffer> scoped_buffer(
+ new GbmSurfaceBuffer(drm, buffer));
+ if (!scoped_buffer->GetFramebufferId())
+ return NULL;
+
+ return scoped_buffer;
+}
+
+// static
+scoped_refptr<GbmSurfaceBuffer> GbmSurfaceBuffer::GetBuffer(gbm_bo* buffer) {
+ return scoped_refptr<GbmSurfaceBuffer>(
+ static_cast<GbmSurfaceBuffer*>(gbm_bo_get_user_data(buffer)));
+}
+
+// static
+void GbmSurfaceBuffer::Destroy(gbm_bo* buffer, void* data) {
+ GbmSurfaceBuffer* scoped_buffer = static_cast<GbmSurfaceBuffer*>(data);
+ scoped_buffer->self_ = NULL;
+}
+
+} // namespace
+
+GbmSurface::GbmSurface(DrmWindow* window_delegate,
+ const scoped_refptr<GbmDevice>& gbm)
+ : GbmSurfaceless(window_delegate, NULL),
+ gbm_(gbm),
+ native_surface_(NULL),
+ current_buffer_(NULL),
+ weak_factory_(this) {
+}
+
+GbmSurface::~GbmSurface() {
+ if (current_buffer_)
+ gbm_surface_release_buffer(native_surface_, current_buffer_);
+
+ if (native_surface_)
+ gbm_surface_destroy(native_surface_);
+}
+
+bool GbmSurface::Initialize() {
+ // If we're initializing the surface without a controller (possible on startup
+ // where the surface creation can happen before the native window delegate
+ // IPCs arrive), initialize the size to a valid value such that surface
+ // creation doesn't fail.
+ gfx::Size size(1, 1);
+ if (window_delegate_->GetController()) {
+ size = window_delegate_->GetController()->GetModeSize();
+ }
+ // TODO(dnicoara) Check underlying system support for pixel format.
+ native_surface_ = gbm_surface_create(
+ gbm_->device(), size.width(), size.height(), GBM_BO_FORMAT_XRGB8888,
+ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+
+ if (!native_surface_)
+ return false;
+
+ size_ = size;
+ return true;
+}
+
+intptr_t GbmSurface::GetNativeWindow() {
+ DCHECK(native_surface_);
+ return reinterpret_cast<intptr_t>(native_surface_);
+}
+
+bool GbmSurface::ResizeNativeWindow(const gfx::Size& viewport_size) {
+ if (size_ == viewport_size)
+ return true;
+
+ return false;
+}
+
+bool GbmSurface::OnSwapBuffers() {
+ return OnSwapBuffersAsync(base::Bind(&DoNothing));
+}
+
+bool GbmSurface::OnSwapBuffersAsync(const SwapCompletionCallback& callback) {
+ DCHECK(native_surface_);
+
+ gbm_bo* pending_buffer = gbm_surface_lock_front_buffer(native_surface_);
+ scoped_refptr<GbmSurfaceBuffer> primary =
+ GbmSurfaceBuffer::GetBuffer(pending_buffer);
+ if (!primary.get()) {
+ primary = GbmSurfaceBuffer::CreateBuffer(gbm_, pending_buffer);
+ if (!primary.get()) {
+ LOG(ERROR) << "Failed to associate the buffer with the controller";
+ callback.Run(gfx::SwapResult::SWAP_FAILED);
+ return false;
+ }
+ }
+
+ // The primary buffer is a special case.
+ window_delegate_->QueueOverlayPlane(OverlayPlane(primary));
+
+ if (!GbmSurfaceless::OnSwapBuffersAsync(
+ base::Bind(&GbmSurface::OnSwapBuffersCallback,
+ weak_factory_.GetWeakPtr(), callback, pending_buffer))) {
+ callback.Run(gfx::SwapResult::SWAP_FAILED);
+ return false;
+ }
+
+ return true;
+}
+
+void GbmSurface::OnSwapBuffersCallback(const SwapCompletionCallback& callback,
+ gbm_bo* pending_buffer,
+ gfx::SwapResult result) {
+ // If there was a frontbuffer, it is no longer active. Release it back to GBM.
+ if (current_buffer_)
+ gbm_surface_release_buffer(native_surface_, current_buffer_);
+
+ current_buffer_ = pending_buffer;
+ callback.Run(result);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface.h b/ui/ozone/platform/drm/gpu/gbm_surface.h
new file mode 100644
index 0000000..45757ec
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/gbm_surface.h
@@ -0,0 +1,62 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_GBM_SURFACE_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_GBM_SURFACE_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/drm/gpu/gbm_surfaceless.h"
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+struct gbm_bo;
+struct gbm_surface;
+
+namespace ui {
+
+class DrmBuffer;
+class DrmWindow;
+class GbmDevice;
+
+// Extends the GBM surfaceless functionality and adds an implicit surface for
+// the primary plane. Arbitrary buffers can still be allocated and displayed as
+// overlay planes, however the primary plane is associated with the native
+// surface and is updated via an EGLSurface.
+class GbmSurface : public GbmSurfaceless {
+ public:
+ GbmSurface(DrmWindow* window_delegate, const scoped_refptr<GbmDevice>& gbm);
+ ~GbmSurface() override;
+
+ bool Initialize();
+
+ // GbmSurfaceless:
+ intptr_t GetNativeWindow() override;
+ bool ResizeNativeWindow(const gfx::Size& viewport_size) override;
+ bool OnSwapBuffers() override;
+ bool OnSwapBuffersAsync(const SwapCompletionCallback& callback) override;
+
+ private:
+ void OnSwapBuffersCallback(const SwapCompletionCallback& callback,
+ gbm_bo* pending_buffer,
+ gfx::SwapResult result);
+
+ scoped_refptr<GbmDevice> gbm_;
+
+ // The native GBM surface. In EGL this represents the EGLNativeWindowType.
+ gbm_surface* native_surface_;
+
+ // Buffer currently used for scanout.
+ gbm_bo* current_buffer_;
+
+ gfx::Size size_;
+
+ base::WeakPtrFactory<GbmSurface> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmSurface);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_GBM_SURFACE_H_
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
new file mode 100644
index 0000000..f482861
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
@@ -0,0 +1,158 @@
+// 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/drm/gpu/gbm_surface_factory.h"
+
+#include <gbm.h>
+
+#include "base/files/file_path.h"
+#include "third_party/khronos/EGL/egl.h"
+#include "ui/ozone/common/egl_util.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
+#include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/gbm_buffer.h"
+#include "ui/ozone/platform/drm/gpu/gbm_device.h"
+#include "ui/ozone/platform/drm/gpu/gbm_surface.h"
+#include "ui/ozone/platform/drm/gpu/gbm_surfaceless.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+#include "ui/ozone/platform/drm/gpu/screen_manager.h"
+#include "ui/ozone/public/native_pixmap.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+namespace ui {
+
+GbmSurfaceFactory::GbmSurfaceFactory(bool allow_surfaceless)
+ : DrmSurfaceFactory(NULL), allow_surfaceless_(allow_surfaceless) {
+}
+
+GbmSurfaceFactory::~GbmSurfaceFactory() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void GbmSurfaceFactory::InitializeGpu(DrmDeviceManager* drm_device_manager,
+ ScreenManager* screen_manager) {
+ drm_device_manager_ = drm_device_manager;
+ screen_manager_ = screen_manager;
+}
+
+intptr_t GbmSurfaceFactory::GetNativeDisplay() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ auto primary_device = drm_device_manager_->GetDrmDevice(
+ gfx::kNullAcceleratedWidget);
+ DCHECK(primary_device.get());
+ auto gbm_device = static_cast<GbmDevice*>(primary_device.get());
+ return reinterpret_cast<EGLNativeDisplayType>(gbm_device->device());
+}
+
+const int32* GbmSurfaceFactory::GetEGLSurfaceProperties(
+ const int32* desired_list) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ static const int32 kConfigAttribs[] = {EGL_BUFFER_SIZE,
+ 32,
+ EGL_ALPHA_SIZE,
+ 8,
+ EGL_BLUE_SIZE,
+ 8,
+ EGL_GREEN_SIZE,
+ 8,
+ EGL_RED_SIZE,
+ 8,
+ EGL_RENDERABLE_TYPE,
+ EGL_OPENGL_ES2_BIT,
+ EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT,
+ EGL_NONE};
+
+ return kConfigAttribs;
+}
+
+bool GbmSurfaceFactory::LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return LoadDefaultEGLGLES2Bindings(add_gl_library, set_gl_get_proc_address);
+}
+
+scoped_ptr<SurfaceOzoneCanvas> GbmSurfaceFactory::CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ LOG(FATAL) << "Software rendering mode is not supported with GBM platform";
+ return nullptr;
+}
+
+scoped_ptr<SurfaceOzoneEGL> GbmSurfaceFactory::CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ scoped_refptr<GbmDevice> gbm = GetGbmDevice(widget);
+ DCHECK(gbm);
+
+ scoped_ptr<GbmSurface> surface(
+ new GbmSurface(screen_manager_->GetWindow(widget), gbm));
+ if (!surface->Initialize())
+ return nullptr;
+
+ return surface.Pass();
+}
+
+scoped_ptr<SurfaceOzoneEGL>
+GbmSurfaceFactory::CreateSurfacelessEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!allow_surfaceless_)
+ return nullptr;
+
+ return make_scoped_ptr(new GbmSurfaceless(screen_manager_->GetWindow(widget),
+ drm_device_manager_));
+}
+
+scoped_refptr<ui::NativePixmap> GbmSurfaceFactory::CreateNativePixmap(
+ gfx::AcceleratedWidget widget,
+ gfx::Size size,
+ BufferFormat format,
+ BufferUsage usage) {
+ if (usage == MAP)
+ return nullptr;
+
+ scoped_refptr<GbmDevice> gbm = GetGbmDevice(widget);
+ DCHECK(gbm);
+
+ scoped_refptr<GbmBuffer> buffer =
+ GbmBuffer::CreateBuffer(gbm, format, size, true);
+ if (!buffer.get())
+ return nullptr;
+
+ scoped_refptr<GbmPixmap> pixmap(new GbmPixmap(buffer, screen_manager_));
+ if (!pixmap->Initialize())
+ return nullptr;
+
+ return pixmap;
+}
+
+bool GbmSurfaceFactory::CanShowPrimaryPlaneAsOverlay() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return allow_surfaceless_;
+}
+
+bool GbmSurfaceFactory::CanCreateNativePixmap(BufferUsage usage) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ switch (usage) {
+ case MAP:
+ return false;
+ case PERSISTENT_MAP:
+ return false;
+ case SCANOUT:
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
+scoped_refptr<GbmDevice> GbmSurfaceFactory::GetGbmDevice(
+ gfx::AcceleratedWidget widget) {
+ return static_cast<GbmDevice*>(
+ drm_device_manager_->GetDrmDevice(widget).get());
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.h b/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
new file mode 100644
index 0000000..0bc01b3
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_GBM_SURFACE_FACTORY_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_GBM_SURFACE_FACTORY_H_
+
+#include "ui/ozone/platform/drm/gpu/drm_surface_factory.h"
+
+namespace ui {
+
+class DrmDeviceManager;
+class DrmWindow;
+class GbmDevice;
+class ScreenManager;
+
+class GbmSurfaceFactory : public DrmSurfaceFactory {
+ public:
+ GbmSurfaceFactory(bool allow_surfaceless);
+ ~GbmSurfaceFactory() override;
+
+ void InitializeGpu(DrmDeviceManager* drm_device_manager,
+ ScreenManager* screen_manager);
+
+ // DrmSurfaceFactory:
+ intptr_t GetNativeDisplay() override;
+ const int32_t* GetEGLSurfaceProperties(const int32_t* desired_list) override;
+ bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) override;
+ scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget) override;
+ scoped_ptr<ui::SurfaceOzoneEGL> CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget w) override;
+ scoped_ptr<SurfaceOzoneEGL> CreateSurfacelessEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget) override;
+ scoped_refptr<ui::NativePixmap> CreateNativePixmap(
+ gfx::AcceleratedWidget widget,
+ gfx::Size size,
+ BufferFormat format,
+ BufferUsage usage) override;
+ bool CanShowPrimaryPlaneAsOverlay() override;
+ bool CanCreateNativePixmap(BufferUsage usage) override;
+
+ private:
+ scoped_refptr<GbmDevice> GetGbmDevice(gfx::AcceleratedWidget widget);
+
+ bool allow_surfaceless_;
+
+ DrmDeviceManager* drm_device_manager_; // Not owned.
+
+ DISALLOW_COPY_AND_ASSIGN(GbmSurfaceFactory);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_GBM_SURFACE_FACTORY_H_
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
new file mode 100644
index 0000000..244b8ab
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -0,0 +1,70 @@
+// 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/drm/gpu/gbm_surfaceless.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
+#include "ui/ozone/platform/drm/gpu/drm_vsync_provider.h"
+#include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/gbm_buffer.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+
+namespace ui {
+namespace {
+void EmptyPageFlipCallback(gfx::SwapResult result) {
+}
+} // namespace
+
+GbmSurfaceless::GbmSurfaceless(DrmWindow* window_delegate,
+ DrmDeviceManager* drm_device_manager)
+ : window_delegate_(window_delegate),
+ drm_device_manager_(drm_device_manager) {
+}
+
+GbmSurfaceless::~GbmSurfaceless() {
+}
+
+intptr_t GbmSurfaceless::GetNativeWindow() {
+ NOTREACHED();
+ return 0;
+}
+
+bool GbmSurfaceless::ResizeNativeWindow(const gfx::Size& viewport_size) {
+ return true;
+}
+
+bool GbmSurfaceless::OnSwapBuffers() {
+ return window_delegate_->SchedulePageFlip(true /* is_sync */,
+ base::Bind(&EmptyPageFlipCallback));
+}
+
+bool GbmSurfaceless::OnSwapBuffersAsync(
+ const SwapCompletionCallback& callback) {
+ return window_delegate_->SchedulePageFlip(false /* is_sync */, callback);
+}
+
+scoped_ptr<gfx::VSyncProvider> GbmSurfaceless::CreateVSyncProvider() {
+ return make_scoped_ptr(new DrmVSyncProvider(window_delegate_));
+}
+
+bool GbmSurfaceless::IsUniversalDisplayLinkDevice() {
+ if (!drm_device_manager_)
+ return false;
+ scoped_refptr<DrmDevice> drm_primary =
+ drm_device_manager_->GetDrmDevice(gfx::kNullAcceleratedWidget);
+ DCHECK(drm_primary);
+
+ HardwareDisplayController* controller = window_delegate_->GetController();
+ if (!controller)
+ return false;
+ scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice();
+ DCHECK(drm);
+
+ return drm_primary != drm;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
new file mode 100644
index 0000000..c890d9d
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_GBM_SURFACELESS_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_GBM_SURFACELESS_H_
+
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+namespace gfx {
+class Size;
+} // namespace gfx
+
+namespace ui {
+
+class DrmDeviceManager;
+class DrmWindow;
+
+// In surfaceless mode drawing and displaying happens directly through
+// NativePixmap buffers. CC would call into SurfaceFactoryOzone to allocate the
+// buffers and then call ScheduleOverlayPlane(..) to schedule the buffer for
+// presentation.
+class GbmSurfaceless : public SurfaceOzoneEGL {
+ public:
+ GbmSurfaceless(DrmWindow* window_delegate,
+ DrmDeviceManager* drm_device_manager);
+ ~GbmSurfaceless() override;
+
+ // SurfaceOzoneEGL:
+ intptr_t GetNativeWindow() override;
+ bool ResizeNativeWindow(const gfx::Size& viewport_size) override;
+ bool OnSwapBuffers() override;
+ bool OnSwapBuffersAsync(const SwapCompletionCallback& callback) override;
+ scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override;
+ bool IsUniversalDisplayLinkDevice() override;
+
+ protected:
+ DrmWindow* window_delegate_;
+ DrmDeviceManager* drm_device_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmSurfaceless);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_GBM_SURFACELESS_H_
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_controller.cc b/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
new file mode 100644
index 0000000..5ee4819
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
@@ -0,0 +1,215 @@
+// 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/drm/gpu/hardware_display_controller.h"
+
+#include <drm.h>
+#include <string.h>
+#include <xf86drm.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/swap_result.h"
+#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
+#include "ui/ozone/platform/drm/gpu/drm_buffer.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/page_flip_request.h"
+#include "ui/ozone/public/native_pixmap.h"
+
+namespace ui {
+
+HardwareDisplayController::HardwareDisplayController(
+ scoped_ptr<CrtcController> controller,
+ const gfx::Point& origin)
+ : origin_(origin),
+ mode_(controller->mode()),
+ is_disabled_(controller->is_disabled()) {
+ AddCrtc(controller.Pass());
+}
+
+HardwareDisplayController::~HardwareDisplayController() {
+ // Reset the cursor.
+ UnsetCursor();
+}
+
+bool HardwareDisplayController::Modeset(const OverlayPlane& primary,
+ drmModeModeInfo mode) {
+ TRACE_EVENT0("drm", "HDC::Modeset");
+ DCHECK(primary.buffer.get());
+ bool status = true;
+ for (size_t i = 0; i < crtc_controllers_.size(); ++i)
+ status &= crtc_controllers_[i]->Modeset(primary, mode);
+
+ is_disabled_ = false;
+ mode_ = mode;
+
+ return status;
+}
+
+void HardwareDisplayController::Disable() {
+ TRACE_EVENT0("drm", "HDC::Disable");
+ for (size_t i = 0; i < crtc_controllers_.size(); ++i)
+ crtc_controllers_[i]->Disable();
+
+
+ is_disabled_ = true;
+}
+
+bool HardwareDisplayController::SchedulePageFlip(
+ const OverlayPlaneList& plane_list,
+ bool is_sync,
+ bool test_only,
+ const PageFlipCallback& callback) {
+ TRACE_EVENT0("drm", "HDC::SchedulePageFlip");
+
+ DCHECK(!is_disabled_);
+
+ // Ignore requests with no planes to schedule.
+ if (plane_list.empty()) {
+ callback.Run(gfx::SwapResult::SWAP_ACK);
+ return true;
+ }
+
+ scoped_refptr<PageFlipRequest> page_flip_request =
+ new PageFlipRequest(crtc_controllers_.size(), callback);
+
+ OverlayPlaneList pending_planes = plane_list;
+ std::sort(pending_planes.begin(), pending_planes.end(),
+ [](const OverlayPlane& l, const OverlayPlane& r) {
+ return l.z_order < r.z_order;
+ });
+ if (pending_planes.front().z_order != 0)
+ return false;
+
+ for (const auto& planes : owned_hardware_planes_)
+ planes.first->plane_manager()->BeginFrame(planes.second);
+
+ bool status = true;
+ for (size_t i = 0; i < crtc_controllers_.size(); ++i) {
+ status &= crtc_controllers_[i]->SchedulePageFlip(
+ owned_hardware_planes_.get(crtc_controllers_[i]->drm().get()),
+ pending_planes, test_only, page_flip_request);
+ }
+
+ for (const auto& planes : owned_hardware_planes_) {
+ if (!planes.first->plane_manager()->Commit(planes.second, is_sync,
+ test_only)) {
+ status = false;
+ }
+ }
+
+ return status;
+}
+
+bool HardwareDisplayController::SetCursor(
+ const scoped_refptr<ScanoutBuffer>& buffer) {
+ bool status = true;
+
+ if (is_disabled_)
+ return true;
+
+ for (size_t i = 0; i < crtc_controllers_.size(); ++i)
+ status &= crtc_controllers_[i]->SetCursor(buffer);
+
+ return status;
+}
+
+bool HardwareDisplayController::UnsetCursor() {
+ bool status = true;
+ for (size_t i = 0; i < crtc_controllers_.size(); ++i)
+ status &= crtc_controllers_[i]->SetCursor(nullptr);
+
+ return status;
+}
+
+bool HardwareDisplayController::MoveCursor(const gfx::Point& location) {
+ if (is_disabled_)
+ return true;
+
+ bool status = true;
+ for (size_t i = 0; i < crtc_controllers_.size(); ++i)
+ status &= crtc_controllers_[i]->MoveCursor(location);
+
+ return status;
+}
+
+void HardwareDisplayController::AddCrtc(scoped_ptr<CrtcController> controller) {
+ owned_hardware_planes_.add(
+ controller->drm().get(),
+ scoped_ptr<HardwareDisplayPlaneList>(new HardwareDisplayPlaneList()));
+ crtc_controllers_.push_back(controller.Pass());
+}
+
+scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc(
+ const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc) {
+ for (ScopedVector<CrtcController>::iterator it = crtc_controllers_.begin();
+ it != crtc_controllers_.end(); ++it) {
+ if ((*it)->drm() == drm && (*it)->crtc() == crtc) {
+ scoped_ptr<CrtcController> controller(*it);
+ crtc_controllers_.weak_erase(it);
+ // Remove entry from |owned_hardware_planes_| iff no other crtcs share it.
+ bool found = false;
+ for (ScopedVector<CrtcController>::iterator it =
+ crtc_controllers_.begin();
+ it != crtc_controllers_.end(); ++it) {
+ if ((*it)->drm() == controller->drm()) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ owned_hardware_planes_.erase(controller->drm().get());
+
+ return controller.Pass();
+ }
+ }
+
+ return nullptr;
+}
+
+bool HardwareDisplayController::HasCrtc(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc) const {
+ for (size_t i = 0; i < crtc_controllers_.size(); ++i)
+ if (crtc_controllers_[i]->drm() == drm &&
+ crtc_controllers_[i]->crtc() == crtc)
+ return true;
+
+ return false;
+}
+
+bool HardwareDisplayController::IsMirrored() const {
+ return crtc_controllers_.size() > 1;
+}
+
+bool HardwareDisplayController::IsDisabled() const {
+ return is_disabled_;
+}
+
+gfx::Size HardwareDisplayController::GetModeSize() const {
+ return gfx::Size(mode_.hdisplay, mode_.vdisplay);
+}
+
+uint64_t HardwareDisplayController::GetTimeOfLastFlip() const {
+ uint64_t time = 0;
+ for (size_t i = 0; i < crtc_controllers_.size(); ++i)
+ if (time < crtc_controllers_[i]->time_of_last_flip())
+ time = crtc_controllers_[i]->time_of_last_flip();
+
+ return time;
+}
+
+scoped_refptr<DrmDevice> HardwareDisplayController::GetAllocationDrmDevice()
+ const {
+ DCHECK(!crtc_controllers_.empty());
+ // TODO(dnicoara) When we support mirroring across DRM devices, figure out
+ // which device should be used for allocations.
+ return crtc_controllers_[0]->drm();
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_controller.h b/ui/ozone/platform/drm/gpu/hardware_display_controller.h
new file mode 100644
index 0000000..3772c35
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/hardware_display_controller.h
@@ -0,0 +1,181 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_CONTROLLER_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_CONTROLLER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <xf86drmMode.h>
+#include <deque>
+#include <map>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "ui/gfx/swap_result.h"
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
+#include "ui/ozone/platform/drm/gpu/overlay_plane.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+
+class CrtcController;
+class ScanoutBuffer;
+class DrmDevice;
+
+// The HDCOz will handle modesettings and scannout operations for hardware
+// devices.
+//
+// In the DRM world there are 3 components that need to be paired up to be able
+// to display an image to the monitor: CRTC (cathode ray tube controller),
+// encoder and connector. The CRTC determines which framebuffer to read, when
+// to scanout and where to scanout. Encoders converts the stream from the CRTC
+// to the appropriate format for the connector. The connector is the physical
+// connection that monitors connect to.
+//
+// There is no 1:1:1 pairing for these components. It is possible for an encoder
+// to be compatible to multiple CRTCs and each connector can be used with
+// multiple encoders. In addition, it is possible to use one CRTC with multiple
+// connectors such that we can display the same image on multiple monitors.
+//
+// For example, the following configuration shows 2 different screens being
+// initialized separately.
+// ------------- -------------
+// | Connector | | Connector |
+// | HDMI | | VGA |
+// ------------- -------------
+// ^ ^
+// | |
+// ------------- -------------
+// | Encoder1 | | Encoder2 |
+// ------------- -------------
+// ^ ^
+// | |
+// ------------- -------------
+// | CRTC1 | | CRTC2 |
+// ------------- -------------
+//
+// In the following configuration 2 different screens are associated with the
+// same CRTC, so on scanout the same framebuffer will be displayed on both
+// monitors.
+// ------------- -------------
+// | Connector | | Connector |
+// | HDMI | | VGA |
+// ------------- -------------
+// ^ ^
+// | |
+// ------------- -------------
+// | Encoder1 | | Encoder2 |
+// ------------- -------------
+// ^ ^
+// | |
+// ----------------------
+// | CRTC1 |
+// ----------------------
+//
+// Note that it is possible to have more connectors than CRTCs which means that
+// only a subset of connectors can be active independently, showing different
+// framebuffers. Though, in this case, it would be possible to have all
+// connectors active if some use the same CRTC to mirror the display.
+class OZONE_EXPORT HardwareDisplayController {
+ typedef base::Callback<void(gfx::SwapResult)> PageFlipCallback;
+
+ public:
+ HardwareDisplayController(scoped_ptr<CrtcController> controller,
+ const gfx::Point& origin);
+ ~HardwareDisplayController();
+
+ // Performs the initial CRTC configuration. If successful, it will display the
+ // framebuffer for |primary| with |mode|.
+ bool Modeset(const OverlayPlane& primary, drmModeModeInfo mode);
+
+ // Disables the CRTC.
+ void Disable();
+
+ // Schedules the |overlays|' framebuffers to be displayed on the next vsync
+ // event. The event will be posted on the graphics card file descriptor |fd_|
+ // and it can be read and processed by |drmHandleEvent|. That function can
+ // define the callback for the page flip event. A generic data argument will
+ // be presented to the callback. We use that argument to pass in the HDCO
+ // object the event belongs to.
+ //
+ // Between this call and the callback, the framebuffers used in this call
+ // should not be modified in any way as it would cause screen tearing if the
+ // hardware performed the flip. Note that the frontbuffer should also not
+ // be modified as it could still be displayed.
+ //
+ // Note that this function does not block. Also, this function should not be
+ // called again before the page flip occurrs.
+ //
+ // Returns true if the page flip was successfully registered, false otherwise.
+ //
+ // When called with |test_only| true, this performs the page flip without
+ // changing any state, reporting if this page flip would be allowed to occur.
+ // This is always a synchronous operation, so |is_sync| is ignored and the
+ // callback is called immediately but should also be ignored; only the return
+ // value matters.
+ bool SchedulePageFlip(const OverlayPlaneList& plane_list,
+ bool is_sync,
+ bool test_only,
+ const PageFlipCallback& callback);
+
+ // Set the hardware cursor to show the contents of |surface|.
+ bool SetCursor(const scoped_refptr<ScanoutBuffer>& buffer);
+
+ bool UnsetCursor();
+
+ // Moves the hardware cursor to |location|.
+ bool MoveCursor(const gfx::Point& location);
+
+ void AddCrtc(scoped_ptr<CrtcController> controller);
+ scoped_ptr<CrtcController> RemoveCrtc(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc);
+ bool HasCrtc(const scoped_refptr<DrmDevice>& drm, uint32_t crtc) const;
+ bool IsMirrored() const;
+ bool IsDisabled() const;
+ gfx::Size GetModeSize() const;
+
+ gfx::Point origin() const { return origin_; }
+ void set_origin(const gfx::Point& origin) { origin_ = origin; }
+
+ const drmModeModeInfo& get_mode() const { return mode_; };
+
+ uint64_t GetTimeOfLastFlip() const;
+
+ const std::vector<CrtcController*>& crtc_controllers() const {
+ return crtc_controllers_.get();
+ }
+
+ scoped_refptr<DrmDevice> GetAllocationDrmDevice() const;
+
+ private:
+ base::ScopedPtrHashMap<DrmDevice*, scoped_ptr<HardwareDisplayPlaneList>>
+ owned_hardware_planes_;
+
+ // Stores the CRTC configuration. This is used to identify monitors and
+ // configure them.
+ ScopedVector<CrtcController> crtc_controllers_;
+
+ // Location of the controller on the screen.
+ gfx::Point origin_;
+
+ // The mode used by the last modesetting operation.
+ drmModeModeInfo mode_;
+
+ bool is_disabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayController);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_CONTROLLER_H_
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc b/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
new file mode 100644
index 0000000..eaa3cdc
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
@@ -0,0 +1,331 @@
+// 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 "base/bind.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
+#include "ui/ozone/platform/drm/gpu/drm_buffer.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+#include "ui/ozone/platform/drm/test/mock_drm_device.h"
+#include "ui/ozone/public/native_pixmap.h"
+
+namespace {
+
+// Create a basic mode for a 6x4 screen.
+const drmModeModeInfo kDefaultMode =
+ {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
+
+const uint32_t kPrimaryCrtc = 1;
+const uint32_t kPrimaryConnector = 2;
+const uint32_t kSecondaryCrtc = 3;
+const uint32_t kSecondaryConnector = 4;
+const size_t kPlanesPerCrtc = 2;
+
+const gfx::Size kDefaultModeSize(kDefaultMode.hdisplay, kDefaultMode.vdisplay);
+const gfx::SizeF kDefaultModeSizeF(1.0, 1.0);
+
+class MockScanoutBuffer : public ui::ScanoutBuffer {
+ public:
+ MockScanoutBuffer(const gfx::Size& size) : size_(size) {}
+
+ // ScanoutBuffer:
+ uint32_t GetFramebufferId() const override { return 0; }
+ uint32_t GetHandle() const override { return 0; }
+ gfx::Size GetSize() const override { return size_; }
+
+ private:
+ ~MockScanoutBuffer() override {}
+
+ gfx::Size size_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockScanoutBuffer);
+};
+
+} // namespace
+
+class HardwareDisplayControllerTest : public testing::Test {
+ public:
+ HardwareDisplayControllerTest() : page_flips_(0) {}
+ ~HardwareDisplayControllerTest() override {}
+
+ void SetUp() override;
+ void TearDown() override;
+
+ void PageFlipCallback(gfx::SwapResult);
+
+ protected:
+ scoped_ptr<ui::HardwareDisplayController> controller_;
+ scoped_refptr<ui::MockDrmDevice> drm_;
+
+ int page_flips_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayControllerTest);
+};
+
+void HardwareDisplayControllerTest::SetUp() {
+ std::vector<uint32_t> crtcs;
+ crtcs.push_back(kPrimaryCrtc);
+ crtcs.push_back(kSecondaryCrtc);
+ drm_ = new ui::MockDrmDevice(false, crtcs, kPlanesPerCrtc);
+ controller_.reset(new ui::HardwareDisplayController(
+ scoped_ptr<ui::CrtcController>(
+ new ui::CrtcController(drm_.get(), kPrimaryCrtc, kPrimaryConnector)),
+ gfx::Point()));
+}
+
+void HardwareDisplayControllerTest::TearDown() {
+ controller_.reset();
+ drm_ = nullptr;
+}
+
+void HardwareDisplayControllerTest::PageFlipCallback(gfx::SwapResult) {
+ page_flips_++;
+}
+
+TEST_F(HardwareDisplayControllerTest, CheckModesettingResult) {
+ ui::OverlayPlane plane(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+
+ EXPECT_TRUE(controller_->Modeset(plane, kDefaultMode));
+ EXPECT_FALSE(plane.buffer->HasOneRef());
+}
+
+TEST_F(HardwareDisplayControllerTest, CheckStateAfterPageFlip) {
+ ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+
+ EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+
+ ui::OverlayPlane plane2(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+ std::vector<ui::OverlayPlane> planes =
+ std::vector<ui::OverlayPlane>(1, plane2);
+ EXPECT_TRUE(controller_->SchedulePageFlip(
+ planes, false, false,
+ base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this))));
+ drm_->RunCallbacks();
+ EXPECT_TRUE(plane1.buffer->HasOneRef());
+ EXPECT_FALSE(plane2.buffer->HasOneRef());
+
+ EXPECT_EQ(1, drm_->get_page_flip_call_count());
+ EXPECT_EQ(0, drm_->get_overlay_flip_call_count());
+}
+
+TEST_F(HardwareDisplayControllerTest, CheckStateIfModesetFails) {
+ drm_->set_set_crtc_expectation(false);
+
+ ui::OverlayPlane plane(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+
+ EXPECT_FALSE(controller_->Modeset(plane, kDefaultMode));
+}
+
+TEST_F(HardwareDisplayControllerTest, CheckStateIfPageFlipFails) {
+ drm_->set_page_flip_expectation(false);
+
+ ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+
+ EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+
+ ui::OverlayPlane plane2(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+ std::vector<ui::OverlayPlane> planes =
+ std::vector<ui::OverlayPlane>(1, plane2);
+ EXPECT_FALSE(controller_->SchedulePageFlip(
+ planes, false, false,
+ base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this))));
+ drm_->RunCallbacks();
+ planes.clear();
+
+ EXPECT_FALSE(plane1.buffer->HasOneRef());
+ EXPECT_TRUE(plane2.buffer->HasOneRef());
+}
+
+TEST_F(HardwareDisplayControllerTest, CheckOverlayPresent) {
+ ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+ ui::OverlayPlane plane2(
+ scoped_refptr<ui::ScanoutBuffer>(new MockScanoutBuffer(kDefaultModeSize)),
+ 1, gfx::OVERLAY_TRANSFORM_NONE, gfx::Rect(kDefaultModeSize),
+ gfx::RectF(kDefaultModeSizeF));
+
+ EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+
+ std::vector<ui::OverlayPlane> planes;
+ planes.push_back(plane1);
+ planes.push_back(plane2);
+
+ EXPECT_TRUE(controller_->SchedulePageFlip(
+ planes, false, false,
+ base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this))));
+ drm_->RunCallbacks();
+ EXPECT_EQ(1, drm_->get_page_flip_call_count());
+ EXPECT_EQ(1, drm_->get_overlay_flip_call_count());
+}
+
+TEST_F(HardwareDisplayControllerTest, CheckOverlayTestMode) {
+ ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+ ui::OverlayPlane plane2(
+ scoped_refptr<ui::ScanoutBuffer>(new MockScanoutBuffer(kDefaultModeSize)),
+ 1, gfx::OVERLAY_TRANSFORM_NONE, gfx::Rect(kDefaultModeSize),
+ gfx::RectF(kDefaultModeSizeF));
+
+ EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+
+ std::vector<ui::OverlayPlane> planes;
+ planes.push_back(plane1);
+ planes.push_back(plane2);
+
+ EXPECT_TRUE(controller_->SchedulePageFlip(
+ planes, false, false,
+ base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this))));
+ drm_->RunCallbacks();
+ EXPECT_EQ(1, drm_->get_page_flip_call_count());
+ EXPECT_EQ(1, drm_->get_overlay_flip_call_count());
+
+ // A test call shouldn't cause new flips, but should succeed.
+ EXPECT_TRUE(controller_->SchedulePageFlip(
+ planes, false, true,
+ base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this))));
+ drm_->RunCallbacks();
+ EXPECT_EQ(1, drm_->get_page_flip_call_count());
+ EXPECT_EQ(1, drm_->get_overlay_flip_call_count());
+
+ // Regular flips should continue on normally.
+ EXPECT_TRUE(controller_->SchedulePageFlip(
+ planes, false, false,
+ base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this))));
+ drm_->RunCallbacks();
+ EXPECT_EQ(2, drm_->get_page_flip_call_count());
+ EXPECT_EQ(2, drm_->get_overlay_flip_call_count());
+}
+
+TEST_F(HardwareDisplayControllerTest, RejectUnderlays) {
+ ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+ ui::OverlayPlane plane2(
+ scoped_refptr<ui::ScanoutBuffer>(new MockScanoutBuffer(kDefaultModeSize)),
+ -1, gfx::OVERLAY_TRANSFORM_NONE, gfx::Rect(kDefaultModeSize),
+ gfx::RectF(kDefaultModeSizeF));
+
+ EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+
+ std::vector<ui::OverlayPlane> planes;
+ planes.push_back(plane1);
+ planes.push_back(plane2);
+
+ EXPECT_FALSE(controller_->SchedulePageFlip(
+ planes, false, false,
+ base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this))));
+}
+
+TEST_F(HardwareDisplayControllerTest, PageflipMirroredControllers) {
+ controller_->AddCrtc(scoped_ptr<ui::CrtcController>(
+ new ui::CrtcController(drm_.get(), kSecondaryCrtc, kSecondaryConnector)));
+
+ ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+ EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ EXPECT_EQ(2, drm_->get_set_crtc_call_count());
+
+ ui::OverlayPlane plane2(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+ std::vector<ui::OverlayPlane> planes =
+ std::vector<ui::OverlayPlane>(1, plane2);
+ EXPECT_TRUE(controller_->SchedulePageFlip(
+ planes, false, false,
+ base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this))));
+ drm_->RunCallbacks();
+ EXPECT_EQ(2, drm_->get_page_flip_call_count());
+ EXPECT_EQ(1, page_flips_);
+}
+
+TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) {
+ ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+ EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ std::vector<ui::OverlayPlane> planes =
+ std::vector<ui::OverlayPlane>(1, plane1);
+ EXPECT_TRUE(controller_->SchedulePageFlip(
+ planes, false, false,
+ base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this))));
+ drm_->RunCallbacks();
+
+ const ui::HardwareDisplayPlane* owned_plane = nullptr;
+ for (const auto& plane : drm_->plane_manager()->planes())
+ if (plane->in_use())
+ owned_plane = plane;
+ ASSERT_TRUE(owned_plane != nullptr);
+ EXPECT_EQ(kPrimaryCrtc, owned_plane->owning_crtc());
+ // Removing the crtc should free the plane.
+ scoped_ptr<ui::CrtcController> crtc =
+ controller_->RemoveCrtc(drm_, kPrimaryCrtc);
+ EXPECT_FALSE(owned_plane->in_use());
+}
+
+TEST_F(HardwareDisplayControllerTest, ModesetWhilePageFlipping) {
+ ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+ EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ std::vector<ui::OverlayPlane> planes =
+ std::vector<ui::OverlayPlane>(1, plane1);
+ EXPECT_TRUE(controller_->SchedulePageFlip(
+ planes, false, false,
+ base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this))));
+
+ EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ drm_->RunCallbacks();
+ EXPECT_EQ(1, page_flips_);
+}
+
+TEST_F(HardwareDisplayControllerTest, AddCrtcMidPageFlip) {
+ ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+ EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ std::vector<ui::OverlayPlane> planes =
+ std::vector<ui::OverlayPlane>(1, plane1);
+ EXPECT_TRUE(controller_->SchedulePageFlip(
+ planes, false, false,
+ base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this))));
+
+ controller_->AddCrtc(scoped_ptr<ui::CrtcController>(
+ new ui::CrtcController(drm_.get(), kSecondaryCrtc, kSecondaryConnector)));
+
+ drm_->RunCallbacks();
+ EXPECT_EQ(1, page_flips_);
+}
+
+TEST_F(HardwareDisplayControllerTest, RemoveCrtcMidPageFlip) {
+ ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+ EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ std::vector<ui::OverlayPlane> planes =
+ std::vector<ui::OverlayPlane>(1, plane1);
+ EXPECT_TRUE(controller_->SchedulePageFlip(
+ planes, false, false,
+ base::Bind(&HardwareDisplayControllerTest::PageFlipCallback,
+ base::Unretained(this))));
+
+ controller_->RemoveCrtc(drm_, kPrimaryCrtc);
+
+ EXPECT_EQ(1, page_flips_);
+ drm_->RunCallbacks();
+ EXPECT_EQ(1, page_flips_);
+}
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane.cc
new file mode 100644
index 0000000..b8b3bd1
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane.cc
@@ -0,0 +1,32 @@
+// 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/drm/gpu/hardware_display_plane.h"
+
+#include <drm.h>
+#include <xf86drm.h>
+
+#include "base/logging.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+
+namespace ui {
+
+HardwareDisplayPlane::HardwareDisplayPlane(uint32_t plane_id,
+ uint32_t possible_crtcs)
+ : plane_id_(plane_id), possible_crtcs_(possible_crtcs) {
+}
+
+HardwareDisplayPlane::~HardwareDisplayPlane() {
+}
+
+bool HardwareDisplayPlane::CanUseForCrtc(uint32_t crtc_index) {
+ return possible_crtcs_ & (1 << crtc_index);
+}
+
+bool HardwareDisplayPlane::Initialize(DrmDevice* drm) {
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane.h b/ui/ozone/platform/drm/gpu/hardware_display_plane.h
new file mode 100644
index 0000000..cef1ada
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane.h
@@ -0,0 +1,56 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/basictypes.h"
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform/drm/common/scoped_drm_types.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace ui {
+
+class DrmDevice;
+
+class OZONE_EXPORT HardwareDisplayPlane {
+ public:
+ HardwareDisplayPlane(uint32_t plane_id, uint32_t possible_crtcs);
+
+ virtual ~HardwareDisplayPlane();
+
+ virtual bool Initialize(DrmDevice* drm);
+
+ bool CanUseForCrtc(uint32_t crtc_index);
+
+ bool in_use() const { return in_use_; }
+ void set_in_use(bool in_use) { in_use_ = in_use; }
+
+ bool is_dummy() const { return is_dummy_; }
+ void set_is_dummy(bool is_dummy) { is_dummy_ = is_dummy; }
+
+ uint32_t plane_id() const { return plane_id_; }
+
+ void set_owning_crtc(uint32_t crtc) { owning_crtc_ = crtc; }
+ uint32_t owning_crtc() const { return owning_crtc_; }
+
+ protected:
+ uint32_t plane_id_ = 0;
+ uint32_t possible_crtcs_ = 0;
+ uint32_t owning_crtc_ = 0;
+ bool in_use_ = false;
+ bool is_dummy_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlane);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_H_
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
new file mode 100644
index 0000000..3f0952e
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
@@ -0,0 +1,117 @@
+// Copyright 2015 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/drm/gpu/hardware_display_plane_atomic.h"
+
+#include <drm.h>
+#include <errno.h>
+#include <xf86drm.h>
+
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+
+namespace ui {
+namespace {
+
+const char* kCrtcPropName = "CRTC_ID";
+const char* kFbPropName = "FB_ID";
+const char* kCrtcXPropName = "CRTC_X";
+const char* kCrtcYPropName = "CRTC_Y";
+const char* kCrtcWPropName = "CRTC_W";
+const char* kCrtcHPropName = "CRTC_H";
+const char* kSrcXPropName = "SRC_X";
+const char* kSrcYPropName = "SRC_Y";
+const char* kSrcWPropName = "SRC_W";
+const char* kSrcHPropName = "SRC_H";
+
+} // namespace
+
+HardwareDisplayPlaneAtomic::Property::Property() {
+}
+
+bool HardwareDisplayPlaneAtomic::Property::Initialize(
+ DrmDevice* drm,
+ const char* name,
+ const ScopedDrmObjectPropertyPtr& plane_props) {
+ for (uint32_t i = 0; i < plane_props->count_props; i++) {
+ ScopedDrmPropertyPtr property(
+ drmModeGetProperty(drm->get_fd(), plane_props->props[i]));
+ if (property && !strcmp(property->name, name)) {
+ id = property->prop_id;
+ break;
+ }
+ }
+ if (!id) {
+ LOG(ERROR) << "Could not find property " << name;
+ return false;
+ }
+ return true;
+}
+
+HardwareDisplayPlaneAtomic::HardwareDisplayPlaneAtomic(uint32_t plane_id,
+ uint32_t possible_crtcs)
+ : HardwareDisplayPlane(plane_id, possible_crtcs) {
+}
+HardwareDisplayPlaneAtomic::~HardwareDisplayPlaneAtomic() {
+}
+
+bool HardwareDisplayPlaneAtomic::SetPlaneData(drmModePropertySet* property_set,
+ uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& crtc_rect,
+ const gfx::Rect& src_rect) {
+ int plane_set_error =
+ drmModePropertySetAdd(property_set, plane_id_, crtc_prop_.id, crtc_id) ||
+ drmModePropertySetAdd(property_set, plane_id_, fb_prop_.id,
+ framebuffer) ||
+ drmModePropertySetAdd(property_set, plane_id_, crtc_x_prop_.id,
+ crtc_rect.x()) ||
+ drmModePropertySetAdd(property_set, plane_id_, crtc_y_prop_.id,
+ crtc_rect.y()) ||
+ drmModePropertySetAdd(property_set, plane_id_, crtc_w_prop_.id,
+ crtc_rect.width()) ||
+ drmModePropertySetAdd(property_set, plane_id_, crtc_h_prop_.id,
+ crtc_rect.height()) ||
+ drmModePropertySetAdd(property_set, plane_id_, src_x_prop_.id,
+ src_rect.x()) ||
+ drmModePropertySetAdd(property_set, plane_id_, src_y_prop_.id,
+ src_rect.x()) ||
+ drmModePropertySetAdd(property_set, plane_id_, src_w_prop_.id,
+ src_rect.width()) ||
+ drmModePropertySetAdd(property_set, plane_id_, src_h_prop_.id,
+ src_rect.height());
+ if (plane_set_error) {
+ PLOG(ERROR) << "Failed to set plane data";
+ return false;
+ }
+ return true;
+}
+
+bool HardwareDisplayPlaneAtomic::Initialize(DrmDevice* drm) {
+ ScopedDrmObjectPropertyPtr plane_props(drmModeObjectGetProperties(
+ drm->get_fd(), plane_id_, DRM_MODE_OBJECT_PLANE));
+
+ if (!plane_props) {
+ PLOG(ERROR) << "Unable to get plane properties.";
+ return false;
+ }
+
+ bool props_init = crtc_prop_.Initialize(drm, kCrtcPropName, plane_props) &&
+ fb_prop_.Initialize(drm, kFbPropName, plane_props) &&
+ crtc_x_prop_.Initialize(drm, kCrtcXPropName, plane_props) &&
+ crtc_y_prop_.Initialize(drm, kCrtcYPropName, plane_props) &&
+ crtc_w_prop_.Initialize(drm, kCrtcWPropName, plane_props) &&
+ crtc_h_prop_.Initialize(drm, kCrtcHPropName, plane_props) &&
+ src_x_prop_.Initialize(drm, kSrcXPropName, plane_props) &&
+ src_y_prop_.Initialize(drm, kSrcYPropName, plane_props) &&
+ src_w_prop_.Initialize(drm, kSrcWPropName, plane_props) &&
+ src_h_prop_.Initialize(drm, kSrcHPropName, plane_props);
+
+ if (!props_init) {
+ LOG(ERROR) << "Unable to get plane properties.";
+ return false;
+ }
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h b/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h
new file mode 100644
index 0000000..f89c119
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h
@@ -0,0 +1,58 @@
+// Copyright 2015 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_ATOMIC_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_ATOMIC_H_
+
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
+
+#include <xf86drmMode.h>
+
+namespace ui {
+
+class CrtcController;
+class DrmDevice;
+
+class HardwareDisplayPlaneAtomic : public HardwareDisplayPlane {
+ public:
+ HardwareDisplayPlaneAtomic(uint32_t plane_id, uint32_t possible_crtcs);
+ ~HardwareDisplayPlaneAtomic() override;
+
+ bool SetPlaneData(drmModePropertySet* property_set,
+ uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& crtc_rect,
+ const gfx::Rect& src_rect);
+
+ // HardwareDisplayPlane:
+ bool Initialize(DrmDevice* drm) override;
+
+ void set_crtc(CrtcController* crtc) { crtc_ = crtc; }
+ CrtcController* crtc() const { return crtc_; }
+
+ private:
+ struct Property {
+ Property();
+ bool Initialize(DrmDevice* drm,
+ const char* name,
+ const ScopedDrmObjectPropertyPtr& plane_properties);
+ uint32_t id = 0;
+ };
+
+ Property crtc_prop_;
+ Property fb_prop_;
+ Property crtc_x_prop_;
+ Property crtc_y_prop_;
+ Property crtc_w_prop_;
+ Property crtc_h_prop_;
+ Property src_x_prop_;
+ Property src_y_prop_;
+ Property src_w_prop_;
+ Property src_h_prop_;
+ CrtcController* crtc_ = nullptr;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_ATOMIC_H_
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
new file mode 100644
index 0000000..a790d62
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
@@ -0,0 +1,235 @@
+// 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/drm/gpu/hardware_display_plane_manager.h"
+
+#include <drm.h>
+#include <xf86drm.h>
+
+#include <set>
+
+#include "base/logging.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
+#include "ui/ozone/public/ozone_switches.h"
+
+namespace ui {
+namespace {
+
+const float kFixedPointScaleValue = 65536.0f;
+
+} // namespace
+
+HardwareDisplayPlaneList::HardwareDisplayPlaneList() {
+#if defined(USE_DRM_ATOMIC)
+ atomic_property_set.reset(drmModePropertySetAlloc());
+#endif // defined(USE_DRM_ATOMIC)
+}
+
+HardwareDisplayPlaneList::~HardwareDisplayPlaneList() {
+ for (auto* plane : plane_list) {
+ plane->set_in_use(false);
+ plane->set_owning_crtc(0);
+ }
+ for (auto* plane : old_plane_list) {
+ plane->set_in_use(false);
+ plane->set_owning_crtc(0);
+ }
+}
+
+HardwareDisplayPlaneList::PageFlipInfo::PageFlipInfo(uint32_t crtc_id,
+ uint32_t framebuffer,
+ CrtcController* crtc)
+ : crtc_id(crtc_id), framebuffer(framebuffer), crtc(crtc) {
+}
+
+HardwareDisplayPlaneList::PageFlipInfo::~PageFlipInfo() {
+}
+
+HardwareDisplayPlaneList::PageFlipInfo::Plane::Plane(int plane,
+ int framebuffer,
+ const gfx::Rect& bounds,
+ const gfx::Rect& src_rect)
+ : plane(plane),
+ framebuffer(framebuffer),
+ bounds(bounds),
+ src_rect(src_rect) {
+}
+
+HardwareDisplayPlaneList::PageFlipInfo::Plane::~Plane() {
+}
+
+HardwareDisplayPlaneManager::HardwareDisplayPlaneManager() : drm_(nullptr) {
+}
+
+HardwareDisplayPlaneManager::~HardwareDisplayPlaneManager() {
+}
+
+bool HardwareDisplayPlaneManager::Initialize(DrmDevice* drm) {
+ drm_ = drm;
+
+ // Try to get all of the planes if possible, so we don't have to try to
+ // discover hidden primary planes.
+ bool has_universal_planes = false;
+#if defined(DRM_CLIENT_CAP_UNIVERSAL_PLANES)
+ has_universal_planes = drm->SetCapability(DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+#endif // defined(DRM_CLIENT_CAP_UNIVERSAL_PLANES)
+
+ ScopedDrmResourcesPtr resources(drmModeGetResources(drm->get_fd()));
+ if (!resources) {
+ PLOG(ERROR) << "Failed to get resources";
+ return false;
+ }
+
+ ScopedDrmPlaneResPtr plane_resources(drmModeGetPlaneResources(drm->get_fd()));
+ if (!plane_resources) {
+ PLOG(ERROR) << "Failed to get plane resources";
+ return false;
+ }
+
+ crtcs_.clear();
+ for (int i = 0; i < resources->count_crtcs; ++i) {
+ crtcs_.push_back(resources->crtcs[i]);
+ }
+
+ uint32_t num_planes = plane_resources->count_planes;
+ std::set<uint32_t> plane_ids;
+ for (uint32_t i = 0; i < num_planes; ++i) {
+ ScopedDrmPlanePtr drm_plane(
+ drmModeGetPlane(drm->get_fd(), plane_resources->planes[i]));
+ if (!drm_plane) {
+ PLOG(ERROR) << "Failed to get plane " << i;
+ return false;
+ }
+ plane_ids.insert(drm_plane->plane_id);
+ scoped_ptr<HardwareDisplayPlane> plane(
+ CreatePlane(drm_plane->plane_id, drm_plane->possible_crtcs));
+ if (plane->Initialize(drm))
+ planes_.push_back(plane.Pass());
+ }
+
+ // crbug.com/464085: if driver reports no primary planes for a crtc, create a
+ // dummy plane for which we can assign exactly one overlay.
+ // TODO(dnicoara): refactor this to simplify AssignOverlayPlanes and move
+ // this workaround into HardwareDisplayPlaneLegacy.
+ if (!has_universal_planes) {
+ for (int i = 0; i < resources->count_crtcs; ++i) {
+ if (plane_ids.find(resources->crtcs[i] - 1) == plane_ids.end()) {
+ scoped_ptr<HardwareDisplayPlane> dummy_plane(
+ CreatePlane(resources->crtcs[i] - 1, (1 << i)));
+ dummy_plane->set_is_dummy(true);
+ if (dummy_plane->Initialize(drm))
+ planes_.push_back(dummy_plane.Pass());
+ }
+ }
+ }
+
+ std::sort(planes_.begin(), planes_.end(),
+ [](HardwareDisplayPlane* l, HardwareDisplayPlane* r) {
+ return l->plane_id() < r->plane_id();
+ });
+ return true;
+}
+
+scoped_ptr<HardwareDisplayPlane> HardwareDisplayPlaneManager::CreatePlane(
+ uint32_t plane_id,
+ uint32_t possible_crtcs) {
+ return scoped_ptr<HardwareDisplayPlane>(
+ new HardwareDisplayPlane(plane_id, possible_crtcs));
+}
+
+HardwareDisplayPlane* HardwareDisplayPlaneManager::FindNextUnusedPlane(
+ size_t* index,
+ uint32_t crtc_index) {
+ for (size_t i = *index; i < planes_.size(); ++i) {
+ auto plane = planes_[i];
+ if (!plane->in_use() && plane->CanUseForCrtc(crtc_index)) {
+ *index = i + 1;
+ return plane;
+ }
+ }
+ return nullptr;
+}
+
+int HardwareDisplayPlaneManager::LookupCrtcIndex(uint32_t crtc_id) {
+ for (size_t i = 0; i < crtcs_.size(); ++i)
+ if (crtcs_[i] == crtc_id)
+ return i;
+ return -1;
+}
+
+void HardwareDisplayPlaneManager::BeginFrame(
+ HardwareDisplayPlaneList* plane_list) {
+ for (auto* plane : plane_list->old_plane_list) {
+ plane->set_in_use(false);
+ }
+}
+
+bool HardwareDisplayPlaneManager::AssignOverlayPlanes(
+ HardwareDisplayPlaneList* plane_list,
+ const OverlayPlaneList& overlay_list,
+ uint32_t crtc_id,
+ CrtcController* crtc) {
+ int crtc_index = LookupCrtcIndex(crtc_id);
+ if (crtc_index < 0) {
+ LOG(ERROR) << "Cannot find crtc " << crtc_id;
+ return false;
+ }
+
+ size_t plane_idx = 0;
+ for (const auto& plane : overlay_list) {
+ HardwareDisplayPlane* hw_plane =
+ FindNextUnusedPlane(&plane_idx, crtc_index);
+ if (!hw_plane) {
+ LOG(ERROR) << "Failed to find a free plane for crtc " << crtc_id;
+ return false;
+ }
+
+ gfx::Rect fixed_point_rect;
+ if (!hw_plane->is_dummy()) {
+ const gfx::Size& size = plane.buffer->GetSize();
+ gfx::RectF crop_rect = plane.crop_rect;
+ crop_rect.Scale(size.width(), size.height());
+
+ // This returns a number in 16.16 fixed point, required by the DRM overlay
+ // APIs.
+ auto to_fixed_point =
+ [](double v) -> uint32_t { return v * kFixedPointScaleValue; };
+ fixed_point_rect = gfx::Rect(to_fixed_point(crop_rect.x()),
+ to_fixed_point(crop_rect.y()),
+ to_fixed_point(crop_rect.width()),
+ to_fixed_point(crop_rect.height()));
+ }
+
+ plane_list->plane_list.push_back(hw_plane);
+ hw_plane->set_owning_crtc(crtc_id);
+ if (SetPlaneData(plane_list, hw_plane, plane, crtc_id, fixed_point_rect,
+ crtc)) {
+ hw_plane->set_in_use(true);
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+void HardwareDisplayPlaneManager::ResetPlanes(
+ HardwareDisplayPlaneList* plane_list,
+ uint32_t crtc_id) {
+ std::vector<HardwareDisplayPlane*> planes;
+ planes.swap(plane_list->old_plane_list);
+ for (auto* plane : planes) {
+ if (plane->owning_crtc() == crtc_id) {
+ plane->set_owning_crtc(0);
+ plane->set_in_use(false);
+ } else {
+ plane_list->old_plane_list.push_back(plane);
+ }
+ }
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
new file mode 100644
index 0000000..55afa9e
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
@@ -0,0 +1,132 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_MANAGER_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_MANAGER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <xf86drmMode.h>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_vector.h"
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform/drm/common/scoped_drm_types.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
+#include "ui/ozone/platform/drm/gpu/overlay_plane.h"
+
+namespace gfx {
+class Rect;
+} // namespace gfx
+
+namespace ui {
+
+class CrtcController;
+class DrmDevice;
+
+// This contains the list of planes controlled by one HDC on a given DRM fd.
+// It is owned by the HDC and filled by the CrtcController.
+struct OZONE_EXPORT HardwareDisplayPlaneList {
+ HardwareDisplayPlaneList();
+ ~HardwareDisplayPlaneList();
+
+ // This is the list of planes to be committed this time.
+ std::vector<HardwareDisplayPlane*> plane_list;
+ // This is the list of planes that was committed last time.
+ std::vector<HardwareDisplayPlane*> old_plane_list;
+
+ struct PageFlipInfo {
+ PageFlipInfo(uint32_t crtc_id, uint32_t framebuffer, CrtcController* crtc);
+ ~PageFlipInfo();
+
+ uint32_t crtc_id;
+ uint32_t framebuffer;
+ CrtcController* crtc;
+
+ struct Plane {
+ Plane(int plane,
+ int framebuffer,
+ const gfx::Rect& bounds,
+ const gfx::Rect& src_rect);
+ ~Plane();
+ int plane;
+ int framebuffer;
+ gfx::Rect bounds;
+ gfx::Rect src_rect;
+ };
+ std::vector<Plane> planes;
+ };
+ // In the case of non-atomic operation, this info will be used for
+ // pageflipping.
+ std::vector<PageFlipInfo> legacy_page_flips;
+
+#if defined(USE_DRM_ATOMIC)
+ ScopedDrmPropertySetPtr atomic_property_set;
+#endif // defined(USE_DRM_ATOMIC)
+};
+
+class OZONE_EXPORT HardwareDisplayPlaneManager {
+ public:
+ HardwareDisplayPlaneManager();
+ virtual ~HardwareDisplayPlaneManager();
+
+ // This parses information from the drm driver, adding any new planes
+ // or crtcs found.
+ bool Initialize(DrmDevice* drm);
+
+ // Clears old frame state out. Must be called before any AssignOverlayPlanes
+ // calls.
+ void BeginFrame(HardwareDisplayPlaneList* plane_list);
+
+ // Assign hardware planes from the |planes_| list to |overlay_list| entries,
+ // recording the plane IDs in the |plane_list|. Only planes compatible with
+ // |crtc_id| will be used. |overlay_list| must be sorted bottom-to-top.
+ virtual bool AssignOverlayPlanes(HardwareDisplayPlaneList* plane_list,
+ const OverlayPlaneList& overlay_list,
+ uint32_t crtc_id,
+ CrtcController* crtc);
+
+ // Commit the plane states in |plane_list|.
+ virtual bool Commit(HardwareDisplayPlaneList* plane_list,
+ bool is_sync,
+ bool test_only) = 0;
+
+ // Set all planes in |plane_list| owned by |crtc_id| to free.
+ static void ResetPlanes(HardwareDisplayPlaneList* plane_list,
+ uint32_t crtc_id);
+
+ const ScopedVector<HardwareDisplayPlane>& planes() { return planes_; }
+
+ protected:
+ virtual bool SetPlaneData(HardwareDisplayPlaneList* plane_list,
+ HardwareDisplayPlane* hw_plane,
+ const OverlayPlane& overlay,
+ uint32_t crtc_id,
+ const gfx::Rect& src_rect,
+ CrtcController* crtc) = 0;
+
+ virtual scoped_ptr<HardwareDisplayPlane> CreatePlane(uint32_t plane_id,
+ uint32_t possible_crtcs);
+
+ // Finds the plane located at or after |*index| that is not in use and can
+ // be used with |crtc_index|.
+ HardwareDisplayPlane* FindNextUnusedPlane(size_t* index, uint32_t crtc_index);
+
+ // Convert |crtc_id| into an index, returning -1 if the ID couldn't be found.
+ int LookupCrtcIndex(uint32_t crtc_id);
+
+ // Object containing the connection to the graphics device and wraps the API
+ // calls to control it. Not owned.
+ DrmDevice* drm_;
+
+ ScopedVector<HardwareDisplayPlane> planes_;
+ std::vector<uint32_t> crtcs_;
+
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_MANAGER_H_
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
new file mode 100644
index 0000000..9ee6948
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
@@ -0,0 +1,103 @@
+// 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/drm/gpu/hardware_display_plane_manager_atomic.h"
+
+#include "base/bind.h"
+#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
+
+namespace ui {
+
+static void AtomicPageFlipCallback(
+ std::vector<base::WeakPtr<CrtcController>> crtcs,
+ unsigned int frame,
+ unsigned int seconds,
+ unsigned int useconds) {
+ for (auto& crtc : crtcs) {
+ auto* crtc_ptr = crtc.get();
+ if (crtc_ptr)
+ crtc_ptr->OnPageFlipEvent(frame, seconds, useconds);
+ }
+}
+
+HardwareDisplayPlaneManagerAtomic::HardwareDisplayPlaneManagerAtomic() {
+}
+
+HardwareDisplayPlaneManagerAtomic::~HardwareDisplayPlaneManagerAtomic() {
+}
+
+bool HardwareDisplayPlaneManagerAtomic::Commit(
+ HardwareDisplayPlaneList* plane_list,
+ bool is_sync,
+ bool test_only) {
+ for (HardwareDisplayPlane* plane : plane_list->old_plane_list) {
+ bool found =
+ std::find(plane_list->plane_list.begin(), plane_list->plane_list.end(),
+ plane) != plane_list->plane_list.end();
+ if (!found) {
+ // This plane is being released, so we need to zero it.
+ plane->set_in_use(false);
+ HardwareDisplayPlaneAtomic* atomic_plane =
+ static_cast<HardwareDisplayPlaneAtomic*>(plane);
+ atomic_plane->SetPlaneData(plane_list->atomic_property_set.get(), 0, 0,
+ gfx::Rect(), gfx::Rect());
+ }
+ }
+
+ std::vector<base::WeakPtr<CrtcController>> crtcs;
+ for (HardwareDisplayPlane* plane : plane_list->plane_list) {
+ HardwareDisplayPlaneAtomic* atomic_plane =
+ static_cast<HardwareDisplayPlaneAtomic*>(plane);
+ if (crtcs.empty() || crtcs.back().get() != atomic_plane->crtc())
+ crtcs.push_back(atomic_plane->crtc()->AsWeakPtr());
+ }
+
+ if (test_only) {
+ for (HardwareDisplayPlane* plane : plane_list->plane_list) {
+ plane->set_in_use(false);
+ }
+ } else {
+ plane_list->plane_list.swap(plane_list->old_plane_list);
+ }
+ plane_list->plane_list.clear();
+ if (!drm_->CommitProperties(plane_list->atomic_property_set.get(), 0, is_sync,
+ test_only,
+ base::Bind(&AtomicPageFlipCallback, crtcs))) {
+ PLOG(ERROR) << "Failed to commit properties";
+ return false;
+ }
+ plane_list->atomic_property_set.reset(drmModePropertySetAlloc());
+ return true;
+}
+
+bool HardwareDisplayPlaneManagerAtomic::SetPlaneData(
+ HardwareDisplayPlaneList* plane_list,
+ HardwareDisplayPlane* hw_plane,
+ const OverlayPlane& overlay,
+ uint32_t crtc_id,
+ const gfx::Rect& src_rect,
+ CrtcController* crtc) {
+ HardwareDisplayPlaneAtomic* atomic_plane =
+ static_cast<HardwareDisplayPlaneAtomic*>(hw_plane);
+ if (!atomic_plane->SetPlaneData(plane_list->atomic_property_set.get(),
+ crtc_id, overlay.buffer->GetFramebufferId(),
+ overlay.display_bounds, src_rect)) {
+ LOG(ERROR) << "Failed to set plane properties";
+ return false;
+ }
+ atomic_plane->set_crtc(crtc);
+ return true;
+}
+
+scoped_ptr<HardwareDisplayPlane> HardwareDisplayPlaneManagerAtomic::CreatePlane(
+ uint32_t plane_id,
+ uint32_t possible_crtcs) {
+ return scoped_ptr<HardwareDisplayPlane>(
+ new HardwareDisplayPlaneAtomic(plane_id, possible_crtcs));
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
new file mode 100644
index 0000000..de883ee
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
@@ -0,0 +1,41 @@
+// Copyright 2015 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_MANAGER_ATOMIC_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_MANAGER_ATOMIC_H_
+
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
+
+namespace ui {
+
+class OZONE_EXPORT HardwareDisplayPlaneManagerAtomic
+ : public HardwareDisplayPlaneManager {
+ public:
+ HardwareDisplayPlaneManagerAtomic();
+ ~HardwareDisplayPlaneManagerAtomic() override;
+
+ // HardwareDisplayPlaneManager:
+ bool Commit(HardwareDisplayPlaneList* plane_list,
+ bool is_sync,
+ bool test_only) override;
+
+ private:
+ bool SetPlaneData(HardwareDisplayPlaneList* plane_list,
+ HardwareDisplayPlane* hw_plane,
+ const OverlayPlane& overlay,
+ uint32_t crtc_id,
+ const gfx::Rect& src_rect,
+ CrtcController* crtc) override;
+
+ scoped_ptr<HardwareDisplayPlane> CreatePlane(
+ uint32_t plane_id,
+ uint32_t possible_crtcs) override;
+
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneManagerAtomic);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_MANAGER_ATOMIC_H_
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc
new file mode 100644
index 0000000..dff9e57
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc
@@ -0,0 +1,108 @@
+// 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/drm/gpu/hardware_display_plane_manager_legacy.h"
+
+#include "base/bind.h"
+#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
+
+namespace ui {
+
+HardwareDisplayPlaneManagerLegacy::HardwareDisplayPlaneManagerLegacy() {
+}
+
+HardwareDisplayPlaneManagerLegacy::~HardwareDisplayPlaneManagerLegacy() {
+}
+
+bool HardwareDisplayPlaneManagerLegacy::Commit(
+ HardwareDisplayPlaneList* plane_list,
+ bool is_sync,
+ bool test_only) {
+ if (test_only) {
+ for (HardwareDisplayPlane* plane : plane_list->plane_list) {
+ plane->set_in_use(false);
+ }
+ plane_list->plane_list.clear();
+ plane_list->legacy_page_flips.clear();
+ return true;
+ }
+ if (plane_list->plane_list.empty()) // No assigned planes, nothing to do.
+ return true;
+ bool ret = true;
+ // The order of operations here (set new planes, pageflip, clear old planes)
+ // is designed to minimze the chance of a significant artifact occurring.
+ // The planes must be updated first because the main plane no longer contains
+ // their content. The old planes are removed last because the previous primary
+ // plane used them as overlays and thus didn't contain their content, so we
+ // must first flip to the new primary plane, which does. The error here will
+ // be the delta of (new contents, old contents), but it should be barely
+ // noticeable.
+ for (const auto& flip : plane_list->legacy_page_flips) {
+ // Permission Denied is a legitimate error
+ for (const auto& plane : flip.planes) {
+ if (!drm_->PageFlipOverlay(flip.crtc_id, plane.framebuffer, plane.bounds,
+ plane.src_rect, plane.plane)) {
+ PLOG(ERROR) << "Cannot display plane on overlay: crtc=" << flip.crtc
+ << " plane=" << plane.plane;
+ ret = false;
+ flip.crtc->PageFlipFailed();
+ break;
+ }
+ }
+ if (!drm_->PageFlip(flip.crtc_id, flip.framebuffer, is_sync,
+ base::Bind(&CrtcController::OnPageFlipEvent,
+ flip.crtc->AsWeakPtr()))) {
+ if (errno != EACCES) {
+ PLOG(ERROR) << "Cannot page flip: crtc=" << flip.crtc_id
+ << " framebuffer=" << flip.framebuffer
+ << " is_sync=" << is_sync;
+ ret = false;
+ }
+ flip.crtc->PageFlipFailed();
+ }
+ }
+ // For each element in |old_plane_list|, if it hasn't been reclaimed (by
+ // this or any other HDPL), clear the overlay contents.
+ for (HardwareDisplayPlane* plane : plane_list->old_plane_list) {
+ if (!plane->in_use() && !plane->is_dummy()) {
+ // This plane is being released, so we need to zero it.
+ if (!drm_->PageFlipOverlay(plane->owning_crtc(), 0, gfx::Rect(),
+ gfx::Rect(), plane->plane_id())) {
+ PLOG(ERROR) << "Cannot free overlay: crtc=" << plane->owning_crtc()
+ << " plane=" << plane->plane_id();
+ ret = false;
+ break;
+ }
+ }
+ }
+ plane_list->plane_list.swap(plane_list->old_plane_list);
+ plane_list->plane_list.clear();
+ plane_list->legacy_page_flips.clear();
+ return ret;
+}
+
+bool HardwareDisplayPlaneManagerLegacy::SetPlaneData(
+ HardwareDisplayPlaneList* plane_list,
+ HardwareDisplayPlane* hw_plane,
+ const OverlayPlane& overlay,
+ uint32_t crtc_id,
+ const gfx::Rect& src_rect,
+ CrtcController* crtc) {
+ if (hw_plane->is_dummy() || plane_list->legacy_page_flips.empty() ||
+ plane_list->legacy_page_flips.back().crtc_id != crtc_id) {
+ plane_list->legacy_page_flips.push_back(
+ HardwareDisplayPlaneList::PageFlipInfo(
+ crtc_id, overlay.buffer->GetFramebufferId(), crtc));
+ } else {
+ plane_list->legacy_page_flips.back().planes.push_back(
+ HardwareDisplayPlaneList::PageFlipInfo::Plane(
+ hw_plane->plane_id(), overlay.buffer->GetFramebufferId(),
+ overlay.display_bounds, src_rect));
+ }
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h
new file mode 100644
index 0000000..6ab43dd
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h
@@ -0,0 +1,37 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_MANAGER_LEGACY_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_MANAGER_LEGACY_H_
+
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
+
+namespace ui {
+
+class OZONE_EXPORT HardwareDisplayPlaneManagerLegacy
+ : public HardwareDisplayPlaneManager {
+ public:
+ HardwareDisplayPlaneManagerLegacy();
+ ~HardwareDisplayPlaneManagerLegacy() override;
+
+ // HardwareDisplayPlaneManager:
+ bool Commit(HardwareDisplayPlaneList* plane_list,
+ bool is_sync,
+ bool test_only) override;
+
+ private:
+ bool SetPlaneData(HardwareDisplayPlaneList* plane_list,
+ HardwareDisplayPlane* hw_plane,
+ const OverlayPlane& overlay,
+ uint32_t crtc_id,
+ const gfx::Rect& src_rect,
+ CrtcController* crtc) override;
+
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneManagerLegacy);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_MANAGER_LEGACY_H_
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
new file mode 100644
index 0000000..f74497f
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
@@ -0,0 +1,258 @@
+// 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 <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h"
+#include "ui/ozone/platform/drm/gpu/overlay_plane.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
+#include "ui/ozone/platform/drm/test/mock_drm_device.h"
+
+namespace {
+
+struct FakePlaneInfo {
+ uint32_t id;
+ uint32_t allowed_crtc_mask;
+};
+
+const FakePlaneInfo kOnePlanePerCrtc[] = {{10, 1}, {20, 2}};
+const FakePlaneInfo kTwoPlanesPerCrtc[] = {{10, 1}, {11, 1}, {20, 2}, {21, 2}};
+const FakePlaneInfo kOnePlanePerCrtcWithShared[] = {{10, 1}, {20, 2}, {50, 3}};
+
+class FakeScanoutBuffer : public ui::ScanoutBuffer {
+ public:
+ FakeScanoutBuffer() {}
+
+ // ui::ScanoutBuffer:
+ uint32_t GetFramebufferId() const override { return 1; }
+ uint32_t GetHandle() const override { return 0; }
+ gfx::Size GetSize() const override { return gfx::Size(1, 1); }
+
+ protected:
+ ~FakeScanoutBuffer() override {}
+};
+
+class FakePlaneManager : public ui::HardwareDisplayPlaneManager {
+ public:
+ FakePlaneManager() : plane_count_(0) {}
+ ~FakePlaneManager() override {}
+
+ // Normally we'd use DRM to figure out the controller configuration. But we
+ // can't use DRM in unit tests, so we just create a fake configuration.
+ void InitForTest(const FakePlaneInfo* planes,
+ size_t count,
+ const std::vector<uint32_t>& crtcs) {
+ crtcs_ = crtcs;
+ for (size_t i = 0; i < count; i++) {
+ planes_.push_back(new ui::HardwareDisplayPlane(
+ planes[i].id, planes[i].allowed_crtc_mask));
+ }
+ // The real HDPM uses sorted planes, so sort them for consistency.
+ std::sort(planes_.begin(), planes_.end(),
+ [](ui::HardwareDisplayPlane* l, ui::HardwareDisplayPlane* r) {
+ return l->plane_id() < r->plane_id();
+ });
+ }
+
+ bool Commit(ui::HardwareDisplayPlaneList* plane_list,
+ bool is_sync,
+ bool test_only) override {
+ return false;
+ }
+
+ bool SetPlaneData(ui::HardwareDisplayPlaneList* plane_list,
+ ui::HardwareDisplayPlane* hw_plane,
+ const ui::OverlayPlane& overlay,
+ uint32_t crtc_id,
+ const gfx::Rect& src_rect,
+ ui::CrtcController* crtc) override {
+ // Check that the chosen plane is a legal choice for the crtc.
+ EXPECT_NE(-1, LookupCrtcIndex(crtc_id));
+ EXPECT_TRUE(hw_plane->CanUseForCrtc(LookupCrtcIndex(crtc_id)));
+ EXPECT_FALSE(hw_plane->in_use());
+ plane_count_++;
+ return true;
+ }
+
+ int plane_count() const { return plane_count_; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FakePlaneManager);
+
+ int plane_count_;
+};
+
+class HardwareDisplayPlaneManagerTest : public testing::Test {
+ public:
+ HardwareDisplayPlaneManagerTest() {}
+
+ void SetUp() override;
+
+ protected:
+ scoped_ptr<FakePlaneManager> plane_manager_;
+ ui::HardwareDisplayPlaneList state_;
+ std::vector<uint32_t> default_crtcs_;
+ scoped_refptr<ui::ScanoutBuffer> fake_buffer_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneManagerTest);
+};
+
+void HardwareDisplayPlaneManagerTest::SetUp() {
+ fake_buffer_ = new FakeScanoutBuffer();
+ plane_manager_.reset(new FakePlaneManager());
+ default_crtcs_.push_back(100);
+ default_crtcs_.push_back(200);
+}
+
+TEST_F(HardwareDisplayPlaneManagerTest, SinglePlaneAssignment) {
+ ui::OverlayPlaneList assigns;
+ assigns.push_back(ui::OverlayPlane(fake_buffer_));
+ plane_manager_->InitForTest(kOnePlanePerCrtc, arraysize(kOnePlanePerCrtc),
+ default_crtcs_);
+ EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns,
+ default_crtcs_[0], nullptr));
+ EXPECT_EQ(1, plane_manager_->plane_count());
+}
+
+TEST_F(HardwareDisplayPlaneManagerTest, BadCrtc) {
+ ui::OverlayPlaneList assigns;
+ assigns.push_back(ui::OverlayPlane(fake_buffer_));
+ plane_manager_->InitForTest(kOnePlanePerCrtc, arraysize(kOnePlanePerCrtc),
+ default_crtcs_);
+ EXPECT_FALSE(
+ plane_manager_->AssignOverlayPlanes(&state_, assigns, 1, nullptr));
+}
+
+TEST_F(HardwareDisplayPlaneManagerTest, MultiplePlaneAssignment) {
+ ui::OverlayPlaneList assigns;
+ assigns.push_back(ui::OverlayPlane(fake_buffer_));
+ assigns.push_back(ui::OverlayPlane(fake_buffer_));
+ plane_manager_->InitForTest(kTwoPlanesPerCrtc, arraysize(kTwoPlanesPerCrtc),
+ default_crtcs_);
+ EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns,
+ default_crtcs_[0], nullptr));
+ EXPECT_EQ(2, plane_manager_->plane_count());
+}
+
+TEST_F(HardwareDisplayPlaneManagerTest, NotEnoughPlanes) {
+ ui::OverlayPlaneList assigns;
+ assigns.push_back(ui::OverlayPlane(fake_buffer_));
+ assigns.push_back(ui::OverlayPlane(fake_buffer_));
+ plane_manager_->InitForTest(kOnePlanePerCrtc, arraysize(kOnePlanePerCrtc),
+ default_crtcs_);
+
+ EXPECT_FALSE(plane_manager_->AssignOverlayPlanes(&state_, assigns,
+ default_crtcs_[0], nullptr));
+}
+
+TEST_F(HardwareDisplayPlaneManagerTest, MultipleCrtcs) {
+ ui::OverlayPlaneList assigns;
+ assigns.push_back(ui::OverlayPlane(fake_buffer_));
+ plane_manager_->InitForTest(kOnePlanePerCrtc, arraysize(kOnePlanePerCrtc),
+ default_crtcs_);
+
+ EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns,
+ default_crtcs_[0], nullptr));
+ EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns,
+ default_crtcs_[1], nullptr));
+ EXPECT_EQ(2, plane_manager_->plane_count());
+}
+
+TEST_F(HardwareDisplayPlaneManagerTest, MultiplePlanesAndCrtcs) {
+ ui::OverlayPlaneList assigns;
+ assigns.push_back(ui::OverlayPlane(fake_buffer_));
+ assigns.push_back(ui::OverlayPlane(fake_buffer_));
+ plane_manager_->InitForTest(kTwoPlanesPerCrtc, arraysize(kTwoPlanesPerCrtc),
+ default_crtcs_);
+ EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns,
+ default_crtcs_[0], nullptr));
+ EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns,
+ default_crtcs_[1], nullptr));
+ EXPECT_EQ(4, plane_manager_->plane_count());
+}
+
+TEST_F(HardwareDisplayPlaneManagerTest, MultipleFrames) {
+ ui::OverlayPlaneList assigns;
+ assigns.push_back(ui::OverlayPlane(fake_buffer_));
+ plane_manager_->InitForTest(kTwoPlanesPerCrtc, arraysize(kTwoPlanesPerCrtc),
+ default_crtcs_);
+
+ EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns,
+ default_crtcs_[0], nullptr));
+ EXPECT_EQ(1, plane_manager_->plane_count());
+ // Pretend we committed the frame.
+ state_.plane_list.swap(state_.old_plane_list);
+ plane_manager_->BeginFrame(&state_);
+ ui::HardwareDisplayPlane* old_plane = state_.old_plane_list[0];
+ // The same plane should be used.
+ EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns,
+ default_crtcs_[0], nullptr));
+ EXPECT_EQ(2, plane_manager_->plane_count());
+ EXPECT_EQ(state_.plane_list[0], old_plane);
+}
+
+TEST_F(HardwareDisplayPlaneManagerTest, MultipleFramesDifferentPlanes) {
+ ui::OverlayPlaneList assigns;
+ assigns.push_back(ui::OverlayPlane(fake_buffer_));
+ plane_manager_->InitForTest(kTwoPlanesPerCrtc, arraysize(kTwoPlanesPerCrtc),
+ default_crtcs_);
+
+ EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns,
+ default_crtcs_[0], nullptr));
+ EXPECT_EQ(1, plane_manager_->plane_count());
+ // The other plane should be used.
+ EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns,
+ default_crtcs_[0], nullptr));
+ EXPECT_EQ(2, plane_manager_->plane_count());
+ EXPECT_NE(state_.plane_list[0], state_.plane_list[1]);
+}
+
+TEST_F(HardwareDisplayPlaneManagerTest, SharedPlanes) {
+ ui::OverlayPlaneList assigns;
+ assigns.push_back(ui::OverlayPlane(fake_buffer_));
+ assigns.push_back(ui::OverlayPlane(fake_buffer_));
+ plane_manager_->InitForTest(kOnePlanePerCrtcWithShared,
+ arraysize(kOnePlanePerCrtcWithShared),
+ default_crtcs_);
+
+ EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns,
+ default_crtcs_[1], nullptr));
+ EXPECT_EQ(2, plane_manager_->plane_count());
+ // The shared plane is now unavailable for use by the other CRTC.
+ EXPECT_FALSE(plane_manager_->AssignOverlayPlanes(&state_, assigns,
+ default_crtcs_[0], nullptr));
+}
+
+TEST(HardwareDisplayPlaneManagerLegacyTest, UnusedPlanesAreReleased) {
+ std::vector<uint32_t> crtcs;
+ crtcs.push_back(100);
+ scoped_refptr<ui::MockDrmDevice> drm = new ui::MockDrmDevice(false, crtcs, 2);
+ ui::OverlayPlaneList assigns;
+ scoped_refptr<FakeScanoutBuffer> fake_buffer = new FakeScanoutBuffer();
+ assigns.push_back(ui::OverlayPlane(fake_buffer));
+ assigns.push_back(ui::OverlayPlane(fake_buffer));
+ ui::HardwareDisplayPlaneList hdpl;
+ ui::CrtcController crtc(drm, crtcs[0], 0);
+ drm->plane_manager()->BeginFrame(&hdpl);
+ EXPECT_TRUE(drm->plane_manager()->AssignOverlayPlanes(&hdpl, assigns,
+ crtcs[0], &crtc));
+ EXPECT_TRUE(drm->plane_manager()->Commit(&hdpl, false, false));
+ assigns.clear();
+ assigns.push_back(ui::OverlayPlane(fake_buffer));
+ drm->plane_manager()->BeginFrame(&hdpl);
+ EXPECT_TRUE(drm->plane_manager()->AssignOverlayPlanes(&hdpl, assigns,
+ crtcs[0], &crtc));
+ EXPECT_EQ(0, drm->get_overlay_clear_call_count());
+ EXPECT_TRUE(drm->plane_manager()->Commit(&hdpl, false, false));
+ EXPECT_EQ(1, drm->get_overlay_clear_call_count());
+}
+
+} // namespace
diff --git a/ui/ozone/platform/drm/gpu/overlay_plane.cc b/ui/ozone/platform/drm/gpu/overlay_plane.cc
new file mode 100644
index 0000000..1312969
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/overlay_plane.cc
@@ -0,0 +1,44 @@
+// 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/drm/gpu/overlay_plane.h"
+
+#include "base/logging.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
+
+namespace ui {
+
+OverlayPlane::OverlayPlane(scoped_refptr<ScanoutBuffer> buffer)
+ : buffer(buffer),
+ display_bounds(gfx::Point(), buffer->GetSize()),
+ crop_rect(0, 0, 1, 1) {
+}
+
+OverlayPlane::OverlayPlane(scoped_refptr<ScanoutBuffer> buffer,
+ int z_order,
+ gfx::OverlayTransform plane_transform,
+ const gfx::Rect& display_bounds,
+ const gfx::RectF& crop_rect)
+ : buffer(buffer),
+ z_order(z_order),
+ plane_transform(plane_transform),
+ display_bounds(display_bounds),
+ crop_rect(crop_rect) {
+}
+
+OverlayPlane::~OverlayPlane() {
+}
+
+// static
+const OverlayPlane* OverlayPlane::GetPrimaryPlane(
+ const OverlayPlaneList& overlays) {
+ for (size_t i = 0; i < overlays.size(); ++i) {
+ if (overlays[i].z_order == 0)
+ return &overlays[i];
+ }
+
+ return nullptr;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/overlay_plane.h b/ui/ozone/platform/drm/gpu/overlay_plane.h
new file mode 100644
index 0000000..4be105e
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/overlay_plane.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_OVERLAY_PLANE_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_OVERLAY_PLANE_H_
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/overlay_transform.h"
+#include "ui/ozone/ozone_export.h"
+
+namespace ui {
+
+class ScanoutBuffer;
+
+struct OverlayPlane;
+typedef std::vector<OverlayPlane> OverlayPlaneList;
+
+struct OZONE_EXPORT OverlayPlane {
+ // Simpler constructor for the primary plane.
+ explicit OverlayPlane(scoped_refptr<ScanoutBuffer> buffer);
+
+ OverlayPlane(scoped_refptr<ScanoutBuffer> buffer,
+ int z_order,
+ gfx::OverlayTransform plane_transform,
+ const gfx::Rect& display_bounds,
+ const gfx::RectF& crop_rect);
+
+ ~OverlayPlane();
+
+ // Returns the primary plane in |overlays|.
+ static const OverlayPlane* GetPrimaryPlane(const OverlayPlaneList& overlays);
+
+ scoped_refptr<ScanoutBuffer> buffer;
+ int z_order = 0;
+ gfx::OverlayTransform plane_transform;
+ gfx::Rect display_bounds;
+ gfx::RectF crop_rect;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_OVERLAY_PLANE_H_
diff --git a/ui/ozone/platform/drm/gpu/page_flip_request.cc b/ui/ozone/platform/drm/gpu/page_flip_request.cc
new file mode 100644
index 0000000..5b69d75
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/page_flip_request.cc
@@ -0,0 +1,29 @@
+// 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/drm/gpu/page_flip_request.h"
+
+namespace ui {
+
+PageFlipRequest::PageFlipRequest(int crtc_count,
+ const SwapCompletionCallback& callback)
+ : callback_(callback), crtc_count_(crtc_count) {
+}
+
+PageFlipRequest::~PageFlipRequest() {
+}
+
+void PageFlipRequest::Signal(gfx::SwapResult result) {
+ if (result == gfx::SwapResult::SWAP_FAILED)
+ result_ = gfx::SwapResult::SWAP_FAILED;
+ else if (result != gfx::SwapResult::SWAP_ACK)
+ result_ = result;
+
+ if (!--crtc_count_) {
+ callback_.Run(result_);
+ callback_.Reset();
+ }
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/page_flip_request.h b/ui/ozone/platform/drm/gpu/page_flip_request.h
new file mode 100644
index 0000000..01cc30c
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/page_flip_request.h
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_PAGE_FLIP_REQUEST_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_PAGE_FLIP_REQUEST_H_
+
+#include "base/atomic_ref_count.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/swap_result.h"
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+namespace ui {
+
+class PageFlipRequest : public base::RefCounted<PageFlipRequest> {
+ public:
+ PageFlipRequest(int crtc_count, const SwapCompletionCallback& callback);
+
+ void Signal(gfx::SwapResult result);
+
+ private:
+ friend class base::RefCounted<PageFlipRequest>;
+ ~PageFlipRequest();
+
+ SwapCompletionCallback callback_;
+ int crtc_count_;
+ gfx::SwapResult result_ = gfx::SwapResult::SWAP_ACK;
+
+ DISALLOW_COPY_AND_ASSIGN(PageFlipRequest);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_PAGE_FLIP_REQUEST_H_
diff --git a/ui/ozone/platform/drm/gpu/scanout_buffer.h b/ui/ozone/platform/drm/gpu/scanout_buffer.h
new file mode 100644
index 0000000..ca512aa
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/scanout_buffer.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_SCANOUT_BUFFER_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_SCANOUT_BUFFER_H_
+
+#include <stdint.h>
+
+#include "base/memory/ref_counted.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace ui {
+
+class DrmDevice;
+
+// Abstraction for a DRM buffer that can be scanned-out of.
+class ScanoutBuffer : public base::RefCountedThreadSafe<ScanoutBuffer> {
+ public:
+ // ID allocated by the KMS API when the buffer is registered (via the handle).
+ virtual uint32_t GetFramebufferId() const = 0;
+
+ // Handle for the buffer. This is received when allocating the buffer.
+ virtual uint32_t GetHandle() const = 0;
+
+ // Size of the buffer.
+ virtual gfx::Size GetSize() const = 0;
+
+ protected:
+ virtual ~ScanoutBuffer() {}
+
+ friend class base::RefCountedThreadSafe<ScanoutBuffer>;
+};
+
+class ScanoutBufferGenerator {
+ public:
+ virtual ~ScanoutBufferGenerator() {}
+
+ virtual scoped_refptr<ScanoutBuffer> Create(
+ const scoped_refptr<DrmDevice>& drm,
+ const gfx::Size& size) = 0;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_SCANOUT_BUFFER_H_
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.cc b/ui/ozone/platform/drm/gpu/screen_manager.cc
new file mode 100644
index 0000000..4b4d3f1
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/screen_manager.cc
@@ -0,0 +1,348 @@
+// 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/drm/gpu/screen_manager.h"
+
+#include <xf86drmMode.h>
+
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/drm/common/drm_util.h"
+#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
+#include "ui/ozone/platform/drm/gpu/drm_console_buffer.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
+
+namespace ui {
+
+namespace {
+
+// Copies the contents of the saved framebuffer from the CRTCs in |controller|
+// to the new modeset buffer |buffer|.
+void FillModesetBuffer(const scoped_refptr<DrmDevice>& drm,
+ HardwareDisplayController* controller,
+ ScanoutBuffer* buffer) {
+ DrmConsoleBuffer modeset_buffer(drm, buffer->GetFramebufferId());
+ if (!modeset_buffer.Initialize()) {
+ VLOG(2) << "Failed to grab framebuffer " << buffer->GetFramebufferId();
+ return;
+ }
+
+ auto crtcs = controller->crtc_controllers();
+ DCHECK(!crtcs.empty());
+
+ ScopedDrmCrtcPtr saved_crtc(drm->GetCrtc(crtcs[0]->crtc()));
+ if (!saved_crtc || !saved_crtc->buffer_id) {
+ VLOG(2) << "Crtc has no saved state or wasn't modeset";
+ return;
+ }
+
+ // If the display controller is in mirror mode, the CRTCs should be sharing
+ // the same framebuffer.
+ DrmConsoleBuffer saved_buffer(drm, saved_crtc->buffer_id);
+ if (!saved_buffer.Initialize()) {
+ VLOG(2) << "Failed to grab saved framebuffer " << saved_crtc->buffer_id;
+ return;
+ }
+
+ // Don't copy anything if the sizes mismatch. This can happen when the user
+ // changes modes.
+ if (saved_buffer.canvas()->getBaseLayerSize() !=
+ modeset_buffer.canvas()->getBaseLayerSize()) {
+ VLOG(2) << "Previous buffer has a different size than modeset buffer";
+ return;
+ }
+
+ skia::RefPtr<SkImage> image = saved_buffer.image();
+ SkPaint paint;
+ // Copy the source buffer. Do not perform any blending.
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ modeset_buffer.canvas()->drawImage(image.get(), 0, 0, &paint);
+}
+
+} // namespace
+
+ScreenManager::ScreenManager(ScanoutBufferGenerator* buffer_generator)
+ : buffer_generator_(buffer_generator) {
+}
+
+ScreenManager::~ScreenManager() {
+ DCHECK(window_map_.empty());
+}
+
+void ScreenManager::AddDisplayController(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector) {
+ HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
+ // TODO(dnicoara): Turn this into a DCHECK when async display configuration is
+ // properly supported. (When there can't be a race between forcing initial
+ // display configuration in ScreenManager and NativeDisplayDelegate creating
+ // the display controllers.)
+ if (it != controllers_.end()) {
+ LOG(WARNING) << "Display controller (crtc=" << crtc << ") already present.";
+ return;
+ }
+
+ controllers_.push_back(new HardwareDisplayController(
+ scoped_ptr<CrtcController>(new CrtcController(drm, crtc, connector)),
+ gfx::Point()));
+}
+
+void ScreenManager::RemoveDisplayController(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc) {
+ HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
+ if (it != controllers_.end()) {
+ bool is_mirrored = (*it)->IsMirrored();
+ (*it)->RemoveCrtc(drm, crtc);
+ if (!is_mirrored) {
+ controllers_.erase(it);
+ UpdateControllerToWindowMapping();
+ }
+ }
+}
+
+bool ScreenManager::ConfigureDisplayController(
+ const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector,
+ const gfx::Point& origin,
+ const drmModeModeInfo& mode) {
+ bool status =
+ ActualConfigureDisplayController(drm, crtc, connector, origin, mode);
+ if (status)
+ UpdateControllerToWindowMapping();
+
+ return status;
+}
+
+bool ScreenManager::ActualConfigureDisplayController(
+ const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector,
+ const gfx::Point& origin,
+ const drmModeModeInfo& mode) {
+ gfx::Rect modeset_bounds(origin.x(), origin.y(), mode.hdisplay,
+ mode.vdisplay);
+ HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
+ DCHECK(controllers_.end() != it) << "Display controller (crtc=" << crtc
+ << ") doesn't exist.";
+
+ HardwareDisplayController* controller = *it;
+ // If nothing changed just enable the controller. Note, we perform an exact
+ // comparison on the mode since the refresh rate may have changed.
+ if (SameMode(mode, controller->get_mode()) &&
+ origin == controller->origin()) {
+ if (controller->IsDisabled()) {
+ HardwareDisplayControllers::iterator mirror =
+ FindActiveDisplayControllerByLocation(modeset_bounds);
+ // If there is an active controller at the same location then start mirror
+ // mode.
+ if (mirror != controllers_.end())
+ return HandleMirrorMode(it, mirror, drm, crtc, connector);
+ }
+
+ // Just re-enable the controller to re-use the current state.
+ return EnableController(controller, controller->origin(),
+ controller->get_mode());
+ }
+
+ // Either the mode or the location of the display changed, so exit mirror
+ // mode and configure the display independently. If the caller still wants
+ // mirror mode, subsequent calls configuring the other controllers will
+ // restore mirror mode.
+ if (controller->IsMirrored()) {
+ controller = new HardwareDisplayController(
+ controller->RemoveCrtc(drm, crtc), controller->origin());
+ controllers_.push_back(controller);
+ it = controllers_.end() - 1;
+ }
+
+ HardwareDisplayControllers::iterator mirror =
+ FindActiveDisplayControllerByLocation(modeset_bounds);
+ // Handle mirror mode.
+ if (mirror != controllers_.end() && it != mirror)
+ return HandleMirrorMode(it, mirror, drm, crtc, connector);
+
+ return EnableController(controller, origin, mode);
+}
+
+bool ScreenManager::DisableDisplayController(
+ const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc) {
+ HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
+ if (it != controllers_.end()) {
+ HardwareDisplayController* controller = *it;
+ if (controller->IsMirrored()) {
+ controller = new HardwareDisplayController(
+ controller->RemoveCrtc(drm, crtc), controller->origin());
+ controllers_.push_back(controller);
+ }
+
+ controller->Disable();
+ UpdateControllerToWindowMapping();
+ return true;
+ }
+
+ LOG(ERROR) << "Failed to find display controller crtc=" << crtc;
+ return false;
+}
+
+HardwareDisplayController* ScreenManager::GetDisplayController(
+ const gfx::Rect& bounds) {
+ HardwareDisplayControllers::iterator it =
+ FindActiveDisplayControllerByLocation(bounds);
+ if (it != controllers_.end())
+ return *it;
+
+ return nullptr;
+}
+
+void ScreenManager::AddWindow(gfx::AcceleratedWidget widget,
+ scoped_ptr<DrmWindow> window) {
+ std::pair<WidgetToWindowMap::iterator, bool> result =
+ window_map_.add(widget, window.Pass());
+ DCHECK(result.second) << "Window already added.";
+ UpdateControllerToWindowMapping();
+}
+
+scoped_ptr<DrmWindow> ScreenManager::RemoveWindow(
+ gfx::AcceleratedWidget widget) {
+ scoped_ptr<DrmWindow> window = window_map_.take_and_erase(widget);
+ DCHECK(window) << "Attempting to remove non-existing window for " << widget;
+ UpdateControllerToWindowMapping();
+ return window.Pass();
+}
+
+DrmWindow* ScreenManager::GetWindow(gfx::AcceleratedWidget widget) {
+ WidgetToWindowMap::iterator it = window_map_.find(widget);
+ if (it != window_map_.end())
+ return it->second;
+
+ NOTREACHED() << "Attempting to get non-existing window for " << widget;
+ return nullptr;
+}
+
+ScreenManager::HardwareDisplayControllers::iterator
+ScreenManager::FindDisplayController(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc) {
+ for (HardwareDisplayControllers::iterator it = controllers_.begin();
+ it != controllers_.end(); ++it) {
+ if ((*it)->HasCrtc(drm, crtc))
+ return it;
+ }
+
+ return controllers_.end();
+}
+
+ScreenManager::HardwareDisplayControllers::iterator
+ScreenManager::FindActiveDisplayControllerByLocation(const gfx::Rect& bounds) {
+ for (HardwareDisplayControllers::iterator it = controllers_.begin();
+ it != controllers_.end(); ++it) {
+ gfx::Rect controller_bounds((*it)->origin(), (*it)->GetModeSize());
+ if (controller_bounds == bounds && !(*it)->IsDisabled())
+ return it;
+ }
+
+ return controllers_.end();
+}
+
+bool ScreenManager::HandleMirrorMode(
+ HardwareDisplayControllers::iterator original,
+ HardwareDisplayControllers::iterator mirror,
+ const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector) {
+ (*mirror)->AddCrtc((*original)->RemoveCrtc(drm, crtc));
+ if (EnableController(*mirror, (*mirror)->origin(), (*mirror)->get_mode())) {
+ controllers_.erase(original);
+ return true;
+ }
+
+ LOG(ERROR) << "Failed to switch to mirror mode";
+
+ // When things go wrong revert back to the previous configuration since
+ // it is expected that the configuration would not have changed if
+ // things fail.
+ (*original)->AddCrtc((*mirror)->RemoveCrtc(drm, crtc));
+ EnableController(*original, (*original)->origin(), (*original)->get_mode());
+ return false;
+}
+
+void ScreenManager::UpdateControllerToWindowMapping() {
+ std::map<DrmWindow*, HardwareDisplayController*> window_to_controller_map;
+ // First create a unique mapping between a window and a controller. Note, a
+ // controller may be associated with at most 1 window.
+ for (HardwareDisplayController* controller : controllers_) {
+ if (controller->IsDisabled())
+ continue;
+
+ DrmWindow* window = FindWindowAt(
+ gfx::Rect(controller->origin(), controller->GetModeSize()));
+ if (!window)
+ continue;
+
+ window_to_controller_map[window] = controller;
+ }
+
+ // Apply the new mapping to all windows.
+ for (auto pair : window_map_) {
+ auto it = window_to_controller_map.find(pair.second);
+ if (it != window_to_controller_map.end())
+ pair.second->SetController(it->second);
+ else
+ pair.second->SetController(nullptr);
+ }
+}
+
+bool ScreenManager::EnableController(HardwareDisplayController* controller,
+ const gfx::Point& origin,
+ const drmModeModeInfo& mode) {
+ DCHECK(!controller->crtc_controllers().empty());
+ gfx::Rect rect(origin, gfx::Size(mode.hdisplay, mode.vdisplay));
+ controller->set_origin(origin);
+
+ DrmWindow* window = FindWindowAt(rect);
+ if (window) {
+ const OverlayPlane* primary = window->GetLastModesetBuffer();
+ if (primary) {
+ if (!controller->Modeset(*primary, mode)) {
+ LOG(ERROR) << "Failed to modeset controller";
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice();
+ scoped_refptr<ScanoutBuffer> buffer =
+ buffer_generator_->Create(drm, rect.size());
+ if (!buffer) {
+ LOG(ERROR) << "Failed to create scanout buffer";
+ return false;
+ }
+
+ FillModesetBuffer(drm, controller, buffer.get());
+ if (!controller->Modeset(OverlayPlane(buffer), mode)) {
+ LOG(ERROR) << "Failed to modeset controller";
+ return false;
+ }
+
+ return true;
+}
+
+DrmWindow* ScreenManager::FindWindowAt(const gfx::Rect& bounds) const {
+ for (auto pair : window_map_) {
+ if (pair.second->bounds() == bounds)
+ return pair.second;
+ }
+
+ return nullptr;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.h b/ui/ozone/platform/drm/gpu/screen_manager.h
new file mode 100644
index 0000000..f9c5bc0
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/screen_manager.h
@@ -0,0 +1,132 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_SCREEN_MANAGER_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_SCREEN_MANAGER_H_
+
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/observer_list.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+
+typedef struct _drmModeModeInfo drmModeModeInfo;
+
+namespace gfx {
+class Point;
+class Rect;
+class Size;
+} // namespace gfx
+
+namespace ui {
+
+class DrmDevice;
+class DrmWindow;
+class ScanoutBufferGenerator;
+
+// Responsible for keeping track of active displays and configuring them.
+class OZONE_EXPORT ScreenManager {
+ public:
+ ScreenManager(ScanoutBufferGenerator* surface_generator);
+ virtual ~ScreenManager();
+
+ // Register a display controller. This must be called before trying to
+ // configure it.
+ void AddDisplayController(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector);
+
+ // Remove a display controller from the list of active controllers. The
+ // controller is removed since it was disconnected.
+ void RemoveDisplayController(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc);
+
+ // Configure a display controller. The display controller is identified by
+ // (|crtc|, |connector|) and the controller is modeset using |mode|.
+ bool ConfigureDisplayController(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector,
+ const gfx::Point& origin,
+ const drmModeModeInfo& mode);
+
+ // Disable the display controller identified by |crtc|. Note, the controller
+ // may still be connected, so this does not remove the controller.
+ bool DisableDisplayController(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc);
+
+ // Returns a reference to the display controller configured to display within
+ // |bounds|. If the caller caches the controller it must also register as an
+ // observer to be notified when the controller goes out of scope.
+ HardwareDisplayController* GetDisplayController(const gfx::Rect& bounds);
+
+ // Adds a window for |widget|. Note: |widget| should not be associated with a
+ // window when calling this function.
+ void AddWindow(gfx::AcceleratedWidget widget, scoped_ptr<DrmWindow> window);
+
+ // Removes the window for |widget|. Note: |widget| must have a window
+ // associated with it when calling this function.
+ scoped_ptr<DrmWindow> RemoveWindow(gfx::AcceleratedWidget widget);
+
+ // Returns the window associated with |widget|. Note: This function should be
+ // called only if a valid window has been associated with |widget|.
+ DrmWindow* GetWindow(gfx::AcceleratedWidget widget);
+
+ // Updates the mapping between display controllers and windows such that a
+ // controller will be associated with at most one window.
+ void UpdateControllerToWindowMapping();
+
+ private:
+ typedef ScopedVector<HardwareDisplayController> HardwareDisplayControllers;
+
+ typedef base::ScopedPtrHashMap<gfx::AcceleratedWidget, scoped_ptr<DrmWindow>>
+ WidgetToWindowMap;
+
+ // Returns an iterator into |controllers_| for the controller identified by
+ // (|crtc|, |connector|).
+ HardwareDisplayControllers::iterator FindDisplayController(
+ const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc);
+
+ bool ActualConfigureDisplayController(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector,
+ const gfx::Point& origin,
+ const drmModeModeInfo& mode);
+
+ // Returns an iterator into |controllers_| for the controller located at
+ // |origin|.
+ HardwareDisplayControllers::iterator FindActiveDisplayControllerByLocation(
+ const gfx::Rect& bounds);
+
+ // Tries to set the controller identified by (|crtc|, |connector|) to mirror
+ // those in |mirror|. |original| is an iterator to the HDC where the
+ // controller is currently present.
+ bool HandleMirrorMode(HardwareDisplayControllers::iterator original,
+ HardwareDisplayControllers::iterator mirror,
+ const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector);
+
+ // Modeset the |controller| using |origin| and |mode|. If there is a window at
+ // the controller location, then we'll re-use the current buffer.
+ bool EnableController(HardwareDisplayController* controller,
+ const gfx::Point& origin,
+ const drmModeModeInfo& mode);
+
+ DrmWindow* FindWindowAt(const gfx::Rect& bounds) const;
+
+ ScanoutBufferGenerator* buffer_generator_; // Not owned.
+ // List of display controllers (active and disabled).
+ HardwareDisplayControllers controllers_;
+
+ WidgetToWindowMap window_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_SCREEN_MANAGER_H_
diff --git a/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc b/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
new file mode 100644
index 0000000..f8b59a6
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
@@ -0,0 +1,477 @@
+// 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 "testing/gtest/include/gtest/gtest.h"
+#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
+#include "ui/ozone/platform/drm/gpu/drm_buffer.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
+#include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+#include "ui/ozone/platform/drm/gpu/screen_manager.h"
+#include "ui/ozone/platform/drm/test/mock_drm_device.h"
+
+namespace {
+
+void EmptySwapCallback(gfx::SwapResult) {
+}
+
+// Create a basic mode for a 6x4 screen.
+const drmModeModeInfo kDefaultMode =
+ {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
+
+const uint32_t kPrimaryCrtc = 1;
+const uint32_t kPrimaryConnector = 2;
+const uint32_t kSecondaryCrtc = 3;
+const uint32_t kSecondaryConnector = 4;
+
+} // namespace
+
+class ScreenManagerTest : public testing::Test {
+ public:
+ ScreenManagerTest() {}
+ ~ScreenManagerTest() override {}
+
+ gfx::Rect GetPrimaryBounds() const {
+ return gfx::Rect(0, 0, kDefaultMode.hdisplay, kDefaultMode.vdisplay);
+ }
+
+ // Secondary is in extended mode, right-of primary.
+ gfx::Rect GetSecondaryBounds() const {
+ return gfx::Rect(kDefaultMode.hdisplay, 0, kDefaultMode.hdisplay,
+ kDefaultMode.vdisplay);
+ }
+
+ void SetUp() override {
+ drm_ = new ui::MockDrmDevice();
+ device_manager_.reset(new ui::DrmDeviceManager(nullptr));
+ buffer_generator_.reset(new ui::DrmBufferGenerator());
+ screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get()));
+ }
+ void TearDown() override {
+ screen_manager_.reset();
+ drm_ = nullptr;
+ }
+
+ protected:
+ scoped_refptr<ui::MockDrmDevice> drm_;
+ scoped_ptr<ui::DrmDeviceManager> device_manager_;
+ scoped_ptr<ui::DrmBufferGenerator> buffer_generator_;
+ scoped_ptr<ui::ScreenManager> screen_manager_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScreenManagerTest);
+};
+
+TEST_F(ScreenManagerTest, CheckWithNoControllers) {
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+}
+
+TEST_F(ScreenManagerTest, CheckWithValidController) {
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ ui::HardwareDisplayController* controller =
+ screen_manager_->GetDisplayController(GetPrimaryBounds());
+
+ EXPECT_TRUE(controller);
+ EXPECT_TRUE(controller->HasCrtc(drm_, kPrimaryCrtc));
+}
+
+TEST_F(ScreenManagerTest, CheckWithInvalidBounds) {
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+}
+
+TEST_F(ScreenManagerTest, CheckForSecondValidController) {
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(),
+ kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+}
+
+TEST_F(ScreenManagerTest, CheckControllerAfterItIsRemoved) {
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+
+ screen_manager_->RemoveDisplayController(drm_, kPrimaryCrtc);
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+}
+
+TEST_F(ScreenManagerTest, CheckDuplicateConfiguration) {
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ uint32_t framebuffer = drm_->current_framebuffer();
+
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ // Should not hold onto buffers.
+ EXPECT_NE(framebuffer, drm_->current_framebuffer());
+
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+}
+
+TEST_F(ScreenManagerTest, CheckChangingMode) {
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ drmModeModeInfo new_mode = kDefaultMode;
+ new_mode.vdisplay = 10;
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ new_mode);
+
+ gfx::Rect new_bounds(0, 0, new_mode.hdisplay, new_mode.vdisplay);
+ EXPECT_TRUE(screen_manager_->GetDisplayController(new_bounds));
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+ drmModeModeInfo mode =
+ screen_manager_->GetDisplayController(new_bounds)->get_mode();
+ EXPECT_EQ(new_mode.vdisplay, mode.vdisplay);
+ EXPECT_EQ(new_mode.hdisplay, mode.hdisplay);
+}
+
+TEST_F(ScreenManagerTest, CheckForControllersInMirroredMode) {
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+}
+
+TEST_F(ScreenManagerTest, CheckMirrorModeTransitions) {
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(),
+ kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetSecondaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+}
+
+TEST_F(ScreenManagerTest, MonitorGoneInMirrorMode) {
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ screen_manager_->RemoveDisplayController(drm_, kSecondaryCrtc);
+
+ ui::HardwareDisplayController* controller =
+ screen_manager_->GetDisplayController(GetPrimaryBounds());
+ EXPECT_TRUE(controller);
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+
+ EXPECT_TRUE(controller->HasCrtc(drm_, kPrimaryCrtc));
+ EXPECT_FALSE(controller->HasCrtc(drm_, kSecondaryCrtc));
+}
+
+TEST_F(ScreenManagerTest, MonitorDisabledInMirrorMode) {
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ screen_manager_->DisableDisplayController(drm_, kSecondaryCrtc);
+
+ ui::HardwareDisplayController* controller =
+ screen_manager_->GetDisplayController(GetPrimaryBounds());
+ EXPECT_TRUE(controller);
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+
+ EXPECT_TRUE(controller->HasCrtc(drm_, kPrimaryCrtc));
+ EXPECT_FALSE(controller->HasCrtc(drm_, kSecondaryCrtc));
+}
+
+TEST_F(ScreenManagerTest, DoNotEnterMirrorModeUnlessSameBounds) {
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+
+ // Configure displays in extended mode.
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(),
+ kDefaultMode);
+
+ drmModeModeInfo new_mode = kDefaultMode;
+ new_mode.vdisplay = 10;
+ // Shouldn't enter mirror mode unless the display bounds are the same.
+ screen_manager_->ConfigureDisplayController(
+ drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
+ new_mode);
+
+ EXPECT_FALSE(
+ screen_manager_->GetDisplayController(GetPrimaryBounds())->IsMirrored());
+}
+
+TEST_F(ScreenManagerTest, ReuseFramebufferIfDisabledThenReEnabled) {
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ uint32_t framebuffer = drm_->current_framebuffer();
+
+ screen_manager_->DisableDisplayController(drm_, kPrimaryCrtc);
+ EXPECT_EQ(0u, drm_->current_framebuffer());
+
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ // Buffers are released when disabled.
+ EXPECT_NE(framebuffer, drm_->current_framebuffer());
+}
+
+TEST_F(ScreenManagerTest, CheckMirrorModeAfterBeginReEnabled) {
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->DisableDisplayController(drm_, kPrimaryCrtc);
+
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ ui::HardwareDisplayController* controller =
+ screen_manager_->GetDisplayController(GetPrimaryBounds());
+ EXPECT_TRUE(controller);
+ EXPECT_FALSE(controller->IsMirrored());
+
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ EXPECT_TRUE(controller);
+ EXPECT_TRUE(controller->IsMirrored());
+}
+
+TEST_F(ScreenManagerTest,
+ CheckProperConfigurationWithDifferentDeviceAndSameCrtc) {
+ scoped_refptr<ui::MockDrmDevice> drm2 = new ui::MockDrmDevice();
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->AddDisplayController(drm2, kPrimaryCrtc, kPrimaryConnector);
+
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->ConfigureDisplayController(
+ drm2, kPrimaryCrtc, kPrimaryConnector, GetSecondaryBounds().origin(),
+ kDefaultMode);
+
+ ui::HardwareDisplayController* controller1 =
+ screen_manager_->GetDisplayController(GetPrimaryBounds());
+ ui::HardwareDisplayController* controller2 =
+ screen_manager_->GetDisplayController(GetSecondaryBounds());
+
+ EXPECT_NE(controller1, controller2);
+ EXPECT_EQ(drm_, controller1->crtc_controllers()[0]->drm());
+ EXPECT_EQ(drm2, controller2->crtc_controllers()[0]->drm());
+}
+
+TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithSameBounds) {
+ scoped_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->OnBoundsChanged(GetPrimaryBounds());
+ screen_manager_->AddWindow(1, window.Pass());
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetWindow(1)->GetController());
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
+TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithDifferentBounds) {
+ scoped_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ gfx::Rect new_bounds = GetPrimaryBounds();
+ new_bounds.Inset(0, 0, 1, 1);
+ window->OnBoundsChanged(new_bounds);
+ screen_manager_->AddWindow(1, window.Pass());
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ EXPECT_FALSE(screen_manager_->GetWindow(1)->GetController());
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
+TEST_F(ScreenManagerTest,
+ CheckControllerToWindowMappingWithOverlappingWindows) {
+ const size_t kWindowCount = 2;
+ for (size_t i = 1; i < kWindowCount + 1; ++i) {
+ scoped_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(i, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->OnBoundsChanged(GetPrimaryBounds());
+ screen_manager_->AddWindow(i, window.Pass());
+ }
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ bool window1_has_controller = screen_manager_->GetWindow(1)->GetController();
+ bool window2_has_controller = screen_manager_->GetWindow(2)->GetController();
+ // Only one of the windows can have a controller.
+ EXPECT_TRUE(window1_has_controller ^ window2_has_controller);
+
+ for (size_t i = 1; i < kWindowCount + 1; ++i) {
+ scoped_ptr<ui::DrmWindow> window = screen_manager_->RemoveWindow(i);
+ window->Shutdown();
+ }
+}
+
+TEST_F(ScreenManagerTest, ShouldDissociateWindowOnControllerRemoval) {
+ gfx::AcceleratedWidget window_id = 1;
+ scoped_ptr<ui::DrmWindow> window(new ui::DrmWindow(
+ window_id, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->OnBoundsChanged(GetPrimaryBounds());
+ screen_manager_->AddWindow(window_id, window.Pass());
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetWindow(window_id)->GetController());
+
+ screen_manager_->RemoveDisplayController(drm_, kPrimaryCrtc);
+
+ EXPECT_FALSE(screen_manager_->GetWindow(window_id)->GetController());
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
+TEST_F(ScreenManagerTest, EnableControllerWhenWindowHasNoBuffer) {
+ scoped_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->OnBoundsChanged(GetPrimaryBounds());
+ screen_manager_->AddWindow(1, window.Pass());
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetWindow(1)->GetController());
+ // There is a buffer after initial config.
+ uint32_t framebuffer = drm_->current_framebuffer();
+ EXPECT_NE(0U, framebuffer);
+
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ // There is a new buffer after we configured with the same mode but no
+ // pending frames on the window.
+ EXPECT_NE(framebuffer, drm_->current_framebuffer());
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
+TEST_F(ScreenManagerTest, EnableControllerWhenWindowHasBuffer) {
+ scoped_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->OnBoundsChanged(GetPrimaryBounds());
+ scoped_refptr<ui::ScanoutBuffer> buffer =
+ buffer_generator_->Create(drm_, GetPrimaryBounds().size());
+ window->QueueOverlayPlane(ui::OverlayPlane(buffer));
+ window->SchedulePageFlip(false /* is_sync */, base::Bind(&EmptySwapCallback));
+ screen_manager_->AddWindow(1, window.Pass());
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(
+ drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ EXPECT_EQ(buffer->GetFramebufferId(), drm_->current_framebuffer());
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
diff --git a/ui/ozone/platform/drm/host/channel_observer.h b/ui/ozone/platform/drm/host/channel_observer.h
new file mode 100644
index 0000000..ffbfa04
--- /dev/null
+++ b/ui/ozone/platform/drm/host/channel_observer.h
@@ -0,0 +1,21 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_HOST_CHANNEL_OBSERVER_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_CHANNEL_OBSERVER_H_
+
+namespace ui {
+
+// Observes the channel state.
+class ChannelObserver {
+ public:
+ virtual ~ChannelObserver() {}
+
+ virtual void OnChannelEstablished() = 0;
+ virtual void OnChannelDestroyed() = 0;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_HOST_CHANNEL_OBSERVER_H_
diff --git a/ui/ozone/platform/drm/host/drm_cursor.cc b/ui/ozone/platform/drm/host/drm_cursor.cc
new file mode 100644
index 0000000..f1c2021
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_cursor.cc
@@ -0,0 +1,76 @@
+// 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/drm/host/drm_cursor.h"
+
+#include "base/thread_task_runner_handle.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/ozone/platform/drm/host/drm_window_host.h"
+#include "ui/ozone/platform/drm/host/drm_window_host_manager.h"
+
+#if defined(OS_CHROMEOS)
+#include "ui/events/ozone/chromeos/cursor_controller.h"
+#endif
+
+namespace ui {
+
+DrmCursor::DrmCursor(DrmWindowHostManager* window_manager) {
+}
+
+DrmCursor::~DrmCursor() {
+}
+
+void DrmCursor::SetCursor(gfx::AcceleratedWidget window,
+ PlatformCursor platform_cursor) {
+ //TODO
+}
+
+void DrmCursor::OnWindowAdded(gfx::AcceleratedWidget window,
+ const gfx::Rect& bounds_in_screen,
+ const gfx::Rect& cursor_confined_bounds) {
+ //TODO
+}
+
+void DrmCursor::OnWindowRemoved(gfx::AcceleratedWidget window) {
+ //TODO
+}
+
+void DrmCursor::CommitBoundsChange(
+ gfx::AcceleratedWidget window,
+ const gfx::Rect& new_display_bounds_in_screen,
+ const gfx::Rect& new_confined_bounds) {
+ //TODO
+}
+
+void DrmCursor::MoveCursorTo(gfx::AcceleratedWidget window,
+ const gfx::PointF& location) {
+ //TODO
+}
+
+void DrmCursor::MoveCursorTo(const gfx::PointF& screen_location) {
+ //TODO
+}
+
+void DrmCursor::MoveCursor(const gfx::Vector2dF& delta) {
+ //TODO
+}
+
+bool DrmCursor::IsCursorVisible() {
+ //TODO
+ return false;
+}
+
+gfx::PointF DrmCursor::GetLocation() {
+ //TODO
+ return gfx::PointF();
+}
+
+gfx::Rect DrmCursor::GetCursorConfinedBounds() {
+ //TODO
+ return gfx::Rect();
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_cursor.h b/ui/ozone/platform/drm/host/drm_cursor.h
new file mode 100644
index 0000000..b747fcb
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_cursor.h
@@ -0,0 +1,64 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_HOST_DRM_CURSOR_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_DRM_CURSOR_H_
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
+#include "ui/platform_window/platform_window.h" // for PlatformCursor
+
+namespace gfx {
+class PointF;
+class Vector2dF;
+class Rect;
+}
+
+namespace ui {
+
+class BitmapCursorOzone;
+class BitmapCursorFactoryOzone;
+class DrmGpuPlatformSupportHost;
+class DrmWindowHostManager;
+
+class DrmCursor : public CursorDelegateEvdev {
+ public:
+ explicit DrmCursor(DrmWindowHostManager* window_manager);
+ ~DrmCursor() override;
+
+ // Change the cursor over the specifed window.
+ void SetCursor(gfx::AcceleratedWidget window, PlatformCursor platform_cursor);
+
+ // Handle window lifecycle.
+ void OnWindowAdded(gfx::AcceleratedWidget window,
+ const gfx::Rect& bounds_in_screen,
+ const gfx::Rect& cursor_confined_bounds);
+ void OnWindowRemoved(gfx::AcceleratedWidget window);
+
+ // Handle window bounds changes.
+ void CommitBoundsChange(gfx::AcceleratedWidget window,
+ const gfx::Rect& new_display_bounds_in_screen,
+ const gfx::Rect& new_confined_bounds);
+
+ // CursorDelegateEvdev:
+ void MoveCursorTo(gfx::AcceleratedWidget window,
+ const gfx::PointF& location) override;
+ void MoveCursorTo(const gfx::PointF& screen_location) override;
+ void MoveCursor(const gfx::Vector2dF& delta) override;
+ bool IsCursorVisible() override;
+ gfx::PointF GetLocation() override;
+ gfx::Rect GetCursorConfinedBounds() override;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_HOST_DRM_CURSOR_H_
diff --git a/ui/ozone/platform/drm/host/drm_device_handle.cc b/ui/ozone/platform/drm/host/drm_device_handle.cc
new file mode 100644
index 0000000..8d9fc0c
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_device_handle.cc
@@ -0,0 +1,71 @@
+// Copyright 2015 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/drm/host/drm_device_handle.h"
+
+#include <fcntl.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "base/files/file_path.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace ui {
+
+namespace {
+
+bool Authenticate(int fd) {
+ drm_magic_t magic;
+ memset(&magic, 0, sizeof(magic));
+ // We need to make sure the DRM device has enough privilege. Use the DRM
+ // authentication logic to figure out if the device has enough permissions.
+ return !drmGetMagic(fd, &magic) && !drmAuthMagic(fd, magic);
+}
+
+} // namespace
+
+DrmDeviceHandle::DrmDeviceHandle() {
+}
+
+DrmDeviceHandle::~DrmDeviceHandle() {
+ if (file_.is_valid())
+ base::ThreadRestrictions::AssertIOAllowed();
+}
+
+bool DrmDeviceHandle::Initialize(const base::FilePath& path) {
+ CHECK(path.DirName() == base::FilePath("/dev/dri"));
+ base::ThreadRestrictions::AssertIOAllowed();
+ bool print_warning = true;
+ while (true) {
+ file_.reset();
+ int fd = HANDLE_EINTR(open(path.value().c_str(), O_RDWR | O_CLOEXEC));
+ if (fd < 0) {
+ PLOG(ERROR) << "Failed to open " << path.value();
+ return false;
+ }
+
+ file_.reset(fd);
+
+ if (Authenticate(file_.get()))
+ break;
+
+ LOG_IF(WARNING, print_warning) << "Failed to authenticate " << path.value();
+ print_warning = false;
+ usleep(100000);
+ }
+
+ VLOG(1) << "Succeeded authenticating " << path.value();
+ return true;
+}
+
+bool DrmDeviceHandle::IsValid() const {
+ return file_.is_valid();
+}
+
+base::ScopedFD DrmDeviceHandle::PassFD() {
+ return file_.Pass();
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_device_handle.h b/ui/ozone/platform/drm/host/drm_device_handle.h
new file mode 100644
index 0000000..b360837
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_device_handle.h
@@ -0,0 +1,36 @@
+// Copyright 2015 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_HOST_DRM_DEVICE_HANDLE_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_DRM_DEVICE_HANDLE_H_
+
+#include "base/files/scoped_file.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace ui {
+
+class DrmDeviceHandle {
+ public:
+ DrmDeviceHandle();
+ ~DrmDeviceHandle();
+
+ int fd() const { return file_.get(); }
+
+ bool Initialize(const base::FilePath& path);
+
+ bool IsValid() const;
+ base::ScopedFD PassFD();
+
+ private:
+ base::ScopedFD file_;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmDeviceHandle);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_HOST_DRM_DEVICE_HANDLE_H_
diff --git a/ui/ozone/platform/drm/host/drm_display_host.cc b/ui/ozone/platform/drm/host/drm_display_host.cc
new file mode 100644
index 0000000..c09b070
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_display_host.cc
@@ -0,0 +1,130 @@
+// Copyright 2015 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/drm/host/drm_display_host.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/thread_task_runner_handle.h"
+#include "ui/ozone/common/display_snapshot_proxy.h"
+#include "ui/ozone/common/display_util.h"
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+#include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h"
+
+namespace ui {
+
+DrmDisplayHost::DrmDisplayHost(DrmGpuPlatformSupportHost* sender,
+ const DisplaySnapshot_Params& params,
+ bool is_dummy)
+ : sender_(sender),
+ snapshot_(new DisplaySnapshotProxy(params)),
+ is_dummy_(is_dummy) {
+ sender_->AddChannelObserver(this);
+}
+
+DrmDisplayHost::~DrmDisplayHost() {
+ sender_->RemoveChannelObserver(this);
+ ClearCallbacks();
+}
+
+void DrmDisplayHost::UpdateDisplaySnapshot(
+ const DisplaySnapshot_Params& params) {
+ snapshot_ = make_scoped_ptr(new DisplaySnapshotProxy(params));
+}
+
+void DrmDisplayHost::Configure(const DisplayMode* mode,
+ const gfx::Point& origin,
+ const ConfigureCallback& callback) {
+ if (is_dummy_) {
+ callback.Run(true);
+ return;
+ }
+
+ configure_callback_ = callback;
+ bool status = false;
+ if (mode) {
+ status = sender_->ConfigureNativeDisplay(
+ snapshot_->display_id(), GetDisplayModeParams(*mode), origin);
+ } else {
+ status = sender_->DisableNativeDisplay(snapshot_->display_id());
+ }
+
+ if (!status)
+ OnDisplayConfigured(false);
+}
+
+void DrmDisplayHost::OnDisplayConfigured(bool status) {
+ if (!configure_callback_.is_null()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(configure_callback_, status));
+ } else {
+ LOG(ERROR) << "Got unexpected event for display "
+ << snapshot_->display_id();
+ }
+
+ configure_callback_.Reset();
+}
+
+void DrmDisplayHost::GetHDCPState(const GetHDCPStateCallback& callback) {
+ get_hdcp_callback_ = callback;
+ if (!sender_->GetHDCPState(snapshot_->display_id()))
+ OnHDCPStateReceived(false, HDCP_STATE_UNDESIRED);
+}
+
+void DrmDisplayHost::OnHDCPStateReceived(bool status, HDCPState state) {
+ if (!get_hdcp_callback_.is_null()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(get_hdcp_callback_, status, state));
+ } else {
+ LOG(ERROR) << "Got unexpected event for display "
+ << snapshot_->display_id();
+ }
+
+ get_hdcp_callback_.Reset();
+}
+
+void DrmDisplayHost::SetHDCPState(HDCPState state,
+ const SetHDCPStateCallback& callback) {
+ set_hdcp_callback_ = callback;
+ if (!sender_->SetHDCPState(snapshot_->display_id(), state))
+ OnHDCPStateUpdated(false);
+}
+
+void DrmDisplayHost::OnHDCPStateUpdated(bool status) {
+ if (!set_hdcp_callback_.is_null()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(set_hdcp_callback_, status));
+ } else {
+ LOG(ERROR) << "Got unexpected event for display "
+ << snapshot_->display_id();
+ }
+
+ set_hdcp_callback_.Reset();
+}
+
+void DrmDisplayHost::SetGammaRamp(const std::vector<GammaRampRGBEntry>& lut) {
+ sender_->SetGammaRamp(snapshot_->display_id(), lut);
+}
+
+void DrmDisplayHost::OnChannelEstablished() {
+ is_dummy_ = false;
+
+ // Note: These responses are done here since the OnChannelDestroyed() is
+ // called after OnChannelEstablished().
+ ClearCallbacks();
+}
+
+void DrmDisplayHost::OnChannelDestroyed() {
+}
+
+void DrmDisplayHost::ClearCallbacks() {
+ if (!configure_callback_.is_null())
+ OnDisplayConfigured(false);
+ if (!get_hdcp_callback_.is_null())
+ OnHDCPStateReceived(false, HDCP_STATE_UNDESIRED);
+ if (!set_hdcp_callback_.is_null())
+ OnHDCPStateUpdated(false);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_display_host.h b/ui/ozone/platform/drm/host/drm_display_host.h
new file mode 100644
index 0000000..b6c09bf
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_display_host.h
@@ -0,0 +1,67 @@
+// Copyright 2015 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_HOST_DRM_DISPLAY_HOST_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_DRM_DISPLAY_HOST_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/display/types/display_constants.h"
+#include "ui/display/types/native_display_delegate.h"
+#include "ui/ozone/platform/drm/host/channel_observer.h"
+
+namespace ui {
+
+struct DisplaySnapshot_Params;
+class DisplaySnapshot;
+class DrmGpuPlatformSupportHost;
+
+class DrmDisplayHost : public ChannelObserver {
+ public:
+ DrmDisplayHost(DrmGpuPlatformSupportHost* sender,
+ const DisplaySnapshot_Params& params,
+ bool is_dummy);
+ ~DrmDisplayHost() override;
+
+ DisplaySnapshot* snapshot() const { return snapshot_.get(); }
+
+ void UpdateDisplaySnapshot(const DisplaySnapshot_Params& params);
+ void Configure(const DisplayMode* mode,
+ const gfx::Point& origin,
+ const ConfigureCallback& callback);
+ void GetHDCPState(const GetHDCPStateCallback& callback);
+ void SetHDCPState(HDCPState state, const SetHDCPStateCallback& callback);
+ void SetGammaRamp(const std::vector<GammaRampRGBEntry>& lut);
+
+ // Called when the IPC from the GPU process arrives to answer the above
+ // commands.
+ void OnDisplayConfigured(bool status);
+ void OnHDCPStateReceived(bool status, HDCPState state);
+ void OnHDCPStateUpdated(bool status);
+
+ // ChannelObserver:
+ void OnChannelEstablished() override;
+ void OnChannelDestroyed() override;
+
+ private:
+ // Calls all the callbacks with failure.
+ void ClearCallbacks();
+
+ DrmGpuPlatformSupportHost* sender_; // Not owned.
+
+ scoped_ptr<DisplaySnapshot> snapshot_;
+
+ // Used during startup to signify that any display configuration should be
+ // synchronous and succeed.
+ bool is_dummy_;
+
+ ConfigureCallback configure_callback_;
+ GetHDCPStateCallback get_hdcp_callback_;
+ SetHDCPStateCallback set_hdcp_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmDisplayHost);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_HOST_DRM_DISPLAY_HOST_H_
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
new file mode 100644
index 0000000..3fa038d
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -0,0 +1,461 @@
+// 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/drm/host/drm_display_host_manager.h"
+
+#include <fcntl.h>
+#include <xf86drm.h>
+
+#include "base/files/file_enumerator.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/worker_pool.h"
+#include "ui/display/types/display_snapshot.h"
+#include "ui/events/ozone/device/device_event.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/ozone/common/display_util.h"
+#include "ui/ozone/platform/drm/common/drm_util.h"
+#include "ui/ozone/platform/drm/host/drm_device_handle.h"
+#include "ui/ozone/platform/drm/host/drm_display_host.h"
+#include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h"
+#include "ui/ozone/platform/drm/host/drm_native_display_delegate.h"
+
+namespace ui {
+
+namespace {
+
+typedef base::Callback<void(const base::FilePath&, scoped_ptr<DrmDeviceHandle>)>
+ OnOpenDeviceReplyCallback;
+
+const char kDefaultGraphicsCardPattern[] = "/dev/dri/card%d";
+const char kVgemDevDriCardPath[] = "/dev/dri/";
+const char kVgemSysCardPath[] = "/sys/bus/platform/devices/vgem/drm/";
+
+const char* kDisplayActionString[] = {
+ "ADD",
+ "REMOVE",
+ "CHANGE",
+};
+
+void OpenDeviceOnWorkerThread(
+ const base::FilePath& path,
+ const scoped_refptr<base::TaskRunner>& reply_runner,
+ const OnOpenDeviceReplyCallback& callback) {
+ scoped_ptr<DrmDeviceHandle> handle(new DrmDeviceHandle());
+ handle->Initialize(path);
+ reply_runner->PostTask(
+ FROM_HERE, base::Bind(callback, path, base::Passed(handle.Pass())));
+}
+
+base::FilePath GetPrimaryDisplayCardPath() {
+ struct drm_mode_card_res res;
+ for (int i = 0; /* end on first card# that does not exist */; i++) {
+ std::string card_path = base::StringPrintf(kDefaultGraphicsCardPattern, i);
+
+ if (access(card_path.c_str(), F_OK) != 0) {
+ LOG(WARNING) << "Can't access card: " << card_path;
+ break;
+ }
+
+
+ int fd = open(card_path.c_str(), O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ VPLOG(1) << "Failed to open '" << card_path << "'";
+ continue;
+ }
+
+ memset(&res, 0, sizeof(struct drm_mode_card_res));
+ int ret = drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
+ close(fd);
+ if (ret == 0 && res.count_crtcs > 0) {
+ return base::FilePath(card_path);
+ }
+
+ VPLOG_IF(1, ret) << "Failed to get DRM resources for '" << card_path << "'";
+ }
+
+ return base::FilePath();
+}
+
+base::FilePath GetVgemCardPath() {
+ base::FileEnumerator file_iter(base::FilePath(kVgemSysCardPath), false,
+ base::FileEnumerator::DIRECTORIES,
+ FILE_PATH_LITERAL("card*"));
+
+ while (!file_iter.Next().empty()) {
+ // Inspect the card%d directories in the directory and extract the filename.
+ std::string vgem_card_path =
+ kVgemDevDriCardPath + file_iter.GetInfo().GetName().BaseName().value();
+ DVLOG(1) << "VGEM card path is " << vgem_card_path;
+ return base::FilePath(vgem_card_path);
+ }
+ DVLOG(1) << "Don't support VGEM";
+ return base::FilePath();
+}
+
+class FindDrmDisplayHostById {
+ public:
+ explicit FindDrmDisplayHostById(int64_t display_id)
+ : display_id_(display_id) {}
+
+ bool operator()(const DrmDisplayHost* display) const {
+ return display->snapshot()->display_id() == display_id_;
+ }
+
+ private:
+ int64_t display_id_;
+};
+
+} // namespace
+
+DrmDisplayHostManager::DrmDisplayHostManager(
+ DrmGpuPlatformSupportHost* proxy,
+ DeviceManager* device_manager,
+ InputControllerEvdev* input_controller)
+ : proxy_(proxy),
+ device_manager_(device_manager),
+ input_controller_(input_controller),
+ primary_graphics_card_path_(GetPrimaryDisplayCardPath()),
+ weak_ptr_factory_(this) {
+ {
+ // First device needs to be treated specially. We need to open this
+ // synchronously since the GPU process will need it to initialize the
+ // graphics state.
+ primary_drm_device_handle_.reset(new DrmDeviceHandle());
+ if (!primary_drm_device_handle_->Initialize(primary_graphics_card_path_)) {
+ LOG(FATAL) << "Failed to open primary graphics card";
+ return;
+ }
+ drm_devices_.insert(primary_graphics_card_path_);
+
+ vgem_card_path_ = GetVgemCardPath();
+ if (!vgem_card_path_.empty()) {
+ int fd = HANDLE_EINTR(
+ open(vgem_card_path_.value().c_str(), O_RDWR | O_CLOEXEC));
+ if (fd < 0) {
+ PLOG(ERROR) << "Failed to open vgem: " << vgem_card_path_.value();
+ }
+ vgem_card_device_file_.reset(fd);
+ }
+ }
+
+ device_manager_->AddObserver(this);
+
+ ScopedVector<HardwareDisplayControllerInfo> display_infos =
+ GetAvailableDisplayControllerInfos(primary_drm_device_handle_->fd());
+ has_dummy_display_ = !display_infos.empty();
+ for (size_t i = 0; i < display_infos.size(); ++i) {
+ displays_.push_back(new DrmDisplayHost(
+ proxy_, CreateDisplaySnapshotParams(display_infos[i],
+ primary_drm_device_handle_->fd(), i,
+ gfx::Point()),
+ true /* is_dummy */));
+ }
+}
+
+DrmDisplayHostManager::~DrmDisplayHostManager() {
+ device_manager_->RemoveObserver(this);
+}
+
+DrmDisplayHost* DrmDisplayHostManager::GetDisplay(int64_t display_id) {
+ auto it = std::find_if(displays_.begin(), displays_.end(),
+ FindDrmDisplayHostById(display_id));
+ if (it == displays_.end())
+ return nullptr;
+
+ return *it;
+}
+
+void DrmDisplayHostManager::AddDelegate(DrmNativeDisplayDelegate* delegate) {
+ DCHECK(!delegate_);
+ delegate_ = delegate;
+}
+
+void DrmDisplayHostManager::RemoveDelegate(DrmNativeDisplayDelegate* delegate) {
+ DCHECK_EQ(delegate_, delegate);
+ delegate_ = nullptr;
+}
+
+void DrmDisplayHostManager::TakeDisplayControl(
+ const DisplayControlCallback& callback) {
+ if (display_control_change_pending_) {
+ LOG(ERROR) << "TakeDisplayControl called while change already pending";
+ callback.Run(false);
+ return;
+ }
+
+ if (!display_externally_controlled_) {
+ LOG(ERROR) << "TakeDisplayControl called while display already owned";
+ callback.Run(true);
+ return;
+ }
+
+ take_display_control_callback_ = callback;
+ display_control_change_pending_ = true;
+
+ if (!proxy_->TakeDisplayControl())
+ OnTakeDisplayControl(false);
+}
+
+void DrmDisplayHostManager::RelinquishDisplayControl(
+ const DisplayControlCallback& callback) {
+ if (display_control_change_pending_) {
+ LOG(ERROR)
+ << "RelinquishDisplayControl called while change already pending";
+ callback.Run(false);
+ return;
+ }
+
+ if (display_externally_controlled_) {
+ LOG(ERROR) << "RelinquishDisplayControl called while display not owned";
+ callback.Run(true);
+ return;
+ }
+
+ relinquish_display_control_callback_ = callback;
+ display_control_change_pending_ = true;
+
+ if (!proxy_->RelinquishDisplayControl())
+ OnRelinquishDisplayControl(false);
+}
+
+void DrmDisplayHostManager::UpdateDisplays(
+ const GetDisplaysCallback& callback) {
+ get_displays_callback_ = callback;
+ if (!proxy_->RefreshNativeDisplays()) {
+ get_displays_callback_.Reset();
+ RunUpdateDisplaysCallback(callback);
+ }
+}
+
+void DrmDisplayHostManager::OnDeviceEvent(const DeviceEvent& event) {
+ if (event.device_type() != DeviceEvent::DISPLAY)
+ return;
+
+ event_queue_.push(DisplayEvent(event.action_type(), event.path()));
+ ProcessEvent();
+}
+
+void DrmDisplayHostManager::ProcessEvent() {
+ while (!event_queue_.empty() && !task_pending_) {
+ DisplayEvent event = event_queue_.front();
+ event_queue_.pop();
+ VLOG(1) << "Got display event " << kDisplayActionString[event.action_type]
+ << " for " << event.path.value();
+ switch (event.action_type) {
+ case DeviceEvent::ADD:
+ if (event.path == vgem_card_path_)
+ continue;
+ if (drm_devices_.find(event.path) == drm_devices_.end()) {
+ task_pending_ = base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&OpenDeviceOnWorkerThread, event.path,
+ base::ThreadTaskRunnerHandle::Get(),
+ base::Bind(&DrmDisplayHostManager::OnAddGraphicsDevice,
+ weak_ptr_factory_.GetWeakPtr())),
+ false /* task_is_slow */);
+ }
+ break;
+ case DeviceEvent::CHANGE:
+ task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&DrmDisplayHostManager::OnUpdateGraphicsDevice,
+ weak_ptr_factory_.GetWeakPtr()));
+ break;
+ case DeviceEvent::REMOVE:
+ DCHECK(event.path != primary_graphics_card_path_)
+ << "Removing primary graphics card";
+ DCHECK(event.path != vgem_card_path_) << "Removing VGEM device";
+ auto it = drm_devices_.find(event.path);
+ if (it != drm_devices_.end()) {
+ task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&DrmDisplayHostManager::OnRemoveGraphicsDevice,
+ weak_ptr_factory_.GetWeakPtr(), event.path));
+ drm_devices_.erase(it);
+ }
+ break;
+ }
+ }
+}
+
+void DrmDisplayHostManager::OnAddGraphicsDevice(
+ const base::FilePath& path,
+ scoped_ptr<DrmDeviceHandle> handle) {
+ if (handle->IsValid()) {
+ drm_devices_.insert(path);
+ proxy_->AddGraphicsDevice(path, base::FileDescriptor(handle->PassFD()));
+ NotifyDisplayDelegate();
+ }
+
+ task_pending_ = false;
+ ProcessEvent();
+}
+
+void DrmDisplayHostManager::OnUpdateGraphicsDevice() {
+ NotifyDisplayDelegate();
+ task_pending_ = false;
+ ProcessEvent();
+}
+
+void DrmDisplayHostManager::OnRemoveGraphicsDevice(const base::FilePath& path) {
+ proxy_->RemoveGraphicsDevice(path);
+ NotifyDisplayDelegate();
+ task_pending_ = false;
+ ProcessEvent();
+}
+
+void DrmDisplayHostManager::OnChannelEstablished(int host_id) {
+ // If in the middle of a configuration, just respond with the old list of
+ // displays. This is fine, since after the DRM resources are initialized and
+ // IPC-ed to the GPU NotifyDisplayDelegate() is called to let the display
+ // delegate know that the display configuration changed and it needs to
+ // update it again.
+ if (!get_displays_callback_.is_null()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&DrmDisplayHostManager::RunUpdateDisplaysCallback,
+ weak_ptr_factory_.GetWeakPtr(), get_displays_callback_));
+ get_displays_callback_.Reset();
+ }
+
+ // Signal that we're taking DRM master since we're going through the
+ // initialization process again and we'll take all the available resources.
+ if (!take_display_control_callback_.is_null())
+ OnTakeDisplayControl(true);
+
+ if (!relinquish_display_control_callback_.is_null())
+ OnRelinquishDisplayControl(false);
+
+ drm_devices_.clear();
+ drm_devices_.insert(primary_graphics_card_path_);
+ scoped_ptr<DrmDeviceHandle> handle = primary_drm_device_handle_.Pass();
+ if (!handle) {
+ handle.reset(new DrmDeviceHandle());
+ if (!handle->Initialize(primary_graphics_card_path_))
+ LOG(FATAL) << "Failed to open primary graphics card";
+ }
+
+ // Send the primary device first since this is used to initialize graphics
+ // state.
+ proxy_->AddGraphicsDevice(primary_graphics_card_path_,
+ base::FileDescriptor(handle->PassFD()));
+
+ device_manager_->ScanDevices(this);
+ NotifyDisplayDelegate();
+}
+
+void DrmDisplayHostManager::OnChannelDestroyed(int host_id) {
+ // Do nothing.
+}
+
+void DrmDisplayHostManager::OnUpdateNativeDisplays(
+ const std::vector<DisplaySnapshot_Params>& params) {
+ ScopedVector<DrmDisplayHost> old_displays(displays_.Pass());
+ for (size_t i = 0; i < params.size(); ++i) {
+ auto it = std::find_if(old_displays.begin(), old_displays.end(),
+ FindDrmDisplayHostById(params[i].display_id));
+ if (it == old_displays.end()) {
+ displays_.push_back(
+ new DrmDisplayHost(proxy_, params[i], false /* is_dummy */));
+ } else {
+ (*it)->UpdateDisplaySnapshot(params[i]);
+ displays_.push_back(*it);
+ old_displays.weak_erase(it);
+ }
+ }
+
+ if (!get_displays_callback_.is_null()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&DrmDisplayHostManager::RunUpdateDisplaysCallback,
+ weak_ptr_factory_.GetWeakPtr(), get_displays_callback_));
+ get_displays_callback_.Reset();
+ }
+}
+
+void DrmDisplayHostManager::OnDisplayConfigured(int64_t display_id,
+ bool status) {
+ DrmDisplayHost* display = GetDisplay(display_id);
+ if (display)
+ display->OnDisplayConfigured(status);
+ else
+ LOG(ERROR) << "Couldn't find display with id=" << display_id;
+}
+
+void DrmDisplayHostManager::OnHDCPStateReceived(int64_t display_id,
+ bool status,
+ HDCPState state) {
+ DrmDisplayHost* display = GetDisplay(display_id);
+ if (display)
+ display->OnHDCPStateReceived(status, state);
+ else
+ LOG(ERROR) << "Couldn't find display with id=" << display_id;
+}
+
+void DrmDisplayHostManager::OnHDCPStateUpdated(int64_t display_id,
+ bool status) {
+ DrmDisplayHost* display = GetDisplay(display_id);
+ if (display)
+ display->OnHDCPStateUpdated(status);
+ else
+ LOG(ERROR) << "Couldn't find display with id=" << display_id;
+}
+
+void DrmDisplayHostManager::OnTakeDisplayControl(bool status) {
+ if (take_display_control_callback_.is_null()) {
+ LOG(ERROR) << "No callback for take display control";
+ return;
+ }
+
+ DCHECK(display_externally_controlled_);
+ DCHECK(display_control_change_pending_);
+
+ if (status) {
+ input_controller_->SetInputDevicesEnabled(true);
+ display_externally_controlled_ = false;
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(take_display_control_callback_, status));
+ take_display_control_callback_.Reset();
+ display_control_change_pending_ = false;
+}
+
+void DrmDisplayHostManager::OnRelinquishDisplayControl(bool status) {
+ if (relinquish_display_control_callback_.is_null()) {
+ LOG(ERROR) << "No callback for relinquish display control";
+ return;
+ }
+
+ DCHECK(!display_externally_controlled_);
+ DCHECK(display_control_change_pending_);
+
+ if (status) {
+ input_controller_->SetInputDevicesEnabled(false);
+ display_externally_controlled_ = true;
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(relinquish_display_control_callback_, status));
+ relinquish_display_control_callback_.Reset();
+ display_control_change_pending_ = false;
+}
+
+void DrmDisplayHostManager::RunUpdateDisplaysCallback(
+ const GetDisplaysCallback& callback) const {
+ std::vector<DisplaySnapshot*> snapshots;
+ for (auto* display : displays_)
+ snapshots.push_back(display->snapshot());
+
+ callback.Run(snapshots);
+}
+
+void DrmDisplayHostManager::NotifyDisplayDelegate() const {
+ if (delegate_)
+ delegate_->OnConfigurationChanged();
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.h b/ui/ozone/platform/drm/host/drm_display_host_manager.h
new file mode 100644
index 0000000..bacba0b
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.h
@@ -0,0 +1,140 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_HOST_DRM_DISPLAY_HOST_MANAGER_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_DRM_DISPLAY_HOST_MANAGER_H_
+
+#include <queue>
+#include <set>
+
+#include "base/files/scoped_file.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/display/types/native_display_delegate.h"
+#include "ui/events/ozone/device/device_event.h"
+#include "ui/events/ozone/device/device_event_observer.h"
+#include "ui/events/ozone/evdev/event_factory_evdev.h"
+
+namespace ui {
+
+class DeviceManager;
+class DrmDeviceHandle;
+class DrmDisplayHost;
+class DrmGpuPlatformSupportHost;
+class DrmNativeDisplayDelegate;
+
+struct DisplaySnapshot_Params;
+
+class DrmDisplayHostManager : public DeviceEventObserver {
+ public:
+ // Note: IO is performed in this constructor.
+ DrmDisplayHostManager(DrmGpuPlatformSupportHost* proxy,
+ DeviceManager* device_manager,
+ InputControllerEvdev* input_controller);
+ ~DrmDisplayHostManager() override;
+
+ DrmDisplayHost* GetDisplay(int64_t display_id);
+
+ void AddDelegate(DrmNativeDisplayDelegate* delegate);
+ void RemoveDelegate(DrmNativeDisplayDelegate* delegate);
+
+ void TakeDisplayControl(const DisplayControlCallback& callback);
+ void RelinquishDisplayControl(const DisplayControlCallback& callback);
+ void UpdateDisplays(const GetDisplaysCallback& callback);
+
+ // DeviceEventObserver overrides:
+ void OnDeviceEvent(const DeviceEvent& event) override;
+
+ // Note: IO is performed in OnChannelEstablished.
+ void OnChannelEstablished(int host_id);
+ void OnChannelDestroyed(int host_id);
+
+ void OnUpdateNativeDisplays(
+ const std::vector<DisplaySnapshot_Params>& displays);
+ void OnDisplayConfigured(int64_t display_id, bool status);
+
+ // Called as a result of finishing to process the display hotplug event. These
+ // are responsible for dequing the event and scheduling the next event.
+ void OnAddGraphicsDevice(const base::FilePath& path,
+ scoped_ptr<DrmDeviceHandle> handle);
+ void OnUpdateGraphicsDevice();
+ void OnRemoveGraphicsDevice(const base::FilePath& path);
+
+ void OnHDCPStateReceived(int64_t display_id, bool status, HDCPState state);
+ void OnHDCPStateUpdated(int64_t display_id, bool status);
+
+ void OnTakeDisplayControl(bool status);
+ void OnRelinquishDisplayControl(bool status);
+
+ private:
+ struct DisplayEvent {
+ DisplayEvent(DeviceEvent::ActionType action_type,
+ const base::FilePath& path)
+ : action_type(action_type), path(path) {}
+
+ DeviceEvent::ActionType action_type;
+ base::FilePath path;
+ };
+
+
+ void ProcessEvent();
+
+ void RunUpdateDisplaysCallback(const GetDisplaysCallback& callback) const;
+
+ void NotifyDisplayDelegate() const;
+
+ DrmGpuPlatformSupportHost* proxy_; // Not owned.
+ DeviceManager* device_manager_; // Not owned.
+ InputControllerEvdev* input_controller_; // Not owned.
+
+ DrmNativeDisplayDelegate* delegate_ = nullptr; // Not owned.
+
+ // File path for the primary graphics card which is opened by default in the
+ // GPU process. We'll avoid opening this in hotplug events since it will race
+ // with the GPU process trying to open it and aquire DRM master.
+ base::FilePath primary_graphics_card_path_;
+
+ // File path for virtual gem (VGEM) device.
+ base::FilePath vgem_card_path_;
+
+ // Keeps track if there is a dummy display. This happens on initialization
+ // when there is no connection to the GPU to update the displays.
+ bool has_dummy_display_ = false;
+
+ ScopedVector<DrmDisplayHost> displays_;
+
+ GetDisplaysCallback get_displays_callback_;
+
+ bool display_externally_controlled_ = false;
+ bool display_control_change_pending_ = false;
+ DisplayControlCallback take_display_control_callback_;
+ DisplayControlCallback relinquish_display_control_callback_;
+
+ // Used to serialize display event processing. This is done since
+ // opening/closing DRM devices cannot be done on the UI thread and are handled
+ // on a worker thread. Thus, we need to queue events in order to process them
+ // in the correct order.
+ std::queue<DisplayEvent> event_queue_;
+
+ // True if a display event is currently being processed on a worker thread.
+ bool task_pending_ = false;
+
+ // Keeps track of all the active DRM devices.
+ std::set<base::FilePath> drm_devices_;
+
+ // This is used to cache the primary DRM device until the channel is
+ // established.
+ scoped_ptr<DrmDeviceHandle> primary_drm_device_handle_;
+
+ // Manages the VGEM device by itself and doesn't send it to GPU process.
+ base::ScopedFD vgem_card_device_file_;
+
+ base::WeakPtrFactory<DrmDisplayHostManager> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmDisplayHostManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_HOST_DRM_DISPLAY_HOST_MANAGER_H_
diff --git a/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
new file mode 100644
index 0000000..47f9f4f
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
@@ -0,0 +1,157 @@
+// 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/drm/host/drm_gpu_platform_support_host.h"
+
+#include "base/trace_event/trace_event.h"
+#include "ui/ozone/platform/drm/host/channel_observer.h"
+
+namespace ui {
+
+DrmGpuPlatformSupportHost::DrmGpuPlatformSupportHost(DrmCursor* cursor)
+ : display_manager_(nullptr),
+ window_manager_(nullptr),
+ cursor_(cursor),
+ delegate_(nullptr) {
+}
+
+DrmGpuPlatformSupportHost::~DrmGpuPlatformSupportHost() {
+}
+
+void DrmGpuPlatformSupportHost::SetDisplayManager(
+ DrmDisplayHostManager* display_manager) {
+ DCHECK(!display_manager_);
+ display_manager_ = display_manager;
+ if (IsConnected()) {
+ display_manager_->OnChannelEstablished(host_id_);
+ }
+}
+
+void DrmGpuPlatformSupportHost::SetWindowManager(
+ DrmWindowHostManager* window_manager) {
+ DCHECK(!window_manager_);
+ window_manager_ = window_manager;
+}
+
+void DrmGpuPlatformSupportHost::AddChannelObserver(ChannelObserver* observer) {
+ channel_observers_.AddObserver(observer);
+
+ if (IsConnected())
+ observer->OnChannelEstablished();
+}
+
+void DrmGpuPlatformSupportHost::RemoveChannelObserver(
+ ChannelObserver* observer) {
+ channel_observers_.RemoveObserver(observer);
+}
+
+bool DrmGpuPlatformSupportHost::IsConnected() {
+ return host_id_ >= 0;
+}
+
+void DrmGpuPlatformSupportHost::OnChannelEstablished(int host_id) {
+ TRACE_EVENT1("drm", "DrmGpuPlatformSupportHost::OnChannelEstablished",
+ "host_id", host_id);
+
+ host_id_ = host_id;
+
+ if (display_manager_) {
+ display_manager_->OnChannelEstablished(host_id_);
+ }
+
+ FOR_EACH_OBSERVER(ChannelObserver, channel_observers_,
+ OnChannelEstablished());
+}
+
+void DrmGpuPlatformSupportHost::OnChannelDestroyed(int host_id) {
+ TRACE_EVENT1("drm", "DrmGpuPlatformSupportHost::OnChannelDestroyed",
+ "host_id", host_id);
+
+ if (host_id_ == host_id) {
+ host_id_ = -1;
+ FOR_EACH_OBSERVER(ChannelObserver, channel_observers_,
+ OnChannelDestroyed());
+ }
+}
+
+void DrmGpuPlatformSupportHost::CreateWindow(
+ const gfx::AcceleratedWidget& widget) {
+ DCHECK(delegate_);
+ delegate_->CreateWindow(widget);
+}
+
+void DrmGpuPlatformSupportHost::DestroyWindow(
+ const gfx::AcceleratedWidget& widget) {
+ NOTIMPLEMENTED();
+}
+
+void DrmGpuPlatformSupportHost::WindowBoundsChanged(
+ const gfx::AcceleratedWidget& widget,
+ const gfx::Rect& bounds) {
+ DCHECK(delegate_);
+ delegate_->WindowBoundsChanged(widget, bounds);
+}
+
+void DrmGpuPlatformSupportHost::AddGraphicsDevice(
+ const base::FilePath& path,
+ const base::FileDescriptor& fd) {
+ DCHECK(delegate_);
+ delegate_->AddGraphicsDevice(path, fd);
+}
+
+void DrmGpuPlatformSupportHost::RemoveGraphicsDevice(
+ const base::FilePath& path) {
+ NOTIMPLEMENTED();
+}
+
+bool DrmGpuPlatformSupportHost::RefreshNativeDisplays() {
+ DCHECK(delegate_);
+ return delegate_->RefreshNativeDisplays();
+}
+
+bool DrmGpuPlatformSupportHost::ConfigureNativeDisplay(
+ int64_t id, const DisplayMode_Params& mode, const gfx::Point& originhost) {
+ DCHECK(delegate_);
+ return delegate_->ConfigureNativeDisplay(id, mode, originhost);
+}
+
+bool DrmGpuPlatformSupportHost::DisableNativeDisplay(int64_t id) {
+ NOTIMPLEMENTED();
+ return true;
+}
+
+void DrmGpuPlatformSupportHost::CheckOverlayCapabilities(
+ const gfx::AcceleratedWidget& widget,
+ const std::vector<OverlayCheck_Params>& list) {
+ NOTIMPLEMENTED();
+}
+
+bool DrmGpuPlatformSupportHost::GetHDCPState(int64_t id) {
+ NOTIMPLEMENTED();
+ return true;
+}
+
+bool DrmGpuPlatformSupportHost::SetHDCPState(int64_t id,
+ const HDCPState& state) {
+ NOTIMPLEMENTED();
+ return true;
+}
+
+bool DrmGpuPlatformSupportHost::TakeDisplayControl() {
+ NOTIMPLEMENTED();
+ return true;
+}
+
+bool DrmGpuPlatformSupportHost::RelinquishDisplayControl() {
+ NOTIMPLEMENTED();
+ return true;
+}
+
+bool DrmGpuPlatformSupportHost::SetGammaRamp(
+ int64_t id, const std::vector<GammaRampRGBEntry>& lut) {
+ NOTIMPLEMENTED();
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h
new file mode 100644
index 0000000..b9745bf
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h
@@ -0,0 +1,119 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_HOST_DRM_GPU_PLATFORM_SUPPORT_HOST_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_DRM_GPU_PLATFORM_SUPPORT_HOST_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/file_descriptor_posix.h"
+#include "base/observer_list.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+#include "ui/ozone/platform/drm/host/drm_display_host_manager.h"
+#include "ui/ozone/platform/drm/host/drm_window_host_manager.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
+
+class SkBitmap;
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+
+class ChannelObserver;
+class DrmCursor;
+
+class DrmGpuPlatformSupportHostDelegate {
+public:
+ DrmGpuPlatformSupportHostDelegate() {}
+ virtual ~DrmGpuPlatformSupportHostDelegate() {}
+
+ virtual void CreateWindow(const gfx::AcceleratedWidget& widget) = 0;
+ virtual void WindowBoundsChanged(const gfx::AcceleratedWidget& widget,
+ const gfx::Rect& bounds) = 0;
+ virtual void AddGraphicsDevice(const base::FilePath& path,
+ const base::FileDescriptor& fd) = 0;
+ virtual bool RefreshNativeDisplays() = 0;
+ virtual bool ConfigureNativeDisplay(int64_t id,
+ const DisplayMode_Params& mode,
+ const gfx::Point& originhost) = 0;
+};
+
+
+class DrmGpuPlatformSupportHost : public GpuPlatformSupportHost {
+ public:
+ DrmGpuPlatformSupportHost(DrmCursor* cursor);
+ ~DrmGpuPlatformSupportHost() override;
+
+ void SetDisplayManager(DrmDisplayHostManager* display_manager);
+ void SetWindowManager(DrmWindowHostManager* window_manager);
+
+ DrmDisplayHostManager* get_display_manager() {
+ return display_manager_;
+ }
+ DrmWindowHostManager* get_window_manager() {
+ return window_manager_;
+ }
+
+ void SetDelegate(DrmGpuPlatformSupportHostDelegate* delegate) {
+ DCHECK(!delegate_);
+ delegate_ = delegate;
+ }
+
+ DrmGpuPlatformSupportHostDelegate* get_delegate() {
+ return delegate_;
+ }
+
+ void AddChannelObserver(ChannelObserver* observer);
+ void RemoveChannelObserver(ChannelObserver* observer);
+
+ bool IsConnected();
+
+ // GpuPlatformSupportHost:
+ void OnChannelEstablished(int host_id) override;
+ void OnChannelDestroyed(int host_id) override;
+
+ // host to gpu interfaces
+ void CreateWindow(const gfx::AcceleratedWidget& widget);
+ void DestroyWindow(const gfx::AcceleratedWidget& widget);
+ void WindowBoundsChanged(const gfx::AcceleratedWidget& widget,
+ const gfx::Rect& bounds);
+ void AddGraphicsDevice(const base::FilePath& path,
+ const base::FileDescriptor& fd);
+ void RemoveGraphicsDevice(const base::FilePath& path);
+ bool RefreshNativeDisplays();
+ bool ConfigureNativeDisplay(int64_t id,
+ const DisplayMode_Params& mode,
+ const gfx::Point& originhost);
+ bool DisableNativeDisplay(int64_t id);
+
+ void CheckOverlayCapabilities(const gfx::AcceleratedWidget& widget,
+ const std::vector<OverlayCheck_Params>& list);
+
+ bool GetHDCPState(int64_t id);
+ bool SetHDCPState(int64_t id, const HDCPState& state);
+
+ bool TakeDisplayControl();
+ bool RelinquishDisplayControl();
+
+ bool SetGammaRamp(int64_t id, const std::vector<GammaRampRGBEntry>& lut);
+
+ private:
+ int host_id_ = -1;
+
+ DrmDisplayHostManager* display_manager_; // Not owned
+ DrmWindowHostManager* window_manager_; // Not owned
+ DrmCursor* cursor_; // Not owned.
+ base::ObserverList<ChannelObserver> channel_observers_;
+ DrmGpuPlatformSupportHostDelegate* delegate_;
+
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_GPU_DRM_GPU_PLATFORM_SUPPORT_HOST_H_
diff --git a/ui/ozone/platform/drm/host/drm_gpu_platform_support_host_inprocess.cc b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host_inprocess.cc
new file mode 100644
index 0000000..248427b
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host_inprocess.cc
@@ -0,0 +1,103 @@
+// 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/drm/host/drm_gpu_platform_support_host_inprocess.h"
+#include "ui/ozone/public/ozone_platform.h"
+
+namespace ui {
+
+DrmGpuPlatformSupportHostInprocess::DrmGpuPlatformSupportHostInprocess()
+ : platform_support_(static_cast<DrmGpuPlatformSupportHost*>(
+ ui::OzonePlatform::GetInstance()->GetGpuPlatformSupportHost())) {
+ platform_support_->SetDelegate(this);
+}
+
+DrmGpuPlatformSupportHostInprocess::~DrmGpuPlatformSupportHostInprocess() {
+}
+
+void DrmGpuPlatformSupportHostInprocess::OnChannelEstablished(
+ int host_id,
+ scoped_refptr<base::SingleThreadTaskRunner> send_runner,
+ const base::Callback<void(Message*)>& send_callback) {
+
+ send_runner_ = send_runner;
+ send_callback_ = send_callback;
+
+ platform_support_->OnChannelEstablished(host_id);
+}
+
+void DrmGpuPlatformSupportHostInprocess::OnChannelDestroyed(int host_id) {
+ send_runner_ = nullptr;
+ send_callback_.Reset();
+
+ platform_support_->OnChannelDestroyed(host_id);
+}
+
+bool DrmGpuPlatformSupportHostInprocess::OnMessageReceived(
+ const Message& message) {
+ DrmDisplayHostManager* display_manager =
+ platform_support_->get_display_manager();
+ DCHECK(display_manager);
+
+ bool handled = true;
+
+ switch (message.id) {
+ case OZONE_HOST_MSG__UPDATE_NATIVE_DISPLAYS: {
+ auto message_params = static_cast<
+ const OzoneHostMsg_UpdateNativeDisplays*>(&message);
+ display_manager->OnUpdateNativeDisplays(message_params->displays);
+ break;
+ }
+
+ case OZONE_HOST_MSG__DISPLAY_CONFIGURED: {
+ auto message_params = static_cast<
+ const OzoneHostMsg_DisplayConfigured*>(&message);
+ display_manager->OnDisplayConfigured(message_params->id,
+ message_params->result);
+ break;
+ }
+
+ default:
+ handled = false;
+ }
+ return handled;
+}
+
+bool DrmGpuPlatformSupportHostInprocess::Send(Message* message) {
+ if (platform_support_->IsConnected() &&
+ send_runner_->PostTask(FROM_HERE, base::Bind(send_callback_, message)))
+ return true;
+
+ delete message;
+ return false;
+}
+
+void DrmGpuPlatformSupportHostInprocess::CreateWindow(
+ const gfx::AcceleratedWidget& widget) {
+ Send(new OzoneGpuMsg_CreateWindow(widget));
+}
+
+void DrmGpuPlatformSupportHostInprocess::WindowBoundsChanged(
+ const gfx::AcceleratedWidget& widget, const gfx::Rect& bounds) {
+ Send(new OzoneGpuMsg_WindowBoundsChanged(widget, bounds));
+}
+
+void DrmGpuPlatformSupportHostInprocess::AddGraphicsDevice(
+ const base::FilePath& path,
+ const base::FileDescriptor& fd) {
+ Send(new OzoneGpuMsg_AddGraphicsDevice(path, fd));
+}
+
+bool DrmGpuPlatformSupportHostInprocess::RefreshNativeDisplays() {
+ return Send(new OzoneGpuMsg_RefreshNativeDisplays());
+}
+
+bool DrmGpuPlatformSupportHostInprocess::ConfigureNativeDisplay(
+ int64_t id,
+ const DisplayMode_Params& mode,
+ const gfx::Point& originhost) {
+ return Send(new OzoneGpuMsg_ConfigureNativeDisplay(id, mode, originhost));
+}
+
+} // namespace
diff --git a/ui/ozone/platform/drm/host/drm_gpu_platform_support_host_inprocess.h b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host_inprocess.h
new file mode 100644
index 0000000..e910ca6
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host_inprocess.h
@@ -0,0 +1,47 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_HOST_DRM_GPU_PLATFORM_SUPPORT_HOST_INPROCESS_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_DRM_GPU_PLATFORM_SUPPORT_HOST_INPROCESS_H_
+
+#include "base/single_thread_task_runner.h"
+#include "ui/ozone/platform/drm/common/inprocess_messages.h"
+#include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h"
+
+namespace ui {
+
+class DrmGpuPlatformSupportHostInprocess :
+ public DrmGpuPlatformSupportHostDelegate {
+ public:
+ DrmGpuPlatformSupportHostInprocess();
+ ~DrmGpuPlatformSupportHostInprocess() override;
+
+ void OnChannelEstablished(
+ int host_id,
+ scoped_refptr<base::SingleThreadTaskRunner> send_runner,
+ const base::Callback<void(Message*)>& send_callback);
+ void OnChannelDestroyed(int host_id);
+
+ bool OnMessageReceived(const Message& message);
+ bool Send(Message* message);
+
+ void CreateWindow(const gfx::AcceleratedWidget& widget) override;
+ void WindowBoundsChanged(const gfx::AcceleratedWidget& widget,
+ const gfx::Rect& bounds) override;
+ void AddGraphicsDevice(const base::FilePath& primary_graphics_card_path,
+ const base::FileDescriptor& fd) override;
+ bool RefreshNativeDisplays() override;
+ bool ConfigureNativeDisplay(int64_t id,
+ const DisplayMode_Params& mode,
+ const gfx::Point& originhost) override;
+
+ private:
+ DrmGpuPlatformSupportHost* platform_support_;
+ scoped_refptr<base::SingleThreadTaskRunner> send_runner_;
+ base::Callback<void(Message*)> send_callback_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_GPU_DRM_GPU_PLATFORM_SUPPORT_HOST_INPROCESS_H_
diff --git a/ui/ozone/platform/drm/host/drm_native_display_delegate.cc b/ui/ozone/platform/drm/host/drm_native_display_delegate.cc
new file mode 100644
index 0000000..0d6389b
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_native_display_delegate.cc
@@ -0,0 +1,121 @@
+// 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/drm/host/drm_native_display_delegate.h"
+
+#include "ui/display/types/display_snapshot.h"
+#include "ui/display/types/native_display_observer.h"
+#include "ui/ozone/platform/drm/host/drm_display_host.h"
+#include "ui/ozone/platform/drm/host/drm_display_host_manager.h"
+
+namespace ui {
+
+DrmNativeDisplayDelegate::DrmNativeDisplayDelegate(
+ DrmDisplayHostManager* display_manager)
+ : display_manager_(display_manager) {
+}
+
+DrmNativeDisplayDelegate::~DrmNativeDisplayDelegate() {
+ display_manager_->RemoveDelegate(this);
+}
+
+void DrmNativeDisplayDelegate::OnConfigurationChanged() {
+ FOR_EACH_OBSERVER(NativeDisplayObserver, observers_,
+ OnConfigurationChanged());
+}
+
+void DrmNativeDisplayDelegate::Initialize() {
+ display_manager_->AddDelegate(this);
+}
+
+void DrmNativeDisplayDelegate::GrabServer() {
+}
+
+void DrmNativeDisplayDelegate::UngrabServer() {
+}
+
+void DrmNativeDisplayDelegate::TakeDisplayControl(
+ const DisplayControlCallback& callback) {
+ display_manager_->TakeDisplayControl(callback);
+}
+
+void DrmNativeDisplayDelegate::RelinquishDisplayControl(
+ const DisplayControlCallback& callback) {
+ display_manager_->RelinquishDisplayControl(callback);
+}
+
+void DrmNativeDisplayDelegate::SyncWithServer() {
+}
+
+void DrmNativeDisplayDelegate::SetBackgroundColor(uint32_t color_argb) {
+}
+
+void DrmNativeDisplayDelegate::ForceDPMSOn() {
+}
+
+void DrmNativeDisplayDelegate::GetDisplays(
+ const GetDisplaysCallback& callback) {
+ display_manager_->UpdateDisplays(callback);
+}
+
+void DrmNativeDisplayDelegate::AddMode(const ui::DisplaySnapshot& output,
+ const ui::DisplayMode* mode) {
+}
+
+void DrmNativeDisplayDelegate::Configure(const ui::DisplaySnapshot& output,
+ const ui::DisplayMode* mode,
+ const gfx::Point& origin,
+ const ConfigureCallback& callback) {
+ DrmDisplayHost* display = display_manager_->GetDisplay(output.display_id());
+ display->Configure(mode, origin, callback);
+}
+
+void DrmNativeDisplayDelegate::CreateFrameBuffer(const gfx::Size& size) {
+}
+
+void DrmNativeDisplayDelegate::GetHDCPState(
+ const ui::DisplaySnapshot& output,
+ const GetHDCPStateCallback& callback) {
+ DrmDisplayHost* display = display_manager_->GetDisplay(output.display_id());
+ display->GetHDCPState(callback);
+}
+
+void DrmNativeDisplayDelegate::SetHDCPState(
+ const ui::DisplaySnapshot& output,
+ ui::HDCPState state,
+ const SetHDCPStateCallback& callback) {
+ DrmDisplayHost* display = display_manager_->GetDisplay(output.display_id());
+ display->SetHDCPState(state, callback);
+}
+
+std::vector<ui::ColorCalibrationProfile>
+DrmNativeDisplayDelegate::GetAvailableColorCalibrationProfiles(
+ const ui::DisplaySnapshot& output) {
+ return std::vector<ui::ColorCalibrationProfile>();
+}
+
+bool DrmNativeDisplayDelegate::SetColorCalibrationProfile(
+ const ui::DisplaySnapshot& output,
+ ui::ColorCalibrationProfile new_profile) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool DrmNativeDisplayDelegate::SetGammaRamp(
+ const ui::DisplaySnapshot& output,
+ const std::vector<GammaRampRGBEntry>& lut) {
+ DrmDisplayHost* display = display_manager_->GetDisplay(output.display_id());
+ display->SetGammaRamp(lut);
+ return true;
+}
+
+void DrmNativeDisplayDelegate::AddObserver(NativeDisplayObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void DrmNativeDisplayDelegate::RemoveObserver(NativeDisplayObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_native_display_delegate.h b/ui/ozone/platform/drm/host/drm_native_display_delegate.h
new file mode 100644
index 0000000..6b8e690
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_native_display_delegate.h
@@ -0,0 +1,67 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_HOST_DRM_NATIVE_DISPLAY_DELEGATE_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_DRM_NATIVE_DISPLAY_DELEGATE_H_
+
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "ui/display/types/native_display_delegate.h"
+
+namespace ui {
+
+class DrmDisplayHostManager;
+
+class DrmNativeDisplayDelegate : public NativeDisplayDelegate {
+ public:
+ DrmNativeDisplayDelegate(DrmDisplayHostManager* display_manager);
+ ~DrmNativeDisplayDelegate() override;
+
+ void OnConfigurationChanged();
+
+ // NativeDisplayDelegate overrides:
+ void Initialize() override;
+ void GrabServer() override;
+ void UngrabServer() override;
+ void TakeDisplayControl(const DisplayControlCallback& callback) override;
+ void RelinquishDisplayControl(
+ const DisplayControlCallback& callback) override;
+ void SyncWithServer() override;
+ void SetBackgroundColor(uint32_t color_argb) override;
+ void ForceDPMSOn() override;
+ void GetDisplays(const GetDisplaysCallback& callback) override;
+ void AddMode(const ui::DisplaySnapshot& output,
+ const ui::DisplayMode* mode) override;
+ void Configure(const ui::DisplaySnapshot& output,
+ const ui::DisplayMode* mode,
+ const gfx::Point& origin,
+ const ConfigureCallback& callback) override;
+ void CreateFrameBuffer(const gfx::Size& size) override;
+ void GetHDCPState(const ui::DisplaySnapshot& output,
+ const GetHDCPStateCallback& callback) override;
+ void SetHDCPState(const ui::DisplaySnapshot& output,
+ ui::HDCPState state,
+ const SetHDCPStateCallback& callback) override;
+ std::vector<ui::ColorCalibrationProfile> GetAvailableColorCalibrationProfiles(
+ const ui::DisplaySnapshot& output) override;
+ bool SetColorCalibrationProfile(
+ const ui::DisplaySnapshot& output,
+ ui::ColorCalibrationProfile new_profile) override;
+ bool SetGammaRamp(const ui::DisplaySnapshot& output,
+ const std::vector<GammaRampRGBEntry>& lut) override;
+
+ void AddObserver(NativeDisplayObserver* observer) override;
+ void RemoveObserver(NativeDisplayObserver* observer) override;
+
+ private:
+ DrmDisplayHostManager* display_manager_; // Not owned.
+
+ base::ObserverList<NativeDisplayObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmNativeDisplayDelegate);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_HOST_DRM_NATIVE_DISPLAY_DELEGATE_H_
diff --git a/ui/ozone/platform/drm/host/drm_overlay_candidates_host.cc b/ui/ozone/platform/drm/host/drm_overlay_candidates_host.cc
new file mode 100644
index 0000000..61fe49f
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_overlay_candidates_host.cc
@@ -0,0 +1,120 @@
+// Copyright 2015 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/drm/host/drm_overlay_candidates_host.h"
+
+#include <algorithm>
+
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+#include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h"
+
+namespace ui {
+
+namespace {
+const size_t kMaxCacheSize = 100;
+} // namespace
+
+bool DrmOverlayCandidatesHost::OverlayCompare::operator()(
+ const OverlayCheck_Params& l,
+ const OverlayCheck_Params& r) {
+ if (l.plane_z_order < r.plane_z_order)
+ return true;
+ if (l.plane_z_order > r.plane_z_order)
+ return false;
+ if (l.display_rect < r.display_rect)
+ return true;
+ if (l.display_rect != r.display_rect)
+ return false;
+ if (l.format < r.format)
+ return true;
+ if (l.format > r.format)
+ return false;
+ if (l.transform < r.transform)
+ return true;
+ if (l.transform > r.transform)
+ return false;
+ if (l.buffer_size.width() < r.buffer_size.width())
+ return true;
+ if (l.buffer_size.width() > r.buffer_size.width())
+ return false;
+ return l.buffer_size.height() < r.buffer_size.height();
+}
+
+DrmOverlayCandidatesHost::DrmOverlayCandidatesHost(
+ gfx::AcceleratedWidget widget,
+ DrmGpuPlatformSupportHost* platform_support)
+ : widget_(widget),
+ platform_support_(platform_support),
+ cache_(kMaxCacheSize) {
+}
+
+DrmOverlayCandidatesHost::~DrmOverlayCandidatesHost() {
+}
+
+void DrmOverlayCandidatesHost::CheckOverlaySupport(
+ OverlaySurfaceCandidateList* candidates) {
+ if (candidates->size() == 2)
+ CheckSingleOverlay(candidates);
+}
+
+void DrmOverlayCandidatesHost::CheckSingleOverlay(
+ OverlaySurfaceCandidateList* candidates) {
+ OverlayCandidatesOzone::OverlaySurfaceCandidate* first = &(*candidates)[0];
+ OverlayCandidatesOzone::OverlaySurfaceCandidate* second = &(*candidates)[1];
+ OverlayCandidatesOzone::OverlaySurfaceCandidate* overlay;
+ if (first->plane_z_order == 0) {
+ overlay = second;
+ } else if (second->plane_z_order == 0) {
+ overlay = first;
+ } else {
+ return;
+ }
+ // 0.01 constant chosen to match DCHECKs in gfx::ToNearestRect and avoid
+ // that code asserting on quads that we accept.
+ if (!gfx::IsNearestRectWithinDistance(overlay->display_rect, 0.01f))
+ return;
+ if (overlay->transform == gfx::OVERLAY_TRANSFORM_INVALID)
+ return;
+
+ OverlayCheck_Params lookup(*overlay);
+ auto iter = cache_.Get(lookup);
+ if (iter == cache_.end()) {
+ cache_.Put(lookup, false);
+ SendRequest(*candidates, lookup);
+ } else {
+ overlay->overlay_handled = iter->second;
+ }
+}
+
+void DrmOverlayCandidatesHost::SendRequest(
+ const OverlaySurfaceCandidateList& candidates,
+ const OverlayCheck_Params& check) {
+ if (!platform_support_->IsConnected())
+ return;
+ pending_checks_.push_back(check);
+ std::vector<OverlayCheck_Params> list;
+ for (const auto& candidate : candidates)
+ list.push_back(OverlayCheck_Params(candidate));
+ platform_support_->CheckOverlayCapabilities(widget_, list);
+}
+
+void DrmOverlayCandidatesHost::OnOverlayResult(bool* handled,
+ gfx::AcceleratedWidget widget,
+ bool result) {
+ if (widget != widget_)
+ return;
+ *handled = true;
+ DCHECK(!pending_checks_.empty());
+ ProcessResult(pending_checks_.front(), result);
+ pending_checks_.pop_front();
+}
+
+void DrmOverlayCandidatesHost::ProcessResult(const OverlayCheck_Params& check,
+ bool result) {
+ if (result)
+ cache_.Put(check, true);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_overlay_candidates_host.h b/ui/ozone/platform/drm/host/drm_overlay_candidates_host.h
new file mode 100644
index 0000000..f0e935f
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_overlay_candidates_host.h
@@ -0,0 +1,77 @@
+// Copyright 2015 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_HOST_OVERLAY_CANDIDATES_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_OVERLAY_CANDIDATES_H_
+
+#include <deque>
+#include <map>
+#include <vector>
+
+#include "base/containers/mru_cache.h"
+#include "base/single_thread_task_runner.h"
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
+#include "ui/ozone/public/overlay_candidates_ozone.h"
+
+namespace ui {
+
+class DrmGpuPlatformSupportHost;
+
+// This is an implementation of OverlayCandidatesOzone where the driver is asked
+// about overlay capabilities via IPC. We have no way of querying abstract
+// capabilities, only if a particular configuration is supported or not.
+// Each time we we are asked if a particular configuration is supported, if we
+// have not seen that configuration before, it is IPCed to the GPU via
+// OzoneGpuMsg_CheckOverlayCapabilities; a test commit is then performed and
+// the result is returned in OzoneHostMsg_OverlayCapabilitiesReceived. Testing
+// is asynchronous, until the reply arrives that configuration will be failed.
+//
+// There is a many:1 relationship between this class and
+// DrmGpuPlatformSupportHost, each compositor will own one of these objects.
+// Each request has a unique request ID, which is assigned from a shared
+// sequence number so that replies can be routed to the correct object.
+class DrmOverlayCandidatesHost : public OverlayCandidatesOzone {
+ struct OverlayCompare {
+ bool operator()(const OverlayCheck_Params& l, const OverlayCheck_Params& r);
+ };
+
+ public:
+ DrmOverlayCandidatesHost(gfx::AcceleratedWidget widget,
+ DrmGpuPlatformSupportHost* platform_support);
+ ~DrmOverlayCandidatesHost() override;
+
+ // OverlayCandidatesOzone:
+ void CheckOverlaySupport(OverlaySurfaceCandidateList* candidates) override;
+
+ private:
+ void SendRequest(const OverlaySurfaceCandidateList& candidates,
+ const OverlayCheck_Params& check);
+ void OnOverlayResult(bool* handled,
+ gfx::AcceleratedWidget widget,
+ bool result);
+ void ProcessResult(const OverlayCheck_Params& check, bool result);
+
+ void CheckSingleOverlay(OverlaySurfaceCandidateList* candidates);
+
+ gfx::AcceleratedWidget widget_;
+ DrmGpuPlatformSupportHost* platform_support_; // Not owned.
+
+ std::deque<OverlayCheck_Params> pending_checks_;
+
+ template <class KeyType, class ValueType>
+ struct OverlayMap {
+ typedef std::map<KeyType, ValueType, OverlayCompare> Type;
+ };
+ base::MRUCacheBase<OverlayCheck_Params,
+ bool,
+ base::MRUCacheNullDeletor<bool>,
+ OverlayMap> cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmOverlayCandidatesHost);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_HOST_OVERLAY_CANDIDATES_H_
diff --git a/ui/ozone/platform/drm/host/drm_overlay_manager.cc b/ui/ozone/platform/drm/host/drm_overlay_manager.cc
new file mode 100644
index 0000000..4f101cc
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_overlay_manager.cc
@@ -0,0 +1,39 @@
+// Copyright 2015 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/drm/host/drm_overlay_manager.h"
+
+#include "base/command_line.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/ozone/platform/drm/host/drm_overlay_candidates_host.h"
+#include "ui/ozone/public/overlay_candidates_ozone.h"
+#include "ui/ozone/public/ozone_switches.h"
+
+namespace ui {
+
+DrmOverlayManager::DrmOverlayManager(
+ bool allow_surfaceless,
+ DrmGpuPlatformSupportHost* platform_support_host)
+ : platform_support_host_(platform_support_host),
+ allow_surfaceless_(allow_surfaceless) {
+ is_supported_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kOzoneTestSingleOverlaySupport);
+}
+
+DrmOverlayManager::~DrmOverlayManager() {
+}
+
+scoped_ptr<OverlayCandidatesOzone> DrmOverlayManager::CreateOverlayCandidates(
+ gfx::AcceleratedWidget w) {
+ if (!is_supported_)
+ return nullptr;
+ return make_scoped_ptr(
+ new DrmOverlayCandidatesHost(w, platform_support_host_));
+}
+
+bool DrmOverlayManager::CanShowPrimaryPlaneAsOverlay() {
+ return allow_surfaceless_;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_overlay_manager.h b/ui/ozone/platform/drm/host/drm_overlay_manager.h
new file mode 100644
index 0000000..fcaf621
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_overlay_manager.h
@@ -0,0 +1,35 @@
+// Copyright 2015 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_HOST_DRM_OVERLAY_MANAGER_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_DRM_OVERLAY_MANAGER_H_
+
+#include "ui/ozone/public/overlay_manager_ozone.h"
+
+namespace ui {
+
+class DrmGpuPlatformSupportHost;
+
+class DrmOverlayManager : public OverlayManagerOzone {
+ public:
+ DrmOverlayManager(bool allow_surfaceless,
+ DrmGpuPlatformSupportHost* platform_support_host);
+ ~DrmOverlayManager() override;
+
+ // OverlayManagerOzone:
+ scoped_ptr<OverlayCandidatesOzone> CreateOverlayCandidates(
+ gfx::AcceleratedWidget w) override;
+ bool CanShowPrimaryPlaneAsOverlay() override;
+
+ private:
+ DrmGpuPlatformSupportHost* platform_support_host_;
+ bool allow_surfaceless_;
+ bool is_supported_;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmOverlayManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_HOST_DRM_OVERLAY_MANAGER_H_
diff --git a/ui/ozone/platform/drm/host/drm_window_host.cc b/ui/ozone/platform/drm/host/drm_window_host.cc
new file mode 100644
index 0000000..51c19ce
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_window_host.cc
@@ -0,0 +1,195 @@
+// 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/drm/host/drm_window_host.h"
+
+#include "base/bind.h"
+#include "ui/events/devices/device_data_manager.h"
+#include "ui/events/event.h"
+#include "ui/events/ozone/evdev/event_factory_evdev.h"
+#include "ui/events/ozone/events_ozone.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/gfx/display.h"
+#include "ui/ozone/platform/drm/host/drm_cursor.h"
+#include "ui/ozone/platform/drm/host/drm_display_host.h"
+#include "ui/ozone/platform/drm/host/drm_display_host_manager.h"
+#include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h"
+#include "ui/ozone/platform/drm/host/drm_window_host_manager.h"
+#include "ui/platform_window/platform_window_delegate.h"
+
+namespace ui {
+
+DrmWindowHost::DrmWindowHost(PlatformWindowDelegate* delegate,
+ const gfx::Rect& bounds,
+ DrmGpuPlatformSupportHost* sender,
+ EventFactoryEvdev* event_factory,
+ DrmCursor* cursor,
+ DrmWindowHostManager* window_manager,
+ DrmDisplayHostManager* display_manager)
+ : delegate_(delegate),
+ sender_(sender),
+ event_factory_(event_factory),
+ cursor_(cursor),
+ window_manager_(window_manager),
+ display_manager_(display_manager),
+ bounds_(bounds),
+ widget_(window_manager->NextAcceleratedWidget()) {
+ window_manager_->AddWindow(widget_, this);
+}
+
+DrmWindowHost::~DrmWindowHost() {
+ PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
+ window_manager_->RemoveWindow(widget_);
+ cursor_->OnWindowRemoved(widget_);
+
+ sender_->RemoveChannelObserver(this);
+ sender_->DestroyWindow(widget_);
+}
+
+void DrmWindowHost::Initialize() {
+ sender_->AddChannelObserver(this);
+ PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
+ cursor_->OnWindowAdded(widget_, bounds_, GetCursorConfinedBounds());
+ delegate_->OnAcceleratedWidgetAvailable(widget_);
+}
+
+gfx::AcceleratedWidget DrmWindowHost::GetAcceleratedWidget() {
+ return widget_;
+}
+
+gfx::Rect DrmWindowHost::GetCursorConfinedBounds() const {
+ return cursor_confined_bounds_.IsEmpty() ? gfx::Rect(bounds_.size())
+ : cursor_confined_bounds_;
+}
+
+void DrmWindowHost::Show() {
+}
+
+void DrmWindowHost::Hide() {
+}
+
+void DrmWindowHost::Close() {
+}
+
+void DrmWindowHost::SetBounds(const gfx::Rect& bounds) {
+ bounds_ = bounds;
+ delegate_->OnBoundsChanged(bounds);
+ SendBoundsChange();
+}
+
+gfx::Rect DrmWindowHost::GetBounds() {
+ return bounds_;
+}
+
+void DrmWindowHost::SetCapture() {
+ window_manager_->GrabEvents(widget_);
+}
+
+void DrmWindowHost::ReleaseCapture() {
+ window_manager_->UngrabEvents(widget_);
+}
+
+void DrmWindowHost::ToggleFullscreen() {
+}
+
+void DrmWindowHost::Maximize() {
+}
+
+void DrmWindowHost::Minimize() {
+}
+
+void DrmWindowHost::Restore() {
+}
+
+void DrmWindowHost::SetCursor(PlatformCursor cursor) {
+ cursor_->SetCursor(widget_, cursor);
+}
+
+void DrmWindowHost::MoveCursorTo(const gfx::Point& location) {
+ event_factory_->WarpCursorTo(widget_, location);
+}
+
+void DrmWindowHost::ConfineCursorToBounds(const gfx::Rect& bounds) {
+ if (cursor_confined_bounds_ == bounds)
+ return;
+
+ cursor_confined_bounds_ = bounds;
+ cursor_->CommitBoundsChange(widget_, bounds_, bounds);
+}
+
+bool DrmWindowHost::CanDispatchEvent(const PlatformEvent& ne) {
+ DCHECK(ne);
+ Event* event = static_cast<Event*>(ne);
+
+ // If there is a grab, capture events here.
+ gfx::AcceleratedWidget grabber = window_manager_->event_grabber();
+ if (grabber != gfx::kNullAcceleratedWidget)
+ return grabber == widget_;
+
+ if (event->IsTouchEvent()) {
+ // Dispatch the event if it is from the touchscreen associated with the
+ // DrmWindowHost. We cannot check the event's location because if the
+ // touchscreen has a bezel, touches in the bezel have a location outside of
+ // |bounds_|.
+ int64_t display_id =
+ DeviceDataManager::GetInstance()->GetTargetDisplayForTouchDevice(
+ event->source_device_id());
+
+ if (display_id == gfx::Display::kInvalidDisplayID)
+ return false;
+
+ DrmDisplayHost* display = display_manager_->GetDisplay(display_id);
+ if (!display)
+ return false;
+
+ DisplaySnapshot* snapshot = display->snapshot();
+ if (!snapshot->current_mode())
+ return false;
+
+ gfx::Rect display_bounds(snapshot->origin(),
+ snapshot->current_mode()->size());
+ return display_bounds == bounds_;
+ } else if (event->IsLocatedEvent()) {
+ LocatedEvent* located_event = static_cast<LocatedEvent*>(event);
+ return bounds_.Contains(gfx::ToFlooredPoint(located_event->location()));
+ }
+
+ // TODO(spang): For non-ash builds we would need smarter keyboard focus.
+ return true;
+}
+
+uint32_t DrmWindowHost::DispatchEvent(const PlatformEvent& native_event) {
+ DCHECK(native_event);
+
+ Event* event = static_cast<Event*>(native_event);
+ if (event->IsLocatedEvent()) {
+ // Make the event location relative to this window's origin.
+ LocatedEvent* located_event = static_cast<LocatedEvent*>(event);
+ gfx::PointF location = located_event->location();
+ location -= bounds_.OffsetFromOrigin();
+ located_event->set_location(location);
+ located_event->set_root_location(location);
+ }
+ DispatchEventFromNativeUiEvent(
+ native_event, base::Bind(&PlatformWindowDelegate::DispatchEvent,
+ base::Unretained(delegate_)));
+ return POST_DISPATCH_STOP_PROPAGATION;
+}
+
+void DrmWindowHost::OnChannelEstablished() {
+ sender_->CreateWindow(widget_);
+ SendBoundsChange();
+}
+
+void DrmWindowHost::OnChannelDestroyed() {
+}
+
+void DrmWindowHost::SendBoundsChange() {
+ // Update the cursor before the window so that the cursor stays within the
+ // window bounds when the window size shrinks.
+ cursor_->CommitBoundsChange(widget_, bounds_, GetCursorConfinedBounds());
+ sender_->WindowBoundsChanged(widget_, bounds_);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_window_host.h b/ui/ozone/platform/drm/host/drm_window_host.h
new file mode 100644
index 0000000..70f1393
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_window_host.h
@@ -0,0 +1,98 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_HOST_DRM_WINDOW_HOST_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_DRM_WINDOW_HOST_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/display/types/display_snapshot.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/drm/host/channel_observer.h"
+#include "ui/platform_window/platform_window.h"
+
+namespace ui {
+
+class DrmDisplayHostManager;
+class DrmCursor;
+class DrmGpuPlatformSupportHost;
+class DrmGpuWindow;
+class DrmWindowHostManager;
+class EventFactoryEvdev;
+
+// Implementation of the platform window. This object and its handle |widget_|
+// uniquely identify a window. Since the DRI/GBM platform is split into 2
+// pieces (Browser process and GPU process), internally we need to make sure the
+// state is synchronized between the 2 processes.
+//
+// |widget_| is used in both processes to uniquely identify the window. This
+// means that any state on the browser side needs to be propagated to the GPU.
+// State propagation needs to happen before the state change is acknowledged to
+// |delegate_| as |delegate_| is responsible for initializing the surface
+// associated with the window (the surface is created on the GPU process).
+class DrmWindowHost : public PlatformWindow,
+ public PlatformEventDispatcher,
+ public ChannelObserver {
+ public:
+ DrmWindowHost(PlatformWindowDelegate* delegate,
+ const gfx::Rect& bounds,
+ DrmGpuPlatformSupportHost* sender,
+ EventFactoryEvdev* event_factory,
+ DrmCursor* cursor,
+ DrmWindowHostManager* window_manager,
+ DrmDisplayHostManager* display_manager);
+ ~DrmWindowHost() override;
+
+ void Initialize();
+
+ gfx::AcceleratedWidget GetAcceleratedWidget();
+
+ gfx::Rect GetCursorConfinedBounds() const;
+
+ // PlatformWindow:
+ void Show() override;
+ void Hide() override;
+ void Close() override;
+ void SetBounds(const gfx::Rect& bounds) override;
+ gfx::Rect GetBounds() 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;
+
+ // ChannelObserver:
+ void OnChannelEstablished() override;
+ void OnChannelDestroyed() override;
+
+ private:
+ void SendBoundsChange();
+
+ PlatformWindowDelegate* delegate_; // Not owned.
+ DrmGpuPlatformSupportHost* sender_; // Not owned.
+ EventFactoryEvdev* event_factory_; // Not owned.
+ DrmCursor* cursor_; // Not owned.
+ DrmWindowHostManager* window_manager_; // Not owned.
+ DrmDisplayHostManager* display_manager_; // Not owned.
+
+ gfx::Rect bounds_;
+ gfx::AcceleratedWidget widget_;
+
+ gfx::Rect cursor_confined_bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmWindowHost);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_HOST_DRM_WINDOW_HOST_H_
diff --git a/ui/ozone/platform/drm/host/drm_window_host_manager.cc b/ui/ozone/platform/drm/host/drm_window_host_manager.cc
new file mode 100644
index 0000000..4aad916
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_window_host_manager.cc
@@ -0,0 +1,76 @@
+// 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/drm/host/drm_window_host_manager.h"
+
+#include "base/logging.h"
+#include "ui/ozone/platform/drm/host/drm_window_host.h"
+
+namespace ui {
+
+DrmWindowHostManager::DrmWindowHostManager() {
+}
+
+DrmWindowHostManager::~DrmWindowHostManager() {
+}
+
+gfx::AcceleratedWidget DrmWindowHostManager::NextAcceleratedWidget() {
+ // We're not using 0 since other code assumes that a 0 AcceleratedWidget is an
+ // invalid widget.
+ return ++last_allocated_widget_;
+}
+
+void DrmWindowHostManager::AddWindow(gfx::AcceleratedWidget widget,
+ DrmWindowHost* window) {
+ std::pair<WidgetToWindowMap::iterator, bool> result = window_map_.insert(
+ std::pair<gfx::AcceleratedWidget, DrmWindowHost*>(widget, window));
+ DCHECK(result.second) << "Window for " << widget << " already added.";
+}
+
+void DrmWindowHostManager::RemoveWindow(gfx::AcceleratedWidget widget) {
+ WidgetToWindowMap::iterator it = window_map_.find(widget);
+ if (it != window_map_.end())
+ window_map_.erase(it);
+ else
+ NOTREACHED() << "Attempting to remove non-existing window " << widget;
+
+ if (event_grabber_ == widget)
+ event_grabber_ = gfx::kNullAcceleratedWidget;
+}
+
+DrmWindowHost* DrmWindowHostManager::GetWindow(gfx::AcceleratedWidget widget) {
+ WidgetToWindowMap::iterator it = window_map_.find(widget);
+ if (it != window_map_.end())
+ return it->second;
+
+ NOTREACHED() << "Attempting to get non-existing window " << widget;
+ return NULL;
+}
+
+DrmWindowHost* DrmWindowHostManager::GetWindowAt(const gfx::Point& location) {
+ for (auto it = window_map_.begin(); it != window_map_.end(); ++it)
+ if (it->second->GetBounds().Contains(location))
+ return it->second;
+
+ return NULL;
+}
+
+DrmWindowHost* DrmWindowHostManager::GetPrimaryWindow() {
+ auto it = window_map_.begin();
+ return it != window_map_.end() ? it->second : nullptr;
+}
+
+void DrmWindowHostManager::GrabEvents(gfx::AcceleratedWidget widget) {
+ if (event_grabber_ != gfx::kNullAcceleratedWidget)
+ return;
+ event_grabber_ = widget;
+}
+
+void DrmWindowHostManager::UngrabEvents(gfx::AcceleratedWidget widget) {
+ if (event_grabber_ != widget)
+ return;
+ event_grabber_ = gfx::kNullAcceleratedWidget;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_window_host_manager.h b/ui/ozone/platform/drm/host/drm_window_host_manager.h
new file mode 100644
index 0000000..7e9a368
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_window_host_manager.h
@@ -0,0 +1,72 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_HOST_DRM_WINDOW_HOST_MANAGER_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_DRM_WINDOW_HOST_MANAGER_H_
+
+#include <map>
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+
+class DrmGpuPlatformSupportHost;
+class DrmWindowHost;
+
+// Responsible for keeping the mapping between the allocated widgets and
+// windows.
+class DrmWindowHostManager {
+ public:
+ DrmWindowHostManager();
+ ~DrmWindowHostManager();
+
+ gfx::AcceleratedWidget NextAcceleratedWidget();
+
+ // Adds a window for |widget|. Note: |widget| should not be associated when
+ // calling this function.
+ void AddWindow(gfx::AcceleratedWidget widget, DrmWindowHost* window);
+
+ // Removes the window association for |widget|. Note: |widget| must be
+ // associated with a window when calling this function.
+ void RemoveWindow(gfx::AcceleratedWidget widget);
+
+ // Returns the window associated with |widget|. Note: This function should
+ // only be called if a valid window has been associated.
+ DrmWindowHost* GetWindow(gfx::AcceleratedWidget widget);
+
+ // Returns the window containing the specified screen location, or NULL.
+ DrmWindowHost* GetWindowAt(const gfx::Point& location);
+
+ // Returns a window. Probably the first one created.
+ DrmWindowHost* GetPrimaryWindow();
+
+ // Tries to set a given widget as the recipient for events. It will
+ // fail if there is already another widget as recipient.
+ void GrabEvents(gfx::AcceleratedWidget widget);
+
+ // Unsets a given widget as the recipient for events.
+ void UngrabEvents(gfx::AcceleratedWidget widget);
+
+ // Gets the current widget recipient of mouse events.
+ gfx::AcceleratedWidget event_grabber() const { return event_grabber_; }
+
+ private:
+ typedef std::map<gfx::AcceleratedWidget, DrmWindowHost*> WidgetToWindowMap;
+
+ gfx::AcceleratedWidget last_allocated_widget_ = 0;
+ WidgetToWindowMap window_map_;
+
+ gfx::AcceleratedWidget event_grabber_ = gfx::kNullAcceleratedWidget;
+
+ DISALLOW_COPY_AND_ASSIGN(DrmWindowHostManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_HOST_DRM_WINDOW_HOST_MANAGER_H_
diff --git a/ui/ozone/platform/drm/ozone_platform_drm.cc b/ui/ozone/platform/drm/ozone_platform_drm.cc
new file mode 100644
index 0000000..0424644
--- /dev/null
+++ b/ui/ozone/platform/drm/ozone_platform_drm.cc
@@ -0,0 +1,166 @@
+// Copyright 2013 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/drm/ozone_platform_drm.h"
+
+#include "base/at_exit.h"
+#include "base/thread_task_runner_handle.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
+#include "ui/events/ozone/evdev/event_factory_evdev.h"
+#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
+#include "ui/ozone/platform/drm/common/drm_util.h"
+#include "ui/ozone/platform/drm/gpu/drm_buffer.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
+#include "ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h"
+#include "ui/ozone/platform/drm/gpu/drm_gpu_platform_support.h"
+#include "ui/ozone/platform/drm/gpu/drm_surface_factory.h"
+#include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/screen_manager.h"
+#include "ui/ozone/platform/drm/host/drm_cursor.h"
+#include "ui/ozone/platform/drm/host/drm_display_host_manager.h"
+#include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h"
+#include "ui/ozone/platform/drm/host/drm_native_display_delegate.h"
+#include "ui/ozone/platform/drm/host/drm_overlay_manager.h"
+#include "ui/ozone/platform/drm/host/drm_window_host.h"
+#include "ui/ozone/platform/drm/host/drm_window_host_manager.h"
+#include "ui/ozone/public/ozone_gpu_test_helper.h"
+#include "ui/ozone/public/ozone_platform.h"
+
+#if defined(USE_XKBCOMMON)
+#include "ui/events/ozone/layout/xkb/xkb_evdev_codes.h"
+#include "ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h"
+#else
+#include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
+#endif
+
+namespace ui {
+
+namespace {
+
+// OzonePlatform for Linux DRM (Direct Rendering Manager)
+//
+// This platform is Linux without any display server (no X, wayland, or
+// anything). This means chrome alone owns the display and input devices.
+class OzonePlatformDrm : public OzonePlatform {
+ public:
+ OzonePlatformDrm()
+ : buffer_generator_(new DrmBufferGenerator()),
+ screen_manager_(new ScreenManager(buffer_generator_.get())),
+ device_manager_(CreateDeviceManager()) {}
+ ~OzonePlatformDrm() override {}
+
+ // OzonePlatform:
+ ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override {
+ return surface_factory_ozone_.get();
+ }
+ OverlayManagerOzone* GetOverlayManager() override {
+ return overlay_manager_.get();
+ }
+ CursorFactoryOzone* GetCursorFactoryOzone() override {
+ NOTIMPLEMENTED();
+ return nullptr;
+ }
+ 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 event_factory_ozone_->CreateSystemInputInjector();
+ }
+ scoped_ptr<PlatformWindow> CreatePlatformWindow(
+ PlatformWindowDelegate* delegate,
+ const gfx::Rect& bounds) override {
+ scoped_ptr<DrmWindowHost> platform_window(
+ new DrmWindowHost(delegate, bounds, gpu_platform_support_host_.get(),
+ event_factory_ozone_.get(), cursor_.get(),
+ window_manager_.get(), display_manager_.get()));
+ platform_window->Initialize();
+ return platform_window.Pass();
+ }
+ scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate() override {
+ return make_scoped_ptr(
+ new DrmNativeDisplayDelegate(display_manager_.get()));
+ }
+ void InitializeUI() override {
+ drm_device_manager_.reset(new DrmDeviceManager(
+ scoped_ptr<DrmDeviceGenerator>(new DrmDeviceGenerator())));
+ window_manager_.reset(new DrmWindowHostManager());
+ cursor_.reset(new DrmCursor(window_manager_.get()));
+#if defined(USE_XKBCOMMON)
+ KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(make_scoped_ptr(
+ new XkbKeyboardLayoutEngine(xkb_evdev_code_converter_)));
+#else
+ KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
+ make_scoped_ptr(new StubKeyboardLayoutEngine()));
+#endif
+ event_factory_ozone_.reset(new EventFactoryEvdev(
+ cursor_.get(), device_manager_.get(),
+ KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()));
+ overlay_manager_.reset(new DrmOverlayManager(false, nullptr));
+ surface_factory_ozone_.reset(new DrmSurfaceFactory(screen_manager_.get()));
+ scoped_ptr<DrmGpuDisplayManager> display_manager(new DrmGpuDisplayManager(
+ screen_manager_.get(), drm_device_manager_.get()));
+ gpu_platform_support_.reset(new DrmGpuPlatformSupport(
+ drm_device_manager_.get(), screen_manager_.get(),
+ buffer_generator_.get(), display_manager.Pass()));
+ gpu_platform_support_host_.reset(
+ new DrmGpuPlatformSupportHost(cursor_.get()));
+ display_manager_.reset(new DrmDisplayHostManager(
+ gpu_platform_support_host_.get(), device_manager_.get(),
+ event_factory_ozone_->input_controller()));
+
+ if (!gpu_helper_.Initialize(base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get()))
+ LOG(FATAL) << "Failed to initialize dummy channel.";
+ }
+
+ void InitializeGPU() override {}
+
+ private:
+ // Objects in the "GPU" process.
+ scoped_ptr<DrmDeviceManager> drm_device_manager_;
+ scoped_ptr<DrmBufferGenerator> buffer_generator_;
+ scoped_ptr<ScreenManager> screen_manager_;
+ scoped_ptr<DrmGpuPlatformSupport> gpu_platform_support_;
+
+ // Objects in the "Browser" process.
+ scoped_ptr<OverlayManagerOzone> overlay_manager_;
+ scoped_ptr<DeviceManager> device_manager_;
+ scoped_ptr<DrmWindowHostManager> window_manager_;
+ scoped_ptr<DrmCursor> cursor_;
+ scoped_ptr<EventFactoryEvdev> event_factory_ozone_;
+ scoped_ptr<DrmGpuPlatformSupportHost> gpu_platform_support_host_;
+ scoped_ptr<DrmDisplayHostManager> display_manager_;
+
+#if defined(USE_XKBCOMMON)
+ XkbEvdevCodes xkb_evdev_code_converter_;
+#endif
+
+ // Objects on both processes.
+ scoped_ptr<DrmSurfaceFactory> surface_factory_ozone_;
+
+ OzoneGpuTestHelper gpu_helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(OzonePlatformDrm);
+};
+
+} // namespace
+
+OzonePlatform* CreateOzonePlatformDri() {
+ return new OzonePlatformDrm;
+}
+
+OzonePlatform* CreateOzonePlatformDrm() {
+ return new OzonePlatformDrm;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/ozone_platform_drm.h b/ui/ozone/platform/drm/ozone_platform_drm.h
new file mode 100644
index 0000000..5837870
--- /dev/null
+++ b/ui/ozone/platform/drm/ozone_platform_drm.h
@@ -0,0 +1,19 @@
+// Copyright 2013 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_DRM_H_
+#define UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_DRM_H_
+
+namespace ui {
+
+class OzonePlatform;
+
+// Constructor hook for use in ozone_platform_list.cc
+OzonePlatform* CreateOzonePlatformDri();
+
+OzonePlatform* CreateOzonePlatformDrm();
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_DRM_H_
diff --git a/ui/ozone/platform/drm/ozone_platform_gbm.cc b/ui/ozone/platform/drm/ozone_platform_gbm.cc
new file mode 100644
index 0000000..a59908a
--- /dev/null
+++ b/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -0,0 +1,236 @@
+// 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/drm/ozone_platform_gbm.h"
+
+#include <dlfcn.h>
+#include <gbm.h>
+#include <stdlib.h>
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/thread_task_runner_handle.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/events/ozone/evdev/event_factory_evdev.h"
+#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
+#include "ui/ozone/platform/drm/common/drm_util.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
+#include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
+#include "ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h"
+#include "ui/ozone/platform/drm/gpu/drm_gpu_platform_support.h"
+#include "ui/ozone/platform/drm/gpu/gbm_buffer.h"
+#include "ui/ozone/platform/drm/gpu/gbm_device.h"
+#include "ui/ozone/platform/drm/gpu/gbm_surface.h"
+#include "ui/ozone/platform/drm/gpu/gbm_surface_factory.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
+#include "ui/ozone/platform/drm/gpu/screen_manager.h"
+#include "ui/ozone/platform/drm/host/drm_cursor.h"
+#include "ui/ozone/platform/drm/host/drm_display_host_manager.h"
+#include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h"
+#include "ui/ozone/platform/drm/host/drm_native_display_delegate.h"
+#include "ui/ozone/platform/drm/host/drm_overlay_manager.h"
+#include "ui/ozone/platform/drm/host/drm_window_host.h"
+#include "ui/ozone/platform/drm/host/drm_window_host_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_gpu_test_helper.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/ozone_switches.h"
+
+#if defined(USE_XKBCOMMON)
+#include "ui/events/ozone/layout/xkb/xkb_evdev_codes.h"
+#include "ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h"
+#else
+#include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
+#endif
+
+namespace ui {
+
+namespace {
+
+class GlApiLoader {
+ public:
+ GlApiLoader()
+ : glapi_lib_(dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL)) {}
+
+ ~GlApiLoader() {
+ if (glapi_lib_)
+ dlclose(glapi_lib_);
+ }
+
+ private:
+ // HACK: gbm drivers have broken linkage. The Mesa DRI driver references
+ // symbols in the libglapi library however it does not explicitly link against
+ // it. That caused linkage errors when running an application that does not
+ // explicitly link against libglapi.
+ void* glapi_lib_;
+
+ DISALLOW_COPY_AND_ASSIGN(GlApiLoader);
+};
+
+class GbmBufferGenerator : public ScanoutBufferGenerator {
+ public:
+ GbmBufferGenerator() {}
+ ~GbmBufferGenerator() override {}
+
+ // ScanoutBufferGenerator:
+ scoped_refptr<ScanoutBuffer> Create(const scoped_refptr<DrmDevice>& drm,
+ const gfx::Size& size) override {
+ scoped_refptr<GbmDevice> gbm(static_cast<GbmDevice*>(drm.get()));
+ return GbmBuffer::CreateBuffer(gbm, SurfaceFactoryOzone::BGRA_8888, size,
+ true);
+ }
+
+ protected:
+ DISALLOW_COPY_AND_ASSIGN(GbmBufferGenerator);
+};
+
+class GbmDeviceGenerator : public DrmDeviceGenerator {
+ public:
+ GbmDeviceGenerator(bool use_atomic) : use_atomic_(use_atomic) {}
+ ~GbmDeviceGenerator() override {}
+
+ // DrmDeviceGenerator:
+ scoped_refptr<DrmDevice> CreateDevice(const base::FilePath& path,
+ base::File file) override {
+ scoped_refptr<DrmDevice> drm = new GbmDevice(path, file.Pass());
+ if (drm->Initialize(use_atomic_))
+ return drm;
+
+ return nullptr;
+ }
+
+ private:
+ bool use_atomic_;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmDeviceGenerator);
+};
+
+class OzonePlatformGbm : public OzonePlatform {
+ public:
+ OzonePlatformGbm(bool use_surfaceless) : use_surfaceless_(use_surfaceless) {}
+ ~OzonePlatformGbm() override {}
+
+ // OzonePlatform:
+ ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override {
+ return surface_factory_ozone_.get();
+ }
+ OverlayManagerOzone* GetOverlayManager() override {
+ return overlay_manager_.get();
+ }
+ CursorFactoryOzone* GetCursorFactoryOzone() override {
+ NOTIMPLEMENTED();
+ return nullptr;
+ }
+ 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 event_factory_ozone_->CreateSystemInputInjector();
+ }
+ scoped_ptr<PlatformWindow> CreatePlatformWindow(
+ PlatformWindowDelegate* delegate,
+ const gfx::Rect& bounds) override {
+ scoped_ptr<DrmWindowHost> platform_window(
+ new DrmWindowHost(delegate, bounds, gpu_platform_support_host_.get(),
+ event_factory_ozone_.get(), cursor_.get(),
+ window_manager_.get(), display_manager_.get()));
+ platform_window->Initialize();
+ return platform_window.Pass();
+ }
+ scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate() override {
+ return make_scoped_ptr(
+ new DrmNativeDisplayDelegate(display_manager_.get()));
+ }
+ void InitializeUI() override {
+ device_manager_ = CreateDeviceManager();
+ window_manager_.reset(new DrmWindowHostManager());
+ cursor_.reset(new DrmCursor(window_manager_.get()));
+#if defined(USE_XKBCOMMON)
+ KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(make_scoped_ptr(
+ new XkbKeyboardLayoutEngine(xkb_evdev_code_converter_)));
+#else
+ KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
+ make_scoped_ptr(new StubKeyboardLayoutEngine()));
+#endif
+ event_factory_ozone_.reset(new EventFactoryEvdev(
+ cursor_.get(), device_manager_.get(),
+ KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()));
+ gpu_platform_support_host_.reset(
+ new DrmGpuPlatformSupportHost(cursor_.get()));
+ display_manager_.reset(new DrmDisplayHostManager(
+ gpu_platform_support_host_.get(), device_manager_.get(),
+ event_factory_ozone_->input_controller()));
+ overlay_manager_.reset(new DrmOverlayManager(
+ use_surfaceless_, gpu_platform_support_host_.get()));
+
+ gpu_platform_support_host_->SetDisplayManager(display_manager_.get());
+ gpu_platform_support_host_->SetWindowManager(window_manager_.get());
+ }
+
+ void InitializeGPU() override {
+ bool use_atomic = false;
+ gl_api_loader_.reset(new GlApiLoader());
+ drm_device_manager_.reset(new DrmDeviceManager(
+ scoped_ptr<DrmDeviceGenerator>(new GbmDeviceGenerator(use_atomic))));
+ buffer_generator_.reset(new GbmBufferGenerator());
+ screen_manager_.reset(new ScreenManager(buffer_generator_.get()));
+ surface_factory_ozone_.reset(new GbmSurfaceFactory(use_surfaceless_));
+ surface_factory_ozone_->InitializeGpu(drm_device_manager_.get(),
+ screen_manager_.get());
+ scoped_ptr<DrmGpuDisplayManager> display_manager(new DrmGpuDisplayManager(
+ screen_manager_.get(), drm_device_manager_.get()));
+ gpu_platform_support_.reset(new DrmGpuPlatformSupport(
+ drm_device_manager_.get(), screen_manager_.get(),
+ buffer_generator_.get(), display_manager.Pass()));
+ }
+
+ private:
+ // Objects in both processes.
+ bool use_surfaceless_;
+
+ // Objects in the GPU process.
+ scoped_ptr<GbmSurfaceFactory> surface_factory_ozone_;
+ scoped_ptr<GlApiLoader> gl_api_loader_;
+ scoped_ptr<DrmDeviceManager> drm_device_manager_;
+ scoped_ptr<GbmBufferGenerator> buffer_generator_;
+ scoped_ptr<ScreenManager> screen_manager_;
+ scoped_ptr<DrmGpuPlatformSupport> gpu_platform_support_;
+
+ // Objects in the Browser process.
+ scoped_ptr<DeviceManager> device_manager_;
+ scoped_ptr<DrmWindowHostManager> window_manager_;
+ scoped_ptr<DrmCursor> cursor_;
+ scoped_ptr<EventFactoryEvdev> event_factory_ozone_;
+ scoped_ptr<DrmGpuPlatformSupportHost> gpu_platform_support_host_;
+ scoped_ptr<DrmDisplayHostManager> display_manager_;
+ scoped_ptr<DrmOverlayManager> overlay_manager_;
+
+#if defined(USE_XKBCOMMON)
+ XkbEvdevCodes xkb_evdev_code_converter_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(OzonePlatformGbm);
+};
+
+} // namespace
+
+OzonePlatform* CreateOzonePlatformGbm() {
+ base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
+#if defined(USE_MESA_PLATFORM_NULL)
+ // Only works with surfaceless.
+ cmd->AppendSwitch(switches::kOzoneUseSurfaceless);
+#endif
+ return new OzonePlatformGbm(cmd->HasSwitch(switches::kOzoneUseSurfaceless));
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/ozone_platform_gbm.h b/ui/ozone/platform/drm/ozone_platform_gbm.h
new file mode 100644
index 0000000..324535d
--- /dev/null
+++ b/ui/ozone/platform/drm/ozone_platform_gbm.h
@@ -0,0 +1,17 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_GBM_H_
+#define UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_GBM_H_
+
+namespace ui {
+
+class OzonePlatform;
+
+// Constructor hook for use in ozone_platform_list.cc
+OzonePlatform* CreateOzonePlatformGbm();
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_GBM_H_
diff --git a/ui/ozone/platform/drm/test/mock_drm_device.cc b/ui/ozone/platform/drm/test/mock_drm_device.cc
new file mode 100644
index 0000000..8999297
--- /dev/null
+++ b/ui/ozone/platform/drm/test/mock_drm_device.cc
@@ -0,0 +1,262 @@
+// 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/drm/test/mock_drm_device.h"
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "base/logging.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h"
+
+namespace ui {
+
+namespace {
+
+template <class Object>
+Object* DrmAllocator() {
+ return static_cast<Object*>(drmMalloc(sizeof(Object)));
+}
+
+class MockHardwareDisplayPlaneManager
+ : public HardwareDisplayPlaneManagerLegacy {
+ public:
+ MockHardwareDisplayPlaneManager(DrmDevice* drm,
+ std::vector<uint32_t> crtcs,
+ size_t planes_per_crtc) {
+ const int kPlaneBaseId = 50;
+ drm_ = drm;
+ crtcs_.swap(crtcs);
+ for (size_t crtc_idx = 0; crtc_idx < crtcs_.size(); crtc_idx++) {
+ for (size_t i = 0; i < planes_per_crtc; i++) {
+ planes_.push_back(
+ new HardwareDisplayPlane(kPlaneBaseId + i, 1 << crtc_idx));
+ }
+ }
+ }
+};
+
+} // namespace
+
+MockDrmDevice::MockDrmDevice()
+ : DrmDevice(base::FilePath(), base::File()),
+ get_crtc_call_count_(0),
+ set_crtc_call_count_(0),
+ restore_crtc_call_count_(0),
+ add_framebuffer_call_count_(0),
+ remove_framebuffer_call_count_(0),
+ page_flip_call_count_(0),
+ overlay_flip_call_count_(0),
+ overlay_clear_call_count_(0),
+ allocate_buffer_count_(0),
+ set_crtc_expectation_(true),
+ add_framebuffer_expectation_(true),
+ page_flip_expectation_(true),
+ create_dumb_buffer_expectation_(true),
+ current_framebuffer_(0) {
+ plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy());
+}
+
+MockDrmDevice::MockDrmDevice(bool use_sync_flips,
+ std::vector<uint32_t> crtcs,
+ size_t planes_per_crtc)
+ : DrmDevice(base::FilePath(), base::File()),
+ get_crtc_call_count_(0),
+ set_crtc_call_count_(0),
+ restore_crtc_call_count_(0),
+ add_framebuffer_call_count_(0),
+ remove_framebuffer_call_count_(0),
+ page_flip_call_count_(0),
+ overlay_flip_call_count_(0),
+ overlay_clear_call_count_(0),
+ allocate_buffer_count_(0),
+ set_crtc_expectation_(true),
+ add_framebuffer_expectation_(true),
+ page_flip_expectation_(true),
+ create_dumb_buffer_expectation_(true),
+ use_sync_flips_(use_sync_flips),
+ current_framebuffer_(0) {
+ plane_manager_.reset(
+ new MockHardwareDisplayPlaneManager(this, crtcs, planes_per_crtc));
+}
+
+MockDrmDevice::~MockDrmDevice() {
+}
+
+ScopedDrmCrtcPtr MockDrmDevice::GetCrtc(uint32_t crtc_id) {
+ get_crtc_call_count_++;
+ return ScopedDrmCrtcPtr(DrmAllocator<drmModeCrtc>());
+}
+
+bool MockDrmDevice::SetCrtc(uint32_t crtc_id,
+ uint32_t framebuffer,
+ std::vector<uint32_t> connectors,
+ drmModeModeInfo* mode) {
+ current_framebuffer_ = framebuffer;
+ set_crtc_call_count_++;
+ return set_crtc_expectation_;
+}
+
+bool MockDrmDevice::SetCrtc(drmModeCrtc* crtc,
+ std::vector<uint32_t> connectors) {
+ restore_crtc_call_count_++;
+ return true;
+}
+
+bool MockDrmDevice::DisableCrtc(uint32_t crtc_id) {
+ current_framebuffer_ = 0;
+ return true;
+}
+
+ScopedDrmConnectorPtr MockDrmDevice::GetConnector(uint32_t connector_id) {
+ return ScopedDrmConnectorPtr(DrmAllocator<drmModeConnector>());
+}
+
+bool MockDrmDevice::AddFramebuffer(uint32_t width,
+ uint32_t height,
+ uint8_t depth,
+ uint8_t bpp,
+ uint32_t stride,
+ uint32_t handle,
+ uint32_t* framebuffer) {
+ add_framebuffer_call_count_++;
+ *framebuffer = add_framebuffer_call_count_;
+ return add_framebuffer_expectation_;
+}
+
+bool MockDrmDevice::RemoveFramebuffer(uint32_t framebuffer) {
+ remove_framebuffer_call_count_++;
+ return true;
+}
+
+ScopedDrmFramebufferPtr MockDrmDevice::GetFramebuffer(uint32_t framebuffer) {
+ return ScopedDrmFramebufferPtr();
+}
+
+bool MockDrmDevice::PageFlip(uint32_t crtc_id,
+ uint32_t framebuffer,
+ bool is_sync,
+ const PageFlipCallback& callback) {
+ page_flip_call_count_++;
+ current_framebuffer_ = framebuffer;
+ if (page_flip_expectation_) {
+ if (use_sync_flips_)
+ callback.Run(0, 0, 0);
+ else
+ callbacks_.push(callback);
+ }
+
+ return page_flip_expectation_;
+}
+
+bool MockDrmDevice::PageFlipOverlay(uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& location,
+ const gfx::Rect& source,
+ int overlay_plane) {
+ if (!framebuffer)
+ overlay_clear_call_count_++;
+ overlay_flip_call_count_++;
+ return true;
+}
+
+ScopedDrmPropertyPtr MockDrmDevice::GetProperty(drmModeConnector* connector,
+ const char* name) {
+ return ScopedDrmPropertyPtr(DrmAllocator<drmModePropertyRes>());
+}
+
+bool MockDrmDevice::SetProperty(uint32_t connector_id,
+ uint32_t property_id,
+ uint64_t value) {
+ return true;
+}
+
+bool MockDrmDevice::GetCapability(uint64_t capability, uint64_t* value) {
+ return true;
+}
+
+ScopedDrmPropertyBlobPtr MockDrmDevice::GetPropertyBlob(
+ drmModeConnector* connector,
+ const char* name) {
+ return ScopedDrmPropertyBlobPtr(DrmAllocator<drmModePropertyBlobRes>());
+}
+
+bool MockDrmDevice::SetCursor(uint32_t crtc_id,
+ uint32_t handle,
+ const gfx::Size& size) {
+ crtc_cursor_map_[crtc_id] = handle;
+ return true;
+}
+
+bool MockDrmDevice::MoveCursor(uint32_t crtc_id, const gfx::Point& point) {
+ return true;
+}
+
+bool MockDrmDevice::CreateDumbBuffer(const SkImageInfo& info,
+ uint32_t* handle,
+ uint32_t* stride) {
+ if (!create_dumb_buffer_expectation_)
+ return false;
+
+ *handle = allocate_buffer_count_++;
+ *stride = info.minRowBytes();
+ void* pixels = new char[info.getSafeSize(*stride)];
+ buffers_.push_back(
+ skia::AdoptRef(SkSurface::NewRasterDirect(info, pixels, *stride)));
+ buffers_[*handle]->getCanvas()->clear(SK_ColorBLACK);
+
+ return true;
+}
+
+bool MockDrmDevice::DestroyDumbBuffer(uint32_t handle) {
+ if (handle >= buffers_.size() || !buffers_[handle])
+ return false;
+
+ buffers_[handle].clear();
+ return true;
+}
+
+bool MockDrmDevice::MapDumbBuffer(uint32_t handle, size_t size, void** pixels) {
+ if (handle >= buffers_.size() || !buffers_[handle])
+ return false;
+
+ *pixels = const_cast<void*>(buffers_[handle]->peekPixels(nullptr, nullptr));
+ return true;
+}
+
+bool MockDrmDevice::UnmapDumbBuffer(void* pixels, size_t size) {
+ return true;
+}
+
+bool MockDrmDevice::CloseBufferHandle(uint32_t handle) {
+ return true;
+}
+
+bool MockDrmDevice::CommitProperties(drmModePropertySet* properties,
+ uint32_t flags,
+ bool is_sync,
+ bool test_only,
+ const PageFlipCallback& callback) {
+ return false;
+}
+
+bool MockDrmDevice::SetGammaRamp(uint32_t crtc_id,
+ const std::vector<GammaRampRGBEntry>& lut) {
+ return true;
+}
+
+bool MockDrmDevice::SetCapability(uint64_t capability, uint64_t value) {
+ return false;
+}
+
+void MockDrmDevice::RunCallbacks() {
+ while (!callbacks_.empty()) {
+ PageFlipCallback callback = callbacks_.front();
+ callbacks_.pop();
+ callback.Run(0, 0, 0);
+ }
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/drm/test/mock_drm_device.h b/ui/ozone/platform/drm/test/mock_drm_device.h
new file mode 100644
index 0000000..a25bad9
--- /dev/null
+++ b/ui/ozone/platform/drm/test/mock_drm_device.h
@@ -0,0 +1,151 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_TEST_MOCK_DRM_DEVICE_H_
+#define UI_OZONE_PLATFORM_DRM_TEST_MOCK_DRM_DEVICE_H_
+
+#include <map>
+#include <queue>
+#include <vector>
+
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+
+namespace ui {
+
+class CrtcController;
+struct GammaRampRGBEntry;
+
+// The real DrmDevice makes actual DRM calls which we can't use in unit tests.
+class MockDrmDevice : public ui::DrmDevice {
+ public:
+ MockDrmDevice();
+ MockDrmDevice(bool use_sync_flips,
+ std::vector<uint32_t> crtcs,
+ size_t planes_per_crtc);
+
+ int get_get_crtc_call_count() const { return get_crtc_call_count_; }
+ int get_set_crtc_call_count() const { return set_crtc_call_count_; }
+ int get_restore_crtc_call_count() const { return restore_crtc_call_count_; }
+ int get_add_framebuffer_call_count() const {
+ return add_framebuffer_call_count_;
+ }
+ int get_remove_framebuffer_call_count() const {
+ return remove_framebuffer_call_count_;
+ }
+ int get_page_flip_call_count() const { return page_flip_call_count_; }
+ int get_overlay_flip_call_count() const { return overlay_flip_call_count_; }
+ int get_overlay_clear_call_count() const { return overlay_clear_call_count_; }
+ void set_set_crtc_expectation(bool state) { set_crtc_expectation_ = state; }
+ void set_page_flip_expectation(bool state) { page_flip_expectation_ = state; }
+ void set_add_framebuffer_expectation(bool state) {
+ add_framebuffer_expectation_ = state;
+ }
+ void set_create_dumb_buffer_expectation(bool state) {
+ create_dumb_buffer_expectation_ = state;
+ }
+
+ uint32_t current_framebuffer() const { return current_framebuffer_; }
+
+ const std::vector<skia::RefPtr<SkSurface>> buffers() const {
+ return buffers_;
+ }
+
+ uint32_t get_cursor_handle_for_crtc(uint32_t crtc) const {
+ const auto it = crtc_cursor_map_.find(crtc);
+ return it != crtc_cursor_map_.end() ? it->second : 0;
+ }
+
+ void RunCallbacks();
+
+ // DrmDevice:
+ ScopedDrmCrtcPtr GetCrtc(uint32_t crtc_id) override;
+ bool SetCrtc(uint32_t crtc_id,
+ uint32_t framebuffer,
+ std::vector<uint32_t> connectors,
+ drmModeModeInfo* mode) override;
+ bool SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) override;
+ bool DisableCrtc(uint32_t crtc_id) override;
+ ScopedDrmConnectorPtr GetConnector(uint32_t connector_id) override;
+ bool AddFramebuffer(uint32_t width,
+ uint32_t height,
+ uint8_t depth,
+ uint8_t bpp,
+ uint32_t stride,
+ uint32_t handle,
+ uint32_t* framebuffer) override;
+ bool RemoveFramebuffer(uint32_t framebuffer) override;
+ ScopedDrmFramebufferPtr GetFramebuffer(uint32_t framebuffer) override;
+ bool PageFlip(uint32_t crtc_id,
+ uint32_t framebuffer,
+ bool is_sync,
+ const PageFlipCallback& callback) override;
+ bool PageFlipOverlay(uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& location,
+ const gfx::Rect& source,
+ int overlay_plane) override;
+ ScopedDrmPropertyPtr GetProperty(drmModeConnector* connector,
+ const char* name) override;
+ bool SetProperty(uint32_t connector_id,
+ uint32_t property_id,
+ uint64_t value) override;
+ bool GetCapability(uint64_t capability, uint64_t* value) override;
+ ScopedDrmPropertyBlobPtr GetPropertyBlob(drmModeConnector* connector,
+ const char* name) override;
+ bool SetCursor(uint32_t crtc_id,
+ uint32_t handle,
+ const gfx::Size& size) override;
+ bool MoveCursor(uint32_t crtc_id, const gfx::Point& point) override;
+ bool CreateDumbBuffer(const SkImageInfo& info,
+ uint32_t* handle,
+ uint32_t* stride) override;
+ bool DestroyDumbBuffer(uint32_t handle) override;
+ bool MapDumbBuffer(uint32_t handle, size_t size, void** pixels) override;
+ bool UnmapDumbBuffer(void* pixels, size_t size) override;
+ bool CloseBufferHandle(uint32_t handle) override;
+ bool CommitProperties(drmModePropertySet* properties,
+ uint32_t flags,
+ bool is_sync,
+ bool test_only,
+ const PageFlipCallback& callback) override;
+ bool SetGammaRamp(uint32_t crtc_id,
+ const std::vector<GammaRampRGBEntry>& lut) override;
+ bool SetCapability(uint64_t capability, uint64_t value) override;
+
+ private:
+ ~MockDrmDevice() override;
+
+ int get_crtc_call_count_;
+ int set_crtc_call_count_;
+ int restore_crtc_call_count_;
+ int add_framebuffer_call_count_;
+ int remove_framebuffer_call_count_;
+ int page_flip_call_count_;
+ int overlay_flip_call_count_;
+ int overlay_clear_call_count_;
+ int allocate_buffer_count_;
+
+ bool set_crtc_expectation_;
+ bool add_framebuffer_expectation_;
+ bool page_flip_expectation_;
+ bool create_dumb_buffer_expectation_;
+
+ bool use_sync_flips_;
+
+ uint32_t current_framebuffer_;
+
+ std::vector<skia::RefPtr<SkSurface>> buffers_;
+
+ std::map<uint32_t, uint32_t> crtc_cursor_map_;
+
+ std::queue<PageFlipCallback> callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDrmDevice);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_TEST_MOCK_DRM_DEVICE_H_
diff --git a/ui/ozone/platform/egltest/BUILD.gn b/ui/ozone/platform/egltest/BUILD.gn
new file mode 100644
index 0000000..4ffd2f9
--- /dev/null
+++ b/ui/ozone/platform/egltest/BUILD.gn
@@ -0,0 +1,46 @@
+# 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.
+
+import("//tools/generate_library_loader/generate_library_loader.gni")
+
+source_set("egltest") {
+ sources = [
+ "ozone_platform_egltest.cc",
+ "ozone_platform_egltest.h",
+ ]
+
+ deps = [
+ ":eglplatform_shim",
+ "//base",
+ "//ui/events/devices",
+ "//ui/ozone:ozone_base",
+ "//ui/events",
+ "//ui/events/ozone:events_ozone",
+ "//ui/events/ozone:events_ozone_evdev",
+ "//ui/events/ozone:events_ozone_layout",
+ "//ui/events/platform",
+ "//ui/gfx",
+ "//ui/platform_window",
+ ]
+}
+
+generate_library_loader("eglplatform_shim") {
+ name = "LibeglplatformShimLoader"
+ output_h = "libeglplatform_shim.h"
+ output_cc = "libeglplatform_shim_loader.cc"
+ header = "\"ui/ozone/platform/egltest/eglplatform_shim.h\""
+
+ functions = [
+ "ShimQueryString",
+ "ShimInitialize",
+ "ShimTerminate",
+ "ShimCreateWindow",
+ "ShimQueryWindow",
+ "ShimDestroyWindow",
+ "ShimGetNativeDisplay",
+ "ShimGetNativeWindow",
+ "ShimReleaseNativeWindow",
+ ]
+}
+# TODO(spang): eglplatform_shim_x11 once support lands: http://crbug.com/380327
diff --git a/ui/ozone/platform/egltest/eglplatform_shim.h b/ui/ozone/platform/egltest/eglplatform_shim.h
new file mode 100644
index 0000000..ce7cce9
--- /dev/null
+++ b/ui/ozone/platform/egltest/eglplatform_shim.h
@@ -0,0 +1,58 @@
+// 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.
+
+#ifndef __eglplatform_shim_h_
+#define __eglplatform_shim_h_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SHIM_EXPORT __attribute__((visibility("default")))
+
+// Simple integral native window identifier.
+// NB: Unlike EGLNativeWindowType, this will be shipped between processes.
+typedef int ShimNativeWindowId;
+#define SHIM_NO_WINDOW_ID ((ShimNativeWindowId)0)
+
+// Opaque versions of EGL types (as used by ozone).
+typedef intptr_t ShimEGLNativeDisplayType;
+typedef intptr_t ShimEGLNativeWindowType;
+
+// QueryString targets
+#define SHIM_EGL_LIBRARY 0x1001
+#define SHIM_GLES_LIBRARY 0x1002
+
+// CreateWindow / QueryWindow attributes
+#define SHIM_WINDOW_WIDTH 0x0001
+#define SHIM_WINDOW_HEIGHT 0x0002
+
+// Query global implementation information.
+SHIM_EXPORT const char* ShimQueryString(int name);
+
+// Init/terminate library.
+SHIM_EXPORT bool ShimInitialize(void);
+SHIM_EXPORT bool ShimTerminate(void);
+
+// Create window handle & query window properties (called from browser process).
+SHIM_EXPORT ShimNativeWindowId ShimCreateWindow(void);
+SHIM_EXPORT bool ShimQueryWindow(ShimNativeWindowId window_id,
+ int attribute,
+ int* value);
+SHIM_EXPORT bool ShimDestroyWindow(ShimNativeWindowId window_id);
+
+// Manage actual EGL platform objects (called from GPU process).
+SHIM_EXPORT ShimEGLNativeDisplayType ShimGetNativeDisplay(void);
+SHIM_EXPORT ShimEGLNativeWindowType
+ ShimGetNativeWindow(ShimNativeWindowId native_window_id);
+SHIM_EXPORT bool ShimReleaseNativeWindow(ShimEGLNativeWindowType native_window);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __eglplatform_shim_h */
diff --git a/ui/ozone/platform/egltest/eglplatform_shim_xeleven.cc b/ui/ozone/platform/egltest/eglplatform_shim_xeleven.cc
new file mode 100644
index 0000000..c7e0080
--- /dev/null
+++ b/ui/ozone/platform/egltest/eglplatform_shim_xeleven.cc
@@ -0,0 +1,106 @@
+// 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/eglplatform_shim.h"
+
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+Display* g_display;
+
+const int kDefaultX = 0;
+const int kDefaultY = 0;
+const int kDefaultWidth = 1280;
+const int kDefaultHeight = 720;
+const int kDefaultBorderWidth = 0;
+
+const char* ShimQueryString(int name) {
+ switch (name) {
+ case SHIM_EGL_LIBRARY:
+ return "libEGL.so.1";
+ case SHIM_GLES_LIBRARY:
+ return "libGLESv2.so.2";
+ default:
+ return NULL;
+ }
+}
+
+bool ShimInitialize(void) {
+ g_display = XOpenDisplay(NULL);
+ return g_display != NULL;
+}
+
+bool ShimTerminate(void) {
+ XCloseDisplay(g_display);
+ return true;
+}
+
+ShimNativeWindowId ShimCreateWindow(void) {
+ XSetWindowAttributes swa;
+ memset(&swa, 0, sizeof(swa));
+ swa.event_mask = 0;
+
+ Window window = XCreateWindow(g_display,
+ DefaultRootWindow(g_display),
+ kDefaultX,
+ kDefaultY,
+ kDefaultWidth,
+ kDefaultHeight,
+ kDefaultBorderWidth,
+ CopyFromParent,
+ InputOutput,
+ CopyFromParent,
+ CWEventMask,
+ &swa);
+
+ XMapWindow(g_display, window);
+ XStoreName(g_display, window, "EGL test");
+ XFlush(g_display);
+
+ return window;
+}
+
+bool ShimQueryWindow(ShimNativeWindowId window_id, int attribute, int* value) {
+ XWindowAttributes window_attributes;
+ switch (attribute) {
+ case SHIM_WINDOW_WIDTH:
+ XGetWindowAttributes(g_display, window_id, &window_attributes);
+ *value = window_attributes.width;
+ return true;
+ case SHIM_WINDOW_HEIGHT:
+ XGetWindowAttributes(g_display, window_id, &window_attributes);
+ *value = window_attributes.height;
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool ShimDestroyWindow(ShimNativeWindowId window_id) {
+ XDestroyWindow(g_display, window_id);
+ return true;
+}
+
+ShimEGLNativeDisplayType ShimGetNativeDisplay(void) {
+ return reinterpret_cast<ShimEGLNativeDisplayType>(g_display);
+}
+
+ShimEGLNativeWindowType ShimGetNativeWindow(
+ ShimNativeWindowId native_window_id) {
+ return native_window_id;
+}
+
+bool ShimReleaseNativeWindow(ShimEGLNativeWindowType native_window) {
+ return true;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/ui/ozone/platform/egltest/ozone_platform_egltest.cc b/ui/ozone/platform/egltest/ozone_platform_egltest.cc
new file mode 100644
index 0000000..31f35a6
--- /dev/null
+++ b/ui/ozone/platform/egltest/ozone_platform_egltest.cc
@@ -0,0 +1,412 @@
+// 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
diff --git a/ui/ozone/platform/egltest/ozone_platform_egltest.h b/ui/ozone/platform/egltest/ozone_platform_egltest.h
new file mode 100644
index 0000000..fb49be5
--- /dev/null
+++ b/ui/ozone/platform/egltest/ozone_platform_egltest.h
@@ -0,0 +1,17 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_TEST_OZONE_PLATFORM_EGLTEST_H_
+#define UI_OZONE_PLATFORM_TEST_OZONE_PLATFORM_EGLTEST_H_
+
+namespace ui {
+
+class OzonePlatform;
+
+// Constructor hook for use in ozone_platform_list.cc
+OzonePlatform* CreateOzonePlatformEgltest();
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_TEST_OZONE_PLATFORM_EGLTEST_H_
diff --git a/ui/ozone/platform/test/BUILD.gn b/ui/ozone/platform/test/BUILD.gn
new file mode 100644
index 0000000..eaaa60c
--- /dev/null
+++ b/ui/ozone/platform/test/BUILD.gn
@@ -0,0 +1,23 @@
+# 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.
+
+source_set("test") {
+ sources = [
+ "ozone_platform_test.cc",
+ "ozone_platform_test.h",
+ "test_window.cc",
+ "test_window.h",
+ "test_window_manager.cc",
+ "test_window_manager.h",
+ ]
+
+ deps = [
+ "//base",
+ "//skia",
+ "//ui/base",
+ "//ui/gfx/geometry",
+ "//ui/events/ozone:events_ozone_layout",
+ "//ui/events/platform",
+ ]
+}
diff --git a/ui/ozone/platform/test/ozone_platform_test.cc b/ui/ozone/platform/test/ozone_platform_test.cc
new file mode 100644
index 0000000..c6da9e3
--- /dev/null
+++ b/ui/ozone/platform/test/ozone_platform_test.cc
@@ -0,0 +1,122 @@
+// Copyright 2013 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/test/ozone_platform_test.h"
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "ui/base/cursor/ozone/bitmap_cursor_factory_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_source.h"
+#include "ui/ozone/common/native_display_delegate_ozone.h"
+#include "ui/ozone/common/stub_overlay_manager.h"
+#include "ui/ozone/platform/test/test_window.h"
+#include "ui/ozone/platform/test/test_window_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/input_controller.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/ozone_switches.h"
+#include "ui/ozone/public/system_input_injector.h"
+
+namespace ui {
+
+namespace {
+
+// A test implementation of PlatformEventSource that we can instantiate to make
+// sure that the PlatformEventSource has an instance while in unit tests.
+class TestPlatformEventSource : public ui::PlatformEventSource {
+ public:
+ TestPlatformEventSource() {}
+ ~TestPlatformEventSource() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource);
+};
+
+// OzonePlatform for testing
+//
+// This platform dumps images to a file for testing purposes.
+class OzonePlatformTest : public OzonePlatform {
+ public:
+ OzonePlatformTest(const base::FilePath& dump_file) : file_path_(dump_file) {}
+ ~OzonePlatformTest() override {}
+
+ // OzonePlatform:
+ ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override {
+ return window_manager_.get();
+ }
+ OverlayManagerOzone* GetOverlayManager() override {
+ return overlay_manager_.get();
+ }
+ CursorFactoryOzone* GetCursorFactoryOzone() override {
+ return cursor_factory_ozone_.get();
+ }
+ InputController* GetInputController() override {
+ return input_controller_.get();
+ }
+ 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 TestWindow(delegate, window_manager_.get(), bounds));
+ }
+ scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate() override {
+ return make_scoped_ptr(new NativeDisplayDelegateOzone());
+ }
+
+ void InitializeUI() override {
+ window_manager_.reset(new TestWindowManager(file_path_));
+ window_manager_->Initialize();
+ // This unbreaks tests that create their own.
+ if (!PlatformEventSource::GetInstance())
+ platform_event_source_.reset(new TestPlatformEventSource);
+ KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
+ make_scoped_ptr(new StubKeyboardLayoutEngine()));
+
+ overlay_manager_.reset(new StubOverlayManager());
+ input_controller_ = CreateStubInputController();
+ cursor_factory_ozone_.reset(new BitmapCursorFactoryOzone);
+ gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
+ }
+
+ void InitializeGPU() override {
+ gpu_platform_support_.reset(CreateStubGpuPlatformSupport());
+ }
+
+ private:
+ scoped_ptr<TestWindowManager> window_manager_;
+ scoped_ptr<PlatformEventSource> platform_event_source_;
+ scoped_ptr<CursorFactoryOzone> cursor_factory_ozone_;
+ scoped_ptr<InputController> input_controller_;
+ scoped_ptr<GpuPlatformSupport> gpu_platform_support_;
+ scoped_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
+ scoped_ptr<OverlayManagerOzone> overlay_manager_;
+ base::FilePath file_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(OzonePlatformTest);
+};
+
+} // namespace
+
+OzonePlatform* CreateOzonePlatformTest() {
+ base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
+ base::FilePath location;
+ if (cmd->HasSwitch(switches::kOzoneDumpFile))
+ location = cmd->GetSwitchValuePath(switches::kOzoneDumpFile);
+ return new OzonePlatformTest(location);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/test/ozone_platform_test.h b/ui/ozone/platform/test/ozone_platform_test.h
new file mode 100644
index 0000000..fb25fd6
--- /dev/null
+++ b/ui/ozone/platform/test/ozone_platform_test.h
@@ -0,0 +1,17 @@
+// Copyright 2013 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.
+
+#ifndef UI_OZONE_PLATFORM_TEST_OZONE_PLATFORM_TEST_H_
+#define UI_OZONE_PLATFORM_TEST_OZONE_PLATFORM_TEST_H_
+
+namespace ui {
+
+class OzonePlatform;
+
+// Constructor hook for use in ozone_platform_list.cc
+OzonePlatform* CreateOzonePlatformTest();
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_TEST_OZONE_PLATFORM_TEST_H_
diff --git a/ui/ozone/platform/test/test_window.cc b/ui/ozone/platform/test/test_window.cc
new file mode 100644
index 0000000..2890ccf
--- /dev/null
+++ b/ui/ozone/platform/test/test_window.cc
@@ -0,0 +1,83 @@
+// 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/test/test_window.h"
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/strings/string_number_conversions.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/ozone/platform/test/test_window_manager.h"
+#include "ui/platform_window/platform_window_delegate.h"
+
+namespace ui {
+
+TestWindow::TestWindow(PlatformWindowDelegate* delegate,
+ TestWindowManager* manager,
+ const gfx::Rect& bounds)
+ : delegate_(delegate), manager_(manager), bounds_(bounds) {
+ widget_ = manager_->AddWindow(this);
+ delegate_->OnAcceleratedWidgetAvailable(widget_);
+}
+
+TestWindow::~TestWindow() {
+ manager_->RemoveWindow(widget_, this);
+}
+
+base::FilePath TestWindow::path() {
+ base::FilePath base_path = manager_->base_path();
+ if (base_path.empty() || base_path == base::FilePath("/dev/null"))
+ return base_path;
+
+ // Disambiguate multiple window output files with the window id.
+ return base_path.Append(base::IntToString(widget_));
+}
+
+gfx::Rect TestWindow::GetBounds() {
+ return bounds_;
+}
+
+void TestWindow::SetBounds(const gfx::Rect& bounds) {
+ bounds_ = bounds;
+ delegate_->OnBoundsChanged(bounds);
+}
+
+void TestWindow::Show() {
+}
+
+void TestWindow::Hide() {
+}
+
+void TestWindow::Close() {
+}
+
+void TestWindow::SetCapture() {
+}
+
+void TestWindow::ReleaseCapture() {
+}
+
+void TestWindow::ToggleFullscreen() {
+}
+
+void TestWindow::Maximize() {
+}
+
+void TestWindow::Minimize() {
+}
+
+void TestWindow::Restore() {
+}
+
+void TestWindow::SetCursor(PlatformCursor cursor) {
+}
+
+void TestWindow::MoveCursorTo(const gfx::Point& location) {
+}
+
+void TestWindow::ConfineCursorToBounds(const gfx::Rect& bounds) {
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/test/test_window.h b/ui/ozone/platform/test/test_window.h
new file mode 100644
index 0000000..aaeb003
--- /dev/null
+++ b/ui/ozone/platform/test/test_window.h
@@ -0,0 +1,55 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_TEST_TEST_WINDOW_H_
+#define UI_OZONE_PLATFORM_TEST_TEST_WINDOW_H_
+
+#include "base/files/file_path.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/platform_window/platform_window.h"
+
+namespace ui {
+
+class PlatformWindowDelegate;
+class TestWindowManager;
+
+class TestWindow : public PlatformWindow {
+ public:
+ TestWindow(PlatformWindowDelegate* delegate,
+ TestWindowManager* manager,
+ const gfx::Rect& bounds);
+ ~TestWindow() override;
+
+ // Path for image file for this window.
+ base::FilePath path();
+
+ // 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;
+
+ private:
+ PlatformWindowDelegate* delegate_;
+ TestWindowManager* manager_;
+ gfx::Rect bounds_;
+ gfx::AcceleratedWidget widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestWindow);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_TEST_TEST_WINDOW_H_
diff --git a/ui/ozone/platform/test/test_window_manager.cc b/ui/ozone/platform/test/test_window_manager.cc
new file mode 100644
index 0000000..cd48bf3
--- /dev/null
+++ b/ui/ozone/platform/test/test_window_manager.cc
@@ -0,0 +1,113 @@
+// 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/test/test_window_manager.h"
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/stl_util.h"
+#include "base/threading/worker_pool.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/gfx/vsync_provider.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+
+namespace ui {
+
+namespace {
+
+void WriteDataToFile(const base::FilePath& location, const SkBitmap& bitmap) {
+ DCHECK(!location.empty());
+ std::vector<unsigned char> png_data;
+ gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, true, &png_data);
+ base::WriteFile(location,
+ reinterpret_cast<const char*>(vector_as_array(&png_data)),
+ png_data.size());
+}
+
+class FileSurface : public SurfaceOzoneCanvas {
+ public:
+ FileSurface(const base::FilePath& location) : location_(location) {}
+ ~FileSurface() override {}
+
+ // SurfaceOzoneCanvas overrides:
+ void ResizeCanvas(const gfx::Size& viewport_size) override {
+ surface_ = skia::AdoptRef(SkSurface::NewRaster(SkImageInfo::MakeN32Premul(
+ viewport_size.width(), viewport_size.height())));
+ }
+ skia::RefPtr<SkSurface> GetSurface() override { return surface_; }
+ void PresentCanvas(const gfx::Rect& damage) override {
+ if (location_.empty())
+ return;
+ SkBitmap bitmap;
+ bitmap.setInfo(surface_->getCanvas()->imageInfo());
+
+ // TODO(dnicoara) Use SkImage instead to potentially avoid a copy.
+ // See crbug.com/361605 for details.
+ if (surface_->getCanvas()->readPixels(&bitmap, 0, 0)) {
+ base::WorkerPool::PostTask(
+ FROM_HERE, base::Bind(&WriteDataToFile, location_, bitmap), true);
+ }
+ }
+ scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override {
+ return nullptr;
+ }
+
+ private:
+ base::FilePath location_;
+ skia::RefPtr<SkSurface> surface_;
+};
+
+} // namespace
+
+TestWindowManager::TestWindowManager(const base::FilePath& dump_location)
+ : location_(dump_location) {
+}
+
+TestWindowManager::~TestWindowManager() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void TestWindowManager::Initialize() {
+ if (location_.empty())
+ return;
+ if (!DirectoryExists(location_) && !base::CreateDirectory(location_) &&
+ location_ != base::FilePath("/dev/null"))
+ PLOG(FATAL) << "unable to create output directory";
+ if (!base::PathIsWritable(location_))
+ PLOG(FATAL) << "unable to write to output location";
+}
+
+int32_t TestWindowManager::AddWindow(TestWindow* window) {
+ return windows_.Add(window);
+}
+
+void TestWindowManager::RemoveWindow(int32_t window_id, TestWindow* window) {
+ DCHECK_EQ(window, windows_.Lookup(window_id));
+ windows_.Remove(window_id);
+}
+
+base::FilePath TestWindowManager::base_path() const {
+ return location_;
+}
+
+scoped_ptr<SurfaceOzoneCanvas> TestWindowManager::CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ TestWindow* window = windows_.Lookup(widget);
+ DCHECK(window);
+ return make_scoped_ptr<SurfaceOzoneCanvas>(new FileSurface(window->path()));
+}
+
+bool TestWindowManager::LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return false;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/test/test_window_manager.h b/ui/ozone/platform/test/test_window_manager.h
new file mode 100644
index 0000000..b651207
--- /dev/null
+++ b/ui/ozone/platform/test/test_window_manager.h
@@ -0,0 +1,53 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_TEST_FILE_SURFACE_FACTORY_H_
+#define UI_OZONE_PLATFORM_TEST_FILE_SURFACE_FACTORY_H_
+
+#include "base/files/file_path.h"
+#include "base/id_map.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/test/test_window.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace ui {
+
+class TestWindowManager : public SurfaceFactoryOzone {
+ public:
+ explicit TestWindowManager(const base::FilePath& dump_location);
+ ~TestWindowManager() override;
+
+ // Initialize (mainly check that we have a place to write output to).
+ void Initialize();
+
+ // Register a new window. Returns the window id.
+ int32_t AddWindow(TestWindow* window);
+
+ // Remove a window.
+ void RemoveWindow(int32_t window_id, TestWindow* window);
+
+ // User-supplied path for images.
+ base::FilePath base_path() const;
+
+ // SurfaceFactoryOzone:
+ scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
+ gfx::AcceleratedWidget w) override;
+ bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) override;
+
+ private:
+ base::FilePath location_;
+
+ IDMap<TestWindow> windows_;
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestWindowManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_TEST_FILE_SURFACE_FACTORY_H_
diff --git a/ui/ozone/platform_constructor_list.h b/ui/ozone/platform_constructor_list.h
new file mode 100644
index 0000000..4f2fa98
--- /dev/null
+++ b/ui/ozone/platform_constructor_list.h
@@ -0,0 +1,21 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_CONSTRUCTOR_LIST_H_
+#define UI_OZONE_PLATFORM_CONSTRUCTOR_LIST_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/ozone/platform_list.h"
+
+namespace ui {
+
+template <class T>
+struct PlatformConstructorList {
+ typedef T* (*Constructor)();
+ static const Constructor kConstructors[kPlatformCount];
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_CONSTRUCTOR_LIST_H_
diff --git a/ui/ozone/platform_object.h b/ui/ozone/platform_object.h
new file mode 100644
index 0000000..2518c7c
--- /dev/null
+++ b/ui/ozone/platform_object.h
@@ -0,0 +1,34 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_OBJECT_H_
+#define UI_OZONE_PLATFORM_OBJECT_H_
+
+#include "base/memory/scoped_ptr.h"
+
+namespace ui {
+
+// Create an instance of platform specific object.
+//
+// This calls a static constructor function based on the --ozone-platform flag.
+//
+// For the platform called "foo", PlatformObject<PlatformWidget> will ultimately
+// call the function with signature
+//
+// PlatformWidget* CreatePlatformWidgetFoo();
+//
+// A definition of this function for each compiled platform must be provided, or
+// link errors will result.
+//
+// To find the right constructor function, this uses static data defined in the
+// source file generated by the generate_constructor_list.py.
+template <class T>
+class PlatformObject {
+ public:
+ static scoped_ptr<T> Create();
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_OBJECT_H_
diff --git a/ui/ozone/platform_object_internal.h b/ui/ozone/platform_object_internal.h
new file mode 100644
index 0000000..68a42b3
--- /dev/null
+++ b/ui/ozone/platform_object_internal.h
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_OBJECT_INTERNAL_H_
+#define UI_OZONE_PLATFORM_OBJECT_INTERNAL_H_
+
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform_constructor_list.h"
+#include "ui/ozone/platform_object.h"
+#include "ui/ozone/platform_selection.h"
+
+namespace ui {
+
+template <class T>
+scoped_ptr<T> PlatformObject<T>::Create() {
+ typedef typename PlatformConstructorList<T>::Constructor Constructor;
+
+ // Determine selected platform (from --ozone-platform flag, or default).
+ int platform = GetOzonePlatformId();
+
+ // Look up the constructor in the constructor list.
+ Constructor constructor = PlatformConstructorList<T>::kConstructors[platform];
+
+ // Call the constructor.
+ return make_scoped_ptr(constructor());
+}
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_OBJECT_INTERNAL_H_
diff --git a/ui/ozone/platform_selection.cc b/ui/ozone/platform_selection.cc
new file mode 100644
index 0000000..04dc04c
--- /dev/null
+++ b/ui/ozone/platform_selection.cc
@@ -0,0 +1,53 @@
+// 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_selection.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "ui/ozone/platform_list.h"
+#include "ui/ozone/public/ozone_switches.h"
+
+namespace ui {
+
+namespace {
+
+// Returns the name of the platform to use (value of --ozone-platform flag).
+std::string GetPlatformName() {
+ // The first platform is the default.
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kOzonePlatform) &&
+ kPlatformCount > 0)
+ return "gbm";//kPlatformNames[0];
+ return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kOzonePlatform);
+}
+
+int g_selected_platform = -1;
+
+} // namespace
+
+int GetOzonePlatformId() {
+ if (g_selected_platform >= 0)
+ return g_selected_platform;
+
+ std::string platform_name = GetPlatformName();
+
+ // Search for a matching platform in the list.
+ for (int platform_id = 0; platform_id < kPlatformCount; ++platform_id) {
+ if (platform_name == kPlatformNames[platform_id]) {
+ g_selected_platform = platform_id;
+ return g_selected_platform;
+ }
+ }
+
+ LOG(FATAL) << "Invalid ozone platform: " << platform_name;
+ return -1; // not reached
+}
+
+const char* GetOzonePlatformName() {
+ return kPlatformNames[GetOzonePlatformId()];
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform_selection.h b/ui/ozone/platform_selection.h
new file mode 100644
index 0000000..5a1229f
--- /dev/null
+++ b/ui/ozone/platform_selection.h
@@ -0,0 +1,21 @@
+// 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.
+
+#ifndef UI_OZONE_PLATFORM_SELECTION_H_
+#define UI_OZONE_PLATFORM_SELECTION_H_
+
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform_list.h"
+
+namespace ui {
+
+// Get active platform id (by parsing --ozone-platform flag).
+OZONE_EXPORT int GetOzonePlatformId();
+
+// Get active platform name.
+OZONE_EXPORT const char* GetOzonePlatformName();
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_SELECTION_H_
diff --git a/ui/ozone/public/README b/ui/ozone/public/README
new file mode 100644
index 0000000..27e1b3b
--- /dev/null
+++ b/ui/ozone/public/README
@@ -0,0 +1,2 @@
+This directory contains the platform API exposed to higher level components such
+as content. These interfaces can be used outside of ui/ozone.
diff --git a/ui/ozone/public/cursor_factory_ozone.cc b/ui/ozone/public/cursor_factory_ozone.cc
new file mode 100644
index 0000000..c7f388d
--- /dev/null
+++ b/ui/ozone/public/cursor_factory_ozone.cc
@@ -0,0 +1,57 @@
+// 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/public/cursor_factory_ozone.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+// static
+CursorFactoryOzone* CursorFactoryOzone::impl_ = NULL;
+
+CursorFactoryOzone::CursorFactoryOzone() {
+ DCHECK(!impl_) << "There should only be a single CursorFactoryOzone.";
+ impl_ = this;
+}
+
+CursorFactoryOzone::~CursorFactoryOzone() {
+ DCHECK_EQ(impl_, this);
+ impl_ = NULL;
+}
+
+CursorFactoryOzone* CursorFactoryOzone::GetInstance() {
+ DCHECK(impl_) << "No CursorFactoryOzone implementation set.";
+ return impl_;
+}
+
+PlatformCursor CursorFactoryOzone::GetDefaultCursor(int type) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+PlatformCursor CursorFactoryOzone::CreateImageCursor(
+ const SkBitmap& bitmap,
+ const gfx::Point& hotspot) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+PlatformCursor CursorFactoryOzone::CreateAnimatedCursor(
+ const std::vector<SkBitmap>& bitmaps,
+ const gfx::Point& hotspot,
+ int frame_delay_ms) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+void CursorFactoryOzone::RefImageCursor(PlatformCursor cursor) {
+ NOTIMPLEMENTED();
+}
+
+void CursorFactoryOzone::UnrefImageCursor(PlatformCursor cursor) {
+ NOTIMPLEMENTED();
+}
+
+} // namespace ui
diff --git a/ui/ozone/public/cursor_factory_ozone.h b/ui/ozone/public/cursor_factory_ozone.h
new file mode 100644
index 0000000..4950a31
--- /dev/null
+++ b/ui/ozone/public/cursor_factory_ozone.h
@@ -0,0 +1,61 @@
+// 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.
+
+#ifndef UI_OZONE_PUBLIC_CURSOR_FACTORY_OZONE_H_
+#define UI_OZONE_PUBLIC_CURSOR_FACTORY_OZONE_H_
+
+#include <vector>
+
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/ozone_base_export.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+
+typedef void* PlatformCursor;
+
+class OZONE_BASE_EXPORT CursorFactoryOzone {
+ public:
+ CursorFactoryOzone();
+ virtual ~CursorFactoryOzone();
+
+ // Returns the singleton instance.
+ static CursorFactoryOzone* GetInstance();
+
+ // Return the default cursor of the specified type. The types are listed in
+ // ui/base/cursor/cursor.h. Default cursors are managed by the implementation
+ // and must live indefinitely; there's no way to know when to free them.
+ virtual PlatformCursor GetDefaultCursor(int type);
+
+ // Return a image cursor from the specified image & hotspot. Image cursors
+ // are referenced counted and have an initial refcount of 1. Therefore, each
+ // CreateImageCursor call must be matched with a call to UnrefImageCursor.
+ virtual PlatformCursor CreateImageCursor(const SkBitmap& bitmap,
+ const gfx::Point& hotspot);
+
+ // Return a animated cursor from the specified image & hotspot. Animated
+ // cursors are referenced counted and have an initial refcount of 1.
+ // Therefore, each CreateAnimatedCursor call must be matched with a call to
+ // UnrefImageCursor.
+ virtual PlatformCursor CreateAnimatedCursor(
+ const std::vector<SkBitmap>& bitmaps,
+ const gfx::Point& hotspot,
+ int frame_delay_ms);
+
+ // Increment platform image cursor refcount.
+ virtual void RefImageCursor(PlatformCursor cursor);
+
+ // Decrement platform image cursor refcount.
+ virtual void UnrefImageCursor(PlatformCursor cursor);
+
+ private:
+ static CursorFactoryOzone* impl_; // not owned
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_CURSOR_FACTORY_OZONE_H_
diff --git a/ui/ozone/public/gpu_platform_support.cc b/ui/ozone/public/gpu_platform_support.cc
new file mode 100644
index 0000000..fdc5b54
--- /dev/null
+++ b/ui/ozone/public/gpu_platform_support.cc
@@ -0,0 +1,41 @@
+// 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/public/gpu_platform_support.h"
+
+#include "base/logging.h"
+#include "ui/ozone/ozone_export.h"
+
+namespace ui {
+
+namespace {
+
+// No-op implementation of GpuPlatformSupport.
+class StubGpuPlatformSupport : public GpuPlatformSupport {
+ public:
+ // GpuPlatformSupport:
+ void OnChannelEstablished() override {}
+ // bool OnMessageReceived(const IPC::Message&) override { return false; }
+ //void RelinquishGpuResources(const base::Closure& callback) override;
+ //IPC::MessageFilter* GetMessageFilter() override { return nullptr; }
+};
+
+// void StubGpuPlatformSupport::RelinquishGpuResources(
+// const base::Closure& callback) {
+// callback.Run();
+// }
+
+} // namespace
+
+GpuPlatformSupport::GpuPlatformSupport() {
+}
+
+GpuPlatformSupport::~GpuPlatformSupport() {
+}
+
+GpuPlatformSupport* CreateStubGpuPlatformSupport() {
+ return new StubGpuPlatformSupport;
+}
+
+} // namespace ui
diff --git a/ui/ozone/public/gpu_platform_support.h b/ui/ozone/public/gpu_platform_support.h
new file mode 100644
index 0000000..5e2750e
--- /dev/null
+++ b/ui/ozone/public/gpu_platform_support.h
@@ -0,0 +1,30 @@
+// 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.
+
+#ifndef UI_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_H_
+#define UI_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_H_
+
+#include "base/callback.h"
+#include "ui/ozone/ozone_base_export.h"
+
+namespace ui {
+
+// Platform-specific object to support a GPU process.
+//
+// See GpuPlatformSupportHost for more context.
+class OZONE_BASE_EXPORT GpuPlatformSupport {
+ public:
+ GpuPlatformSupport();
+ virtual ~GpuPlatformSupport();
+
+ // Called when the GPU process is spun up & channel established.
+ virtual void OnChannelEstablished() = 0;
+};
+
+// Create a stub implementation.
+OZONE_BASE_EXPORT GpuPlatformSupport* CreateStubGpuPlatformSupport();
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_H_
diff --git a/ui/ozone/public/gpu_platform_support_host.cc b/ui/ozone/public/gpu_platform_support_host.cc
new file mode 100644
index 0000000..16b3561
--- /dev/null
+++ b/ui/ozone/public/gpu_platform_support_host.cc
@@ -0,0 +1,35 @@
+// 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/public/gpu_platform_support_host.h"
+
+#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
+#include "ui/ozone/ozone_export.h"
+
+namespace ui {
+
+namespace {
+
+// No-op implementations of GpuPlatformSupportHost.
+class StubGpuPlatformSupportHost : public GpuPlatformSupportHost {
+ public:
+ // GpuPlatformSupportHost:
+ void OnChannelEstablished(int host_id) override {}
+ void OnChannelDestroyed(int host_id) override {}
+};
+
+} // namespace
+
+GpuPlatformSupportHost::GpuPlatformSupportHost() {
+}
+
+GpuPlatformSupportHost::~GpuPlatformSupportHost() {
+}
+
+GpuPlatformSupportHost* CreateStubGpuPlatformSupportHost() {
+ return new StubGpuPlatformSupportHost;
+}
+
+} // namespace ui
diff --git a/ui/ozone/public/gpu_platform_support_host.h b/ui/ozone/public/gpu_platform_support_host.h
new file mode 100644
index 0000000..d4c76af
--- /dev/null
+++ b/ui/ozone/public/gpu_platform_support_host.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef UI_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_HOST_H_
+#define UI_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_HOST_H_
+
+#include "base/memory/ref_counted.h"
+#include "ui/ozone/ozone_base_export.h"
+
+namespace ui {
+
+// Platform-specific object to support a GPU process host.
+//
+// ChromeOS on bare hardware will do display configuration and cursor
+// movement from the GPU process. This provides a conduit for the
+// messages needed to make this work.
+//
+// Under X11, we don't need any GPU messages for display configuration.
+// That's why there's no real functionality here: it's purely mechanism
+// to support additional messages needed by specific platforms.
+class OZONE_BASE_EXPORT GpuPlatformSupportHost {
+ public:
+ GpuPlatformSupportHost();
+ virtual ~GpuPlatformSupportHost();
+
+ // Called when the GPU process is spun up & channel established.
+ virtual void OnChannelEstablished(int host_id) = 0;
+
+ // Called when the GPU process is destroyed.
+ virtual void OnChannelDestroyed(int host_id) = 0;
+};
+
+// create a stub implementation.
+OZONE_BASE_EXPORT GpuPlatformSupportHost* CreateStubGpuPlatformSupportHost();
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_HOST_H_
diff --git a/ui/ozone/public/input_controller.cc b/ui/ozone/public/input_controller.cc
new file mode 100644
index 0000000..dd508a3
--- /dev/null
+++ b/ui/ozone/public/input_controller.cc
@@ -0,0 +1,137 @@
+// 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/public/input_controller.h"
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+
+namespace ui {
+
+namespace {
+
+class StubInputController : public InputController {
+ public:
+ StubInputController();
+ ~StubInputController() override;
+
+ // InputController:
+ bool HasMouse() override;
+ bool HasTouchpad() override;
+ bool IsCapsLockEnabled() override;
+ void SetCapsLockEnabled(bool enabled) override;
+ void SetNumLockEnabled(bool enabled) override;
+ bool IsAutoRepeatEnabled() override;
+ void SetAutoRepeatEnabled(bool enabled) override;
+ void SetAutoRepeatRate(const base::TimeDelta& delay,
+ const base::TimeDelta& interval) override;
+ void GetAutoRepeatRate(base::TimeDelta* delay,
+ base::TimeDelta* interval) override;
+ void SetTouchpadSensitivity(int value) override;
+ void SetTapToClick(bool enabled) override;
+ void SetThreeFingerClick(bool enabled) override;
+ void SetTapDragging(bool enabled) override;
+ void SetNaturalScroll(bool enabled) override;
+ void SetMouseSensitivity(int value) override;
+ void SetPrimaryButtonRight(bool right) override;
+ void SetTapToClickPaused(bool state) override;
+ void GetTouchDeviceStatus(const GetTouchDeviceStatusReply& reply) override;
+ void GetTouchEventLog(const base::FilePath& out_dir,
+ const GetTouchEventLogReply& reply) override;
+ void SetInternalTouchpadEnabled(bool enabled) override;
+ void SetInternalKeyboardFilter(bool enable_filter,
+ std::vector<DomCode> allowed_keys) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StubInputController);
+};
+
+StubInputController::StubInputController() {
+}
+
+StubInputController::~StubInputController() {
+}
+
+bool StubInputController::HasMouse() {
+ return false;
+}
+
+bool StubInputController::HasTouchpad() {
+ return false;
+}
+
+bool StubInputController::IsCapsLockEnabled() {
+ return false;
+}
+
+void StubInputController::SetCapsLockEnabled(bool enabled) {
+}
+
+void StubInputController::SetNumLockEnabled(bool enabled) {
+}
+
+bool StubInputController::IsAutoRepeatEnabled() {
+ return true;
+}
+
+void StubInputController::SetAutoRepeatEnabled(bool enabled) {
+}
+
+void StubInputController::SetAutoRepeatRate(const base::TimeDelta& delay,
+ const base::TimeDelta& interval) {
+}
+
+void StubInputController::GetAutoRepeatRate(base::TimeDelta* delay,
+ base::TimeDelta* interval) {
+}
+
+void StubInputController::SetTouchpadSensitivity(int value) {
+}
+
+void StubInputController::SetTapToClick(bool enabled) {
+}
+
+void StubInputController::SetThreeFingerClick(bool enabled) {
+}
+
+void StubInputController::SetTapDragging(bool enabled) {
+}
+
+void StubInputController::SetNaturalScroll(bool enabled) {
+}
+
+void StubInputController::SetMouseSensitivity(int value) {
+}
+
+void StubInputController::SetPrimaryButtonRight(bool right) {
+}
+
+void StubInputController::SetTapToClickPaused(bool state) {
+}
+
+void StubInputController::GetTouchDeviceStatus(
+ const GetTouchDeviceStatusReply& reply) {
+ reply.Run(scoped_ptr<std::string>(new std::string));
+}
+
+void StubInputController::GetTouchEventLog(const base::FilePath& out_dir,
+ const GetTouchEventLogReply& reply) {
+ reply.Run(make_scoped_ptr(new std::vector<base::FilePath>));
+}
+
+void StubInputController::SetInternalTouchpadEnabled(bool enabled) {
+}
+
+void StubInputController::SetInternalKeyboardFilter(
+ bool enable_filter,
+ std::vector<DomCode> allowed_keys) {
+}
+
+} // namespace
+
+scoped_ptr<InputController> CreateStubInputController() {
+ return make_scoped_ptr(new StubInputController);
+}
+
+} // namespace ui
diff --git a/ui/ozone/public/input_controller.h b/ui/ozone/public/input_controller.h
new file mode 100644
index 0000000..b8dae61
--- /dev/null
+++ b/ui/ozone/public/input_controller.h
@@ -0,0 +1,92 @@
+// 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.
+
+#ifndef UI_OZONE_PUBLIC_INPUT_CONTROLLER_H_
+#define UI_OZONE_PUBLIC_INPUT_CONTROLLER_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/ozone/ozone_export.h"
+
+namespace base {
+class TimeDelta;
+}
+
+namespace ui {
+
+enum class DomCode;
+
+// Platform-specific interface for controlling input devices.
+//
+// The object provides methods for the preference page to configure input
+// devices w.r.t. the user setting. On ChromeOS, this replaces the inputcontrol
+// script that is originally located at /opt/google/chrome/.
+class OZONE_EXPORT InputController {
+ public:
+ typedef base::Callback<void(scoped_ptr<std::string>)>
+ GetTouchDeviceStatusReply;
+ typedef base::Callback<void(scoped_ptr<std::vector<base::FilePath>>)>
+ GetTouchEventLogReply;
+
+ InputController() {}
+ virtual ~InputController() {}
+
+ // Functions for checking devices existence.
+ virtual bool HasMouse() = 0;
+ virtual bool HasTouchpad() = 0;
+
+ // Keyboard settings.
+ virtual bool IsCapsLockEnabled() = 0;
+ virtual void SetCapsLockEnabled(bool enabled) = 0;
+ virtual void SetNumLockEnabled(bool enabled) = 0;
+ virtual bool IsAutoRepeatEnabled() = 0;
+ virtual void SetAutoRepeatEnabled(bool enabled) = 0;
+ virtual void SetAutoRepeatRate(const base::TimeDelta& delay,
+ const base::TimeDelta& interval) = 0;
+ virtual void GetAutoRepeatRate(base::TimeDelta* delay,
+ base::TimeDelta* interval) = 0;
+
+ // Touchpad settings.
+ virtual void SetTouchpadSensitivity(int value) = 0;
+ virtual void SetTapToClick(bool enabled) = 0;
+ virtual void SetThreeFingerClick(bool enabled) = 0;
+ virtual void SetTapDragging(bool enabled) = 0;
+ virtual void SetNaturalScroll(bool enabled) = 0;
+
+ // Mouse settings.
+ virtual void SetMouseSensitivity(int value) = 0;
+ virtual void SetPrimaryButtonRight(bool right) = 0;
+
+ // Touch log collection.
+ virtual void GetTouchDeviceStatus(const GetTouchDeviceStatusReply& reply) = 0;
+ virtual void GetTouchEventLog(const base::FilePath& out_dir,
+ const GetTouchEventLogReply& reply) = 0;
+
+ // Temporarily enable/disable Tap-to-click. Used to enhance the user
+ // experience in some use cases (e.g., typing, watching video).
+ virtual void SetTapToClickPaused(bool state) = 0;
+
+ virtual void SetInternalTouchpadEnabled(bool enabled) = 0;
+
+ // If |enable_filter| is true, all keys on the internal keyboard except
+ // |allowed_keys| are disabled.
+ virtual void SetInternalKeyboardFilter(bool enable_filter,
+ std::vector<DomCode> allowed_keys) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InputController);
+};
+
+// Create an input controller that does nothing.
+OZONE_EXPORT scoped_ptr<InputController> CreateStubInputController();
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_INPUT_CONTROLLER_H_
diff --git a/ui/ozone/public/native_pixmap.h b/ui/ozone/public/native_pixmap.h
new file mode 100644
index 0000000..a1204f7
--- /dev/null
+++ b/ui/ozone/public/native_pixmap.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef UI_OZONE_PUBLIC_NATIVE_PIXMAP_H_
+#define UI_OZONE_PUBLIC_NATIVE_PIXMAP_H_
+
+#include "base/memory/ref_counted.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/overlay_transform.h"
+
+namespace gfx {
+class Rect;
+class RectF;
+}
+
+namespace ui {
+
+// This represents a buffer that can be directly imported via GL for
+// rendering, or exported via dma-buf fds.
+class NativePixmap : public base::RefCountedThreadSafe<NativePixmap> {
+ public:
+ NativePixmap() {}
+
+ virtual void* /* EGLClientBuffer */ GetEGLClientBuffer() = 0;
+ virtual int GetDmaBufFd() = 0;
+ virtual int GetDmaBufPitch() = 0;
+
+ // Sets the overlay plane to switch to at the next page flip.
+ // |w| specifies the screen to display this overlay plane on.
+ // |plane_z_order| specifies the stacking order of the plane relative to the
+ // main framebuffer located at index 0.
+ // |plane_transform| specifies how the buffer is to be transformed during.
+ // composition.
+ // |buffer| to be presented by the overlay.
+ // |display_bounds| specify where it is supposed to be on the screen.
+ // |crop_rect| specifies the region within the buffer to be placed
+ // inside |display_bounds|. This is specified in texture coordinates, in the
+ // range of [0,1].
+ virtual bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
+ int plane_z_order,
+ gfx::OverlayTransform plane_transform,
+ const gfx::Rect& display_bounds,
+ const gfx::RectF& crop_rect) = 0;
+
+ protected:
+ virtual ~NativePixmap() {}
+
+ private:
+ friend class base::RefCountedThreadSafe<NativePixmap>;
+
+ DISALLOW_COPY_AND_ASSIGN(NativePixmap);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_NATIVE_PIXMAP_H_
diff --git a/ui/ozone/public/overlay_candidates_ozone.cc b/ui/ozone/public/overlay_candidates_ozone.cc
new file mode 100644
index 0000000..9e01440
--- /dev/null
+++ b/ui/ozone/public/overlay_candidates_ozone.cc
@@ -0,0 +1,25 @@
+// 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/public/overlay_candidates_ozone.h"
+
+#include <stdlib.h>
+
+namespace ui {
+
+OverlayCandidatesOzone::OverlaySurfaceCandidate::OverlaySurfaceCandidate() {
+}
+
+OverlayCandidatesOzone::OverlaySurfaceCandidate::~OverlaySurfaceCandidate() {
+}
+
+void OverlayCandidatesOzone::CheckOverlaySupport(
+ OverlaySurfaceCandidateList* surfaces) {
+ NOTREACHED();
+}
+
+OverlayCandidatesOzone::~OverlayCandidatesOzone() {
+}
+
+} // namespace ui
diff --git a/ui/ozone/public/overlay_candidates_ozone.h b/ui/ozone/public/overlay_candidates_ozone.h
new file mode 100644
index 0000000..e71dc6f
--- /dev/null
+++ b/ui/ozone/public/overlay_candidates_ozone.h
@@ -0,0 +1,62 @@
+// 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.
+
+#ifndef UI_OZONE_PUBLIC_OVERLAY_CANDIDATES_OZONE_H_
+#define UI_OZONE_PUBLIC_OVERLAY_CANDIDATES_OZONE_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/ozone/ozone_base_export.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace ui {
+
+// This class can be used to answer questions about possible overlay
+// configurations for a particular output device. We get an instance of this
+// class from SurfaceFactoryOzone given an AcceleratedWidget.
+class OZONE_BASE_EXPORT OverlayCandidatesOzone {
+ public:
+ struct OverlaySurfaceCandidate {
+ OverlaySurfaceCandidate();
+ ~OverlaySurfaceCandidate();
+
+ // Transformation to apply to layer during composition.
+ gfx::OverlayTransform transform = gfx::OVERLAY_TRANSFORM_NONE;
+ // Format of the buffer to composite.
+ SurfaceFactoryOzone::BufferFormat format = SurfaceFactoryOzone::UNKNOWN;
+ // Size of the buffer, in pixels.
+ gfx::Size buffer_size;
+ // Rect on the display to position the overlay to. Input rectangle may
+ // not have integer coordinates, but when accepting for overlay, must
+ // be modified by CheckOverlaySupport to output integer values.
+ gfx::RectF display_rect;
+ // Crop within the buffer to be placed inside |display_rect|.
+ gfx::RectF crop_rect;
+ // Stacking order of the overlay plane relative to the main surface,
+ // which is 0. Signed to allow for "underlays".
+ int plane_z_order = 0;
+
+ // To be modified by the implementer if this candidate can go into
+ // an overlay.
+ bool overlay_handled = false;
+ };
+
+ typedef std::vector<OverlaySurfaceCandidate> OverlaySurfaceCandidateList;
+
+ // A list of possible overlay candidates is presented to this function.
+ // The expected result is that those candidates that can be in a separate
+ // plane are marked with |overlay_handled| set to true, otherwise they are
+ // to be traditionally composited. When setting |overlay_handled| to true,
+ // the implementation must also snap |display_rect| to integer coordinates
+ // if necessary.
+ virtual void CheckOverlaySupport(OverlaySurfaceCandidateList* surfaces);
+
+ virtual ~OverlayCandidatesOzone();
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_OVERLAY_CANDIDATES_OZONE_H_
diff --git a/ui/ozone/public/overlay_manager_ozone.h b/ui/ozone/public/overlay_manager_ozone.h
new file mode 100644
index 0000000..5e8d94f
--- /dev/null
+++ b/ui/ozone/public/overlay_manager_ozone.h
@@ -0,0 +1,33 @@
+// Copyright 2015 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.
+
+#ifndef UI_OZONE_PUBLIC_OVERLAY_MANAGER_OZONE_H_
+#define UI_OZONE_PUBLIC_OVERLAY_MANAGER_OZONE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace ui {
+
+class OverlayCandidatesOzone;
+
+// Responsible for providing the oracles used to decide when overlays can be
+// used.
+class OverlayManagerOzone {
+ public:
+ virtual ~OverlayManagerOzone() {}
+
+ // Get the hal struct to check for overlay support.
+ virtual scoped_ptr<OverlayCandidatesOzone> CreateOverlayCandidates(
+ gfx::AcceleratedWidget w) = 0;
+
+ // Returns true if overlays can be shown at z-index 0, replacing the main
+ // surface. Combined with surfaceless extensions, it allows for an
+ // overlay-only mode.
+ virtual bool CanShowPrimaryPlaneAsOverlay() = 0;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_OVERLAY_MANAGER_OZONE_H_
diff --git a/ui/ozone/public/ozone_gpu_test_helper.h b/ui/ozone/public/ozone_gpu_test_helper.h
new file mode 100644
index 0000000..e342865
--- /dev/null
+++ b/ui/ozone/public/ozone_gpu_test_helper.h
@@ -0,0 +1,48 @@
+// 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.
+
+#ifndef UI_OZONE_PUBLIC_OZONE_GPU_THREAD_HELPER_H_
+#define UI_OZONE_PUBLIC_OZONE_GPU_THREAD_HELPER_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/ozone/ozone_export.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+class Thread;
+}
+
+namespace ui {
+
+class FakeGpuProcess;
+class FakeGpuProcessHost;
+
+// Helper class for applications that do not have a dedicated GPU channel.
+//
+// This sets up message forwarding between the "gpu" and "ui" threads.
+class OZONE_EXPORT OzoneGpuTestHelper {
+ public:
+ OzoneGpuTestHelper();
+ virtual ~OzoneGpuTestHelper();
+
+ // Start processing gpu messages. The host process will be using the
+ // |gpu_task_runner| to post messages intended for the GPU thread. The "gpu"
+ // process will be using the |ui_task_runner| to post messages intended for
+ // the "ui" thread.
+ bool Initialize(
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>& gpu_task_runner);
+
+ private:
+ scoped_ptr<FakeGpuProcess> fake_gpu_process_;
+ scoped_ptr<FakeGpuProcessHost> fake_gpu_process_host_;
+ scoped_ptr<base::Thread> io_helper_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(OzoneGpuTestHelper);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_OZONE_GPU_THREAD_HELPER_H_
diff --git a/ui/ozone/public/ozone_platform.cc b/ui/ozone/public/ozone_platform.cc
new file mode 100644
index 0000000..b69bc28
--- /dev/null
+++ b/ui/ozone/public/ozone_platform.cc
@@ -0,0 +1,81 @@
+// 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 "base/command_line.h"
+#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
+#include "ui/events/devices/device_data_manager.h"
+#include "ui/ozone/platform_object.h"
+#include "ui/ozone/platform_selection.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/ozone_switches.h"
+
+namespace ui {
+
+namespace {
+
+bool g_platform_initialized_ui = false;
+bool g_platform_initialized_gpu = false;
+
+}
+
+OzonePlatform::OzonePlatform() {
+ DCHECK(!instance_) << "There should only be a single OzonePlatform.";
+ instance_ = this;
+ g_platform_initialized_ui = false;
+ g_platform_initialized_gpu = false;
+}
+
+OzonePlatform::~OzonePlatform() {
+ DCHECK_EQ(instance_, this);
+ instance_ = NULL;
+}
+
+// static
+void OzonePlatform::InitializeForUI() {
+ CreateInstance();
+ if (g_platform_initialized_ui)
+ return;
+ g_platform_initialized_ui = true;
+ instance_->InitializeUI();
+ // This is deliberately created after initializing so that the platform can
+ // create its own version of DDM.
+ DeviceDataManager::CreateInstance();
+}
+
+// static
+void OzonePlatform::InitializeForGPU() {
+ CreateInstance();
+ if (g_platform_initialized_gpu)
+ return;
+ g_platform_initialized_gpu = true;
+ instance_->InitializeGPU();
+}
+
+// static
+OzonePlatform* OzonePlatform::GetInstance() {
+ DCHECK(instance_) << "OzonePlatform is not initialized";
+ return instance_;
+}
+
+// static
+void OzonePlatform::CreateInstance() {
+ if (!instance_) {
+ TRACE_EVENT1("ozone",
+ "OzonePlatform::Initialize",
+ "platform",
+ GetOzonePlatformName());
+ scoped_ptr<OzonePlatform> platform =
+ PlatformObject<OzonePlatform>::Create();
+
+ // TODO(spang): Currently need to leak this object.
+ OzonePlatform* pl = platform.release();
+ DCHECK_EQ(instance_, pl);
+ }
+}
+
+// static
+OzonePlatform* OzonePlatform::instance_;
+
+} // namespace ui
diff --git a/ui/ozone/public/ozone_platform.h b/ui/ozone/public/ozone_platform.h
new file mode 100644
index 0000000..590104b
--- /dev/null
+++ b/ui/ozone/public/ozone_platform.h
@@ -0,0 +1,85 @@
+// 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.
+
+#ifndef UI_OZONE_PUBLIC_OZONE_PLATFORM_H_
+#define UI_OZONE_PUBLIC_OZONE_PLATFORM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/ozone/ozone_export.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace ui {
+
+class CursorFactoryOzone;
+class InputController;
+class GpuPlatformSupport;
+class GpuPlatformSupportHost;
+class NativeDisplayDelegate;
+class OverlayManagerOzone;
+class PlatformWindow;
+class PlatformWindowDelegate;
+class SurfaceFactoryOzone;
+class SystemInputInjector;
+
+// Base class for Ozone platform implementations.
+//
+// Ozone platforms must override this class and implement the virtual
+// GetFooFactoryOzone() methods to provide implementations of the
+// various ozone interfaces.
+//
+// The OzonePlatform subclass can own any state needed by the
+// implementation that is shared between the various ozone interfaces,
+// such as a connection to the windowing system.
+//
+// A platform is free to use different implementations of each
+// interface depending on the context. You can, for example, create
+// different objects depending on the underlying hardware, command
+// line flags, or whatever is appropriate for the platform.
+class OZONE_EXPORT OzonePlatform {
+ public:
+ OzonePlatform();
+ virtual ~OzonePlatform();
+
+ // Initializes the subsystems/resources necessary for the UI process (e.g.
+ // events, surface, etc.)
+ static void InitializeForUI();
+
+ // Initializes the subsystems/resources necessary for the GPU process.
+ static void InitializeForGPU();
+
+ static OzonePlatform* GetInstance();
+
+ // Factory getters to override in subclasses. The returned objects will be
+ // injected into the appropriate layer at startup. Subclasses should not
+ // inject these objects themselves. Ownership is retained by OzonePlatform.
+ virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() = 0;
+ virtual ui::OverlayManagerOzone* GetOverlayManager() = 0;
+ virtual ui::CursorFactoryOzone* GetCursorFactoryOzone() = 0;
+ virtual ui::InputController* GetInputController() = 0;
+ virtual ui::GpuPlatformSupport* GetGpuPlatformSupport() = 0;
+ virtual ui::GpuPlatformSupportHost* GetGpuPlatformSupportHost() = 0;
+ virtual scoped_ptr<SystemInputInjector> CreateSystemInputInjector() = 0;
+ virtual scoped_ptr<PlatformWindow> CreatePlatformWindow(
+ PlatformWindowDelegate* delegate,
+ const gfx::Rect& bounds) = 0;
+ virtual scoped_ptr<ui::NativeDisplayDelegate>
+ CreateNativeDisplayDelegate() = 0;
+
+ private:
+ virtual void InitializeUI() = 0;
+ virtual void InitializeGPU() = 0;
+
+ static void CreateInstance();
+
+ static OzonePlatform* instance_;
+
+ DISALLOW_COPY_AND_ASSIGN(OzonePlatform);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_OZONE_PLATFORM_H_
diff --git a/ui/ozone/public/ozone_switches.cc b/ui/ozone/public/ozone_switches.cc
new file mode 100644
index 0000000..47b6b57
--- /dev/null
+++ b/ui/ozone/public/ozone_switches.cc
@@ -0,0 +1,30 @@
+// 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/public/ozone_switches.h"
+
+namespace switches {
+
+// Specify ozone platform implementation to use.
+const char kOzonePlatform[] = "ozone-platform";
+
+// Specify location for image dumps.
+const char kOzoneDumpFile[] = "ozone-dump-file";
+
+// Specify if the accelerated path should use surfaceless rendering. In this
+// mode there is no EGL surface.
+const char kOzoneUseSurfaceless[] = "ozone-use-surfaceless";
+
+// Enable support for a single overlay plane.
+const char kOzoneTestSingleOverlaySupport[] =
+ "ozone-test-single-overlay-support";
+
+// Specifies the size of the primary display at initialization.
+const char kOzoneInitialDisplayBounds[] = "ozone-initial-display-bounds";
+
+// Specifies the physical display size in millimeters.
+const char kOzoneInitialDisplayPhysicalSizeMm[] =
+ "ozone-initial-display-physical-size-mm";
+
+} // namespace switches
diff --git a/ui/ozone/public/ozone_switches.h b/ui/ozone/public/ozone_switches.h
new file mode 100644
index 0000000..4cc85a8
--- /dev/null
+++ b/ui/ozone/public/ozone_switches.h
@@ -0,0 +1,27 @@
+// 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.
+
+#ifndef UI_OZONE_PUBLIC_OZONE_SWITCHES_H_
+#define UI_OZONE_PUBLIC_OZONE_SWITCHES_H_
+
+#include "base/compiler_specific.h"
+#include "ui/ozone/ozone_export.h"
+
+namespace switches {
+
+OZONE_EXPORT extern const char kOzonePlatform[];
+
+OZONE_EXPORT extern const char kOzoneDumpFile[];
+
+OZONE_EXPORT extern const char kOzoneUseSurfaceless[];
+
+OZONE_EXPORT extern const char kOzoneTestSingleOverlaySupport[];
+
+OZONE_EXPORT extern const char kOzoneInitialDisplayBounds[];
+
+OZONE_EXPORT extern const char kOzoneInitialDisplayPhysicalSizeMm[];
+
+} // namespace switches
+
+#endif // UI_OZONE_PUBLIC_OZONE_SWITCHES_H_
diff --git a/ui/ozone/public/surface_factory_ozone.cc b/ui/ozone/public/surface_factory_ozone.cc
new file mode 100644
index 0000000..70a81ad
--- /dev/null
+++ b/ui/ozone/public/surface_factory_ozone.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2013 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/public/surface_factory_ozone.h"
+
+#include <stdlib.h>
+
+#include "base/command_line.h"
+#include "ui/ozone/public/native_pixmap.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+namespace ui {
+
+SurfaceFactoryOzone::SurfaceFactoryOzone() {
+}
+
+SurfaceFactoryOzone::~SurfaceFactoryOzone() {
+}
+
+intptr_t SurfaceFactoryOzone::GetNativeDisplay() {
+ return 0;
+}
+
+scoped_ptr<SurfaceOzoneEGL> SurfaceFactoryOzone::CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget) {
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+scoped_ptr<SurfaceOzoneEGL>
+SurfaceFactoryOzone::CreateSurfacelessEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget) {
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+scoped_ptr<SurfaceOzoneCanvas> SurfaceFactoryOzone::CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget) {
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+const int32* SurfaceFactoryOzone::GetEGLSurfaceProperties(
+ const int32* desired_attributes) {
+ return desired_attributes;
+}
+
+scoped_refptr<ui::NativePixmap> SurfaceFactoryOzone::CreateNativePixmap(
+ gfx::AcceleratedWidget widget,
+ gfx::Size size,
+ BufferFormat format,
+ BufferUsage usage) {
+ return NULL;
+}
+
+bool SurfaceFactoryOzone::CanShowPrimaryPlaneAsOverlay() {
+ return false;
+}
+
+bool SurfaceFactoryOzone::CanCreateNativePixmap(BufferUsage usage) {
+ return false;
+}
+
+} // namespace ui
diff --git a/ui/ozone/public/surface_factory_ozone.h b/ui/ozone/public/surface_factory_ozone.h
new file mode 100644
index 0000000..4dc5572
--- /dev/null
+++ b/ui/ozone/public/surface_factory_ozone.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2013 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.
+
+#ifndef UI_OZONE_PUBLIC_SURFACE_FACTORY_OZONE_H_
+#define UI_OZONE_PUBLIC_SURFACE_FACTORY_OZONE_H_
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/native_library.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/overlay_transform.h"
+#include "ui/ozone/ozone_base_export.h"
+
+namespace ui {
+
+class NativePixmap;
+class SurfaceOzoneCanvas;
+class SurfaceOzoneEGL;
+
+// The Ozone interface allows external implementations to hook into Chromium to
+// provide a system specific implementation. The Ozone interface supports two
+// drawing modes: 1) accelerated drawing through EGL and 2) software drawing
+// through Skia.
+//
+// If you want to paint on a window with ozone, you need to create a
+// SurfaceOzoneEGL or SurfaceOzoneCanvas for that window. The platform can
+// support software, EGL, or both for painting on the window.
+// The following functionality is specific to the drawing mode and may not have
+// any meaningful implementation in the other mode. An implementation must
+// provide functionality for at least one mode.
+//
+// 1) Accelerated Drawing (EGL path):
+//
+// The following functions are specific to EGL:
+// - GetNativeDisplay
+// - LoadEGLGLES2Bindings
+// - GetEGLSurfaceProperties (optional if the properties match the default
+// Chromium ones).
+// - CreateEGLSurfaceForWidget
+//
+// 2) Software Drawing (Skia):
+//
+// The following function is specific to the software path:
+// - CreateCanvasForWidget
+//
+// The accelerated path can optionally provide support for the software drawing
+// path.
+//
+// The remaining functions are not covered since they are needed in both drawing
+// modes (See comments bellow for descriptions).
+class OZONE_BASE_EXPORT SurfaceFactoryOzone {
+ public:
+ // Describes overlay buffer format.
+ // TODO: this is a placeholder for now and will be populated with more
+ // formats once we know what sorts of content, video, etc. we can support.
+ enum BufferFormat {
+ UNKNOWN,
+ BGRA_8888,
+ RGBX_8888,
+ BUFFER_FORMAT_LAST = RGBX_8888
+ };
+
+ enum BufferUsage {
+ MAP,
+ PERSISTENT_MAP,
+ SCANOUT,
+ };
+
+ typedef void* (*GLGetProcAddressProc)(const char* name);
+ typedef base::Callback<void(base::NativeLibrary)> AddGLLibraryCallback;
+ typedef base::Callback<void(GLGetProcAddressProc)>
+ SetGLGetProcAddressProcCallback;
+
+ // Returns native platform display handle. This is used to obtain the EGL
+ // display connection for the native display.
+ virtual intptr_t GetNativeDisplay();
+
+ // Create SurfaceOzoneEGL for the specified gfx::AcceleratedWidget.
+ //
+ // Note: When used from content, this is called in the GPU process. The
+ // platform must support creation of SurfaceOzoneEGL from the GPU process
+ // using only the handle contained in gfx::AcceleratedWidget.
+ virtual scoped_ptr<SurfaceOzoneEGL> CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget);
+
+ // Create an EGL surface that isn't backed by any buffers, and is used
+ // for overlay-only displays. This will return NULL if this mode is
+ // not supported.
+ virtual scoped_ptr<SurfaceOzoneEGL> CreateSurfacelessEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget);
+
+ // Create SurfaceOzoneCanvas for the specified gfx::AcceleratedWidget.
+ //
+ // Note: The platform must support creation of SurfaceOzoneCanvas from the
+ // Browser Process using only the handle contained in gfx::AcceleratedWidget.
+ virtual scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget);
+
+ // Sets up GL bindings for the native surface. Takes two callback parameters
+ // that allow Ozone to register the GL bindings.
+ virtual bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) = 0;
+
+ // Returns an array of EGL properties, which can be used in any EGL function
+ // used to select a display configuration. Note that all properties should be
+ // immediately followed by the corresponding desired value and array should be
+ // terminated with EGL_NONE. Ownership of the array is not transferred to
+ // caller. desired_list contains list of desired EGL properties and values.
+ virtual const int32* GetEGLSurfaceProperties(const int32* desired_list);
+
+ // Create a single native buffer to be used for overlay planes or zero copy
+ // for |widget| representing a particular display controller or default
+ // display controller for kNullAcceleratedWidget.
+ // It can be called on any thread.
+ virtual scoped_refptr<NativePixmap> CreateNativePixmap(
+ gfx::AcceleratedWidget widget,
+ gfx::Size size,
+ BufferFormat format,
+ BufferUsage usage);
+
+ // Returns true if overlays can be shown at z-index 0, replacing the main
+ // surface. Combined with surfaceless extensions, it allows for an
+ // overlay-only mode.
+ virtual bool CanShowPrimaryPlaneAsOverlay();
+
+ // Returns true if the platform is able to create buffers for a specific usage
+ // such as MAP for zero copy or SCANOUT for display controller.
+ virtual bool CanCreateNativePixmap(BufferUsage usage);
+
+ protected:
+ SurfaceFactoryOzone();
+ virtual ~SurfaceFactoryOzone();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SurfaceFactoryOzone);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_SURFACE_FACTORY_OZONE_H_
diff --git a/ui/ozone/public/surface_ozone_canvas.h b/ui/ozone/public/surface_ozone_canvas.h
new file mode 100644
index 0000000..42347c3
--- /dev/null
+++ b/ui/ozone/public/surface_ozone_canvas.h
@@ -0,0 +1,56 @@
+// 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.
+
+#ifndef UI_OZONE_PUBLIC_SURFACE_OZONE_CANVAS_H_
+#define UI_OZONE_PUBLIC_SURFACE_OZONE_CANVAS_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "skia/ext/refptr.h"
+#include "ui/ozone/ozone_base_export.h"
+
+class SkSurface;
+
+namespace gfx {
+class Size;
+class VSyncProvider;
+}
+
+namespace ui {
+
+// The platform-specific part of an software output. The class is intended
+// for use when no EGL/GLES2 acceleration is possible.
+// This class owns any bits that the ozone implementation needs freed when
+// the software output is destroyed.
+class OZONE_BASE_EXPORT SurfaceOzoneCanvas {
+ public:
+ virtual ~SurfaceOzoneCanvas() {}
+
+ // Returns an SkSurface for drawing on the window.
+ virtual skia::RefPtr<SkSurface> GetSurface() = 0;
+
+ // Attempts to resize the canvas to match the viewport size. After
+ // resizing, the compositor must call GetCanvas() to get the next
+ // canvas - this invalidates any previous canvas from GetCanvas().
+ virtual void ResizeCanvas(const gfx::Size& viewport_size) = 0;
+
+ // Present the current canvas. After presenting, the compositor must
+ // call GetCanvas() to get the next canvas - this invalidates any
+ // previous canvas from GetCanvas().
+ //
+ // The implementation may assume that any pixels outside the damage
+ // rectangle are unchanged since the previous call to PresentCanvas().
+ virtual void PresentCanvas(const gfx::Rect& damage) = 0;
+
+ // Returns a gfx::VsyncProvider for this surface. Note that this may be
+ // called after we have entered the sandbox so if there are operations (e.g.
+ // opening a file descriptor providing vsync events) that must be done
+ // outside of the sandbox, they must have been completed in
+ // InitializeHardware. Returns an empty scoped_ptr on error.
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() = 0;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_SURFACE_OZONE_CANVAS_H_
diff --git a/ui/ozone/public/surface_ozone_egl.cc b/ui/ozone/public/surface_ozone_egl.cc
new file mode 100644
index 0000000..92330f3
--- /dev/null
+++ b/ui/ozone/public/surface_ozone_egl.cc
@@ -0,0 +1,13 @@
+// Copyright 2015 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/public/surface_ozone_egl.h"
+
+namespace ui {
+
+bool SurfaceOzoneEGL::IsUniversalDisplayLinkDevice() {
+ return false;
+}
+
+} // namespace ui
diff --git a/ui/ozone/public/surface_ozone_egl.h b/ui/ozone/public/surface_ozone_egl.h
new file mode 100644
index 0000000..3056dec
--- /dev/null
+++ b/ui/ozone/public/surface_ozone_egl.h
@@ -0,0 +1,64 @@
+// 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.
+
+#ifndef UI_OZONE_PUBLIC_SURFACE_OZONE_EGL_H_
+#define UI_OZONE_PUBLIC_SURFACE_OZONE_EGL_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/overlay_transform.h"
+#include "ui/gfx/swap_result.h"
+#include "ui/ozone/ozone_base_export.h"
+
+namespace gfx {
+class Size;
+class VSyncProvider;
+}
+
+namespace ui {
+class NativePixmap;
+
+typedef base::Callback<void(gfx::SwapResult)> SwapCompletionCallback;
+
+// The platform-specific part of an EGL surface.
+//
+// This class owns any bits that the ozone implementation needs freed when
+// the EGL surface is destroyed.
+class OZONE_BASE_EXPORT SurfaceOzoneEGL {
+ public:
+ virtual ~SurfaceOzoneEGL() {}
+
+ // Returns the EGL native window for rendering onto this surface.
+ // This can be used to to create a GLSurface.
+ virtual intptr_t /* EGLNativeWindowType */ GetNativeWindow() = 0;
+
+ // Attempts to resize the EGL native window to match the viewport
+ // size.
+ virtual bool ResizeNativeWindow(const gfx::Size& viewport_size) = 0;
+
+ // Called after we swap buffers. This is usually a no-op but can
+ // be used to present the new front buffer if the platform requires this.
+ virtual bool OnSwapBuffers() = 0;
+
+ // Called after we swap buffers. This is usually a no-op but can
+ // be used to present the new front buffer if the platform requires this.
+ // The callback should be run on the calling thread
+ // (i.e. same thread SwapBuffersAsync is called).
+ virtual bool OnSwapBuffersAsync(const SwapCompletionCallback& callback) = 0;
+
+ // Returns a gfx::VsyncProvider for this surface. Note that this may be
+ // called after we have entered the sandbox so if there are operations (e.g.
+ // opening a file descriptor providing vsync events) that must be done
+ // outside of the sandbox, they must have been completed in
+ // InitializeHardware. Returns an empty scoped_ptr on error.
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() = 0;
+
+ // Returns true if the surface is created on a UDL device.
+ virtual bool IsUniversalDisplayLinkDevice();
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_SURFACE_OZONE_EGL_H_
diff --git a/ui/ozone/public/system_input_injector.h b/ui/ozone/public/system_input_injector.h
new file mode 100644
index 0000000..0bfb278
--- /dev/null
+++ b/ui/ozone/public/system_input_injector.h
@@ -0,0 +1,56 @@
+// 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.
+
+#ifndef UI_OZONE_PUBLIC_SYSTEM_INPUT_INJECTOR_H_
+#define UI_OZONE_PUBLIC_SYSTEM_INPUT_INJECTOR_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/ozone/ozone_export.h"
+
+namespace gfx {
+class PointF;
+} // namespace gfx
+
+namespace ui {
+class Event;
+
+// Interface for converting input into ui::Events and injecting them to the
+// Ozone platform.
+class OZONE_EXPORT SystemInputInjector {
+ public:
+ SystemInputInjector() {}
+ virtual ~SystemInputInjector() {}
+
+ // Moves the cursor on the screen and generates the corresponding MouseMove or
+ // MouseDragged event. |location| is in physical screen co-ordinates,
+ // independent of the scale factor and the display rotation settings.
+ virtual void MoveCursorTo(const gfx::PointF& location) = 0;
+
+ // Simulates a mouse button click. |button| must be one of
+ // EF_LEFT_MOUSE_BUTTON, EF_RIGHT_MOUSE_BUTTON or EF_MIDDLE_MOUSE_BUTTON.
+ // SystemInputInjector will apply the correct modifiers (shift, ctrl, etc).
+ virtual void InjectMouseButton(EventFlags button, bool down) = 0;
+
+ // |delta_x| and |delta_y| are in physical pixels independent of the scale
+ // factor.
+ virtual void InjectMouseWheel(int delta_x, int delta_y) = 0;
+
+ // Simulates a key event. SystemInputInjector maps |physical_key| to the
+ // correct logical key based on the current keyboard layout. |down| is true
+ // for presses. If |suppress_auto_repeat| is set, the platform must not
+ // auto-repeat the event.
+ virtual void InjectKeyEvent(DomCode physical_key,
+ bool down,
+ bool suppress_auto_repeat) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SystemInputInjector);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_SYSTEM_INPUT_INJECTOR_H_
diff --git a/ui/ozone/run_all_unittests.cc b/ui/ozone/run_all_unittests.cc
new file mode 100644
index 0000000..5f038b3
--- /dev/null
+++ b/ui/ozone/run_all_unittests.cc
@@ -0,0 +1,45 @@
+// 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 "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "build/build_config.h"
+
+namespace {
+
+class OzoneTestSuite : public base::TestSuite {
+ public:
+ OzoneTestSuite(int argc, char** argv);
+
+ protected:
+ // base::TestSuite:
+ void Initialize() override;
+ void Shutdown() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OzoneTestSuite);
+};
+
+OzoneTestSuite::OzoneTestSuite(int argc, char** argv)
+ : base::TestSuite(argc, argv) {}
+
+void OzoneTestSuite::Initialize() {
+ base::TestSuite::Initialize();
+}
+
+void OzoneTestSuite::Shutdown() {
+ base::TestSuite::Shutdown();
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+ OzoneTestSuite test_suite(argc, argv);
+
+ return base::LaunchUnitTests(argc,
+ argv,
+ base::Bind(&OzoneTestSuite::Run,
+ base::Unretained(&test_suite)));
+}