| #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 |