summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordnicoara@chromium.org <dnicoara@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-12 07:28:12 +0000
committerdnicoara@chromium.org <dnicoara@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-12 07:28:12 +0000
commit9f5881b7eff7046cb060825e4a3189def1370c5b (patch)
tree666c709ca97a910f6a42c57d3854603e372ea36f
parent34fadad9cca3303423ae114c71ca421f889e3259 (diff)
downloadchromium_src-9f5881b7eff7046cb060825e4a3189def1370c5b.zip
chromium_src-9f5881b7eff7046cb060825e4a3189def1370c5b.tar.gz
chromium_src-9f5881b7eff7046cb060825e4a3189def1370c5b.tar.bz2
[Ozone] Adding HardwareDisplayController implementation
BUG= Review URL: https://codereview.chromium.org/26538005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@228329 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ui/gfx/ozone/impl/drm_skbitmap_ozone.h1
-rw-r--r--ui/gfx/ozone/impl/drm_wrapper_ozone.cc86
-rw-r--r--ui/gfx/ozone/impl/drm_wrapper_ozone.h79
-rw-r--r--ui/gfx/ozone/impl/hardware_display_controller_ozone.cc110
-rw-r--r--ui/gfx/ozone/impl/hardware_display_controller_ozone.h170
5 files changed, 446 insertions, 0 deletions
diff --git a/ui/gfx/ozone/impl/drm_skbitmap_ozone.h b/ui/gfx/ozone/impl/drm_skbitmap_ozone.h
index b694747..20af5aa 100644
--- a/ui/gfx/ozone/impl/drm_skbitmap_ozone.h
+++ b/ui/gfx/ozone/impl/drm_skbitmap_ozone.h
@@ -32,6 +32,7 @@ class DrmSkBitmapOzone : public SkBitmap {
private:
friend class DrmAllocator;
+ friend class HardwareDisplayControllerOzone;
void set_handle(uint32_t handle) { handle_ = handle; };
void set_framebuffer(uint32_t framebuffer) { framebuffer_ = framebuffer; };
diff --git a/ui/gfx/ozone/impl/drm_wrapper_ozone.cc b/ui/gfx/ozone/impl/drm_wrapper_ozone.cc
new file mode 100644
index 0000000..8536786
--- /dev/null
+++ b/ui/gfx/ozone/impl/drm_wrapper_ozone.cc
@@ -0,0 +1,86 @@
+// 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/gfx/ozone/impl/drm_wrapper_ozone.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <xf86drmMode.h>
+
+#include "base/logging.h"
+
+namespace gfx {
+
+DrmWrapperOzone::DrmWrapperOzone(const char* device_path) {
+ fd_ = open(device_path, O_RDWR | O_CLOEXEC);
+}
+
+DrmWrapperOzone::~DrmWrapperOzone() {
+ if (fd_ >= 0)
+ close(fd_);
+}
+
+drmModeCrtc* DrmWrapperOzone::GetCrtc(uint32_t crtc_id) {
+ CHECK(fd_ >= 0);
+ return drmModeGetCrtc(fd_, crtc_id);
+}
+
+void DrmWrapperOzone::FreeCrtc(drmModeCrtc* crtc) {
+ drmModeFreeCrtc(crtc);
+}
+
+bool DrmWrapperOzone::SetCrtc(uint32_t crtc_id,
+ uint32_t framebuffer,
+ uint32_t* connectors,
+ drmModeModeInfo* mode) {
+ CHECK(fd_ >= 0);
+ return !drmModeSetCrtc(fd_, crtc_id, framebuffer, 0, 0, connectors, 1, mode);
+}
+
+bool DrmWrapperOzone::SetCrtc(drmModeCrtc* crtc, uint32_t* connectors) {
+ CHECK(fd_ >= 0);
+ return !drmModeSetCrtc(fd_,
+ crtc->crtc_id,
+ crtc->buffer_id,
+ crtc->x,
+ crtc->y,
+ connectors,
+ 1,
+ &crtc->mode);
+}
+
+bool DrmWrapperOzone::AddFramebuffer(const drmModeModeInfo& mode,
+ uint8_t depth,
+ uint8_t bpp,
+ uint32_t stride,
+ uint32_t handle,
+ uint32_t* framebuffer) {
+ CHECK(fd_ >= 0);
+ return !drmModeAddFB(fd_,
+ mode.hdisplay,
+ mode.vdisplay,
+ depth,
+ bpp,
+ stride,
+ handle,
+ framebuffer);
+}
+
+bool DrmWrapperOzone::RemoveFramebuffer(uint32_t framebuffer) {
+ CHECK(fd_ >= 0);
+ return !drmModeRmFB(fd_, framebuffer);
+}
+
+bool DrmWrapperOzone::PageFlip(uint32_t crtc_id,
+ uint32_t framebuffer,
+ void* data) {
+ CHECK(fd_ >= 0);
+ return !drmModePageFlip(fd_,
+ crtc_id,
+ framebuffer,
+ DRM_MODE_PAGE_FLIP_EVENT,
+ data);
+}
+
+} // namespace gfx
diff --git a/ui/gfx/ozone/impl/drm_wrapper_ozone.h b/ui/gfx/ozone/impl/drm_wrapper_ozone.h
new file mode 100644
index 0000000..dbd12bc
--- /dev/null
+++ b/ui/gfx/ozone/impl/drm_wrapper_ozone.h
@@ -0,0 +1,79 @@
+// 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_GFX_OZONE_IMPL_DRM_WRAPPER_OZONE_H_
+#define UI_GFX_OZONE_IMPL_DRM_WRAPPER_OZONE_H_
+
+#include <stdint.h>
+
+#include "base/basictypes.h"
+
+typedef struct _drmModeCrtc drmModeCrtc;
+typedef struct _drmModeModeInfo drmModeModeInfo;
+
+namespace gfx {
+
+// 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 DrmWrapperOzone {
+ public:
+ DrmWrapperOzone(const char* device_path);
+ virtual ~DrmWrapperOzone();
+
+ // 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 drmModeCrtc* GetCrtc(uint32_t crtc_id);
+
+ // Frees the CRTC mode object.
+ virtual void FreeCrtc(drmModeCrtc* crtc);
+
+ // 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,
+ 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, uint32_t* connectors);
+
+ // Register a buffer with the CRTC. On successful registration, the CRTC will
+ // assign a framebuffer ID to |framebuffer|.
+ virtual bool AddFramebuffer(const drmModeModeInfo& mode,
+ 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);
+
+ // 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);
+
+ 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:
+ DISALLOW_COPY_AND_ASSIGN(DrmWrapperOzone);
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_OZONE_IMPL_DRM_WRAPPER_OZONE_H_
diff --git a/ui/gfx/ozone/impl/hardware_display_controller_ozone.cc b/ui/gfx/ozone/impl/hardware_display_controller_ozone.cc
new file mode 100644
index 0000000..c8c6459
--- /dev/null
+++ b/ui/gfx/ozone/impl/hardware_display_controller_ozone.cc
@@ -0,0 +1,110 @@
+// 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/gfx/ozone/impl/hardware_display_controller_ozone.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "ui/gfx/ozone/impl/drm_skbitmap_ozone.h"
+#include "ui/gfx/ozone/impl/drm_wrapper_ozone.h"
+#include "ui/gfx/ozone/impl/software_surface_ozone.h"
+
+namespace gfx {
+
+HardwareDisplayControllerOzone::HardwareDisplayControllerOzone()
+ : drm_(NULL),
+ connector_id_(0),
+ crtc_id_(0),
+ mode_(),
+ saved_crtc_(NULL),
+ state_(UNASSOCIATED),
+ surface_() {
+}
+
+void HardwareDisplayControllerOzone::SetControllerInfo(
+ DrmWrapperOzone* drm,
+ uint32_t connector_id,
+ uint32_t crtc_id,
+ drmModeModeInfo mode) {
+ drm_ = drm;
+ connector_id_ = connector_id;
+ crtc_id_ = crtc_id;
+ mode_ = mode;
+ saved_crtc_ = drm_->GetCrtc(crtc_id_);
+ state_ = UNINITIALIZED;
+}
+
+HardwareDisplayControllerOzone::~HardwareDisplayControllerOzone() {
+ if (saved_crtc_) {
+ if (!drm_->SetCrtc(saved_crtc_, &connector_id_))
+ DLOG(ERROR) << "Failed to restore CRTC state: " << strerror(errno);
+ drm_->FreeCrtc(saved_crtc_);
+ }
+
+ if (surface_.get()) {
+ // Unregister the buffers.
+ for (int i = 0; i < 2; ++i) {
+ if (!drm_->RemoveFramebuffer(surface_->bitmaps_[i]->get_framebuffer()))
+ DLOG(ERROR) << "Failed to remove FB: " << strerror(errno);
+ }
+ }
+}
+
+bool
+HardwareDisplayControllerOzone::BindSurfaceToController(
+ SoftwareSurfaceOzone* surface) {
+ CHECK(state_ == UNINITIALIZED);
+
+ // Register the buffers.
+ for (int i = 0; i < 2; ++i) {
+ uint32_t fb_id;
+ if (!drm_->AddFramebuffer(mode_,
+ surface->bitmaps_[i]->GetColorDepth(),
+ surface->bitmaps_[i]->bytesPerPixel() << 3,
+ surface->bitmaps_[i]->rowBytes(),
+ surface->bitmaps_[i]->get_handle(),
+ &fb_id)) {
+ DLOG(ERROR) << "Failed to register framebuffer: " << strerror(errno);
+ state_ = FAILED;
+ return false;
+ }
+ surface->bitmaps_[i]->set_framebuffer(fb_id);
+ }
+
+ surface_.reset(surface);
+ state_ = SURFACE_INITIALIZED;
+ return true;
+}
+
+bool HardwareDisplayControllerOzone::SchedulePageFlip() {
+ CHECK(state_ == SURFACE_INITIALIZED || state_ == INITIALIZED);
+
+ if (state_ == SURFACE_INITIALIZED) {
+ // Perform the initial modeset.
+ if (!drm_->SetCrtc(crtc_id_,
+ surface_->GetFramebufferId(),
+ &connector_id_,
+ &mode_)) {
+ DLOG(ERROR) << "Cannot set CRTC: " << strerror(errno);
+ state_ = FAILED;
+ return false;
+ } else {
+ state_ = INITIALIZED;
+ }
+ }
+
+ if (!drm_->PageFlip(crtc_id_,
+ surface_->GetFramebufferId(),
+ this)) {
+ state_ = FAILED;
+ LOG(ERROR) << "Cannot page flip: " << strerror(errno);
+ return false;
+ }
+ return true;
+}
+
+} // namespace gfx
diff --git a/ui/gfx/ozone/impl/hardware_display_controller_ozone.h b/ui/gfx/ozone/impl/hardware_display_controller_ozone.h
new file mode 100644
index 0000000..ad0d1f4
--- /dev/null
+++ b/ui/gfx/ozone/impl/hardware_display_controller_ozone.h
@@ -0,0 +1,170 @@
+// 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_GFX_OZONE_IMPL_HARDWARE_DISPLAY_CONTROLLER_OZONE_H_
+#define UI_GFX_OZONE_IMPL_HARDWARE_DISPLAY_CONTROLLER_OZONE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <xf86drmMode.h>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/ozone/impl/drm_wrapper_ozone.h"
+
+namespace gfx {
+
+class SoftwareSurfaceOzone;
+
+// 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.
+//
+// TODO(dnicoara) Need to have a way to detect events (such as monitor
+// connected or disconnected).
+class HardwareDisplayControllerOzone {
+ public:
+ // Controller states. The state transitions will happen from top to bottom.
+ enum State {
+ // When we allocate a HDCO as a stub. At this point there is no connector
+ // and CRTC associated with this device.
+ UNASSOCIATED,
+
+ // When |SetControllerInfo| is called and the HDCO has the information of
+ // the hardware it will control. At this point it knows everything it needs
+ // to control the hardware but doesn't have a surface.
+ UNINITIALIZED,
+
+ // A surface is associated with the HDCO. This means that the controller can
+ // potentially display the backing surface to the display. Though the
+ // surface framebuffer still needs to be registered with the CRTC.
+ SURFACE_INITIALIZED,
+
+ // The CRTC now knows about the surface attributes.
+ INITIALIZED,
+
+ // Error state if any of the initialization steps fail.
+ FAILED,
+ };
+
+ HardwareDisplayControllerOzone();
+
+ ~HardwareDisplayControllerOzone();
+
+ // Set the hardware configuration for this HDCO. Once this is set, the HDCO is
+ // responsible for keeping track of the connector and CRTC and cleaning up
+ // when it is destroyed.
+ void SetControllerInfo(DrmWrapperOzone* drm,
+ uint32_t connector_id,
+ uint32_t crtc_id,
+ drmModeModeInfo mode);
+
+ // Associate the HDCO with a surface implementation and initialize it.
+ bool BindSurfaceToController(SoftwareSurfaceOzone* surface);
+
+ // Schedules the |surface_|'s framebuffer 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 framebuffer 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();
+
+ State get_state() const { return state_; };
+
+ int get_fd() const { return drm_->get_fd(); };
+
+ const drmModeModeInfo& get_mode() const { return mode_; };
+
+ SoftwareSurfaceOzone* get_surface() const { return surface_.get(); };
+
+ private:
+ // Object containing the connection to the graphics device and wraps the API
+ // calls to control it.
+ DrmWrapperOzone* drm_;
+
+ // TODO(dnicoara) Need to allow a CRTC to have multiple connectors.
+ uint32_t connector_id_;
+
+ uint32_t crtc_id_;
+
+ // TODO(dnicoara) Need to store all the modes.
+ drmModeModeInfo mode_;
+
+ // Saved CRTC state from before we used it. Need it to restore state once we
+ // are finished using this device.
+ drmModeCrtc* saved_crtc_;
+
+ State state_;
+
+ scoped_ptr<SoftwareSurfaceOzone> surface_;
+
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayControllerOzone);
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_OZONE_IMPL_HARDWARE_DISPLAY_CONTROLLER_OZONE_H_