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