1#include "include/private/dvr/buffer_hub_queue_producer.h" 2 3#include <dvr/dvr_api.h> 4#include <inttypes.h> 5#include <log/log.h> 6 7namespace android { 8namespace dvr { 9 10/* static */ 11sp<BufferHubQueueProducer> BufferHubQueueProducer::Create() { 12 sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer; 13 producer->queue_ = ProducerQueue::Create<DvrNativeBufferMetadata>(); 14 return producer; 15} 16 17/* static */ 18sp<BufferHubQueueProducer> BufferHubQueueProducer::Create( 19 const std::shared_ptr<ProducerQueue>& queue) { 20 if (queue->metadata_size() != sizeof(DvrNativeBufferMetadata)) { 21 ALOGE( 22 "BufferHubQueueProducer::Create producer's metadata size is different " 23 "than the size of DvrNativeBufferMetadata"); 24 return nullptr; 25 } 26 27 sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer; 28 producer->queue_ = queue; 29 return producer; 30} 31 32status_t BufferHubQueueProducer::requestBuffer(int slot, 33 sp<GraphicBuffer>* buf) { 34 ALOGD_IF(TRACE, "requestBuffer: slot=%d", slot); 35 36 std::unique_lock<std::mutex> lock(mutex_); 37 38 if (connected_api_ == kNoConnectedApi) { 39 ALOGE("requestBuffer: BufferHubQueueProducer has no connected producer"); 40 return NO_INIT; 41 } 42 43 if (slot < 0 || slot >= max_buffer_count_) { 44 ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot, 45 max_buffer_count_); 46 return BAD_VALUE; 47 } else if (!buffers_[slot].mBufferState.isDequeued()) { 48 ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)", 49 slot, buffers_[slot].mBufferState.string()); 50 return BAD_VALUE; 51 } else if (buffers_[slot].mGraphicBuffer != nullptr) { 52 ALOGE("requestBuffer: slot %d is not empty.", slot); 53 return BAD_VALUE; 54 } else if (buffers_[slot].mBufferProducer == nullptr) { 55 ALOGE("requestBuffer: slot %d is not dequeued.", slot); 56 return BAD_VALUE; 57 } 58 59 const auto& buffer_producer = buffers_[slot].mBufferProducer; 60 sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer(); 61 62 buffers_[slot].mGraphicBuffer = graphic_buffer; 63 buffers_[slot].mRequestBufferCalled = true; 64 65 *buf = graphic_buffer; 66 return NO_ERROR; 67} 68 69status_t BufferHubQueueProducer::setMaxDequeuedBufferCount( 70 int max_dequeued_buffers) { 71 ALOGD_IF(TRACE, "setMaxDequeuedBufferCount: max_dequeued_buffers=%d", 72 max_dequeued_buffers); 73 74 std::unique_lock<std::mutex> lock(mutex_); 75 76 if (max_dequeued_buffers <= 0 || 77 max_dequeued_buffers > 78 static_cast<int>(BufferHubQueue::kMaxQueueCapacity - 79 kDefaultUndequeuedBuffers)) { 80 ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]", 81 max_dequeued_buffers, BufferHubQueue::kMaxQueueCapacity); 82 return BAD_VALUE; 83 } 84 85 // The new dequeued_buffers count should not be violated by the number 86 // of currently dequeued buffers. 87 int dequeued_count = 0; 88 for (const auto& buf : buffers_) { 89 if (buf.mBufferState.isDequeued()) { 90 dequeued_count++; 91 } 92 } 93 if (dequeued_count > max_dequeued_buffers) { 94 ALOGE( 95 "setMaxDequeuedBufferCount: the requested dequeued_buffers" 96 "count (%d) exceeds the current dequeued buffer count (%d)", 97 max_dequeued_buffers, dequeued_count); 98 return BAD_VALUE; 99 } 100 101 max_dequeued_buffer_count_ = max_dequeued_buffers; 102 return NO_ERROR; 103} 104 105status_t BufferHubQueueProducer::setAsyncMode(bool async) { 106 if (async) { 107 // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer 108 // automatically and behaves differently from IGraphicBufferConsumer. Thus, 109 // android::BufferQueue's async mode (a.k.a. allocating an additional buffer 110 // to prevent dequeueBuffer from being blocking) technically does not apply 111 // here. 112 // 113 // In Daydream, non-blocking producer side dequeue is guaranteed by careful 114 // buffer consumer implementations. In another word, BufferHubQueue based 115 // dequeueBuffer should never block whether setAsyncMode(true) is set or 116 // not. 117 // 118 // See: IGraphicBufferProducer::setAsyncMode and 119 // BufferQueueProducer::setAsyncMode for more about original implementation. 120 ALOGW( 121 "BufferHubQueueProducer::setAsyncMode: BufferHubQueue should always be " 122 "asynchronous. This call makes no effact."); 123 return NO_ERROR; 124 } 125 return NO_ERROR; 126} 127 128status_t BufferHubQueueProducer::dequeueBuffer( 129 int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height, 130 PixelFormat format, uint32_t usage, 131 FrameEventHistoryDelta* /* out_timestamps */) { 132 ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%u", width, 133 height, format, usage); 134 135 status_t ret; 136 std::unique_lock<std::mutex> lock(mutex_); 137 138 if (connected_api_ == kNoConnectedApi) { 139 ALOGE("dequeueBuffer: BufferQueue has no connected producer"); 140 return NO_INIT; 141 } 142 143 const uint32_t kLayerCount = 1; 144 if (static_cast<int32_t>(queue_->capacity()) < 145 max_dequeued_buffer_count_ + kDefaultUndequeuedBuffers) { 146 // Lazy allocation. When the capacity of |queue_| has not reached 147 // |max_dequeued_buffer_count_|, allocate new buffer. 148 // TODO(jwcai) To save memory, the really reasonable thing to do is to go 149 // over existing slots and find first existing one to dequeue. 150 ret = AllocateBuffer(width, height, kLayerCount, format, usage); 151 if (ret < 0) 152 return ret; 153 } 154 155 size_t slot; 156 std::shared_ptr<BufferProducer> buffer_producer; 157 158 for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) { 159 LocalHandle fence; 160 auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence); 161 162 buffer_producer = buffer_status.take(); 163 if (!buffer_producer) 164 return NO_MEMORY; 165 166 if (width == buffer_producer->width() && 167 height == buffer_producer->height() && 168 static_cast<uint32_t>(format) == buffer_producer->format()) { 169 // The producer queue returns a buffer producer matches the request. 170 break; 171 } 172 173 // Needs reallocation. 174 // TODO(jwcai) Consider use VLOG instead if we find this log is not useful. 175 ALOGI( 176 "dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different " 177 "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need " 178 "re-allocattion.", 179 width, height, format, slot, buffer_producer->width(), 180 buffer_producer->height(), buffer_producer->format()); 181 // Mark the slot as reallocating, so that later we can set 182 // BUFFER_NEEDS_REALLOCATION when the buffer actually get dequeued. 183 buffers_[slot].mIsReallocating = true; 184 185 // Remove the old buffer once the allocation before allocating its 186 // replacement. 187 RemoveBuffer(slot); 188 189 // Allocate a new producer buffer with new buffer configs. Note that if 190 // there are already multiple buffers in the queue, the next one returned 191 // from |queue_->Dequeue| may not be the new buffer we just reallocated. 192 // Retry up to BufferHubQueue::kMaxQueueCapacity times. 193 ret = AllocateBuffer(width, height, kLayerCount, format, usage); 194 if (ret < 0) 195 return ret; 196 } 197 198 // With the BufferHub backed solution. Buffer slot returned from 199 // |queue_->Dequeue| is guaranteed to avaiable for producer's use. 200 // It's either in free state (if the buffer has never been used before) or 201 // in queued state (if the buffer has been dequeued and queued back to 202 // BufferHubQueue). 203 // TODO(jwcai) Clean this up, make mBufferState compatible with BufferHub's 204 // model. 205 LOG_ALWAYS_FATAL_IF((!buffers_[slot].mBufferState.isFree() && 206 !buffers_[slot].mBufferState.isQueued()), 207 "dequeueBuffer: slot %zu is not free or queued.", slot); 208 209 buffers_[slot].mBufferState.freeQueued(); 210 buffers_[slot].mBufferState.dequeue(); 211 ALOGD_IF(TRACE, "dequeueBuffer: slot=%zu", slot); 212 213 // TODO(jwcai) Handle fence properly. |BufferHub| has full fence support, we 214 // just need to exopose that through |BufferHubQueue| once we need fence. 215 *out_fence = Fence::NO_FENCE; 216 *out_slot = slot; 217 ret = NO_ERROR; 218 219 if (buffers_[slot].mIsReallocating) { 220 ret |= BUFFER_NEEDS_REALLOCATION; 221 buffers_[slot].mIsReallocating = false; 222 } 223 224 return ret; 225} 226 227status_t BufferHubQueueProducer::detachBuffer(int /* slot */) { 228 ALOGE("BufferHubQueueProducer::detachBuffer not implemented."); 229 return INVALID_OPERATION; 230} 231 232status_t BufferHubQueueProducer::detachNextBuffer( 233 sp<GraphicBuffer>* /* out_buffer */, sp<Fence>* /* out_fence */) { 234 ALOGE("BufferHubQueueProducer::detachNextBuffer not implemented."); 235 return INVALID_OPERATION; 236} 237 238status_t BufferHubQueueProducer::attachBuffer( 239 int* /* out_slot */, const sp<GraphicBuffer>& /* buffer */) { 240 // With this BufferHub backed implementation, we assume (for now) all buffers 241 // are allocated and owned by the BufferHub. Thus the attempt of transfering 242 // ownership of a buffer to the buffer queue is intentionally unsupported. 243 LOG_ALWAYS_FATAL("BufferHubQueueProducer::attachBuffer not supported."); 244 return INVALID_OPERATION; 245} 246 247status_t BufferHubQueueProducer::queueBuffer(int slot, 248 const QueueBufferInput& input, 249 QueueBufferOutput* output) { 250 ALOGD_IF(TRACE, "queueBuffer: slot %d", slot); 251 252 if (output == nullptr) { 253 return BAD_VALUE; 254 } 255 256 int64_t timestamp; 257 bool is_auto_timestamp; 258 android_dataspace dataspace; 259 Rect crop(Rect::EMPTY_RECT); 260 int scaling_mode; 261 uint32_t transform; 262 sp<Fence> fence; 263 264 input.deflate(×tamp, &is_auto_timestamp, &dataspace, &crop, 265 &scaling_mode, &transform, &fence); 266 267 // Check input scaling mode is valid. 268 switch (scaling_mode) { 269 case NATIVE_WINDOW_SCALING_MODE_FREEZE: 270 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: 271 case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: 272 case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: 273 break; 274 default: 275 ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode); 276 return BAD_VALUE; 277 } 278 279 // Check input fence is valid. 280 if (fence == nullptr) { 281 ALOGE("queueBuffer: fence is NULL"); 282 return BAD_VALUE; 283 } 284 285 status_t ret; 286 std::unique_lock<std::mutex> lock(mutex_); 287 288 if (connected_api_ == kNoConnectedApi) { 289 ALOGE("queueBuffer: BufferQueue has no connected producer"); 290 return NO_INIT; 291 } 292 293 if (slot < 0 || slot >= max_buffer_count_) { 294 ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot, 295 max_buffer_count_); 296 return BAD_VALUE; 297 } else if (!buffers_[slot].mBufferState.isDequeued()) { 298 ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)", 299 slot, buffers_[slot].mBufferState.string()); 300 return BAD_VALUE; 301 } else if ((!buffers_[slot].mRequestBufferCalled || 302 buffers_[slot].mGraphicBuffer == nullptr)) { 303 ALOGE( 304 "queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, " 305 "mGraphicBuffer=%p)", 306 slot, buffers_[slot].mRequestBufferCalled, 307 buffers_[slot].mGraphicBuffer.get()); 308 return BAD_VALUE; 309 } 310 311 // Post the buffer producer with timestamp in the metadata. 312 const auto& buffer_producer = buffers_[slot].mBufferProducer; 313 314 // Check input crop is not out of boundary of current buffer. 315 Rect buffer_rect(buffer_producer->width(), buffer_producer->height()); 316 Rect cropped_rect(Rect::EMPTY_RECT); 317 crop.intersect(buffer_rect, &cropped_rect); 318 if (cropped_rect != crop) { 319 ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot); 320 return BAD_VALUE; 321 } 322 323 LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1); 324 325 DvrNativeBufferMetadata meta_data = {}; 326 meta_data.timestamp = timestamp; 327 meta_data.is_auto_timestamp = static_cast<int32_t>(is_auto_timestamp); 328 meta_data.dataspace = static_cast<int32_t>(dataspace); 329 meta_data.crop_left = crop.left; 330 meta_data.crop_top = crop.top; 331 meta_data.crop_right = crop.right; 332 meta_data.crop_bottom = crop.bottom; 333 meta_data.scaling_mode = static_cast<int32_t>(scaling_mode); 334 meta_data.transform = static_cast<int32_t>(transform); 335 336 buffer_producer->Post(fence_fd, &meta_data, sizeof(meta_data)); 337 buffers_[slot].mBufferState.queue(); 338 339 output->width = buffer_producer->width(); 340 output->height = buffer_producer->height(); 341 output->transformHint = 0; // default value, we don't use it yet. 342 343 // |numPendingBuffers| counts of the number of buffers that has been enqueued 344 // by the producer but not yet acquired by the consumer. Due to the nature 345 // of BufferHubQueue design, this is hard to trace from the producer's client 346 // side, but it's safe to assume it's zero. 347 output->numPendingBuffers = 0; 348 349 // Note that we are not setting nextFrameNumber here as it seems to be only 350 // used by surface flinger. See more at b/22802885, ag/791760. 351 output->nextFrameNumber = 0; 352 353 return NO_ERROR; 354} 355 356status_t BufferHubQueueProducer::cancelBuffer(int slot, 357 const sp<Fence>& fence) { 358 ALOGD_IF(TRACE, __FUNCTION__); 359 360 std::unique_lock<std::mutex> lock(mutex_); 361 362 if (connected_api_ == kNoConnectedApi) { 363 ALOGE("cancelBuffer: BufferQueue has no connected producer"); 364 return NO_INIT; 365 } 366 367 if (slot < 0 || slot >= max_buffer_count_) { 368 ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, 369 max_buffer_count_); 370 return BAD_VALUE; 371 } else if (!buffers_[slot].mBufferState.isDequeued()) { 372 ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)", 373 slot, buffers_[slot].mBufferState.string()); 374 return BAD_VALUE; 375 } else if (fence == nullptr) { 376 ALOGE("cancelBuffer: fence is NULL"); 377 return BAD_VALUE; 378 } 379 380 auto buffer_producer = buffers_[slot].mBufferProducer; 381 queue_->Enqueue(buffer_producer, slot); 382 buffers_[slot].mBufferState.cancel(); 383 buffers_[slot].mFence = fence; 384 ALOGD_IF(TRACE, "cancelBuffer: slot %d", slot); 385 386 return NO_ERROR; 387} 388 389status_t BufferHubQueueProducer::query(int what, int* out_value) { 390 ALOGD_IF(TRACE, __FUNCTION__); 391 392 std::unique_lock<std::mutex> lock(mutex_); 393 394 if (out_value == nullptr) { 395 ALOGE("query: out_value was NULL"); 396 return BAD_VALUE; 397 } 398 399 int value = 0; 400 switch (what) { 401 case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: 402 // TODO(b/36187402) This should be the maximum number of buffers that this 403 // producer queue's consumer can acquire. Set to be at least one. Need to 404 // find a way to set from the consumer side. 405 value = kDefaultUndequeuedBuffers; 406 break; 407 case NATIVE_WINDOW_BUFFER_AGE: 408 value = 0; 409 break; 410 case NATIVE_WINDOW_WIDTH: 411 value = queue_->default_width(); 412 break; 413 case NATIVE_WINDOW_HEIGHT: 414 value = queue_->default_height(); 415 break; 416 case NATIVE_WINDOW_FORMAT: 417 value = queue_->default_format(); 418 break; 419 case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: 420 // BufferHubQueue is always operating in async mode, thus semantically 421 // consumer can never be running behind. See BufferQueueCore.cpp core 422 // for more information about the original meaning of this flag. 423 value = 0; 424 break; 425 case NATIVE_WINDOW_CONSUMER_USAGE_BITS: 426 // TODO(jwcai) This is currently not implement as we don't need 427 // IGraphicBufferConsumer parity. 428 value = 0; 429 break; 430 case NATIVE_WINDOW_DEFAULT_DATASPACE: 431 // TODO(jwcai) Return the default value android::BufferQueue is using as 432 // there is no way dvr::ConsumerQueue can set it. 433 value = 0; // HAL_DATASPACE_UNKNOWN 434 break; 435 case NATIVE_WINDOW_STICKY_TRANSFORM: 436 // TODO(jwcai) Return the default value android::BufferQueue is using as 437 // there is no way dvr::ConsumerQueue can set it. 438 value = 0; 439 break; 440 case NATIVE_WINDOW_CONSUMER_IS_PROTECTED: 441 // In Daydream's implementation, the consumer end (i.e. VR Compostior) 442 // knows how to handle protected buffers. 443 value = 1; 444 break; 445 default: 446 return BAD_VALUE; 447 } 448 449 ALOGD_IF(TRACE, "query: key=%d, v=%d", what, value); 450 *out_value = value; 451 return NO_ERROR; 452} 453 454status_t BufferHubQueueProducer::connect( 455 const sp<IProducerListener>& /* listener */, int api, 456 bool /* producer_controlled_by_app */, QueueBufferOutput* output) { 457 // Consumer interaction are actually handled by buffer hub, and we need 458 // to maintain consumer operations here. We only need to perform basic input 459 // parameter checks here. 460 ALOGD_IF(TRACE, __FUNCTION__); 461 462 if (output == nullptr) { 463 return BAD_VALUE; 464 } 465 466 std::unique_lock<std::mutex> lock(mutex_); 467 468 if (connected_api_ != kNoConnectedApi) { 469 return BAD_VALUE; 470 } 471 472 switch (api) { 473 case NATIVE_WINDOW_API_EGL: 474 case NATIVE_WINDOW_API_CPU: 475 case NATIVE_WINDOW_API_MEDIA: 476 case NATIVE_WINDOW_API_CAMERA: 477 connected_api_ = api; 478 479 output->width = queue_->default_width(); 480 output->height = queue_->default_height(); 481 482 // default values, we don't use them yet. 483 output->transformHint = 0; 484 output->numPendingBuffers = 0; 485 output->nextFrameNumber = 0; 486 output->bufferReplaced = false; 487 488 break; 489 default: 490 ALOGE("BufferHubQueueProducer::connect: unknow API %d", api); 491 return BAD_VALUE; 492 } 493 494 return NO_ERROR; 495} 496 497status_t BufferHubQueueProducer::disconnect(int api, DisconnectMode /*mode*/) { 498 // Consumer interaction are actually handled by buffer hub, and we need 499 // to maintain consumer operations here. We only need to perform basic input 500 // parameter checks here. 501 ALOGD_IF(TRACE, __FUNCTION__); 502 503 std::unique_lock<std::mutex> lock(mutex_); 504 505 if (kNoConnectedApi == connected_api_) { 506 return NO_INIT; 507 } else if (api != connected_api_) { 508 return BAD_VALUE; 509 } 510 511 connected_api_ = kNoConnectedApi; 512 return NO_ERROR; 513} 514 515status_t BufferHubQueueProducer::setSidebandStream( 516 const sp<NativeHandle>& stream) { 517 if (stream != nullptr) { 518 // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's 519 // metadata. 520 ALOGE("SidebandStream is not currently supported."); 521 return INVALID_OPERATION; 522 } 523 return NO_ERROR; 524} 525 526void BufferHubQueueProducer::allocateBuffers(uint32_t /* width */, 527 uint32_t /* height */, 528 PixelFormat /* format */, 529 uint32_t /* usage */) { 530 // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number 531 // of buffers permitted by the current BufferQueue configuration (aka 532 // |max_buffer_count_|). 533 ALOGE("BufferHubQueueProducer::allocateBuffers not implemented."); 534} 535 536status_t BufferHubQueueProducer::allowAllocation(bool /* allow */) { 537 ALOGE("BufferHubQueueProducer::allowAllocation not implemented."); 538 return INVALID_OPERATION; 539} 540 541status_t BufferHubQueueProducer::setGenerationNumber( 542 uint32_t generation_number) { 543 ALOGD_IF(TRACE, __FUNCTION__); 544 545 std::unique_lock<std::mutex> lock(mutex_); 546 generation_number_ = generation_number; 547 return NO_ERROR; 548} 549 550String8 BufferHubQueueProducer::getConsumerName() const { 551 // BufferHub based implementation could have one to many producer/consumer 552 // relationship, thus |getConsumerName| from the producer side does not 553 // make any sense. 554 ALOGE("BufferHubQueueProducer::getConsumerName not supported."); 555 return String8("BufferHubQueue::DummyConsumer"); 556} 557 558status_t BufferHubQueueProducer::setSharedBufferMode(bool shared_buffer_mode) { 559 if (shared_buffer_mode) { 560 ALOGE( 561 "BufferHubQueueProducer::setSharedBufferMode(true) is not supported."); 562 // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow. 563 return INVALID_OPERATION; 564 } 565 // Setting to default should just work as a no-op. 566 return NO_ERROR; 567} 568 569status_t BufferHubQueueProducer::setAutoRefresh(bool auto_refresh) { 570 if (auto_refresh) { 571 ALOGE("BufferHubQueueProducer::setAutoRefresh(true) is not supported."); 572 return INVALID_OPERATION; 573 } 574 // Setting to default should just work as a no-op. 575 return NO_ERROR; 576} 577 578status_t BufferHubQueueProducer::setDequeueTimeout(nsecs_t timeout) { 579 ALOGD_IF(TRACE, __FUNCTION__); 580 581 std::unique_lock<std::mutex> lock(mutex_); 582 dequeue_timeout_ms_ = static_cast<int>(timeout / (1000 * 1000)); 583 return NO_ERROR; 584} 585 586status_t BufferHubQueueProducer::getLastQueuedBuffer( 587 sp<GraphicBuffer>* /* out_buffer */, sp<Fence>* /* out_fence */, 588 float /*out_transform_matrix*/[16]) { 589 ALOGE("BufferHubQueueProducer::getLastQueuedBuffer not implemented."); 590 return INVALID_OPERATION; 591} 592 593void BufferHubQueueProducer::getFrameTimestamps( 594 FrameEventHistoryDelta* /*outDelta*/) { 595 ALOGE("BufferHubQueueProducer::getFrameTimestamps not implemented."); 596} 597 598status_t BufferHubQueueProducer::getUniqueId(uint64_t* out_id) const { 599 ALOGD_IF(TRACE, __FUNCTION__); 600 601 *out_id = unique_id_; 602 return NO_ERROR; 603} 604 605status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height, 606 uint32_t layer_count, 607 PixelFormat format, 608 uint64_t usage) { 609 size_t slot; 610 611 if (queue_->AllocateBuffer(width, height, layer_count, format, usage, &slot) < 612 0) { 613 ALOGE("Failed to allocate new buffer in BufferHub."); 614 return NO_MEMORY; 615 } 616 617 auto buffer_producer = queue_->GetBuffer(slot); 618 619 LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr, 620 "Failed to get buffer producer at slot: %zu", slot); 621 622 buffers_[slot].mBufferProducer = buffer_producer; 623 624 return NO_ERROR; 625} 626 627status_t BufferHubQueueProducer::RemoveBuffer(size_t slot) { 628 int ret = queue_->DetachBuffer(slot); 629 if (ret < 0) { 630 ALOGE("BufferHubQueueProducer::RemoveBuffer failed through RPC, ret=%s", 631 strerror(-ret)); 632 return ret; 633 } 634 635 // Reset in memory objects related the the buffer. 636 buffers_[slot].mBufferProducer = nullptr; 637 buffers_[slot].mGraphicBuffer = nullptr; 638 buffers_[slot].mBufferState.detachProducer(); 639 return NO_ERROR; 640} 641 642} // namespace dvr 643} // namespace android 644