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