1 /* 2 * Copyright 2016 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 "Camera3-BufferManager" 19 #define ATRACE_TAG ATRACE_TAG_CAMERA 20 21 #include <gui/ISurfaceComposer.h> 22 #include <private/gui/ComposerService.h> 23 #include <utils/Log.h> 24 #include <utils/Trace.h> 25 #include "utils/CameraTraces.h" 26 #include "Camera3BufferManager.h" 27 28 namespace android { 29 30 namespace camera3 { 31 32 Camera3BufferManager::Camera3BufferManager(const sp<IGraphicBufferAlloc>& allocator) : 33 mAllocator(allocator) { 34 if (allocator == NULL) { 35 sp<ISurfaceComposer> composer(ComposerService::getComposerService()); 36 mAllocator = composer->createGraphicBufferAlloc(); 37 if (mAllocator == NULL) { 38 ALOGE("createGraphicBufferAlloc failed"); 39 } 40 } 41 } 42 43 Camera3BufferManager::~Camera3BufferManager() { 44 } 45 46 status_t Camera3BufferManager::registerStream(wp<Camera3OutputStream>& stream, 47 const StreamInfo& streamInfo) { 48 ATRACE_CALL(); 49 50 int streamId = streamInfo.streamId; 51 int streamSetId = streamInfo.streamSetId; 52 53 if (streamId == CAMERA3_STREAM_ID_INVALID || streamSetId == CAMERA3_STREAM_SET_ID_INVALID) { 54 ALOGE("%s: Stream id (%d) or stream set id (%d) is invalid", 55 __FUNCTION__, streamId, streamSetId); 56 return BAD_VALUE; 57 } 58 if (streamInfo.totalBufferCount > kMaxBufferCount || streamInfo.totalBufferCount == 0) { 59 ALOGE("%s: Stream id (%d) with stream set id (%d) total buffer count %zu is invalid", 60 __FUNCTION__, streamId, streamSetId, streamInfo.totalBufferCount); 61 return BAD_VALUE; 62 } 63 if (!streamInfo.isConfigured) { 64 ALOGE("%s: Stream (%d) is not configured", __FUNCTION__, streamId); 65 return BAD_VALUE; 66 } 67 68 // For Gralloc v1, try to allocate a buffer and see if it is successful, otherwise, stream 69 // buffer sharing for this newly added stream is not supported. For Gralloc v0, we don't 70 // need check this, as the buffers are not really shared between streams, the buffers are 71 // allocated for each stream individually, the allocation failure will be checked in 72 // getBufferForStream() call. 73 if (mGrallocVersion > HARDWARE_DEVICE_API_VERSION(0,1)) { 74 // TODO: To be implemented. 75 76 // In case allocation fails, return invalid operation 77 return INVALID_OPERATION; 78 } 79 80 Mutex::Autolock l(mLock); 81 if (mAllocator == NULL) { 82 ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__); 83 return INVALID_OPERATION; 84 } 85 86 // Check if this stream was registered with different stream set ID, if so, error out. 87 for (size_t i = 0; i < mStreamSetMap.size(); i++) { 88 ssize_t streamIdx = mStreamSetMap[i].streamInfoMap.indexOfKey(streamId); 89 if (streamIdx != NAME_NOT_FOUND && 90 mStreamSetMap[i].streamInfoMap[streamIdx].streamSetId != streamInfo.streamSetId) { 91 ALOGE("%s: It is illegal to register the same stream id with different stream set", 92 __FUNCTION__); 93 return BAD_VALUE; 94 } 95 } 96 // Check if there is an existing stream set registered; if not, create one; otherwise, add this 97 // stream info to the existing stream set entry. 98 ssize_t setIdx = mStreamSetMap.indexOfKey(streamSetId); 99 if (setIdx == NAME_NOT_FOUND) { 100 ALOGV("%s: stream set %d is not registered to stream set map yet, create it.", 101 __FUNCTION__, streamSetId); 102 // Create stream info map, then add to mStreamsetMap. 103 StreamSet newStreamSet; 104 setIdx = mStreamSetMap.add(streamSetId, newStreamSet); 105 } 106 // Update stream set map and water mark. 107 StreamSet& currentStreamSet = mStreamSetMap.editValueAt(setIdx); 108 ssize_t streamIdx = currentStreamSet.streamInfoMap.indexOfKey(streamId); 109 if (streamIdx != NAME_NOT_FOUND) { 110 ALOGW("%s: stream %d was already registered with stream set %d", 111 __FUNCTION__, streamId, streamSetId); 112 return OK; 113 } 114 currentStreamSet.streamInfoMap.add(streamId, streamInfo); 115 currentStreamSet.handoutBufferCountMap.add(streamId, 0); 116 currentStreamSet.attachedBufferCountMap.add(streamId, 0); 117 mStreamMap.add(streamId, stream); 118 119 // The max allowed buffer count should be the max of buffer count of each stream inside a stream 120 // set. 121 if (streamInfo.totalBufferCount > currentStreamSet.maxAllowedBufferCount) { 122 currentStreamSet.maxAllowedBufferCount = streamInfo.totalBufferCount; 123 } 124 125 return OK; 126 } 127 128 status_t Camera3BufferManager::unregisterStream(int streamId, int streamSetId) { 129 ATRACE_CALL(); 130 131 Mutex::Autolock l(mLock); 132 ALOGV("%s: unregister stream %d with stream set %d", __FUNCTION__, 133 streamId, streamSetId); 134 if (mAllocator == NULL) { 135 ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__); 136 return INVALID_OPERATION; 137 } 138 139 if (!checkIfStreamRegisteredLocked(streamId, streamSetId)){ 140 ALOGE("%s: stream %d with set id %d wasn't properly registered to this buffer manager!", 141 __FUNCTION__, streamId, streamSetId); 142 return BAD_VALUE; 143 } 144 145 // De-list all the buffers associated with this stream first. 146 StreamSet& currentSet = mStreamSetMap.editValueFor(streamSetId); 147 BufferList& freeBufs = currentSet.freeBuffers; 148 BufferCountMap& handOutBufferCounts = currentSet.handoutBufferCountMap; 149 BufferCountMap& attachedBufferCounts = currentSet.attachedBufferCountMap; 150 InfoMap& infoMap = currentSet.streamInfoMap; 151 removeBuffersFromBufferListLocked(freeBufs, streamId); 152 handOutBufferCounts.removeItem(streamId); 153 attachedBufferCounts.removeItem(streamId); 154 155 // Remove the stream info from info map and recalculate the buffer count water mark. 156 infoMap.removeItem(streamId); 157 currentSet.maxAllowedBufferCount = 0; 158 for (size_t i = 0; i < infoMap.size(); i++) { 159 if (infoMap[i].totalBufferCount > currentSet.maxAllowedBufferCount) { 160 currentSet.maxAllowedBufferCount = infoMap[i].totalBufferCount; 161 } 162 } 163 mStreamMap.removeItem(streamId); 164 165 // Lazy solution: when a stream is unregistered, the streams will be reconfigured, reset 166 // the water mark and let it grow again. 167 currentSet.allocatedBufferWaterMark = 0; 168 169 // Remove this stream set if all its streams have been removed. 170 if (freeBufs.size() == 0 && handOutBufferCounts.size() == 0 && infoMap.size() == 0) { 171 mStreamSetMap.removeItem(streamSetId); 172 } 173 174 return OK; 175 } 176 177 status_t Camera3BufferManager::getBufferForStream(int streamId, int streamSetId, 178 sp<GraphicBuffer>* gb, int* fenceFd) { 179 ATRACE_CALL(); 180 181 Mutex::Autolock l(mLock); 182 ALOGV("%s: get buffer for stream %d with stream set %d", __FUNCTION__, 183 streamId, streamSetId); 184 if (mAllocator == NULL) { 185 ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__); 186 return INVALID_OPERATION; 187 } 188 189 if (!checkIfStreamRegisteredLocked(streamId, streamSetId)) { 190 ALOGE("%s: stream %d is not registered with stream set %d yet!!!", 191 __FUNCTION__, streamId, streamSetId); 192 return BAD_VALUE; 193 } 194 195 StreamSet &streamSet = mStreamSetMap.editValueFor(streamSetId); 196 BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap; 197 size_t& bufferCount = handOutBufferCounts.editValueFor(streamId); 198 if (bufferCount >= streamSet.maxAllowedBufferCount) { 199 ALOGE("%s: bufferCount (%zu) exceeds the max allowed buffer count (%zu) of this stream set", 200 __FUNCTION__, bufferCount, streamSet.maxAllowedBufferCount); 201 return INVALID_OPERATION; 202 } 203 204 BufferCountMap& attachedBufferCounts = streamSet.attachedBufferCountMap; 205 size_t& attachedBufferCount = attachedBufferCounts.editValueFor(streamId); 206 if (attachedBufferCount > bufferCount) { 207 // We've already attached more buffers to this stream than we currently have 208 // outstanding, so have the stream just use an already-attached buffer 209 bufferCount++; 210 return ALREADY_EXISTS; 211 } 212 ALOGV("Stream %d set %d: Get buffer for stream: Allocate new", streamId, streamSetId); 213 214 GraphicBufferEntry buffer = 215 getFirstBufferFromBufferListLocked(streamSet.freeBuffers, streamId); 216 217 if (mGrallocVersion < HARDWARE_DEVICE_API_VERSION(1,0)) { 218 // Allocate one if there is no free buffer available. 219 if (buffer.graphicBuffer == nullptr) { 220 const StreamInfo& info = streamSet.streamInfoMap.valueFor(streamId); 221 status_t res = OK; 222 buffer.fenceFd = -1; 223 buffer.graphicBuffer = mAllocator->createGraphicBuffer( 224 info.width, info.height, info.format, info.combinedUsage, &res); 225 ALOGV("%s: allocating a new graphic buffer (%dx%d, format 0x%x) %p with handle %p", 226 __FUNCTION__, info.width, info.height, info.format, 227 buffer.graphicBuffer.get(), buffer.graphicBuffer->handle); 228 if (res != OK) { 229 ALOGE("%s: graphic buffer allocation failed: (error %d %s) ", 230 __FUNCTION__, res, strerror(-res)); 231 return res; 232 } 233 ALOGV("%s: allocation done", __FUNCTION__); 234 } 235 236 // Increase the hand-out and attached buffer counts for tracking purposes. 237 bufferCount++; 238 attachedBufferCount++; 239 // Update the water mark to be the max hand-out buffer count + 1. An additional buffer is 240 // added to reduce the chance of buffer allocation during stream steady state, especially 241 // for cases where one stream is active, the other stream may request some buffers randomly. 242 if (bufferCount + 1 > streamSet.allocatedBufferWaterMark) { 243 streamSet.allocatedBufferWaterMark = bufferCount + 1; 244 } 245 *gb = buffer.graphicBuffer; 246 *fenceFd = buffer.fenceFd; 247 ALOGV("%s: get buffer (%p) with handle (%p).", 248 __FUNCTION__, buffer.graphicBuffer.get(), buffer.graphicBuffer->handle); 249 250 // Proactively free buffers for other streams if the current number of allocated buffers 251 // exceeds the water mark. This only for Gralloc V1, for V2, this logic can also be handled 252 // in returnBufferForStream() if we want to free buffer more quickly. 253 // TODO: probably should find out all the inactive stream IDs, and free the firstly found 254 // buffers for them. 255 StreamId firstOtherStreamId = CAMERA3_STREAM_ID_INVALID; 256 if (streamSet.streamInfoMap.size() > 1) { 257 bool freeBufferIsAttached = false; 258 for (size_t i = 0; i < streamSet.streamInfoMap.size(); i++) { 259 firstOtherStreamId = streamSet.streamInfoMap[i].streamId; 260 if (firstOtherStreamId != streamId) { 261 262 size_t otherBufferCount = 263 streamSet.handoutBufferCountMap.valueFor(firstOtherStreamId); 264 size_t otherAttachedBufferCount = 265 streamSet.attachedBufferCountMap.valueFor(firstOtherStreamId); 266 if (otherAttachedBufferCount > otherBufferCount) { 267 freeBufferIsAttached = true; 268 break; 269 } 270 if (hasBufferForStreamLocked(streamSet.freeBuffers, firstOtherStreamId)) { 271 freeBufferIsAttached = false; 272 break; 273 } 274 } 275 firstOtherStreamId = CAMERA3_STREAM_ID_INVALID; 276 } 277 if (firstOtherStreamId == CAMERA3_STREAM_ID_INVALID) { 278 return OK; 279 } 280 281 // This will drop the reference to one free buffer, which will effectively free one 282 // buffer (from the free buffer list) for the inactive streams. 283 size_t totalAllocatedBufferCount = streamSet.freeBuffers.size(); 284 for (size_t i = 0; i < streamSet.attachedBufferCountMap.size(); i++) { 285 totalAllocatedBufferCount += streamSet.attachedBufferCountMap[i]; 286 } 287 if (totalAllocatedBufferCount > streamSet.allocatedBufferWaterMark) { 288 ALOGV("%s: free a buffer from stream %d", __FUNCTION__, firstOtherStreamId); 289 if (freeBufferIsAttached) { 290 ALOGV("Stream %d: Freeing buffer: detach", firstOtherStreamId); 291 sp<Camera3OutputStream> stream = 292 mStreamMap.valueFor(firstOtherStreamId).promote(); 293 if (stream == nullptr) { 294 ALOGE("%s: unable to promote stream %d to detach buffer", __FUNCTION__, 295 firstOtherStreamId); 296 return INVALID_OPERATION; 297 } 298 299 // Detach and then drop the buffer. 300 // 301 // Need to unlock because the stream may also be calling 302 // into the buffer manager in parallel to signal buffer 303 // release, or acquire a new buffer. 304 { 305 mLock.unlock(); 306 sp<GraphicBuffer> buffer; 307 stream->detachBuffer(&buffer, /*fenceFd*/ nullptr); 308 mLock.lock(); 309 } 310 size_t& otherAttachedBufferCount = 311 streamSet.attachedBufferCountMap.editValueFor(firstOtherStreamId); 312 otherAttachedBufferCount--; 313 } else { 314 // Droppable buffer is in the free buffer list, grab and drop 315 getFirstBufferFromBufferListLocked(streamSet.freeBuffers, firstOtherStreamId); 316 } 317 } 318 } 319 } else { 320 // TODO: implement this. 321 return BAD_VALUE; 322 } 323 324 return OK; 325 } 326 327 status_t Camera3BufferManager::onBufferReleased(int streamId, int streamSetId) { 328 ATRACE_CALL(); 329 Mutex::Autolock l(mLock); 330 331 ALOGV("Stream %d set %d: Buffer released", streamId, streamSetId); 332 if (mAllocator == NULL) { 333 ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__); 334 return INVALID_OPERATION; 335 } 336 337 if (!checkIfStreamRegisteredLocked(streamId, streamSetId)){ 338 ALOGV("%s: signaling buffer release for an already unregistered stream " 339 "(stream %d with set id %d)", __FUNCTION__, streamId, streamSetId); 340 return OK; 341 } 342 343 if (mGrallocVersion < HARDWARE_DEVICE_API_VERSION(1,0)) { 344 StreamSet& streamSet = mStreamSetMap.editValueFor(streamSetId); 345 BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap; 346 size_t& bufferCount = handOutBufferCounts.editValueFor(streamId); 347 bufferCount--; 348 ALOGV("%s: Stream %d set %d: Buffer count now %zu", __FUNCTION__, streamId, streamSetId, 349 bufferCount); 350 } else { 351 // TODO: implement gralloc V1 support 352 return BAD_VALUE; 353 } 354 355 return OK; 356 } 357 358 status_t Camera3BufferManager::returnBufferForStream(int streamId, 359 int streamSetId, const sp<GraphicBuffer>& buffer, int fenceFd) { 360 ATRACE_CALL(); 361 Mutex::Autolock l(mLock); 362 ALOGV_IF(buffer != 0, "%s: return buffer (%p) with handle (%p) for stream %d and stream set %d", 363 __FUNCTION__, buffer.get(), buffer->handle, streamId, streamSetId); 364 if (mAllocator == NULL) { 365 ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__); 366 return INVALID_OPERATION; 367 } 368 369 if (!checkIfStreamRegisteredLocked(streamId, streamSetId)){ 370 ALOGV("%s: returning buffer for an already unregistered stream (stream %d with set id %d)," 371 "buffer will be dropped right away!", __FUNCTION__, streamId, streamSetId); 372 return OK; 373 } 374 375 if (mGrallocVersion < HARDWARE_DEVICE_API_VERSION(1,0)) { 376 // Add to the freeBuffer list. 377 StreamSet& streamSet = mStreamSetMap.editValueFor(streamSetId); 378 if (buffer != 0) { 379 BufferEntry entry; 380 entry.add(streamId, GraphicBufferEntry(buffer, fenceFd)); 381 status_t res = addBufferToBufferListLocked(streamSet.freeBuffers, entry); 382 if (res != OK) { 383 ALOGE("%s: add buffer to free buffer list failed", __FUNCTION__); 384 return res; 385 } 386 } 387 388 // Update the handed out and attached buffer count for this buffer. 389 BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap; 390 size_t& bufferCount = handOutBufferCounts.editValueFor(streamId); 391 bufferCount--; 392 size_t& attachedBufferCount = streamSet.attachedBufferCountMap.editValueFor(streamId); 393 attachedBufferCount--; 394 } else { 395 // TODO: implement this. 396 return BAD_VALUE; 397 } 398 399 return OK; 400 } 401 402 void Camera3BufferManager::dump(int fd, const Vector<String16>& args) const { 403 Mutex::Autolock l(mLock); 404 405 (void) args; 406 String8 lines; 407 lines.appendFormat(" Total stream sets: %zu\n", mStreamSetMap.size()); 408 for (size_t i = 0; i < mStreamSetMap.size(); i++) { 409 lines.appendFormat(" Stream set %d has below streams:\n", mStreamSetMap.keyAt(i)); 410 for (size_t j = 0; j < mStreamSetMap[i].streamInfoMap.size(); j++) { 411 lines.appendFormat(" Stream %d\n", mStreamSetMap[i].streamInfoMap[j].streamId); 412 } 413 lines.appendFormat(" Stream set max allowed buffer count: %zu\n", 414 mStreamSetMap[i].maxAllowedBufferCount); 415 lines.appendFormat(" Stream set buffer count water mark: %zu\n", 416 mStreamSetMap[i].allocatedBufferWaterMark); 417 lines.appendFormat(" Handout buffer counts:\n"); 418 for (size_t m = 0; m < mStreamSetMap[i].handoutBufferCountMap.size(); m++) { 419 int streamId = mStreamSetMap[i].handoutBufferCountMap.keyAt(m); 420 size_t bufferCount = mStreamSetMap[i].handoutBufferCountMap.valueAt(m); 421 lines.appendFormat(" stream id: %d, buffer count: %zu.\n", 422 streamId, bufferCount); 423 } 424 lines.appendFormat(" Attached buffer counts:\n"); 425 for (size_t m = 0; m < mStreamSetMap[i].attachedBufferCountMap.size(); m++) { 426 int streamId = mStreamSetMap[i].attachedBufferCountMap.keyAt(m); 427 size_t bufferCount = mStreamSetMap[i].attachedBufferCountMap.valueAt(m); 428 lines.appendFormat(" stream id: %d, attached buffer count: %zu.\n", 429 streamId, bufferCount); 430 } 431 432 lines.appendFormat(" Free buffer count: %zu\n", 433 mStreamSetMap[i].freeBuffers.size()); 434 for (auto& bufEntry : mStreamSetMap[i].freeBuffers) { 435 for (size_t m = 0; m < bufEntry.size(); m++) { 436 const sp<GraphicBuffer>& buffer = bufEntry.valueAt(m).graphicBuffer; 437 int streamId = bufEntry.keyAt(m); 438 lines.appendFormat(" stream id: %d, buffer: %p, handle: %p.\n", 439 streamId, buffer.get(), buffer->handle); 440 } 441 } 442 } 443 write(fd, lines.string(), lines.size()); 444 } 445 446 bool Camera3BufferManager::checkIfStreamRegisteredLocked(int streamId, int streamSetId) const { 447 ssize_t setIdx = mStreamSetMap.indexOfKey(streamSetId); 448 if (setIdx == NAME_NOT_FOUND) { 449 ALOGV("%s: stream set %d is not registered to stream set map yet!", 450 __FUNCTION__, streamSetId); 451 return false; 452 } 453 454 ssize_t streamIdx = mStreamSetMap.valueAt(setIdx).streamInfoMap.indexOfKey(streamId); 455 if (streamIdx == NAME_NOT_FOUND) { 456 ALOGV("%s: stream %d is not registered to stream info map yet!", __FUNCTION__, streamId); 457 return false; 458 } 459 460 size_t bufferWaterMark = mStreamSetMap[setIdx].maxAllowedBufferCount; 461 if (bufferWaterMark == 0 || bufferWaterMark > kMaxBufferCount) { 462 ALOGW("%s: stream %d with stream set %d is not registered correctly to stream set map," 463 " as the water mark (%zu) is wrong!", 464 __FUNCTION__, streamId, streamSetId, bufferWaterMark); 465 return false; 466 } 467 468 return true; 469 } 470 471 status_t Camera3BufferManager::addBufferToBufferListLocked(BufferList& bufList, 472 const BufferEntry& buffer) { 473 // TODO: need add some sanity check here. 474 bufList.push_back(buffer); 475 476 return OK; 477 } 478 479 status_t Camera3BufferManager::removeBuffersFromBufferListLocked(BufferList& bufferList, 480 int streamId) { 481 BufferList::iterator i = bufferList.begin(); 482 while (i != bufferList.end()) { 483 ssize_t idx = i->indexOfKey(streamId); 484 if (idx != NAME_NOT_FOUND) { 485 ALOGV("%s: Remove a buffer for stream %d, free buffer total count: %zu", 486 __FUNCTION__, streamId, bufferList.size()); 487 i->removeItem(streamId); 488 if (i->isEmpty()) { 489 i = bufferList.erase(i); 490 } 491 } else { 492 i++; 493 } 494 } 495 496 return OK; 497 } 498 499 bool Camera3BufferManager::hasBufferForStreamLocked(BufferList& buffers, int streamId) { 500 BufferList::iterator i = buffers.begin(); 501 while (i != buffers.end()) { 502 ssize_t idx = i->indexOfKey(streamId); 503 if (idx != NAME_NOT_FOUND) { 504 return true; 505 } 506 i++; 507 } 508 509 return false; 510 } 511 512 Camera3BufferManager::GraphicBufferEntry Camera3BufferManager::getFirstBufferFromBufferListLocked( 513 BufferList& buffers, int streamId) { 514 // Try to get the first buffer from the free buffer list if there is one. 515 GraphicBufferEntry entry; 516 BufferList::iterator i = buffers.begin(); 517 while (i != buffers.end()) { 518 ssize_t idx = i->indexOfKey(streamId); 519 if (idx != NAME_NOT_FOUND) { 520 entry = GraphicBufferEntry(i->valueAt(idx)); 521 i = buffers.erase(i); 522 break; 523 } else { 524 i++; 525 } 526 } 527 528 ALOGV_IF(entry.graphicBuffer == 0, "%s: Unable to find free buffer for stream %d", 529 __FUNCTION__, streamId); 530 return entry; 531 } 532 533 } // namespace camera3 534 } // namespace android 535