Add libvrflinger for use in SurfaceFlinger
A separate CL uses this code from SurfaceFlinger.
Bug: None
Test: Manually ran modified SurfaceFlinger
Change-Id: I34588df1365588c0a0265e1e2325e3dd5516206a
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
new file mode 100644
index 0000000..dff08b5
--- /dev/null
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -0,0 +1,435 @@
+#include "display_surface.h"
+
+#include <utils/Trace.h>
+
+#include <private/dvr/platform_defines.h>
+
+#include "display_service.h"
+#include "hardware_composer.h"
+
+#define LOCAL_TRACE 1
+
+using android::pdx::BorrowedChannelHandle;
+using android::pdx::LocalChannelHandle;
+using android::pdx::Message;
+using android::pdx::RemoteChannelHandle;
+using android::pdx::Status;
+using android::pdx::rpc::DispatchRemoteMethod;
+using android::pdx::rpc::IfAnyOf;
+
+namespace android {
+namespace dvr {
+
+DisplaySurface::DisplaySurface(DisplayService* service, int surface_id,
+ int process_id, int width, int height,
+ int format, int usage, int flags)
+ : SurfaceChannel(service, surface_id, SurfaceTypeEnum::Normal,
+ sizeof(DisplaySurfaceMetadata)),
+ process_id_(process_id),
+ posted_buffers_(kMaxPostedBuffers),
+ video_mesh_surfaces_updated_(false),
+ width_(width),
+ height_(height),
+ format_(format),
+ usage_(usage),
+ flags_(flags),
+ client_visible_(false),
+ client_z_order_(0),
+ client_exclude_from_blur_(false),
+ client_blur_behind_(false),
+ manager_visible_(false),
+ manager_z_order_(0),
+ manager_blur_(0.0f),
+ allocated_buffer_index_(0),
+ layer_order_(0) {}
+
+DisplaySurface::~DisplaySurface() {
+ ALOGD_IF(LOCAL_TRACE,
+ "DisplaySurface::~DisplaySurface: surface_id=%d process_id=%d",
+ surface_id(), process_id_);
+}
+
+void DisplaySurface::ManagerSetVisible(bool visible) {
+ std::lock_guard<std::mutex> autolock(lock_);
+ manager_visible_ = visible;
+}
+
+void DisplaySurface::ManagerSetZOrder(int z_order) {
+ std::lock_guard<std::mutex> autolock(lock_);
+ manager_z_order_ = z_order;
+}
+
+void DisplaySurface::ManagerSetBlur(float blur) {
+ std::lock_guard<std::mutex> autolock(lock_);
+ manager_blur_ = blur;
+}
+
+void DisplaySurface::ClientSetVisible(bool visible) {
+ std::lock_guard<std::mutex> autolock(lock_);
+ client_visible_ = visible;
+}
+
+void DisplaySurface::ClientSetZOrder(int z_order) {
+ std::lock_guard<std::mutex> autolock(lock_);
+ client_z_order_ = z_order;
+}
+
+void DisplaySurface::ClientSetExcludeFromBlur(bool exclude_from_blur) {
+ std::lock_guard<std::mutex> autolock(lock_);
+ client_exclude_from_blur_ = exclude_from_blur;
+}
+
+void DisplaySurface::ClientSetBlurBehind(bool blur_behind) {
+ std::lock_guard<std::mutex> autolock(lock_);
+ client_blur_behind_ = blur_behind;
+}
+
+size_t DisplaySurface::GetBufferCount() const {
+ std::lock_guard<std::mutex> autolock(lock_);
+ return buffers_.size();
+}
+
+std::vector<std::shared_ptr<BufferConsumer>> DisplaySurface::GetBuffers() {
+ std::lock_guard<std::mutex> autolock(lock_);
+ std::vector<std::shared_ptr<BufferConsumer>> return_vector(buffers_.size());
+
+ for (const auto pair : buffers_) {
+ return_vector.push_back(pair.second);
+ }
+
+ return return_vector;
+}
+
+AcquiredBuffer DisplaySurface::AcquireNewestAvailableBuffer(
+ AcquiredBuffer* skipped_buffer) {
+ std::lock_guard<std::mutex> autolock(lock_);
+ AcquiredBuffer buffer;
+ int frames = 0;
+ // Basic latency stopgap for when the application misses a frame:
+ // If the application recovers on the 2nd or 3rd (etc) frame after
+ // missing, this code will skip frames to catch up by checking if
+ // the next frame is also available.
+ while (!posted_buffers_.IsEmpty() && posted_buffers_.Front().IsAvailable()) {
+ // Capture the skipped buffer into the result parameter.
+ // Note that this API only supports skipping one buffer per vsync.
+ if (frames > 0 && skipped_buffer)
+ *skipped_buffer = std::move(buffer);
+ ++frames;
+ buffer = std::move(posted_buffers_.Front());
+ posted_buffers_.PopFront();
+ if (frames == 2)
+ break;
+ }
+ return buffer;
+}
+
+bool DisplaySurface::IsBufferAvailable() const {
+ std::lock_guard<std::mutex> autolock(lock_);
+ return !posted_buffers_.IsEmpty() && posted_buffers_.Front().IsAvailable();
+}
+
+bool DisplaySurface::IsBufferPosted() const {
+ std::lock_guard<std::mutex> autolock(lock_);
+ return !posted_buffers_.IsEmpty();
+}
+
+AcquiredBuffer DisplaySurface::AcquireCurrentBuffer() {
+ std::lock_guard<std::mutex> autolock(lock_);
+ if (posted_buffers_.IsEmpty()) {
+ ALOGE("Error: attempt to acquire buffer when none are posted.");
+ return AcquiredBuffer();
+ }
+ AcquiredBuffer buffer = std::move(posted_buffers_.Front());
+ posted_buffers_.PopFront();
+ return buffer;
+}
+
+int DisplaySurface::GetConsumers(std::vector<LocalChannelHandle>* consumers) {
+ std::lock_guard<std::mutex> autolock(lock_);
+ std::vector<LocalChannelHandle> items;
+
+ for (auto pair : buffers_) {
+ const auto& buffer = pair.second;
+
+ Status<LocalChannelHandle> consumer_channel = buffer->CreateConsumer();
+ if (!consumer_channel) {
+ ALOGE(
+ "DisplaySurface::GetConsumers: Failed to get a new consumer for "
+ "buffer %d: %s",
+ buffer->id(), consumer_channel.GetErrorMessage().c_str());
+ return -consumer_channel.error();
+ }
+
+ items.push_back(consumer_channel.take());
+ }
+
+ *consumers = std::move(items);
+ return 0;
+}
+
+int DisplaySurface::HandleMessage(pdx::Message& message) {
+ switch (message.GetOp()) {
+ case DisplayRPC::SetAttributes::Opcode:
+ DispatchRemoteMethod<DisplayRPC::SetAttributes>(
+ *this, &DisplaySurface::OnClientSetAttributes, message);
+ break;
+
+ case DisplayRPC::AllocateBuffer::Opcode:
+ DispatchRemoteMethod<DisplayRPC::AllocateBuffer>(
+ *this, &DisplaySurface::OnAllocateBuffer, message);
+ break;
+
+ case DisplayRPC::CreateVideoMeshSurface::Opcode:
+ DispatchRemoteMethod<DisplayRPC::CreateVideoMeshSurface>(
+ *this, &DisplaySurface::OnCreateVideoMeshSurface, message);
+ break;
+
+ default:
+ return SurfaceChannel::HandleMessage(message);
+ }
+
+ return 0;
+}
+
+int DisplaySurface::OnClientSetAttributes(
+ pdx::Message& /*message*/, const DisplaySurfaceAttributes& attributes) {
+ for (const auto& attribute : attributes) {
+ const auto& key = attribute.first;
+ const auto* variant = &attribute.second;
+ bool invalid_value = false;
+ switch (key) {
+ case DisplaySurfaceAttributeEnum::ZOrder:
+ invalid_value = !IfAnyOf<int32_t, int64_t, float>::Call(
+ variant, [this](const auto& value) {
+ DisplaySurface::ClientSetZOrder(value);
+ });
+ break;
+ case DisplaySurfaceAttributeEnum::Visible:
+ invalid_value = !IfAnyOf<int32_t, int64_t, bool>::Call(
+ variant, [this](const auto& value) {
+ DisplaySurface::ClientSetVisible(value);
+ });
+ break;
+ case DisplaySurfaceAttributeEnum::ExcludeFromBlur:
+ invalid_value = !IfAnyOf<int32_t, int64_t, bool>::Call(
+ variant, [this](const auto& value) {
+ DisplaySurface::ClientSetExcludeFromBlur(value);
+ });
+ break;
+ case DisplaySurfaceAttributeEnum::BlurBehind:
+ invalid_value = !IfAnyOf<int32_t, int64_t, bool>::Call(
+ variant, [this](const auto& value) {
+ DisplaySurface::ClientSetBlurBehind(value);
+ });
+ break;
+ default:
+ ALOGW(
+ "DisplaySurface::OnClientSetAttributes: Unrecognized attribute %d "
+ "surface_id=%d",
+ key, surface_id());
+ break;
+ }
+
+ if (invalid_value) {
+ ALOGW(
+ "DisplaySurface::OnClientSetAttributes: Failed to set display "
+ "surface attribute '%s' because of incompatible type: %d",
+ DisplaySurfaceAttributeEnum::ToString(key).c_str(), variant->index());
+ }
+ }
+
+ service()->NotifyDisplayConfigurationUpdate();
+ return 0;
+}
+
+// Allocates a new buffer for the DisplaySurface associated with this channel.
+std::pair<uint32_t, LocalChannelHandle> DisplaySurface::OnAllocateBuffer(
+ pdx::Message& message) {
+ // Inject flag to enable framebuffer compression for the application buffers.
+ // TODO(eieio,jbates): Make this configurable per hardware platform.
+ const int usage = usage_ | GRALLOC_USAGE_QCOM_FRAMEBUFFER_COMPRESSION;
+ const int slice_count =
+ (flags_ & static_cast<int>(DisplaySurfaceFlagsEnum::SeparateGeometry))
+ ? 2
+ : 1;
+
+ ALOGI_IF(
+ TRACE,
+ "DisplaySurface::OnAllocateBuffer: width=%d height=%d format=%x usage=%x "
+ "slice_count=%d",
+ width_, height_, format_, usage, slice_count);
+
+ // Create a producer buffer to hand back to the sender.
+ auto producer = BufferProducer::Create(width_, height_, format_, usage,
+ sizeof(uint64_t), slice_count);
+ if (!producer)
+ REPLY_ERROR_RETURN(message, EINVAL, {});
+
+ // Create and import a consumer attached to the producer.
+ Status<LocalChannelHandle> consumer_channel = producer->CreateConsumer();
+ if (!consumer_channel)
+ REPLY_ERROR_RETURN(message, consumer_channel.error(), {});
+
+ std::shared_ptr<BufferConsumer> consumer =
+ BufferConsumer::Import(consumer_channel.take());
+ if (!consumer)
+ REPLY_ERROR_RETURN(message, ENOMEM, {});
+
+ // Add the consumer to this surface.
+ int err = AddConsumer(consumer);
+ if (err < 0) {
+ ALOGE("DisplaySurface::OnAllocateBuffer: failed to add consumer: buffer=%d",
+ consumer->id());
+ REPLY_ERROR_RETURN(message, -err, {});
+ }
+
+ // Move the channel handle so that it doesn't get closed when the producer
+ // goes out of scope.
+ std::pair<uint32_t, LocalChannelHandle> return_value(
+ allocated_buffer_index_, std::move(producer->GetChannelHandle()));
+
+ // Save buffer index, associated with the buffer id so that it can be looked
+ // up later.
+ buffer_id_to_index_[consumer->id()] = allocated_buffer_index_;
+ ++allocated_buffer_index_;
+
+ return return_value;
+}
+
+RemoteChannelHandle DisplaySurface::OnCreateVideoMeshSurface(
+ pdx::Message& message) {
+ if (flags_ & DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION) {
+ ALOGE(
+ "DisplaySurface::OnCreateVideoMeshSurface: system distorion is "
+ "disabled on this display surface, cannot create VideoMeshSurface on "
+ "top of it.");
+ REPLY_ERROR_RETURN(message, EINVAL, {});
+ }
+
+ int channel_id;
+ auto status = message.PushChannel(0, nullptr, &channel_id);
+
+ if (!status) {
+ ALOGE(
+ "DisplaySurface::OnCreateVideoMeshSurface: failed to push channel: %s",
+ status.GetErrorMessage().c_str());
+ REPLY_ERROR_RETURN(message, ENOMEM, {});
+ }
+
+ auto surface = std::make_shared<VideoMeshSurface>(service(), channel_id);
+ const int ret = service()->SetChannel(channel_id, surface);
+ if (ret < 0) {
+ ALOGE(
+ "DisplaySurface::OnCreateVideoMeshSurface: failed to set new video "
+ "mesh surface channel: %s",
+ strerror(-ret));
+ REPLY_ERROR_RETURN(message, ENOMEM, {});
+ }
+
+ {
+ std::lock_guard<std::mutex> autolock(lock_);
+ pending_video_mesh_surfaces_.push_back(surface);
+ video_mesh_surfaces_updated_ = true;
+ }
+
+ return status.take();
+}
+
+int DisplaySurface::AddConsumer(
+ const std::shared_ptr<BufferConsumer>& consumer) {
+ ALOGD_IF(TRACE, "DisplaySurface::AddConsumer: buffer_id=%d", consumer->id());
+ // Add the consumer to the epoll dispatcher, edge-triggered.
+ int err = service()->dispatcher_.AddEventHandler(
+ consumer->event_fd(), EPOLLET | EPOLLIN | EPOLLHUP,
+ std::bind(&DisplaySurface::HandleConsumerEvents,
+ std::static_pointer_cast<DisplaySurface>(shared_from_this()),
+ consumer, std::placeholders::_1));
+ if (err) {
+ ALOGE(
+ "DisplaySurface::AddConsumer: failed to add epoll event handler for "
+ "consumer: %s",
+ strerror(-err));
+ return err;
+ }
+
+ // Add the consumer to the list of buffers for this surface.
+ std::lock_guard<std::mutex> autolock(lock_);
+ buffers_.insert(std::make_pair(consumer->id(), consumer));
+ return 0;
+}
+
+void DisplaySurface::RemoveConsumer(
+ const std::shared_ptr<BufferConsumer>& consumer) {
+ ALOGD_IF(TRACE, "DisplaySurface::RemoveConsumer: buffer_id=%d",
+ consumer->id());
+ service()->dispatcher_.RemoveEventHandler(consumer->event_fd());
+
+ std::lock_guard<std::mutex> autolock(lock_);
+ buffers_.erase(consumer->id());
+}
+
+void DisplaySurface::RemoveConsumerUnlocked(
+ const std::shared_ptr<BufferConsumer>& consumer) {
+ ALOGD_IF(TRACE, "DisplaySurface::RemoveConsumerUnlocked: buffer_id=%d",
+ consumer->id());
+ service()->dispatcher_.RemoveEventHandler(consumer->event_fd());
+ buffers_.erase(consumer->id());
+}
+
+void DisplaySurface::OnPostConsumer(
+ const std::shared_ptr<BufferConsumer>& consumer) {
+ ATRACE_NAME("DisplaySurface::OnPostConsumer");
+ std::lock_guard<std::mutex> autolock(lock_);
+
+ if (posted_buffers_.IsFull()) {
+ ALOGE("Error: posted buffers full, overwriting");
+ posted_buffers_.PopBack();
+ }
+
+ int error;
+ posted_buffers_.Append(AcquiredBuffer(consumer, &error));
+
+ // Remove the consumer if the other end was closed.
+ if (posted_buffers_.Back().IsEmpty() && error == -EPIPE)
+ RemoveConsumerUnlocked(consumer);
+}
+
+void DisplaySurface::HandleConsumerEvents(
+ const std::shared_ptr<BufferConsumer>& consumer, int events) {
+ if (events & EPOLLHUP) {
+ ALOGD_IF(TRACE,
+ "DisplaySurface::HandleConsumerEvents: removing event handler for "
+ "buffer=%d",
+ consumer->id());
+ RemoveConsumer(consumer);
+ } else if (events & EPOLLIN) {
+ // BufferHub uses EPOLLIN to signal consumer ownership.
+ ALOGD_IF(TRACE,
+ "DisplaySurface::HandleConsumerEvents: posting buffer=%d for "
+ "process=%d",
+ consumer->id(), process_id_);
+
+ OnPostConsumer(consumer);
+ }
+}
+
+std::vector<std::shared_ptr<VideoMeshSurface>>
+DisplaySurface::GetVideoMeshSurfaces() {
+ std::lock_guard<std::mutex> autolock(lock_);
+ std::vector<std::shared_ptr<VideoMeshSurface>> surfaces;
+
+ for (auto& surface : pending_video_mesh_surfaces_) {
+ if (auto video_surface = surface.lock()) {
+ surfaces.push_back(video_surface);
+ } else {
+ ALOGE("Unable to lock video mesh surface.");
+ }
+ }
+
+ pending_video_mesh_surfaces_.clear();
+ video_mesh_surfaces_updated_ = false;
+ return surfaces;
+}
+
+} // namespace dvr
+} // namespace android