blob: a7220feeddaad247734cfb505fbebd4b58e939dc [file] [log] [blame]
Alex Vakulenkoa8a92782017-01-27 14:41:57 -08001#include "display_surface.h"
2
3#include <utils/Trace.h>
4
5#include <private/dvr/platform_defines.h>
6
7#include "display_service.h"
8#include "hardware_composer.h"
9
10#define LOCAL_TRACE 1
11
12using android::pdx::BorrowedChannelHandle;
13using android::pdx::LocalChannelHandle;
14using android::pdx::Message;
15using android::pdx::RemoteChannelHandle;
16using android::pdx::Status;
17using android::pdx::rpc::DispatchRemoteMethod;
18using android::pdx::rpc::IfAnyOf;
19
20namespace android {
21namespace dvr {
22
23DisplaySurface::DisplaySurface(DisplayService* service, int surface_id,
24 int process_id, int width, int height,
25 int format, int usage, int flags)
26 : SurfaceChannel(service, surface_id, SurfaceTypeEnum::Normal,
27 sizeof(DisplaySurfaceMetadata)),
28 process_id_(process_id),
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -080029 acquired_buffers_(kMaxPostedBuffers),
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080030 video_mesh_surfaces_updated_(false),
31 width_(width),
32 height_(height),
33 format_(format),
34 usage_(usage),
35 flags_(flags),
36 client_visible_(false),
37 client_z_order_(0),
38 client_exclude_from_blur_(false),
39 client_blur_behind_(false),
40 manager_visible_(false),
41 manager_z_order_(0),
42 manager_blur_(0.0f),
Jiwen 'Steve' Cai14553422017-03-21 15:43:31 -070043 layer_order_(0),
44 allocated_buffer_index_(0) {}
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080045
46DisplaySurface::~DisplaySurface() {
47 ALOGD_IF(LOCAL_TRACE,
48 "DisplaySurface::~DisplaySurface: surface_id=%d process_id=%d",
49 surface_id(), process_id_);
50}
51
52void DisplaySurface::ManagerSetVisible(bool visible) {
53 std::lock_guard<std::mutex> autolock(lock_);
54 manager_visible_ = visible;
55}
56
57void DisplaySurface::ManagerSetZOrder(int z_order) {
58 std::lock_guard<std::mutex> autolock(lock_);
59 manager_z_order_ = z_order;
60}
61
62void DisplaySurface::ManagerSetBlur(float blur) {
63 std::lock_guard<std::mutex> autolock(lock_);
64 manager_blur_ = blur;
65}
66
67void DisplaySurface::ClientSetVisible(bool visible) {
68 std::lock_guard<std::mutex> autolock(lock_);
69 client_visible_ = visible;
70}
71
72void DisplaySurface::ClientSetZOrder(int z_order) {
73 std::lock_guard<std::mutex> autolock(lock_);
74 client_z_order_ = z_order;
75}
76
77void DisplaySurface::ClientSetExcludeFromBlur(bool exclude_from_blur) {
78 std::lock_guard<std::mutex> autolock(lock_);
79 client_exclude_from_blur_ = exclude_from_blur;
80}
81
82void DisplaySurface::ClientSetBlurBehind(bool blur_behind) {
83 std::lock_guard<std::mutex> autolock(lock_);
84 client_blur_behind_ = blur_behind;
85}
86
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -080087void DisplaySurface::DequeueBuffersLocked() {
88 if (consumer_queue_ == nullptr) {
89 ALOGE(
90 "DisplaySurface::DequeueBuffersLocked: Consumer queue is not "
91 "initialized.");
92 return;
93 }
94
95 size_t slot;
96 uint64_t sequence;
97 while (true) {
98 LocalHandle acquire_fence;
99 auto buffer_consumer =
100 consumer_queue_->Dequeue(0, &slot, &sequence, &acquire_fence);
101 if (!buffer_consumer) {
102 ALOGD_IF(TRACE,
103 "DisplaySurface::DequeueBuffersLocked: We have dequeued all "
104 "available buffers.");
105 return;
106 }
107
Jiwen 'Steve' Cai14553422017-03-21 15:43:31 -0700108 // Save buffer index, associated with the buffer id so that it can be looked
109 // up later.
110 int buffer_id = buffer_consumer->id();
111 if (buffer_id_to_index_.find(buffer_id) == buffer_id_to_index_.end()) {
112 buffer_id_to_index_[buffer_id] = allocated_buffer_index_;
113 ++allocated_buffer_index_;
114 }
115
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800116 if (!IsVisible()) {
117 ATRACE_NAME("DropFrameOnInvisibleSurface");
118 ALOGD_IF(TRACE,
119 "DisplaySurface::DequeueBuffersLocked: Discarding buffer_id=%d "
120 "on invisible surface.",
121 buffer_consumer->id());
122 buffer_consumer->Discard();
123 continue;
124 }
125
126 if (acquired_buffers_.IsFull()) {
127 ALOGE(
128 "DisplaySurface::DequeueBuffersLocked: Posted buffers full, "
129 "overwriting.");
130 acquired_buffers_.PopBack();
131 }
132
133 acquired_buffers_.Append(
134 AcquiredBuffer(buffer_consumer, std::move(acquire_fence), sequence));
135 }
136}
137
138AcquiredBuffer DisplaySurface::AcquireCurrentBuffer() {
139 std::lock_guard<std::mutex> autolock(lock_);
140 DequeueBuffersLocked();
141
142 if (acquired_buffers_.IsEmpty()) {
143 ALOGE(
144 "DisplaySurface::AcquireCurrentBuffer: attempt to acquire buffer when "
145 "none are posted.");
146 return AcquiredBuffer();
147 }
148 AcquiredBuffer buffer = std::move(acquired_buffers_.Front());
149 acquired_buffers_.PopFront();
150 ALOGD_IF(TRACE, "DisplaySurface::AcquireCurrentBuffer: buffer: %p",
151 buffer.buffer().get());
152 return buffer;
153}
154
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800155AcquiredBuffer DisplaySurface::AcquireNewestAvailableBuffer(
156 AcquiredBuffer* skipped_buffer) {
157 std::lock_guard<std::mutex> autolock(lock_);
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800158 DequeueBuffersLocked();
159
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800160 AcquiredBuffer buffer;
161 int frames = 0;
162 // Basic latency stopgap for when the application misses a frame:
163 // If the application recovers on the 2nd or 3rd (etc) frame after
164 // missing, this code will skip frames to catch up by checking if
165 // the next frame is also available.
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800166 while (!acquired_buffers_.IsEmpty() &&
167 acquired_buffers_.Front().IsAvailable()) {
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800168 // Capture the skipped buffer into the result parameter.
169 // Note that this API only supports skipping one buffer per vsync.
170 if (frames > 0 && skipped_buffer)
171 *skipped_buffer = std::move(buffer);
172 ++frames;
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800173 buffer = std::move(acquired_buffers_.Front());
174 acquired_buffers_.PopFront();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800175 if (frames == 2)
176 break;
177 }
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800178 ALOGD_IF(TRACE, "DisplaySurface::AcquireNewestAvailableBuffer: buffer: %p",
179 buffer.buffer().get());
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800180 return buffer;
181}
182
Jiwen 'Steve' Cai14553422017-03-21 15:43:31 -0700183uint32_t DisplaySurface::GetRenderBufferIndex(int buffer_id) {
184 std::lock_guard<std::mutex> autolock(lock_);
185
186 if (buffer_id_to_index_.find(buffer_id) == buffer_id_to_index_.end()) {
187 ALOGW("DisplaySurface::GetRenderBufferIndex: unknown buffer_id %d.",
188 buffer_id);
189 return 0;
190 }
191 return buffer_id_to_index_[buffer_id];
192}
193
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800194bool DisplaySurface::IsBufferAvailable() {
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800195 std::lock_guard<std::mutex> autolock(lock_);
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800196 DequeueBuffersLocked();
197
198 return !acquired_buffers_.IsEmpty() &&
199 acquired_buffers_.Front().IsAvailable();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800200}
201
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800202bool DisplaySurface::IsBufferPosted() {
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800203 std::lock_guard<std::mutex> autolock(lock_);
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800204 DequeueBuffersLocked();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800205
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800206 return !acquired_buffers_.IsEmpty();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800207}
208
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700209pdx::Status<void> DisplaySurface::HandleMessage(pdx::Message& message) {
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800210 switch (message.GetOp()) {
211 case DisplayRPC::SetAttributes::Opcode:
212 DispatchRemoteMethod<DisplayRPC::SetAttributes>(
213 *this, &DisplaySurface::OnClientSetAttributes, message);
214 break;
215
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800216 case DisplayRPC::CreateBufferQueue::Opcode:
217 DispatchRemoteMethod<DisplayRPC::CreateBufferQueue>(
218 *this, &DisplaySurface::OnCreateBufferQueue, message);
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800219 break;
220
221 case DisplayRPC::CreateVideoMeshSurface::Opcode:
222 DispatchRemoteMethod<DisplayRPC::CreateVideoMeshSurface>(
223 *this, &DisplaySurface::OnCreateVideoMeshSurface, message);
224 break;
225
226 default:
227 return SurfaceChannel::HandleMessage(message);
228 }
229
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700230 return {};
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800231}
232
233int DisplaySurface::OnClientSetAttributes(
234 pdx::Message& /*message*/, const DisplaySurfaceAttributes& attributes) {
235 for (const auto& attribute : attributes) {
236 const auto& key = attribute.first;
237 const auto* variant = &attribute.second;
238 bool invalid_value = false;
239 switch (key) {
240 case DisplaySurfaceAttributeEnum::ZOrder:
241 invalid_value = !IfAnyOf<int32_t, int64_t, float>::Call(
242 variant, [this](const auto& value) {
243 DisplaySurface::ClientSetZOrder(value);
244 });
245 break;
246 case DisplaySurfaceAttributeEnum::Visible:
247 invalid_value = !IfAnyOf<int32_t, int64_t, bool>::Call(
248 variant, [this](const auto& value) {
249 DisplaySurface::ClientSetVisible(value);
250 });
251 break;
252 case DisplaySurfaceAttributeEnum::ExcludeFromBlur:
253 invalid_value = !IfAnyOf<int32_t, int64_t, bool>::Call(
254 variant, [this](const auto& value) {
255 DisplaySurface::ClientSetExcludeFromBlur(value);
256 });
257 break;
258 case DisplaySurfaceAttributeEnum::BlurBehind:
259 invalid_value = !IfAnyOf<int32_t, int64_t, bool>::Call(
260 variant, [this](const auto& value) {
261 DisplaySurface::ClientSetBlurBehind(value);
262 });
263 break;
264 default:
265 ALOGW(
266 "DisplaySurface::OnClientSetAttributes: Unrecognized attribute %d "
267 "surface_id=%d",
268 key, surface_id());
269 break;
270 }
271
272 if (invalid_value) {
273 ALOGW(
274 "DisplaySurface::OnClientSetAttributes: Failed to set display "
275 "surface attribute '%s' because of incompatible type: %d",
276 DisplaySurfaceAttributeEnum::ToString(key).c_str(), variant->index());
277 }
278 }
279
280 service()->NotifyDisplayConfigurationUpdate();
281 return 0;
282}
283
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800284LocalChannelHandle DisplaySurface::OnCreateBufferQueue(Message& message) {
285 ATRACE_NAME("DisplaySurface::OnCreateBufferQueue");
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800286
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800287 if (consumer_queue_ != nullptr) {
288 ALOGE(
289 "DisplaySurface::OnCreateBufferQueue: A ProdcuerQueue has already been "
290 "created and transported to DisplayClient.");
291 REPLY_ERROR_RETURN(message, EALREADY, {});
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800292 }
293
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800294 auto producer = ProducerQueue::Create<uint64_t>();
295 consumer_queue_ = producer->CreateConsumerQueue();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800296
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800297 return std::move(producer->GetChannelHandle());
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800298}
299
300RemoteChannelHandle DisplaySurface::OnCreateVideoMeshSurface(
301 pdx::Message& message) {
302 if (flags_ & DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION) {
303 ALOGE(
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700304 "DisplaySurface::OnCreateVideoMeshSurface: system distortion is "
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800305 "disabled on this display surface, cannot create VideoMeshSurface on "
306 "top of it.");
307 REPLY_ERROR_RETURN(message, EINVAL, {});
308 }
309
310 int channel_id;
311 auto status = message.PushChannel(0, nullptr, &channel_id);
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800312 if (!status) {
313 ALOGE(
314 "DisplaySurface::OnCreateVideoMeshSurface: failed to push channel: %s",
315 status.GetErrorMessage().c_str());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700316 REPLY_ERROR_RETURN(message, status.error(), {});
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800317 }
318
319 auto surface = std::make_shared<VideoMeshSurface>(service(), channel_id);
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700320 auto channel_status = service()->SetChannel(channel_id, surface);
321 if (!channel_status) {
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800322 ALOGE(
323 "DisplaySurface::OnCreateVideoMeshSurface: failed to set new video "
324 "mesh surface channel: %s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700325 channel_status.GetErrorMessage().c_str());
326 REPLY_ERROR_RETURN(message, channel_status.error(), {});
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800327 }
328
329 {
330 std::lock_guard<std::mutex> autolock(lock_);
331 pending_video_mesh_surfaces_.push_back(surface);
332 video_mesh_surfaces_updated_ = true;
333 }
334
335 return status.take();
336}
337
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800338std::vector<std::shared_ptr<VideoMeshSurface>>
339DisplaySurface::GetVideoMeshSurfaces() {
340 std::lock_guard<std::mutex> autolock(lock_);
341 std::vector<std::shared_ptr<VideoMeshSurface>> surfaces;
342
343 for (auto& surface : pending_video_mesh_surfaces_) {
344 if (auto video_surface = surface.lock()) {
345 surfaces.push_back(video_surface);
346 } else {
347 ALOGE("Unable to lock video mesh surface.");
348 }
349 }
350
351 pending_video_mesh_surfaces_.clear();
352 video_mesh_surfaces_updated_ = false;
353 return surfaces;
354}
355
356} // namespace dvr
357} // namespace android