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