blob: d427ea6b10d4d4583c2e94344211c9c1b3a52391 [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),
29 posted_buffers_(kMaxPostedBuffers),
30 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),
43 allocated_buffer_index_(0),
44 layer_order_(0) {}
45
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
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080087AcquiredBuffer DisplaySurface::AcquireNewestAvailableBuffer(
88 AcquiredBuffer* skipped_buffer) {
89 std::lock_guard<std::mutex> autolock(lock_);
90 AcquiredBuffer buffer;
91 int frames = 0;
92 // Basic latency stopgap for when the application misses a frame:
93 // If the application recovers on the 2nd or 3rd (etc) frame after
94 // missing, this code will skip frames to catch up by checking if
95 // the next frame is also available.
96 while (!posted_buffers_.IsEmpty() && posted_buffers_.Front().IsAvailable()) {
97 // Capture the skipped buffer into the result parameter.
98 // Note that this API only supports skipping one buffer per vsync.
99 if (frames > 0 && skipped_buffer)
100 *skipped_buffer = std::move(buffer);
101 ++frames;
102 buffer = std::move(posted_buffers_.Front());
103 posted_buffers_.PopFront();
104 if (frames == 2)
105 break;
106 }
107 return buffer;
108}
109
110bool DisplaySurface::IsBufferAvailable() const {
111 std::lock_guard<std::mutex> autolock(lock_);
112 return !posted_buffers_.IsEmpty() && posted_buffers_.Front().IsAvailable();
113}
114
115bool DisplaySurface::IsBufferPosted() const {
116 std::lock_guard<std::mutex> autolock(lock_);
117 return !posted_buffers_.IsEmpty();
118}
119
120AcquiredBuffer DisplaySurface::AcquireCurrentBuffer() {
121 std::lock_guard<std::mutex> autolock(lock_);
122 if (posted_buffers_.IsEmpty()) {
123 ALOGE("Error: attempt to acquire buffer when none are posted.");
124 return AcquiredBuffer();
125 }
126 AcquiredBuffer buffer = std::move(posted_buffers_.Front());
127 posted_buffers_.PopFront();
128 return buffer;
129}
130
131int DisplaySurface::GetConsumers(std::vector<LocalChannelHandle>* consumers) {
132 std::lock_guard<std::mutex> autolock(lock_);
133 std::vector<LocalChannelHandle> items;
134
135 for (auto pair : buffers_) {
136 const auto& buffer = pair.second;
137
138 Status<LocalChannelHandle> consumer_channel = buffer->CreateConsumer();
139 if (!consumer_channel) {
140 ALOGE(
141 "DisplaySurface::GetConsumers: Failed to get a new consumer for "
142 "buffer %d: %s",
143 buffer->id(), consumer_channel.GetErrorMessage().c_str());
144 return -consumer_channel.error();
145 }
146
147 items.push_back(consumer_channel.take());
148 }
149
150 *consumers = std::move(items);
151 return 0;
152}
153
154int DisplaySurface::HandleMessage(pdx::Message& message) {
155 switch (message.GetOp()) {
156 case DisplayRPC::SetAttributes::Opcode:
157 DispatchRemoteMethod<DisplayRPC::SetAttributes>(
158 *this, &DisplaySurface::OnClientSetAttributes, message);
159 break;
160
161 case DisplayRPC::AllocateBuffer::Opcode:
162 DispatchRemoteMethod<DisplayRPC::AllocateBuffer>(
163 *this, &DisplaySurface::OnAllocateBuffer, message);
164 break;
165
166 case DisplayRPC::CreateVideoMeshSurface::Opcode:
167 DispatchRemoteMethod<DisplayRPC::CreateVideoMeshSurface>(
168 *this, &DisplaySurface::OnCreateVideoMeshSurface, message);
169 break;
170
171 default:
172 return SurfaceChannel::HandleMessage(message);
173 }
174
175 return 0;
176}
177
178int DisplaySurface::OnClientSetAttributes(
179 pdx::Message& /*message*/, const DisplaySurfaceAttributes& attributes) {
180 for (const auto& attribute : attributes) {
181 const auto& key = attribute.first;
182 const auto* variant = &attribute.second;
183 bool invalid_value = false;
184 switch (key) {
185 case DisplaySurfaceAttributeEnum::ZOrder:
186 invalid_value = !IfAnyOf<int32_t, int64_t, float>::Call(
187 variant, [this](const auto& value) {
188 DisplaySurface::ClientSetZOrder(value);
189 });
190 break;
191 case DisplaySurfaceAttributeEnum::Visible:
192 invalid_value = !IfAnyOf<int32_t, int64_t, bool>::Call(
193 variant, [this](const auto& value) {
194 DisplaySurface::ClientSetVisible(value);
195 });
196 break;
197 case DisplaySurfaceAttributeEnum::ExcludeFromBlur:
198 invalid_value = !IfAnyOf<int32_t, int64_t, bool>::Call(
199 variant, [this](const auto& value) {
200 DisplaySurface::ClientSetExcludeFromBlur(value);
201 });
202 break;
203 case DisplaySurfaceAttributeEnum::BlurBehind:
204 invalid_value = !IfAnyOf<int32_t, int64_t, bool>::Call(
205 variant, [this](const auto& value) {
206 DisplaySurface::ClientSetBlurBehind(value);
207 });
208 break;
209 default:
210 ALOGW(
211 "DisplaySurface::OnClientSetAttributes: Unrecognized attribute %d "
212 "surface_id=%d",
213 key, surface_id());
214 break;
215 }
216
217 if (invalid_value) {
218 ALOGW(
219 "DisplaySurface::OnClientSetAttributes: Failed to set display "
220 "surface attribute '%s' because of incompatible type: %d",
221 DisplaySurfaceAttributeEnum::ToString(key).c_str(), variant->index());
222 }
223 }
224
225 service()->NotifyDisplayConfigurationUpdate();
226 return 0;
227}
228
229// Allocates a new buffer for the DisplaySurface associated with this channel.
230std::pair<uint32_t, LocalChannelHandle> DisplaySurface::OnAllocateBuffer(
231 pdx::Message& message) {
232 // Inject flag to enable framebuffer compression for the application buffers.
233 // TODO(eieio,jbates): Make this configurable per hardware platform.
234 const int usage = usage_ | GRALLOC_USAGE_QCOM_FRAMEBUFFER_COMPRESSION;
235 const int slice_count =
236 (flags_ & static_cast<int>(DisplaySurfaceFlagsEnum::SeparateGeometry))
237 ? 2
238 : 1;
239
240 ALOGI_IF(
241 TRACE,
242 "DisplaySurface::OnAllocateBuffer: width=%d height=%d format=%x usage=%x "
243 "slice_count=%d",
244 width_, height_, format_, usage, slice_count);
245
246 // Create a producer buffer to hand back to the sender.
247 auto producer = BufferProducer::Create(width_, height_, format_, usage,
248 sizeof(uint64_t), slice_count);
249 if (!producer)
250 REPLY_ERROR_RETURN(message, EINVAL, {});
251
252 // Create and import a consumer attached to the producer.
253 Status<LocalChannelHandle> consumer_channel = producer->CreateConsumer();
254 if (!consumer_channel)
255 REPLY_ERROR_RETURN(message, consumer_channel.error(), {});
256
257 std::shared_ptr<BufferConsumer> consumer =
258 BufferConsumer::Import(consumer_channel.take());
259 if (!consumer)
260 REPLY_ERROR_RETURN(message, ENOMEM, {});
261
262 // Add the consumer to this surface.
263 int err = AddConsumer(consumer);
264 if (err < 0) {
265 ALOGE("DisplaySurface::OnAllocateBuffer: failed to add consumer: buffer=%d",
266 consumer->id());
267 REPLY_ERROR_RETURN(message, -err, {});
268 }
269
270 // Move the channel handle so that it doesn't get closed when the producer
271 // goes out of scope.
272 std::pair<uint32_t, LocalChannelHandle> return_value(
273 allocated_buffer_index_, std::move(producer->GetChannelHandle()));
274
275 // Save buffer index, associated with the buffer id so that it can be looked
276 // up later.
277 buffer_id_to_index_[consumer->id()] = allocated_buffer_index_;
278 ++allocated_buffer_index_;
279
280 return return_value;
281}
282
283RemoteChannelHandle DisplaySurface::OnCreateVideoMeshSurface(
284 pdx::Message& message) {
285 if (flags_ & DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION) {
286 ALOGE(
287 "DisplaySurface::OnCreateVideoMeshSurface: system distorion is "
288 "disabled on this display surface, cannot create VideoMeshSurface on "
289 "top of it.");
290 REPLY_ERROR_RETURN(message, EINVAL, {});
291 }
292
293 int channel_id;
294 auto status = message.PushChannel(0, nullptr, &channel_id);
295
296 if (!status) {
297 ALOGE(
298 "DisplaySurface::OnCreateVideoMeshSurface: failed to push channel: %s",
299 status.GetErrorMessage().c_str());
300 REPLY_ERROR_RETURN(message, ENOMEM, {});
301 }
302
303 auto surface = std::make_shared<VideoMeshSurface>(service(), channel_id);
304 const int ret = service()->SetChannel(channel_id, surface);
305 if (ret < 0) {
306 ALOGE(
307 "DisplaySurface::OnCreateVideoMeshSurface: failed to set new video "
308 "mesh surface channel: %s",
309 strerror(-ret));
310 REPLY_ERROR_RETURN(message, ENOMEM, {});
311 }
312
313 {
314 std::lock_guard<std::mutex> autolock(lock_);
315 pending_video_mesh_surfaces_.push_back(surface);
316 video_mesh_surfaces_updated_ = true;
317 }
318
319 return status.take();
320}
321
322int DisplaySurface::AddConsumer(
323 const std::shared_ptr<BufferConsumer>& consumer) {
324 ALOGD_IF(TRACE, "DisplaySurface::AddConsumer: buffer_id=%d", consumer->id());
325 // Add the consumer to the epoll dispatcher, edge-triggered.
326 int err = service()->dispatcher_.AddEventHandler(
327 consumer->event_fd(), EPOLLET | EPOLLIN | EPOLLHUP,
328 std::bind(&DisplaySurface::HandleConsumerEvents,
329 std::static_pointer_cast<DisplaySurface>(shared_from_this()),
330 consumer, std::placeholders::_1));
331 if (err) {
332 ALOGE(
333 "DisplaySurface::AddConsumer: failed to add epoll event handler for "
334 "consumer: %s",
335 strerror(-err));
336 return err;
337 }
338
339 // Add the consumer to the list of buffers for this surface.
340 std::lock_guard<std::mutex> autolock(lock_);
341 buffers_.insert(std::make_pair(consumer->id(), consumer));
342 return 0;
343}
344
345void DisplaySurface::RemoveConsumer(
346 const std::shared_ptr<BufferConsumer>& consumer) {
347 ALOGD_IF(TRACE, "DisplaySurface::RemoveConsumer: buffer_id=%d",
348 consumer->id());
349 service()->dispatcher_.RemoveEventHandler(consumer->event_fd());
350
351 std::lock_guard<std::mutex> autolock(lock_);
352 buffers_.erase(consumer->id());
353}
354
355void DisplaySurface::RemoveConsumerUnlocked(
356 const std::shared_ptr<BufferConsumer>& consumer) {
357 ALOGD_IF(TRACE, "DisplaySurface::RemoveConsumerUnlocked: buffer_id=%d",
358 consumer->id());
359 service()->dispatcher_.RemoveEventHandler(consumer->event_fd());
360 buffers_.erase(consumer->id());
361}
362
363void DisplaySurface::OnPostConsumer(
364 const std::shared_ptr<BufferConsumer>& consumer) {
365 ATRACE_NAME("DisplaySurface::OnPostConsumer");
366 std::lock_guard<std::mutex> autolock(lock_);
367
Hendrik Wagenaarcd11bd52017-02-07 14:27:28 -0800368 if (!IsVisible()) {
369 ALOGD_IF(TRACE,
370 "DisplaySurface::OnPostConsumer: Discarding buffer_id=%d on "
371 "invisible surface.",
372 consumer->id());
373 consumer->Discard();
374 return;
375 }
376
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800377 if (posted_buffers_.IsFull()) {
378 ALOGE("Error: posted buffers full, overwriting");
379 posted_buffers_.PopBack();
380 }
381
382 int error;
383 posted_buffers_.Append(AcquiredBuffer(consumer, &error));
384
385 // Remove the consumer if the other end was closed.
386 if (posted_buffers_.Back().IsEmpty() && error == -EPIPE)
387 RemoveConsumerUnlocked(consumer);
388}
389
390void DisplaySurface::HandleConsumerEvents(
391 const std::shared_ptr<BufferConsumer>& consumer, int events) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800392 auto status = consumer->GetEventMask(events);
393 if (!status) {
394 ALOGW(
395 "DisplaySurface::HandleConsumerEvents: Failed to get event mask for "
396 "consumer: %s",
397 status.GetErrorMessage().c_str());
398 return;
399 }
400
401 events = status.get();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800402 if (events & EPOLLHUP) {
403 ALOGD_IF(TRACE,
404 "DisplaySurface::HandleConsumerEvents: removing event handler for "
405 "buffer=%d",
406 consumer->id());
407 RemoveConsumer(consumer);
408 } else if (events & EPOLLIN) {
409 // BufferHub uses EPOLLIN to signal consumer ownership.
410 ALOGD_IF(TRACE,
411 "DisplaySurface::HandleConsumerEvents: posting buffer=%d for "
412 "process=%d",
413 consumer->id(), process_id_);
414
415 OnPostConsumer(consumer);
416 }
417}
418
419std::vector<std::shared_ptr<VideoMeshSurface>>
420DisplaySurface::GetVideoMeshSurfaces() {
421 std::lock_guard<std::mutex> autolock(lock_);
422 std::vector<std::shared_ptr<VideoMeshSurface>> surfaces;
423
424 for (auto& surface : pending_video_mesh_surfaces_) {
425 if (auto video_surface = surface.lock()) {
426 surfaces.push_back(video_surface);
427 } else {
428 ALOGE("Unable to lock video mesh surface.");
429 }
430 }
431
432 pending_video_mesh_surfaces_.clear();
433 video_mesh_surfaces_updated_ = false;
434 return surfaces;
435}
436
437} // namespace dvr
438} // namespace android