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