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