You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
278 lines
8.6 KiB
278 lines
8.6 KiB
#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"
|