• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
181 #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
releaseBufferLocked(int buf,sp<GraphicBuffer> graphicBuffer)182 status_t SurfaceTexture::releaseBufferLocked(int buf, sp<GraphicBuffer> graphicBuffer) {
183 #else
184 status_t SurfaceTexture::releaseBufferLocked(int buf, sp<GraphicBuffer> graphicBuffer,
185                                              EGLDisplay display, EGLSyncKHR eglFence) {
186 #endif
187     // release the buffer if it hasn't already been discarded by the
188     // BufferQueue. This can happen, for example, when the producer of this
189     // buffer has reallocated the original buffer slot after this buffer
190     // was acquired.
191 #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
192     status_t err = ConsumerBase::releaseBufferLocked(buf, graphicBuffer);
193 #else
194     status_t err = ConsumerBase::releaseBufferLocked(buf, graphicBuffer, display, eglFence);
195 #endif
196     // We could be releasing an EGL/Vulkan buffer, even if not currently
197     // attached to a GL context.
198     mImageConsumer.onReleaseBufferLocked(buf);
199     mEGLConsumer.onReleaseBufferLocked(buf);
200     return err;
201 }
202 
203 status_t SurfaceTexture::detachFromContext() {
204     ATRACE_CALL();
205     SFT_LOGV("detachFromContext");
206     Mutex::Autolock lock(mMutex);
207 
208     if (mAbandoned) {
209         SFT_LOGE("detachFromContext: abandoned SurfaceTexture");
210         return NO_INIT;
211     }
212 
213     if (mOpMode != OpMode::attachedToGL) {
214         SFT_LOGE("detachFromContext: SurfaceTexture is not attached to a GL context");
215         return INVALID_OPERATION;
216     }
217 
218     status_t err = mEGLConsumer.detachFromContext(*this);
219     if (err == OK) {
220         mOpMode = OpMode::detached;
221     }
222 
223     return err;
224 }
225 
226 status_t SurfaceTexture::attachToContext(uint32_t tex) {
227     ATRACE_CALL();
228     SFT_LOGV("attachToContext");
229     Mutex::Autolock lock(mMutex);
230 
231     if (mAbandoned) {
232         SFT_LOGE("attachToContext: abandoned SurfaceTexture");
233         return NO_INIT;
234     }
235 
236     if (mOpMode != OpMode::detached) {
237         SFT_LOGE("attachToContext: SurfaceTexture is already attached to a "
238                  "context");
239         return INVALID_OPERATION;
240     }
241 
242     return mEGLConsumer.attachToContext(tex, *this);
243 }
244 
245 void SurfaceTexture::takeConsumerOwnership() {
246     ATRACE_CALL();
247     Mutex::Autolock _l(mMutex);
248     if (mAbandoned) {
249         SFT_LOGE("attachToView: abandoned SurfaceTexture");
250         return;
251     }
252     if (mOpMode == OpMode::detached) {
253         mOpMode = OpMode::attachedToConsumer;
254 
255         if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
256             // release possible EGLConsumer texture cache
257             mEGLConsumer.onFreeBufferLocked(mCurrentTexture);
258             mEGLConsumer.onAbandonLocked();
259         }
260     } else {
261         SFT_LOGE("attachToView: already attached");
262     }
263 }
264 
265 void SurfaceTexture::releaseConsumerOwnership() {
266     ATRACE_CALL();
267     Mutex::Autolock _l(mMutex);
268 
269     if (mAbandoned) {
270         SFT_LOGE("detachFromView: abandoned SurfaceTexture");
271         return;
272     }
273 
274     if (mOpMode == OpMode::attachedToConsumer) {
275         mOpMode = OpMode::detached;
276     } else {
277         SFT_LOGE("detachFromView: not attached to View");
278     }
279 }
280 
281 uint32_t SurfaceTexture::getCurrentTextureTarget() const {
282     return mTexTarget;
283 }
284 
285 void SurfaceTexture::getTransformMatrix(float mtx[16]) {
286     Mutex::Autolock lock(mMutex);
287     memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
288 }
289 
290 void SurfaceTexture::setFilteringEnabled(bool enabled) {
291     Mutex::Autolock lock(mMutex);
292     if (mAbandoned) {
293         SFT_LOGE("setFilteringEnabled: SurfaceTexture is abandoned!");
294         return;
295     }
296     bool needsRecompute = mFilteringEnabled != enabled;
297     mFilteringEnabled = enabled;
298 
299     if (needsRecompute && mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) {
300         SFT_LOGD("setFilteringEnabled called with no current item");
301     }
302 
303     if (needsRecompute && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
304         computeCurrentTransformMatrixLocked();
305     }
306 }
307 
308 void SurfaceTexture::computeCurrentTransformMatrixLocked() {
309     SFT_LOGV("computeCurrentTransformMatrixLocked");
310     sp<GraphicBuffer> buf = (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT)
311             ? nullptr
312             : mSlots[mCurrentTexture].mGraphicBuffer;
313     if (buf == nullptr) {
314         SFT_LOGD("computeCurrentTransformMatrixLocked: no current item");
315     }
316     computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop, mCurrentTransform,
317                            mFilteringEnabled);
318 }
319 
320 void SurfaceTexture::computeTransformMatrix(float outTransform[16], const sp<GraphicBuffer>& buf,
321                                             const Rect& cropRect, uint32_t transform,
322                                             bool filtering) {
323     // Transform matrices
324     static const mat4 mtxFlipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
325     static const mat4 mtxFlipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
326     static const mat4 mtxRot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
327 
328     mat4 xform;
329     if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
330         xform *= mtxFlipH;
331     }
332     if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
333         xform *= mtxFlipV;
334     }
335     if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
336         xform *= mtxRot90;
337     }
338 
339     if (!cropRect.isEmpty() && buf.get()) {
340         float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
341         float bufferWidth = buf->getWidth();
342         float bufferHeight = buf->getHeight();
343         float shrinkAmount = 0.0f;
344         if (filtering) {
345             // In order to prevent bilinear sampling beyond the edge of the
346             // crop rectangle we may need to shrink it by 2 texels in each
347             // dimension.  Normally this would just need to take 1/2 a texel
348             // off each end, but because the chroma channels of YUV420 images
349             // are subsampled we may need to shrink the crop region by a whole
350             // texel on each side.
351             switch (buf->getPixelFormat()) {
352                 case PIXEL_FORMAT_RGBA_8888:
353                 case PIXEL_FORMAT_RGBX_8888:
354                 case PIXEL_FORMAT_RGBA_FP16:
355                 case PIXEL_FORMAT_RGBA_1010102:
356                 case PIXEL_FORMAT_RGB_888:
357                 case PIXEL_FORMAT_RGB_565:
358                 case PIXEL_FORMAT_BGRA_8888:
359                     // We know there's no subsampling of any channels, so we
360                     // only need to shrink by a half a pixel.
361                     shrinkAmount = 0.5;
362                     break;
363 
364                 default:
365                     // If we don't recognize the format, we must assume the
366                     // worst case (that we care about), which is YUV420.
367                     shrinkAmount = 1.0;
368                     break;
369             }
370         }
371 
372         // Only shrink the dimensions that are not the size of the buffer.
373         if (cropRect.width() < bufferWidth) {
374             tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
375             sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / bufferWidth;
376         }
377         if (cropRect.height() < bufferHeight) {
378             ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / bufferHeight;
379             sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight;
380         }
381 
382         mat4 crop(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1);
383         xform = crop * xform;
384     }
385 
386     // SurfaceFlinger expects the top of its window textures to be at a Y
387     // coordinate of 0, so SurfaceTexture must behave the same way.  We don't
388     // want to expose this to applications, however, so we must add an
389     // additional vertical flip to the transform after all the other transforms.
390     xform = mtxFlipV * xform;
391 
392     memcpy(outTransform, xform.asArray(), sizeof(xform));
393 }
394 
395 Rect SurfaceTexture::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) {
396     Rect outCrop = crop;
397 
398     uint32_t newWidth = static_cast<uint32_t>(crop.width());
399     uint32_t newHeight = static_cast<uint32_t>(crop.height());
400 
401     if (newWidth * bufferHeight > newHeight * bufferWidth) {
402         newWidth = newHeight * bufferWidth / bufferHeight;
403         ALOGV("too wide: newWidth = %d", newWidth);
404     } else if (newWidth * bufferHeight < newHeight * bufferWidth) {
405         newHeight = newWidth * bufferHeight / bufferWidth;
406         ALOGV("too tall: newHeight = %d", newHeight);
407     }
408 
409     uint32_t currentWidth = static_cast<uint32_t>(crop.width());
410     uint32_t currentHeight = static_cast<uint32_t>(crop.height());
411 
412     // The crop is too wide
413     if (newWidth < currentWidth) {
414         uint32_t dw = currentWidth - newWidth;
415         auto halfdw = dw / 2;
416         outCrop.left += halfdw;
417         // Not halfdw because it would subtract 1 too few when dw is odd
418         outCrop.right -= (dw - halfdw);
419         // The crop is too tall
420     } else if (newHeight < currentHeight) {
421         uint32_t dh = currentHeight - newHeight;
422         auto halfdh = dh / 2;
423         outCrop.top += halfdh;
424         // Not halfdh because it would subtract 1 too few when dh is odd
425         outCrop.bottom -= (dh - halfdh);
426     }
427 
428     ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]", outCrop.left, outCrop.top, outCrop.right,
429           outCrop.bottom);
430 
431     return outCrop;
432 }
433 
434 nsecs_t SurfaceTexture::getTimestamp() {
435     SFT_LOGV("getTimestamp");
436     Mutex::Autolock lock(mMutex);
437     return mCurrentTimestamp;
438 }
439 
440 android_dataspace SurfaceTexture::getCurrentDataSpace() {
441     SFT_LOGV("getCurrentDataSpace");
442     Mutex::Autolock lock(mMutex);
443     return mCurrentDataSpace;
444 }
445 
446 uint64_t SurfaceTexture::getFrameNumber() {
447     SFT_LOGV("getFrameNumber");
448     Mutex::Autolock lock(mMutex);
449     return mCurrentFrameNumber;
450 }
451 
452 Rect SurfaceTexture::getCurrentCrop() const {
453     Mutex::Autolock lock(mMutex);
454     return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
455             ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
456             : mCurrentCrop;
457 }
458 
459 uint32_t SurfaceTexture::getCurrentTransform() const {
460     Mutex::Autolock lock(mMutex);
461     return mCurrentTransform;
462 }
463 
464 uint32_t SurfaceTexture::getCurrentScalingMode() const {
465     Mutex::Autolock lock(mMutex);
466     return mCurrentScalingMode;
467 }
468 
469 sp<Fence> SurfaceTexture::getCurrentFence() const {
470     Mutex::Autolock lock(mMutex);
471     return mCurrentFence;
472 }
473 
474 std::shared_ptr<FenceTime> SurfaceTexture::getCurrentFenceTime() const {
475     Mutex::Autolock lock(mMutex);
476     return mCurrentFenceTime;
477 }
478 
479 void SurfaceTexture::freeBufferLocked(int slotIndex) {
480     SFT_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
481     if (slotIndex == mCurrentTexture) {
482         mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
483     }
484     // The slotIndex buffer could have EGL cache, but there is no way to tell
485     // for sure. Buffers can be freed after SurfaceTexture has detached from GL
486     // context or View.
487     mEGLConsumer.onFreeBufferLocked(slotIndex);
488     ConsumerBase::freeBufferLocked(slotIndex);
489 }
490 
491 void SurfaceTexture::abandonLocked() {
492     SFT_LOGV("abandonLocked");
493     mEGLConsumer.onAbandonLocked();
494     ConsumerBase::abandonLocked();
495 }
496 
497 status_t SurfaceTexture::setConsumerUsageBits(uint64_t usage) {
498     return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
499 }
500 
501 void SurfaceTexture::dumpLocked(String8& result, const char* prefix) const {
502     result.appendFormat("%smTexName=%d mCurrentTexture=%d\n"
503                         "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
504                         prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
505                         mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
506                         mCurrentTransform);
507 
508     ConsumerBase::dumpLocked(result, prefix);
509 }
510 
511 sp<GraphicBuffer> SurfaceTexture::dequeueBuffer(int* outSlotid, android_dataspace* outDataspace,
512                                                 HdrMetadata* outHdrMetadata,
513                                                 float* outTransformMatrix, uint32_t* outTransform,
514                                                 bool* outQueueEmpty,
515                                                 SurfaceTexture_createReleaseFence createFence,
516                                                 SurfaceTexture_fenceWait fenceWait,
517                                                 void* fencePassThroughHandle, ARect* currentCrop) {
518     Mutex::Autolock _l(mMutex);
519     sp<GraphicBuffer> buffer;
520 
521     if (mAbandoned) {
522         SFT_LOGE("dequeueImage: SurfaceTexture is abandoned!");
523         return buffer;
524     }
525 
526     if (mOpMode != OpMode::attachedToConsumer) {
527         SFT_LOGE("dequeueImage: SurfaceTexture is not attached to a View");
528         return buffer;
529     }
530 
531     buffer = mImageConsumer.dequeueBuffer(outSlotid, outDataspace, outHdrMetadata, outQueueEmpty,
532                                           *this, createFence, fenceWait, fencePassThroughHandle);
533     memcpy(outTransformMatrix, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
534     *outTransform = mCurrentTransform;
535     *currentCrop = mCurrentCrop;
536     return buffer;
537 }
538 
539 void SurfaceTexture::setSurfaceTextureListener(
540         const sp<android::SurfaceTexture::SurfaceTextureListener>& listener) {
541     SFT_LOGV("setSurfaceTextureListener");
542 
543     Mutex::Autolock _l(mMutex);
544     mSurfaceTextureListener = listener;
545     if (mSurfaceTextureListener != nullptr) {
546         mFrameAvailableListenerProxy =
547                 sp<FrameAvailableListenerProxy>::make(mSurfaceTextureListener);
548         setFrameAvailableListener(mFrameAvailableListenerProxy);
549     } else {
550         mFrameAvailableListenerProxy.clear();
551     }
552 }
553 
554 void SurfaceTexture::FrameAvailableListenerProxy::onFrameAvailable(const BufferItem& item) {
555     const auto listener = mSurfaceTextureListener.promote();
556     if (listener) {
557         listener->onFrameAvailable(item);
558     }
559 }
560 
561 #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
562 void SurfaceTexture::onSetFrameRate(float frameRate, int8_t compatibility,
563                                     int8_t changeFrameRateStrategy) {
564     SFT_LOGV("onSetFrameRate: %.2f", frameRate);
565 
566     auto listener = [&] {
567         Mutex::Autolock _l(mMutex);
568         return mSurfaceTextureListener;
569     }();
570 
571     if (listener) {
572         listener->onSetFrameRate(frameRate, compatibility, changeFrameRateStrategy);
573     }
574 }
575 #endif
576 
577 void SurfaceTexture::initialize() {
578     SFT_LOGV("SurfaceTexture");
579 
580     memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
581 
582     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
583 }
584 
585 } // namespace android
586