| Index: ui/ozone/platform/drm/gpu/crtc_controller.cc
|
| diff --git a/ui/ozone/platform/drm/gpu/crtc_controller.cc b/ui/ozone/platform/drm/gpu/crtc_controller.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..34390a252636b403522a3df5bb1d99c1f429cac9
|
| --- /dev/null
|
| +++ b/ui/ozone/platform/drm/gpu/crtc_controller.cc
|
| @@ -0,0 +1,167 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/time/time.h"
|
| +#include "ui/ozone/platform/drm/gpu/drm_device.h"
|
| +#include "ui/ozone/platform/drm/gpu/page_flip_request.h"
|
| +#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
|
| +
|
| +namespace ui {
|
| +
|
| +CrtcController::CrtcController(const scoped_refptr<DrmDevice>& drm,
|
| + uint32_t crtc,
|
| + uint32_t connector)
|
| + : drm_(drm), crtc_(crtc), connector_(connector) {
|
| +}
|
| +
|
| +CrtcController::~CrtcController() {
|
| + if (!is_disabled_) {
|
| + SetCursor(nullptr);
|
| + drm_->DisableCrtc(crtc_);
|
| + SignalPageFlipRequest();
|
| + }
|
| +}
|
| +
|
| +bool CrtcController::Modeset(const OverlayPlane& plane, drmModeModeInfo mode) {
|
| + if (!drm_->SetCrtc(crtc_, plane.buffer->GetFramebufferId(),
|
| + std::vector<uint32_t>(1, connector_), &mode)) {
|
| + PLOG(ERROR) << "Failed to modeset: crtc=" << crtc_
|
| + << " connector=" << connector_
|
| + << " framebuffer_id=" << plane.buffer->GetFramebufferId()
|
| + << " mode=" << mode.hdisplay << "x" << mode.vdisplay << "@"
|
| + << mode.vrefresh;
|
| + return false;
|
| + }
|
| +
|
| + mode_ = mode;
|
| + pending_planes_.clear();
|
| + is_disabled_ = false;
|
| +
|
| + // drmModeSetCrtc has an immediate effect, so we can assume that the current
|
| + // planes have been updated. However if a page flip is still pending, set the
|
| + // pending planes to the same values so that the callback keeps the correct
|
| + // state.
|
| + current_planes_ = std::vector<OverlayPlane>(1, plane);
|
| + if (page_flip_request_.get())
|
| + pending_planes_ = current_planes_;
|
| +
|
| + ResetCursor();
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool CrtcController::Disable() {
|
| + if (is_disabled_)
|
| + return true;
|
| +
|
| + is_disabled_ = true;
|
| + return drm_->DisableCrtc(crtc_);
|
| +}
|
| +
|
| +bool CrtcController::SchedulePageFlip(
|
| + HardwareDisplayPlaneList* plane_list,
|
| + const OverlayPlaneList& overlays,
|
| + bool test_only,
|
| + scoped_refptr<PageFlipRequest> page_flip_request) {
|
| + DCHECK(!page_flip_request_.get() || test_only);
|
| + DCHECK(!is_disabled_);
|
| + const OverlayPlane* primary = OverlayPlane::GetPrimaryPlane(overlays);
|
| + if (!primary) {
|
| + LOG(ERROR) << "No primary plane to display on crtc " << crtc_;
|
| + page_flip_request->Signal(gfx::SwapResult::SWAP_ACK);
|
| + return true;
|
| + }
|
| + DCHECK(primary->buffer.get());
|
| +
|
| + if (primary->buffer->GetSize() != gfx::Size(mode_.hdisplay, mode_.vdisplay)) {
|
| + VLOG(2) << "Trying to pageflip a buffer with the wrong size. Expected "
|
| + << mode_.hdisplay << "x" << mode_.vdisplay << " got "
|
| + << primary->buffer->GetSize().ToString() << " for"
|
| + << " crtc=" << crtc_ << " connector=" << connector_;
|
| + page_flip_request->Signal(gfx::SwapResult::SWAP_ACK);
|
| + return true;
|
| + }
|
| +
|
| + if (!drm_->plane_manager()->AssignOverlayPlanes(plane_list, overlays, crtc_,
|
| + this)) {
|
| + PLOG(ERROR) << "Failed to assign overlay planes for crtc " << crtc_;
|
| + page_flip_request->Signal(gfx::SwapResult::SWAP_FAILED);
|
| + return false;
|
| + }
|
| +
|
| + if (test_only) {
|
| + page_flip_request->Signal(gfx::SwapResult::SWAP_ACK);
|
| + } else {
|
| + pending_planes_ = overlays;
|
| + page_flip_request_ = page_flip_request;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void CrtcController::PageFlipFailed() {
|
| + pending_planes_.clear();
|
| + SignalPageFlipRequest();
|
| +}
|
| +
|
| +void CrtcController::OnPageFlipEvent(unsigned int frame,
|
| + unsigned int seconds,
|
| + unsigned int useconds) {
|
| + time_of_last_flip_ =
|
| + static_cast<uint64_t>(seconds) * base::Time::kMicrosecondsPerSecond +
|
| + useconds;
|
| +
|
| + current_planes_.clear();
|
| + current_planes_.swap(pending_planes_);
|
| +
|
| + SignalPageFlipRequest();
|
| +}
|
| +
|
| +bool CrtcController::SetCursor(const scoped_refptr<ScanoutBuffer>& buffer) {
|
| + DCHECK(!is_disabled_ || !buffer);
|
| + cursor_buffer_ = buffer;
|
| +
|
| + return ResetCursor();
|
| +}
|
| +
|
| +bool CrtcController::MoveCursor(const gfx::Point& location) {
|
| + DCHECK(!is_disabled_);
|
| + return drm_->MoveCursor(crtc_, location);
|
| +}
|
| +
|
| +bool CrtcController::ResetCursor() {
|
| + uint32_t handle = 0;
|
| + gfx::Size size;
|
| +
|
| + if (cursor_buffer_) {
|
| + handle = cursor_buffer_->GetHandle();
|
| + size = cursor_buffer_->GetSize();
|
| + }
|
| +
|
| + bool status = drm_->SetCursor(crtc_, handle, size);
|
| + if (!status) {
|
| + PLOG(ERROR) << "drmModeSetCursor: device " << drm_->device_path().value()
|
| + << " crtc " << crtc_ << " handle " << handle << " size "
|
| + << size.ToString();
|
| + }
|
| +
|
| + return status;
|
| +}
|
| +
|
| +void CrtcController::SignalPageFlipRequest() {
|
| + if (page_flip_request_.get()) {
|
| + // If another frame is queued up and available immediately, calling Signal()
|
| + // may result in a call to SchedulePageFlip(), which will override
|
| + // page_flip_request_ and possibly release the ref. Stash previous request
|
| + // locally to avoid deleting the object we are making a call on.
|
| + scoped_refptr<PageFlipRequest> last_request;
|
| + last_request.swap(page_flip_request_);
|
| + last_request->Signal(gfx::SwapResult::SWAP_ACK);
|
| + }
|
| +}
|
| +
|
| +} // namespace ui
|
|
|