#include "include/private/dvr/display_client.h"
#include <cutils/native_handle.h>
#include <log/log.h>
#include <pdx/default_transport/client_channel.h>
#include <pdx/default_transport/client_channel_factory.h>
#include <pdx/status.h>
#include <mutex>
#include <private/dvr/display_protocol.h>
#include <private/dvr/native_buffer.h>
using android::pdx::ErrorStatus;
using android::pdx::LocalHandle;
using android::pdx::LocalChannelHandle;
using android::pdx::Status;
using android::pdx::Transaction;
using android::pdx::rpc::IfAnyOf;
namespace android {
namespace dvr {
namespace display {
Surface::Surface(LocalChannelHandle channel_handle, int* error)
: BASE{pdx::default_transport::ClientChannel::Create(
std::move(channel_handle))} {
auto status = InvokeRemoteMethod<DisplayProtocol::GetSurfaceInfo>();
if (!status) {
ALOGE("Surface::Surface: Failed to get surface info: %s",
status.GetErrorMessage().c_str());
Close(status.error());
if (error)
*error = status.error();
}
surface_id_ = status.get().surface_id;
z_order_ = status.get().z_order;
visible_ = status.get().visible;
}
Surface::Surface(const SurfaceAttributes& attributes, int* error)
: BASE{pdx::default_transport::ClientChannelFactory::Create(
DisplayProtocol::kClientPath),
kInfiniteTimeout} {
auto status = InvokeRemoteMethod<DisplayProtocol::CreateSurface>(attributes);
if (!status) {
ALOGE("Surface::Surface: Failed to create display surface: %s",
status.GetErrorMessage().c_str());
Close(status.error());
if (error)
*error = status.error();
}
surface_id_ = status.get().surface_id;
z_order_ = status.get().z_order;
visible_ = status.get().visible;
}
Status<void> Surface::SetVisible(bool visible) {
return SetAttributes(
{{SurfaceAttribute::Visible, SurfaceAttributeValue{visible}}});
}
Status<void> Surface::SetZOrder(int z_order) {
return SetAttributes(
{{SurfaceAttribute::ZOrder, SurfaceAttributeValue{z_order}}});
}
Status<void> Surface::SetAttributes(const SurfaceAttributes& attributes) {
auto status = InvokeRemoteMethod<DisplayProtocol::SetAttributes>(attributes);
if (!status) {
ALOGE(
"Surface::SetAttributes: Failed to set display surface "
"attributes: %s",
status.GetErrorMessage().c_str());
return status.error_status();
}
// Set the local cached copies of the attributes we care about from the full
// set of attributes sent to the display service.
for (const auto& attribute : attributes) {
const auto& key = attribute.first;
const auto* variant = &attribute.second;
bool invalid_value = false;
switch (key) {
case SurfaceAttribute::Visible:
invalid_value =
!IfAnyOf<int32_t, int64_t, bool>::Get(variant, &visible_);
break;
case SurfaceAttribute::ZOrder:
invalid_value = !IfAnyOf<int32_t>::Get(variant, &z_order_);
break;
}
if (invalid_value) {
ALOGW(
"Surface::SetAttributes: Failed to set display surface "
"attribute %d because of incompatible type: %d",
key, variant->index());
}
}
return {};
}
Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue() {
ALOGD_IF(TRACE, "Surface::CreateQueue: Creating empty queue.");
auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(0);
if (!status) {
ALOGE("Surface::CreateQueue: Failed to create queue: %s",
status.GetErrorMessage().c_str());
return status.error_status();
}
auto producer_queue = ProducerQueue::Import(status.take());
if (!producer_queue) {
ALOGE("Surface::CreateQueue: Failed to import producer queue!");
return ErrorStatus(ENOMEM);
}
return {std::move(producer_queue)};
}
Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(
uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
uint64_t usage, size_t capacity) {
ALOGD_IF(TRACE,
"Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u "
"usage=%" PRIx64 " capacity=%zu",
width, height, layer_count, format, usage, capacity);
auto status = CreateQueue();
if (!status)
return status.error_status();
auto producer_queue = status.take();
ALOGD_IF(TRACE, "Surface::CreateQueue: Allocating %zu buffers...", capacity);
for (size_t i = 0; i < capacity; i++) {
size_t slot;
const int ret = producer_queue->AllocateBuffer(width, height, layer_count,
format, usage, &slot);
if (ret < 0) {
ALOGE(
"Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s",
producer_queue->id(), strerror(-ret));
return ErrorStatus(ENOMEM);
}
ALOGD_IF(
TRACE,
"Surface::CreateQueue: Allocated buffer at slot=%zu of capacity=%zu",
slot, capacity);
}
return {std::move(producer_queue)};
}
DisplayClient::DisplayClient(int* error)
: BASE(pdx::default_transport::ClientChannelFactory::Create(
DisplayProtocol::kClientPath),
kInfiniteTimeout) {
if (error)
*error = Client::error();
}
Status<Metrics> DisplayClient::GetDisplayMetrics() {
return InvokeRemoteMethod<DisplayProtocol::GetMetrics>();
}
Status<std::unique_ptr<Surface>> DisplayClient::CreateSurface(
const SurfaceAttributes& attributes) {
int error;
if (auto client = Surface::Create(attributes, &error))
return {std::move(client)};
else
return ErrorStatus(error);
}
Status<std::unique_ptr<IonBuffer>> DisplayClient::GetNamedBuffer(
const std::string& name) {
auto status = InvokeRemoteMethod<DisplayProtocol::GetNamedBuffer>(name);
if (!status) {
ALOGE(
"DisplayClient::GetNamedBuffer: Failed to get named buffer: name=%s; "
"error=%s",
name.c_str(), status.GetErrorMessage().c_str());
return status.error_status();
}
auto ion_buffer = std::make_unique<IonBuffer>();
auto native_buffer_handle = status.take();
const int ret = native_buffer_handle.Import(ion_buffer.get());
if (ret < 0) {
ALOGE(
"DisplayClient::GetNamedBuffer: Failed to import named buffer: "
"name=%s; error=%s",
name.c_str(), strerror(-ret));
return ErrorStatus(-ret);
}
return {std::move(ion_buffer)};
}
Status<bool> DisplayClient::IsVrAppRunning() {
return InvokeRemoteMethod<DisplayProtocol::IsVrAppRunning>();
}
} // namespace display
} // namespace dvr
} // namespace android