Clone of chromium aad1ce808763f59c7a3753e08f1500a104ecc6fd refs/remotes/origin/HEAD
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/caca/BUILD.gn b/ui/ozone/platform/caca/BUILD.gn
new file mode 100644
index 0000000..085925d
--- /dev/null
+++ b/ui/ozone/platform/caca/BUILD.gn
@@ -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.
+
+import("//build/config/linux/pkg_config.gni")
+
+source_set("caca") {
+ sources = [
+ "caca_event_source.cc",
+ "caca_event_source.h",
+ "caca_window.cc",
+ "caca_window.h",
+ "caca_window_manager.cc",
+ "caca_window_manager.h",
+ "ozone_platform_caca.cc",
+ "ozone_platform_caca.h",
+ "scoped_caca_types.cc",
+ "scoped_caca_types.h",
+ ]
+
+ deps = [
+ "//base",
+ "//skia",
+ "//ui/gfx/geometry",
+ ]
+
+ configs += [
+ ":libcaca",
+ ]
+}
+
+pkg_config("libcaca") {
+ packages = [ "caca" ]
+}
diff --git a/ui/ozone/platform/caca/OWNERS b/ui/ozone/platform/caca/OWNERS
new file mode 100644
index 0000000..0d77c0e
--- /dev/null
+++ b/ui/ozone/platform/caca/OWNERS
@@ -0,0 +1 @@
+dnicoara@chromium.org
diff --git a/ui/ozone/platform/caca/caca.gypi b/ui/ozone/platform/caca/caca.gypi
new file mode 100644
index 0000000..34a5e69
--- /dev/null
+++ b/ui/ozone/platform/caca/caca.gypi
@@ -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.
+
+{
+ 'variables': {
+ 'internal_ozone_platform_deps': [
+ 'ozone_platform_caca',
+ ],
+ 'internal_ozone_platforms': [
+ 'caca'
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'ozone_platform_caca',
+ 'type': 'static_library',
+ 'defines': [
+ 'OZONE_IMPLEMENTATION',
+ ],
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../skia/skia.gyp:skia',
+ '../events/events.gyp:events',
+ '../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-lcaca',
+ ],
+ },
+ 'sources': [
+ 'caca_event_source.cc',
+ 'caca_event_source.h',
+ 'caca_window.cc',
+ 'caca_window.h',
+ 'caca_window_manager.cc',
+ 'caca_window_manager.h',
+ 'ozone_platform_caca.cc',
+ 'ozone_platform_caca.h',
+ 'scoped_caca_types.cc',
+ 'scoped_caca_types.h',
+ ],
+ },
+ ],
+}
diff --git a/ui/ozone/platform/caca/caca_event_source.cc b/ui/ozone/platform/caca/caca_event_source.cc
new file mode 100644
index 0000000..a8da8b4
--- /dev/null
+++ b/ui/ozone/platform/caca/caca_event_source.cc
@@ -0,0 +1,229 @@
+// 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/caca/caca_event_source.h"
+
+#include <caca.h>
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/events/event.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/ozone/platform/caca/caca_window.h"
+
+namespace ui {
+
+namespace {
+
+ui::KeyboardCode GetKeyboardCode(const caca_event_t& event) {
+ // List of special mappings the Caca provides.
+ static const ui::KeyboardCode kCacaKeyMap[] = {
+ ui::VKEY_UNKNOWN,
+ ui::VKEY_A,
+ ui::VKEY_B,
+ ui::VKEY_C,
+ ui::VKEY_D,
+ ui::VKEY_E,
+ ui::VKEY_F,
+ ui::VKEY_G,
+ ui::VKEY_BACK,
+ ui::VKEY_TAB,
+ ui::VKEY_J,
+ ui::VKEY_K,
+ ui::VKEY_L,
+ ui::VKEY_RETURN,
+ ui::VKEY_N,
+ ui::VKEY_O,
+ ui::VKEY_P,
+ ui::VKEY_Q,
+ ui::VKEY_R,
+ ui::VKEY_PAUSE,
+ ui::VKEY_T,
+ ui::VKEY_U,
+ ui::VKEY_V,
+ ui::VKEY_W,
+ ui::VKEY_X,
+ ui::VKEY_Y,
+ ui::VKEY_Z,
+ ui::VKEY_ESCAPE,
+ ui::VKEY_DELETE,
+ ui::VKEY_UP,
+ ui::VKEY_DOWN,
+ ui::VKEY_LEFT,
+ ui::VKEY_RIGHT,
+ ui::VKEY_INSERT,
+ ui::VKEY_HOME,
+ ui::VKEY_END,
+ ui::VKEY_PRIOR,
+ ui::VKEY_NEXT,
+ ui::VKEY_F1,
+ ui::VKEY_F2,
+ ui::VKEY_F3,
+ ui::VKEY_F4,
+ ui::VKEY_F5,
+ ui::VKEY_F6,
+ ui::VKEY_F7,
+ ui::VKEY_F8,
+ ui::VKEY_F9,
+ ui::VKEY_F10,
+ ui::VKEY_F11,
+ ui::VKEY_F12,
+ };
+
+ int key_code = caca_get_event_key_ch(&event);
+ if (key_code >= 'a' && key_code <= 'z')
+ return static_cast<ui::KeyboardCode>(key_code - ('a' - 'A'));
+ if (key_code >= '0' && key_code <= 'Z')
+ return static_cast<ui::KeyboardCode>(key_code);
+ if (static_cast<unsigned int>(key_code) < arraysize(kCacaKeyMap))
+ return kCacaKeyMap[key_code];
+
+ return ui::VKEY_UNKNOWN;
+}
+
+int ModifierFromKey(const caca_event_t& event) {
+ int key_code = caca_get_event_key_ch(&event);
+ if (key_code >= 'A' && key_code <= 'Z')
+ return ui::EF_SHIFT_DOWN;
+ if ((key_code >= CACA_KEY_CTRL_A && key_code <= CACA_KEY_CTRL_G) ||
+ (key_code >= CACA_KEY_CTRL_J && key_code <= CACA_KEY_CTRL_L) ||
+ (key_code >= CACA_KEY_CTRL_N && key_code <= CACA_KEY_CTRL_R) ||
+ (key_code >= CACA_KEY_CTRL_T && key_code <= CACA_KEY_CTRL_Z))
+ return ui::EF_CONTROL_DOWN;
+
+ return ui::EF_NONE;
+}
+
+int ModifierFromButton(const caca_event_t& event) {
+ switch (caca_get_event_mouse_button(&event)) {
+ case 1:
+ return ui::EF_LEFT_MOUSE_BUTTON;
+ case 2:
+ return ui::EF_RIGHT_MOUSE_BUTTON;
+ case 3:
+ return ui::EF_MIDDLE_MOUSE_BUTTON;
+ }
+ return 0;
+}
+
+// Translate coordinates to bitmap coordinates.
+gfx::PointF TranslateLocation(const gfx::PointF& location, CacaWindow* window) {
+ gfx::Size physical_size = window->physical_size();
+ gfx::Size bitmap_size = window->bitmap_size();
+ return gfx::PointF(
+ location.x() * bitmap_size.width() / physical_size.width(),
+ location.y() * bitmap_size.height() / physical_size.height());
+}
+
+ui::EventType GetEventTypeFromNative(const caca_event_t& event) {
+ switch (caca_get_event_type(&event)) {
+ case CACA_EVENT_KEY_PRESS:
+ return ui::ET_KEY_PRESSED;
+ case CACA_EVENT_KEY_RELEASE:
+ return ui::ET_KEY_RELEASED;
+ case CACA_EVENT_MOUSE_PRESS:
+ return ui::ET_MOUSE_PRESSED;
+ case CACA_EVENT_MOUSE_RELEASE:
+ return ui::ET_MOUSE_RELEASED;
+ case CACA_EVENT_MOUSE_MOTION:
+ return ui::ET_MOUSE_MOVED;
+ default:
+ return ui::ET_UNKNOWN;
+ }
+}
+
+} // namespace
+
+CacaEventSource::CacaEventSource() : modifier_flags_(0) {
+}
+
+CacaEventSource::~CacaEventSource() {
+}
+
+void CacaEventSource::TryProcessingEvent(CacaWindow* window) {
+ if (!window->display())
+ return;
+
+ caca_event_t event;
+ int event_mask = CACA_EVENT_KEY_PRESS | CACA_EVENT_KEY_RELEASE |
+ CACA_EVENT_MOUSE_PRESS | CACA_EVENT_MOUSE_RELEASE |
+ CACA_EVENT_MOUSE_MOTION | CACA_EVENT_RESIZE |
+ CACA_EVENT_QUIT;
+
+ if (!caca_get_event(window->display(), event_mask, &event, 0))
+ return;
+
+ switch (caca_get_event_type(&event)) {
+ case CACA_EVENT_KEY_PRESS:
+ case CACA_EVENT_KEY_RELEASE:
+ case CACA_EVENT_MOUSE_PRESS:
+ case CACA_EVENT_MOUSE_RELEASE:
+ case CACA_EVENT_MOUSE_MOTION:
+ OnInputEvent(&event, window);
+ break;
+ case CACA_EVENT_RESIZE:
+ window->OnCacaResize();
+ break;
+ case CACA_EVENT_QUIT:
+ window->OnCacaQuit();
+ break;
+ default:
+ NOTIMPLEMENTED();
+ }
+}
+
+void CacaEventSource::OnInputEvent(caca_event_t* event, CacaWindow* window) {
+ ui::EventType type = GetEventTypeFromNative(*event);
+ bool pressed = type == ui::ET_KEY_PRESSED || type == ui::ET_MOUSE_PRESSED;
+
+ switch (type) {
+ case ui::ET_KEY_PRESSED:
+ case ui::ET_KEY_RELEASED: {
+ if (pressed)
+ modifier_flags_ |= ModifierFromKey(*event);
+ else
+ modifier_flags_ &= ~ModifierFromKey(*event);
+
+ ui::KeyEvent key_event(
+ type, GetKeyboardCode(*event), modifier_flags_);
+ window->OnCacaEvent(&key_event);
+ break;
+ }
+ case ui::ET_MOUSE_MOVED:
+ last_cursor_location_.SetPoint(caca_get_event_mouse_x(event),
+ caca_get_event_mouse_y(event));
+ // Update cursor location.
+ caca_gotoxy(caca_get_canvas(window->display()),
+ last_cursor_location_.x(),
+ last_cursor_location_.y());
+
+ // fallthrough
+ case ui::ET_MOUSE_PRESSED:
+ case ui::ET_MOUSE_RELEASED: {
+ int flags = 0;
+ int changed_flags = 0;
+ if (type != ui::ET_MOUSE_MOVED) {
+ if (pressed) {
+ changed_flags = ModifierFromButton(*event);
+ modifier_flags_ |= changed_flags;
+ } else {
+ modifier_flags_ &= ~changed_flags;
+ }
+ // On release the button pressed is removed from |modifier_flags_|,
+ // but sending the event needs it set.
+ flags = modifier_flags_ | changed_flags;
+ }
+ gfx::PointF location = TranslateLocation(last_cursor_location_, window);
+ ui::MouseEvent mouse_event(
+ type, location, location, flags, changed_flags);
+ window->OnCacaEvent(&mouse_event);
+ break;
+ }
+ default:
+ NOTIMPLEMENTED();
+ break;
+ }
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/caca/caca_event_source.h b/ui/ozone/platform/caca/caca_event_source.h
new file mode 100644
index 0000000..daa7fc9
--- /dev/null
+++ b/ui/ozone/platform/caca/caca_event_source.h
@@ -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.
+
+#ifndef UI_OZONE_PLATFORM_CACA_CACA_EVENT_SOURCE_H_
+#define UI_OZONE_PLATFORM_CACA_CACA_EVENT_SOURCE_H_
+
+#include <caca.h>
+
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/events/platform/scoped_event_dispatcher.h"
+#include "ui/gfx/geometry/point_f.h"
+
+namespace ui {
+
+class CacaWindow;
+
+class CacaEventSource : public PlatformEventSource {
+ public:
+ CacaEventSource();
+ virtual ~CacaEventSource();
+
+ // Poll for an event on a particular window. Input events will be
+ // dispatched on the given dispatcher.
+ void TryProcessingEvent(CacaWindow* window);
+
+ // Process an input event on a particular window.
+ void OnInputEvent(caca_event_t* event, CacaWindow* window);
+
+ private:
+ // Keep track of last cursor position to dispatch correct mouse push/release
+ // events.
+ gfx::PointF last_cursor_location_;
+
+ int modifier_flags_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacaEventSource);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_CACA_CACA_EVENT_SOURCE_H_
diff --git a/ui/ozone/platform/caca/caca_window.cc b/ui/ozone/platform/caca/caca_window.cc
new file mode 100644
index 0000000..ff2f571
--- /dev/null
+++ b/ui/ozone/platform/caca/caca_window.cc
@@ -0,0 +1,146 @@
+// 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/caca/caca_window.h"
+
+#include "base/bind.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/events/ozone/events_ozone.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/ozone/platform/caca/caca_event_source.h"
+#include "ui/ozone/platform/caca/caca_window_manager.h"
+#include "ui/platform_window/platform_window_delegate.h"
+
+namespace ui {
+
+namespace {
+
+// Size of initial cnavas (in characters).
+const int kDefaultCanvasWidth = 160;
+const int kDefaultCanvasHeight = 48;
+
+} // namespace
+
+// TODO(dnicoara) As an optimization, |bitmap_size_| should be scaled based on
+// |physical_size_| and font size.
+CacaWindow::CacaWindow(PlatformWindowDelegate* delegate,
+ CacaWindowManager* manager,
+ CacaEventSource* event_source,
+ const gfx::Rect& bounds)
+ : delegate_(delegate),
+ manager_(manager),
+ event_source_(event_source),
+ weak_ptr_factory_(this) {
+ widget_ = manager_->AddWindow(this);
+ ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
+ delegate_->OnAcceleratedWidgetAvailable(widget_);
+}
+
+CacaWindow::~CacaWindow() {
+ ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
+ manager_->RemoveWindow(widget_, this);
+}
+
+bool CacaWindow::Initialize() {
+ if (display_)
+ return true;
+
+ canvas_.reset(caca_create_canvas(kDefaultCanvasWidth, kDefaultCanvasHeight));
+ if (!canvas_) {
+ PLOG(ERROR) << "failed to create libcaca canvas";
+ return false;
+ }
+
+ display_.reset(caca_create_display(canvas_.get()));
+ if (!display_) {
+ PLOG(ERROR) << "failed to initialize libcaca display";
+ return false;
+ }
+
+ caca_set_cursor(display_.get(), 1);
+ caca_set_display_title(display_.get(), "Ozone Content Shell");
+
+ UpdateDisplaySize();
+
+ TryProcessingEvent();
+
+ return true;
+}
+
+void CacaWindow::TryProcessingEvent() {
+ event_source_->TryProcessingEvent(this);
+
+ // Caca uses a poll based event retrieval. Since we don't want to block we'd
+ // either need to spin up a new thread or just poll. For simplicity just poll
+ // for messages.
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&CacaWindow::TryProcessingEvent,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(10));
+}
+
+void CacaWindow::UpdateDisplaySize() {
+ physical_size_.SetSize(caca_get_canvas_width(canvas_.get()),
+ caca_get_canvas_height(canvas_.get()));
+
+ bitmap_size_.SetSize(caca_get_display_width(display_.get()),
+ caca_get_display_height(display_.get()));
+}
+
+void CacaWindow::OnCacaResize() {
+ UpdateDisplaySize();
+
+ delegate_->OnBoundsChanged(gfx::Rect(bitmap_size_));
+}
+
+void CacaWindow::OnCacaQuit() {
+ delegate_->OnCloseRequest();
+}
+
+
+void CacaWindow::OnCacaEvent(ui::Event* event) {
+ DispatchEventFromNativeUiEvent(
+ event,
+ base::Bind(&PlatformWindowDelegate::DispatchEvent,
+ base::Unretained(delegate_)));
+}
+
+gfx::Rect CacaWindow::GetBounds() { return gfx::Rect(bitmap_size_); }
+
+void CacaWindow::SetBounds(const gfx::Rect& bounds) {}
+
+void CacaWindow::Show() {}
+
+void CacaWindow::Hide() {}
+
+void CacaWindow::Close() {}
+
+void CacaWindow::SetCapture() {}
+
+void CacaWindow::ReleaseCapture() {}
+
+void CacaWindow::ToggleFullscreen() {}
+
+void CacaWindow::Maximize() {}
+
+void CacaWindow::Minimize() {}
+
+void CacaWindow::Restore() {}
+
+void CacaWindow::SetCursor(PlatformCursor cursor) {}
+
+void CacaWindow::MoveCursorTo(const gfx::Point& location) {}
+
+bool CacaWindow::CanDispatchEvent(const PlatformEvent& event) { return true; }
+
+uint32_t CacaWindow::DispatchEvent(const PlatformEvent& ne) {
+ // We don't dispatch events via PlatformEventSource.
+ NOTREACHED();
+ return ui::POST_DISPATCH_STOP_PROPAGATION;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/caca/caca_window.h b/ui/ozone/platform/caca/caca_window.h
new file mode 100644
index 0000000..444f3d5
--- /dev/null
+++ b/ui/ozone/platform/caca/caca_window.h
@@ -0,0 +1,97 @@
+// 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_CACA_CACA_WINDOW_H_
+#define UI_OZONE_PLATFORM_CACA_CACA_WINDOW_H_
+
+#include <caca.h>
+
+#include "base/debug/stack_trace.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/caca/scoped_caca_types.h"
+#include "ui/platform_window/platform_window.h"
+
+namespace ui {
+
+class CacaEventSource;
+class CacaWindowManager;
+class PlatformWindowDelegate;
+
+// Basic initialization of Libcaca. This needs to be shared between SFO and EFO
+// since both need the |display_| to draw and process events respectively.
+// Note, |canvas_| needs to be here since it is needed for creating a
+// |display_|.
+class CacaWindow : public PlatformWindow, public PlatformEventDispatcher {
+ public:
+ CacaWindow(PlatformWindowDelegate* delegate,
+ CacaWindowManager* manager,
+ CacaEventSource* event_source,
+ const gfx::Rect& bounds);
+ virtual ~CacaWindow();
+
+ bool Initialize();
+
+ // Handlers for events received from libcaca.
+ void OnCacaQuit();
+ void OnCacaResize();
+ void OnCacaEvent(ui::Event* event);
+
+ // This is the Caca canvas size.
+ gfx::Size physical_size() const { return physical_size_; }
+ gfx::Size bitmap_size() const { return bitmap_size_; }
+ caca_display_t* display() const { return display_.get(); }
+
+ // PlatformWindow:
+ virtual gfx::Rect GetBounds() OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual void ToggleFullscreen() OVERRIDE;
+ virtual void Maximize() OVERRIDE;
+ virtual void Minimize() OVERRIDE;
+ virtual void Restore() OVERRIDE;
+ virtual void SetCursor(PlatformCursor cursor) OVERRIDE;
+ virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
+
+ // PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const PlatformEvent& event) OVERRIDE;
+ virtual uint32_t DispatchEvent(const PlatformEvent& event) OVERRIDE;
+
+ private:
+ // Event polling.
+ void TryProcessingEvent();
+
+ // Sync sizes with libcaca.
+ void UpdateDisplaySize();
+
+ PlatformWindowDelegate* delegate_;
+ CacaWindowManager* manager_;
+ CacaEventSource* event_source_;
+ gfx::AcceleratedWidget widget_;
+
+ ScopedCacaCanvas canvas_;
+ ScopedCacaDisplay display_;
+
+ // Size of the console in characters. This can be changed by setting
+ // CACA_GEOMETRY environment variable.
+ gfx::Size physical_size_;
+
+ // Size of the backing buffer we draw into. Size in pixels.
+ gfx::Size bitmap_size_;
+
+ base::WeakPtrFactory<CacaWindow> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacaWindow);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_CACA_CACA_WINDOW_H_
diff --git a/ui/ozone/platform/caca/caca_window_manager.cc b/ui/ozone/platform/caca/caca_window_manager.cc
new file mode 100644
index 0000000..9dbbc6b
--- /dev/null
+++ b/ui/ozone/platform/caca/caca_window_manager.cc
@@ -0,0 +1,141 @@
+// 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/caca/caca_window_manager.h"
+
+#include "base/debug/trace_event.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/gfx/vsync_provider.h"
+#include "ui/ozone/platform/caca/caca_window.h"
+#include "ui/ozone/platform/caca/scoped_caca_types.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+
+namespace ui {
+
+namespace {
+
+class CacaSurface : public ui::SurfaceOzoneCanvas {
+ public:
+ CacaSurface(CacaWindow* window);
+ virtual ~CacaSurface();
+
+ bool Initialize();
+
+ // ui::SurfaceOzoneCanvas overrides:
+ virtual skia::RefPtr<SkCanvas> GetCanvas() OVERRIDE;
+ virtual void ResizeCanvas(const gfx::Size& viewport_size) OVERRIDE;
+ virtual void PresentCanvas(const gfx::Rect& damage) OVERRIDE;
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE;
+
+ private:
+ CacaWindow* window_; // Not owned.
+
+ ScopedCacaDither dither_;
+
+ skia::RefPtr<SkSurface> surface_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacaSurface);
+};
+
+CacaSurface::CacaSurface(CacaWindow* window) : window_(window) {
+}
+
+CacaSurface::~CacaSurface() {
+}
+
+bool CacaSurface::Initialize() {
+ ResizeCanvas(window_->bitmap_size());
+ return true;
+}
+
+skia::RefPtr<SkCanvas> CacaSurface::GetCanvas() {
+ return skia::SharePtr<SkCanvas>(surface_->getCanvas());
+}
+
+void CacaSurface::ResizeCanvas(const gfx::Size& viewport_size) {
+ TRACE_EVENT0("ozone", "CacaSurface::ResizeCanvas");
+
+ VLOG(2) << "creating libcaca surface with from window " << (void*)window_;
+
+ SkImageInfo info = SkImageInfo::Make(window_->bitmap_size().width(),
+ window_->bitmap_size().height(),
+ kN32_SkColorType,
+ kPremul_SkAlphaType);
+
+ surface_ = skia::AdoptRef(SkSurface::NewRaster(info));
+ if (!surface_)
+ LOG(ERROR) << "Failed to create SkSurface";
+
+ dither_.reset(caca_create_dither(info.bytesPerPixel() * 8,
+ info.width(),
+ info.height(),
+ info.minRowBytes(),
+ 0x00ff0000,
+ 0x0000ff00,
+ 0x000000ff,
+ 0xff000000));
+ if (!dither_)
+ LOG(ERROR) << "failed to create dither";
+}
+
+void CacaSurface::PresentCanvas(const gfx::Rect& damage) {
+ TRACE_EVENT0("ozone", "CacaSurface::PresentCanvas");
+
+ SkImageInfo info;
+ size_t row_bytes;
+ const void* pixels = surface_->peekPixels(&info, &row_bytes);
+
+ caca_canvas_t* canvas = caca_get_canvas(window_->display());
+ caca_dither_bitmap(canvas,
+ 0,
+ 0,
+ caca_get_canvas_width(canvas),
+ caca_get_canvas_height(canvas),
+ dither_.get(),
+ static_cast<const uint8_t*>(pixels));
+ caca_refresh_display(window_->display());
+}
+
+scoped_ptr<gfx::VSyncProvider> CacaSurface::CreateVSyncProvider() {
+ return scoped_ptr<gfx::VSyncProvider>();
+}
+
+} // namespace
+
+CacaWindowManager::CacaWindowManager() {
+}
+
+int32_t CacaWindowManager::AddWindow(CacaWindow* window) {
+ return windows_.Add(window);
+}
+
+void CacaWindowManager::RemoveWindow(int window_id, CacaWindow* window) {
+ DCHECK_EQ(window, windows_.Lookup(window_id));
+ windows_.Remove(window_id);
+}
+
+CacaWindowManager::~CacaWindowManager() {
+}
+
+bool CacaWindowManager::LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+ return false;
+}
+
+scoped_ptr<ui::SurfaceOzoneCanvas> CacaWindowManager::CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget) {
+ CacaWindow* window = windows_.Lookup(widget);
+ DCHECK(window);
+
+ scoped_ptr<CacaSurface> canvas(new CacaSurface(window));
+ bool initialized = canvas->Initialize();
+ DCHECK(initialized);
+ return canvas.PassAs<ui::SurfaceOzoneCanvas>();
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/caca/caca_window_manager.h b/ui/ozone/platform/caca/caca_window_manager.h
new file mode 100644
index 0000000..e01cf55
--- /dev/null
+++ b/ui/ozone/platform/caca/caca_window_manager.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_CACA_CACA_WINDOW_MANAGER_H_
+#define UI_OZONE_PLATFORM_CACA_CACA_WINDOW_MANAGER_H_
+
+#include "base/id_map.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace ui {
+
+class CacaWindow;
+
+class CacaWindowManager : public SurfaceFactoryOzone {
+ public:
+ CacaWindowManager();
+ virtual ~CacaWindowManager();
+
+ // Register a new libcaca window/instance. Returns the window id.
+ int32_t AddWindow(CacaWindow* window);
+
+ // Remove a libcaca window/instance.
+ void RemoveWindow(int32_t window_id, CacaWindow* window);
+
+ // ui::SurfaceFactoryOzone overrides:
+ virtual bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
+ virtual scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget) OVERRIDE;
+
+ private:
+ IDMap<CacaWindow> windows_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacaWindowManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_CACA_CACA_WINDOW_MANAGER_H_
diff --git a/ui/ozone/platform/caca/ozone_platform_caca.cc b/ui/ozone/platform/caca/ozone_platform_caca.cc
new file mode 100644
index 0000000..d892a63
--- /dev/null
+++ b/ui/ozone/platform/caca/ozone_platform_caca.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/caca/ozone_platform_caca.h"
+
+#include "ui/ozone/common/native_display_delegate_ozone.h"
+#include "ui/ozone/platform/caca/caca_event_source.h"
+#include "ui/ozone/platform/caca/caca_window.h"
+#include "ui/ozone/platform/caca/caca_window_manager.h"
+#include "ui/ozone/public/cursor_factory_ozone.h"
+#include "ui/ozone/public/ozone_platform.h"
+
+namespace ui {
+
+namespace {
+
+class OzonePlatformCaca : public OzonePlatform {
+ public:
+ OzonePlatformCaca() {}
+ virtual ~OzonePlatformCaca() {}
+
+ // OzonePlatform:
+ virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE {
+ return window_manager_.get();
+ }
+ virtual CursorFactoryOzone* GetCursorFactoryOzone() OVERRIDE {
+ return cursor_factory_ozone_.get();
+ }
+ virtual GpuPlatformSupport* GetGpuPlatformSupport() OVERRIDE {
+ return NULL; // no GPU support
+ }
+ virtual GpuPlatformSupportHost* GetGpuPlatformSupportHost() OVERRIDE {
+ return NULL; // no GPU support
+ }
+ virtual scoped_ptr<PlatformWindow> CreatePlatformWindow(
+ PlatformWindowDelegate* delegate,
+ const gfx::Rect& bounds) OVERRIDE {
+ scoped_ptr<CacaWindow> caca_window(new CacaWindow(
+ delegate, window_manager_.get(), event_source_.get(), bounds));
+ if (!caca_window->Initialize())
+ return scoped_ptr<PlatformWindow>();
+ return caca_window.PassAs<PlatformWindow>();
+ }
+ virtual scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate()
+ OVERRIDE {
+ return scoped_ptr<NativeDisplayDelegate>(new NativeDisplayDelegateOzone());
+ }
+
+ virtual void InitializeUI() OVERRIDE {
+ window_manager_.reset(new CacaWindowManager);
+ event_source_.reset(new CacaEventSource());
+ cursor_factory_ozone_.reset(new CursorFactoryOzone());
+ }
+
+ virtual void InitializeGPU() OVERRIDE {}
+
+ private:
+ scoped_ptr<CacaWindowManager> window_manager_;
+ scoped_ptr<CacaEventSource> event_source_;
+ scoped_ptr<CursorFactoryOzone> cursor_factory_ozone_;
+
+ DISALLOW_COPY_AND_ASSIGN(OzonePlatformCaca);
+};
+
+} // namespace
+
+OzonePlatform* CreateOzonePlatformCaca() { return new OzonePlatformCaca; }
+
+} // namespace ui
diff --git a/ui/ozone/platform/caca/ozone_platform_caca.h b/ui/ozone/platform/caca/ozone_platform_caca.h
new file mode 100644
index 0000000..bf1f735
--- /dev/null
+++ b/ui/ozone/platform/caca/ozone_platform_caca.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_CACA_OZONE_PLATFORM_CACA_H_
+#define UI_OZONE_PLATFORM_CACA_OZONE_PLATFORM_CACA_H_
+
+namespace ui {
+
+class OzonePlatform;
+
+// Constructor hook for use in ozone_platform_list.cc
+OzonePlatform* CreateOzonePlatformCaca();
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_CACA_OZONE_PLATFORM_CACA_H_
diff --git a/ui/ozone/platform/caca/scoped_caca_types.cc b/ui/ozone/platform/caca/scoped_caca_types.cc
new file mode 100644
index 0000000..093b7c9
--- /dev/null
+++ b/ui/ozone/platform/caca/scoped_caca_types.cc
@@ -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.
+
+#include "ui/ozone/platform/caca/scoped_caca_types.h"
+
+#include <caca.h>
+
+namespace ui {
+
+void CacaCanvasDeleter::operator()(caca_canvas_t* canvas) const {
+ caca_free_canvas(canvas);
+}
+
+void CacaDisplayDeleter::operator()(caca_display_t* display) const {
+ caca_free_display(display);
+}
+
+void CacaDitherDeleter::operator()(caca_dither_t* dither) const {
+ caca_free_dither(dither);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/caca/scoped_caca_types.h b/ui/ozone/platform/caca/scoped_caca_types.h
new file mode 100644
index 0000000..d789476
--- /dev/null
+++ b/ui/ozone/platform/caca/scoped_caca_types.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_CACA_SCOPED_CACA_TYPES_H_
+#define UI_OZONE_PLATFORM_CACA_SCOPED_CACA_TYPES_H_
+
+#include "base/memory/scoped_ptr.h"
+
+typedef struct caca_canvas caca_canvas_t;
+typedef struct caca_dither caca_dither_t;
+typedef struct caca_display caca_display_t;
+
+namespace ui {
+
+struct CacaCanvasDeleter {
+ void operator()(caca_canvas_t* canvas) const;
+};
+
+struct CacaDisplayDeleter {
+ void operator()(caca_display_t* display) const;
+};
+
+struct CacaDitherDeleter {
+ void operator()(caca_dither_t* dither) const;
+};
+
+typedef scoped_ptr<caca_canvas_t, CacaCanvasDeleter> ScopedCacaCanvas;
+typedef scoped_ptr<caca_display_t, CacaDisplayDeleter> ScopedCacaDisplay;
+typedef scoped_ptr<caca_dither_t, CacaDitherDeleter> ScopedCacaDither;
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_CACA_SCOPED_CACA_TYPES_H_
diff --git a/ui/ozone/platform/dri/BUILD.gn b/ui/ozone/platform/dri/BUILD.gn
new file mode 100644
index 0000000..61d2baf
--- /dev/null
+++ b/ui/ozone/platform/dri/BUILD.gn
@@ -0,0 +1,150 @@
+# 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")
+
+pkg_config("libdrm") {
+ packages = [ "libdrm" ]
+}
+
+source_set("dri_common") {
+ sources = [
+ "crtc_state.cc",
+ "crtc_state.h",
+ "display_mode_dri.cc",
+ "display_mode_dri.h",
+ "display_snapshot_dri.cc",
+ "display_snapshot_dri.h",
+ "dri_console_buffer.cc",
+ "dri_console_buffer.h",
+ "dri_cursor.cc",
+ "dri_cursor.h",
+ "dri_buffer.cc",
+ "dri_buffer.h",
+ "dri_surface.cc",
+ "dri_surface.h",
+ "dri_surface_factory.cc",
+ "dri_surface_factory.h",
+ "dri_util.cc",
+ "dri_util.h",
+ "dri_vsync_provider.cc",
+ "dri_vsync_provider.h",
+ "dri_window.cc",
+ "dri_window.h",
+ "dri_window_delegate.h",
+ "dri_window_delegate_impl.cc",
+ "dri_window_delegate_impl.h",
+ "dri_window_delegate_manager.cc",
+ "dri_window_delegate_manager.h",
+ "dri_window_manager.cc",
+ "dri_window_manager.h",
+ "dri_wrapper.cc",
+ "dri_wrapper.h",
+ "hardware_display_controller.cc",
+ "hardware_display_controller.h",
+ "native_display_delegate_dri.cc",
+ "native_display_delegate_dri.h",
+ "scoped_drm_types.cc",
+ "scoped_drm_types.h",
+ "screen_manager.cc",
+ "screen_manager.h",
+ "scanout_buffer.h",
+ "virtual_terminal_manager.cc",
+ "virtual_terminal_manager.h",
+ ]
+
+ deps = [
+ "//base",
+ "//skia",
+ "//ipc",
+ "//ui/base",
+ "//ui/display/types",
+ "//ui/events",
+ "//ui/events/ozone:events_ozone_evdev",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+
+ public_configs = [
+ ":libdrm",
+ ]
+}
+
+if (ozone_platform_dri) {
+ source_set("dri") {
+ sources = [
+ "ozone_platform_dri.cc",
+ "ozone_platform_dri.h",
+ ]
+
+ deps = [
+ ":dri_common",
+ "//base",
+ "//skia",
+ "//ui/events/ozone:events_ozone_evdev",
+ ]
+ }
+
+ source_set("dri_unittests") {
+ testonly = true
+ sources = [
+ "dri_surface_factory_unittest.cc",
+ "dri_surface_unittest.cc",
+ "hardware_display_controller_unittest.cc",
+ "screen_manager_unittest.cc",
+ "test/mock_dri_wrapper.cc",
+ "test/mock_dri_wrapper.h",
+ ]
+
+ deps = [
+ ":dri_common",
+ "//skia",
+ "//testing/gtest",
+ ]
+ }
+}
+
+if (ozone_platform_gbm) {
+ pkg_config("libgbm") {
+ packages = [ "gbm" ]
+ }
+
+ source_set("gbm") {
+ sources = [
+ "channel_observer.h",
+ "dri_window_delegate_proxy.cc",
+ "dri_window_delegate_proxy.h",
+ "gbm_buffer.cc",
+ "gbm_buffer.h",
+ "gbm_buffer_base.cc",
+ "gbm_buffer_base.h",
+ "gbm_surface.cc",
+ "gbm_surface.h",
+ "gbm_surfaceless.cc",
+ "gbm_surfaceless.h",
+ "gbm_surface_factory.cc",
+ "gbm_surface_factory.h",
+ "gpu_platform_support_gbm.cc",
+ "gpu_platform_support_gbm.h",
+ "gpu_platform_support_host_gbm.cc",
+ "gpu_platform_support_host_gbm.h",
+ "native_display_delegate_proxy.cc",
+ "native_display_delegate_proxy.h",
+ "ozone_platform_gbm.cc",
+ "ozone_platform_gbm.h",
+ ]
+
+ deps = [
+ ":dri_common",
+ "//base",
+ "//skia",
+ "//ui/events/ozone:events_ozone_evdev",
+ ]
+
+ public_configs = [
+ ":libgbm",
+ ]
+ }
+}
diff --git a/ui/ozone/platform/dri/DEPS b/ui/ozone/platform/dri/DEPS
new file mode 100644
index 0000000..0ab1471
--- /dev/null
+++ b/ui/ozone/platform/dri/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+ui/display/util",
+]
diff --git a/ui/ozone/platform/dri/OWNERS b/ui/ozone/platform/dri/OWNERS
new file mode 100644
index 0000000..0d77c0e
--- /dev/null
+++ b/ui/ozone/platform/dri/OWNERS
@@ -0,0 +1 @@
+dnicoara@chromium.org
diff --git a/ui/ozone/platform/dri/channel_observer.h b/ui/ozone/platform/dri/channel_observer.h
new file mode 100644
index 0000000..356a79e
--- /dev/null
+++ b/ui/ozone/platform/dri/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_DRI_CHANNEL_OBSERVER_H_
+#define UI_OZONE_PLATFORM_DRI_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_DRI_CHANNEL_OBSERVER_H_
diff --git a/ui/ozone/platform/dri/crtc_state.cc b/ui/ozone/platform/dri/crtc_state.cc
new file mode 100644
index 0000000..ff2e137
--- /dev/null
+++ b/ui/ozone/platform/dri/crtc_state.cc
@@ -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.
+
+#include "ui/ozone/platform/dri/crtc_state.h"
+
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+
+namespace ui {
+
+CrtcState::CrtcState(DriWrapper* drm,
+ uint32_t crtc,
+ uint32_t connector)
+ : drm_(drm),
+ crtc_(crtc),
+ connector_(connector),
+ saved_crtc_(drm->GetCrtc(crtc)),
+ is_disabled_(true) {}
+
+CrtcState::~CrtcState() {
+ if (!is_disabled_) {
+ drm_->SetCrtc(saved_crtc_.get(), std::vector<uint32_t>(1, connector_));
+ drm_->SetCursor(crtc_, 0, gfx::Size());
+ }
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/crtc_state.h b/ui/ozone/platform/dri/crtc_state.h
new file mode 100644
index 0000000..e4ad391
--- /dev/null
+++ b/ui/ozone/platform/dri/crtc_state.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_DRI_CRTC_STATE_H_
+#define UI_OZONE_PLATFORM_DRI_CRTC_STATE_H_
+
+#include <stdint.h>
+
+#include "ui/ozone/platform/dri/scoped_drm_types.h"
+
+namespace ui {
+
+class DriWrapper;
+
+// Represents the state of 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 CrtcState {
+ public:
+ CrtcState(DriWrapper* drm, uint32_t crtc, uint32_t connector);
+ ~CrtcState();
+
+ uint32_t crtc() const { return crtc_; }
+ uint32_t connector() const { return connector_; }
+ bool is_disabled() const { return is_disabled_; }
+
+ void set_is_disabled(bool state) { is_disabled_ = state; }
+
+ private:
+ DriWrapper* drm_; // Not owned.
+
+ uint32_t crtc_;
+
+ // TODO(dnicoara) Add support for hardware mirroring (multiple connectors).
+ uint32_t connector_;
+
+ // Store the state of the CRTC before we took over. Used to restore the CRTC
+ // once we no longer need it.
+ ScopedDrmCrtcPtr saved_crtc_;
+
+ // 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_;
+
+ DISALLOW_COPY_AND_ASSIGN(CrtcState);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_CRTC_STATE_H_
diff --git a/ui/ozone/platform/dri/display_mode_dri.cc b/ui/ozone/platform/dri/display_mode_dri.cc
new file mode 100644
index 0000000..6dd660c
--- /dev/null
+++ b/ui/ozone/platform/dri/display_mode_dri.cc
@@ -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.
+
+#include "ui/ozone/platform/dri/display_mode_dri.h"
+
+namespace ui {
+
+DisplayModeDri::DisplayModeDri(const drmModeModeInfo& mode)
+ : DisplayMode(gfx::Size(mode.hdisplay, mode.vdisplay),
+ mode.flags & DRM_MODE_FLAG_INTERLACE,
+ mode.vrefresh),
+ mode_info_(mode) {
+}
+
+DisplayModeDri::~DisplayModeDri() {
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/display_mode_dri.h b/ui/ozone/platform/dri/display_mode_dri.h
new file mode 100644
index 0000000..c23c339
--- /dev/null
+++ b/ui/ozone/platform/dri/display_mode_dri.h
@@ -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.
+
+#ifndef UI_OZONE_PLATFORM_DRI_DISPLAY_MODE_DRI_H_
+#define UI_OZONE_PLATFORM_DRI_DISPLAY_MODE_DRI_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <xf86drmMode.h>
+
+#include "ui/display/types/display_mode.h"
+
+namespace ui {
+
+class DisplayModeDri : public DisplayMode {
+ public:
+ DisplayModeDri(const drmModeModeInfo& mode);
+ virtual ~DisplayModeDri();
+
+ // Native details about this mode. Only used internally in the DRI
+ // implementation.
+ drmModeModeInfo mode_info() const { return mode_info_; }
+
+ private:
+ drmModeModeInfo mode_info_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplayModeDri);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DISPLAY_MODE_DRI_H_
diff --git a/ui/ozone/platform/dri/display_snapshot_dri.cc b/ui/ozone/platform/dri/display_snapshot_dri.cc
new file mode 100644
index 0000000..fa7b6f9
--- /dev/null
+++ b/ui/ozone/platform/dri/display_snapshot_dri.cc
@@ -0,0 +1,127 @@
+// 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/dri/display_snapshot_dri.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <xf86drmMode.h>
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "ui/display/util/edid_parser.h"
+#include "ui/ozone/platform/dri/display_mode_dri.h"
+#include "ui/ozone/platform/dri/dri_util.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+
+namespace ui {
+
+namespace {
+
+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:
+ 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;
+ }
+}
+
+bool IsAspectPreserving(DriWrapper* drm, drmModeConnector* connector) {
+ ScopedDrmPropertyPtr property(drm->GetProperty(connector, "scaling mode"));
+ if (property) {
+ for (int j = 0; j < property->count_enums; ++j) {
+ if (property->enums[j].value ==
+ connector->prop_values[property->prop_id] &&
+ strcmp(property->enums[j].name, "Full aspect") == 0)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace
+
+DisplaySnapshotDri::DisplaySnapshotDri(DriWrapper* drm,
+ drmModeConnector* connector,
+ drmModeCrtc* crtc,
+ uint32_t index)
+ : DisplaySnapshot(index,
+ false,
+ gfx::Point(crtc->x, crtc->y),
+ gfx::Size(connector->mmWidth, connector->mmHeight),
+ GetDisplayType(connector),
+ IsAspectPreserving(drm, connector),
+ false,
+ std::string(),
+ std::vector<const DisplayMode*>(),
+ NULL,
+ NULL),
+ connector_(connector->connector_id),
+ crtc_(crtc->crtc_id),
+ dpms_property_(drm->GetProperty(connector, "DPMS")) {
+ if (!dpms_property_)
+ VLOG(1) << "Failed to find the DPMS property for connector "
+ << connector->connector_id;
+
+ ScopedDrmPropertyBlobPtr edid_blob(drm->GetPropertyBlob(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);
+
+ has_proper_display_id_ = GetDisplayIdFromEDID(edid, index, &display_id_);
+ ParseOutputDeviceData(edid, NULL, &display_name_);
+ ParseOutputOverscanFlag(edid, &overscan_flag_);
+ } else {
+ VLOG(1) << "Failed to get EDID blob for connector "
+ << connector->connector_id;
+ }
+
+ for (int i = 0; i < connector->count_modes; ++i) {
+ drmModeModeInfo& mode = connector->modes[i];
+ modes_.push_back(new DisplayModeDri(mode));
+
+ if (crtc->mode_valid && SameMode(crtc->mode, mode))
+ current_mode_ = modes_.back();
+
+ if (mode.type & DRM_MODE_TYPE_PREFERRED)
+ native_mode_ = 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 (!native_mode_ && !modes_.empty())
+ native_mode_ = modes_.front();
+}
+
+DisplaySnapshotDri::~DisplaySnapshotDri() {
+}
+
+std::string DisplaySnapshotDri::ToString() const {
+ return base::StringPrintf(
+ "[type=%d, connector=%" PRIu32 ", crtc=%" PRIu32 ", mode=%s, dim=%s]",
+ type_,
+ connector_,
+ crtc_,
+ current_mode_ ? current_mode_->ToString().c_str() : "NULL",
+ physical_size_.ToString().c_str());
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/display_snapshot_dri.h b/ui/ozone/platform/dri/display_snapshot_dri.h
new file mode 100644
index 0000000..a509be4
--- /dev/null
+++ b/ui/ozone/platform/dri/display_snapshot_dri.h
@@ -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.
+
+#ifndef UI_OZONE_PLATFORM_DRI_DISPLAY_SNAPSHOT_DRI_H_
+#define UI_OZONE_PLATFORM_DRI_DISPLAY_SNAPSHOT_DRI_H_
+
+#include "ui/display/types/display_snapshot.h"
+#include "ui/ozone/platform/dri/scoped_drm_types.h"
+
+namespace ui {
+
+class DriWrapper;
+
+class DisplaySnapshotDri : public DisplaySnapshot {
+ public:
+ DisplaySnapshotDri(DriWrapper* drm,
+ drmModeConnector* connector,
+ drmModeCrtc* crtc,
+ uint32_t index);
+ virtual ~DisplaySnapshotDri();
+
+ // Native properties of a display used by the DRI implementation in
+ // configuring this display.
+ uint32_t connector() const { return connector_; }
+ uint32_t crtc() const { return crtc_; }
+ drmModePropertyRes* dpms_property() const { return dpms_property_.get(); }
+
+ // DisplaySnapshot overrides:
+ virtual std::string ToString() const OVERRIDE;
+
+ private:
+ uint32_t connector_;
+ uint32_t crtc_;
+ ScopedDrmPropertyPtr dpms_property_;
+ std::string name_;
+ bool overscan_flag_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplaySnapshotDri);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DISPLAY_SNAPSHOT_DRI_H_
diff --git a/ui/ozone/platform/dri/dri.gypi b/ui/ozone/platform/dri/dri.gypi
new file mode 100644
index 0000000..9c74b7f
--- /dev/null
+++ b/ui/ozone/platform/dri/dri.gypi
@@ -0,0 +1,120 @@
+# 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.
+
+{
+ 'variables': {
+ 'internal_ozone_platform_deps': [
+ 'ozone_platform_dri',
+ ],
+ 'internal_ozone_platform_unittest_deps': [
+ 'ozone_platform_dri_unittests',
+ ],
+ 'internal_ozone_platforms': [
+ 'dri',
+ ],
+ 'use_drm_atomic_flip%': 0,
+ },
+ 'targets': [
+ {
+ 'target_name': 'ozone_platform_dri',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../build/linux/system.gyp:libdrm',
+ '../../skia/skia.gyp:skia',
+ '../base/ui_base.gyp:ui_base',
+ '../display/display.gyp:display_types',
+ '../display/display.gyp:display_util',
+ '../events/events.gyp:events',
+ '../events/ozone/events_ozone.gyp:events_ozone_evdev',
+ '../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'defines': [
+ 'OZONE_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'crtc_state.cc',
+ 'crtc_state.h',
+ 'display_mode_dri.cc',
+ 'display_mode_dri.h',
+ 'display_snapshot_dri.cc',
+ 'display_snapshot_dri.h',
+ 'dri_console_buffer.cc',
+ 'dri_console_buffer.h',
+ 'dri_buffer.cc',
+ 'dri_buffer.h',
+ 'dri_cursor.cc',
+ 'dri_cursor.h',
+ 'dri_surface.cc',
+ 'dri_surface.h',
+ 'dri_surface_factory.cc',
+ 'dri_surface_factory.h',
+ 'dri_util.cc',
+ 'dri_util.h',
+ 'dri_vsync_provider.cc',
+ 'dri_vsync_provider.h',
+ 'dri_window.cc',
+ 'dri_window.h',
+ 'dri_window_delegate.h',
+ 'dri_window_delegate_impl.cc',
+ 'dri_window_delegate_impl.h',
+ 'dri_window_delegate_manager.cc',
+ 'dri_window_delegate_manager.h',
+ 'dri_window_manager.cc',
+ 'dri_window_manager.h',
+ 'dri_wrapper.cc',
+ 'dri_wrapper.h',
+ 'hardware_display_controller.cc',
+ 'hardware_display_controller.h',
+ 'native_display_delegate_dri.cc',
+ 'native_display_delegate_dri.h',
+ 'ozone_platform_dri.cc',
+ 'ozone_platform_dri.h',
+ 'scoped_drm_types.cc',
+ 'scoped_drm_types.h',
+ 'screen_manager.cc',
+ 'screen_manager.h',
+ 'scanout_buffer.h',
+ 'virtual_terminal_manager.cc',
+ 'virtual_terminal_manager.h',
+ ],
+ 'conditions': [
+ ['use_drm_atomic_flip==1', {
+ 'sources': [
+ 'hardware_display_plane.cc',
+ 'hardware_display_plane.h',
+ 'hardware_display_plane_manager.cc',
+ 'hardware_display_plane_manager.h',
+ ],
+ }],
+ ],
+ },
+ {
+ 'target_name': 'ozone_platform_dri_unittests',
+ 'type': 'none',
+ 'dependencies': [
+ '../../build/linux/system.gyp:libdrm',
+ '../../skia/skia.gyp:skia',
+ '../gfx/gfx.gyp:gfx_geometry',
+ 'ozone_platform_dri',
+ ],
+ 'export_dependent_settings': [
+ '../../build/linux/system.gyp:libdrm',
+ '../../skia/skia.gyp:skia',
+ '../gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'direct_dependent_settings': {
+ 'sources': [
+ 'dri_surface_factory_unittest.cc',
+ 'dri_surface_unittest.cc',
+ 'hardware_display_controller_unittest.cc',
+ 'screen_manager_unittest.cc',
+ 'test/mock_dri_wrapper.cc',
+ 'test/mock_dri_wrapper.h',
+ ],
+ },
+ },
+ ],
+}
diff --git a/ui/ozone/platform/dri/dri_buffer.cc b/ui/ozone/platform/dri/dri_buffer.cc
new file mode 100644
index 0000000..4a35395
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_buffer.cc
@@ -0,0 +1,111 @@
+// 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/dri/dri_buffer.h"
+
+#include "base/logging.h"
+#include "ui/ozone/platform/dri/dri_wrapper.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
+
+DriBuffer::DriBuffer(DriWrapper* dri)
+ : dri_(dri), handle_(0), framebuffer_(0) {}
+
+DriBuffer::~DriBuffer() {
+ if (!surface_)
+ return;
+
+ if (framebuffer_)
+ dri_->RemoveFramebuffer(framebuffer_);
+
+ SkImageInfo info;
+ void* pixels = const_cast<void*>(surface_->peekPixels(&info, NULL));
+ if (!pixels)
+ return;
+
+ dri_->DestroyDumbBuffer(info, handle_, stride_, pixels);
+}
+
+bool DriBuffer::Initialize(const SkImageInfo& info) {
+ void* pixels = NULL;
+ if (!dri_->CreateDumbBuffer(info, &handle_, &stride_, &pixels)) {
+ VLOG(2) << "Cannot create drm dumb buffer";
+ return false;
+ }
+
+ if (!dri_->AddFramebuffer(info.width(),
+ info.height(),
+ GetColorDepth(info.colorType()),
+ info.bytesPerPixel() << 3,
+ stride_,
+ handle_,
+ &framebuffer_)) {
+ VLOG(2) << "Failed to register framebuffer: " << strerror(errno);
+ return false;
+ }
+
+ surface_ = skia::AdoptRef(SkSurface::NewRasterDirect(info, pixels, stride_));
+ if (!surface_) {
+ VLOG(2) << "Cannot install Skia pixels for drm buffer";
+ return false;
+ }
+
+ return true;
+}
+
+SkCanvas* DriBuffer::GetCanvas() const {
+ return surface_->getCanvas();
+}
+
+uint32_t DriBuffer::GetFramebufferId() const {
+ return framebuffer_;
+}
+
+uint32_t DriBuffer::GetHandle() const {
+ return handle_;
+}
+
+gfx::Size DriBuffer::GetSize() const {
+ return gfx::Size(surface_->width(), surface_->height());
+}
+
+DriBufferGenerator::DriBufferGenerator(DriWrapper* dri) : dri_(dri) {}
+
+DriBufferGenerator::~DriBufferGenerator() {}
+
+scoped_refptr<ScanoutBuffer> DriBufferGenerator::Create(const gfx::Size& size) {
+ scoped_refptr<DriBuffer> buffer(new DriBuffer(dri_));
+ SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
+ if (!buffer->Initialize(info))
+ return NULL;
+
+ return buffer;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/dri_buffer.h b/ui/ozone/platform/dri/dri_buffer.h
new file mode 100644
index 0000000..9b645ae
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_buffer.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_DRI_DRI_BUFFER_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_BUFFER_H_
+
+#include "base/macros.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/ozone/platform/dri/scanout_buffer.h"
+
+namespace ui {
+
+class DriWrapper;
+
+// 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 DriBuffer : public ScanoutBuffer {
+ public:
+ DriBuffer(DriWrapper* dri);
+
+ // Allocates the backing pixels and wraps them in |surface_|. |info| is used
+ // to describe the buffer characteristics (size, color format).
+ bool Initialize(const SkImageInfo& info);
+
+ SkCanvas* GetCanvas() const;
+
+ // ScanoutBuffer:
+ virtual uint32_t GetFramebufferId() const OVERRIDE;
+ virtual uint32_t GetHandle() const OVERRIDE;
+ virtual gfx::Size GetSize() const OVERRIDE;
+
+ protected:
+ virtual ~DriBuffer();
+
+ DriWrapper* dri_; // Not owned.
+
+ // Wrapper around the native pixel memory.
+ skia::RefPtr<SkSurface> surface_;
+
+ // Length of a row of pixels.
+ uint32_t stride_;
+
+ // Buffer handle used by the DRM allocator.
+ uint32_t handle_;
+
+ // Buffer ID used by the DRM modesettings API. This is set when the buffer is
+ // registered with the CRTC.
+ uint32_t framebuffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriBuffer);
+};
+
+class DriBufferGenerator : public ScanoutBufferGenerator {
+ public:
+ DriBufferGenerator(DriWrapper* dri);
+ virtual ~DriBufferGenerator();
+
+ // ScanoutBufferGenerator:
+ virtual scoped_refptr<ScanoutBuffer> Create(const gfx::Size& size) OVERRIDE;
+
+ private:
+ DriWrapper* dri_; // Not owned.
+
+ DISALLOW_COPY_AND_ASSIGN(DriBufferGenerator);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_BUFFER_H_
diff --git a/ui/ozone/platform/dri/dri_console_buffer.cc b/ui/ozone/platform/dri/dri_console_buffer.cc
new file mode 100644
index 0000000..6c1f7a9
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_console_buffer.cc
@@ -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.
+
+#include "ui/ozone/platform/dri/dri_console_buffer.h"
+
+#include <sys/mman.h>
+#include <xf86drmMode.h>
+
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/ozone/platform/dri/dri_util.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/scoped_drm_types.h"
+
+namespace ui {
+
+DriConsoleBuffer::DriConsoleBuffer(DriWrapper* dri, uint32_t framebuffer)
+ : dri_(dri),
+ handle_(0),
+ framebuffer_(framebuffer),
+ mmap_base_(NULL),
+ mmap_size_(0) {
+}
+
+DriConsoleBuffer::~DriConsoleBuffer() {
+ if (mmap_base_)
+ if (munmap(mmap_base_, mmap_size_))
+ PLOG(ERROR) << "munmap";
+}
+
+bool DriConsoleBuffer::Initialize() {
+ ScopedDrmFramebufferPtr fb(dri_->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 (!MapDumbBuffer(dri_->get_fd(), 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/dri/dri_console_buffer.h b/ui/ozone/platform/dri/dri_console_buffer.h
new file mode 100644
index 0000000..51cb4ad
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_console_buffer.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 UI_OZONE_PLATFORM_DRI_DRI_CONSOLE_BUFFER_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_CONSOLE_BUFFER_H_
+
+#include "base/macros.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkSurface.h"
+
+class SkCanvas;
+
+namespace ui {
+
+class DriWrapper;
+
+// 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 DriConsoleBuffer {
+ public:
+ DriConsoleBuffer(DriWrapper* dri, uint32_t framebuffer);
+ ~DriConsoleBuffer();
+
+ SkCanvas* canvas() { return surface_->getCanvas(); }
+
+ // Memory map the backing pixels and wrap them in |surface_|.
+ bool Initialize();
+
+ protected:
+ DriWrapper* dri_; // Not owned.
+
+ // Wrapper around the native pixel memory.
+ skia::RefPtr<SkSurface> surface_;
+
+ // Length of a row of pixels.
+ uint32_t stride_;
+
+ // Buffer handle used by the DRM allocator.
+ uint32_t handle_;
+
+ // Buffer ID used by the DRM modesettings API.
+ uint32_t framebuffer_;
+
+ // Memory map base address.
+ void* mmap_base_;
+
+ // Memory map size.
+ size_t mmap_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriConsoleBuffer);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_CONSOLE_BUFFER_H_
diff --git a/ui/ozone/platform/dri/dri_cursor.cc b/ui/ozone/platform/dri/dri_cursor.cc
new file mode 100644
index 0000000..308541b
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_cursor.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 "ui/ozone/platform/dri/dri_cursor.h"
+
+#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.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/dri/dri_surface_factory.h"
+#include "ui/ozone/platform/dri/dri_window.h"
+#include "ui/ozone/platform/dri/dri_window_manager.h"
+#include "ui/ozone/platform/dri/hardware_cursor_delegate.h"
+
+namespace ui {
+
+DriCursor::DriCursor(HardwareCursorDelegate* hardware,
+ DriWindowManager* window_manager)
+ : hardware_(hardware),
+ window_manager_(window_manager),
+ cursor_window_(gfx::kNullAcceleratedWidget) {
+}
+
+DriCursor::~DriCursor() {
+}
+
+void DriCursor::SetCursor(gfx::AcceleratedWidget widget,
+ PlatformCursor platform_cursor) {
+ DCHECK_NE(widget, gfx::kNullAcceleratedWidget);
+ scoped_refptr<BitmapCursorOzone> cursor =
+ BitmapCursorFactoryOzone::GetBitmapCursor(platform_cursor);
+ if (cursor_ == cursor || cursor_window_ != widget)
+ return;
+
+ cursor_ = cursor;
+ ShowCursor();
+}
+
+void DriCursor::ShowCursor() {
+ DCHECK_NE(cursor_window_, gfx::kNullAcceleratedWidget);
+ if (cursor_.get())
+ hardware_->SetHardwareCursor(cursor_window_,
+ cursor_->bitmaps(),
+ bitmap_location(),
+ cursor_->frame_delay_ms());
+ else
+ HideCursor();
+}
+
+void DriCursor::HideCursor() {
+ DCHECK_NE(cursor_window_, gfx::kNullAcceleratedWidget);
+ hardware_->SetHardwareCursor(
+ cursor_window_, std::vector<SkBitmap>(), gfx::Point(), 0);
+}
+
+void DriCursor::MoveCursorTo(gfx::AcceleratedWidget widget,
+ const gfx::PointF& location) {
+ if (widget != cursor_window_ && cursor_window_ != gfx::kNullAcceleratedWidget)
+ HideCursor();
+
+ cursor_window_ = widget;
+ cursor_location_ = location;
+
+ if (cursor_window_ == gfx::kNullAcceleratedWidget)
+ return;
+
+ DriWindow* window = window_manager_->GetWindow(cursor_window_);
+ const gfx::Size& size = window->GetBounds().size();
+ cursor_location_.SetToMax(gfx::PointF(0, 0));
+ // Right and bottom edges are exclusive.
+ cursor_location_.SetToMin(gfx::PointF(size.width() - 1, size.height() - 1));
+
+ if (cursor_.get())
+ hardware_->MoveHardwareCursor(cursor_window_, bitmap_location());
+}
+
+void DriCursor::MoveCursor(const gfx::Vector2dF& delta) {
+ MoveCursorTo(cursor_window_, cursor_location_ + delta);
+}
+
+gfx::AcceleratedWidget DriCursor::GetCursorWindow() {
+ return cursor_window_;
+}
+
+bool DriCursor::IsCursorVisible() {
+ return cursor_.get();
+}
+
+gfx::PointF DriCursor::location() {
+ return cursor_location_;
+}
+
+gfx::Point DriCursor::bitmap_location() {
+ return gfx::ToFlooredPoint(cursor_location_) -
+ cursor_->hotspot().OffsetFromOrigin();
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/dri_cursor.h b/ui/ozone/platform/dri/dri_cursor.h
new file mode 100644
index 0000000..949584c
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_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_DRI_DRI_CURSOR_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_CURSOR_H_
+
+#include "base/memory/ref_counted.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace gfx {
+class PointF;
+class Vector2dF;
+}
+
+namespace ui {
+
+class BitmapCursorOzone;
+class BitmapCursorFactoryOzone;
+class DriWindowManager;
+class HardwareCursorDelegate;
+
+class DriCursor : public CursorDelegateEvdev {
+ public:
+ explicit DriCursor(HardwareCursorDelegate* hardware,
+ DriWindowManager* window_manager);
+ virtual ~DriCursor();
+
+ void SetCursor(gfx::AcceleratedWidget widget, PlatformCursor platform_cursor);
+ void ShowCursor();
+ void HideCursor();
+ gfx::AcceleratedWidget GetCursorWindow();
+
+ // CursorDelegateEvdev:
+ virtual void MoveCursorTo(gfx::AcceleratedWidget widget,
+ const gfx::PointF& location) OVERRIDE;
+ virtual void MoveCursor(const gfx::Vector2dF& delta) OVERRIDE;
+ virtual bool IsCursorVisible() OVERRIDE;
+ virtual gfx::PointF location() OVERRIDE;
+
+ private:
+ // The location of the bitmap (the cursor location is the hotspot location).
+ gfx::Point bitmap_location();
+
+ // The DRI implementation for setting the hardware cursor.
+ HardwareCursorDelegate* hardware_;
+
+ DriWindowManager* window_manager_; // Not owned.
+
+ // The current cursor bitmap.
+ scoped_refptr<BitmapCursorOzone> cursor_;
+
+ // The window under the cursor.
+ gfx::AcceleratedWidget cursor_window_;
+
+ // The location of the cursor within the window.
+ gfx::PointF cursor_location_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_CURSOR_H_
diff --git a/ui/ozone/platform/dri/dri_surface.cc b/ui/ozone/platform/dri/dri_surface.cc
new file mode 100644
index 0000000..34f2ce2
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_surface.cc
@@ -0,0 +1,101 @@
+// 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/dri/dri_surface.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/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_vsync_provider.h"
+#include "ui/ozone/platform/dri/dri_window_delegate_impl.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+
+namespace ui {
+
+namespace {
+
+scoped_refptr<DriBuffer> AllocateBuffer(DriWrapper* dri,
+ const gfx::Size& size) {
+ scoped_refptr<DriBuffer> buffer(new DriBuffer(dri));
+ SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
+
+ bool initialized = buffer->Initialize(info);
+ DCHECK(initialized) << "Failed to create drm buffer.";
+
+ return buffer;
+}
+
+} // namespace
+
+DriSurface::DriSurface(DriWindowDelegate* window_delegate, DriWrapper* dri)
+ : window_delegate_(window_delegate),
+ dri_(dri),
+ buffers_(),
+ front_buffer_(0) {
+}
+
+DriSurface::~DriSurface() {
+}
+
+skia::RefPtr<SkCanvas> DriSurface::GetCanvas() {
+ return skia::SharePtr(surface_->getCanvas());
+}
+
+void DriSurface::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.
+ for (size_t i = 0; i < arraysize(buffers_); ++i)
+ buffers_[i] = AllocateBuffer(dri_, controller->GetModeSize());
+}
+
+void DriSurface::PresentCanvas(const gfx::Rect& damage) {
+ DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(buffers_[front_buffer_ ^ 1].get());
+
+ HardwareDisplayController* controller = window_delegate_->GetController();
+ if (!controller)
+ return;
+
+ controller->QueueOverlayPlane(OverlayPlane(buffers_[front_buffer_ ^ 1]));
+
+ UpdateNativeSurface(damage);
+ controller->SchedulePageFlip();
+ controller->WaitForPageFlipEvent();
+
+ // Update our front buffer pointer.
+ front_buffer_ ^= 1;
+}
+
+scoped_ptr<gfx::VSyncProvider> DriSurface::CreateVSyncProvider() {
+ return scoped_ptr<gfx::VSyncProvider>(new DriVSyncProvider(window_delegate_));
+}
+
+void DriSurface::UpdateNativeSurface(const gfx::Rect& damage) {
+ SkCanvas* canvas = buffers_[front_buffer_ ^ 1]->GetCanvas();
+
+ // The DriSurface is double buffered, so the current back buffer is
+ // missing the previous update. Expand damage region.
+ SkRect real_damage = RectToSkRect(UnionRects(damage, last_damage_));
+
+ // Copy damage region.
+ skia::RefPtr<SkImage> image = skia::AdoptRef(surface_->newImageSnapshot());
+ canvas->drawImageRect(image.get(), &real_damage, real_damage, NULL);
+
+ last_damage_ = damage;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/dri_surface.h b/ui/ozone/platform/dri/dri_surface.h
new file mode 100644
index 0000000..740a310
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_surface.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 UI_OZONE_PLATFORM_DRI_DRI_SURFACE_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_SURFACE_H_
+
+#include "base/memory/ref_counted.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+
+class SkCanvas;
+class SkSurface;
+
+namespace ui {
+
+class DriBuffer;
+class DriWindowDelegate;
+class DriWrapper;
+class HardwareDisplayController;
+
+class DriSurface : public SurfaceOzoneCanvas {
+ public:
+ DriSurface(DriWindowDelegate* window_delegate, DriWrapper* dri);
+ virtual ~DriSurface();
+
+ // SurfaceOzoneCanvas:
+ virtual skia::RefPtr<SkCanvas> GetCanvas() OVERRIDE;
+ virtual void ResizeCanvas(const gfx::Size& viewport_size) OVERRIDE;
+ virtual void PresentCanvas(const gfx::Rect& damage) OVERRIDE;
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE;
+
+ private:
+ void UpdateNativeSurface(const gfx::Rect& damage);
+
+ DriWindowDelegate* window_delegate_;
+
+ // Stores the connection to the graphics card. Pointer not owned by this
+ // class.
+ DriWrapper* dri_;
+
+ // The actual buffers used for painting.
+ scoped_refptr<DriBuffer> buffers_[2];
+
+ // Keeps track of which bitmap is |buffers_| is the frontbuffer.
+ int front_buffer_;
+
+ skia::RefPtr<SkSurface> surface_;
+ gfx::Rect last_damage_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriSurface);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_SURFACE_H_
diff --git a/ui/ozone/platform/dri/dri_surface_factory.cc b/ui/ozone/platform/dri/dri_surface_factory.cc
new file mode 100644
index 0000000..fb8ce75
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_surface_factory.cc
@@ -0,0 +1,184 @@
+// 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/dri/dri_surface_factory.h"
+
+#include <errno.h>
+
+#include "base/debug/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/gfx/native_widget_types.h"
+#include "ui/ozone/platform/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_surface.h"
+#include "ui/ozone/platform/dri/dri_util.h"
+#include "ui/ozone/platform/dri/dri_window_delegate_impl.h"
+#include "ui/ozone/platform/dri/dri_window_delegate_manager.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+
+namespace ui {
+
+namespace {
+
+// TODO(dnicoara) Read the cursor plane size from the hardware.
+const gfx::Size kCursorSize(64, 64);
+
+void UpdateCursorImage(DriBuffer* 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
+
+// static
+const gfx::AcceleratedWidget DriSurfaceFactory::kDefaultWidgetHandle = 1;
+
+DriSurfaceFactory::DriSurfaceFactory(DriWrapper* drm,
+ ScreenManager* screen_manager,
+ DriWindowDelegateManager* window_manager)
+ : drm_(drm),
+ screen_manager_(screen_manager),
+ window_manager_(window_manager),
+ state_(UNINITIALIZED),
+ cursor_frontbuffer_(0),
+ cursor_widget_(0),
+ cursor_frame_(0),
+ cursor_frame_delay_ms_(0) {
+}
+
+DriSurfaceFactory::~DriSurfaceFactory() {
+ if (state_ == INITIALIZED)
+ ShutdownHardware();
+}
+
+DriSurfaceFactory::HardwareState DriSurfaceFactory::InitializeHardware() {
+ if (state_ != UNINITIALIZED)
+ return state_;
+
+ if (drm_->get_fd() < 0) {
+ LOG(ERROR) << "Failed to create DRI connection";
+ state_ = FAILED;
+ return state_;
+ }
+
+ SkImageInfo info = SkImageInfo::MakeN32Premul(kCursorSize.width(),
+ kCursorSize.height());
+ for (size_t i = 0; i < arraysize(cursor_buffers_); ++i) {
+ cursor_buffers_[i] = new DriBuffer(drm_);
+ if (!cursor_buffers_[i]->Initialize(info)) {
+ LOG(ERROR) << "Failed to initialize cursor buffer";
+ state_ = FAILED;
+ return state_;
+ }
+ }
+
+ state_ = INITIALIZED;
+ return state_;
+}
+
+void DriSurfaceFactory::ShutdownHardware() {
+ DCHECK(state_ == INITIALIZED);
+ state_ = UNINITIALIZED;
+}
+
+scoped_ptr<ui::SurfaceOzoneCanvas> DriSurfaceFactory::CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget) {
+ DCHECK(state_ == INITIALIZED);
+
+ return scoped_ptr<ui::SurfaceOzoneCanvas>(
+ new DriSurface(window_manager_->GetWindowDelegate(widget), drm_));
+}
+
+bool DriSurfaceFactory::LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+ return false;
+}
+
+void DriSurfaceFactory::SetHardwareCursor(gfx::AcceleratedWidget widget,
+ const std::vector<SkBitmap>& bitmaps,
+ const gfx::Point& location,
+ int frame_delay_ms) {
+ cursor_widget_ = widget;
+ 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,
+ &DriSurfaceFactory::OnCursorAnimationTimeout);
+
+ if (state_ != INITIALIZED)
+ return;
+
+ ResetCursor();
+}
+
+void DriSurfaceFactory::MoveHardwareCursor(gfx::AcceleratedWidget widget,
+ const gfx::Point& location) {
+ cursor_location_ = location;
+
+ if (state_ != INITIALIZED)
+ return;
+
+ HardwareDisplayController* controller =
+ window_manager_->GetWindowDelegate(widget)->GetController();
+ if (controller)
+ controller->MoveCursor(location);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DriSurfaceFactory private
+
+void DriSurfaceFactory::ResetCursor() {
+ if (!cursor_widget_)
+ return;
+
+ HardwareDisplayController* controller =
+ window_manager_->GetWindowDelegate(cursor_widget_)->GetController();
+ if (cursor_bitmaps_.size()) {
+ // Draw new cursor into backbuffer.
+ UpdateCursorImage(cursor_buffers_[cursor_frontbuffer_ ^ 1].get(),
+ cursor_bitmaps_[cursor_frame_]);
+
+ // Reset location & buffer.
+ if (controller) {
+ controller->MoveCursor(cursor_location_);
+ controller->SetCursor(cursor_buffers_[cursor_frontbuffer_ ^ 1]);
+ cursor_frontbuffer_ ^= 1;
+ }
+ } else {
+ // No cursor set.
+ if (controller)
+ controller->UnsetCursor();
+ }
+}
+
+void DriSurfaceFactory::OnCursorAnimationTimeout() {
+ cursor_frame_++;
+ cursor_frame_ %= cursor_bitmaps_.size();
+
+ ResetCursor();
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/dri_surface_factory.h b/ui/ozone/platform/dri/dri_surface_factory.h
new file mode 100644
index 0000000..6800128
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_surface_factory.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_PLATFORM_DRI_DRI_SURFACE_FACTORY_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_SURFACE_FACTORY_H_
+
+#include <map>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/timer/timer.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/ozone/platform/dri/hardware_cursor_delegate.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace ui {
+
+class DriBuffer;
+class DriWindowDelegateManager;
+class DriWrapper;
+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 DriSurfaceFactory : public SurfaceFactoryOzone,
+ public HardwareCursorDelegate {
+ public:
+ static const gfx::AcceleratedWidget kDefaultWidgetHandle;
+
+ DriSurfaceFactory(DriWrapper* drm,
+ ScreenManager* screen_manager,
+ DriWindowDelegateManager* window_manager);
+ virtual ~DriSurfaceFactory();
+
+ // Describes the state of the hardware after initialization.
+ enum HardwareState {
+ UNINITIALIZED,
+ INITIALIZED,
+ FAILED,
+ };
+
+ // Open the display device.
+ HardwareState InitializeHardware();
+
+ // Close the display device.
+ void ShutdownHardware();
+
+ // SurfaceFactoryOzone:
+ virtual scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget) OVERRIDE;
+ virtual bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
+
+ // HardwareCursorDelegate:
+ virtual void SetHardwareCursor(gfx::AcceleratedWidget widget,
+ const std::vector<SkBitmap>& bitmaps,
+ const gfx::Point& location,
+ int frame_delay_ms) OVERRIDE;
+ virtual void MoveHardwareCursor(gfx::AcceleratedWidget window,
+ const gfx::Point& location) OVERRIDE;
+
+ protected:
+ // Draw the last set cursor & update the cursor plane.
+ void ResetCursor();
+
+ // Draw next frame in an animated cursor.
+ void OnCursorAnimationTimeout();
+
+ DriWrapper* drm_; // Not owned.
+ ScreenManager* screen_manager_; // Not owned.
+ DriWindowDelegateManager* window_manager_; // Not owned.
+ HardwareState state_;
+
+ scoped_refptr<DriBuffer> cursor_buffers_[2];
+ int cursor_frontbuffer_;
+
+ gfx::AcceleratedWidget cursor_widget_;
+ std::vector<SkBitmap> cursor_bitmaps_;
+ gfx::Point cursor_location_;
+ int cursor_frame_;
+ int cursor_frame_delay_ms_;
+ base::RepeatingTimer<DriSurfaceFactory> cursor_timer_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriSurfaceFactory);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_SURFACE_FACTORY_H_
diff --git a/ui/ozone/platform/dri/dri_surface_factory_unittest.cc b/ui/ozone/platform/dri/dri_surface_factory_unittest.cc
new file mode 100644
index 0000000..1fbaf31
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_surface_factory_unittest.cc
@@ -0,0 +1,155 @@
+// 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/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_surface.h"
+#include "ui/ozone/platform/dri/dri_surface_factory.h"
+#include "ui/ozone/platform/dri/dri_window_delegate_impl.h"
+#include "ui/ozone/platform/dri/dri_window_delegate_manager.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h"
+#include "ui/ozone/public/surface_factory_ozone.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 uint32_t kDefaultCrtc = 1;
+const uint32_t kDefaultConnector = 2;
+
+class MockScreenManager : public ui::ScreenManager {
+ public:
+ MockScreenManager(ui::DriWrapper* dri,
+ ui::ScanoutBufferGenerator* buffer_generator)
+ : ScreenManager(dri, buffer_generator),
+ dri_(dri) {}
+ virtual ~MockScreenManager() {}
+
+ // 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.
+ virtual void ForceInitializationOfPrimaryDisplay() OVERRIDE {
+ ConfigureDisplayController(
+ kDefaultCrtc, kDefaultConnector, gfx::Point(), kDefaultMode);
+ }
+
+ private:
+ ui::DriWrapper* dri_; // Not owned.
+
+ DISALLOW_COPY_AND_ASSIGN(MockScreenManager);
+};
+
+} // namespace
+
+class DriSurfaceFactoryTest : public testing::Test {
+ public:
+ DriSurfaceFactoryTest() {}
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+ protected:
+ scoped_ptr<base::MessageLoop> message_loop_;
+ scoped_ptr<ui::MockDriWrapper> dri_;
+ scoped_ptr<ui::DriBufferGenerator> buffer_generator_;
+ scoped_ptr<MockScreenManager> screen_manager_;
+ scoped_ptr<ui::DriSurfaceFactory> factory_;
+ scoped_ptr<ui::DriWindowDelegateManager> window_delegate_manager_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DriSurfaceFactoryTest);
+};
+
+void DriSurfaceFactoryTest::SetUp() {
+ message_loop_.reset(new base::MessageLoopForUI);
+ dri_.reset(new ui::MockDriWrapper(3));
+ buffer_generator_.reset(new ui::DriBufferGenerator(dri_.get()));
+ screen_manager_.reset(new MockScreenManager(dri_.get(),
+ buffer_generator_.get()));
+ window_delegate_manager_.reset(new ui::DriWindowDelegateManager());
+ factory_.reset(new ui::DriSurfaceFactory(
+ dri_.get(), screen_manager_.get(), window_delegate_manager_.get()));
+
+ scoped_ptr<ui::DriWindowDelegate> window_delegate(
+ new ui::DriWindowDelegateImpl(ui::DriSurfaceFactory::kDefaultWidgetHandle,
+ screen_manager_.get()));
+ window_delegate->Initialize();
+ window_delegate_manager_->AddWindowDelegate(
+ ui::DriSurfaceFactory::kDefaultWidgetHandle, window_delegate.Pass());
+}
+
+void DriSurfaceFactoryTest::TearDown() {
+ scoped_ptr<ui::DriWindowDelegate> delegate =
+ window_delegate_manager_->RemoveWindowDelegate(
+ ui::DriSurfaceFactory::kDefaultWidgetHandle);
+ delegate->Shutdown();
+ factory_.reset();
+ message_loop_.reset();
+}
+
+TEST_F(DriSurfaceFactoryTest, FailInitialization) {
+ dri_->fail_init();
+ EXPECT_EQ(ui::DriSurfaceFactory::FAILED, factory_->InitializeHardware());
+}
+
+TEST_F(DriSurfaceFactoryTest, SuccessfulInitialization) {
+ EXPECT_EQ(ui::DriSurfaceFactory::INITIALIZED,
+ factory_->InitializeHardware());
+}
+
+TEST_F(DriSurfaceFactoryTest, SuccessfulWidgetRealization) {
+ EXPECT_EQ(ui::DriSurfaceFactory::INITIALIZED,
+ factory_->InitializeHardware());
+
+ EXPECT_TRUE(factory_->CreateCanvasForWidget(
+ ui::DriSurfaceFactory::kDefaultWidgetHandle));
+}
+
+TEST_F(DriSurfaceFactoryTest, SetCursorImage) {
+ EXPECT_EQ(ui::DriSurfaceFactory::INITIALIZED,
+ factory_->InitializeHardware());
+
+ scoped_ptr<ui::SurfaceOzoneCanvas> surf = factory_->CreateCanvasForWidget(
+ ui::DriSurfaceFactory::kDefaultWidgetHandle);
+ EXPECT_TRUE(surf);
+
+ SkBitmap image;
+ SkImageInfo info = SkImageInfo::Make(
+ 6, 4, kN32_SkColorType, kPremul_SkAlphaType);
+ image.allocPixels(info);
+ image.eraseColor(SK_ColorWHITE);
+
+ std::vector<SkBitmap> cursor_bitmaps;
+ cursor_bitmaps.push_back(image);
+ factory_->SetHardwareCursor(ui::DriSurfaceFactory::kDefaultWidgetHandle,
+ cursor_bitmaps,
+ gfx::Point(4, 2),
+ 0);
+
+ SkBitmap cursor;
+ // Buffers 0 and 1 are the cursor buffers.
+ cursor.setInfo(dri_->buffers()[1]->getCanvas()->imageInfo());
+ EXPECT_TRUE(dri_->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 < info.width() && i < info.height())
+ EXPECT_EQ(SK_ColorWHITE, cursor.getColor(j, i));
+ else
+ EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
+ cursor.getColor(j, i));
+ }
+ }
+}
diff --git a/ui/ozone/platform/dri/dri_surface_unittest.cc b/ui/ozone/platform/dri/dri_surface_unittest.cc
new file mode 100644
index 0000000..0d64728
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_surface_unittest.cc
@@ -0,0 +1,128 @@
+// 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/dri/crtc_state.h"
+#include "ui/ozone/platform/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_surface.h"
+#include "ui/ozone/platform/dri/dri_window_delegate.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+#include "ui/ozone/platform/dri/test/mock_dri_wrapper.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 kDefaultCrtc = 1;
+const uint32_t kDefaultConnector = 2;
+
+class MockDriWindowDelegate : public ui::DriWindowDelegate {
+ public:
+ MockDriWindowDelegate(ui::DriWrapper* drm) {
+ controller_.reset(new ui::HardwareDisplayController(
+ drm,
+ make_scoped_ptr(
+ new ui::CrtcState(drm, kDefaultCrtc, kDefaultConnector))));
+ scoped_refptr<ui::DriBuffer> buffer(new ui::DriBuffer(drm));
+ SkImageInfo info = SkImageInfo::MakeN32Premul(kDefaultMode.hdisplay,
+ kDefaultMode.vdisplay);
+ EXPECT_TRUE(buffer->Initialize(info));
+ EXPECT_TRUE(controller_->Modeset(ui::OverlayPlane(buffer), kDefaultMode));
+ }
+ virtual ~MockDriWindowDelegate() {}
+
+ // DriWindowDelegate:
+ virtual void Initialize() OVERRIDE {}
+ virtual void Shutdown() OVERRIDE {}
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE { return 1; }
+ virtual ui::HardwareDisplayController* GetController() OVERRIDE {
+ return controller_.get();
+ }
+ virtual void OnBoundsChanged(const gfx::Rect& bounds) OVERRIDE {}
+
+ private:
+ scoped_ptr<ui::HardwareDisplayController> controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDriWindowDelegate);
+};
+
+} // namespace
+
+class DriSurfaceTest : public testing::Test {
+ public:
+ DriSurfaceTest() {}
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ protected:
+ scoped_ptr<base::MessageLoop> message_loop_;
+ scoped_ptr<ui::MockDriWrapper> drm_;
+ scoped_ptr<MockDriWindowDelegate> window_delegate_;
+ scoped_ptr<ui::DriSurface> surface_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DriSurfaceTest);
+};
+
+void DriSurfaceTest::SetUp() {
+ message_loop_.reset(new base::MessageLoopForUI);
+ drm_.reset(new ui::MockDriWrapper(3));
+ window_delegate_.reset(new MockDriWindowDelegate(drm_.get()));
+ surface_.reset(new ui::DriSurface(window_delegate_.get(), drm_.get()));
+ surface_->ResizeCanvas(gfx::Size(kDefaultMode.hdisplay,
+ kDefaultMode.vdisplay));
+}
+
+void DriSurfaceTest::TearDown() {
+ surface_.reset();
+ window_delegate_.reset();
+ drm_.reset();
+ message_loop_.reset();
+}
+
+TEST_F(DriSurfaceTest, CheckFBIDOnSwap) {
+ surface_->PresentCanvas(gfx::Rect());
+ // Framebuffer ID 1 is allocated in SetUp for the buffer used to modeset.
+ EXPECT_EQ(3u, drm_->current_framebuffer());
+ surface_->PresentCanvas(gfx::Rect());
+ EXPECT_EQ(2u, drm_->current_framebuffer());
+}
+
+TEST_F(DriSurfaceTest, CheckSurfaceContents) {
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ SkRect rect = SkRect::MakeWH(kDefaultMode.hdisplay / 2,
+ kDefaultMode.vdisplay / 2);
+ surface_->GetCanvas()->drawRect(rect, paint);
+ surface_->PresentCanvas(
+ gfx::Rect(0, 0, kDefaultMode.hdisplay / 2, kDefaultMode.vdisplay / 2));
+
+ SkBitmap image;
+ // Buffer 0 is the buffer used in SetUp for modesetting and buffer 1 is the
+ // frontbuffer.
+ // Buffer 2 is the backbuffer we just painted in, so we want to make sure its
+ // contents are correct.
+ image.setInfo(drm_->buffers()[2]->getCanvas()->imageInfo());
+ EXPECT_TRUE(drm_->buffers()[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));
+ }
+ }
+}
diff --git a/ui/ozone/platform/dri/dri_util.cc b/ui/ozone/platform/dri/dri_util.cc
new file mode 100644
index 0000000..5305f6d
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_util.cc
@@ -0,0 +1,138 @@
+// 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/dri/dri_util.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+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;
+}
+
+} // 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;
+}
+
+bool MapDumbBuffer(int fd,
+ uint32_t handle,
+ uint32_t size,
+ void** pixels) {
+ struct drm_mode_map_dumb map_request;
+ memset(&map_request, 0, sizeof(map_request));
+ map_request.handle = handle;
+ if (drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map_request)) {
+ VLOG(2) << "Cannot prepare dumb buffer for mapping (" << errno << ") "
+ << strerror(errno);
+ return false;
+ }
+
+ *pixels = mmap(0,
+ size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ map_request.offset);
+ if (*pixels == MAP_FAILED) {
+ VLOG(2) << "Cannot mmap dumb buffer (" << errno << ") " << strerror(errno);
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/dri_util.h b/ui/ozone/platform/dri/dri_util.h
new file mode 100644
index 0000000..94f2b45
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_util.h
@@ -0,0 +1,49 @@
+// 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_DRI_DRI_UTIL_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_UTIL_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "ui/ozone/platform/dri/scoped_drm_types.h"
+
+typedef struct _drmModeModeInfo drmModeModeInfo;
+
+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);
+
+// Memory maps a DRM buffer.
+bool MapDumbBuffer(int fd,
+ uint32_t handle,
+ uint32_t size,
+ void** pixels);
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_UTIL_H_
diff --git a/ui/ozone/platform/dri/dri_vsync_provider.cc b/ui/ozone/platform/dri/dri_vsync_provider.cc
new file mode 100644
index 0000000..3888d40
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_vsync_provider.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/dri/dri_vsync_provider.h"
+
+#include "base/time/time.h"
+#include "ui/ozone/platform/dri/dri_window_delegate.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+
+namespace ui {
+
+DriVSyncProvider::DriVSyncProvider(DriWindowDelegate* window_delegate)
+ : window_delegate_(window_delegate) {
+}
+
+DriVSyncProvider::~DriVSyncProvider() {}
+
+void DriVSyncProvider::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->get_time_of_last_flip() == 0 ||
+ controller->get_mode().vrefresh == 0)
+ return;
+
+ // Stores the time of the last refresh.
+ base::TimeTicks timebase =
+ base::TimeTicks::FromInternalValue(controller->get_time_of_last_flip());
+ // 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/dri/dri_vsync_provider.h b/ui/ozone/platform/dri/dri_vsync_provider.h
new file mode 100644
index 0000000..c90aa80
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_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_DRI_VSYNC_PROVIDER_H_
+#define UI_OZONE_PLATFORM_IMPL_DRI_VSYNC_PROVIDER_H_
+
+#include "ui/gfx/vsync_provider.h"
+
+namespace ui {
+
+class DriWindowDelegate;
+
+class DriVSyncProvider : public gfx::VSyncProvider {
+ public:
+ DriVSyncProvider(DriWindowDelegate* window_delegate);
+ virtual ~DriVSyncProvider();
+
+ virtual void GetVSyncParameters(const UpdateVSyncCallback& callback) OVERRIDE;
+
+ private:
+ DriWindowDelegate* window_delegate_; // Not owned.
+
+ DISALLOW_COPY_AND_ASSIGN(DriVSyncProvider);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_IMPL_DRI_VSYNC_PROVIDER_H_
diff --git a/ui/ozone/platform/dri/dri_window.cc b/ui/ozone/platform/dri/dri_window.cc
new file mode 100644
index 0000000..7e60bd7
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_window.cc
@@ -0,0 +1,111 @@
+// 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/dri/dri_window.h"
+
+#include "base/bind.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/ozone/platform/dri/dri_cursor.h"
+#include "ui/ozone/platform/dri/dri_window_delegate.h"
+#include "ui/ozone/platform/dri/dri_window_delegate_manager.h"
+#include "ui/ozone/platform/dri/dri_window_manager.h"
+#include "ui/platform_window/platform_window_delegate.h"
+
+namespace ui {
+
+DriWindow::DriWindow(PlatformWindowDelegate* delegate,
+ const gfx::Rect& bounds,
+ scoped_ptr<DriWindowDelegate> dri_window_delegate,
+ EventFactoryEvdev* event_factory,
+ DriWindowDelegateManager* window_delegate_manager,
+ DriWindowManager* window_manager)
+ : delegate_(delegate),
+ bounds_(bounds),
+ widget_(dri_window_delegate->GetAcceleratedWidget()),
+ dri_window_delegate_(dri_window_delegate.get()),
+ event_factory_(event_factory),
+ window_delegate_manager_(window_delegate_manager),
+ window_manager_(window_manager) {
+ window_delegate_manager_->AddWindowDelegate(widget_,
+ dri_window_delegate.Pass());
+ window_manager_->AddWindow(widget_, this);
+}
+
+DriWindow::~DriWindow() {
+ PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
+ dri_window_delegate_->Shutdown();
+ window_manager_->RemoveWindow(widget_);
+ window_delegate_manager_->RemoveWindowDelegate(widget_);
+}
+
+void DriWindow::Initialize() {
+ dri_window_delegate_->Initialize();
+ dri_window_delegate_->OnBoundsChanged(bounds_);
+ delegate_->OnAcceleratedWidgetAvailable(widget_);
+ PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
+}
+
+void DriWindow::Show() {}
+
+void DriWindow::Hide() {}
+
+void DriWindow::Close() {}
+
+void DriWindow::SetBounds(const gfx::Rect& bounds) {
+ bounds_ = bounds;
+ delegate_->OnBoundsChanged(bounds);
+ if (window_manager_->cursor()->GetCursorWindow() == widget_)
+ window_manager_->cursor()->HideCursor();
+
+ dri_window_delegate_->OnBoundsChanged(bounds);
+
+ if (window_manager_->cursor()->GetCursorWindow() == widget_)
+ window_manager_->cursor()->ShowCursor();
+}
+
+gfx::Rect DriWindow::GetBounds() {
+ return bounds_;
+}
+
+void DriWindow::SetCapture() {}
+
+void DriWindow::ReleaseCapture() {}
+
+void DriWindow::ToggleFullscreen() {}
+
+void DriWindow::Maximize() {}
+
+void DriWindow::Minimize() {}
+
+void DriWindow::Restore() {}
+
+void DriWindow::SetCursor(PlatformCursor cursor) {
+ window_manager_->cursor()->SetCursor(widget_, cursor);
+}
+
+void DriWindow::MoveCursorTo(const gfx::Point& location) {
+ event_factory_->WarpCursorTo(widget_, location);
+}
+
+bool DriWindow::CanDispatchEvent(const PlatformEvent& ne) {
+ DCHECK(ne);
+ Event* event = static_cast<Event*>(ne);
+ if (event->IsMouseEvent() || event->IsScrollEvent())
+ return window_manager_->cursor()->GetCursorWindow() == widget_;
+
+ return true;
+}
+
+uint32_t DriWindow::DispatchEvent(const PlatformEvent& native_event) {
+ DispatchEventFromNativeUiEvent(
+ native_event,
+ base::Bind(&PlatformWindowDelegate::DispatchEvent,
+ base::Unretained(delegate_)));
+ return POST_DISPATCH_STOP_PROPAGATION;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/dri_window.h b/ui/ozone/platform/dri/dri_window.h
new file mode 100644
index 0000000..799b1ee
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_window.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_DRI_DRI_WINDOW_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_WINDOW_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/platform_window/platform_window.h"
+
+namespace ui {
+
+class DriWindowDelegate;
+class DriWindowDelegateManager;
+class DriWindowManager;
+class EventFactoryEvdev;
+
+class DriWindow : public PlatformWindow,
+ public PlatformEventDispatcher {
+ public:
+ DriWindow(PlatformWindowDelegate* delegate,
+ const gfx::Rect& bounds,
+ scoped_ptr<DriWindowDelegate> dri_window_delegate,
+ EventFactoryEvdev* event_factory,
+ DriWindowDelegateManager* window_delegate_manager,
+ DriWindowManager* window_manager);
+ virtual ~DriWindow();
+
+ void Initialize();
+
+ // PlatformWindow:
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual gfx::Rect GetBounds() OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual void ToggleFullscreen() OVERRIDE;
+ virtual void Maximize() OVERRIDE;
+ virtual void Minimize() OVERRIDE;
+ virtual void Restore() OVERRIDE;
+ virtual void SetCursor(PlatformCursor cursor) OVERRIDE;
+ virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
+
+ // PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const PlatformEvent& event) OVERRIDE;
+ virtual uint32_t DispatchEvent(const PlatformEvent& event) OVERRIDE;
+
+ private:
+ PlatformWindowDelegate* delegate_;
+ gfx::Rect bounds_;
+ gfx::AcceleratedWidget widget_;
+ DriWindowDelegate* dri_window_delegate_;
+ EventFactoryEvdev* event_factory_;
+ DriWindowDelegateManager* window_delegate_manager_;
+ DriWindowManager* window_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriWindow);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_WINDOW_H_
diff --git a/ui/ozone/platform/dri/dri_window_delegate.h b/ui/ozone/platform/dri/dri_window_delegate.h
new file mode 100644
index 0000000..2787e2c
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_window_delegate.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_PLATFORM_DRI_DRI_WINDOW_DELEGATE_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_WINDOW_DELEGATE_H_
+
+#include "ui/gfx/native_widget_types.h"
+
+namespace gfx {
+class Rect;
+} // namespace gfx
+
+namespace ui {
+
+class HardwareDisplayController;
+
+// Interface for the display-server half of a DriWindow.
+//
+// The main implementation of this lives in the process that owns the display
+// connection (usually the GPU process) and associates a platform window
+// (DriWindow) 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.
+//
+// In software mode, this is owned directly on DriWindow because the display
+// controller object is in the same process.
+//
+// In accelerated mode, there's a proxy implementation and calls are forwarded
+// to the real object in the GPU process via IPC.
+class DriWindowDelegate {
+ public:
+ virtual ~DriWindowDelegate() {}
+
+ virtual void Initialize() = 0;
+
+ virtual void Shutdown() = 0;
+
+ // Returns the accelerated widget associated with the delegate.
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0;
+
+ // 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.
+ virtual HardwareDisplayController* GetController() = 0;
+
+ // Called when the window is resized/moved.
+ virtual void OnBoundsChanged(const gfx::Rect& bounds) = 0;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_WINDOW_DELEGATE_H_
diff --git a/ui/ozone/platform/dri/dri_window_delegate_impl.cc b/ui/ozone/platform/dri/dri_window_delegate_impl.cc
new file mode 100644
index 0000000..a95a8fc
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_window_delegate_impl.cc
@@ -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.
+
+#include "ui/ozone/platform/dri/dri_window_delegate_impl.h"
+
+#include "base/debug/trace_event.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+
+namespace ui {
+
+DriWindowDelegateImpl::DriWindowDelegateImpl(gfx::AcceleratedWidget widget,
+ ScreenManager* screen_manager)
+ : widget_(widget), screen_manager_(screen_manager) {
+}
+
+DriWindowDelegateImpl::~DriWindowDelegateImpl() {
+}
+
+void DriWindowDelegateImpl::Initialize() {
+ TRACE_EVENT1("dri", "DriWindowDelegateImpl::Initialize", "widget", widget_);
+}
+
+void DriWindowDelegateImpl::Shutdown() {
+ TRACE_EVENT1("dri", "DriWindowDelegateImpl::Shutdown", "widget", widget_);
+}
+
+gfx::AcceleratedWidget DriWindowDelegateImpl::GetAcceleratedWidget() {
+ return widget_;
+}
+
+HardwareDisplayController* DriWindowDelegateImpl::GetController() {
+ return controller_.get();
+}
+
+void DriWindowDelegateImpl::OnBoundsChanged(const gfx::Rect& bounds) {
+ TRACE_EVENT2("dri",
+ "DriWindowDelegateImpl::OnBoundsChanged",
+ "widget",
+ widget_,
+ "bounds",
+ bounds.ToString());
+ controller_ = screen_manager_->GetDisplayController(bounds);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/dri_window_delegate_impl.h b/ui/ozone/platform/dri/dri_window_delegate_impl.h
new file mode 100644
index 0000000..336b05d
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_window_delegate_impl.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_DRI_DRI_WINDOW_DELEGATE_IMPL_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_WINDOW_DELEGATE_IMPL_H_
+
+#include "base/memory/weak_ptr.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/dri/dri_window_delegate.h"
+
+namespace gfx {
+class Rect;
+} // namespace gfx
+
+namespace ui {
+
+class HardwareDisplayController;
+class ScreenManager;
+
+class DriWindowDelegateImpl : public DriWindowDelegate {
+ public:
+ DriWindowDelegateImpl(gfx::AcceleratedWidget widget,
+ ScreenManager* screen_manager);
+ virtual ~DriWindowDelegateImpl();
+
+ // DriWindowDelegate:
+ virtual void Initialize() OVERRIDE;
+ virtual void Shutdown() OVERRIDE;
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+ virtual HardwareDisplayController* GetController() OVERRIDE;
+ virtual void OnBoundsChanged(const gfx::Rect& bounds) OVERRIDE;
+
+ private:
+ gfx::AcceleratedWidget widget_;
+
+ ScreenManager* screen_manager_; // Not owned.
+
+ base::WeakPtr<HardwareDisplayController> controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriWindowDelegateImpl);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_WINDOW_DELEGATE_IMPL_H_
diff --git a/ui/ozone/platform/dri/dri_window_delegate_manager.cc b/ui/ozone/platform/dri/dri_window_delegate_manager.cc
new file mode 100644
index 0000000..ffbc4ba
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_window_delegate_manager.cc
@@ -0,0 +1,49 @@
+// 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/dri/dri_window_delegate_manager.h"
+
+#include "ui/ozone/platform/dri/dri_window_delegate.h"
+
+namespace ui {
+
+DriWindowDelegateManager::DriWindowDelegateManager() {
+}
+
+DriWindowDelegateManager::~DriWindowDelegateManager() {
+ DCHECK(delegate_map_.empty());
+}
+
+void DriWindowDelegateManager::AddWindowDelegate(
+ gfx::AcceleratedWidget widget,
+ scoped_ptr<DriWindowDelegate> delegate) {
+ std::pair<WidgetToDelegateMap::iterator, bool> result =
+ delegate_map_.add(widget, delegate.Pass());
+ DCHECK(result.second) << "Delegate already added.";
+}
+
+scoped_ptr<DriWindowDelegate> DriWindowDelegateManager::RemoveWindowDelegate(
+ gfx::AcceleratedWidget widget) {
+ scoped_ptr<DriWindowDelegate> delegate = delegate_map_.take_and_erase(widget);
+ DCHECK(delegate) << "Attempting to remove non-existing delegate for "
+ << widget;
+ return delegate.Pass();
+}
+
+DriWindowDelegate* DriWindowDelegateManager::GetWindowDelegate(
+ gfx::AcceleratedWidget widget) {
+ WidgetToDelegateMap::iterator it = delegate_map_.find(widget);
+ if (it != delegate_map_.end())
+ return it->second;
+
+ NOTREACHED() << "Attempting to get non-existing delegate for " << widget;
+ return NULL;
+}
+
+bool DriWindowDelegateManager::HasWindowDelegate(
+ gfx::AcceleratedWidget widget) {
+ return delegate_map_.find(widget) != delegate_map_.end();
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/dri_window_delegate_manager.h b/ui/ozone/platform/dri/dri_window_delegate_manager.h
new file mode 100644
index 0000000..5f2a572
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_window_delegate_manager.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_PLATFORM_DRI_DRI_WINDOW_DELEGATE_MANAGER_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_WINDOW_DELEGATE_MANAGER_H_
+
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace ui {
+
+class DriWindowDelegate;
+
+class DriWindowDelegateManager {
+ public:
+ DriWindowDelegateManager();
+ ~DriWindowDelegateManager();
+
+ // Adds a delegate for |widget|. Note: |widget| should not be associated with
+ // a delegate when calling this function.
+ void AddWindowDelegate(gfx::AcceleratedWidget widget,
+ scoped_ptr<DriWindowDelegate> surface);
+
+ // Removes the delegate for |widget|. Note: |widget| must have a delegate
+ // associated with it when calling this function.
+ scoped_ptr<DriWindowDelegate> RemoveWindowDelegate(
+ gfx::AcceleratedWidget widget);
+
+ // Returns the delegate associated with |widget|. Note: This function should
+ // be called only if a valid delegate has been associated with |widget|.
+ DriWindowDelegate* GetWindowDelegate(gfx::AcceleratedWidget widget);
+
+ // Check if |widget| has a valid delegate associated with it.
+ bool HasWindowDelegate(gfx::AcceleratedWidget widget);
+
+ private:
+ typedef base::ScopedPtrHashMap<gfx::AcceleratedWidget, DriWindowDelegate>
+ WidgetToDelegateMap;
+
+ WidgetToDelegateMap delegate_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriWindowDelegateManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_WINDOW_DELEGATE_MANAGER_H_
diff --git a/ui/ozone/platform/dri/dri_window_delegate_proxy.cc b/ui/ozone/platform/dri/dri_window_delegate_proxy.cc
new file mode 100644
index 0000000..8d875f4
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_window_delegate_proxy.cc
@@ -0,0 +1,74 @@
+// 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/dri/dri_window_delegate_proxy.h"
+
+#include "ui/ozone/common/gpu/ozone_gpu_messages.h"
+#include "ui/ozone/platform/dri/gpu_platform_support_host_gbm.h"
+
+namespace ui {
+
+DriWindowDelegateProxy::DriWindowDelegateProxy(
+ gfx::AcceleratedWidget widget,
+ GpuPlatformSupportHostGbm* sender)
+ : widget_(widget), sender_(sender) {
+}
+
+DriWindowDelegateProxy::~DriWindowDelegateProxy() {
+}
+
+void DriWindowDelegateProxy::Initialize() {
+ TRACE_EVENT1("dri", "DriWindowDelegateProxy::Initialize", "widget", widget_);
+ sender_->AddChannelObserver(this);
+}
+
+void DriWindowDelegateProxy::Shutdown() {
+ TRACE_EVENT1("dri", "DriWindowDelegateProxy::Shutdown", "widget", widget_);
+ sender_->RemoveChannelObserver(this);
+ if (!sender_->IsConnected())
+ return;
+
+ bool status = sender_->Send(new OzoneGpuMsg_DestroyWindowDelegate(widget_));
+ DCHECK(status);
+}
+
+gfx::AcceleratedWidget DriWindowDelegateProxy::GetAcceleratedWidget() {
+ return widget_;
+}
+
+HardwareDisplayController* DriWindowDelegateProxy::GetController() {
+ NOTREACHED();
+ return NULL;
+}
+
+void DriWindowDelegateProxy::OnBoundsChanged(const gfx::Rect& bounds) {
+ TRACE_EVENT2("dri",
+ "DriWindowDelegateProxy::OnBoundsChanged",
+ "widget",
+ widget_,
+ "bounds",
+ bounds.ToString());
+ bounds_ = bounds;
+ if (!sender_->IsConnected())
+ return;
+
+ bool status =
+ sender_->Send(new OzoneGpuMsg_WindowBoundsChanged(widget_, bounds));
+ DCHECK(status);
+}
+
+void DriWindowDelegateProxy::OnChannelEstablished() {
+ TRACE_EVENT1(
+ "dri", "DriWindowDelegateProxy::OnChannelEstablished", "widget", widget_);
+ bool status = sender_->Send(new OzoneGpuMsg_CreateWindowDelegate(widget_));
+ DCHECK(status);
+ OnBoundsChanged(bounds_);
+}
+
+void DriWindowDelegateProxy::OnChannelDestroyed() {
+ TRACE_EVENT1(
+ "dri", "DriWindowDelegateProxy::OnChannelDestroyed", "widget", widget_);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/dri_window_delegate_proxy.h b/ui/ozone/platform/dri/dri_window_delegate_proxy.h
new file mode 100644
index 0000000..ef95c4c
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_window_delegate_proxy.h
@@ -0,0 +1,49 @@
+// 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_DRI_DRI_WINDOW_DELEGATE_PROXY_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_WINDOW_DELEGATE_PROXY_H_
+
+#include "ui/gfx/geometry/rect.h"
+#include "ui/ozone/platform/dri/channel_observer.h"
+#include "ui/ozone/platform/dri/dri_window_delegate.h"
+
+namespace ui {
+
+class GpuPlatformSupportHostGbm;
+
+// This is used when running with a GPU process (or with the in-process GPU) to
+// IPC the native window configuration from the browser to the GPU.
+class DriWindowDelegateProxy : public DriWindowDelegate,
+ public ChannelObserver {
+ public:
+ DriWindowDelegateProxy(gfx::AcceleratedWidget widget,
+ GpuPlatformSupportHostGbm* sender);
+ virtual ~DriWindowDelegateProxy();
+
+ // DriWindowDelegate:
+ virtual void Initialize() OVERRIDE;
+ virtual void Shutdown() OVERRIDE;
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+ virtual HardwareDisplayController* GetController() OVERRIDE;
+ virtual void OnBoundsChanged(const gfx::Rect& bounds) OVERRIDE;
+
+ // ChannelObserver:
+ virtual void OnChannelEstablished() OVERRIDE;
+ virtual void OnChannelDestroyed() OVERRIDE;
+
+ private:
+ gfx::AcceleratedWidget widget_;
+ GpuPlatformSupportHostGbm* sender_; // Not owned.
+
+ // Cached state for the window. If the GPU process crashes, this state is used
+ // to update the GPU side when it comes back.
+ gfx::Rect bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriWindowDelegateProxy);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_WINDOW_DELEGATE_PROXY_H_
diff --git a/ui/ozone/platform/dri/dri_window_manager.cc b/ui/ozone/platform/dri/dri_window_manager.cc
new file mode 100644
index 0000000..289d930
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_window_manager.cc
@@ -0,0 +1,77 @@
+// 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/dri/dri_window_manager.h"
+
+#include "base/logging.h"
+#include "ui/ozone/platform/dri/dri_cursor.h"
+#include "ui/ozone/platform/dri/dri_window.h"
+
+namespace ui {
+
+namespace {
+
+gfx::PointF GetDefaultCursorLocation(DriWindow* window) {
+ return gfx::PointF(window->GetBounds().width() / 2,
+ window->GetBounds().height() / 2);
+}
+
+} // namespace
+
+DriWindowManager::DriWindowManager(HardwareCursorDelegate* cursor_delegate)
+ : last_allocated_widget_(0), cursor_(new DriCursor(cursor_delegate, this)) {
+}
+
+DriWindowManager::~DriWindowManager() {
+}
+
+gfx::AcceleratedWidget DriWindowManager::NextAcceleratedWidget() {
+ // We're not using 0 since other code assumes that a 0 AcceleratedWidget is an
+ // invalid widget.
+ return ++last_allocated_widget_;
+}
+
+void DriWindowManager::AddWindow(gfx::AcceleratedWidget widget,
+ DriWindow* window) {
+ std::pair<WidgetToWindowMap::iterator, bool> result = window_map_.insert(
+ std::pair<gfx::AcceleratedWidget, DriWindow*>(widget, window));
+ DCHECK(result.second) << "Window for " << widget << " already added.";
+
+ if (cursor_->GetCursorWindow() == gfx::kNullAcceleratedWidget)
+ ResetCursorLocation();
+}
+
+void DriWindowManager::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 (cursor_->GetCursorWindow() == widget)
+ ResetCursorLocation();
+}
+
+DriWindow* DriWindowManager::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;
+}
+
+void DriWindowManager::ResetCursorLocation() {
+ gfx::AcceleratedWidget cursor_widget = gfx::kNullAcceleratedWidget;
+ gfx::PointF location;
+ if (!window_map_.empty()) {
+ WidgetToWindowMap::iterator it = window_map_.begin();
+ cursor_widget = it->first;
+ location = GetDefaultCursorLocation(it->second);
+ }
+
+ cursor_->MoveCursorTo(cursor_widget, location);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/dri_window_manager.h b/ui/ozone/platform/dri/dri_window_manager.h
new file mode 100644
index 0000000..5a03957
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_window_manager.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 UI_OZONE_PLATFORM_DRI_DRI_WINDOW_MANAGER_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_WINDOW_MANAGER_H_
+
+#include <map>
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace ui {
+
+class DriCursor;
+class DriWindow;
+class HardwareCursorDelegate;
+
+// Responsible for keeping the mapping between the allocated widgets and
+// windows.
+class DriWindowManager {
+ public:
+ explicit DriWindowManager(HardwareCursorDelegate* cursor_delegate);
+ ~DriWindowManager();
+
+ gfx::AcceleratedWidget NextAcceleratedWidget();
+
+ // Adds a window for |widget|. Note: |widget| should not be associated when
+ // calling this function.
+ void AddWindow(gfx::AcceleratedWidget widget, DriWindow* 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.
+ DriWindow* GetWindow(gfx::AcceleratedWidget widget);
+
+ DriCursor* cursor() const { return cursor_.get(); }
+
+ private:
+ // Reset the cursor location based on the list of active windows.
+ void ResetCursorLocation();
+
+ typedef std::map<gfx::AcceleratedWidget, DriWindow*> WidgetToWindowMap;
+
+ gfx::AcceleratedWidget last_allocated_widget_;
+ WidgetToWindowMap window_map_;
+
+ scoped_ptr<DriCursor> cursor_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriWindowManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_WINDOW_MANAGER_H_
diff --git a/ui/ozone/platform/dri/dri_wrapper.cc b/ui/ozone/platform/dri/dri_wrapper.cc
new file mode 100644
index 0000000..7e80c3a
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_wrapper.cc
@@ -0,0 +1,304 @@
+// 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/dri/dri_wrapper.h"
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
+#include "ui/ozone/platform/dri/dri_util.h"
+
+namespace ui {
+
+namespace {
+
+uint32_t ToFixedPoint(double v) {
+ // This returns a number in a 16-bit.16-bit fixed point.
+ return v * 65536.0;
+}
+
+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) {
+ VLOG(2) << "Cannot create dumb buffer (" << errno << ") "
+ << strerror(errno);
+ 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;
+}
+
+void DrmDestroyDumbBuffer(int fd, uint32_t handle) {
+ struct drm_mode_destroy_dumb destroy_request;
+ memset(&destroy_request, 0, sizeof(destroy_request));
+ destroy_request.handle = handle;
+ drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request);
+}
+
+} // namespace
+
+DriWrapper::DriWrapper(const char* device_path)
+ : fd_(-1), device_path_(device_path) {
+}
+
+DriWrapper::~DriWrapper() {
+ if (fd_ >= 0)
+ close(fd_);
+}
+
+void DriWrapper::Initialize() {
+ fd_ = open(device_path_, O_RDWR | O_CLOEXEC);
+ if (fd_ < 0)
+ PLOG(FATAL) << "open: " << device_path_;
+}
+
+ScopedDrmCrtcPtr DriWrapper::GetCrtc(uint32_t crtc_id) {
+ DCHECK(fd_ >= 0);
+ return ScopedDrmCrtcPtr(drmModeGetCrtc(fd_, crtc_id));
+}
+
+bool DriWrapper::SetCrtc(uint32_t crtc_id,
+ uint32_t framebuffer,
+ std::vector<uint32_t> connectors,
+ drmModeModeInfo* mode) {
+ DCHECK(fd_ >= 0);
+ DCHECK(!connectors.empty());
+ DCHECK(mode);
+
+ TRACE_EVENT2("dri",
+ "DriWrapper::SetCrtc",
+ "crtc",
+ crtc_id,
+ "size",
+ gfx::Size(mode->hdisplay, mode->vdisplay).ToString());
+ return !drmModeSetCrtc(fd_,
+ crtc_id,
+ framebuffer,
+ 0,
+ 0,
+ vector_as_array(&connectors),
+ connectors.size(), mode);
+}
+
+bool DriWrapper::SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) {
+ DCHECK(fd_ >= 0);
+ // If there's no buffer then the CRTC was disabled.
+ if (!crtc->buffer_id)
+ return DisableCrtc(crtc->crtc_id);
+
+ DCHECK(!connectors.empty());
+
+ TRACE_EVENT1("dri", "DriWrapper::RestoreCrtc",
+ "crtc", crtc->crtc_id);
+ return !drmModeSetCrtc(fd_,
+ crtc->crtc_id,
+ crtc->buffer_id,
+ crtc->x,
+ crtc->y,
+ vector_as_array(&connectors),
+ connectors.size(),
+ &crtc->mode);
+}
+
+bool DriWrapper::DisableCrtc(uint32_t crtc_id) {
+ DCHECK(fd_ >= 0);
+ TRACE_EVENT1("dri", "DriWrapper::DisableCrtc",
+ "crtc", crtc_id);
+ return !drmModeSetCrtc(fd_, crtc_id, 0, 0, 0, NULL, 0, NULL);
+}
+
+ScopedDrmConnectorPtr DriWrapper::GetConnector(uint32_t connector_id) {
+ DCHECK(fd_ >= 0);
+ TRACE_EVENT1("dri", "DriWrapper::GetConnector", "connector", connector_id);
+ return ScopedDrmConnectorPtr(drmModeGetConnector(fd_, connector_id));
+}
+
+bool DriWrapper::AddFramebuffer(uint32_t width,
+ uint32_t height,
+ uint8_t depth,
+ uint8_t bpp,
+ uint32_t stride,
+ uint32_t handle,
+ uint32_t* framebuffer) {
+ DCHECK(fd_ >= 0);
+ TRACE_EVENT1("dri", "DriWrapper::AddFramebuffer",
+ "handle", handle);
+ return !drmModeAddFB(fd_,
+ width,
+ height,
+ depth,
+ bpp,
+ stride,
+ handle,
+ framebuffer);
+}
+
+bool DriWrapper::RemoveFramebuffer(uint32_t framebuffer) {
+ DCHECK(fd_ >= 0);
+ TRACE_EVENT1("dri", "DriWrapper::RemoveFramebuffer",
+ "framebuffer", framebuffer);
+ return !drmModeRmFB(fd_, framebuffer);
+}
+
+bool DriWrapper::PageFlip(uint32_t crtc_id,
+ uint32_t framebuffer,
+ void* data) {
+ DCHECK(fd_ >= 0);
+ TRACE_EVENT2("dri", "DriWrapper::PageFlip",
+ "crtc", crtc_id,
+ "framebuffer", framebuffer);
+ return !drmModePageFlip(fd_,
+ crtc_id,
+ framebuffer,
+ DRM_MODE_PAGE_FLIP_EVENT,
+ data);
+}
+
+bool DriWrapper::PageFlipOverlay(uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& location,
+ const gfx::RectF& source,
+ int overlay_plane) {
+ DCHECK(fd_ >= 0);
+ TRACE_EVENT2("dri", "DriWrapper::PageFlipOverlay",
+ "crtc", crtc_id,
+ "framebuffer", framebuffer);
+ return !drmModeSetPlane(fd_,
+ overlay_plane,
+ crtc_id,
+ framebuffer,
+ 0,
+ location.x(),
+ location.y(),
+ location.width(),
+ location.height(),
+ ToFixedPoint(source.x()),
+ ToFixedPoint(source.y()),
+ ToFixedPoint(source.width()),
+ ToFixedPoint(source.height()));
+}
+
+ScopedDrmFramebufferPtr DriWrapper::GetFramebuffer(uint32_t framebuffer) {
+ DCHECK(fd_ >= 0);
+ TRACE_EVENT1("dri", "DriWrapper::GetFramebuffer",
+ "framebuffer", framebuffer);
+ return ScopedDrmFramebufferPtr(drmModeGetFB(fd_, framebuffer));
+}
+
+ScopedDrmPropertyPtr DriWrapper::GetProperty(drmModeConnector* connector,
+ const char* name) {
+ TRACE_EVENT2("dri", "DriWrapper::GetProperty",
+ "connector", connector->connector_id,
+ "name", name);
+ for (int i = 0; i < connector->count_props; ++i) {
+ ScopedDrmPropertyPtr property(drmModeGetProperty(fd_, connector->props[i]));
+ if (!property)
+ continue;
+
+ if (strcmp(property->name, name) == 0)
+ return property.Pass();
+ }
+
+ return ScopedDrmPropertyPtr();
+}
+
+bool DriWrapper::SetProperty(uint32_t connector_id,
+ uint32_t property_id,
+ uint64_t value) {
+ DCHECK(fd_ >= 0);
+ return !drmModeConnectorSetProperty(fd_, connector_id, property_id, value);
+}
+
+ScopedDrmPropertyBlobPtr DriWrapper::GetPropertyBlob(
+ drmModeConnector* connector, const char* name) {
+ DCHECK(fd_ >= 0);
+ TRACE_EVENT2("dri", "DriWrapper::GetPropertyBlob",
+ "connector", connector->connector_id,
+ "name", name);
+ for (int i = 0; i < connector->count_props; ++i) {
+ ScopedDrmPropertyPtr property(drmModeGetProperty(fd_, connector->props[i]));
+ if (!property)
+ continue;
+
+ if (strcmp(property->name, name) == 0 &&
+ property->flags & DRM_MODE_PROP_BLOB)
+ return ScopedDrmPropertyBlobPtr(
+ drmModeGetPropertyBlob(fd_, connector->prop_values[i]));
+ }
+
+ return ScopedDrmPropertyBlobPtr();
+}
+
+bool DriWrapper::SetCursor(uint32_t crtc_id,
+ uint32_t handle,
+ const gfx::Size& size) {
+ DCHECK(fd_ >= 0);
+ TRACE_EVENT1("dri", "DriWrapper::SetCursor", "handle", handle);
+ return !drmModeSetCursor(fd_, crtc_id, handle, size.width(), size.height());
+}
+
+bool DriWrapper::MoveCursor(uint32_t crtc_id, const gfx::Point& point) {
+ DCHECK(fd_ >= 0);
+ return !drmModeMoveCursor(fd_, crtc_id, point.x(), point.y());
+}
+
+void DriWrapper::HandleEvent(drmEventContext& event) {
+ DCHECK(fd_ >= 0);
+ TRACE_EVENT0("dri", "DriWrapper::HandleEvent");
+ drmHandleEvent(fd_, &event);
+}
+
+bool DriWrapper::CreateDumbBuffer(const SkImageInfo& info,
+ uint32_t* handle,
+ uint32_t* stride,
+ void** pixels) {
+ DCHECK(fd_ >= 0);
+
+ TRACE_EVENT0("dri", "DriWrapper::CreateDumbBuffer");
+ if (!DrmCreateDumbBuffer(fd_, info, handle, stride))
+ return false;
+
+ if (!MapDumbBuffer(fd_, *handle, info.getSafeSize(*stride), pixels)) {
+ DrmDestroyDumbBuffer(fd_, *handle);
+ return false;
+ }
+
+ return true;
+}
+
+void DriWrapper::DestroyDumbBuffer(const SkImageInfo& info,
+ uint32_t handle,
+ uint32_t stride,
+ void* pixels) {
+ DCHECK(fd_ >= 0);
+ TRACE_EVENT1("dri", "DriWrapper::DestroyDumbBuffer", "handle", handle);
+ munmap(pixels, info.getSafeSize(stride));
+ DrmDestroyDumbBuffer(fd_, handle);
+}
+
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/dri_wrapper.h b/ui/ozone/platform/dri/dri_wrapper.h
new file mode 100644
index 0000000..a555814
--- /dev/null
+++ b/ui/ozone/platform/dri/dri_wrapper.h
@@ -0,0 +1,149 @@
+// 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_DRI_DRI_WRAPPER_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_WRAPPER_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/macros.h"
+#include "ui/gfx/overlay_transform.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/rect_f.h"
+#include "ui/ozone/platform/dri/scoped_drm_types.h"
+
+typedef struct _drmEventContext drmEventContext;
+typedef struct _drmModeModeInfo drmModeModeInfo;
+
+struct SkImageInfo;
+
+namespace ui {
+
+// 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 DriWrapper {
+ public:
+ DriWrapper(const char* device_path);
+ virtual ~DriWrapper();
+
+ // Open device.
+ virtual void Initialize();
+
+ // 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_|. |data| is a generic pointer to some information the user
+ // will receive when processing the pageflip event.
+ virtual bool PageFlip(uint32_t crtc_id, uint32_t framebuffer, void* data);
+
+ // 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::RectF& 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);
+
+ // 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 void HandleEvent(drmEventContext& event);
+
+ virtual bool CreateDumbBuffer(const SkImageInfo& info,
+ uint32_t* handle,
+ uint32_t* stride,
+ void** pixels);
+
+ virtual void DestroyDumbBuffer(const SkImageInfo& info,
+ uint32_t handle,
+ uint32_t stride,
+ void* pixels);
+
+ int get_fd() const { return fd_; }
+
+ protected:
+ // The file descriptor associated with this wrapper. All DRM operations will
+ // be performed using this FD.
+ int fd_;
+
+ private:
+ // Path to DRM device.
+ const char* device_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriWrapper);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_WRAPPER_H_
diff --git a/ui/ozone/platform/dri/gbm.gypi b/ui/ozone/platform/dri/gbm.gypi
new file mode 100644
index 0000000..b5af8bd
--- /dev/null
+++ b/ui/ozone/platform/dri/gbm.gypi
@@ -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.
+
+{
+ 'variables': {
+ 'internal_ozone_platform_deps': [
+ 'ozone_platform_gbm',
+ ],
+ 'internal_ozone_platforms': [
+ 'gbm',
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'ozone_platform_gbm',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../build/linux/system.gyp:libdrm',
+ '../../build/linux/system.gyp:gbm',
+ '../../skia/skia.gyp:skia',
+ '../../third_party/khronos/khronos.gyp:khronos_headers',
+ '../base/ui_base.gyp:ui_base',
+ '../events/events.gyp:events',
+ '../events/ozone/events_ozone.gyp:events_ozone',
+ '../gfx/gfx.gyp:gfx',
+ ],
+ 'defines': [
+ 'OZONE_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'channel_observer.h',
+ 'dri_window_delegate_proxy.cc',
+ 'dri_window_delegate_proxy.h',
+ 'gbm_buffer.cc',
+ 'gbm_buffer.h',
+ 'gbm_buffer_base.cc',
+ 'gbm_buffer_base.h',
+ 'gbm_surface.cc',
+ 'gbm_surface.h',
+ 'gbm_surfaceless.cc',
+ 'gbm_surfaceless.h',
+ 'gbm_surface_factory.cc',
+ 'gbm_surface_factory.h',
+ 'gpu_platform_support_gbm.cc',
+ 'gpu_platform_support_gbm.h',
+ 'gpu_platform_support_host_gbm.cc',
+ 'gpu_platform_support_host_gbm.h',
+ 'native_display_delegate_proxy.cc',
+ 'native_display_delegate_proxy.h',
+ 'ozone_platform_gbm.cc',
+ 'ozone_platform_gbm.h',
+ ],
+ },
+ ],
+}
diff --git a/ui/ozone/platform/dri/gbm_buffer.cc b/ui/ozone/platform/dri/gbm_buffer.cc
new file mode 100644
index 0000000..398064d
--- /dev/null
+++ b/ui/ozone/platform/dri/gbm_buffer.cc
@@ -0,0 +1,78 @@
+// 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/dri/gbm_buffer.h"
+
+#include <gbm.h>
+
+#include "base/logging.h"
+
+namespace ui {
+
+namespace {
+
+int GetGbmFormatFromBufferFormat(SurfaceFactoryOzone::BufferFormat fmt) {
+ switch (fmt) {
+ case SurfaceFactoryOzone::RGBA_8888:
+ return GBM_BO_FORMAT_ARGB8888;
+ case SurfaceFactoryOzone::RGBX_8888:
+ return GBM_BO_FORMAT_XRGB8888;
+ default:
+ NOTREACHED();
+ return 0;
+ }
+}
+
+} // namespace
+
+GbmBuffer::GbmBuffer(DriWrapper* dri, gbm_bo* bo, bool scanout)
+ : GbmBufferBase(dri, bo, scanout) {
+}
+
+GbmBuffer::~GbmBuffer() {
+ if (bo())
+ gbm_bo_destroy(bo());
+}
+
+// static
+scoped_refptr<GbmBuffer> GbmBuffer::CreateBuffer(
+ DriWrapper* dri,
+ gbm_device* device,
+ SurfaceFactoryOzone::BufferFormat format,
+ const gfx::Size& size,
+ bool scanout) {
+ unsigned flags = GBM_BO_USE_RENDERING;
+ if (scanout)
+ flags |= GBM_BO_USE_SCANOUT;
+ gbm_bo* bo = gbm_bo_create(device,
+ size.width(),
+ size.height(),
+ GetGbmFormatFromBufferFormat(format),
+ flags);
+ if (!bo)
+ return NULL;
+
+ scoped_refptr<GbmBuffer> buffer(new GbmBuffer(dri, bo, scanout));
+ if (scanout && !buffer->GetFramebufferId())
+ return NULL;
+
+ return buffer;
+}
+
+GbmPixmap::GbmPixmap(scoped_refptr<GbmBuffer> buffer) : buffer_(buffer) {
+}
+
+GbmPixmap::~GbmPixmap() {
+}
+
+void* GbmPixmap::GetEGLClientBuffer() {
+ return buffer_->bo();
+}
+
+int GbmPixmap::GetDmaBufFd() {
+ NOTIMPLEMENTED();
+ return -1;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/gbm_buffer.h b/ui/ozone/platform/dri/gbm_buffer.h
new file mode 100644
index 0000000..b455db3
--- /dev/null
+++ b/ui/ozone/platform/dri/gbm_buffer.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 UI_OZONE_PLATFORM_DRI_GBM_BUFFER_H_
+#define UI_OZONE_PLATFORM_DRI_GBM_BUFFER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/dri/gbm_buffer_base.h"
+#include "ui/ozone/public/native_pixmap.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+struct gbm_bo;
+struct gbm_device;
+
+namespace ui {
+
+class DriWrapper;
+
+class GbmBuffer : public GbmBufferBase {
+ public:
+ static scoped_refptr<GbmBuffer> CreateBuffer(
+ DriWrapper* dri,
+ gbm_device* device,
+ SurfaceFactoryOzone::BufferFormat format,
+ const gfx::Size& size,
+ bool scanout);
+
+ private:
+ GbmBuffer(DriWrapper* dri, gbm_bo* bo, bool scanout);
+ virtual ~GbmBuffer();
+
+ DISALLOW_COPY_AND_ASSIGN(GbmBuffer);
+};
+
+class GbmPixmap : public NativePixmap {
+ public:
+ GbmPixmap(scoped_refptr<GbmBuffer> buffer);
+
+ // NativePixmap:
+ virtual void* GetEGLClientBuffer() OVERRIDE;
+ virtual int GetDmaBufFd() OVERRIDE;
+
+ scoped_refptr<GbmBuffer> buffer() { return buffer_; }
+
+ private:
+ virtual ~GbmPixmap();
+
+ scoped_refptr<GbmBuffer> buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmPixmap);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_GBM_BUFFER_H_
diff --git a/ui/ozone/platform/dri/gbm_buffer_base.cc b/ui/ozone/platform/dri/gbm_buffer_base.cc
new file mode 100644
index 0000000..f5c057a
--- /dev/null
+++ b/ui/ozone/platform/dri/gbm_buffer_base.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/dri/gbm_buffer_base.h"
+
+#include <gbm.h>
+
+#include "base/logging.h"
+#include "ui/ozone/platform/dri/dri_wrapper.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(DriWrapper* dri, gbm_bo* bo, bool scanout)
+ : dri_(dri), bo_(bo), framebuffer_(0) {
+ if (scanout && !dri_->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_))
+ LOG(ERROR) << "Failed to register buffer";
+}
+
+GbmBufferBase::~GbmBufferBase() {
+ if (framebuffer_)
+ dri_->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/dri/gbm_buffer_base.h b/ui/ozone/platform/dri/gbm_buffer_base.h
new file mode 100644
index 0000000..b536694
--- /dev/null
+++ b/ui/ozone/platform/dri/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_DRI_GBM_BUFFER_BASE_H_
+#define UI_OZONE_PLATFORM_DRI_GBM_BUFFER_BASE_H_
+
+#include "ui/ozone/platform/dri/scanout_buffer.h"
+
+struct gbm_bo;
+
+namespace ui {
+
+class DriWrapper;
+
+// 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:
+ virtual uint32_t GetFramebufferId() const OVERRIDE;
+ virtual uint32_t GetHandle() const OVERRIDE;
+ virtual gfx::Size GetSize() const OVERRIDE;
+
+ protected:
+ GbmBufferBase(DriWrapper* dri, gbm_bo* bo, bool scanout);
+ virtual ~GbmBufferBase();
+
+ private:
+ DriWrapper* dri_;
+ gbm_bo* bo_;
+ uint32_t framebuffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmBufferBase);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_GBM_BUFFER_BASE_H_
diff --git a/ui/ozone/platform/dri/gbm_surface.cc b/ui/ozone/platform/dri/gbm_surface.cc
new file mode 100644
index 0000000..18d00e6
--- /dev/null
+++ b/ui/ozone/platform/dri/gbm_surface.cc
@@ -0,0 +1,161 @@
+// 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/dri/gbm_surface.h"
+
+#include <gbm.h>
+
+#include "base/logging.h"
+#include "ui/ozone/platform/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_window_delegate.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/gbm_buffer_base.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+#include "ui/ozone/platform/dri/scanout_buffer.h"
+
+namespace ui {
+
+namespace {
+
+class GbmSurfaceBuffer : public GbmBufferBase {
+ public:
+ static scoped_refptr<GbmSurfaceBuffer> CreateBuffer(DriWrapper* dri,
+ gbm_bo* buffer);
+ static scoped_refptr<GbmSurfaceBuffer> GetBuffer(gbm_bo* buffer);
+
+ private:
+ GbmSurfaceBuffer(DriWrapper* dri, gbm_bo* bo);
+ virtual ~GbmSurfaceBuffer();
+
+ 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(DriWrapper* dri, gbm_bo* bo)
+ : GbmBufferBase(dri, bo, true) {
+ if (GetFramebufferId()) {
+ self_ = this;
+ gbm_bo_set_user_data(bo, this, GbmSurfaceBuffer::Destroy);
+ }
+}
+
+GbmSurfaceBuffer::~GbmSurfaceBuffer() {}
+
+// static
+scoped_refptr<GbmSurfaceBuffer> GbmSurfaceBuffer::CreateBuffer(
+ DriWrapper* dri, gbm_bo* buffer) {
+ scoped_refptr<GbmSurfaceBuffer> scoped_buffer(new GbmSurfaceBuffer(dri,
+ 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(DriWindowDelegate* window_delegate,
+ gbm_device* device,
+ DriWrapper* dri)
+ : GbmSurfaceless(window_delegate),
+ gbm_device_(device),
+ dri_(dri),
+ native_surface_(NULL),
+ current_buffer_(NULL) {
+}
+
+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() {
+ 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(dri_, pending_buffer);
+ if (!primary.get()) {
+ LOG(ERROR) << "Failed to associate the buffer with the controller";
+ return false;
+ }
+ }
+
+ // The primary buffer is a special case.
+ if (window_delegate_->GetController())
+ window_delegate_->GetController()->QueueOverlayPlane(OverlayPlane(primary));
+
+ if (!GbmSurfaceless::OnSwapBuffers())
+ return false;
+
+ // 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;
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/gbm_surface.h b/ui/ozone/platform/dri/gbm_surface.h
new file mode 100644
index 0000000..be52c9c
--- /dev/null
+++ b/ui/ozone/platform/dri/gbm_surface.h
@@ -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.
+
+#ifndef UI_OZONE_PLATFORM_DRI_GBM_SURFACE_H_
+#define UI_OZONE_PLATFORM_DRI_GBM_SURFACE_H_
+
+#include "base/macros.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/dri/gbm_surfaceless.h"
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+struct gbm_bo;
+struct gbm_device;
+struct gbm_surface;
+
+namespace ui {
+
+class DriBuffer;
+class DriWrapper;
+class DriWindowDelegate;
+
+// 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(DriWindowDelegate* window_delegate,
+ gbm_device* device,
+ DriWrapper* dri);
+ virtual ~GbmSurface();
+
+ bool Initialize();
+
+ // GbmSurfaceless:
+ virtual intptr_t GetNativeWindow() OVERRIDE;
+ virtual bool ResizeNativeWindow(const gfx::Size& viewport_size) OVERRIDE;
+ virtual bool OnSwapBuffers() OVERRIDE;
+
+ private:
+ gbm_device* gbm_device_;
+
+ DriWrapper* dri_;
+
+ // 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_;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmSurface);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_GBM_SURFACE_H_
diff --git a/ui/ozone/platform/dri/gbm_surface_factory.cc b/ui/ozone/platform/dri/gbm_surface_factory.cc
new file mode 100644
index 0000000..a31fcee
--- /dev/null
+++ b/ui/ozone/platform/dri/gbm_surface_factory.cc
@@ -0,0 +1,231 @@
+// 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/dri/gbm_surface_factory.h"
+
+#include <gbm.h>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "third_party/khronos/EGL/egl.h"
+#include "ui/ozone/platform/dri/dri_window_delegate_impl.h"
+#include "ui/ozone/platform/dri/dri_window_delegate_manager.h"
+#include "ui/ozone/platform/dri/gbm_buffer.h"
+#include "ui/ozone/platform/dri/gbm_surface.h"
+#include "ui/ozone/platform/dri/gbm_surfaceless.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+#include "ui/ozone/public/native_pixmap.h"
+#include "ui/ozone/public/overlay_candidates_ozone.h"
+#include "ui/ozone/public/ozone_switches.h"
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+namespace ui {
+namespace {
+
+class SingleOverlay : public OverlayCandidatesOzone {
+ public:
+ SingleOverlay() {}
+ virtual ~SingleOverlay() {}
+
+ virtual void CheckOverlaySupport(
+ OverlaySurfaceCandidateList* candidates) OVERRIDE {
+ if (candidates->size() == 2) {
+ 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 {
+ NOTREACHED();
+ return;
+ }
+ if (overlay->plane_z_order > 0 &&
+ IsTransformSupported(overlay->transform)) {
+ overlay->overlay_handled = true;
+ }
+ }
+ }
+
+ private:
+ bool IsTransformSupported(gfx::OverlayTransform transform) {
+ switch (transform) {
+ case gfx::OVERLAY_TRANSFORM_NONE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(SingleOverlay);
+};
+
+} // namespace
+
+GbmSurfaceFactory::GbmSurfaceFactory(bool allow_surfaceless)
+ : DriSurfaceFactory(NULL, NULL, NULL),
+ device_(NULL),
+ allow_surfaceless_(allow_surfaceless) {
+}
+
+GbmSurfaceFactory::~GbmSurfaceFactory() {}
+
+void GbmSurfaceFactory::InitializeGpu(
+ DriWrapper* dri,
+ gbm_device* device,
+ ScreenManager* screen_manager,
+ DriWindowDelegateManager* window_manager) {
+ drm_ = dri;
+ device_ = device;
+ screen_manager_ = screen_manager;
+ window_manager_ = window_manager;
+}
+
+intptr_t GbmSurfaceFactory::GetNativeDisplay() {
+ DCHECK(state_ == INITIALIZED);
+ return reinterpret_cast<intptr_t>(device_);
+}
+
+const int32* GbmSurfaceFactory::GetEGLSurfaceProperties(
+ const int32* desired_list) {
+ 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) {
+ base::NativeLibraryLoadError error;
+ base::NativeLibrary gles_library = base::LoadNativeLibrary(
+ base::FilePath("libGLESv2.so.2"),
+ &error);
+ if (!gles_library) {
+ LOG(WARNING) << "Failed to load GLES library: " << error.ToString();
+ return false;
+ }
+
+ base::NativeLibrary egl_library = base::LoadNativeLibrary(
+ base::FilePath("libEGL.so.1"),
+ &error);
+ if (!egl_library) {
+ LOG(WARNING) << "Failed to load EGL library: " << error.ToString();
+ base::UnloadNativeLibrary(gles_library);
+ return false;
+ }
+
+ GLGetProcAddressProc get_proc_address =
+ reinterpret_cast<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;
+}
+
+scoped_ptr<SurfaceOzoneEGL> GbmSurfaceFactory::CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget) {
+ DCHECK(state_ == INITIALIZED);
+
+ DriWindowDelegate* delegate = GetOrCreateWindowDelegate(widget);
+
+ scoped_ptr<GbmSurface> surface(new GbmSurface(delegate, device_, drm_));
+ if (!surface->Initialize())
+ return scoped_ptr<SurfaceOzoneEGL>();
+
+ return surface.PassAs<SurfaceOzoneEGL>();
+}
+
+scoped_ptr<SurfaceOzoneEGL>
+GbmSurfaceFactory::CreateSurfacelessEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget) {
+ if (!allow_surfaceless_)
+ return scoped_ptr<SurfaceOzoneEGL>();
+
+ DriWindowDelegate* delegate = GetOrCreateWindowDelegate(widget);
+ return scoped_ptr<SurfaceOzoneEGL>(new GbmSurfaceless(delegate));
+}
+
+scoped_refptr<ui::NativePixmap> GbmSurfaceFactory::CreateNativePixmap(
+ gfx::Size size,
+ BufferFormat format) {
+ scoped_refptr<GbmBuffer> buffer = GbmBuffer::CreateBuffer(
+ drm_, device_, format, size, true);
+ if (!buffer.get())
+ return NULL;
+
+ return scoped_refptr<GbmPixmap>(new GbmPixmap(buffer));
+}
+
+OverlayCandidatesOzone* GbmSurfaceFactory::GetOverlayCandidates(
+ gfx::AcceleratedWidget w) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kOzoneTestSingleOverlaySupport))
+ return new SingleOverlay();
+ return NULL;
+}
+
+bool GbmSurfaceFactory::ScheduleOverlayPlane(
+ gfx::AcceleratedWidget widget,
+ int plane_z_order,
+ gfx::OverlayTransform plane_transform,
+ scoped_refptr<NativePixmap> buffer,
+ const gfx::Rect& display_bounds,
+ const gfx::RectF& crop_rect) {
+ scoped_refptr<GbmPixmap> pixmap = static_cast<GbmPixmap*>(buffer.get());
+ if (!pixmap.get()) {
+ LOG(ERROR) << "ScheduleOverlayPlane passed NULL buffer.";
+ return false;
+ }
+ HardwareDisplayController* hdc =
+ window_manager_->GetWindowDelegate(widget)->GetController();
+ if (!hdc)
+ return true;
+
+ hdc->QueueOverlayPlane(OverlayPlane(pixmap->buffer(),
+ plane_z_order,
+ plane_transform,
+ display_bounds,
+ crop_rect));
+ return true;
+}
+
+bool GbmSurfaceFactory::CanShowPrimaryPlaneAsOverlay() {
+ return allow_surfaceless_;
+}
+
+DriWindowDelegate* GbmSurfaceFactory::GetOrCreateWindowDelegate(
+ gfx::AcceleratedWidget widget) {
+ if (!window_manager_->HasWindowDelegate(widget)) {
+ scoped_ptr<DriWindowDelegate> delegate(
+ new DriWindowDelegateImpl(widget, screen_manager_));
+ delegate->Initialize();
+ window_manager_->AddWindowDelegate(widget, delegate.Pass());
+ }
+
+ return window_manager_->GetWindowDelegate(widget);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/gbm_surface_factory.h b/ui/ozone/platform/dri/gbm_surface_factory.h
new file mode 100644
index 0000000..2118db2
--- /dev/null
+++ b/ui/ozone/platform/dri/gbm_surface_factory.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_DRI_GBM_SURFACE_FACTORY_H_
+#define UI_OZONE_PLATFORM_DRI_GBM_SURFACE_FACTORY_H_
+
+#include "ui/ozone/platform/dri/dri_surface_factory.h"
+
+struct gbm_device;
+
+namespace ui {
+
+class DriWindowDelegate;
+class DriWindowDelegateManager;
+
+class GbmSurfaceFactory : public DriSurfaceFactory {
+ public:
+ GbmSurfaceFactory(bool allow_surfaceless);
+ virtual ~GbmSurfaceFactory();
+
+ void InitializeGpu(DriWrapper* dri,
+ gbm_device* device,
+ ScreenManager* screen_manager,
+ DriWindowDelegateManager* window_manager);
+
+ // DriSurfaceFactory:
+ virtual intptr_t GetNativeDisplay() OVERRIDE;
+ virtual const int32_t* GetEGLSurfaceProperties(
+ const int32_t* desired_list) OVERRIDE;
+ virtual bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
+ virtual scoped_ptr<ui::SurfaceOzoneEGL> CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget w) OVERRIDE;
+ virtual scoped_ptr<SurfaceOzoneEGL> CreateSurfacelessEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget) OVERRIDE;
+ virtual scoped_refptr<ui::NativePixmap> CreateNativePixmap(
+ gfx::Size size,
+ BufferFormat format) OVERRIDE;
+ virtual OverlayCandidatesOzone* GetOverlayCandidates(
+ gfx::AcceleratedWidget w) OVERRIDE;
+ virtual bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
+ int plane_z_order,
+ gfx::OverlayTransform plane_transform,
+ scoped_refptr<NativePixmap> buffer,
+ const gfx::Rect& display_bounds,
+ const gfx::RectF& crop_rect) OVERRIDE;
+ virtual bool CanShowPrimaryPlaneAsOverlay() OVERRIDE;
+
+ private:
+ DriWindowDelegate* GetOrCreateWindowDelegate(gfx::AcceleratedWidget widget);
+
+ gbm_device* device_; // Not owned.
+ bool allow_surfaceless_;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmSurfaceFactory);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_GBM_SURFACE_FACTORY_H_
diff --git a/ui/ozone/platform/dri/gbm_surfaceless.cc b/ui/ozone/platform/dri/gbm_surfaceless.cc
new file mode 100644
index 0000000..b374844
--- /dev/null
+++ b/ui/ozone/platform/dri/gbm_surfaceless.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 "ui/ozone/platform/dri/gbm_surfaceless.h"
+
+#include "ui/ozone/platform/dri/dri_vsync_provider.h"
+#include "ui/ozone/platform/dri/dri_window_delegate.h"
+#include "ui/ozone/platform/dri/gbm_buffer.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+
+namespace ui {
+
+GbmSurfaceless::GbmSurfaceless(DriWindowDelegate* window_delegate)
+ : window_delegate_(window_delegate) {
+}
+
+GbmSurfaceless::~GbmSurfaceless() {}
+
+intptr_t GbmSurfaceless::GetNativeWindow() {
+ NOTREACHED();
+ return 0;
+}
+
+bool GbmSurfaceless::ResizeNativeWindow(const gfx::Size& viewport_size) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool GbmSurfaceless::OnSwapBuffers() {
+ HardwareDisplayController* controller = window_delegate_->GetController();
+ if (!controller)
+ return true;
+
+ bool success = controller->SchedulePageFlip();
+ controller->WaitForPageFlipEvent();
+
+ return success;
+}
+
+scoped_ptr<gfx::VSyncProvider> GbmSurfaceless::CreateVSyncProvider() {
+ return scoped_ptr<gfx::VSyncProvider>(new DriVSyncProvider(window_delegate_));
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/gbm_surfaceless.h b/ui/ozone/platform/dri/gbm_surfaceless.h
new file mode 100644
index 0000000..4e3b92b
--- /dev/null
+++ b/ui/ozone/platform/dri/gbm_surfaceless.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_DRI_GBM_SURFACELESS_H_
+#define UI_OZONE_PLATFORM_DRI_GBM_SURFACELESS_H_
+
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+namespace gfx {
+class Size;
+} // namespace gfx
+
+namespace ui {
+
+class DriWindowDelegate;
+
+// 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(DriWindowDelegate* window_delegate);
+ virtual ~GbmSurfaceless();
+
+ // SurfaceOzoneEGL:
+ virtual intptr_t GetNativeWindow() OVERRIDE;
+ virtual bool ResizeNativeWindow(const gfx::Size& viewport_size) OVERRIDE;
+ virtual bool OnSwapBuffers() OVERRIDE;
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE;
+
+ protected:
+ DriWindowDelegate* window_delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmSurfaceless);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_GBM_SURFACELESS_H_
diff --git a/ui/ozone/platform/dri/gpu_platform_support_gbm.cc b/ui/ozone/platform/dri/gpu_platform_support_gbm.cc
new file mode 100644
index 0000000..9bcd094
--- /dev/null
+++ b/ui/ozone/platform/dri/gpu_platform_support_gbm.cc
@@ -0,0 +1,206 @@
+// 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/dri/gpu_platform_support_gbm.h"
+
+#include "ipc/ipc_message_macros.h"
+#include "ui/display/types/display_mode.h"
+#include "ui/display/types/display_snapshot.h"
+#include "ui/ozone/common/display_util.h"
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+#include "ui/ozone/common/gpu/ozone_gpu_messages.h"
+#include "ui/ozone/platform/dri/dri_surface_factory.h"
+#include "ui/ozone/platform/dri/dri_window_delegate_impl.h"
+#include "ui/ozone/platform/dri/dri_window_delegate_manager.h"
+#include "ui/ozone/platform/dri/native_display_delegate_dri.h"
+
+namespace ui {
+
+namespace {
+
+class FindDisplayById {
+ public:
+ FindDisplayById(int64_t display_id) : display_id_(display_id) {}
+
+ bool operator()(const DisplaySnapshot_Params& display) const {
+ return display.display_id == display_id_;
+ }
+
+ private:
+ int64_t display_id_;
+};
+
+} // namespace
+
+GpuPlatformSupportGbm::GpuPlatformSupportGbm(
+ DriSurfaceFactory* dri,
+ DriWindowDelegateManager* window_manager,
+ ScreenManager* screen_manager,
+ scoped_ptr<NativeDisplayDelegateDri> ndd)
+ : sender_(NULL),
+ dri_(dri),
+ window_manager_(window_manager),
+ screen_manager_(screen_manager),
+ ndd_(ndd.Pass()) {
+}
+
+GpuPlatformSupportGbm::~GpuPlatformSupportGbm() {}
+
+void GpuPlatformSupportGbm::AddHandler(scoped_ptr<GpuPlatformSupport> handler) {
+ handlers_.push_back(handler.release());
+}
+
+void GpuPlatformSupportGbm::OnChannelEstablished(IPC::Sender* sender) {
+ sender_ = sender;
+
+ for (size_t i = 0; i < handlers_.size(); ++i)
+ handlers_[i]->OnChannelEstablished(sender);
+}
+
+bool GpuPlatformSupportGbm::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+
+ IPC_BEGIN_MESSAGE_MAP(GpuPlatformSupportGbm, message)
+ IPC_MESSAGE_HANDLER(OzoneGpuMsg_CreateWindowDelegate, OnCreateWindowDelegate)
+ IPC_MESSAGE_HANDLER(OzoneGpuMsg_DestroyWindowDelegate,
+ OnDestroyWindowDelegate)
+ IPC_MESSAGE_HANDLER(OzoneGpuMsg_WindowBoundsChanged, OnWindowBoundsChanged)
+
+ IPC_MESSAGE_HANDLER(OzoneGpuMsg_CursorSet, OnCursorSet)
+ IPC_MESSAGE_HANDLER(OzoneGpuMsg_CursorMove, OnCursorMove)
+
+ IPC_MESSAGE_HANDLER(OzoneGpuMsg_ForceDPMSOn, OnForceDPMSOn)
+ IPC_MESSAGE_HANDLER(OzoneGpuMsg_RefreshNativeDisplays,
+ OnRefreshNativeDisplays)
+ IPC_MESSAGE_HANDLER(OzoneGpuMsg_ConfigureNativeDisplay,
+ OnConfigureNativeDisplay)
+ IPC_MESSAGE_HANDLER(OzoneGpuMsg_DisableNativeDisplay, OnDisableNativeDisplay)
+ IPC_MESSAGE_UNHANDLED(handled = false);
+ IPC_END_MESSAGE_MAP()
+
+ if (!handled)
+ for (size_t i = 0; i < handlers_.size(); ++i)
+ if (handlers_[i]->OnMessageReceived(message))
+ return true;
+
+ return false;
+}
+
+void GpuPlatformSupportGbm::OnCreateWindowDelegate(
+ gfx::AcceleratedWidget widget) {
+ // Due to how the GPU process starts up this IPC call may happen after the IPC
+ // to create a surface. Since a surface wants to know the window associated
+ // with it, we create it ahead of time. So when this call happens we do not
+ // create a delegate if it already exists.
+ if (!window_manager_->HasWindowDelegate(widget)) {
+ scoped_ptr<DriWindowDelegate> delegate(
+ new DriWindowDelegateImpl(widget, screen_manager_));
+ delegate->Initialize();
+ window_manager_->AddWindowDelegate(widget, delegate.Pass());
+ }
+}
+
+void GpuPlatformSupportGbm::OnDestroyWindowDelegate(
+ gfx::AcceleratedWidget widget) {
+ scoped_ptr<DriWindowDelegate> delegate =
+ window_manager_->RemoveWindowDelegate(widget);
+ delegate->Shutdown();
+}
+
+void GpuPlatformSupportGbm::OnWindowBoundsChanged(gfx::AcceleratedWidget widget,
+ const gfx::Rect& bounds) {
+ window_manager_->GetWindowDelegate(widget)->OnBoundsChanged(bounds);
+}
+
+void GpuPlatformSupportGbm::OnCursorSet(gfx::AcceleratedWidget widget,
+ const std::vector<SkBitmap>& bitmaps,
+ const gfx::Point& location,
+ int frame_delay_ms) {
+ dri_->SetHardwareCursor(widget, bitmaps, location, frame_delay_ms);
+}
+
+void GpuPlatformSupportGbm::OnCursorMove(gfx::AcceleratedWidget widget,
+ const gfx::Point& location) {
+ dri_->MoveHardwareCursor(widget, location);
+}
+
+void GpuPlatformSupportGbm::OnForceDPMSOn() {
+ ndd_->ForceDPMSOn();
+}
+
+void GpuPlatformSupportGbm::OnRefreshNativeDisplays(
+ const std::vector<DisplaySnapshot_Params>& cached_displays) {
+ std::vector<DisplaySnapshot_Params> displays;
+ std::vector<DisplaySnapshot*> native_displays = ndd_->GetDisplays();
+
+ // If any of the cached displays are in the list of new displays then apply
+ // their configuration immediately.
+ for (size_t i = 0; i < native_displays.size(); ++i) {
+ std::vector<DisplaySnapshot_Params>::const_iterator it =
+ std::find_if(cached_displays.begin(),
+ cached_displays.end(),
+ FindDisplayById(native_displays[i]->display_id()));
+
+ if (it == cached_displays.end())
+ continue;
+
+ if (it->has_current_mode)
+ OnConfigureNativeDisplay(it->display_id, it->current_mode, it->origin);
+ else
+ OnDisableNativeDisplay(it->display_id);
+ }
+
+ for (size_t i = 0; i < native_displays.size(); ++i)
+ displays.push_back(GetDisplaySnapshotParams(*native_displays[i]));
+
+ sender_->Send(new OzoneHostMsg_UpdateNativeDisplays(displays));
+}
+
+void GpuPlatformSupportGbm::OnConfigureNativeDisplay(
+ int64_t id,
+ const DisplayMode_Params& mode_param,
+ const gfx::Point& origin) {
+ DisplaySnapshot* display = ndd_->FindDisplaySnapshot(id);
+ if (!display) {
+ LOG(ERROR) << "There is no display with ID " << id;
+ return;
+ }
+
+ const DisplayMode* mode = NULL;
+ for (size_t i = 0; i < display->modes().size(); ++i) {
+ if (mode_param.size == display->modes()[i]->size() &&
+ mode_param.is_interlaced == display->modes()[i]->is_interlaced() &&
+ mode_param.refresh_rate == display->modes()[i]->refresh_rate()) {
+ mode = display->modes()[i];
+ break;
+ }
+ }
+
+ // 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).
+ if (!mode)
+ mode = ndd_->FindDisplayMode(
+ mode_param.size, mode_param.is_interlaced, mode_param.refresh_rate);
+
+ if (!mode) {
+ LOG(ERROR) << "Failed to find mode: size=" << mode_param.size.ToString()
+ << " is_interlaced=" << mode_param.is_interlaced
+ << " refresh_rate=" << mode_param.refresh_rate;
+ return;
+ }
+
+ ndd_->Configure(*display, mode, origin);
+}
+
+void GpuPlatformSupportGbm::OnDisableNativeDisplay(int64_t id) {
+ DisplaySnapshot* display = ndd_->FindDisplaySnapshot(id);
+ if (display)
+ ndd_->Configure(*display, NULL, gfx::Point());
+ else
+ LOG(ERROR) << "There is no display with ID " << id;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/gpu_platform_support_gbm.h b/ui/ozone/platform/dri/gpu_platform_support_gbm.h
new file mode 100644
index 0000000..8fa4cc3
--- /dev/null
+++ b/ui/ozone/platform/dri/gpu_platform_support_gbm.h
@@ -0,0 +1,79 @@
+// 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_DRI_GPU_PLATFORM_SUPPORT_GBM_H_
+#define UI_OZONE_PLATFORM_DRI_GPU_PLATFORM_SUPPORT_GBM_H_
+
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/public/gpu_platform_support.h"
+
+class SkBitmap;
+
+namespace gfx {
+class Point;
+class Rect;
+}
+
+namespace ui {
+
+class DriSurfaceFactory;
+class DriWindowDelegate;
+class DriWindowDelegateManager;
+class NativeDisplayDelegateDri;
+class ScreenManager;
+
+struct DisplayMode_Params;
+struct DisplaySnapshot_Params;
+
+class GpuPlatformSupportGbm : public GpuPlatformSupport {
+ public:
+ GpuPlatformSupportGbm(DriSurfaceFactory* dri,
+ DriWindowDelegateManager* window_manager,
+ ScreenManager* screen_manager,
+ scoped_ptr<NativeDisplayDelegateDri> ndd);
+ virtual ~GpuPlatformSupportGbm();
+
+ void AddHandler(scoped_ptr<GpuPlatformSupport> handler);
+
+ // GpuPlatformSupport:
+ virtual void OnChannelEstablished(IPC::Sender* sender) OVERRIDE;
+
+ // IPC::Listener:
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ private:
+ void OnCreateWindowDelegate(gfx::AcceleratedWidget widget);
+ void OnDestroyWindowDelegate(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);
+
+ // Display related IPC handlers.
+ void OnForceDPMSOn();
+ void OnRefreshNativeDisplays(
+ const std::vector<DisplaySnapshot_Params>& cached_displays);
+ void OnConfigureNativeDisplay(int64_t id,
+ const DisplayMode_Params& mode,
+ const gfx::Point& origin);
+ void OnDisableNativeDisplay(int64_t id);
+
+ IPC::Sender* sender_; // Not owned.
+ DriSurfaceFactory* dri_; // Not owned.
+ DriWindowDelegateManager* window_manager_; // Not owned.
+ ScreenManager* screen_manager_; // Not owned.
+
+ scoped_ptr<NativeDisplayDelegateDri> ndd_;
+ ScopedVector<GpuPlatformSupport> handlers_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_GPU_PLATFORM_SUPPORT_GBM_H_
diff --git a/ui/ozone/platform/dri/gpu_platform_support_host_gbm.cc b/ui/ozone/platform/dri/gpu_platform_support_host_gbm.cc
new file mode 100644
index 0000000..f5a369a
--- /dev/null
+++ b/ui/ozone/platform/dri/gpu_platform_support_host_gbm.cc
@@ -0,0 +1,117 @@
+// 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/dri/gpu_platform_support_host_gbm.h"
+
+#include "base/debug/trace_event.h"
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+#include "ui/ozone/common/gpu/ozone_gpu_messages.h"
+#include "ui/ozone/platform/dri/channel_observer.h"
+
+namespace ui {
+
+GpuPlatformSupportHostGbm::GpuPlatformSupportHostGbm()
+ : host_id_(-1), sender_(NULL) {
+}
+
+GpuPlatformSupportHostGbm::~GpuPlatformSupportHostGbm() {}
+
+bool GpuPlatformSupportHostGbm::IsConnected() const {
+ return sender_ != NULL;
+}
+
+void GpuPlatformSupportHostGbm::RegisterHandler(
+ GpuPlatformSupportHost* handler) {
+ handlers_.push_back(handler);
+}
+
+void GpuPlatformSupportHostGbm::UnregisterHandler(
+ GpuPlatformSupportHost* handler) {
+ std::vector<GpuPlatformSupportHost*>::iterator it =
+ std::find(handlers_.begin(), handlers_.end(), handler);
+ if (it != handlers_.end())
+ handlers_.erase(it);
+}
+
+void GpuPlatformSupportHostGbm::AddChannelObserver(ChannelObserver* observer) {
+ channel_observers_.AddObserver(observer);
+
+ if (sender_)
+ observer->OnChannelEstablished();
+}
+
+void GpuPlatformSupportHostGbm::RemoveChannelObserver(
+ ChannelObserver* observer) {
+ channel_observers_.RemoveObserver(observer);
+}
+
+void GpuPlatformSupportHostGbm::OnChannelEstablished(int host_id,
+ IPC::Sender* sender) {
+ TRACE_EVENT1("dri",
+ "GpuPlatformSupportHostGbm::OnChannelEstablished",
+ "host_id",
+ host_id);
+ host_id_ = host_id;
+ sender_ = sender;
+
+ while (!queued_messages_.empty()) {
+ Send(queued_messages_.front());
+ queued_messages_.pop();
+ }
+
+ for (size_t i = 0; i < handlers_.size(); ++i)
+ handlers_[i]->OnChannelEstablished(host_id, sender);
+
+ FOR_EACH_OBSERVER(
+ ChannelObserver, channel_observers_, OnChannelEstablished());
+}
+
+void GpuPlatformSupportHostGbm::OnChannelDestroyed(int host_id) {
+ TRACE_EVENT1("dri",
+ "GpuPlatformSupportHostGbm::OnChannelDestroyed",
+ "host_id",
+ host_id);
+ if (host_id_ == host_id) {
+ host_id_ = -1;
+ sender_ = NULL;
+
+ FOR_EACH_OBSERVER(
+ ChannelObserver, channel_observers_, OnChannelDestroyed());
+ }
+
+ for (size_t i = 0; i < handlers_.size(); ++i)
+ handlers_[i]->OnChannelDestroyed(host_id);
+}
+
+bool GpuPlatformSupportHostGbm::OnMessageReceived(const IPC::Message& message) {
+ for (size_t i = 0; i < handlers_.size(); ++i)
+ if (handlers_[i]->OnMessageReceived(message))
+ return true;
+
+ return false;
+}
+
+bool GpuPlatformSupportHostGbm::Send(IPC::Message* message) {
+ if (sender_)
+ return sender_->Send(message);
+
+ queued_messages_.push(message);
+ return true;
+}
+
+void GpuPlatformSupportHostGbm::SetHardwareCursor(
+ gfx::AcceleratedWidget widget,
+ const std::vector<SkBitmap>& bitmaps,
+ const gfx::Point& location,
+ int frame_delay_ms) {
+ Send(new OzoneGpuMsg_CursorSet(widget, bitmaps, location, frame_delay_ms));
+}
+
+void GpuPlatformSupportHostGbm::MoveHardwareCursor(
+ gfx::AcceleratedWidget widget,
+ const gfx::Point& location) {
+ Send(new OzoneGpuMsg_CursorMove(widget, location));
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/gpu_platform_support_host_gbm.h b/ui/ozone/platform/dri/gpu_platform_support_host_gbm.h
new file mode 100644
index 0000000..a0e06f4
--- /dev/null
+++ b/ui/ozone/platform/dri/gpu_platform_support_host_gbm.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_DRI_GPU_PLATFORM_SUPPORT_HOST_GBM_H_
+#define UI_OZONE_PLATFORM_DRI_GPU_PLATFORM_SUPPORT_HOST_GBM_H_
+
+#include <queue>
+#include <vector>
+
+#include "base/observer_list.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/dri/hardware_cursor_delegate.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
+
+class SkBitmap;
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+
+class ChannelObserver;
+
+class GpuPlatformSupportHostGbm : public GpuPlatformSupportHost,
+ public HardwareCursorDelegate,
+ public IPC::Sender {
+ public:
+ GpuPlatformSupportHostGbm();
+ virtual ~GpuPlatformSupportHostGbm();
+
+ bool IsConnected() const;
+
+ void RegisterHandler(GpuPlatformSupportHost* handler);
+ void UnregisterHandler(GpuPlatformSupportHost* handler);
+
+ void AddChannelObserver(ChannelObserver* observer);
+ void RemoveChannelObserver(ChannelObserver* observer);
+
+ // GpuPlatformSupportHost:
+ virtual void OnChannelEstablished(int host_id, IPC::Sender* sender) OVERRIDE;
+ virtual void OnChannelDestroyed(int host_id) OVERRIDE;
+
+ // IPC::Listener:
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ // IPC::Sender:
+ virtual bool Send(IPC::Message* message) OVERRIDE;
+
+ // HardwareCursorDelegate:
+ virtual void SetHardwareCursor(gfx::AcceleratedWidget widget,
+ const std::vector<SkBitmap>& bitmaps,
+ const gfx::Point& location,
+ int frame_delay_ms) OVERRIDE;
+ virtual void MoveHardwareCursor(gfx::AcceleratedWidget widget,
+ const gfx::Point& location) OVERRIDE;
+
+ private:
+ int host_id_;
+ IPC::Sender* sender_;
+ std::vector<GpuPlatformSupportHost*> handlers_;
+ // If messages are sent before the channel is created, store the messages and
+ // delay sending them until the channel is created. These messages are stored
+ // in |queued_messaged_|.
+ std::queue<IPC::Message*> queued_messages_;
+ ObserverList<ChannelObserver> channel_observers_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_GPU_GPU_PLATFORM_SUPPORT_HOST_GBM_H_
diff --git a/ui/ozone/platform/dri/hardware_cursor_delegate.h b/ui/ozone/platform/dri/hardware_cursor_delegate.h
new file mode 100644
index 0000000..17cea44
--- /dev/null
+++ b/ui/ozone/platform/dri/hardware_cursor_delegate.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_DRI_HARDWARE_CURSOR_DELEGATE_H_
+#define UI_OZONE_PLATFORM_DRI_HARDWARE_CURSOR_DELEGATE_H_
+
+#include "ui/gfx/native_widget_types.h"
+
+class SkBitmap;
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+
+class HardwareCursorDelegate {
+ public:
+ // Update the HW cursor bitmap & move to specified location. If
+ // the bitmap is empty, the cursor is hidden.
+ virtual void SetHardwareCursor(gfx::AcceleratedWidget widget,
+ const std::vector<SkBitmap>& bitmaps,
+ const gfx::Point& location,
+ int frame_delay_ms) = 0;
+
+ // Move the HW cursor to the specified location.
+ virtual void MoveHardwareCursor(gfx::AcceleratedWidget widget,
+ const gfx::Point& location) = 0;
+
+ protected:
+ virtual ~HardwareCursorDelegate() {}
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_HARDWARE_CURSOR_DELEGATE_H_
diff --git a/ui/ozone/platform/dri/hardware_display_controller.cc b/ui/ozone/platform/dri/hardware_display_controller.cc
new file mode 100644
index 0000000..7d41188
--- /dev/null
+++ b/ui/ozone/platform/dri/hardware_display_controller.cc
@@ -0,0 +1,333 @@
+// 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/dri/hardware_display_controller.h"
+
+#include <drm.h>
+#include <errno.h>
+#include <string.h>
+#include <xf86drm.h>
+
+#include "base/basictypes.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/dri/crtc_state.h"
+#include "ui/ozone/platform/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/public/native_pixmap.h"
+
+namespace ui {
+
+namespace {
+
+// DRM callback on page flip events. This callback is triggered after the
+// page flip has happened and the backbuffer is now the new frontbuffer
+// The old frontbuffer is no longer used by the hardware and can be used for
+// future draw operations.
+//
+// |device| will contain a reference to the |ScanoutSurface| object which
+// the event belongs to.
+//
+// TODO(dnicoara) When we have a FD handler for the DRM calls in the message
+// loop, we can move this function in the handler.
+void HandlePageFlipEvent(int fd,
+ unsigned int frame,
+ unsigned int seconds,
+ unsigned int useconds,
+ void* controller) {
+ static_cast<HardwareDisplayController*>(controller)
+ ->OnPageFlipEvent(frame, seconds, useconds);
+}
+
+const OverlayPlane& GetPrimaryPlane(const OverlayPlaneList& overlays) {
+ for (size_t i = 0; i < overlays.size(); ++i) {
+ if (overlays[i].z_order == 0)
+ return overlays[i];
+ }
+
+ NOTREACHED();
+ return overlays[0];
+}
+
+} // namespace
+
+OverlayPlane::OverlayPlane(scoped_refptr<ScanoutBuffer> buffer)
+ : buffer(buffer),
+ z_order(0),
+ display_bounds(gfx::Point(), buffer->GetSize()),
+ crop_rect(0, 0, 1, 1),
+ overlay_plane(0) {}
+
+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),
+ overlay_plane(0) {
+}
+
+OverlayPlane::~OverlayPlane() {}
+
+HardwareDisplayController::HardwareDisplayController(
+ DriWrapper* drm,
+ scoped_ptr<CrtcState> state)
+ : drm_(drm),
+ is_disabled_(true),
+ time_of_last_flip_(0),
+ pending_page_flips_(0) {
+ crtc_states_.push_back(state.release());
+}
+
+HardwareDisplayController::~HardwareDisplayController() {
+ // Reset the cursor.
+ UnsetCursor();
+}
+
+bool HardwareDisplayController::Modeset(const OverlayPlane& primary,
+ drmModeModeInfo mode) {
+ TRACE_EVENT0("dri", "HDC::Modeset");
+ DCHECK(primary.buffer.get());
+ pending_page_flips_ = 0;
+ bool status = true;
+ for (size_t i = 0; i < crtc_states_.size(); ++i) {
+ status &= ModesetCrtc(primary.buffer, mode, crtc_states_[i]);
+ crtc_states_[i]->set_is_disabled(false);
+ }
+
+ // Since a subset of controllers may be actively using |primary|, just keep
+ // track of it.
+ current_planes_ = std::vector<OverlayPlane>(1, primary);
+ pending_planes_.clear();
+ is_disabled_ = false;
+ mode_ = mode;
+ return status;
+}
+
+bool HardwareDisplayController::Enable() {
+ TRACE_EVENT0("dri", "HDC::Enable");
+ DCHECK(!current_planes_.empty());
+ OverlayPlane primary = GetPrimaryPlane(current_planes_);
+ DCHECK(primary.buffer.get());
+ pending_page_flips_ = 0;
+ bool status = true;
+ for (size_t i = 0; i < crtc_states_.size(); ++i)
+ status &= ModesetCrtc(primary.buffer, mode_, crtc_states_[i]);
+
+ return status;
+}
+
+void HardwareDisplayController::Disable() {
+ TRACE_EVENT0("dri", "HDC::Disable");
+ pending_page_flips_ = 0;
+ for (size_t i = 0; i < crtc_states_.size(); ++i) {
+ drm_->DisableCrtc(crtc_states_[i]->crtc());
+ crtc_states_[i]->set_is_disabled(true);
+ }
+
+ is_disabled_ = true;
+}
+
+void HardwareDisplayController::QueueOverlayPlane(const OverlayPlane& plane) {
+ pending_planes_.push_back(plane);
+}
+
+bool HardwareDisplayController::SchedulePageFlip() {
+ DCHECK(!pending_planes_.empty());
+ DCHECK_EQ(0u, pending_page_flips_);
+
+ if (is_disabled_)
+ return true;
+
+ bool status = true;
+ for (size_t i = 0; i < crtc_states_.size(); ++i)
+ status &= SchedulePageFlipOnCrtc(pending_planes_, crtc_states_[i]);
+
+ return status;
+}
+
+void HardwareDisplayController::WaitForPageFlipEvent() {
+ TRACE_EVENT1("dri", "HDC::WaitForPageFlipEvent",
+ "pending_pageflips", pending_page_flips_);
+
+ bool has_pending_page_flips = pending_page_flips_ != 0;
+ drmEventContext drm_event;
+ drm_event.version = DRM_EVENT_CONTEXT_VERSION;
+ drm_event.page_flip_handler = HandlePageFlipEvent;
+ drm_event.vblank_handler = NULL;
+
+ // Wait for the page-flips to complete.
+ while (pending_page_flips_ > 0)
+ drm_->HandleEvent(drm_event);
+
+ // In case there are no pending pageflips do not replace the current planes
+ // since they are still being used.
+ if (has_pending_page_flips)
+ current_planes_.swap(pending_planes_);
+
+ pending_planes_.clear();
+}
+
+void HardwareDisplayController::OnPageFlipEvent(unsigned int frame,
+ unsigned int seconds,
+ unsigned int useconds) {
+ TRACE_EVENT0("dri", "HDC::OnPageFlipEvent");
+
+ --pending_page_flips_;
+ time_of_last_flip_ =
+ static_cast<uint64_t>(seconds) * base::Time::kMicrosecondsPerSecond +
+ useconds;
+}
+
+bool HardwareDisplayController::SetCursor(scoped_refptr<ScanoutBuffer> buffer) {
+ bool status = true;
+ cursor_buffer_ = buffer;
+
+ if (is_disabled_)
+ return true;
+
+ for (size_t i = 0; i < crtc_states_.size(); ++i) {
+ status &= drm_->SetCursor(
+ crtc_states_[i]->crtc(), buffer->GetHandle(), buffer->GetSize());
+ }
+
+ return status;
+}
+
+bool HardwareDisplayController::UnsetCursor() {
+ bool status = true;
+ cursor_buffer_ = NULL;
+ for (size_t i = 0; i < crtc_states_.size(); ++i)
+ status &= drm_->SetCursor(crtc_states_[i]->crtc(), 0, gfx::Size());
+
+ return status;
+}
+
+bool HardwareDisplayController::MoveCursor(const gfx::Point& location) {
+ if (is_disabled_)
+ return true;
+
+ bool status = true;
+ for (size_t i = 0; i < crtc_states_.size(); ++i)
+ status &= drm_->MoveCursor(crtc_states_[i]->crtc(), location);
+
+ return status;
+}
+
+void HardwareDisplayController::AddCrtc(
+ scoped_ptr<CrtcState> state) {
+ crtc_states_.push_back(state.release());
+}
+
+scoped_ptr<CrtcState> HardwareDisplayController::RemoveCrtc(uint32_t crtc) {
+ for (ScopedVector<CrtcState>::iterator it = crtc_states_.begin();
+ it != crtc_states_.end();
+ ++it) {
+ if ((*it)->crtc() == crtc) {
+ scoped_ptr<CrtcState> controller(*it);
+ crtc_states_.weak_erase(it);
+ return controller.Pass();
+ }
+ }
+
+ return scoped_ptr<CrtcState>();
+}
+
+bool HardwareDisplayController::HasCrtc(uint32_t crtc) const {
+ for (size_t i = 0; i < crtc_states_.size(); ++i)
+ if (crtc_states_[i]->crtc() == crtc)
+ return true;
+
+ return false;
+}
+
+bool HardwareDisplayController::IsMirrored() const {
+ return crtc_states_.size() > 1;
+}
+
+bool HardwareDisplayController::IsDisabled() const {
+ return is_disabled_;
+}
+
+gfx::Size HardwareDisplayController::GetModeSize() const {
+ return gfx::Size(mode_.hdisplay, mode_.vdisplay);
+}
+
+bool HardwareDisplayController::ModesetCrtc(
+ const scoped_refptr<ScanoutBuffer>& buffer,
+ drmModeModeInfo mode,
+ CrtcState* state) {
+ if (!drm_->SetCrtc(state->crtc(),
+ buffer->GetFramebufferId(),
+ std::vector<uint32_t>(1, state->connector()),
+ &mode)) {
+ LOG(ERROR) << "Failed to modeset: error='" << strerror(errno)
+ << "' crtc=" << state->crtc()
+ << " connector=" << state->connector()
+ << " framebuffer_id=" << buffer->GetFramebufferId()
+ << " mode=" << mode.hdisplay << "x" << mode.vdisplay << "@"
+ << mode.vrefresh;
+ return false;
+ }
+
+ return true;
+}
+
+bool HardwareDisplayController::SchedulePageFlipOnCrtc(
+ const OverlayPlaneList& overlays,
+ CrtcState* state) {
+ const OverlayPlane& primary = GetPrimaryPlane(overlays);
+ DCHECK(primary.buffer.get());
+
+ if (primary.buffer->GetSize() != gfx::Size(mode_.hdisplay, mode_.vdisplay)) {
+ LOG(WARNING) << "Trying to pageflip a buffer with the wrong size. Expected "
+ << mode_.hdisplay << "x" << mode_.vdisplay
+ << " got " << primary.buffer->GetSize().ToString() << " for"
+ << " crtc=" << state->crtc()
+ << " connector=" << state->connector();
+ return true;
+ }
+
+ if (!drm_->PageFlip(state->crtc(),
+ primary.buffer->GetFramebufferId(),
+ this)) {
+ LOG(ERROR) << "Cannot page flip: error='" << strerror(errno) << "'"
+ << " crtc=" << state->crtc()
+ << " framebuffer=" << primary.buffer->GetFramebufferId()
+ << " size=" << primary.buffer->GetSize().ToString();
+ return false;
+ }
+
+ ++pending_page_flips_;
+
+ for (size_t i = 0; i < overlays.size(); i++) {
+ const OverlayPlane& plane = overlays[i];
+ if (!plane.overlay_plane)
+ continue;
+
+ const gfx::Size& size = plane.buffer->GetSize();
+ gfx::RectF crop_rect = plane.crop_rect;
+ crop_rect.Scale(size.width(), size.height());
+ if (!drm_->PageFlipOverlay(state->crtc(),
+ plane.buffer->GetFramebufferId(),
+ plane.display_bounds,
+ crop_rect,
+ plane.overlay_plane)) {
+ LOG(ERROR) << "Cannot display on overlay: " << strerror(errno);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/hardware_display_controller.h b/ui/ozone/platform/dri/hardware_display_controller.h
new file mode 100644
index 0000000..b26654d
--- /dev/null
+++ b/ui/ozone/platform/dri/hardware_display_controller.h
@@ -0,0 +1,219 @@
+// 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_DRI_HARDWARE_DISPLAY_CONTROLLER_H_
+#define UI_OZONE_PLATFORM_DRI_HARDWARE_DISPLAY_CONTROLLER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <xf86drmMode.h>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+
+class CrtcState;
+class ScanoutBuffer;
+
+struct 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();
+
+ scoped_refptr<ScanoutBuffer> buffer;
+ int z_order;
+ gfx::OverlayTransform plane_transform;
+ gfx::Rect display_bounds;
+ gfx::RectF crop_rect;
+ int overlay_plane;
+};
+
+typedef std::vector<OverlayPlane> OverlayPlaneList;
+
+// 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 HardwareDisplayController
+ : public base::SupportsWeakPtr<HardwareDisplayController> {
+ public:
+ HardwareDisplayController(DriWrapper* drm,
+ scoped_ptr<CrtcState> state);
+
+ ~HardwareDisplayController();
+
+ // Performs the initial CRTC configuration. If successful, it will display the
+ // framebuffer for |primary| with |mode|.
+ bool Modeset(const OverlayPlane& primary,
+ drmModeModeInfo mode);
+
+ // Reconfigures the CRTC with the current surface and mode.
+ bool Enable();
+
+ // Disables the CRTC.
+ void Disable();
+
+ void QueueOverlayPlane(const OverlayPlane& plane);
+
+ // 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.
+ bool SchedulePageFlip();
+
+ // TODO(dnicoara) This should be on the MessageLoop when Ozone can have
+ // BeginFrame can be triggered explicitly by Ozone.
+ void WaitForPageFlipEvent();
+
+ // 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);
+
+ // Set the hardware cursor to show the contents of |surface|.
+ bool SetCursor(scoped_refptr<ScanoutBuffer> buffer);
+
+ bool UnsetCursor();
+
+ // Moves the hardware cursor to |location|.
+ bool MoveCursor(const gfx::Point& location);
+
+ void AddCrtc(scoped_ptr<CrtcState> state);
+ scoped_ptr<CrtcState> RemoveCrtc(uint32_t crtc);
+ bool HasCrtc(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 get_time_of_last_flip() const {
+ return time_of_last_flip_;
+ };
+
+ private:
+ bool ModesetCrtc(const scoped_refptr<ScanoutBuffer>& buffer,
+ drmModeModeInfo mode,
+ CrtcState* state);
+
+ bool SchedulePageFlipOnCrtc(const OverlayPlaneList& overlays,
+ CrtcState* state);
+
+ // 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_;
+
+ // Object containing the connection to the graphics device and wraps the API
+ // calls to control it.
+ DriWrapper* drm_;
+
+ // Stores the CRTC configuration. This is used to identify monitors and
+ // configure them.
+ ScopedVector<CrtcState> crtc_states_;
+ gfx::Point origin_;
+ drmModeModeInfo mode_;
+ bool is_disabled_;
+ uint64_t time_of_last_flip_;
+
+ // Keeps track of the number of page flips scheduled but not yet serviced (in
+ // mirror mode each CRTC schedules its own page flip event). This value is
+ // changed as follows:
+ // 1) incremented when a successful SchedulePageFlipOnController() occurrs,
+ // 2) decremented when the page flip callback is triggered,
+ // 3) reset to 0 when a drmModeSetCrtc is called (via the DriWrapper).
+ uint32_t pending_page_flips_;
+
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayController);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_HARDWARE_DISPLAY_CONTROLLER_H_
diff --git a/ui/ozone/platform/dri/hardware_display_controller_unittest.cc b/ui/ozone/platform/dri/hardware_display_controller_unittest.cc
new file mode 100644
index 0000000..998ccca
--- /dev/null
+++ b/ui/ozone/platform/dri/hardware_display_controller_unittest.cc
@@ -0,0 +1,187 @@
+// 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 "third_party/skia/include/core/SkCanvas.h"
+#include "ui/ozone/platform/dri/crtc_state.h"
+#include "ui/ozone/platform/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+#include "ui/ozone/platform/dri/test/mock_dri_wrapper.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 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:
+ virtual uint32_t GetFramebufferId() const OVERRIDE {return 0; }
+ virtual uint32_t GetHandle() const OVERRIDE { return 0; }
+ virtual gfx::Size GetSize() const OVERRIDE { return size_; }
+
+ private:
+ virtual ~MockScanoutBuffer() {}
+
+ gfx::Size size_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockScanoutBuffer);
+};
+
+} // namespace
+
+class HardwareDisplayControllerTest : public testing::Test {
+ public:
+ HardwareDisplayControllerTest() {}
+ virtual ~HardwareDisplayControllerTest() {}
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+ protected:
+ scoped_ptr<ui::HardwareDisplayController> controller_;
+ scoped_ptr<ui::MockDriWrapper> drm_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayControllerTest);
+};
+
+void HardwareDisplayControllerTest::SetUp() {
+ drm_.reset(new ui::MockDriWrapper(3));
+ controller_.reset(new ui::HardwareDisplayController(
+ drm_.get(),
+ scoped_ptr<ui::CrtcState>(
+ new ui::CrtcState(drm_.get(), kPrimaryCrtc, kPrimaryConnector))));
+}
+
+void HardwareDisplayControllerTest::TearDown() {
+ controller_.reset();
+ drm_.reset();
+}
+
+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)));
+ controller_->QueueOverlayPlane(plane2);
+ EXPECT_TRUE(controller_->SchedulePageFlip());
+ controller_->WaitForPageFlipEvent();
+ 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)));
+ controller_->QueueOverlayPlane(plane2);
+ EXPECT_FALSE(controller_->SchedulePageFlip());
+ EXPECT_FALSE(plane1.buffer->HasOneRef());
+ EXPECT_FALSE(plane2.buffer->HasOneRef());
+
+ controller_->WaitForPageFlipEvent();
+ EXPECT_FALSE(plane1.buffer->HasOneRef());
+ EXPECT_TRUE(plane2.buffer->HasOneRef());
+}
+
+TEST_F(HardwareDisplayControllerTest, VerifyNoDRMCallsWhenDisabled) {
+ ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+
+ EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ controller_->Disable();
+ ui::OverlayPlane plane2(scoped_refptr<ui::ScanoutBuffer>(
+ new MockScanoutBuffer(kDefaultModeSize)));
+ controller_->QueueOverlayPlane(plane2);
+ EXPECT_TRUE(controller_->SchedulePageFlip());
+ controller_->WaitForPageFlipEvent();
+ EXPECT_EQ(0, drm_->get_page_flip_call_count());
+
+ EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ controller_->QueueOverlayPlane(plane2);
+ EXPECT_TRUE(controller_->SchedulePageFlip());
+ controller_->WaitForPageFlipEvent();
+ EXPECT_EQ(1, drm_->get_page_flip_call_count());
+}
+
+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));
+ plane2.overlay_plane = 1; // Force association with a plane.
+
+ EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+
+ controller_->QueueOverlayPlane(plane1);
+ controller_->QueueOverlayPlane(plane2);
+
+ EXPECT_TRUE(controller_->SchedulePageFlip());
+ controller_->WaitForPageFlipEvent();
+ EXPECT_EQ(1, drm_->get_page_flip_call_count());
+ EXPECT_EQ(1, drm_->get_overlay_flip_call_count());
+}
+
+TEST_F(HardwareDisplayControllerTest, PageflipMirroredControllers) {
+ controller_->AddCrtc(
+ scoped_ptr<ui::CrtcState>(
+ new ui::CrtcState(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)));
+ controller_->QueueOverlayPlane(plane2);
+ EXPECT_TRUE(controller_->SchedulePageFlip());
+ EXPECT_EQ(2, drm_->get_page_flip_call_count());
+}
diff --git a/ui/ozone/platform/dri/hardware_display_plane.cc b/ui/ozone/platform/dri/hardware_display_plane.cc
new file mode 100644
index 0000000..61743dc
--- /dev/null
+++ b/ui/ozone/platform/dri/hardware_display_plane.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/platform/dri/hardware_display_plane.h"
+
+#include <drm.h>
+#include <errno.h>
+#include <xf86drm.h>
+
+#include "base/logging.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/ozone/platform/dri/dri_wrapper.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";
+}
+
+HardwareDisplayPlane::Property::Property() : id_(0) {
+}
+
+bool HardwareDisplayPlane::Property::Initialize(
+ DriWrapper* 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 (!strcmp(property->name, name)) {
+ id_ = property->prop_id;
+ break;
+ }
+ }
+ if (!id_) {
+ LOG(ERROR) << "Could not find property " << name;
+ return false;
+ }
+ return true;
+}
+
+HardwareDisplayPlane::HardwareDisplayPlane(
+ DriWrapper* drm,
+ drmModePropertySetPtr atomic_property_set,
+ ScopedDrmPlanePtr plane)
+ : drm_(drm),
+ property_set_(atomic_property_set),
+ plane_(plane.Pass()),
+ plane_id_(plane_->plane_id) {
+}
+
+HardwareDisplayPlane::~HardwareDisplayPlane() {
+}
+
+bool HardwareDisplayPlane::CanUseForCrtc(uint32_t crtc_id) {
+ return plane_->possible_crtcs & (1 << crtc_id);
+}
+
+bool HardwareDisplayPlane::SetPlaneData(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) {
+ LOG(ERROR) << "Failed to set plane data";
+ return false;
+ }
+ return true;
+}
+
+bool HardwareDisplayPlane::Initialize() {
+ ScopedDrmObjectPropertyPtr plane_props(drmModeObjectGetProperties(
+ drm_->get_fd(), plane_id_, DRM_MODE_OBJECT_PLANE));
+
+ if (!plane_props) {
+ LOG(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/dri/hardware_display_plane.h b/ui/ozone/platform/dri/hardware_display_plane.h
new file mode 100644
index 0000000..dd79f76
--- /dev/null
+++ b/ui/ozone/platform/dri/hardware_display_plane.h
@@ -0,0 +1,77 @@
+// 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_DRI_HARDWARE_DISPLAY_PLANE_H_
+#define UI_OZONE_PLATFORM_DRI_HARDWARE_DISPLAY_PLANE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <xf86drmMode.h>
+
+#include "base/basictypes.h"
+#include "ui/ozone/platform/dri/scoped_drm_types.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace ui {
+
+class DriWrapper;
+
+class HardwareDisplayPlane {
+ public:
+ HardwareDisplayPlane(DriWrapper* drm,
+ drmModePropertySetPtr atomic_property_set,
+ ScopedDrmPlanePtr plane);
+
+ ~HardwareDisplayPlane();
+
+ bool Initialize();
+
+ bool CanUseForCrtc(uint32_t crtc_id);
+ bool SetPlaneData(uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& crtc_rect,
+ const gfx::Rect& src_rect);
+
+ bool in_use() const { return in_use_; }
+ void set_in_use(bool in_use) { in_use_ = in_use; }
+
+ private:
+ struct Property {
+ Property();
+ bool Initialize(DriWrapper* drm,
+ const char* name,
+ const ScopedDrmObjectPropertyPtr& plane_properties);
+ uint32_t id_;
+ };
+ // Object containing the connection to the graphics device and wraps the API
+ // calls to control it.
+ DriWrapper* drm_;
+
+ // Not owned.
+ drmModePropertySetPtr property_set_;
+
+ ScopedDrmPlanePtr plane_;
+ uint32_t plane_id_;
+ bool in_use_;
+
+ 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_;
+
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlane);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_HARDWARE_DISPLAY_PLANE_H_
diff --git a/ui/ozone/platform/dri/hardware_display_plane_manager.cc b/ui/ozone/platform/dri/hardware_display_plane_manager.cc
new file mode 100644
index 0000000..0e9bc99
--- /dev/null
+++ b/ui/ozone/platform/dri/hardware_display_plane_manager.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/platform/dri/hardware_display_plane_manager.h"
+
+#include <drm.h>
+#include <errno.h>
+#include <xf86drm.h>
+
+#include "base/logging.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+
+namespace ui {
+
+HardwareDisplayPlaneManager::HardwareDisplayPlaneManager(DriWrapper* drm)
+ : drm_(drm), property_set_(NULL) {
+}
+
+HardwareDisplayPlaneManager::~HardwareDisplayPlaneManager() {
+ if (property_set_)
+ drmModePropertySetFree(property_set_);
+}
+
+bool HardwareDisplayPlaneManager::Initialize() {
+ ScopedDrmPlaneResPtr plane_resources(
+ drmModeGetPlaneResources(drm_->get_fd()));
+ if (!plane_resources) {
+ LOG(ERROR) << "Failed to get plane resources.";
+ return false;
+ }
+
+ property_set_ = drmModePropertySetAlloc();
+ if (!property_set_) {
+ LOG(ERROR) << "Failed to allocate property set.";
+ return false;
+ }
+
+ uint32_t num_planes = plane_resources->count_planes;
+ for (uint32_t i = 0; i < num_planes; ++i) {
+ ScopedDrmPlanePtr drm_plane(
+ drmModeGetPlane(drm_->get_fd(), plane_resources->planes[i]));
+ if (!drm_plane) {
+ LOG(ERROR) << "Failed to get plane " << i << ".";
+ return false;
+ }
+ scoped_ptr<HardwareDisplayPlane> plane(
+ new HardwareDisplayPlane(drm_, property_set_, drm_plane.Pass()));
+ if (plane->Initialize())
+ planes_.push_back(plane.release());
+ }
+
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/hardware_display_plane_manager.h b/ui/ozone/platform/dri/hardware_display_plane_manager.h
new file mode 100644
index 0000000..b6862e3
--- /dev/null
+++ b/ui/ozone/platform/dri/hardware_display_plane_manager.h
@@ -0,0 +1,49 @@
+// 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_DRI_HARDWARE_DISPLAY_PLANE_MANAGER_H_
+#define UI_OZONE_PLATFORM_DRI_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/platform/dri/hardware_display_plane.h"
+#include "ui/ozone/platform/dri/scoped_drm_types.h"
+
+namespace gfx {
+class Rect;
+} // namespace gfx
+
+namespace ui {
+
+class DriWrapper;
+
+class HardwareDisplayPlaneManager {
+ public:
+ HardwareDisplayPlaneManager(DriWrapper* drm);
+
+ ~HardwareDisplayPlaneManager();
+
+ bool Initialize();
+
+ const ScopedVector<HardwareDisplayPlane>& get_planes() { return planes_; }
+
+ private:
+ // Object containing the connection to the graphics device and wraps the API
+ // calls to control it.
+ DriWrapper* drm_;
+
+ drmModePropertySetPtr property_set_;
+ ScopedVector<HardwareDisplayPlane> planes_;
+
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_HARDWARE_DISPLAY_PLANE_MANAGER_H_
diff --git a/ui/ozone/platform/dri/native_display_delegate_dri.cc b/ui/ozone/platform/dri/native_display_delegate_dri.cc
new file mode 100644
index 0000000..6e06d2b
--- /dev/null
+++ b/ui/ozone/platform/dri/native_display_delegate_dri.cc
@@ -0,0 +1,336 @@
+// 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/dri/native_display_delegate_dri.h"
+
+#include "base/bind.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/display/types/native_display_observer.h"
+#include "ui/events/ozone/device/device_event.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/ozone/platform/dri/display_mode_dri.h"
+#include "ui/ozone/platform/dri/display_snapshot_dri.h"
+#include "ui/ozone/platform/dri/dri_console_buffer.h"
+#include "ui/ozone/platform/dri/dri_util.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+
+namespace ui {
+
+namespace {
+
+const size_t kMaxDisplayCount = 2;
+
+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}};
+
+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;
+}
+
+class DisplaySnapshotComparator {
+ public:
+ DisplaySnapshotComparator(const DisplaySnapshotDri* snapshot)
+ : snapshot_(snapshot) {}
+
+ bool operator()(const DisplaySnapshotDri* other) const {
+ if (snapshot_->connector() == other->connector() &&
+ snapshot_->crtc() == other->crtc())
+ return true;
+
+ return false;
+ }
+
+ private:
+ const DisplaySnapshotDri* snapshot_;
+};
+
+} // namespace
+
+NativeDisplayDelegateDri::NativeDisplayDelegateDri(
+ DriWrapper* dri,
+ ScreenManager* screen_manager,
+ DeviceManager* device_manager)
+ : dri_(dri),
+ screen_manager_(screen_manager),
+ device_manager_(device_manager) {
+ // TODO(dnicoara): Remove when async display configuration is supported.
+ screen_manager_->ForceInitializationOfPrimaryDisplay();
+}
+
+NativeDisplayDelegateDri::~NativeDisplayDelegateDri() {
+ if (device_manager_)
+ device_manager_->RemoveObserver(this);
+}
+
+DisplaySnapshot* NativeDisplayDelegateDri::FindDisplaySnapshot(int64_t id) {
+ for (size_t i = 0; i < cached_displays_.size(); ++i)
+ if (cached_displays_[i]->display_id() == id)
+ return cached_displays_[i];
+
+ return NULL;
+}
+
+const DisplayMode* NativeDisplayDelegateDri::FindDisplayMode(
+ const gfx::Size& size,
+ bool is_interlaced,
+ float refresh_rate) {
+ for (size_t i = 0; i < cached_modes_.size(); ++i)
+ if (cached_modes_[i]->size() == size &&
+ cached_modes_[i]->is_interlaced() == is_interlaced &&
+ cached_modes_[i]->refresh_rate() == refresh_rate)
+ return cached_modes_[i];
+
+ return NULL;
+}
+
+void NativeDisplayDelegateDri::Initialize() {
+ if (device_manager_)
+ device_manager_->AddObserver(this);
+
+ ScopedVector<HardwareDisplayControllerInfo> displays =
+ GetAvailableDisplayControllerInfos(dri_->get_fd());
+
+ // By default all displays show the same console buffer.
+ console_buffer_.reset(
+ new DriConsoleBuffer(dri_, displays[0]->crtc()->buffer_id));
+ if (!console_buffer_->Initialize()) {
+ VLOG(1) << "Failed to initialize console buffer";
+ console_buffer_.reset();
+ } else {
+ // Clear the console buffer such that restarting Chrome will show a
+ // predetermined background.
+ //
+ // Black was chosen since Chrome's first buffer paints start with a black
+ // background.
+ console_buffer_->canvas()->clear(SK_ColorBLACK);
+ }
+}
+
+void NativeDisplayDelegateDri::GrabServer() {
+}
+
+void NativeDisplayDelegateDri::UngrabServer() {
+}
+
+void NativeDisplayDelegateDri::SyncWithServer() {
+}
+
+void NativeDisplayDelegateDri::SetBackgroundColor(uint32_t color_argb) {
+ if (console_buffer_)
+ console_buffer_->canvas()->clear(color_argb);
+}
+
+void NativeDisplayDelegateDri::ForceDPMSOn() {
+ for (size_t i = 0; i < cached_displays_.size(); ++i) {
+ DisplaySnapshotDri* dri_output = cached_displays_[i];
+ if (dri_output->dpms_property())
+ dri_->SetProperty(dri_output->connector(),
+ dri_output->dpms_property()->prop_id,
+ DRM_MODE_DPMS_ON);
+ }
+}
+
+std::vector<DisplaySnapshot*> NativeDisplayDelegateDri::GetDisplays() {
+ ScopedVector<DisplaySnapshotDri> old_displays(cached_displays_.Pass());
+ cached_modes_.clear();
+
+ ScopedVector<HardwareDisplayControllerInfo> displays =
+ GetAvailableDisplayControllerInfos(dri_->get_fd());
+ for (size_t i = 0;
+ i < displays.size() && cached_displays_.size() < kMaxDisplayCount;
+ ++i) {
+ DisplaySnapshotDri* display = new DisplaySnapshotDri(
+ dri_, displays[i]->connector(), displays[i]->crtc(), i);
+ cached_displays_.push_back(display);
+ cached_modes_.insert(
+ cached_modes_.end(), display->modes().begin(), display->modes().end());
+ }
+
+ NotifyScreenManager(cached_displays_.get(), old_displays.get());
+
+ std::vector<DisplaySnapshot*> generic_displays(cached_displays_.begin(),
+ cached_displays_.end());
+ return generic_displays;
+}
+
+void NativeDisplayDelegateDri::AddMode(const DisplaySnapshot& output,
+ const DisplayMode* mode) {
+}
+
+bool NativeDisplayDelegateDri::Configure(const DisplaySnapshot& output,
+ const DisplayMode* mode,
+ const gfx::Point& origin) {
+ const DisplaySnapshotDri& dri_output =
+ static_cast<const DisplaySnapshotDri&>(output);
+
+ VLOG(1) << "DRM configuring: crtc=" << dri_output.crtc()
+ << " connector=" << dri_output.connector()
+ << " origin=" << origin.ToString()
+ << " size=" << (mode ? mode->size().ToString() : "0x0");
+
+ if (mode) {
+ if (!screen_manager_->ConfigureDisplayController(
+ dri_output.crtc(),
+ dri_output.connector(),
+ origin,
+ static_cast<const DisplayModeDri*>(mode)->mode_info())) {
+ VLOG(1) << "Failed to configure: crtc=" << dri_output.crtc()
+ << " connector=" << dri_output.connector();
+ return false;
+ }
+ } else {
+ if (!screen_manager_->DisableDisplayController(dri_output.crtc())) {
+ VLOG(1) << "Failed to disable crtc=" << dri_output.crtc();
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void NativeDisplayDelegateDri::CreateFrameBuffer(const gfx::Size& size) {
+}
+
+bool NativeDisplayDelegateDri::GetHDCPState(const DisplaySnapshot& output,
+ HDCPState* state) {
+ const DisplaySnapshotDri& dri_output =
+ static_cast<const DisplaySnapshotDri&>(output);
+
+ ScopedDrmConnectorPtr connector(dri_->GetConnector(dri_output.connector()));
+ if (!connector) {
+ LOG(ERROR) << "Failed to get connector " << dri_output.connector();
+ return false;
+ }
+
+ ScopedDrmPropertyPtr hdcp_property(
+ dri_->GetProperty(connector.get(), kContentProtection));
+ if (!hdcp_property) {
+ LOG(ERROR) << "'" << kContentProtection << "' property doesn't exist.";
+ return false;
+ }
+
+ DCHECK_LT(static_cast<int>(hdcp_property->prop_id), connector->count_props);
+ int hdcp_state_idx = connector->prop_values[hdcp_property->prop_id];
+ DCHECK_LT(hdcp_state_idx, hdcp_property->count_enums);
+
+ std::string name(hdcp_property->enums[hdcp_state_idx].name);
+ 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 NativeDisplayDelegateDri::SetHDCPState(const DisplaySnapshot& output,
+ HDCPState state) {
+ const DisplaySnapshotDri& dri_output =
+ static_cast<const DisplaySnapshotDri&>(output);
+
+ ScopedDrmConnectorPtr connector(dri_->GetConnector(dri_output.connector()));
+ if (!connector) {
+ LOG(ERROR) << "Failed to get connector " << dri_output.connector();
+ return false;
+ }
+
+ ScopedDrmPropertyPtr hdcp_property(
+ dri_->GetProperty(connector.get(), kContentProtection));
+ if (!hdcp_property) {
+ LOG(ERROR) << "'" << kContentProtection << "' property doesn't exist.";
+ return false;
+ }
+
+ return dri_->SetProperty(
+ dri_output.connector(),
+ hdcp_property->prop_id,
+ GetContentProtectionValue(hdcp_property.get(), state));
+}
+
+std::vector<ui::ColorCalibrationProfile>
+NativeDisplayDelegateDri::GetAvailableColorCalibrationProfiles(
+ const ui::DisplaySnapshot& output) {
+ NOTIMPLEMENTED();
+ return std::vector<ui::ColorCalibrationProfile>();
+}
+
+bool NativeDisplayDelegateDri::SetColorCalibrationProfile(
+ const ui::DisplaySnapshot& output,
+ ui::ColorCalibrationProfile new_profile) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void NativeDisplayDelegateDri::AddObserver(NativeDisplayObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void NativeDisplayDelegateDri::RemoveObserver(NativeDisplayObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void NativeDisplayDelegateDri::OnDeviceEvent(const DeviceEvent& event) {
+ if (event.device_type() != DeviceEvent::DISPLAY)
+ return;
+
+ if (event.action_type() == DeviceEvent::CHANGE) {
+ VLOG(1) << "Got display changed event";
+ FOR_EACH_OBSERVER(
+ NativeDisplayObserver, observers_, OnConfigurationChanged());
+ }
+}
+
+void NativeDisplayDelegateDri::NotifyScreenManager(
+ const std::vector<DisplaySnapshotDri*>& new_displays,
+ const std::vector<DisplaySnapshotDri*>& old_displays) const {
+ for (size_t i = 0; i < old_displays.size(); ++i) {
+ const std::vector<DisplaySnapshotDri*>::const_iterator it =
+ std::find_if(new_displays.begin(),
+ new_displays.end(),
+ DisplaySnapshotComparator(old_displays[i]));
+
+ if (it == new_displays.end())
+ screen_manager_->RemoveDisplayController(old_displays[i]->crtc());
+ }
+
+ for (size_t i = 0; i < new_displays.size(); ++i) {
+ const std::vector<DisplaySnapshotDri*>::const_iterator it =
+ std::find_if(old_displays.begin(),
+ old_displays.end(),
+ DisplaySnapshotComparator(new_displays[i]));
+
+ if (it == old_displays.end())
+ screen_manager_->AddDisplayController(new_displays[i]->crtc(),
+ new_displays[i]->connector());
+ }
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/native_display_delegate_dri.h b/ui/ozone/platform/dri/native_display_delegate_dri.h
new file mode 100644
index 0000000..70abb7b
--- /dev/null
+++ b/ui/ozone/platform/dri/native_display_delegate_dri.h
@@ -0,0 +1,87 @@
+// 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_DRI_NATIVE_DISPLAY_DELEGATE_DRI_H_
+#define UI_OZONE_PLATFORM_DRI_NATIVE_DISPLAY_DELEGATE_DRI_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/observer_list.h"
+#include "ui/display/types/native_display_delegate.h"
+#include "ui/events/ozone/device/device_event_observer.h"
+
+namespace ui {
+
+class DeviceManager;
+class DisplaySnapshotDri;
+class DriConsoleBuffer;
+class DriWrapper;
+class ScreenManager;
+
+class NativeDisplayDelegateDri : public NativeDisplayDelegate,
+ DeviceEventObserver {
+ public:
+ NativeDisplayDelegateDri(DriWrapper* dri,
+ ScreenManager* screen_manager,
+ DeviceManager* device_manager);
+ virtual ~NativeDisplayDelegateDri();
+
+ DisplaySnapshot* FindDisplaySnapshot(int64_t id);
+ const DisplayMode* FindDisplayMode(const gfx::Size& size,
+ bool is_interlaced,
+ float refresh_rate);
+
+ // NativeDisplayDelegate overrides:
+ virtual void Initialize() OVERRIDE;
+ virtual void GrabServer() OVERRIDE;
+ virtual void UngrabServer() OVERRIDE;
+ virtual void SyncWithServer() OVERRIDE;
+ virtual void SetBackgroundColor(uint32_t color_argb) OVERRIDE;
+ virtual void ForceDPMSOn() OVERRIDE;
+ virtual std::vector<DisplaySnapshot*> GetDisplays() OVERRIDE;
+ virtual void AddMode(const DisplaySnapshot& output,
+ const DisplayMode* mode) OVERRIDE;
+ virtual bool Configure(const DisplaySnapshot& output,
+ const DisplayMode* mode,
+ const gfx::Point& origin) OVERRIDE;
+ virtual void CreateFrameBuffer(const gfx::Size& size) OVERRIDE;
+ virtual bool GetHDCPState(const DisplaySnapshot& output,
+ HDCPState* state) OVERRIDE;
+ virtual bool SetHDCPState(const DisplaySnapshot& output,
+ HDCPState state) OVERRIDE;
+ virtual std::vector<ui::ColorCalibrationProfile>
+ GetAvailableColorCalibrationProfiles(
+ const ui::DisplaySnapshot& output) OVERRIDE;
+ virtual bool SetColorCalibrationProfile(
+ const ui::DisplaySnapshot& output,
+ ui::ColorCalibrationProfile new_profile) OVERRIDE;
+ virtual void AddObserver(NativeDisplayObserver* observer) OVERRIDE;
+ virtual void RemoveObserver(NativeDisplayObserver* observer) OVERRIDE;
+
+ // DeviceEventObserver overrides:
+ virtual void OnDeviceEvent(const DeviceEvent& event) OVERRIDE;
+
+ private:
+ // Notify ScreenManager of all the displays that were present before the
+ // update but are gone after the update.
+ void NotifyScreenManager(
+ const std::vector<DisplaySnapshotDri*>& new_displays,
+ const std::vector<DisplaySnapshotDri*>& old_displays) const;
+
+ DriWrapper* dri_; // Not owned.
+ ScreenManager* screen_manager_; // Not owned.
+ DeviceManager* device_manager_; // Not owned.
+ scoped_ptr<DriConsoleBuffer> console_buffer_;
+ // Modes can be shared between different displays, so we need to keep track
+ // of them independently for cleanup.
+ ScopedVector<const DisplayMode> cached_modes_;
+ ScopedVector<DisplaySnapshotDri> cached_displays_;
+ ObserverList<NativeDisplayObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeDisplayDelegateDri);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_NATIVE_DISPLAY_DELEGATE_DRI_H_
diff --git a/ui/ozone/platform/dri/native_display_delegate_proxy.cc b/ui/ozone/platform/dri/native_display_delegate_proxy.cc
new file mode 100644
index 0000000..f6cbba3
--- /dev/null
+++ b/ui/ozone/platform/dri/native_display_delegate_proxy.cc
@@ -0,0 +1,162 @@
+// 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/dri/native_display_delegate_proxy.h"
+
+#include "base/logging.h"
+#include "ui/display/types/display_snapshot.h"
+#include "ui/display/types/native_display_observer.h"
+#include "ui/events/ozone/device/device_event.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/ozone/common/display_snapshot_proxy.h"
+#include "ui/ozone/common/display_util.h"
+#include "ui/ozone/common/gpu/ozone_gpu_messages.h"
+#include "ui/ozone/platform/dri/gpu_platform_support_host_gbm.h"
+
+namespace ui {
+
+NativeDisplayDelegateProxy::NativeDisplayDelegateProxy(
+ GpuPlatformSupportHostGbm* proxy,
+ DeviceManager* device_manager)
+ : proxy_(proxy), device_manager_(device_manager) {
+ proxy_->RegisterHandler(this);
+}
+
+NativeDisplayDelegateProxy::~NativeDisplayDelegateProxy() {
+ if (device_manager_)
+ device_manager_->RemoveObserver(this);
+
+ proxy_->UnregisterHandler(this);
+}
+
+void NativeDisplayDelegateProxy::Initialize() {
+ if (device_manager_)
+ device_manager_->AddObserver(this);
+}
+
+void NativeDisplayDelegateProxy::GrabServer() {
+}
+
+void NativeDisplayDelegateProxy::UngrabServer() {
+}
+
+void NativeDisplayDelegateProxy::SyncWithServer() {
+}
+
+void NativeDisplayDelegateProxy::SetBackgroundColor(uint32_t color_argb) {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateProxy::ForceDPMSOn() {
+ proxy_->Send(new OzoneGpuMsg_ForceDPMSOn());
+}
+
+std::vector<DisplaySnapshot*> NativeDisplayDelegateProxy::GetDisplays() {
+ return displays_.get();
+}
+
+void NativeDisplayDelegateProxy::AddMode(const DisplaySnapshot& output,
+ const DisplayMode* mode) {
+}
+
+bool NativeDisplayDelegateProxy::Configure(const DisplaySnapshot& output,
+ const DisplayMode* mode,
+ const gfx::Point& origin) {
+ // TODO(dnicoara) Should handle an asynchronous response.
+ if (mode)
+ proxy_->Send(new OzoneGpuMsg_ConfigureNativeDisplay(
+ output.display_id(), GetDisplayModeParams(*mode), origin));
+ else
+ proxy_->Send(new OzoneGpuMsg_DisableNativeDisplay(output.display_id()));
+
+ return true;
+}
+
+void NativeDisplayDelegateProxy::CreateFrameBuffer(const gfx::Size& size) {
+}
+
+bool NativeDisplayDelegateProxy::GetHDCPState(const DisplaySnapshot& output,
+ HDCPState* state) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool NativeDisplayDelegateProxy::SetHDCPState(const DisplaySnapshot& output,
+ HDCPState state) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+std::vector<ColorCalibrationProfile>
+NativeDisplayDelegateProxy::GetAvailableColorCalibrationProfiles(
+ const DisplaySnapshot& output) {
+ NOTIMPLEMENTED();
+ return std::vector<ColorCalibrationProfile>();
+}
+
+bool NativeDisplayDelegateProxy::SetColorCalibrationProfile(
+ const DisplaySnapshot& output,
+ ColorCalibrationProfile new_profile) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void NativeDisplayDelegateProxy::AddObserver(NativeDisplayObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void NativeDisplayDelegateProxy::RemoveObserver(
+ NativeDisplayObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void NativeDisplayDelegateProxy::OnDeviceEvent(const DeviceEvent& event) {
+ if (event.device_type() != DeviceEvent::DISPLAY)
+ return;
+
+ if (event.action_type() == DeviceEvent::CHANGE) {
+ VLOG(1) << "Got display changed event";
+ proxy_->Send(new OzoneGpuMsg_RefreshNativeDisplays(
+ std::vector<DisplaySnapshot_Params>()));
+ }
+}
+
+void NativeDisplayDelegateProxy::OnChannelEstablished(int host_id,
+ IPC::Sender* sender) {
+ std::vector<DisplaySnapshot_Params> display_params;
+ for (size_t i = 0; i < displays_.size(); ++i)
+ display_params.push_back(GetDisplaySnapshotParams(*displays_[i]));
+
+ // Force an initial configure such that the browser process can get the actual
+ // state. Pass in the current display state since the GPU process may have
+ // crashed and we want to re-synchronize the state between processes.
+ proxy_->Send(new OzoneGpuMsg_RefreshNativeDisplays(display_params));
+}
+
+void NativeDisplayDelegateProxy::OnChannelDestroyed(int host_id) {
+}
+
+bool NativeDisplayDelegateProxy::OnMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+
+ IPC_BEGIN_MESSAGE_MAP(NativeDisplayDelegateProxy, message)
+ IPC_MESSAGE_HANDLER(OzoneHostMsg_UpdateNativeDisplays, OnUpdateNativeDisplays)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void NativeDisplayDelegateProxy::OnUpdateNativeDisplays(
+ const std::vector<DisplaySnapshot_Params>& displays) {
+ displays_.clear();
+ for (size_t i = 0; i < displays.size(); ++i)
+ displays_.push_back(new DisplaySnapshotProxy(displays[i]));
+
+ FOR_EACH_OBSERVER(
+ NativeDisplayObserver, observers_, OnConfigurationChanged());
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/native_display_delegate_proxy.h b/ui/ozone/platform/dri/native_display_delegate_proxy.h
new file mode 100644
index 0000000..ae80f4e
--- /dev/null
+++ b/ui/ozone/platform/dri/native_display_delegate_proxy.h
@@ -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.
+
+#ifndef UI_OZONE_PLATFORM_DRI_NATIVE_DISPLAY_DELEGATE_PROXY_H_
+#define UI_OZONE_PLATFORM_DRI_NATIVE_DISPLAY_DELEGATE_PROXY_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/observer_list.h"
+#include "ui/display/types/native_display_delegate.h"
+#include "ui/events/ozone/device/device_event_observer.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
+
+namespace ui {
+
+class DeviceManager;
+class GpuPlatformSupportHostGbm;
+
+struct DisplaySnapshot_Params;
+
+class NativeDisplayDelegateProxy : public NativeDisplayDelegate,
+ public DeviceEventObserver,
+ public GpuPlatformSupportHost {
+ public:
+ NativeDisplayDelegateProxy(GpuPlatformSupportHostGbm* proxy,
+ DeviceManager* device_manager);
+ virtual ~NativeDisplayDelegateProxy();
+
+ // NativeDisplayDelegate overrides:
+ virtual void Initialize() OVERRIDE;
+ virtual void GrabServer() OVERRIDE;
+ virtual void UngrabServer() OVERRIDE;
+ virtual void SyncWithServer() OVERRIDE;
+ virtual void SetBackgroundColor(uint32_t color_argb) OVERRIDE;
+ virtual void ForceDPMSOn() OVERRIDE;
+ virtual std::vector<DisplaySnapshot*> GetDisplays() OVERRIDE;
+ virtual void AddMode(const DisplaySnapshot& output,
+ const DisplayMode* mode) OVERRIDE;
+ virtual bool Configure(const DisplaySnapshot& output,
+ const DisplayMode* mode,
+ const gfx::Point& origin) OVERRIDE;
+ virtual void CreateFrameBuffer(const gfx::Size& size) OVERRIDE;
+ virtual bool GetHDCPState(const DisplaySnapshot& output,
+ HDCPState* state) OVERRIDE;
+ virtual bool SetHDCPState(const DisplaySnapshot& output,
+ HDCPState state) OVERRIDE;
+ virtual std::vector<ColorCalibrationProfile>
+ GetAvailableColorCalibrationProfiles(
+ const DisplaySnapshot& output) OVERRIDE;
+ virtual bool SetColorCalibrationProfile(
+ const DisplaySnapshot& output,
+ ColorCalibrationProfile new_profile) OVERRIDE;
+ virtual void AddObserver(NativeDisplayObserver* observer) OVERRIDE;
+ virtual void RemoveObserver(NativeDisplayObserver* observer) OVERRIDE;
+
+ // DeviceEventObserver overrides:
+ virtual void OnDeviceEvent(const DeviceEvent& event) OVERRIDE;
+
+ // GpuPlatformSupportHost:
+ virtual void OnChannelEstablished(int host_id, IPC::Sender* sender) OVERRIDE;
+ virtual void OnChannelDestroyed(int host_id) OVERRIDE;
+
+ // IPC::Listener overrides:
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ private:
+ void OnUpdateNativeDisplays(
+ const std::vector<DisplaySnapshot_Params>& displays);
+
+ GpuPlatformSupportHostGbm* proxy_; // Not owned.
+ DeviceManager* device_manager_; // Not owned.
+ ScopedVector<DisplaySnapshot> displays_;
+ ObserverList<NativeDisplayObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeDisplayDelegateProxy);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_NATIVE_DISPLAY_DELEGATE_PROXY_H_
diff --git a/ui/ozone/platform/dri/ozone_platform_dri.cc b/ui/ozone/platform/dri/ozone_platform_dri.cc
new file mode 100644
index 0000000..e4a1324
--- /dev/null
+++ b/ui/ozone/platform/dri/ozone_platform_dri.cc
@@ -0,0 +1,118 @@
+// 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/dri/ozone_platform_dri.h"
+
+#include "base/at_exit.h"
+#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.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/ozone/platform/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_cursor.h"
+#include "ui/ozone/platform/dri/dri_surface_factory.h"
+#include "ui/ozone/platform/dri/dri_window.h"
+#include "ui/ozone/platform/dri/dri_window_delegate_impl.h"
+#include "ui/ozone/platform/dri/dri_window_delegate_manager.h"
+#include "ui/ozone/platform/dri/dri_window_manager.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/native_display_delegate_dri.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+#include "ui/ozone/platform/dri/virtual_terminal_manager.h"
+#include "ui/ozone/public/ozone_platform.h"
+
+namespace ui {
+
+namespace {
+
+const char kDefaultGraphicsCardPath[] = "/dev/dri/card0";
+
+// OzonePlatform for Linux DRI (Direct Rendering Infrastructure)
+//
+// This platform is Linux without any display server (no X, wayland, or
+// anything). This means chrome alone owns the display and input devices.
+class OzonePlatformDri : public OzonePlatform {
+ public:
+ OzonePlatformDri()
+ : vt_manager_(new VirtualTerminalManager()),
+ dri_(new DriWrapper(kDefaultGraphicsCardPath)),
+ buffer_generator_(new DriBufferGenerator(dri_.get())),
+ screen_manager_(new ScreenManager(dri_.get(),
+ buffer_generator_.get())),
+ device_manager_(CreateDeviceManager()) {
+ base::AtExitManager::RegisterTask(
+ base::Bind(&base::DeletePointer<OzonePlatformDri>, this));
+ }
+ virtual ~OzonePlatformDri() {}
+
+ // OzonePlatform:
+ virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE {
+ return surface_factory_ozone_.get();
+ }
+ virtual CursorFactoryOzone* GetCursorFactoryOzone() OVERRIDE {
+ return cursor_factory_ozone_.get();
+ }
+ virtual GpuPlatformSupport* GetGpuPlatformSupport() OVERRIDE {
+ return NULL; // no GPU support
+ }
+ virtual GpuPlatformSupportHost* GetGpuPlatformSupportHost() OVERRIDE {
+ return NULL; // no GPU support
+ }
+ virtual scoped_ptr<PlatformWindow> CreatePlatformWindow(
+ PlatformWindowDelegate* delegate,
+ const gfx::Rect& bounds) OVERRIDE {
+ scoped_ptr<DriWindow> platform_window(new DriWindow(
+ delegate,
+ bounds,
+ scoped_ptr<DriWindowDelegate>(new DriWindowDelegateImpl(
+ window_manager_->NextAcceleratedWidget(), screen_manager_.get())),
+ event_factory_ozone_.get(),
+ &window_delegate_manager_,
+ window_manager_.get()));
+ platform_window->Initialize();
+ return platform_window.PassAs<PlatformWindow>();
+ }
+ virtual scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate()
+ OVERRIDE {
+ return scoped_ptr<NativeDisplayDelegate>(new NativeDisplayDelegateDri(
+ dri_.get(), screen_manager_.get(), device_manager_.get()));
+ }
+ virtual void InitializeUI() OVERRIDE {
+ dri_->Initialize();
+ surface_factory_ozone_.reset(new DriSurfaceFactory(
+ dri_.get(), screen_manager_.get(), &window_delegate_manager_));
+ cursor_factory_ozone_.reset(new BitmapCursorFactoryOzone);
+ window_manager_.reset(new DriWindowManager(surface_factory_ozone_.get()));
+ event_factory_ozone_.reset(new EventFactoryEvdev(window_manager_->cursor(),
+ device_manager_.get()));
+ if (surface_factory_ozone_->InitializeHardware() !=
+ DriSurfaceFactory::INITIALIZED)
+ LOG(FATAL) << "failed to initialize display hardware";
+
+ }
+
+ virtual void InitializeGPU() OVERRIDE {}
+
+ private:
+ scoped_ptr<VirtualTerminalManager> vt_manager_;
+ scoped_ptr<DriWrapper> dri_;
+ scoped_ptr<DriBufferGenerator> buffer_generator_;
+ scoped_ptr<ScreenManager> screen_manager_;
+ scoped_ptr<DeviceManager> device_manager_;
+
+ scoped_ptr<DriSurfaceFactory> surface_factory_ozone_;
+ scoped_ptr<BitmapCursorFactoryOzone> cursor_factory_ozone_;
+ scoped_ptr<EventFactoryEvdev> event_factory_ozone_;
+
+ scoped_ptr<DriWindowManager> window_manager_;
+ DriWindowDelegateManager window_delegate_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(OzonePlatformDri);
+};
+
+} // namespace
+
+OzonePlatform* CreateOzonePlatformDri() { return new OzonePlatformDri; }
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/ozone_platform_dri.h b/ui/ozone/platform/dri/ozone_platform_dri.h
new file mode 100644
index 0000000..a63a054
--- /dev/null
+++ b/ui/ozone/platform/dri/ozone_platform_dri.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_DRI_OZONE_PLATFORM_DRI_H_
+#define UI_OZONE_PLATFORM_DRI_OZONE_PLATFORM_DRI_H_
+
+namespace ui {
+
+class OzonePlatform;
+
+// Constructor hook for use in ozone_platform_list.cc
+OzonePlatform* CreateOzonePlatformDri();
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_OZONE_PLATFORM_DRI_H_
diff --git a/ui/ozone/platform/dri/ozone_platform_gbm.cc b/ui/ozone/platform/dri/ozone_platform_gbm.cc
new file mode 100644
index 0000000..8c467a4
--- /dev/null
+++ b/ui/ozone/platform/dri/ozone_platform_gbm.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 "ui/ozone/platform/dri/ozone_platform_gbm.h"
+
+#include <dlfcn.h>
+#include <gbm.h>
+#include <stdlib.h>
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/events/ozone/evdev/event_factory_evdev.h"
+#include "ui/ozone/platform/dri/dri_cursor.h"
+#include "ui/ozone/platform/dri/dri_window.h"
+#include "ui/ozone/platform/dri/dri_window_delegate_manager.h"
+#include "ui/ozone/platform/dri/dri_window_delegate_proxy.h"
+#include "ui/ozone/platform/dri/dri_window_manager.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/gbm_buffer.h"
+#include "ui/ozone/platform/dri/gbm_surface.h"
+#include "ui/ozone/platform/dri/gbm_surface_factory.h"
+#include "ui/ozone/platform/dri/gpu_platform_support_gbm.h"
+#include "ui/ozone/platform/dri/gpu_platform_support_host_gbm.h"
+#include "ui/ozone/platform/dri/native_display_delegate_dri.h"
+#include "ui/ozone/platform/dri/native_display_delegate_proxy.h"
+#include "ui/ozone/platform/dri/scanout_buffer.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+#include "ui/ozone/platform/dri/virtual_terminal_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"
+
+namespace ui {
+
+namespace {
+
+const char kDefaultGraphicsCardPath[] = "/dev/dri/card0";
+
+class GbmBufferGenerator : public ScanoutBufferGenerator {
+ public:
+ GbmBufferGenerator(DriWrapper* dri)
+ : dri_(dri),
+ glapi_lib_(dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL)),
+ device_(gbm_create_device(dri_->get_fd())) {
+ if (!device_)
+ LOG(FATAL) << "Unable to initialize gbm for " << kDefaultGraphicsCardPath;
+ }
+ virtual ~GbmBufferGenerator() {
+ gbm_device_destroy(device_);
+ if (glapi_lib_)
+ dlclose(glapi_lib_);
+ }
+
+ gbm_device* device() const { return device_; }
+
+ virtual scoped_refptr<ScanoutBuffer> Create(const gfx::Size& size) OVERRIDE {
+ return GbmBuffer::CreateBuffer(
+ dri_, device_, SurfaceFactoryOzone::RGBA_8888, size, true);
+ }
+
+ protected:
+ DriWrapper* dri_; // Not owned.
+
+ // HACK: gbm drivers have broken linkage
+ void *glapi_lib_;
+
+ gbm_device* device_;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmBufferGenerator);
+};
+
+class OzonePlatformGbm : public OzonePlatform {
+ public:
+ OzonePlatformGbm(bool use_surfaceless) : use_surfaceless_(use_surfaceless) {
+ base::AtExitManager::RegisterTask(
+ base::Bind(&base::DeletePointer<OzonePlatformGbm>, this));
+ }
+ virtual ~OzonePlatformGbm() {}
+
+ // OzonePlatform:
+ virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE {
+ return surface_factory_ozone_.get();
+ }
+ virtual CursorFactoryOzone* GetCursorFactoryOzone() OVERRIDE {
+ return cursor_factory_ozone_.get();
+ }
+ virtual GpuPlatformSupport* GetGpuPlatformSupport() OVERRIDE {
+ return gpu_platform_support_.get();
+ }
+ virtual GpuPlatformSupportHost* GetGpuPlatformSupportHost() OVERRIDE {
+ return gpu_platform_support_host_.get();
+ }
+ virtual scoped_ptr<PlatformWindow> CreatePlatformWindow(
+ PlatformWindowDelegate* delegate,
+ const gfx::Rect& bounds) OVERRIDE {
+ scoped_ptr<DriWindow> platform_window(
+ new DriWindow(delegate,
+ bounds,
+ scoped_ptr<DriWindowDelegate>(new DriWindowDelegateProxy(
+ window_manager_->NextAcceleratedWidget(),
+ gpu_platform_support_host_.get())),
+ event_factory_ozone_.get(),
+ ui_window_delegate_manager_.get(),
+ window_manager_.get()));
+ platform_window->Initialize();
+ return platform_window.PassAs<PlatformWindow>();
+ }
+ virtual scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate()
+ OVERRIDE {
+ return scoped_ptr<NativeDisplayDelegate>(new NativeDisplayDelegateProxy(
+ gpu_platform_support_host_.get(), device_manager_.get()));
+ }
+ virtual void InitializeUI() OVERRIDE {
+ vt_manager_.reset(new VirtualTerminalManager());
+ ui_window_delegate_manager_.reset(new DriWindowDelegateManager());
+ // Needed since the browser process creates the accelerated widgets and that
+ // happens through SFO.
+ surface_factory_ozone_.reset(new GbmSurfaceFactory(use_surfaceless_));
+ device_manager_ = CreateDeviceManager();
+ gpu_platform_support_host_.reset(new GpuPlatformSupportHostGbm());
+ cursor_factory_ozone_.reset(new BitmapCursorFactoryOzone);
+ window_manager_.reset(
+ new DriWindowManager(gpu_platform_support_host_.get()));
+ event_factory_ozone_.reset(new EventFactoryEvdev(window_manager_->cursor(),
+ device_manager_.get()));
+ }
+
+ virtual void InitializeGPU() OVERRIDE {
+ dri_.reset(new DriWrapper(kDefaultGraphicsCardPath));
+ dri_->Initialize();
+ buffer_generator_.reset(new GbmBufferGenerator(dri_.get()));
+ screen_manager_.reset(new ScreenManager(dri_.get(),
+ buffer_generator_.get()));
+ gpu_window_delegate_manager_.reset(new DriWindowDelegateManager());
+ if (!surface_factory_ozone_)
+ surface_factory_ozone_.reset(new GbmSurfaceFactory(use_surfaceless_));
+
+ surface_factory_ozone_->InitializeGpu(dri_.get(),
+ buffer_generator_->device(),
+ screen_manager_.get(),
+ gpu_window_delegate_manager_.get());
+ gpu_platform_support_.reset(new GpuPlatformSupportGbm(
+ surface_factory_ozone_.get(),
+ gpu_window_delegate_manager_.get(),
+ screen_manager_.get(),
+ scoped_ptr<NativeDisplayDelegateDri>(new NativeDisplayDelegateDri(
+ dri_.get(), screen_manager_.get(), NULL))));
+ if (surface_factory_ozone_->InitializeHardware() !=
+ DriSurfaceFactory::INITIALIZED)
+ LOG(FATAL) << "failed to initialize display hardware";
+ }
+
+ private:
+ bool use_surfaceless_;
+ scoped_ptr<VirtualTerminalManager> vt_manager_;
+ scoped_ptr<DriWrapper> dri_;
+ scoped_ptr<GbmBufferGenerator> buffer_generator_;
+ scoped_ptr<ScreenManager> screen_manager_;
+ scoped_ptr<DeviceManager> device_manager_;
+
+ scoped_ptr<GbmSurfaceFactory> surface_factory_ozone_;
+ scoped_ptr<BitmapCursorFactoryOzone> cursor_factory_ozone_;
+ scoped_ptr<EventFactoryEvdev> event_factory_ozone_;
+
+ scoped_ptr<GpuPlatformSupportGbm> gpu_platform_support_;
+ scoped_ptr<GpuPlatformSupportHostGbm> gpu_platform_support_host_;
+
+ scoped_ptr<DriWindowDelegateManager> gpu_window_delegate_manager_;
+ // TODO(dnicoara) Once we have a mock channel for the software path the window
+ // can own the delegates on the browser side. Remove this then.
+ scoped_ptr<DriWindowDelegateManager> ui_window_delegate_manager_;
+
+ // Browser side object only.
+ scoped_ptr<DriWindowManager> window_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(OzonePlatformGbm);
+};
+
+} // namespace
+
+OzonePlatform* CreateOzonePlatformGbm() {
+ CommandLine* cmd = CommandLine::ForCurrentProcess();
+ return new OzonePlatformGbm(cmd->HasSwitch(switches::kOzoneUseSurfaceless));
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/ozone_platform_gbm.h b/ui/ozone/platform/dri/ozone_platform_gbm.h
new file mode 100644
index 0000000..47f5ca7
--- /dev/null
+++ b/ui/ozone/platform/dri/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_DRI_OZONE_PLATFORM_GBM_H_
+#define UI_OZONE_PLATFORM_DRI_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_DRI_OZONE_PLATFORM_GBM_H_
diff --git a/ui/ozone/platform/dri/scanout_buffer.h b/ui/ozone/platform/dri/scanout_buffer.h
new file mode 100644
index 0000000..4475c8d
--- /dev/null
+++ b/ui/ozone/platform/dri/scanout_buffer.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_PLATFORM_DRI_SCANOUT_BUFFER_H_
+#define UI_OZONE_PLATFORM_DRI_SCANOUT_BUFFER_H_
+
+#include <stdint.h>
+
+#include "base/memory/ref_counted.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace ui {
+
+// Abstraction for a DRM buffer that can be scanned-out of.
+class ScanoutBuffer : public base::RefCounted<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::RefCounted<ScanoutBuffer>;
+};
+
+class ScanoutBufferGenerator {
+ public:
+ virtual ~ScanoutBufferGenerator() {}
+
+ virtual scoped_refptr<ScanoutBuffer> Create(const gfx::Size& size) = 0;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_SCANOUT_BUFFER_H_
diff --git a/ui/ozone/platform/dri/scoped_drm_types.cc b/ui/ozone/platform/dri/scoped_drm_types.cc
new file mode 100644
index 0000000..0f1c6b3
--- /dev/null
+++ b/ui/ozone/platform/dri/scoped_drm_types.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/dri/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);
+}
+
+void DrmPropertyBlobDeleter::operator()(
+ drmModePropertyBlobRes* property) const {
+ drmModeFreePropertyBlob(property);
+}
+
+void DrmFramebufferDeleter::operator()(drmModeFB* framebuffer) const {
+ drmModeFreeFB(framebuffer);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/scoped_drm_types.h b/ui/ozone/platform/dri/scoped_drm_types.h
new file mode 100644
index 0000000..e651232
--- /dev/null
+++ b/ui/ozone/platform/dri/scoped_drm_types.h
@@ -0,0 +1,69 @@
+// 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_DRI_SCOPED_DRM_TYPES_H_
+#define UI_OZONE_PLATFORM_DRI_SCOPED_DRM_TYPES_H_
+
+#include "base/memory/scoped_ptr.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 _drmModePropertyBlob drmModePropertyBlobRes;
+typedef struct _drmModeRes drmModeRes;
+
+namespace ui {
+
+struct DrmResourcesDeleter {
+ void operator()(drmModeRes* resources) const;
+};
+struct DrmConnectorDeleter {
+ void operator()(drmModeConnector* connector) const;
+};
+struct DrmCrtcDeleter {
+ void operator()(drmModeCrtc* crtc) const;
+};
+struct DrmEncoderDeleter {
+ void operator()(drmModeEncoder* encoder) const;
+};
+struct DrmObjectPropertiesDeleter {
+ void operator()(drmModeObjectProperties* properties) const;
+};
+struct DrmPlaneDeleter {
+ void operator()(drmModePlane* plane) const;
+};
+struct DrmPlaneResDeleter {
+ void operator()(drmModePlaneRes* plane_res) const;
+};
+struct DrmPropertyDeleter {
+ void operator()(drmModePropertyRes* property) const;
+};
+struct DrmPropertyBlobDeleter {
+ void operator()(drmModePropertyBlobRes* property) const;
+};
+struct 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;
+typedef scoped_ptr<drmModePropertyBlobRes, DrmPropertyBlobDeleter>
+ScopedDrmPropertyBlobPtr;
+typedef scoped_ptr<drmModeFB, DrmFramebufferDeleter> ScopedDrmFramebufferPtr;
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_SCOPED_DRM_TYPES_H_
diff --git a/ui/ozone/platform/dri/screen_manager.cc b/ui/ozone/platform/dri/screen_manager.cc
new file mode 100644
index 0000000..6330387
--- /dev/null
+++ b/ui/ozone/platform/dri/screen_manager.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/dri/screen_manager.h"
+
+#include <xf86drmMode.h>
+
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/dri/crtc_state.h"
+#include "ui/ozone/platform/dri/dri_util.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+#include "ui/ozone/platform/dri/scanout_buffer.h"
+
+namespace ui {
+
+ScreenManager::ScreenManager(DriWrapper* dri,
+ ScanoutBufferGenerator* buffer_generator)
+ : dri_(dri), buffer_generator_(buffer_generator) {
+}
+
+ScreenManager::~ScreenManager() {
+}
+
+void ScreenManager::AddDisplayController(uint32_t crtc, uint32_t connector) {
+ HardwareDisplayControllers::iterator it = FindDisplayController(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(
+ dri_, scoped_ptr<CrtcState>(new CrtcState(dri_, crtc, connector))));
+}
+
+void ScreenManager::RemoveDisplayController(uint32_t crtc) {
+ HardwareDisplayControllers::iterator it = FindDisplayController(crtc);
+ if (it != controllers_.end()) {
+ bool is_mirrored = (*it)->IsMirrored();
+ (*it)->RemoveCrtc(crtc);
+ if (!is_mirrored)
+ controllers_.erase(it);
+ }
+}
+
+bool ScreenManager::ConfigureDisplayController(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(crtc);
+ DCHECK(controllers_.end() != it) << "Display controller (crtc=" << crtc
+ << ") doesn't exist.";
+
+ HardwareDisplayController* controller = *it;
+ 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() && !controller->IsDisabled())
+ return controller->Enable();
+
+ // 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(dri_, controller->RemoveCrtc(crtc));
+ 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, crtc, connector);
+
+ return ModesetDisplayController(controller, origin, mode);
+}
+
+bool ScreenManager::DisableDisplayController(uint32_t crtc) {
+ HardwareDisplayControllers::iterator it = FindDisplayController(crtc);
+ if (it != controllers_.end()) {
+ if ((*it)->IsMirrored()) {
+ HardwareDisplayController* controller =
+ new HardwareDisplayController(dri_, (*it)->RemoveCrtc(crtc));
+ controllers_.push_back(controller);
+ }
+
+ (*it)->Disable();
+ return true;
+ }
+
+ LOG(ERROR) << "Failed to find display controller crtc=" << crtc;
+ return false;
+}
+
+base::WeakPtr<HardwareDisplayController> ScreenManager::GetDisplayController(
+ const gfx::Rect& bounds) {
+ // TODO(dnicoara): Remove hack once TestScreen uses a simple Ozone display
+ // configuration reader and ScreenManager is called from there to create the
+ // one display needed by the content_shell target.
+ if (controllers_.empty())
+ ForceInitializationOfPrimaryDisplay();
+
+ HardwareDisplayControllers::iterator it =
+ FindActiveDisplayControllerByLocation(bounds);
+ if (it != controllers_.end())
+ return (*it)->AsWeakPtr();
+
+ return base::WeakPtr<HardwareDisplayController>();
+}
+
+ScreenManager::HardwareDisplayControllers::iterator
+ScreenManager::FindDisplayController(uint32_t crtc) {
+ for (HardwareDisplayControllers::iterator it = controllers_.begin();
+ it != controllers_.end();
+ ++it) {
+ if ((*it)->HasCrtc(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());
+ // We don't perform a strict check since content_shell will have windows
+ // smaller than the display size.
+ if (controller_bounds.Contains(bounds) && !(*it)->IsDisabled())
+ return it;
+ }
+
+ return controllers_.end();
+}
+
+void ScreenManager::ForceInitializationOfPrimaryDisplay() {
+ LOG(WARNING) << "Forcing initialization of primary display.";
+ ScopedVector<HardwareDisplayControllerInfo> displays =
+ GetAvailableDisplayControllerInfos(dri_->get_fd());
+
+ DCHECK_NE(0u, displays.size());
+
+ ScopedDrmPropertyPtr dpms(
+ dri_->GetProperty(displays[0]->connector(), "DPMS"));
+ if (dpms)
+ dri_->SetProperty(displays[0]->connector()->connector_id,
+ dpms->prop_id,
+ DRM_MODE_DPMS_ON);
+
+ AddDisplayController(displays[0]->crtc()->crtc_id,
+ displays[0]->connector()->connector_id);
+ ConfigureDisplayController(displays[0]->crtc()->crtc_id,
+ displays[0]->connector()->connector_id,
+ gfx::Point(),
+ displays[0]->connector()->modes[0]);
+}
+
+bool ScreenManager::ModesetDisplayController(
+ HardwareDisplayController* controller,
+ const gfx::Point& origin,
+ const drmModeModeInfo& mode) {
+ controller->set_origin(origin);
+ // Create a surface suitable for the current controller.
+ scoped_refptr<ScanoutBuffer> buffer =
+ buffer_generator_->Create(gfx::Size(mode.hdisplay, mode.vdisplay));
+
+ if (!buffer.get()) {
+ LOG(ERROR) << "Failed to create scanout buffer";
+ return false;
+ }
+
+ if (!controller->Modeset(OverlayPlane(buffer), mode)) {
+ LOG(ERROR) << "Failed to modeset controller";
+ return false;
+ }
+
+ return true;
+}
+
+bool ScreenManager::HandleMirrorMode(
+ HardwareDisplayControllers::iterator original,
+ HardwareDisplayControllers::iterator mirror,
+ uint32_t crtc,
+ uint32_t connector) {
+ (*mirror)->AddCrtc((*original)->RemoveCrtc(crtc));
+ if ((*mirror)->Enable()) {
+ 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(crtc));
+ (*original)->Enable();
+ return false;
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/screen_manager.h b/ui/ozone/platform/dri/screen_manager.h
new file mode 100644
index 0000000..72278db
--- /dev/null
+++ b/ui/ozone/platform/dri/screen_manager.h
@@ -0,0 +1,100 @@
+// 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_DRI_SCREEN_MANAGER_H_
+#define UI_OZONE_PLATFORM_DRI_SCREEN_MANAGER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+
+typedef struct _drmModeModeInfo drmModeModeInfo;
+
+namespace gfx {
+class Point;
+class Rect;
+class Size;
+} // namespace gfx
+
+namespace ui {
+
+class DriWrapper;
+class ScanoutBufferGenerator;
+
+// Responsible for keeping track of active displays and configuring them.
+class ScreenManager {
+ public:
+ ScreenManager(DriWrapper* dri, ScanoutBufferGenerator* surface_generator);
+ virtual ~ScreenManager();
+
+ // Register a display controller. This must be called before trying to
+ // configure it.
+ void AddDisplayController(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(uint32_t crtc);
+
+ // Configure a display controller. The display controller is identified by
+ // (|crtc|, |connector|) and the controller is modeset using |mode|.
+ bool ConfigureDisplayController(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(uint32_t crtc);
+
+ // Returns a reference to the display controller configured to display within
+ // |bounds|.
+ // This returns a weak reference since the display controller may be destroyed
+ // at any point in time, but the changes are propagated to the compositor much
+ // later (Compositor owns SurfaceOzone*, which is responsible for updating the
+ // display surface).
+ base::WeakPtr<HardwareDisplayController> GetDisplayController(
+ const gfx::Rect& bounds);
+
+ // On non CrOS builds there is no display configurator to look-up available
+ // displays and initialize the HDCs. In such cases this is called internally
+ // to initialize a display.
+ virtual void ForceInitializationOfPrimaryDisplay();
+
+ private:
+ typedef ScopedVector<HardwareDisplayController> HardwareDisplayControllers;
+
+ // Returns an iterator into |controllers_| for the controller identified by
+ // (|crtc|, |connector|).
+ HardwareDisplayControllers::iterator FindDisplayController(uint32_t crtc);
+
+ // Returns an iterator into |controllers_| for the controller located at
+ // |origin|.
+ HardwareDisplayControllers::iterator FindActiveDisplayControllerByLocation(
+ const gfx::Rect& bounds);
+
+ // Perform modesetting in |controller| using |origin| and |mode|.
+ bool ModesetDisplayController(HardwareDisplayController* controller,
+ const gfx::Point& origin,
+ const drmModeModeInfo& mode);
+
+ // 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,
+ uint32_t crtc,
+ uint32_t connector);
+
+ DriWrapper* dri_; // Not owned.
+ ScanoutBufferGenerator* buffer_generator_; // Not owned.
+ // List of display controllers (active and disabled).
+ HardwareDisplayControllers controllers_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_SCREEN_MANAGER_H_
diff --git a/ui/ozone/platform/dri/screen_manager_unittest.cc b/ui/ozone/platform/dri/screen_manager_unittest.cc
new file mode 100644
index 0000000..8eda243
--- /dev/null
+++ b/ui/ozone/platform/dri/screen_manager_unittest.cc
@@ -0,0 +1,240 @@
+// 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/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+#include "ui/ozone/platform/dri/test/mock_dri_wrapper.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;
+
+class MockScreenManager : public ui::ScreenManager {
+ public:
+ MockScreenManager(ui::DriWrapper* dri,
+ ui::ScanoutBufferGenerator* buffer_generator)
+ : ScreenManager(dri, buffer_generator), dri_(dri) {}
+
+ virtual void ForceInitializationOfPrimaryDisplay() OVERRIDE {}
+
+ private:
+ ui::DriWrapper* dri_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockScreenManager);
+};
+
+} // namespace
+
+class ScreenManagerTest : public testing::Test {
+ public:
+ ScreenManagerTest() {}
+ virtual ~ScreenManagerTest() {}
+
+ 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);
+ }
+
+ virtual void SetUp() OVERRIDE {
+ dri_.reset(new ui::MockDriWrapper(3));
+ buffer_generator_.reset(new ui::DriBufferGenerator(dri_.get()));
+ screen_manager_.reset(new MockScreenManager(
+ dri_.get(), buffer_generator_.get()));
+ }
+ virtual void TearDown() OVERRIDE {
+ screen_manager_.reset();
+ dri_.reset();
+ }
+
+ protected:
+ scoped_ptr<ui::MockDriWrapper> dri_;
+ scoped_ptr<ui::DriBufferGenerator> buffer_generator_;
+ scoped_ptr<MockScreenManager> 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(kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(kPrimaryCrtc,
+ kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+ base::WeakPtr<ui::HardwareDisplayController> controller =
+ screen_manager_->GetDisplayController(GetPrimaryBounds());
+
+ EXPECT_TRUE(controller);
+ EXPECT_TRUE(controller->HasCrtc(kPrimaryCrtc));
+}
+
+TEST_F(ScreenManagerTest, CheckWithInvalidBounds) {
+ screen_manager_->AddDisplayController(kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(kPrimaryCrtc,
+ kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+}
+
+TEST_F(ScreenManagerTest, CheckForSecondValidController) {
+ screen_manager_->AddDisplayController(kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(kPrimaryCrtc,
+ kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->AddDisplayController(kSecondaryCrtc, kSecondaryConnector);
+ screen_manager_->ConfigureDisplayController(kSecondaryCrtc,
+ kSecondaryConnector,
+ GetSecondaryBounds().origin(),
+ kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+}
+
+TEST_F(ScreenManagerTest, CheckControllerAfterItIsRemoved) {
+ screen_manager_->AddDisplayController(kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(kPrimaryCrtc,
+ kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+ base::WeakPtr<ui::HardwareDisplayController> controller =
+ screen_manager_->GetDisplayController(GetPrimaryBounds());
+
+ EXPECT_TRUE(controller);
+ screen_manager_->RemoveDisplayController(kPrimaryCrtc);
+ EXPECT_FALSE(controller);
+}
+
+TEST_F(ScreenManagerTest, CheckDuplicateConfiguration) {
+ screen_manager_->AddDisplayController(kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(kPrimaryCrtc,
+ kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->ConfigureDisplayController(kPrimaryCrtc,
+ kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+}
+
+TEST_F(ScreenManagerTest, CheckChangingMode) {
+ screen_manager_->AddDisplayController(kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(kPrimaryCrtc,
+ kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+ drmModeModeInfo new_mode = kDefaultMode;
+ new_mode.vdisplay = 10;
+ screen_manager_->ConfigureDisplayController(
+ 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(kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(kPrimaryCrtc,
+ kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->AddDisplayController(kSecondaryCrtc, kSecondaryConnector);
+ screen_manager_->ConfigureDisplayController(kSecondaryCrtc,
+ kSecondaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+}
+
+TEST_F(ScreenManagerTest, CheckMirrorModeTransitions) {
+ screen_manager_->AddDisplayController(kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(kPrimaryCrtc,
+ kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->AddDisplayController(kSecondaryCrtc, kSecondaryConnector);
+ screen_manager_->ConfigureDisplayController(kSecondaryCrtc,
+ kSecondaryConnector,
+ GetSecondaryBounds().origin(),
+ kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+
+ screen_manager_->ConfigureDisplayController(kPrimaryCrtc,
+ kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->ConfigureDisplayController(kSecondaryCrtc,
+ kSecondaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+
+ screen_manager_->ConfigureDisplayController(kPrimaryCrtc,
+ kPrimaryConnector,
+ GetSecondaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->ConfigureDisplayController(kSecondaryCrtc,
+ kSecondaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+}
+
+TEST_F(ScreenManagerTest, MonitorGoneInMirrorMode) {
+ screen_manager_->AddDisplayController(kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->ConfigureDisplayController(kPrimaryCrtc,
+ kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+ screen_manager_->AddDisplayController(kSecondaryCrtc, kSecondaryConnector);
+ screen_manager_->ConfigureDisplayController(kSecondaryCrtc,
+ kSecondaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode);
+
+ screen_manager_->RemoveDisplayController(kSecondaryCrtc);
+ EXPECT_TRUE(
+ screen_manager_->ConfigureDisplayController(kPrimaryCrtc,
+ kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ kDefaultMode));
+ EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+}
diff --git a/ui/ozone/platform/dri/test/mock_dri_wrapper.cc b/ui/ozone/platform/dri/test/mock_dri_wrapper.cc
new file mode 100644
index 0000000..1ac5215
--- /dev/null
+++ b/ui/ozone/platform/dri/test/mock_dri_wrapper.cc
@@ -0,0 +1,160 @@
+// 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/dri/test/mock_dri_wrapper.h"
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+
+namespace ui {
+
+namespace {
+
+template<class Object> Object* DrmAllocator() {
+ return static_cast<Object*>(drmMalloc(sizeof(Object)));
+}
+
+} // namespace
+
+MockDriWrapper::MockDriWrapper(int fd)
+ : DriWrapper(""),
+ 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),
+ set_crtc_expectation_(true),
+ add_framebuffer_expectation_(true),
+ page_flip_expectation_(true),
+ create_dumb_buffer_expectation_(true),
+ current_framebuffer_(0) {
+ fd_ = fd;
+}
+
+MockDriWrapper::~MockDriWrapper() {
+ fd_ = -1;
+}
+
+ScopedDrmCrtcPtr MockDriWrapper::GetCrtc(uint32_t crtc_id) {
+ get_crtc_call_count_++;
+ return ScopedDrmCrtcPtr(DrmAllocator<drmModeCrtc>());
+}
+
+bool MockDriWrapper::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 MockDriWrapper::SetCrtc(drmModeCrtc* crtc,
+ std::vector<uint32_t> connectors) {
+ restore_crtc_call_count_++;
+ return true;
+}
+
+ScopedDrmConnectorPtr MockDriWrapper::GetConnector(uint32_t connector_id) {
+ return ScopedDrmConnectorPtr(DrmAllocator<drmModeConnector>());
+}
+
+bool MockDriWrapper::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 MockDriWrapper::RemoveFramebuffer(uint32_t framebuffer) {
+ remove_framebuffer_call_count_++;
+ return true;
+}
+
+bool MockDriWrapper::PageFlip(uint32_t crtc_id,
+ uint32_t framebuffer,
+ void* data) {
+ page_flip_call_count_++;
+ current_framebuffer_ = framebuffer;
+ controllers_.push(static_cast<ui::HardwareDisplayController*>(data));
+ return page_flip_expectation_;
+}
+
+bool MockDriWrapper::PageFlipOverlay(uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& location,
+ const gfx::RectF& source,
+ int overlay_plane) {
+ overlay_flip_call_count_++;
+ return true;
+}
+
+ScopedDrmPropertyPtr MockDriWrapper::GetProperty(drmModeConnector* connector,
+ const char* name) {
+ return ScopedDrmPropertyPtr(DrmAllocator<drmModePropertyRes>());
+}
+
+bool MockDriWrapper::SetProperty(uint32_t connector_id,
+ uint32_t property_id,
+ uint64_t value) {
+ return true;
+}
+
+ScopedDrmPropertyBlobPtr MockDriWrapper::GetPropertyBlob(
+ drmModeConnector* connector,
+ const char* name) {
+ return ScopedDrmPropertyBlobPtr(DrmAllocator<drmModePropertyBlobRes>());
+}
+
+bool MockDriWrapper::SetCursor(uint32_t crtc_id,
+ uint32_t handle,
+ const gfx::Size& size) {
+ return true;
+}
+
+bool MockDriWrapper::MoveCursor(uint32_t crtc_id, const gfx::Point& point) {
+ return true;
+}
+
+void MockDriWrapper::HandleEvent(drmEventContext& event) {
+ CHECK(!controllers_.empty());
+ controllers_.front()->OnPageFlipEvent(0, 0, 0);
+ controllers_.pop();
+}
+
+bool MockDriWrapper::CreateDumbBuffer(const SkImageInfo& info,
+ uint32_t* handle,
+ uint32_t* stride,
+ void** pixels) {
+ if (!create_dumb_buffer_expectation_)
+ return false;
+
+ *handle = 0;
+ *stride = info.minRowBytes();
+ *pixels = new char[info.getSafeSize(*stride)];
+ buffers_.push_back(
+ skia::AdoptRef(SkSurface::NewRasterDirect(info, *pixels, *stride)));
+ buffers_.back()->getCanvas()->clear(SK_ColorBLACK);
+
+ return true;
+}
+
+void MockDriWrapper::DestroyDumbBuffer(const SkImageInfo& info,
+ uint32_t handle,
+ uint32_t stride,
+ void* pixels) {
+ delete[] static_cast<char*>(pixels);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/test/mock_dri_wrapper.h b/ui/ozone/platform/dri/test/mock_dri_wrapper.h
new file mode 100644
index 0000000..9ffb868
--- /dev/null
+++ b/ui/ozone/platform/dri/test/mock_dri_wrapper.h
@@ -0,0 +1,123 @@
+// 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_DRI_TEST_MOCK_DRI_WRAPPER_H_
+#define UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRI_WRAPPER_H_
+
+#include <queue>
+#include <vector>
+
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+
+namespace ui {
+
+class HardwareDisplayController;
+
+// The real DriWrapper makes actual DRM calls which we can't use in unit tests.
+class MockDriWrapper : public ui::DriWrapper {
+ public:
+ MockDriWrapper(int fd);
+ virtual ~MockDriWrapper();
+
+ 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_; }
+ void fail_init() { fd_ = -1; }
+ 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_;
+ }
+
+ // DriWrapper:
+ virtual ScopedDrmCrtcPtr GetCrtc(uint32_t crtc_id) OVERRIDE;
+ virtual bool SetCrtc(uint32_t crtc_id,
+ uint32_t framebuffer,
+ std::vector<uint32_t> connectors,
+ drmModeModeInfo* mode) OVERRIDE;
+ virtual bool SetCrtc(drmModeCrtc* crtc,
+ std::vector<uint32_t> connectors) OVERRIDE;
+ virtual ScopedDrmConnectorPtr GetConnector(uint32_t connector_id) OVERRIDE;
+ virtual bool AddFramebuffer(uint32_t width,
+ uint32_t height,
+ uint8_t depth,
+ uint8_t bpp,
+ uint32_t stride,
+ uint32_t handle,
+ uint32_t* framebuffer) OVERRIDE;
+ virtual bool RemoveFramebuffer(uint32_t framebuffer) OVERRIDE;
+ virtual bool PageFlip(uint32_t crtc_id,
+ uint32_t framebuffer,
+ void* data) OVERRIDE;
+ virtual bool PageFlipOverlay(uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& location,
+ const gfx::RectF& source,
+ int overlay_plane) OVERRIDE;
+ virtual ScopedDrmPropertyPtr GetProperty(drmModeConnector* connector,
+ const char* name) OVERRIDE;
+ virtual bool SetProperty(uint32_t connector_id,
+ uint32_t property_id,
+ uint64_t value) OVERRIDE;
+ virtual ScopedDrmPropertyBlobPtr GetPropertyBlob(drmModeConnector* connector,
+ const char* name) OVERRIDE;
+ virtual bool SetCursor(uint32_t crtc_id,
+ uint32_t handle,
+ const gfx::Size& size) OVERRIDE;
+ virtual bool MoveCursor(uint32_t crtc_id, const gfx::Point& point) OVERRIDE;
+ virtual void HandleEvent(drmEventContext& event) OVERRIDE;
+ virtual bool CreateDumbBuffer(const SkImageInfo& info,
+ uint32_t* handle,
+ uint32_t* stride,
+ void** pixels) OVERRIDE;
+ virtual void DestroyDumbBuffer(const SkImageInfo& info,
+ uint32_t handle,
+ uint32_t stride,
+ void* pixels) OVERRIDE;
+
+ private:
+ 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_;
+
+ bool set_crtc_expectation_;
+ bool add_framebuffer_expectation_;
+ bool page_flip_expectation_;
+ bool create_dumb_buffer_expectation_;
+
+ uint32_t current_framebuffer_;
+
+ std::vector<skia::RefPtr<SkSurface> > buffers_;
+
+ std::queue<HardwareDisplayController*> controllers_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDriWrapper);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRI_WRAPPER_H_
diff --git a/ui/ozone/platform/dri/virtual_terminal_manager.cc b/ui/ozone/platform/dri/virtual_terminal_manager.cc
new file mode 100644
index 0000000..efd8350
--- /dev/null
+++ b/ui/ozone/platform/dri/virtual_terminal_manager.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/platform/dri/virtual_terminal_manager.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+
+namespace ui {
+
+namespace {
+
+const char kTTYDevice[] = "/dev/tty1";
+
+const int kVT = 1;
+
+} // namespace
+
+VirtualTerminalManager::VirtualTerminalManager() {
+ // Use the current console.
+ fd_ = open(kTTYDevice, O_RDWR | O_CLOEXEC, 0);
+ if (fd_ < 0)
+ LOG(ERROR) << "Failed to open '" << kTTYDevice << "' " << strerror(errno);
+
+ if (ioctl(fd_, VT_ACTIVATE, kVT) || ioctl(fd_, VT_WAITACTIVE, kVT))
+ LOG(ERROR) << "Failed to switch to VT: " << kVT
+ << " error: " << strerror(errno);;
+
+ if (ioctl(fd_, KDGETMODE, &vt_mode_))
+ LOG(ERROR) << "Failed to get VT mode: " << strerror(errno);
+
+ if (ioctl(fd_, KDSETMODE, KD_GRAPHICS))
+ LOG(ERROR) << "Failed to set graphics mode: " << strerror(errno);
+
+ if (tcgetattr(fd_, &terminal_attributes_))
+ LOG(ERROR) << "Failed to get terminal attributes";
+
+ // Stop the TTY from processing keys and echo-ing them to the terminal.
+ struct termios raw_attributes = terminal_attributes_;
+ cfmakeraw(&raw_attributes);
+ raw_attributes.c_oflag |= OPOST;
+ if (tcsetattr(fd_, TCSANOW, &raw_attributes))
+ LOG(ERROR) << "Failed to set raw attributes";
+
+ if (ioctl(fd_, KDGKBMODE, &previous_keyboard_mode_))
+ LOG(ERROR) << "Failed to get keyboard mode";
+
+ if (ioctl(fd_, KDSKBMODE, K_OFF) && ioctl(fd_, KDSKBMODE, K_RAW))
+ LOG(ERROR) << "Failed to set keyboard mode";
+}
+
+VirtualTerminalManager::~VirtualTerminalManager() {
+ if (fd_ < 0)
+ return;
+
+ if (ioctl(fd_, KDSETMODE, &vt_mode_))
+ LOG(ERROR) << "Failed to restore VT mode";
+
+ if (ioctl(fd_, KDSKBMODE, previous_keyboard_mode_))
+ LOG(ERROR) << "Failed to restore keyboard mode";
+
+ if (tcsetattr(fd_, TCSANOW, &terminal_attributes_))
+ LOG(ERROR) << "Failed to restore terminal attributes";
+
+ close(fd_);
+}
+
+} // namespace ui
diff --git a/ui/ozone/platform/dri/virtual_terminal_manager.h b/ui/ozone/platform/dri/virtual_terminal_manager.h
new file mode 100644
index 0000000..11af0b0
--- /dev/null
+++ b/ui/ozone/platform/dri/virtual_terminal_manager.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_DRI_VIRTUAL_TERMINAL_MANAGER_H_
+#define UI_OZONE_PLATFORM_DRI_VIRTUAL_TERMINAL_MANAGER_H_
+
+#include <termios.h>
+
+#include "base/basictypes.h"
+
+namespace ui {
+
+class VirtualTerminalManager {
+ public:
+ VirtualTerminalManager();
+ ~VirtualTerminalManager();
+
+ private:
+
+ int fd_;
+ int vt_mode_;
+ int previous_keyboard_mode_;
+ struct termios terminal_attributes_;
+
+ DISALLOW_COPY_AND_ASSIGN(VirtualTerminalManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_VIRTUAL_TERMINAL_MANAGER_H_
diff --git a/ui/ozone/platform/egltest/BUILD.gn b/ui/ozone/platform/egltest/BUILD.gn
new file mode 100644
index 0000000..04cae36
--- /dev/null
+++ b/ui/ozone/platform/egltest/BUILD.gn
@@ -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.
+
+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/ozone:events_ozone_evdev",
+ "//ui/gfx",
+ ]
+}
+
+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..af1228d
--- /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 = 800;
+const int kDefaultHeight = 600;
+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/egltest.gypi b/ui/ozone/platform/egltest/egltest.gypi
new file mode 100644
index 0000000..8191af5
--- /dev/null
+++ b/ui/ozone/platform/egltest/egltest.gypi
@@ -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.
+
+{
+ 'variables': {
+ 'internal_ozone_platform_deps': [
+ 'ozone_platform_egltest',
+ ],
+ 'internal_ozone_platforms': [
+ 'egltest'
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'ozone_platform_egltest',
+ 'type': 'static_library',
+ 'defines': [
+ 'OZONE_IMPLEMENTATION',
+ ],
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../third_party/khronos/khronos.gyp:khronos_headers',
+ '../events/events.gyp:events',
+ '../events/ozone/events_ozone.gyp:events_ozone_evdev',
+ '../gfx/gfx.gyp:gfx',
+ 'eglplatform_shim',
+ ],
+ 'sources': [
+ 'ozone_platform_egltest.cc',
+ 'ozone_platform_egltest.h',
+ ],
+ },
+ {
+ 'target_name': 'eglplatform_shim',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../../third_party/khronos/khronos.gyp:khronos_headers',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '<(SHARED_INTERMEDIATE_DIR)',
+ ],
+ },
+ 'include_dirs': [
+ '../../../..',
+ ],
+ 'hard_dependency': 1,
+ 'actions': [
+ {
+ 'variables': {
+ 'output_h': '<(SHARED_INTERMEDIATE_DIR)/library_loaders/libeglplatform_shim.h',
+ 'output_cc': '<(INTERMEDIATE_DIR)/libeglplatform_shim_loader.cc',
+ 'generator': '../../tools/generate_library_loader/generate_library_loader.py',
+ },
+ 'action_name': 'generate_libeglplatform_shim_loader',
+ 'inputs': [
+ '<(generator)',
+ ],
+ 'outputs': [
+ '<(output_h)',
+ '<(output_cc)',
+ ],
+ 'action': ['python',
+ '<(generator)',
+ '--name', 'LibeglplatformShimLoader',
+ '--output-h', '<(output_h)',
+ '--output-cc', '<(output_cc)',
+ '--header', '"ui/ozone/platform/egltest/eglplatform_shim.h"',
+ 'ShimQueryString',
+ 'ShimInitialize',
+ 'ShimTerminate',
+ 'ShimCreateWindow',
+ 'ShimQueryWindow',
+ 'ShimDestroyWindow',
+ 'ShimGetNativeDisplay',
+ 'ShimGetNativeWindow',
+ 'ShimReleaseNativeWindow',
+ ],
+ 'message': 'Generating libeglplatform_shim library loader',
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ ],
+ 'conditions': [
+ ['ozone_platform_ozonex == 1', {
+ 'targets': [
+ {
+ 'target_name': 'eglplatform_shim_x11',
+ 'type': 'loadable_module',
+ 'product_name': 'eglplatform_shim',
+ 'product_extension': 'so.1',
+ 'include_dirs': [
+ '../../../..',
+ ],
+ 'dependencies': [
+ '../../build/linux/system.gyp:x11',
+ ],
+ 'sources': [
+ 'eglplatform_shim.h',
+ 'eglplatform_shim_xeleven.cc',
+ ],
+ },
+ ],
+ }],
+ ],
+}
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..46ee4ef
--- /dev/null
+++ b/ui/ozone/platform/egltest/ozone_platform_egltest.cc
@@ -0,0 +1,386 @@
+// 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 "library_loaders/libeglplatform_shim.h"
+#include "third_party/khronos/EGL/egl.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/platform/platform_event_dispatcher.h"
+#include "ui/gfx/vsync_provider.h"
+#include "ui/ozone/common/native_display_delegate_ozone.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/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;
+}
+
+class EgltestWindow : public PlatformWindow, public PlatformEventDispatcher {
+ public:
+ EgltestWindow(PlatformWindowDelegate* delegate,
+ LibeglplatformShimLoader* eglplatform_shim,
+ EventFactoryEvdev* event_factory,
+ const gfx::Rect& bounds);
+ virtual ~EgltestWindow();
+
+ // PlatformWindow:
+ virtual gfx::Rect GetBounds() OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual void ToggleFullscreen() OVERRIDE;
+ virtual void Maximize() OVERRIDE;
+ virtual void Minimize() OVERRIDE;
+ virtual void Restore() OVERRIDE;
+ virtual void SetCursor(PlatformCursor cursor) OVERRIDE;
+ virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
+
+ // PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const PlatformEvent& event) OVERRIDE;
+ virtual 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);
+}
+
+bool EgltestWindow::CanDispatchEvent(const ui::PlatformEvent& ne) {
+ return true;
+}
+
+uint32_t EgltestWindow::DispatchEvent(const ui::PlatformEvent& native_event) {
+ 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);
+ }
+ virtual ~SurfaceOzoneEgltest() {
+ bool ret = eglplatform_shim_->ShimReleaseNativeWindow(native_window_);
+ DCHECK(ret);
+ }
+
+ virtual intptr_t GetNativeWindow() OVERRIDE { return native_window_; }
+
+ virtual bool OnSwapBuffers() OVERRIDE { return true; }
+
+ virtual bool ResizeNativeWindow(const gfx::Size& viewport_size) OVERRIDE {
+ return true;
+ }
+
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE {
+ return scoped_ptr<gfx::VSyncProvider>();
+ }
+
+ 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) {}
+ virtual ~SurfaceFactoryEgltest() {}
+
+ // SurfaceFactoryOzone:
+ virtual intptr_t GetNativeDisplay() OVERRIDE;
+ virtual scoped_ptr<SurfaceOzoneEGL> CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget) OVERRIDE;
+ virtual const int32* GetEGLSurfaceProperties(
+ const int32* desired_list) OVERRIDE;
+ virtual bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
+
+ private:
+ LibeglplatformShimLoader* eglplatform_shim_;
+};
+
+intptr_t SurfaceFactoryEgltest::GetNativeDisplay() {
+ return eglplatform_shim_->ShimGetNativeDisplay();
+}
+
+scoped_ptr<SurfaceOzoneEGL> SurfaceFactoryEgltest::CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget) {
+ return make_scoped_ptr<SurfaceOzoneEGL>(
+ new SurfaceOzoneEgltest(widget, eglplatform_shim_));
+}
+
+bool SurfaceFactoryEgltest::LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+ 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;
+
+ base::NativeLibraryLoadError error;
+ base::NativeLibrary egl_library =
+ base::LoadNativeLibrary(base::FilePath(egl_soname), &error);
+ if (!egl_library) {
+ LOG(WARNING) << "Failed to load EGL library: " << error.ToString();
+ return false;
+ }
+
+ base::NativeLibrary gles_library =
+ base::LoadNativeLibrary(base::FilePath(gles_soname), &error);
+ if (!gles_library) {
+ LOG(WARNING) << "Failed to load GLES library: " << error.ToString();
+ base::UnloadNativeLibrary(egl_library);
+ return false;
+ }
+
+ GLGetProcAddressProc get_proc_address =
+ reinterpret_cast<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;
+}
+
+const int32* SurfaceFactoryEgltest::GetEGLSurfaceProperties(
+ const int32* desired_list) {
+ 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) {}
+ virtual ~OzonePlatformEgltest() {
+ 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:
+ virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE {
+ return surface_factory_ozone_.get();
+ }
+ virtual CursorFactoryOzone* GetCursorFactoryOzone() OVERRIDE {
+ return cursor_factory_ozone_.get();
+ }
+ virtual GpuPlatformSupport* GetGpuPlatformSupport() OVERRIDE {
+ return gpu_platform_support_.get();
+ }
+ virtual GpuPlatformSupportHost* GetGpuPlatformSupportHost() OVERRIDE {
+ return gpu_platform_support_host_.get();
+ }
+ virtual 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));
+ }
+ virtual scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate()
+ OVERRIDE {
+ return scoped_ptr<NativeDisplayDelegate>(new NativeDisplayDelegateOzone());
+ }
+
+ virtual void InitializeUI() OVERRIDE {
+ device_manager_ = CreateDeviceManager();
+ if (!surface_factory_ozone_)
+ surface_factory_ozone_.reset(
+ new SurfaceFactoryEgltest(&eglplatform_shim_));
+ event_factory_ozone_.reset(
+ new EventFactoryEvdev(NULL, device_manager_.get()));
+ cursor_factory_ozone_.reset(new CursorFactoryOzone());
+ gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
+ }
+
+ virtual void InitializeGPU() OVERRIDE {
+ if (!surface_factory_ozone_)
+ 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_;
+
+ 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..d1ff717
--- /dev/null
+++ b/ui/ozone/platform/test/BUILD.gn
@@ -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.
+
+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",
+ ]
+}
diff --git a/ui/ozone/platform/test/DEPS b/ui/ozone/platform/test/DEPS
new file mode 100644
index 0000000..41cd997
--- /dev/null
+++ b/ui/ozone/platform/test/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+third_party/skia/include",
+]
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..1057291
--- /dev/null
+++ b/ui/ozone/platform/test/ozone_platform_test.cc
@@ -0,0 +1,92 @@
+// 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/platform/platform_event_source.h"
+#include "ui/ozone/common/native_display_delegate_ozone.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/ozone_platform.h"
+#include "ui/ozone/public/ozone_switches.h"
+
+namespace ui {
+
+namespace {
+
+// 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) {}
+ virtual ~OzonePlatformTest() {}
+
+ // OzonePlatform:
+ virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE {
+ return window_manager_.get();
+ }
+ virtual CursorFactoryOzone* GetCursorFactoryOzone() OVERRIDE {
+ return cursor_factory_ozone_.get();
+ }
+ virtual GpuPlatformSupport* GetGpuPlatformSupport() OVERRIDE {
+ return gpu_platform_support_.get();
+ }
+ virtual GpuPlatformSupportHost* GetGpuPlatformSupportHost() OVERRIDE {
+ return gpu_platform_support_host_.get();
+ }
+ virtual scoped_ptr<PlatformWindow> CreatePlatformWindow(
+ PlatformWindowDelegate* delegate,
+ const gfx::Rect& bounds) OVERRIDE {
+ return make_scoped_ptr<PlatformWindow>(
+ new TestWindow(delegate, window_manager_.get(), bounds));
+ }
+ virtual scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate()
+ OVERRIDE {
+ return scoped_ptr<NativeDisplayDelegate>(new NativeDisplayDelegateOzone());
+ }
+
+ virtual 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_ = PlatformEventSource::CreateDefault();
+
+ cursor_factory_ozone_.reset(new BitmapCursorFactoryOzone);
+ gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
+ }
+
+ virtual 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<GpuPlatformSupport> gpu_platform_support_;
+ scoped_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
+ base::FilePath file_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(OzonePlatformTest);
+};
+
+} // namespace
+
+OzonePlatform* CreateOzonePlatformTest() {
+ CommandLine* cmd = 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.gypi b/ui/ozone/platform/test/test.gypi
new file mode 100644
index 0000000..d1a35c8
--- /dev/null
+++ b/ui/ozone/platform/test/test.gypi
@@ -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.
+
+{
+ 'variables': {
+ 'internal_ozone_platform_deps': [
+ 'ozone_platform_test',
+ ],
+ 'internal_ozone_platforms': [
+ 'test'
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'ozone_platform_test',
+ 'type': 'static_library',
+ 'defines': [
+ 'OZONE_IMPLEMENTATION',
+ ],
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../events/events.gyp:events',
+ '../gfx/gfx.gyp:gfx',
+ ],
+ 'sources': [
+ 'ozone_platform_test.cc',
+ 'ozone_platform_test.h',
+ 'test_window.cc',
+ 'test_window.h',
+ 'test_window_manager.cc',
+ 'test_window_manager.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..2cfa26c
--- /dev/null
+++ b/ui/ozone/platform/test/test_window.cc
@@ -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.
+
+#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) {
+}
+
+} // 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..13a23a6
--- /dev/null
+++ b/ui/ozone/platform/test/test_window.h
@@ -0,0 +1,54 @@
+// 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);
+ virtual ~TestWindow();
+
+ // Path for image file for this window.
+ base::FilePath path();
+
+ // PlatformWindow:
+ virtual gfx::Rect GetBounds() OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual void ToggleFullscreen() OVERRIDE;
+ virtual void Maximize() OVERRIDE;
+ virtual void Minimize() OVERRIDE;
+ virtual void Restore() OVERRIDE;
+ virtual void SetCursor(PlatformCursor cursor) OVERRIDE;
+ virtual void MoveCursorTo(const gfx::Point& location) 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..6eb1aef
--- /dev/null
+++ b/ui/ozone/platform/test/test_window_manager.cc
@@ -0,0 +1,112 @@
+// 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) {}
+ virtual ~FileSurface() {}
+
+ // SurfaceOzoneCanvas overrides:
+ virtual void ResizeCanvas(const gfx::Size& viewport_size) OVERRIDE {
+ surface_ = skia::AdoptRef(SkSurface::NewRaster(SkImageInfo::MakeN32Premul(
+ viewport_size.width(), viewport_size.height())));
+ }
+ virtual skia::RefPtr<SkCanvas> GetCanvas() OVERRIDE {
+ return skia::SharePtr(surface_->getCanvas());
+ }
+ virtual 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);
+ }
+ }
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE {
+ return scoped_ptr<gfx::VSyncProvider>();
+ }
+
+ private:
+ base::FilePath location_;
+ skia::RefPtr<SkSurface> surface_;
+};
+
+} // namespace
+
+TestWindowManager::TestWindowManager(const base::FilePath& dump_location)
+ : location_(dump_location) {
+}
+
+TestWindowManager::~TestWindowManager() {
+}
+
+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) {
+ 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) {
+ 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..8efbb69
--- /dev/null
+++ b/ui/ozone/platform/test/test_window_manager.h
@@ -0,0 +1,51 @@
+// 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 "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);
+ virtual ~TestWindowManager();
+
+ // 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:
+ virtual scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
+ gfx::AcceleratedWidget w) OVERRIDE;
+ virtual bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
+
+ private:
+ base::FilePath location_;
+
+ IDMap<TestWindow> windows_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestWindowManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_TEST_FILE_SURFACE_FACTORY_H_