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 <gui/BufferQueueDefs.h> 22 #include <list> 23 #include <map> 24 #include <mutex> 25 26 #include <C2AllocatorGralloc.h> 27 #include <C2BqBufferPriv.h> 28 #include <C2BlockInternal.h> 29 30 using ::android::AnwBuffer; 31 using ::android::BufferQueueDefs::NUM_BUFFER_SLOTS; 32 using ::android::C2AllocatorGralloc; 33 using ::android::C2AndroidMemoryUsage; 34 using ::android::Fence; 35 using ::android::GraphicBuffer; 36 using ::android::HGraphicBufferProducer; 37 using ::android::IGraphicBufferProducer; 38 using ::android::hardware::graphics::common::V1_0::PixelFormat; 39 using ::android::hidl_handle; 40 using ::android::sp; 41 using ::android::status_t; 42 using ::android::wp; 43 44 struct C2BufferQueueBlockPoolData : public _C2BlockPoolData { 45 46 bool held; 47 bool local; 48 uint64_t bqId; 49 int32_t bqSlot; 50 sp<HGraphicBufferProducer> igbp; 51 std::shared_ptr<C2BufferQueueBlockPool::Impl> localPool; 52 53 virtual type_t getType() const override { 54 return TYPE_BUFFERQUEUE; 55 } 56 57 // Create a remote BlockPoolData. 58 C2BufferQueueBlockPoolData( 59 uint64_t bqId, int32_t bqSlot, 60 const sp<HGraphicBufferProducer>& producer = nullptr); 61 62 // Create a local BlockPoolData. 63 C2BufferQueueBlockPoolData( 64 uint64_t bqId, int32_t bqSlot, 65 const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool); 66 67 virtual ~C2BufferQueueBlockPoolData() override; 68 69 }; 70 71 bool _C2BlockFactory::GetBufferQueueData( 72 const std::shared_ptr<_C2BlockPoolData>& data, 73 uint64_t* bqId, int32_t* bqSlot) { 74 if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERQUEUE) { 75 if (bqId) { 76 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 77 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data); 78 *bqId = poolData->bqId; 79 if (bqSlot) { 80 *bqSlot = poolData->bqSlot; 81 } 82 } 83 return true; 84 } 85 return false; 86 } 87 88 bool _C2BlockFactory::AssignBlockToBufferQueue( 89 const std::shared_ptr<_C2BlockPoolData>& data, 90 const sp<HGraphicBufferProducer>& igbp, 91 uint64_t bqId, 92 int32_t bqSlot, 93 bool held) { 94 if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERQUEUE) { 95 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 96 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data); 97 poolData->igbp = igbp; 98 poolData->bqId = bqId; 99 poolData->bqSlot = bqSlot; 100 poolData->held = held; 101 return true; 102 } 103 return false; 104 } 105 106 bool _C2BlockFactory::HoldBlockFromBufferQueue( 107 const std::shared_ptr<_C2BlockPoolData>& data, 108 const sp<HGraphicBufferProducer>& igbp) { 109 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 110 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data); 111 if (!poolData->local) { 112 poolData->igbp = igbp; 113 } 114 if (poolData->held) { 115 poolData->held = true; 116 return false; 117 } 118 poolData->held = true; 119 return true; 120 } 121 122 bool _C2BlockFactory::YieldBlockToBufferQueue( 123 const std::shared_ptr<_C2BlockPoolData>& data) { 124 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 125 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data); 126 if (!poolData->held) { 127 poolData->held = false; 128 return false; 129 } 130 poolData->held = false; 131 return true; 132 } 133 134 std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock( 135 const C2Handle *handle) { 136 // TODO: get proper allocator? and mutex? 137 static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0); 138 139 std::shared_ptr<C2GraphicAllocation> alloc; 140 if (C2AllocatorGralloc::isValid(handle)) { 141 uint32_t width; 142 uint32_t height; 143 uint32_t format; 144 uint64_t usage; 145 uint32_t stride; 146 uint64_t igbp_id; 147 uint32_t igbp_slot; 148 android::_UnwrapNativeCodec2GrallocMetadata( 149 handle, &width, &height, &format, &usage, &stride, &igbp_id, &igbp_slot); 150 c2_status_t err = sAllocator->priorGraphicAllocation(handle, &alloc); 151 if (err == C2_OK) { 152 std::shared_ptr<C2GraphicBlock> block; 153 if (igbp_id || igbp_slot) { 154 // BQBBP 155 std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 156 std::make_shared<C2BufferQueueBlockPoolData>(igbp_id, (int32_t)igbp_slot); 157 block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData); 158 } else { 159 block = _C2BlockFactory::CreateGraphicBlock(alloc); 160 } 161 return block; 162 } 163 } 164 return nullptr; 165 } 166 167 class C2BufferQueueBlockPool::Impl 168 : public std::enable_shared_from_this<C2BufferQueueBlockPool::Impl> { 169 private: 170 c2_status_t fetchFromIgbp_l( 171 uint32_t width, 172 uint32_t height, 173 uint32_t format, 174 C2MemoryUsage usage, 175 std::shared_ptr<C2GraphicBlock> *block /* nonnull */) { 176 // We have an IGBP now. 177 sp<Fence> fence = new Fence(); 178 C2AndroidMemoryUsage androidUsage = usage; 179 status_t status; 180 PixelFormat pixelFormat = static_cast<PixelFormat>(format); 181 int slot; 182 ALOGV("tries to dequeue buffer"); 183 mProducer->dequeueBuffer( 184 width, height, pixelFormat, androidUsage.asGrallocUsage(), true, 185 [&status, &slot, &fence]( 186 int32_t tStatus, int32_t tSlot, hidl_handle const& tFence, 187 HGraphicBufferProducer::FrameEventHistoryDelta const& tTs) { 188 status = tStatus; 189 slot = tSlot; 190 if (!android::conversion::convertTo(fence.get(), tFence) && 191 status == android::NO_ERROR) { 192 status = android::BAD_VALUE; 193 } 194 (void) tTs; 195 }); 196 // dequeueBuffer returns flag. 197 if (status < android::OK) { 198 ALOGD("cannot dequeue buffer %d", status); 199 if (status == android::INVALID_OPERATION) { 200 // Too many buffer dequeued. retrying after some time is required. 201 return C2_TIMED_OUT; 202 } else { 203 return C2_BAD_VALUE; 204 } 205 } 206 ALOGV("dequeued a buffer successfully"); 207 native_handle_t* nh = nullptr; 208 hidl_handle fenceHandle; 209 if (fence) { 210 android::conversion::wrapAs(&fenceHandle, &nh, *fence); 211 } 212 if (fence) { 213 static constexpr int kFenceWaitTimeMs = 10; 214 215 status_t status = fence->wait(kFenceWaitTimeMs); 216 if (status == -ETIME) { 217 // fence is not signalled yet. 218 mProducer->cancelBuffer(slot, fenceHandle); 219 return C2_TIMED_OUT; 220 } 221 if (status != android::NO_ERROR) { 222 ALOGD("buffer fence wait error %d", status); 223 mProducer->cancelBuffer(slot, fenceHandle); 224 return C2_BAD_VALUE; 225 } else if (mRenderCallback) { 226 nsecs_t signalTime = fence->getSignalTime(); 227 if (signalTime >= 0 && signalTime < INT64_MAX) { 228 mRenderCallback(mProducerId, slot, signalTime); 229 } else { 230 ALOGV("got fence signal time of %lld", (long long)signalTime); 231 } 232 } 233 } 234 235 sp<GraphicBuffer> &slotBuffer = mBuffers[slot]; 236 if (status & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION || !slotBuffer) { 237 if (!slotBuffer) { 238 slotBuffer = new GraphicBuffer(); 239 } 240 // N.B. This assumes requestBuffer# returns an existing allocation 241 // instead of a new allocation. 242 mProducer->requestBuffer( 243 slot, 244 [&status, &slotBuffer](int32_t tStatus, AnwBuffer const& tBuffer){ 245 status = tStatus; 246 if (!android::conversion::convertTo(slotBuffer.get(), tBuffer) && 247 status == android::NO_ERROR) { 248 status = android::BAD_VALUE; 249 } 250 }); 251 252 if (status != android::NO_ERROR) { 253 mBuffers[slot].clear(); 254 mProducer->cancelBuffer(slot, fenceHandle); 255 return C2_BAD_VALUE; 256 } 257 } 258 if (mBuffers[slot]) { 259 native_handle_t *grallocHandle = native_handle_clone(mBuffers[slot]->handle); 260 261 if (grallocHandle) { 262 ALOGV("buffer wraps %llu %d", (unsigned long long)mProducerId, slot); 263 C2Handle *c2Handle = android::WrapNativeCodec2GrallocHandle( 264 grallocHandle, 265 mBuffers[slot]->width, 266 mBuffers[slot]->height, 267 mBuffers[slot]->format, 268 mBuffers[slot]->usage, 269 mBuffers[slot]->stride, 270 mProducerId, slot); 271 if (c2Handle) { 272 // Moved everything to c2Handle. 273 native_handle_delete(grallocHandle); 274 std::shared_ptr<C2GraphicAllocation> alloc; 275 c2_status_t err = mAllocator->priorGraphicAllocation(c2Handle, &alloc); 276 if (err != C2_OK) { 277 return err; 278 } 279 std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 280 std::make_shared<C2BufferQueueBlockPoolData>( 281 mProducerId, slot, shared_from_this()); 282 *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData); 283 return C2_OK; 284 } 285 native_handle_close(grallocHandle); 286 native_handle_delete(grallocHandle); 287 } 288 // Block was not created. call requestBuffer# again next time. 289 mBuffers[slot].clear(); 290 mProducer->cancelBuffer(slot, fenceHandle); 291 } 292 return C2_BAD_VALUE; 293 } 294 295 public: 296 Impl(const std::shared_ptr<C2Allocator> &allocator) 297 : mInit(C2_OK), mProducerId(0), mAllocator(allocator) { 298 } 299 300 ~Impl() { 301 std::lock_guard<std::mutex> lock(mMutex); 302 bool noInit = false; 303 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) { 304 if (!noInit && mProducer) { 305 noInit = mProducer->detachBuffer(i) == android::NO_INIT; 306 } 307 mBuffers[i].clear(); 308 } 309 } 310 311 c2_status_t fetchGraphicBlock( 312 uint32_t width, 313 uint32_t height, 314 uint32_t format, 315 C2MemoryUsage usage, 316 std::shared_ptr<C2GraphicBlock> *block /* nonnull */) { 317 block->reset(); 318 if (mInit != C2_OK) { 319 return mInit; 320 } 321 322 static int kMaxIgbpRetry = 20; // TODO: small number can cause crash in releasing. 323 static int kMaxIgbpRetryDelayUs = 10000; 324 325 int curTry = 0; 326 327 while (curTry++ < kMaxIgbpRetry) { 328 std::unique_lock<std::mutex> lock(mMutex); 329 // TODO: return C2_NO_INIT 330 if (mProducerId == 0) { 331 std::shared_ptr<C2GraphicAllocation> alloc; 332 c2_status_t err = mAllocator->newGraphicAllocation( 333 width, height, format, usage, &alloc); 334 if (err != C2_OK) { 335 return err; 336 } 337 std::shared_ptr<C2BufferQueueBlockPoolData> poolData = 338 std::make_shared<C2BufferQueueBlockPoolData>( 339 (uint64_t)0, ~0, shared_from_this()); 340 // TODO: config? 341 *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData); 342 ALOGV("allocated a buffer successfully"); 343 344 return C2_OK; 345 } 346 c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block); 347 if (status == C2_TIMED_OUT) { 348 lock.unlock(); 349 ::usleep(kMaxIgbpRetryDelayUs); 350 continue; 351 } 352 return status; 353 } 354 return C2_TIMED_OUT; 355 } 356 357 void setRenderCallback(const OnRenderCallback &renderCallback) { 358 std::lock_guard<std::mutex> lock(mMutex); 359 mRenderCallback = renderCallback; 360 } 361 362 void configureProducer(const sp<HGraphicBufferProducer> &producer) { 363 int32_t status = android::OK; 364 uint64_t producerId = 0; 365 if (producer) { 366 producer->getUniqueId( 367 [&status, &producerId](int32_t tStatus, int64_t tProducerId) { 368 status = tStatus; 369 producerId = tProducerId; 370 }); 371 } 372 { 373 std::lock_guard<std::mutex> lock(mMutex); 374 if (status == android::OK && producerId == mProducerId) { 375 // producer is not changed. 376 return; 377 } 378 bool noInit = false; 379 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) { 380 if (!noInit && mProducer) { 381 noInit = mProducer->detachBuffer(i) == android::NO_INIT; 382 } 383 mBuffers[i].clear(); 384 } 385 if (producer && status == android::OK) { 386 mProducer = producer; 387 mProducerId = producerId; 388 } else { 389 mProducer = nullptr; 390 mProducerId = 0; 391 } 392 } 393 } 394 395 private: 396 friend struct C2BufferQueueBlockPoolData; 397 398 void cancel(uint64_t igbp_id, int32_t igbp_slot) { 399 std::lock_guard<std::mutex> lock(mMutex); 400 if (igbp_id == mProducerId && mProducer) { 401 mProducer->cancelBuffer(igbp_slot, nullptr); 402 } 403 } 404 405 c2_status_t mInit; 406 uint64_t mProducerId; 407 OnRenderCallback mRenderCallback; 408 409 const std::shared_ptr<C2Allocator> mAllocator; 410 411 std::mutex mMutex; 412 sp<HGraphicBufferProducer> mProducer; 413 414 sp<GraphicBuffer> mBuffers[NUM_BUFFER_SLOTS]; 415 }; 416 417 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData( 418 uint64_t bqId, int32_t bqSlot, 419 const sp<HGraphicBufferProducer>& producer) : 420 held(producer && bqId != 0), local(false), 421 bqId(bqId), bqSlot(bqSlot), 422 igbp(producer), 423 localPool() { 424 } 425 426 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData( 427 uint64_t bqId, int32_t bqSlot, 428 const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool) : 429 held(true), local(true), 430 bqId(bqId), bqSlot(bqSlot), 431 igbp(pool ? pool->mProducer : nullptr), 432 localPool(pool) { 433 } 434 435 C2BufferQueueBlockPoolData::~C2BufferQueueBlockPoolData() { 436 if (!held || bqId == 0) { 437 return; 438 } 439 if (local && localPool) { 440 localPool->cancel(bqId, bqSlot); 441 } else if (igbp) { 442 igbp->cancelBuffer(bqSlot, nullptr); 443 } 444 } 445 446 C2BufferQueueBlockPool::C2BufferQueueBlockPool( 447 const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId) 448 : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {} 449 450 C2BufferQueueBlockPool::~C2BufferQueueBlockPool() {} 451 452 c2_status_t C2BufferQueueBlockPool::fetchGraphicBlock( 453 uint32_t width, 454 uint32_t height, 455 uint32_t format, 456 C2MemoryUsage usage, 457 std::shared_ptr<C2GraphicBlock> *block /* nonnull */) { 458 if (mImpl) { 459 return mImpl->fetchGraphicBlock(width, height, format, usage, block); 460 } 461 return C2_CORRUPTED; 462 } 463 464 void C2BufferQueueBlockPool::configureProducer(const sp<HGraphicBufferProducer> &producer) { 465 if (mImpl) { 466 mImpl->configureProducer(producer); 467 } 468 } 469 470 void C2BufferQueueBlockPool::setRenderCallback(const OnRenderCallback &renderCallback) { 471 if (mImpl) { 472 mImpl->setRenderCallback(renderCallback); 473 } 474 } 475