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