1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //#define LOG_NDEBUG 0 18 #define LOG_TAG "C2BqBuffer" 19 #include <utils/Log.h> 20 21 #include <ui/BufferQueueDefs.h> 22 #include <ui/GraphicBuffer.h> 23 #include <ui/Fence.h> 24 25 #include <types.h> 26 27 #include <hidl/HidlSupport.h> 28 29 #include <C2AllocatorGralloc.h> 30 #include <C2BqBufferPriv.h> 31 #include <C2BlockInternal.h> 32 33 #include <list> 34 #include <map> 35 #include <mutex> 36 37 using ::android::BufferQueueDefs::NUM_BUFFER_SLOTS; 38 using ::android::C2AllocatorGralloc; 39 using ::android::C2AndroidMemoryUsage; 40 using ::android::Fence; 41 using ::android::GraphicBuffer; 42 using ::android::sp; 43 using ::android::status_t; 44 using ::android::wp; 45 using ::android::hardware::hidl_handle; 46 using ::android::hardware::Return; 47 48 using HBuffer = ::android::hardware::graphics::common::V1_2::HardwareBuffer; 49 using HStatus = ::android::hardware::graphics::bufferqueue::V2_0::Status; 50 using ::android::hardware::graphics::bufferqueue::V2_0::utils::b2h; 51 using ::android::hardware::graphics::bufferqueue::V2_0::utils::h2b; 52 using ::android::hardware::graphics::bufferqueue::V2_0::utils::HFenceWrapper; 53 54 using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::V2_0 55 ::IGraphicBufferProducer; 56 57 struct C2BufferQueueBlockPoolData : public _C2BlockPoolData { 58 59 bool held; 60 bool local; 61 uint32_t generation; 62 uint64_t bqId; 63 int32_t bqSlot; 64 bool transfer; // local transfer to remote 65 bool attach; // attach on remote 66 bool display; // display on remote; 67 std::weak_ptr<int> owner; 68 sp<HGraphicBufferProducer> igbp; 69 std::shared_ptr<C2BufferQueueBlockPool::Impl> localPool; 70 mutable std::mutex lock; 71 72 virtual type_t getType() const override { 73 return TYPE_BUFFERQUEUE; 74 } 75 76 // Create a remote BlockPoolData. 77 C2BufferQueueBlockPoolData( 78 uint32_t generation, uint64_t bqId, int32_t bqSlot, 79 const std::shared_ptr<int> &owner, 80 const sp<HGraphicBufferProducer>& producer); 81 82 // Create a local BlockPoolData. 83 C2BufferQueueBlockPoolData( 84 uint32_t generation, uint64_t bqId, int32_t bqSlot, 85 const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool); 86 87 virtual ~C2BufferQueueBlockPoolData() override; 88 89 int migrate(const sp<HGraphicBufferProducer>& producer, 90 uint32_t toGeneration, uint64_t toBqId, 91 sp<GraphicBuffer> *buffers, uint32_t oldGeneration); 92 }; 93 94 bool _C2BlockFactory::GetBufferQueueData( 95 const std::shared_ptr<const _C2BlockPoolData>& data, 96 uint32_t* generation, uint64_t* bqId, int32_t* bqSlot) { 97 if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERQUEUE) { 98 if (generation) { 99 const std::shared_ptr<const C2BufferQueueBlockPoolData> poolData = 100 std::static_pointer_cast<const C2BufferQueueBlockPoolData>(data); 101 std::scoped_lock<std::mutex> lock(poolData->lock); 102 *generation = poolData->generation; 103 if (bqId) { 104 *bqId = poolData->bqId; 105 } 106 if (bqSlot) { 107 *bqSlot = poolData->bqSlot; 108 } 109 } 110 return true; 111 } 112 return false; 113 } 114 115 bool _C2BlockFactory::HoldBlockFromBufferQueue( 116 const std::shared_ptr<_C2BlockPoolData>& data, 117 const std::shared_ptr<int>& owner, 118 const sp<HGraphicBufferProducer>& igbp) { 119 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 120 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data); 121 std::scoped_lock<std::mutex> lock(poolData->lock); 122 if (!poolData->local) { 123 poolData->owner = owner; 124 poolData->igbp = igbp; 125 } 126 if (poolData->held) { 127 poolData->held = true; 128 return false; 129 } 130 poolData->held = true; 131 return true; 132 } 133 134 bool _C2BlockFactory::BeginTransferBlockToClient( 135 const std::shared_ptr<_C2BlockPoolData>& data) { 136 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 137 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data); 138 std::scoped_lock<std::mutex> lock(poolData->lock); 139 poolData->transfer = true; 140 return true; 141 } 142 143 bool _C2BlockFactory::EndTransferBlockToClient( 144 const std::shared_ptr<_C2BlockPoolData>& data, 145 bool transfer) { 146 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 147 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data); 148 std::scoped_lock<std::mutex> lock(poolData->lock); 149 poolData->transfer = false; 150 if (transfer) { 151 poolData->held = false; 152 } 153 return true; 154 } 155 156 bool _C2BlockFactory::BeginAttachBlockToBufferQueue( 157 const std::shared_ptr<_C2BlockPoolData>& data) { 158 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 159 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data); 160 std::scoped_lock<std::mutex> lock(poolData->lock); 161 if (poolData->local || poolData->display || 162 poolData->attach || !poolData->held) { 163 return false; 164 } 165 if (poolData->bqId == 0) { 166 return false; 167 } 168 poolData->attach = true; 169 return true; 170 } 171 172 // if display was tried during attach, buffer should be retired ASAP. 173 bool _C2BlockFactory::EndAttachBlockToBufferQueue( 174 const std::shared_ptr<_C2BlockPoolData>& data, 175 const std::shared_ptr<int>& owner, 176 const sp<HGraphicBufferProducer>& igbp, 177 uint32_t generation, 178 uint64_t bqId, 179 int32_t bqSlot) { 180 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 181 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data); 182 std::scoped_lock<std::mutex> lock(poolData->lock); 183 if (poolData->local || !poolData->attach ) { 184 return false; 185 } 186 if (poolData->display) { 187 poolData->attach = false; 188 poolData->held = false; 189 return false; 190 } 191 poolData->attach = false; 192 poolData->held = true; 193 poolData->owner = owner; 194 poolData->igbp = igbp; 195 poolData->generation = generation; 196 poolData->bqId = bqId; 197 poolData->bqSlot = bqSlot; 198 return true; 199 } 200 201 bool _C2BlockFactory::DisplayBlockToBufferQueue( 202 const std::shared_ptr<_C2BlockPoolData>& data) { 203 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 204 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data); 205 std::scoped_lock<std::mutex> lock(poolData->lock); 206 if (poolData->local || poolData->display || !poolData->held) { 207 return false; 208 } 209 if (poolData->bqId == 0) { 210 return false; 211 } 212 poolData->display = true; 213 if (poolData->attach) { 214 return false; 215 } 216 poolData->held = false; 217 return true; 218 } 219 220 std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock( 221 const C2Handle *handle) { 222 // TODO: get proper allocator? and mutex? 223 static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0); 224 225 std::shared_ptr<C2GraphicAllocation> alloc; 226 if (C2AllocatorGralloc::isValid(handle)) { 227 uint32_t width; 228 uint32_t height; 229 uint32_t format; 230 uint64_t usage; 231 uint32_t stride; 232 uint32_t generation; 233 uint64_t bqId; 234 uint32_t bqSlot; 235 android::_UnwrapNativeCodec2GrallocMetadata( 236 handle, &width, &height, &format, &usage, &stride, &generation, &bqId, &bqSlot); 237 c2_status_t err = sAllocator->priorGraphicAllocation(handle, &alloc); 238 if (err == C2_OK) { 239 std::shared_ptr<C2GraphicBlock> block; 240 if (bqId || bqSlot) { 241 // BQBBP 242 std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 243 std::make_shared<C2BufferQueueBlockPoolData>(generation, 244 bqId, 245 (int32_t)bqSlot, 246 nullptr, 247 nullptr); 248 block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData); 249 } else { 250 block = _C2BlockFactory::CreateGraphicBlock(alloc); 251 } 252 return block; 253 } 254 } 255 return nullptr; 256 } 257 258 namespace { 259 260 int64_t getTimestampNow() { 261 int64_t stamp; 262 struct timespec ts; 263 // TODO: CLOCK_MONOTONIC_COARSE? 264 clock_gettime(CLOCK_MONOTONIC, &ts); 265 stamp = ts.tv_nsec / 1000; 266 stamp += (ts.tv_sec * 1000000LL); 267 return stamp; 268 } 269 270 bool getGenerationNumber(const sp<HGraphicBufferProducer> &producer, 271 uint32_t *generation) { 272 status_t status{}; 273 int slot{}; 274 bool bufferNeedsReallocation{}; 275 sp<Fence> fence = new Fence(); 276 277 using Input = HGraphicBufferProducer::DequeueBufferInput; 278 using Output = HGraphicBufferProducer::DequeueBufferOutput; 279 Return<void> transResult = producer->dequeueBuffer( 280 Input{640, 480, HAL_PIXEL_FORMAT_YCBCR_420_888, 0}, 281 [&status, &slot, &bufferNeedsReallocation, &fence] 282 (HStatus hStatus, int32_t hSlot, Output const& hOutput) { 283 slot = static_cast<int>(hSlot); 284 if (!h2b(hStatus, &status) || !h2b(hOutput.fence, &fence)) { 285 status = ::android::BAD_VALUE; 286 } else { 287 bufferNeedsReallocation = 288 hOutput.bufferNeedsReallocation; 289 } 290 }); 291 if (!transResult.isOk() || status != android::OK) { 292 return false; 293 } 294 HFenceWrapper hFenceWrapper{}; 295 if (!b2h(fence, &hFenceWrapper)) { 296 (void)producer->detachBuffer(static_cast<int32_t>(slot)).isOk(); 297 ALOGE("Invalid fence received from dequeueBuffer."); 298 return false; 299 } 300 sp<GraphicBuffer> slotBuffer = new GraphicBuffer(); 301 // N.B. This assumes requestBuffer# returns an existing allocation 302 // instead of a new allocation. 303 transResult = producer->requestBuffer( 304 slot, 305 [&status, &slotBuffer, &generation]( 306 HStatus hStatus, 307 HBuffer const& hBuffer, 308 uint32_t generationNumber){ 309 if (h2b(hStatus, &status) && 310 h2b(hBuffer, &slotBuffer) && 311 slotBuffer) { 312 *generation = generationNumber; 313 slotBuffer->setGenerationNumber(generationNumber); 314 } else { 315 status = android::BAD_VALUE; 316 } 317 }); 318 if (!transResult.isOk()) { 319 return false; 320 } else if (status != android::NO_ERROR) { 321 (void)producer->detachBuffer(static_cast<int32_t>(slot)).isOk(); 322 return false; 323 } 324 (void)producer->detachBuffer(static_cast<int32_t>(slot)).isOk(); 325 return true; 326 } 327 328 }; 329 330 class C2BufferQueueBlockPool::Impl 331 : public std::enable_shared_from_this<C2BufferQueueBlockPool::Impl> { 332 private: 333 c2_status_t fetchFromIgbp_l( 334 uint32_t width, 335 uint32_t height, 336 uint32_t format, 337 C2MemoryUsage usage, 338 std::shared_ptr<C2GraphicBlock> *block /* nonnull */) { 339 // We have an IGBP now. 340 C2AndroidMemoryUsage androidUsage = usage; 341 status_t status{}; 342 int slot{}; 343 bool bufferNeedsReallocation{}; 344 sp<Fence> fence = new Fence(); 345 ALOGV("tries to dequeue buffer"); 346 347 { // Call dequeueBuffer(). 348 using Input = HGraphicBufferProducer::DequeueBufferInput; 349 using Output = HGraphicBufferProducer::DequeueBufferOutput; 350 Return<void> transResult = mProducer->dequeueBuffer( 351 Input{ 352 width, 353 height, 354 format, 355 androidUsage.asGrallocUsage()}, 356 [&status, &slot, &bufferNeedsReallocation, 357 &fence](HStatus hStatus, 358 int32_t hSlot, 359 Output const& hOutput) { 360 slot = static_cast<int>(hSlot); 361 if (!h2b(hStatus, &status) || 362 !h2b(hOutput.fence, &fence)) { 363 status = ::android::BAD_VALUE; 364 } else { 365 bufferNeedsReallocation = 366 hOutput.bufferNeedsReallocation; 367 } 368 }); 369 if (!transResult.isOk() || status != android::OK) { 370 if (transResult.isOk()) { 371 ++mDqFailure; 372 if (status == android::INVALID_OPERATION || 373 status == android::TIMED_OUT || 374 status == android::WOULD_BLOCK) { 375 // Dequeue buffer is blocked temporarily. Retrying is 376 // required. 377 return C2_BLOCKING; 378 } 379 } 380 ALOGD("cannot dequeue buffer %d", status); 381 return C2_BAD_VALUE; 382 } 383 mDqFailure = 0; 384 mLastDqTs = getTimestampNow(); 385 } 386 HFenceWrapper hFenceWrapper{}; 387 if (!b2h(fence, &hFenceWrapper)) { 388 ALOGE("Invalid fence received from dequeueBuffer."); 389 return C2_BAD_VALUE; 390 } 391 ALOGV("dequeued a buffer successfully"); 392 if (fence) { 393 static constexpr int kFenceWaitTimeMs = 10; 394 395 status_t status = fence->wait(kFenceWaitTimeMs); 396 if (status == -ETIME) { 397 // fence is not signalled yet. 398 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk(); 399 return C2_BLOCKING; 400 } 401 if (status != android::NO_ERROR) { 402 ALOGD("buffer fence wait error %d", status); 403 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk(); 404 return C2_BAD_VALUE; 405 } else if (mRenderCallback) { 406 nsecs_t signalTime = fence->getSignalTime(); 407 if (signalTime >= 0 && signalTime < INT64_MAX) { 408 mRenderCallback(mProducerId, slot, signalTime); 409 } else { 410 ALOGV("got fence signal time of %lld", (long long)signalTime); 411 } 412 } 413 } 414 415 sp<GraphicBuffer> &slotBuffer = mBuffers[slot]; 416 uint32_t outGeneration; 417 if (bufferNeedsReallocation || !slotBuffer) { 418 if (!slotBuffer) { 419 slotBuffer = new GraphicBuffer(); 420 } 421 // N.B. This assumes requestBuffer# returns an existing allocation 422 // instead of a new allocation. 423 Return<void> transResult = mProducer->requestBuffer( 424 slot, 425 [&status, &slotBuffer, &outGeneration]( 426 HStatus hStatus, 427 HBuffer const& hBuffer, 428 uint32_t generationNumber){ 429 if (h2b(hStatus, &status) && 430 h2b(hBuffer, &slotBuffer) && 431 slotBuffer) { 432 slotBuffer->setGenerationNumber(generationNumber); 433 outGeneration = generationNumber; 434 } else { 435 status = android::BAD_VALUE; 436 } 437 }); 438 if (!transResult.isOk()) { 439 slotBuffer.clear(); 440 return C2_BAD_VALUE; 441 } else if (status != android::NO_ERROR) { 442 slotBuffer.clear(); 443 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk(); 444 return C2_BAD_VALUE; 445 } 446 if (mGeneration == 0) { 447 // getting generation # lazily due to dequeue failure. 448 mGeneration = outGeneration; 449 } 450 } 451 if (slotBuffer) { 452 ALOGV("buffer wraps %llu %d", (unsigned long long)mProducerId, slot); 453 C2Handle *c2Handle = android::WrapNativeCodec2GrallocHandle( 454 slotBuffer->handle, 455 slotBuffer->width, 456 slotBuffer->height, 457 slotBuffer->format, 458 slotBuffer->usage, 459 slotBuffer->stride, 460 slotBuffer->getGenerationNumber(), 461 mProducerId, slot); 462 if (c2Handle) { 463 std::shared_ptr<C2GraphicAllocation> alloc; 464 c2_status_t err = mAllocator->priorGraphicAllocation(c2Handle, &alloc); 465 if (err != C2_OK) { 466 return err; 467 } 468 std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 469 std::make_shared<C2BufferQueueBlockPoolData>( 470 slotBuffer->getGenerationNumber(), 471 mProducerId, slot, 472 shared_from_this()); 473 mPoolDatas[slot] = poolData; 474 *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData); 475 return C2_OK; 476 } 477 // Block was not created. call requestBuffer# again next time. 478 slotBuffer.clear(); 479 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk(); 480 } 481 return C2_BAD_VALUE; 482 } 483 484 public: 485 Impl(const std::shared_ptr<C2Allocator> &allocator) 486 : mInit(C2_OK), mProducerId(0), mGeneration(0), 487 mDqFailure(0), mLastDqTs(0), mLastDqLogTs(0), 488 mAllocator(allocator) { 489 } 490 491 ~Impl() { 492 bool noInit = false; 493 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) { 494 if (!noInit && mProducer) { 495 Return<HStatus> transResult = 496 mProducer->detachBuffer(static_cast<int32_t>(i)); 497 noInit = !transResult.isOk() || 498 static_cast<HStatus>(transResult) == HStatus::NO_INIT; 499 } 500 mBuffers[i].clear(); 501 } 502 } 503 504 c2_status_t fetchGraphicBlock( 505 uint32_t width, 506 uint32_t height, 507 uint32_t format, 508 C2MemoryUsage usage, 509 std::shared_ptr<C2GraphicBlock> *block /* nonnull */) { 510 block->reset(); 511 if (mInit != C2_OK) { 512 return mInit; 513 } 514 515 static int kMaxIgbpRetryDelayUs = 10000; 516 517 std::unique_lock<std::mutex> lock(mMutex); 518 if (mLastDqLogTs == 0) { 519 mLastDqLogTs = getTimestampNow(); 520 } else { 521 int64_t now = getTimestampNow(); 522 if (now >= mLastDqLogTs + 5000000) { 523 if (now >= mLastDqTs + 1000000 || mDqFailure > 5) { 524 ALOGW("last successful dequeue was %lld us ago, " 525 "%zu consecutive failures", 526 (long long)(now - mLastDqTs), mDqFailure); 527 } 528 mLastDqLogTs = now; 529 } 530 } 531 if (mProducerId == 0) { 532 std::shared_ptr<C2GraphicAllocation> alloc; 533 c2_status_t err = mAllocator->newGraphicAllocation( 534 width, height, format, usage, &alloc); 535 if (err != C2_OK) { 536 return err; 537 } 538 std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 539 std::make_shared<C2BufferQueueBlockPoolData>( 540 0, (uint64_t)0, ~0, shared_from_this()); 541 *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData); 542 ALOGV("allocated a buffer successfully"); 543 544 return C2_OK; 545 } 546 c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block); 547 if (status == C2_BLOCKING) { 548 lock.unlock(); 549 // in order not to drain cpu from component's spinning 550 ::usleep(kMaxIgbpRetryDelayUs); 551 } 552 return status; 553 } 554 555 void setRenderCallback(const OnRenderCallback &renderCallback) { 556 std::scoped_lock<std::mutex> lock(mMutex); 557 mRenderCallback = renderCallback; 558 } 559 560 void configureProducer(const sp<HGraphicBufferProducer> &producer) { 561 uint64_t producerId = 0; 562 uint32_t generation = 0; 563 bool haveGeneration = false; 564 if (producer) { 565 Return<uint64_t> transResult = producer->getUniqueId(); 566 if (!transResult.isOk()) { 567 ALOGD("configureProducer -- failed to connect to the producer"); 568 return; 569 } 570 producerId = static_cast<uint64_t>(transResult); 571 // TODO: provide gneration number from parameter. 572 haveGeneration = getGenerationNumber(producer, &generation); 573 if (!haveGeneration) { 574 ALOGW("get generationNumber failed %llu", 575 (unsigned long long)producerId); 576 } 577 } 578 int migrated = 0; 579 { 580 sp<GraphicBuffer> buffers[NUM_BUFFER_SLOTS]; 581 std::weak_ptr<C2BufferQueueBlockPoolData> 582 poolDatas[NUM_BUFFER_SLOTS]; 583 std::scoped_lock<std::mutex> lock(mMutex); 584 bool noInit = false; 585 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) { 586 if (!noInit && mProducer) { 587 Return<HStatus> transResult = 588 mProducer->detachBuffer(static_cast<int32_t>(i)); 589 noInit = !transResult.isOk() || 590 static_cast<HStatus>(transResult) == HStatus::NO_INIT; 591 } 592 } 593 int32_t oldGeneration = mGeneration; 594 if (producer) { 595 mProducer = producer; 596 mProducerId = producerId; 597 mGeneration = haveGeneration ? generation : 0; 598 } else { 599 mProducer = nullptr; 600 mProducerId = 0; 601 mGeneration = 0; 602 ALOGW("invalid producer producer(%d), generation(%d)", 603 (bool)producer, haveGeneration); 604 } 605 if (mProducer && haveGeneration) { // migrate buffers 606 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) { 607 std::shared_ptr<C2BufferQueueBlockPoolData> data = 608 mPoolDatas[i].lock(); 609 if (data) { 610 int slot = data->migrate( 611 mProducer, generation, 612 producerId, mBuffers, oldGeneration); 613 if (slot >= 0) { 614 buffers[slot] = mBuffers[i]; 615 poolDatas[slot] = data; 616 ++migrated; 617 } 618 } 619 } 620 } 621 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) { 622 mBuffers[i] = buffers[i]; 623 mPoolDatas[i] = poolDatas[i]; 624 } 625 } 626 if (producer && haveGeneration) { 627 ALOGD("local generation change %u , " 628 "bqId: %llu migrated buffers # %d", 629 generation, (unsigned long long)producerId, migrated); 630 } 631 } 632 633 private: 634 friend struct C2BufferQueueBlockPoolData; 635 636 void cancel(uint32_t generation, uint64_t igbp_id, int32_t igbp_slot) { 637 bool cancelled = false; 638 { 639 std::scoped_lock<std::mutex> lock(mMutex); 640 if (generation == mGeneration && igbp_id == mProducerId && mProducer) { 641 (void)mProducer->cancelBuffer(igbp_slot, hidl_handle{}).isOk(); 642 cancelled = true; 643 } 644 } 645 } 646 647 c2_status_t mInit; 648 uint64_t mProducerId; 649 uint32_t mGeneration; 650 OnRenderCallback mRenderCallback; 651 652 size_t mDqFailure; 653 int64_t mLastDqTs; 654 int64_t mLastDqLogTs; 655 656 const std::shared_ptr<C2Allocator> mAllocator; 657 658 std::mutex mMutex; 659 sp<HGraphicBufferProducer> mProducer; 660 sp<HGraphicBufferProducer> mSavedProducer; 661 662 sp<GraphicBuffer> mBuffers[NUM_BUFFER_SLOTS]; 663 std::weak_ptr<C2BufferQueueBlockPoolData> mPoolDatas[NUM_BUFFER_SLOTS]; 664 }; 665 666 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData( 667 uint32_t generation, uint64_t bqId, int32_t bqSlot, 668 const std::shared_ptr<int>& owner, 669 const sp<HGraphicBufferProducer>& producer) : 670 held(producer && bqId != 0), local(false), 671 generation(generation), bqId(bqId), bqSlot(bqSlot), 672 transfer(false), attach(false), display(false), 673 owner(owner), igbp(producer), 674 localPool() { 675 } 676 677 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData( 678 uint32_t generation, uint64_t bqId, int32_t bqSlot, 679 const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool) : 680 held(true), local(true), 681 generation(generation), bqId(bqId), bqSlot(bqSlot), 682 transfer(false), attach(false), display(false), 683 igbp(pool ? pool->mProducer : nullptr), 684 localPool(pool) { 685 } 686 687 C2BufferQueueBlockPoolData::~C2BufferQueueBlockPoolData() { 688 if (!held || bqId == 0) { 689 return; 690 } 691 if (local) { 692 if (localPool) { 693 localPool->cancel(generation, bqId, bqSlot); 694 } 695 } else if (igbp && !owner.expired()) { 696 igbp->cancelBuffer(bqSlot, hidl_handle{}).isOk(); 697 } 698 } 699 int C2BufferQueueBlockPoolData::migrate( 700 const sp<HGraphicBufferProducer>& producer, 701 uint32_t toGeneration, uint64_t toBqId, 702 sp<GraphicBuffer> *buffers, uint32_t oldGeneration) { 703 std::scoped_lock<std::mutex> l(lock); 704 if (!held || bqId == 0) { 705 ALOGV("buffer is not owned"); 706 return -1; 707 } 708 if (!local || !localPool) { 709 ALOGV("pool is not local"); 710 return -1; 711 } 712 if (bqSlot < 0 || bqSlot >= NUM_BUFFER_SLOTS || !buffers[bqSlot]) { 713 ALOGV("slot is not in effect"); 714 return -1; 715 } 716 if (toGeneration == generation && bqId == toBqId) { 717 ALOGV("cannot migrate to same bufferqueue"); 718 return -1; 719 } 720 if (oldGeneration != generation) { 721 ALOGV("cannot migrate stale buffer"); 722 } 723 if (transfer) { 724 // either transferred or detached. 725 ALOGV("buffer is in transfer"); 726 return -1; 727 } 728 sp<GraphicBuffer> const& graphicBuffer = buffers[bqSlot]; 729 graphicBuffer->setGenerationNumber(toGeneration); 730 731 HBuffer hBuffer{}; 732 uint32_t hGenerationNumber{}; 733 if (!b2h(graphicBuffer, &hBuffer, &hGenerationNumber)) { 734 ALOGD("I to O conversion failed"); 735 return -1; 736 } 737 738 bool converted{}; 739 status_t bStatus{}; 740 int slot; 741 int *outSlot = &slot; 742 Return<void> transResult = 743 producer->attachBuffer(hBuffer, hGenerationNumber, 744 [&converted, &bStatus, outSlot]( 745 HStatus hStatus, int32_t hSlot, bool releaseAll) { 746 converted = h2b(hStatus, &bStatus); 747 *outSlot = static_cast<int>(hSlot); 748 if (converted && releaseAll && bStatus == android::OK) { 749 bStatus = android::INVALID_OPERATION; 750 } 751 }); 752 if (!transResult.isOk() || !converted || bStatus != android::OK) { 753 ALOGD("attach failed %d", static_cast<int>(bStatus)); 754 return -1; 755 } 756 ALOGV("local migration from gen %u : %u slot %d : %d", 757 generation, toGeneration, bqSlot, slot); 758 generation = toGeneration; 759 bqId = toBqId; 760 bqSlot = slot; 761 return slot; 762 } 763 764 C2BufferQueueBlockPool::C2BufferQueueBlockPool( 765 const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId) 766 : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {} 767 768 C2BufferQueueBlockPool::~C2BufferQueueBlockPool() {} 769 770 c2_status_t C2BufferQueueBlockPool::fetchGraphicBlock( 771 uint32_t width, 772 uint32_t height, 773 uint32_t format, 774 C2MemoryUsage usage, 775 std::shared_ptr<C2GraphicBlock> *block /* nonnull */) { 776 if (mImpl) { 777 return mImpl->fetchGraphicBlock(width, height, format, usage, block); 778 } 779 return C2_CORRUPTED; 780 } 781 782 void C2BufferQueueBlockPool::configureProducer(const sp<HGraphicBufferProducer> &producer) { 783 if (mImpl) { 784 mImpl->configureProducer(producer); 785 } 786 } 787 788 void C2BufferQueueBlockPool::setRenderCallback(const OnRenderCallback &renderCallback) { 789 if (mImpl) { 790 mImpl->setRenderCallback(renderCallback); 791 } 792 } 793