Jiwen 'Steve' Cai | bdcee79 | 2017-03-22 16:59:53 -0700 | [diff] [blame] | 1 | #include "include/dvr/dvr_surface.h" |
| 2 | |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 3 | #include <inttypes.h> |
| 4 | |
Corey Tabaka | 49a706d | 2017-06-08 14:29:58 -0700 | [diff] [blame] | 5 | #include <pdx/rpc/variant.h> |
Corey Tabaka | 99c2d73 | 2017-06-07 17:54:33 -0700 | [diff] [blame] | 6 | #include <private/android/AHardwareBufferHelpers.h> |
Jiwen 'Steve' Cai | bdcee79 | 2017-03-22 16:59:53 -0700 | [diff] [blame] | 7 | #include <private/dvr/display_client.h> |
| 8 | |
Jiwen 'Steve' Cai | 656f406 | 2017-05-22 13:02:33 -0700 | [diff] [blame] | 9 | #include "dvr_buffer_queue_internal.h" |
Corey Tabaka | 99c2d73 | 2017-06-07 17:54:33 -0700 | [diff] [blame] | 10 | #include "dvr_internal.h" |
Jiwen 'Steve' Cai | bdcee79 | 2017-03-22 16:59:53 -0700 | [diff] [blame] | 11 | |
Corey Tabaka | 99c2d73 | 2017-06-07 17:54:33 -0700 | [diff] [blame] | 12 | using android::AHardwareBuffer_convertToGrallocUsageBits; |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 13 | using android::dvr::display::DisplayClient; |
| 14 | using android::dvr::display::Surface; |
| 15 | using android::dvr::display::SurfaceAttributes; |
| 16 | using android::dvr::display::SurfaceAttributeValue; |
| 17 | using android::dvr::CreateDvrReadBufferFromBufferConsumer; |
Corey Tabaka | 49a706d | 2017-06-08 14:29:58 -0700 | [diff] [blame] | 18 | using android::pdx::rpc::EmptyVariant; |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 19 | |
| 20 | namespace { |
| 21 | |
Corey Tabaka | 7190e8a | 2017-06-22 20:39:42 -0700 | [diff] [blame] | 22 | // Sets the Variant |destination| to the target std::array type and copies the C |
| 23 | // array into it. Unsupported std::array configurations will fail to compile. |
| 24 | template <typename T, std::size_t N> |
| 25 | void ArrayCopy(SurfaceAttributeValue* destination, const T (&source)[N]) { |
| 26 | using ArrayType = std::array<T, N>; |
| 27 | *destination = ArrayType{}; |
| 28 | std::copy(std::begin(source), std::end(source), |
| 29 | std::get<ArrayType>(*destination).begin()); |
| 30 | } |
| 31 | |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 32 | bool ConvertSurfaceAttributes(const DvrSurfaceAttribute* attributes, |
| 33 | size_t attribute_count, |
| 34 | SurfaceAttributes* surface_attributes, |
| 35 | size_t* error_index) { |
| 36 | for (size_t i = 0; i < attribute_count; i++) { |
| 37 | SurfaceAttributeValue value; |
| 38 | switch (attributes[i].value.type) { |
| 39 | case DVR_SURFACE_ATTRIBUTE_TYPE_INT32: |
| 40 | value = attributes[i].value.int32_value; |
| 41 | break; |
| 42 | case DVR_SURFACE_ATTRIBUTE_TYPE_INT64: |
| 43 | value = attributes[i].value.int64_value; |
| 44 | break; |
| 45 | case DVR_SURFACE_ATTRIBUTE_TYPE_BOOL: |
Corey Tabaka | 7190e8a | 2017-06-22 20:39:42 -0700 | [diff] [blame] | 46 | // bool_value is defined in an extern "C" block, which makes it look |
| 47 | // like an int to C++. Use a cast to assign the correct type to the |
| 48 | // Variant type SurfaceAttributeValue. |
| 49 | value = static_cast<bool>(attributes[i].value.bool_value); |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 50 | break; |
| 51 | case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT: |
| 52 | value = attributes[i].value.float_value; |
| 53 | break; |
| 54 | case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2: |
Corey Tabaka | 7190e8a | 2017-06-22 20:39:42 -0700 | [diff] [blame] | 55 | ArrayCopy(&value, attributes[i].value.float2_value); |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 56 | break; |
| 57 | case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3: |
Corey Tabaka | 7190e8a | 2017-06-22 20:39:42 -0700 | [diff] [blame] | 58 | ArrayCopy(&value, attributes[i].value.float3_value); |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 59 | break; |
| 60 | case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4: |
Corey Tabaka | 7190e8a | 2017-06-22 20:39:42 -0700 | [diff] [blame] | 61 | ArrayCopy(&value, attributes[i].value.float4_value); |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 62 | break; |
| 63 | case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8: |
Corey Tabaka | 7190e8a | 2017-06-22 20:39:42 -0700 | [diff] [blame] | 64 | ArrayCopy(&value, attributes[i].value.float8_value); |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 65 | break; |
| 66 | case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16: |
Corey Tabaka | 7190e8a | 2017-06-22 20:39:42 -0700 | [diff] [blame] | 67 | ArrayCopy(&value, attributes[i].value.float16_value); |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 68 | break; |
Corey Tabaka | 49a706d | 2017-06-08 14:29:58 -0700 | [diff] [blame] | 69 | case DVR_SURFACE_ATTRIBUTE_TYPE_NONE: |
| 70 | value = EmptyVariant{}; |
| 71 | break; |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 72 | default: |
| 73 | *error_index = i; |
| 74 | return false; |
| 75 | } |
| 76 | |
| 77 | surface_attributes->emplace(attributes[i].key, value); |
| 78 | } |
| 79 | |
| 80 | return true; |
| 81 | } |
| 82 | |
| 83 | } // anonymous namespace |
Jiwen 'Steve' Cai | 74cf084 | 2017-03-23 18:53:16 -0700 | [diff] [blame] | 84 | |
Jiwen 'Steve' Cai | bdcee79 | 2017-03-22 16:59:53 -0700 | [diff] [blame] | 85 | extern "C" { |
| 86 | |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 87 | struct DvrSurface { |
| 88 | std::unique_ptr<Surface> surface; |
| 89 | }; |
| 90 | |
| 91 | int dvrSurfaceCreate(const DvrSurfaceAttribute* attributes, |
| 92 | size_t attribute_count, DvrSurface** out_surface) { |
Jiwen 'Steve' Cai | 74cf084 | 2017-03-23 18:53:16 -0700 | [diff] [blame] | 93 | if (out_surface == nullptr) { |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 94 | ALOGE("dvrSurfaceCreate: Invalid inputs: out_surface=%p.", out_surface); |
Jiwen 'Steve' Cai | 74cf084 | 2017-03-23 18:53:16 -0700 | [diff] [blame] | 95 | return -EINVAL; |
| 96 | } |
| 97 | |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 98 | size_t error_index; |
| 99 | SurfaceAttributes surface_attributes; |
| 100 | if (!ConvertSurfaceAttributes(attributes, attribute_count, |
| 101 | &surface_attributes, &error_index)) { |
| 102 | ALOGE("dvrSurfaceCreate: Invalid surface attribute type: %" PRIu64, |
| 103 | attributes[error_index].value.type); |
| 104 | return -EINVAL; |
Jiwen 'Steve' Cai | 74cf084 | 2017-03-23 18:53:16 -0700 | [diff] [blame] | 105 | } |
| 106 | |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 107 | auto status = Surface::CreateSurface(surface_attributes); |
| 108 | if (!status) { |
| 109 | ALOGE("dvrSurfaceCreate:: Failed to create display surface: %s", |
| 110 | status.GetErrorMessage().c_str()); |
| 111 | return -status.error(); |
| 112 | } |
Jiwen 'Steve' Cai | 74cf084 | 2017-03-23 18:53:16 -0700 | [diff] [blame] | 113 | |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 114 | *out_surface = new DvrSurface{status.take()}; |
Jiwen 'Steve' Cai | 74cf084 | 2017-03-23 18:53:16 -0700 | [diff] [blame] | 115 | return 0; |
| 116 | } |
| 117 | |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 118 | void dvrSurfaceDestroy(DvrSurface* surface) { delete surface; } |
| 119 | |
| 120 | int dvrSurfaceGetId(DvrSurface* surface) { |
| 121 | return surface->surface->surface_id(); |
| 122 | } |
| 123 | |
| 124 | int dvrSurfaceSetAttributes(DvrSurface* surface, |
| 125 | const DvrSurfaceAttribute* attributes, |
| 126 | size_t attribute_count) { |
| 127 | if (surface == nullptr || attributes == nullptr) { |
| 128 | ALOGE( |
| 129 | "dvrSurfaceSetAttributes: Invalid inputs: surface=%p attributes=%p " |
| 130 | "attribute_count=%zu", |
| 131 | surface, attributes, attribute_count); |
| 132 | return -EINVAL; |
| 133 | } |
| 134 | |
| 135 | size_t error_index; |
| 136 | SurfaceAttributes surface_attributes; |
| 137 | if (!ConvertSurfaceAttributes(attributes, attribute_count, |
| 138 | &surface_attributes, &error_index)) { |
| 139 | ALOGE("dvrSurfaceSetAttributes: Invalid surface attribute type: %" PRIu64, |
| 140 | attributes[error_index].value.type); |
| 141 | return -EINVAL; |
| 142 | } |
| 143 | |
| 144 | auto status = surface->surface->SetAttributes(surface_attributes); |
| 145 | if (!status) { |
| 146 | ALOGE("dvrSurfaceSetAttributes: Failed to set attributes: %s", |
| 147 | status.GetErrorMessage().c_str()); |
| 148 | return -status.error(); |
| 149 | } |
| 150 | |
| 151 | return 0; |
| 152 | } |
| 153 | |
| 154 | int dvrSurfaceCreateWriteBufferQueue(DvrSurface* surface, uint32_t width, |
| 155 | uint32_t height, uint32_t format, |
Hendrik Wagenaar | 108e84f | 2017-05-07 22:19:17 -0700 | [diff] [blame] | 156 | uint32_t layer_count, uint64_t usage, |
Jiwen 'Steve' Cai | 532e529 | 2017-06-02 15:36:44 -0700 | [diff] [blame] | 157 | size_t capacity, size_t metadata_size, |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 158 | DvrWriteBufferQueue** out_writer) { |
Jiwen 'Steve' Cai | 74cf084 | 2017-03-23 18:53:16 -0700 | [diff] [blame] | 159 | if (surface == nullptr || out_writer == nullptr) { |
| 160 | ALOGE( |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 161 | "dvrSurfaceCreateWriteBufferQueue: Invalid inputs: surface=%p, " |
Jiwen 'Steve' Cai | 74cf084 | 2017-03-23 18:53:16 -0700 | [diff] [blame] | 162 | "out_writer=%p.", |
| 163 | surface, out_writer); |
| 164 | return -EINVAL; |
| 165 | } |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 166 | |
Corey Tabaka | 99c2d73 | 2017-06-07 17:54:33 -0700 | [diff] [blame] | 167 | auto status = surface->surface->CreateQueue( |
| 168 | width, height, layer_count, format, usage, capacity, metadata_size); |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 169 | if (!status) { |
| 170 | ALOGE("dvrSurfaceCreateWriteBufferQueue: Failed to create queue: %s", |
| 171 | status.GetErrorMessage().c_str()); |
| 172 | return -status.error(); |
Jiwen 'Steve' Cai | 74cf084 | 2017-03-23 18:53:16 -0700 | [diff] [blame] | 173 | } |
| 174 | |
Jiwen 'Steve' Cai | 656f406 | 2017-05-22 13:02:33 -0700 | [diff] [blame] | 175 | *out_writer = new DvrWriteBufferQueue(status.take()); |
Jiwen 'Steve' Cai | 74cf084 | 2017-03-23 18:53:16 -0700 | [diff] [blame] | 176 | return 0; |
| 177 | } |
| 178 | |
Corey Tabaka | 99c2d73 | 2017-06-07 17:54:33 -0700 | [diff] [blame] | 179 | int dvrSetupGlobalBuffer(DvrGlobalBufferKey key, size_t size, uint64_t usage, |
| 180 | DvrBuffer** buffer_out) { |
| 181 | if (!buffer_out) |
| 182 | return -EINVAL; |
| 183 | |
| 184 | int error; |
| 185 | auto client = DisplayClient::Create(&error); |
Jiwen 'Steve' Cai | bdcee79 | 2017-03-22 16:59:53 -0700 | [diff] [blame] | 186 | if (!client) { |
Corey Tabaka | 99c2d73 | 2017-06-07 17:54:33 -0700 | [diff] [blame] | 187 | ALOGE("dvrSetupGlobalBuffer: Failed to create display client: %s", |
| 188 | strerror(-error)); |
| 189 | return error; |
Jiwen 'Steve' Cai | bdcee79 | 2017-03-22 16:59:53 -0700 | [diff] [blame] | 190 | } |
| 191 | |
Corey Tabaka | 99c2d73 | 2017-06-07 17:54:33 -0700 | [diff] [blame] | 192 | uint64_t gralloc_usage = AHardwareBuffer_convertToGrallocUsageBits(usage); |
| 193 | |
| 194 | auto buffer_status = client->SetupGlobalBuffer(key, size, gralloc_usage); |
| 195 | if (!buffer_status) { |
| 196 | ALOGE("dvrSetupGlobalBuffer: Failed to setup global buffer: %s", |
| 197 | buffer_status.GetErrorMessage().c_str()); |
| 198 | return -buffer_status.error(); |
| 199 | } |
| 200 | |
| 201 | *buffer_out = CreateDvrBufferFromIonBuffer(buffer_status.take()); |
| 202 | return 0; |
| 203 | } |
| 204 | |
| 205 | int dvrDeleteGlobalBuffer(DvrGlobalBufferKey key) { |
| 206 | int error; |
| 207 | auto client = DisplayClient::Create(&error); |
| 208 | if (!client) { |
| 209 | ALOGE("dvrDeleteGlobalBuffer: Failed to create display client: %s", |
| 210 | strerror(-error)); |
| 211 | return error; |
| 212 | } |
| 213 | |
| 214 | auto buffer_status = client->DeleteGlobalBuffer(key); |
| 215 | if (!buffer_status) { |
| 216 | ALOGE("dvrDeleteGlobalBuffer: Failed to delete named buffer: %s", |
| 217 | buffer_status.GetErrorMessage().c_str()); |
| 218 | return -buffer_status.error(); |
| 219 | } |
| 220 | |
| 221 | return 0; |
| 222 | } |
| 223 | |
| 224 | int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer) { |
| 225 | if (!out_buffer) |
Hendrik Wagenaar | eaa5522 | 2017-04-06 10:56:23 -0700 | [diff] [blame] | 226 | return -EINVAL; |
Corey Tabaka | 99c2d73 | 2017-06-07 17:54:33 -0700 | [diff] [blame] | 227 | |
| 228 | int error; |
| 229 | auto client = DisplayClient::Create(&error); |
| 230 | if (!client) { |
| 231 | ALOGE("dvrGetGlobalBuffer: Failed to create display client: %s", |
| 232 | strerror(-error)); |
| 233 | return error; |
Hendrik Wagenaar | eaa5522 | 2017-04-06 10:56:23 -0700 | [diff] [blame] | 234 | } |
| 235 | |
Okan Arikan | 36d2380 | 2017-05-15 15:20:39 -0700 | [diff] [blame] | 236 | auto status = client->GetGlobalBuffer(key); |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 237 | if (!status) { |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 238 | return -status.error(); |
Hendrik Wagenaar | eaa5522 | 2017-04-06 10:56:23 -0700 | [diff] [blame] | 239 | } |
Corey Tabaka | 2251d82 | 2017-04-20 16:04:07 -0700 | [diff] [blame] | 240 | *out_buffer = CreateDvrBufferFromIonBuffer(status.take()); |
Jiwen 'Steve' Cai | bdcee79 | 2017-03-22 16:59:53 -0700 | [diff] [blame] | 241 | return 0; |
| 242 | } |
| 243 | |
Stephen Kiazyk | c603331 | 2017-06-09 14:26:31 -0700 | [diff] [blame] | 244 | int dvrGetNativeDisplayMetrics(size_t sizeof_metrics, |
| 245 | DvrNativeDisplayMetrics* metrics) { |
| 246 | ALOGE_IF(sizeof_metrics != sizeof(DvrNativeDisplayMetrics), |
| 247 | "dvrGetNativeDisplayMetrics: metrics struct mismatch, your dvr api " |
| 248 | "header is out of date."); |
| 249 | |
| 250 | auto client = DisplayClient::Create(); |
| 251 | if (!client) { |
| 252 | ALOGE("dvrGetNativeDisplayMetrics: Failed to create display client!"); |
| 253 | return -ECOMM; |
| 254 | } |
| 255 | |
| 256 | if (metrics == nullptr) { |
| 257 | ALOGE("dvrGetNativeDisplayMetrics: output metrics buffer must be non-null"); |
| 258 | return -EINVAL; |
| 259 | } |
| 260 | |
| 261 | auto status = client->GetDisplayMetrics(); |
| 262 | |
| 263 | if (!status) { |
| 264 | return -status.error(); |
| 265 | } |
| 266 | |
| 267 | if (sizeof_metrics >= 20) { |
| 268 | metrics->display_width = status.get().display_width; |
| 269 | metrics->display_height = status.get().display_height; |
| 270 | metrics->display_x_dpi = status.get().display_x_dpi; |
| 271 | metrics->display_y_dpi = status.get().display_y_dpi; |
| 272 | metrics->vsync_period_ns = status.get().vsync_period_ns; |
| 273 | } |
| 274 | |
| 275 | return 0; |
| 276 | } |
| 277 | |
Jiwen 'Steve' Cai | bdcee79 | 2017-03-22 16:59:53 -0700 | [diff] [blame] | 278 | } // extern "C" |