| #include "include/dvr/dvr_surface.h" |
| |
| #include <inttypes.h> |
| |
| #include <pdx/rpc/variant.h> |
| #include <private/android/AHardwareBufferHelpers.h> |
| #include <private/dvr/display_client.h> |
| |
| #include "dvr_buffer_queue_internal.h" |
| #include "dvr_internal.h" |
| |
| using android::AHardwareBuffer_convertToGrallocUsageBits; |
| using android::dvr::display::DisplayClient; |
| using android::dvr::display::Surface; |
| using android::dvr::display::SurfaceAttributes; |
| using android::dvr::display::SurfaceAttributeValue; |
| using android::pdx::rpc::EmptyVariant; |
| |
| namespace { |
| |
| // Sets the Variant |destination| to the target std::array type and copies the C |
| // array into it. Unsupported std::array configurations will fail to compile. |
| template <typename T, std::size_t N> |
| void ArrayCopy(SurfaceAttributeValue* destination, const T (&source)[N]) { |
| using ArrayType = std::array<T, N>; |
| *destination = ArrayType{}; |
| std::copy(std::begin(source), std::end(source), |
| std::get<ArrayType>(*destination).begin()); |
| } |
| |
| bool ConvertSurfaceAttributes(const DvrSurfaceAttribute* attributes, |
| size_t attribute_count, |
| SurfaceAttributes* surface_attributes, |
| size_t* error_index) { |
| for (size_t i = 0; i < attribute_count; i++) { |
| SurfaceAttributeValue value; |
| switch (attributes[i].value.type) { |
| case DVR_SURFACE_ATTRIBUTE_TYPE_INT32: |
| value = attributes[i].value.int32_value; |
| break; |
| case DVR_SURFACE_ATTRIBUTE_TYPE_INT64: |
| value = attributes[i].value.int64_value; |
| break; |
| case DVR_SURFACE_ATTRIBUTE_TYPE_BOOL: |
| // bool_value is defined in an extern "C" block, which makes it look |
| // like an int to C++. Use a cast to assign the correct type to the |
| // Variant type SurfaceAttributeValue. |
| value = static_cast<bool>(attributes[i].value.bool_value); |
| break; |
| case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT: |
| value = attributes[i].value.float_value; |
| break; |
| case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2: |
| ArrayCopy(&value, attributes[i].value.float2_value); |
| break; |
| case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3: |
| ArrayCopy(&value, attributes[i].value.float3_value); |
| break; |
| case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4: |
| ArrayCopy(&value, attributes[i].value.float4_value); |
| break; |
| case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8: |
| ArrayCopy(&value, attributes[i].value.float8_value); |
| break; |
| case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16: |
| ArrayCopy(&value, attributes[i].value.float16_value); |
| break; |
| case DVR_SURFACE_ATTRIBUTE_TYPE_NONE: |
| value = EmptyVariant{}; |
| break; |
| default: |
| *error_index = i; |
| return false; |
| } |
| |
| surface_attributes->emplace(attributes[i].key, value); |
| } |
| |
| return true; |
| } |
| |
| } // anonymous namespace |
| |
| extern "C" { |
| |
| struct DvrSurface { |
| std::unique_ptr<Surface> surface; |
| }; |
| |
| int dvrSurfaceCreate(const DvrSurfaceAttribute* attributes, |
| size_t attribute_count, DvrSurface** out_surface) { |
| if (out_surface == nullptr) { |
| ALOGE("dvrSurfaceCreate: Invalid inputs: out_surface=%p.", out_surface); |
| return -EINVAL; |
| } |
| |
| size_t error_index; |
| SurfaceAttributes surface_attributes; |
| if (!ConvertSurfaceAttributes(attributes, attribute_count, |
| &surface_attributes, &error_index)) { |
| ALOGE("dvrSurfaceCreate: Invalid surface attribute type: %" PRIu64, |
| attributes[error_index].value.type); |
| return -EINVAL; |
| } |
| |
| auto status = Surface::CreateSurface(surface_attributes); |
| if (!status) { |
| ALOGE("dvrSurfaceCreate:: Failed to create display surface: %s", |
| status.GetErrorMessage().c_str()); |
| return -status.error(); |
| } |
| |
| *out_surface = new DvrSurface{status.take()}; |
| return 0; |
| } |
| |
| void dvrSurfaceDestroy(DvrSurface* surface) { delete surface; } |
| |
| int dvrSurfaceGetId(DvrSurface* surface) { |
| return surface->surface->surface_id(); |
| } |
| |
| int dvrSurfaceSetAttributes(DvrSurface* surface, |
| const DvrSurfaceAttribute* attributes, |
| size_t attribute_count) { |
| if (surface == nullptr || attributes == nullptr) { |
| ALOGE( |
| "dvrSurfaceSetAttributes: Invalid inputs: surface=%p attributes=%p " |
| "attribute_count=%zu", |
| surface, attributes, attribute_count); |
| return -EINVAL; |
| } |
| |
| size_t error_index; |
| SurfaceAttributes surface_attributes; |
| if (!ConvertSurfaceAttributes(attributes, attribute_count, |
| &surface_attributes, &error_index)) { |
| ALOGE("dvrSurfaceSetAttributes: Invalid surface attribute type: %" PRIu64, |
| attributes[error_index].value.type); |
| return -EINVAL; |
| } |
| |
| auto status = surface->surface->SetAttributes(surface_attributes); |
| if (!status) { |
| ALOGE("dvrSurfaceSetAttributes: Failed to set attributes: %s", |
| status.GetErrorMessage().c_str()); |
| return -status.error(); |
| } |
| |
| return 0; |
| } |
| |
| int dvrSurfaceCreateWriteBufferQueue(DvrSurface* surface, uint32_t width, |
| uint32_t height, uint32_t format, |
| uint32_t layer_count, uint64_t usage, |
| size_t capacity, size_t metadata_size, |
| DvrWriteBufferQueue** out_writer) { |
| if (surface == nullptr || out_writer == nullptr) { |
| ALOGE( |
| "dvrSurfaceCreateWriteBufferQueue: Invalid inputs: surface=%p, " |
| "out_writer=%p.", |
| surface, out_writer); |
| return -EINVAL; |
| } |
| |
| auto status = surface->surface->CreateQueue( |
| width, height, layer_count, format, usage, capacity, metadata_size); |
| if (!status) { |
| ALOGE("dvrSurfaceCreateWriteBufferQueue: Failed to create queue: %s", |
| status.GetErrorMessage().c_str()); |
| return -status.error(); |
| } |
| |
| *out_writer = new DvrWriteBufferQueue(status.take()); |
| return 0; |
| } |
| |
| int dvrSetupGlobalBuffer(DvrGlobalBufferKey key, size_t size, uint64_t usage, |
| DvrBuffer** buffer_out) { |
| if (!buffer_out) |
| return -EINVAL; |
| |
| int error; |
| auto client = DisplayClient::Create(&error); |
| if (!client) { |
| ALOGE("dvrSetupGlobalBuffer: Failed to create display client: %s", |
| strerror(-error)); |
| return error; |
| } |
| |
| uint64_t gralloc_usage = AHardwareBuffer_convertToGrallocUsageBits(usage); |
| |
| auto buffer_status = client->SetupGlobalBuffer(key, size, gralloc_usage); |
| if (!buffer_status) { |
| ALOGE("dvrSetupGlobalBuffer: Failed to setup global buffer: %s", |
| buffer_status.GetErrorMessage().c_str()); |
| return -buffer_status.error(); |
| } |
| |
| *buffer_out = CreateDvrBufferFromIonBuffer(buffer_status.take()); |
| return 0; |
| } |
| |
| int dvrDeleteGlobalBuffer(DvrGlobalBufferKey key) { |
| int error; |
| auto client = DisplayClient::Create(&error); |
| if (!client) { |
| ALOGE("dvrDeleteGlobalBuffer: Failed to create display client: %s", |
| strerror(-error)); |
| return error; |
| } |
| |
| auto buffer_status = client->DeleteGlobalBuffer(key); |
| if (!buffer_status) { |
| ALOGE("dvrDeleteGlobalBuffer: Failed to delete named buffer: %s", |
| buffer_status.GetErrorMessage().c_str()); |
| return -buffer_status.error(); |
| } |
| |
| return 0; |
| } |
| |
| int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer) { |
| if (!out_buffer) |
| return -EINVAL; |
| |
| int error; |
| auto client = DisplayClient::Create(&error); |
| if (!client) { |
| ALOGE("dvrGetGlobalBuffer: Failed to create display client: %s", |
| strerror(-error)); |
| return error; |
| } |
| |
| auto status = client->GetGlobalBuffer(key); |
| if (!status) { |
| return -status.error(); |
| } |
| *out_buffer = CreateDvrBufferFromIonBuffer(status.take()); |
| return 0; |
| } |
| |
| int dvrGetNativeDisplayMetrics(size_t sizeof_metrics, |
| DvrNativeDisplayMetrics* metrics) { |
| ALOGE_IF(sizeof_metrics != sizeof(DvrNativeDisplayMetrics), |
| "dvrGetNativeDisplayMetrics: metrics struct mismatch, your dvr api " |
| "header is out of date."); |
| |
| auto client = DisplayClient::Create(); |
| if (!client) { |
| ALOGE("dvrGetNativeDisplayMetrics: Failed to create display client!"); |
| return -ECOMM; |
| } |
| |
| if (metrics == nullptr) { |
| ALOGE("dvrGetNativeDisplayMetrics: output metrics buffer must be non-null"); |
| return -EINVAL; |
| } |
| |
| auto status = client->GetDisplayMetrics(); |
| |
| if (!status) { |
| return -status.error(); |
| } |
| |
| if (sizeof_metrics >= 20) { |
| metrics->display_width = status.get().display_width; |
| metrics->display_height = status.get().display_height; |
| metrics->display_x_dpi = status.get().display_x_dpi; |
| metrics->display_y_dpi = status.get().display_y_dpi; |
| metrics->vsync_period_ns = status.get().vsync_period_ns; |
| } |
| |
| return 0; |
| } |
| |
| } // extern "C" |