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