OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/ozone/platform/drm/gpu/crtc_controller.h" | 5 #include "ui/ozone/platform/drm/gpu/crtc_controller.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/time/time.h" | 8 #include "base/time/time.h" |
9 #include "ui/ozone/platform/drm/gpu/drm_device.h" | 9 #include "ui/ozone/platform/drm/gpu/drm_device.h" |
10 #include "ui/ozone/platform/drm/gpu/page_flip_observer.h" | 10 #include "ui/ozone/platform/drm/gpu/page_flip_request.h" |
11 #include "ui/ozone/platform/drm/gpu/scanout_buffer.h" | 11 #include "ui/ozone/platform/drm/gpu/scanout_buffer.h" |
12 | 12 |
13 namespace ui { | 13 namespace ui { |
14 | 14 |
15 CrtcController::CrtcController(const scoped_refptr<DrmDevice>& drm, | 15 CrtcController::CrtcController(const scoped_refptr<DrmDevice>& drm, |
16 uint32_t crtc, | 16 uint32_t crtc, |
17 uint32_t connector) | 17 uint32_t connector) |
18 : drm_(drm), | 18 : drm_(drm), |
19 crtc_(crtc), | 19 crtc_(crtc), |
20 connector_(connector), | 20 connector_(connector), |
21 saved_crtc_(drm->GetCrtc(crtc)), | 21 saved_crtc_(drm->GetCrtc(crtc)), |
22 is_disabled_(true), | 22 is_disabled_(true), |
23 page_flip_pending_(false), | |
24 time_of_last_flip_(0) { | 23 time_of_last_flip_(0) { |
25 } | 24 } |
26 | 25 |
27 CrtcController::~CrtcController() { | 26 CrtcController::~CrtcController() { |
28 if (!is_disabled_) { | 27 if (!is_disabled_) { |
29 drm_->SetCrtc(saved_crtc_.get(), std::vector<uint32_t>(1, connector_)); | 28 drm_->SetCrtc(saved_crtc_.get(), std::vector<uint32_t>(1, connector_)); |
30 SetCursor(nullptr); | 29 SetCursor(nullptr); |
| 30 SignalPageFlipRequest(); |
31 } | 31 } |
32 } | 32 } |
33 | 33 |
34 bool CrtcController::Modeset(const OverlayPlane& plane, drmModeModeInfo mode) { | 34 bool CrtcController::Modeset(const OverlayPlane& plane, drmModeModeInfo mode) { |
35 if (!drm_->SetCrtc(crtc_, plane.buffer->GetFramebufferId(), | 35 if (!drm_->SetCrtc(crtc_, plane.buffer->GetFramebufferId(), |
36 std::vector<uint32_t>(1, connector_), &mode)) { | 36 std::vector<uint32_t>(1, connector_), &mode)) { |
37 PLOG(ERROR) << "Failed to modeset: crtc=" << crtc_ | 37 PLOG(ERROR) << "Failed to modeset: crtc=" << crtc_ |
38 << " connector=" << connector_ | 38 << " connector=" << connector_ |
39 << " framebuffer_id=" << plane.buffer->GetFramebufferId() | 39 << " framebuffer_id=" << plane.buffer->GetFramebufferId() |
40 << " mode=" << mode.hdisplay << "x" << mode.vdisplay << "@" | 40 << " mode=" << mode.hdisplay << "x" << mode.vdisplay << "@" |
41 << mode.vrefresh; | 41 << mode.vrefresh; |
42 return false; | 42 return false; |
43 } | 43 } |
44 | 44 |
45 mode_ = mode; | 45 mode_ = mode; |
46 pending_planes_.clear(); | 46 pending_planes_.clear(); |
47 is_disabled_ = false; | 47 is_disabled_ = false; |
48 | 48 |
49 // drmModeSetCrtc has an immediate effect, so we can assume that the current | 49 // drmModeSetCrtc has an immediate effect, so we can assume that the current |
50 // planes have been updated. However if a page flip is still pending, set the | 50 // planes have been updated. However if a page flip is still pending, set the |
51 // pending planes to the same values so that the callback keeps the correct | 51 // pending planes to the same values so that the callback keeps the correct |
52 // state. | 52 // state. |
53 current_planes_ = std::vector<OverlayPlane>(1, plane); | 53 current_planes_ = std::vector<OverlayPlane>(1, plane); |
54 if (page_flip_pending_) | 54 if (page_flip_request_.get()) |
55 pending_planes_ = current_planes_; | 55 pending_planes_ = current_planes_; |
56 | 56 |
57 ResetCursor(); | 57 ResetCursor(); |
58 | 58 |
59 return true; | 59 return true; |
60 } | 60 } |
61 | 61 |
62 bool CrtcController::Disable() { | 62 bool CrtcController::Disable() { |
63 if (is_disabled_) | 63 if (is_disabled_) |
64 return true; | 64 return true; |
65 | 65 |
66 is_disabled_ = true; | 66 is_disabled_ = true; |
67 return drm_->DisableCrtc(crtc_); | 67 return drm_->DisableCrtc(crtc_); |
68 } | 68 } |
69 | 69 |
70 bool CrtcController::SchedulePageFlip(HardwareDisplayPlaneList* plane_list, | 70 bool CrtcController::SchedulePageFlip( |
71 const OverlayPlaneList& overlays) { | 71 HardwareDisplayPlaneList* plane_list, |
72 DCHECK(!page_flip_pending_); | 72 const OverlayPlaneList& overlays, |
| 73 scoped_refptr<PageFlipRequest> page_flip_request) { |
| 74 DCHECK(!page_flip_request_.get()); |
73 DCHECK(!is_disabled_); | 75 DCHECK(!is_disabled_); |
74 const OverlayPlane* primary = OverlayPlane::GetPrimaryPlane(overlays); | 76 const OverlayPlane* primary = OverlayPlane::GetPrimaryPlane(overlays); |
75 if (!primary) { | 77 if (!primary) { |
76 LOG(ERROR) << "No primary plane to display on crtc " << crtc_; | 78 LOG(ERROR) << "No primary plane to display on crtc " << crtc_; |
77 FOR_EACH_OBSERVER(PageFlipObserver, observers_, OnPageFlipEvent()); | 79 page_flip_request->Signal(); |
78 return true; | 80 return true; |
79 } | 81 } |
80 DCHECK(primary->buffer.get()); | 82 DCHECK(primary->buffer.get()); |
81 | 83 |
82 if (primary->buffer->GetSize() != gfx::Size(mode_.hdisplay, mode_.vdisplay)) { | 84 if (primary->buffer->GetSize() != gfx::Size(mode_.hdisplay, mode_.vdisplay)) { |
83 VLOG(2) << "Trying to pageflip a buffer with the wrong size. Expected " | 85 VLOG(2) << "Trying to pageflip a buffer with the wrong size. Expected " |
84 << mode_.hdisplay << "x" << mode_.vdisplay << " got " | 86 << mode_.hdisplay << "x" << mode_.vdisplay << " got " |
85 << primary->buffer->GetSize().ToString() << " for" | 87 << primary->buffer->GetSize().ToString() << " for" |
86 << " crtc=" << crtc_ << " connector=" << connector_; | 88 << " crtc=" << crtc_ << " connector=" << connector_; |
87 FOR_EACH_OBSERVER(PageFlipObserver, observers_, OnPageFlipEvent()); | 89 page_flip_request->Signal(); |
88 return true; | 90 return true; |
89 } | 91 } |
90 | 92 |
91 if (!drm_->plane_manager()->AssignOverlayPlanes(plane_list, overlays, crtc_, | 93 if (!drm_->plane_manager()->AssignOverlayPlanes(plane_list, overlays, crtc_, |
92 this)) { | 94 this)) { |
93 PLOG(ERROR) << "Failed to assign overlay planes for crtc " << crtc_; | 95 PLOG(ERROR) << "Failed to assign overlay planes for crtc " << crtc_; |
| 96 page_flip_request->Signal(); |
94 return false; | 97 return false; |
95 } | 98 } |
96 | 99 |
97 page_flip_pending_ = true; | |
98 pending_planes_ = overlays; | 100 pending_planes_ = overlays; |
| 101 page_flip_request_ = page_flip_request; |
99 | 102 |
100 return true; | 103 return true; |
101 } | 104 } |
102 | 105 |
103 void CrtcController::PageFlipFailed() { | 106 void CrtcController::PageFlipFailed() { |
104 pending_planes_.clear(); | 107 pending_planes_.clear(); |
105 page_flip_pending_ = false; | 108 SignalPageFlipRequest(); |
106 } | 109 } |
107 | 110 |
108 void CrtcController::OnPageFlipEvent(unsigned int frame, | 111 void CrtcController::OnPageFlipEvent(unsigned int frame, |
109 unsigned int seconds, | 112 unsigned int seconds, |
110 unsigned int useconds) { | 113 unsigned int useconds) { |
111 page_flip_pending_ = false; | |
112 time_of_last_flip_ = | 114 time_of_last_flip_ = |
113 static_cast<uint64_t>(seconds) * base::Time::kMicrosecondsPerSecond + | 115 static_cast<uint64_t>(seconds) * base::Time::kMicrosecondsPerSecond + |
114 useconds; | 116 useconds; |
115 | 117 |
116 current_planes_.clear(); | 118 current_planes_.clear(); |
117 current_planes_.swap(pending_planes_); | 119 current_planes_.swap(pending_planes_); |
118 | 120 |
119 FOR_EACH_OBSERVER(PageFlipObserver, observers_, OnPageFlipEvent()); | 121 SignalPageFlipRequest(); |
120 } | 122 } |
121 | 123 |
122 bool CrtcController::SetCursor(const scoped_refptr<ScanoutBuffer>& buffer) { | 124 bool CrtcController::SetCursor(const scoped_refptr<ScanoutBuffer>& buffer) { |
123 DCHECK(!is_disabled_ || !buffer); | 125 DCHECK(!is_disabled_ || !buffer); |
124 cursor_buffer_ = buffer; | 126 cursor_buffer_ = buffer; |
125 | 127 |
126 return ResetCursor(); | 128 return ResetCursor(); |
127 } | 129 } |
128 | 130 |
129 bool CrtcController::MoveCursor(const gfx::Point& location) { | 131 bool CrtcController::MoveCursor(const gfx::Point& location) { |
130 DCHECK(!is_disabled_); | 132 DCHECK(!is_disabled_); |
131 return drm_->MoveCursor(crtc_, location); | 133 return drm_->MoveCursor(crtc_, location); |
132 } | 134 } |
133 | 135 |
134 void CrtcController::AddObserver(PageFlipObserver* observer) { | |
135 observers_.AddObserver(observer); | |
136 } | |
137 | |
138 void CrtcController::RemoveObserver(PageFlipObserver* observer) { | |
139 observers_.RemoveObserver(observer); | |
140 } | |
141 | |
142 bool CrtcController::ResetCursor() { | 136 bool CrtcController::ResetCursor() { |
143 uint32_t handle = 0; | 137 uint32_t handle = 0; |
144 gfx::Size size; | 138 gfx::Size size; |
145 | 139 |
146 if (cursor_buffer_) { | 140 if (cursor_buffer_) { |
147 handle = cursor_buffer_->GetHandle(); | 141 handle = cursor_buffer_->GetHandle(); |
148 size = cursor_buffer_->GetSize(); | 142 size = cursor_buffer_->GetSize(); |
149 } | 143 } |
150 | 144 |
151 bool status = drm_->SetCursor(crtc_, handle, size); | 145 bool status = drm_->SetCursor(crtc_, handle, size); |
152 if (!status) { | 146 if (!status) { |
153 PLOG(ERROR) << "drmModeSetCursor: device " << drm_->device_path().value() | 147 PLOG(ERROR) << "drmModeSetCursor: device " << drm_->device_path().value() |
154 << " crtc " << crtc_ << " handle " << handle << " size " | 148 << " crtc " << crtc_ << " handle " << handle << " size " |
155 << size.ToString(); | 149 << size.ToString(); |
156 } | 150 } |
157 | 151 |
158 return status; | 152 return status; |
159 } | 153 } |
160 | 154 |
| 155 void CrtcController::SignalPageFlipRequest() { |
| 156 if (page_flip_request_.get()) { |
| 157 // If another frame is queued up and available immediately, calling Signal() |
| 158 // may result in a call to SchedulePageFlip(), which will override |
| 159 // page_flip_request_ and possibly release the ref. Stash previous request |
| 160 // locally to avoid deleting the object we are making a call on. |
| 161 scoped_refptr<PageFlipRequest> last_request; |
| 162 last_request.swap(page_flip_request_); |
| 163 last_request->Signal(); |
| 164 } |
| 165 } |
| 166 |
161 } // namespace ui | 167 } // namespace ui |
OLD | NEW |