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 #include <cutils/compiler.h> 18 #include <gui/BufferQueue.h> 19 #include <math/mat4.h> 20 #include <system/window.h> 21 22 #include <utils/Trace.h> 23 24 #include "Matrix.h" 25 #include "SurfaceTexture.h" 26 #include "ImageConsumer.h" 27 28 namespace android { 29 30 // Macros for including the SurfaceTexture name in log messages 31 #define SFT_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) 32 #define SFT_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) 33 #define SFT_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) 34 #define SFT_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) 35 36 static const mat4 mtxIdentity; 37 38 SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, 39 uint32_t texTarget, bool useFenceSync, bool isControlledByApp) 40 : ConsumerBase(bq, isControlledByApp) 41 , mCurrentCrop(Rect::EMPTY_RECT) 42 , mCurrentTransform(0) 43 , mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE) 44 , mCurrentFence(Fence::NO_FENCE) 45 , mCurrentTimestamp(0) 46 , mCurrentDataSpace(HAL_DATASPACE_UNKNOWN) 47 , mCurrentFrameNumber(0) 48 , mDefaultWidth(1) 49 , mDefaultHeight(1) 50 , mFilteringEnabled(true) 51 , mTexName(tex) 52 , mUseFenceSync(useFenceSync) 53 , mTexTarget(texTarget) 54 , mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) 55 , mOpMode(OpMode::attachedToGL) { 56 SFT_LOGV("SurfaceTexture"); 57 58 memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); 59 60 mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); 61 } 62 63 SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget, 64 bool useFenceSync, bool isControlledByApp) 65 : ConsumerBase(bq, isControlledByApp) 66 , mCurrentCrop(Rect::EMPTY_RECT) 67 , mCurrentTransform(0) 68 , mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE) 69 , mCurrentFence(Fence::NO_FENCE) 70 , mCurrentTimestamp(0) 71 , mCurrentDataSpace(HAL_DATASPACE_UNKNOWN) 72 , mCurrentFrameNumber(0) 73 , mDefaultWidth(1) 74 , mDefaultHeight(1) 75 , mFilteringEnabled(true) 76 , mTexName(0) 77 , mUseFenceSync(useFenceSync) 78 , mTexTarget(texTarget) 79 , mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) 80 , mOpMode(OpMode::detached) { 81 SFT_LOGV("SurfaceTexture"); 82 83 memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); 84 85 mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); 86 } 87 88 status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) { 89 Mutex::Autolock lock(mMutex); 90 if (mAbandoned) { 91 SFT_LOGE("setDefaultBufferSize: SurfaceTexture is abandoned!"); 92 return NO_INIT; 93 } 94 mDefaultWidth = w; 95 mDefaultHeight = h; 96 return mConsumer->setDefaultBufferSize(w, h); 97 } 98 99 status_t SurfaceTexture::updateTexImage() { 100 ATRACE_CALL(); 101 SFT_LOGV("updateTexImage"); 102 Mutex::Autolock lock(mMutex); 103 104 if (mAbandoned) { 105 SFT_LOGE("updateTexImage: SurfaceTexture is abandoned!"); 106 return NO_INIT; 107 } 108 109 return mEGLConsumer.updateTexImage(*this); 110 } 111 112 status_t SurfaceTexture::releaseTexImage() { 113 // releaseTexImage can be invoked even when not attached to a GL context. 114 ATRACE_CALL(); 115 SFT_LOGV("releaseTexImage"); 116 Mutex::Autolock lock(mMutex); 117 118 if (mAbandoned) { 119 SFT_LOGE("releaseTexImage: SurfaceTexture is abandoned!"); 120 return NO_INIT; 121 } 122 123 return mEGLConsumer.releaseTexImage(*this); 124 } 125 126 status_t SurfaceTexture::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen, 127 uint64_t maxFrameNumber) { 128 status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber); 129 if (err != NO_ERROR) { 130 return err; 131 } 132 133 switch (mOpMode) { 134 case OpMode::attachedToView: 135 mImageConsumer.onAcquireBufferLocked(item); 136 break; 137 case OpMode::attachedToGL: 138 mEGLConsumer.onAcquireBufferLocked(item, *this); 139 break; 140 case OpMode::detached: 141 break; 142 } 143 144 return NO_ERROR; 145 } 146 147 status_t SurfaceTexture::releaseBufferLocked(int buf, sp<GraphicBuffer> graphicBuffer, 148 EGLDisplay display, EGLSyncKHR eglFence) { 149 // release the buffer if it hasn't already been discarded by the 150 // BufferQueue. This can happen, for example, when the producer of this 151 // buffer has reallocated the original buffer slot after this buffer 152 // was acquired. 153 status_t err = ConsumerBase::releaseBufferLocked(buf, graphicBuffer, display, eglFence); 154 // We could be releasing an EGL/Vulkan buffer, even if not currently attached to a GL context. 155 mImageConsumer.onReleaseBufferLocked(buf); 156 mEGLConsumer.onReleaseBufferLocked(buf); 157 return err; 158 } 159 160 status_t SurfaceTexture::detachFromContext() { 161 ATRACE_CALL(); 162 SFT_LOGV("detachFromContext"); 163 Mutex::Autolock lock(mMutex); 164 165 if (mAbandoned) { 166 SFT_LOGE("detachFromContext: abandoned SurfaceTexture"); 167 return NO_INIT; 168 } 169 170 if (mOpMode != OpMode::attachedToGL) { 171 SFT_LOGE("detachFromContext: SurfaceTexture is not attached to a GL context"); 172 return INVALID_OPERATION; 173 } 174 175 status_t err = mEGLConsumer.detachFromContext(*this); 176 if (err == OK) { 177 mOpMode = OpMode::detached; 178 } 179 180 return err; 181 } 182 183 status_t SurfaceTexture::attachToContext(uint32_t tex) { 184 ATRACE_CALL(); 185 SFT_LOGV("attachToContext"); 186 Mutex::Autolock lock(mMutex); 187 188 if (mAbandoned) { 189 SFT_LOGE("attachToContext: abandoned SurfaceTexture"); 190 return NO_INIT; 191 } 192 193 if (mOpMode != OpMode::detached) { 194 SFT_LOGE( 195 "attachToContext: SurfaceTexture is already attached to a " 196 "context"); 197 return INVALID_OPERATION; 198 } 199 200 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { 201 // release possible ImageConsumer cache 202 mImageConsumer.onFreeBufferLocked(mCurrentTexture); 203 } 204 205 return mEGLConsumer.attachToContext(tex, *this); 206 } 207 208 void SurfaceTexture::attachToView() { 209 ATRACE_CALL(); 210 Mutex::Autolock _l(mMutex); 211 if (mAbandoned) { 212 SFT_LOGE("attachToView: abandoned SurfaceTexture"); 213 return; 214 } 215 if (mOpMode == OpMode::detached) { 216 mOpMode = OpMode::attachedToView; 217 218 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { 219 // release possible EGLConsumer texture cache 220 mEGLConsumer.onFreeBufferLocked(mCurrentTexture); 221 mEGLConsumer.onAbandonLocked(); 222 } 223 } else { 224 SFT_LOGE("attachToView: already attached"); 225 } 226 } 227 228 void SurfaceTexture::detachFromView() { 229 ATRACE_CALL(); 230 Mutex::Autolock _l(mMutex); 231 232 if (mAbandoned) { 233 SFT_LOGE("detachFromView: abandoned SurfaceTexture"); 234 return; 235 } 236 237 if (mOpMode == OpMode::attachedToView) { 238 mOpMode = OpMode::detached; 239 // Free all EglImage and VkImage before the context is destroyed. 240 for (int i=0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) { 241 mImageConsumer.onFreeBufferLocked(i); 242 } 243 } else { 244 SFT_LOGE("detachFromView: not attached to View"); 245 } 246 } 247 248 uint32_t SurfaceTexture::getCurrentTextureTarget() const { 249 return mTexTarget; 250 } 251 252 void SurfaceTexture::getTransformMatrix(float mtx[16]) { 253 Mutex::Autolock lock(mMutex); 254 memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); 255 } 256 257 void SurfaceTexture::setFilteringEnabled(bool enabled) { 258 Mutex::Autolock lock(mMutex); 259 if (mAbandoned) { 260 SFT_LOGE("setFilteringEnabled: SurfaceTexture is abandoned!"); 261 return; 262 } 263 bool needsRecompute = mFilteringEnabled != enabled; 264 mFilteringEnabled = enabled; 265 266 if (needsRecompute && mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) { 267 SFT_LOGD("setFilteringEnabled called with no current item"); 268 } 269 270 if (needsRecompute && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { 271 computeCurrentTransformMatrixLocked(); 272 } 273 } 274 275 void SurfaceTexture::computeCurrentTransformMatrixLocked() { 276 SFT_LOGV("computeCurrentTransformMatrixLocked"); 277 sp<GraphicBuffer> buf = (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) 278 ? nullptr 279 : mSlots[mCurrentTexture].mGraphicBuffer; 280 if (buf == nullptr) { 281 SFT_LOGD("computeCurrentTransformMatrixLocked: no current item"); 282 } 283 computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop, mCurrentTransform, 284 mFilteringEnabled); 285 } 286 287 void SurfaceTexture::computeTransformMatrix(float outTransform[16], const sp<GraphicBuffer>& buf, 288 const Rect& cropRect, uint32_t transform, 289 bool filtering) { 290 // Transform matrices 291 static const mat4 mtxFlipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); 292 static const mat4 mtxFlipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1); 293 static const mat4 mtxRot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); 294 295 mat4 xform; 296 if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { 297 xform *= mtxFlipH; 298 } 299 if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { 300 xform *= mtxFlipV; 301 } 302 if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { 303 xform *= mtxRot90; 304 } 305 306 if (!cropRect.isEmpty() && buf.get()) { 307 float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; 308 float bufferWidth = buf->getWidth(); 309 float bufferHeight = buf->getHeight(); 310 float shrinkAmount = 0.0f; 311 if (filtering) { 312 // In order to prevent bilinear sampling beyond the edge of the 313 // crop rectangle we may need to shrink it by 2 texels in each 314 // dimension. Normally this would just need to take 1/2 a texel 315 // off each end, but because the chroma channels of YUV420 images 316 // are subsampled we may need to shrink the crop region by a whole 317 // texel on each side. 318 switch (buf->getPixelFormat()) { 319 case PIXEL_FORMAT_RGBA_8888: 320 case PIXEL_FORMAT_RGBX_8888: 321 case PIXEL_FORMAT_RGBA_FP16: 322 case PIXEL_FORMAT_RGBA_1010102: 323 case PIXEL_FORMAT_RGB_888: 324 case PIXEL_FORMAT_RGB_565: 325 case PIXEL_FORMAT_BGRA_8888: 326 // We know there's no subsampling of any channels, so we 327 // only need to shrink by a half a pixel. 328 shrinkAmount = 0.5; 329 break; 330 331 default: 332 // If we don't recognize the format, we must assume the 333 // worst case (that we care about), which is YUV420. 334 shrinkAmount = 1.0; 335 break; 336 } 337 } 338 339 // Only shrink the dimensions that are not the size of the buffer. 340 if (cropRect.width() < bufferWidth) { 341 tx = (float(cropRect.left) + shrinkAmount) / bufferWidth; 342 sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / bufferWidth; 343 } 344 if (cropRect.height() < bufferHeight) { 345 ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / bufferHeight; 346 sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight; 347 } 348 349 mat4 crop(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1); 350 xform = crop * xform; 351 } 352 353 // SurfaceFlinger expects the top of its window textures to be at a Y 354 // coordinate of 0, so SurfaceTexture must behave the same way. We don't 355 // want to expose this to applications, however, so we must add an 356 // additional vertical flip to the transform after all the other transforms. 357 xform = mtxFlipV * xform; 358 359 memcpy(outTransform, xform.asArray(), sizeof(xform)); 360 } 361 362 Rect SurfaceTexture::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) { 363 Rect outCrop = crop; 364 365 uint32_t newWidth = static_cast<uint32_t>(crop.width()); 366 uint32_t newHeight = static_cast<uint32_t>(crop.height()); 367 368 if (newWidth * bufferHeight > newHeight * bufferWidth) { 369 newWidth = newHeight * bufferWidth / bufferHeight; 370 ALOGV("too wide: newWidth = %d", newWidth); 371 } else if (newWidth * bufferHeight < newHeight * bufferWidth) { 372 newHeight = newWidth * bufferHeight / bufferWidth; 373 ALOGV("too tall: newHeight = %d", newHeight); 374 } 375 376 uint32_t currentWidth = static_cast<uint32_t>(crop.width()); 377 uint32_t currentHeight = static_cast<uint32_t>(crop.height()); 378 379 // The crop is too wide 380 if (newWidth < currentWidth) { 381 uint32_t dw = currentWidth - newWidth; 382 auto halfdw = dw / 2; 383 outCrop.left += halfdw; 384 // Not halfdw because it would subtract 1 too few when dw is odd 385 outCrop.right -= (dw - halfdw); 386 // The crop is too tall 387 } else if (newHeight < currentHeight) { 388 uint32_t dh = currentHeight - newHeight; 389 auto halfdh = dh / 2; 390 outCrop.top += halfdh; 391 // Not halfdh because it would subtract 1 too few when dh is odd 392 outCrop.bottom -= (dh - halfdh); 393 } 394 395 ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]", outCrop.left, outCrop.top, outCrop.right, 396 outCrop.bottom); 397 398 return outCrop; 399 } 400 401 nsecs_t SurfaceTexture::getTimestamp() { 402 SFT_LOGV("getTimestamp"); 403 Mutex::Autolock lock(mMutex); 404 return mCurrentTimestamp; 405 } 406 407 android_dataspace SurfaceTexture::getCurrentDataSpace() { 408 SFT_LOGV("getCurrentDataSpace"); 409 Mutex::Autolock lock(mMutex); 410 return mCurrentDataSpace; 411 } 412 413 uint64_t SurfaceTexture::getFrameNumber() { 414 SFT_LOGV("getFrameNumber"); 415 Mutex::Autolock lock(mMutex); 416 return mCurrentFrameNumber; 417 } 418 419 Rect SurfaceTexture::getCurrentCrop() const { 420 Mutex::Autolock lock(mMutex); 421 return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) 422 ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight) 423 : mCurrentCrop; 424 } 425 426 uint32_t SurfaceTexture::getCurrentTransform() const { 427 Mutex::Autolock lock(mMutex); 428 return mCurrentTransform; 429 } 430 431 uint32_t SurfaceTexture::getCurrentScalingMode() const { 432 Mutex::Autolock lock(mMutex); 433 return mCurrentScalingMode; 434 } 435 436 sp<Fence> SurfaceTexture::getCurrentFence() const { 437 Mutex::Autolock lock(mMutex); 438 return mCurrentFence; 439 } 440 441 std::shared_ptr<FenceTime> SurfaceTexture::getCurrentFenceTime() const { 442 Mutex::Autolock lock(mMutex); 443 return mCurrentFenceTime; 444 } 445 446 void SurfaceTexture::freeBufferLocked(int slotIndex) { 447 SFT_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); 448 if (slotIndex == mCurrentTexture) { 449 mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; 450 } 451 // The slotIndex buffer could have EGL or SkImage cache, but there is no way to tell for sure. 452 // Buffers can be freed after SurfaceTexture has detached from GL context or View. 453 mImageConsumer.onFreeBufferLocked(slotIndex); 454 mEGLConsumer.onFreeBufferLocked(slotIndex); 455 ConsumerBase::freeBufferLocked(slotIndex); 456 } 457 458 void SurfaceTexture::abandonLocked() { 459 SFT_LOGV("abandonLocked"); 460 mEGLConsumer.onAbandonLocked(); 461 ConsumerBase::abandonLocked(); 462 } 463 464 status_t SurfaceTexture::setConsumerUsageBits(uint64_t usage) { 465 return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS); 466 } 467 468 void SurfaceTexture::dumpLocked(String8& result, const char* prefix) const { 469 result.appendFormat( 470 "%smTexName=%d mCurrentTexture=%d\n" 471 "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n", 472 prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left, mCurrentCrop.top, 473 mCurrentCrop.right, mCurrentCrop.bottom, mCurrentTransform); 474 475 ConsumerBase::dumpLocked(result, prefix); 476 } 477 478 sk_sp<SkImage> SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, bool* queueEmpty, 479 uirenderer::RenderState& renderState) { 480 Mutex::Autolock _l(mMutex); 481 482 if (mAbandoned) { 483 SFT_LOGE("dequeueImage: SurfaceTexture is abandoned!"); 484 return nullptr; 485 } 486 487 if (mOpMode != OpMode::attachedToView) { 488 SFT_LOGE("dequeueImage: SurfaceTexture is not attached to a View"); 489 return nullptr; 490 } 491 492 auto image = mImageConsumer.dequeueImage(queueEmpty, *this, renderState); 493 if (image.get()) { 494 uirenderer::mat4(mCurrentTransformMatrix).copyTo(transformMatrix); 495 } 496 return image; 497 } 498 499 } // namespace android 500