• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SurfaceTexture(const sp<IGraphicBufferConsumer> & bq,uint32_t tex,uint32_t texTarget,bool useFenceSync,bool isControlledByApp)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 
SurfaceTexture(const sp<IGraphicBufferConsumer> & bq,uint32_t texTarget,bool useFenceSync,bool isControlledByApp)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 
setDefaultBufferSize(uint32_t w,uint32_t h)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 
updateTexImage()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 
releaseTexImage()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 
acquireBufferLocked(BufferItem * item,nsecs_t presentWhen,uint64_t maxFrameNumber)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 
releaseBufferLocked(int buf,sp<GraphicBuffer> graphicBuffer,EGLDisplay display,EGLSyncKHR eglFence)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 
detachFromContext()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 
attachToContext(uint32_t tex)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 
attachToView()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 
detachFromView()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 
getCurrentTextureTarget() const248 uint32_t SurfaceTexture::getCurrentTextureTarget() const {
249     return mTexTarget;
250 }
251 
getTransformMatrix(float mtx[16])252 void SurfaceTexture::getTransformMatrix(float mtx[16]) {
253     Mutex::Autolock lock(mMutex);
254     memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
255 }
256 
setFilteringEnabled(bool enabled)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 
computeCurrentTransformMatrixLocked()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 
computeTransformMatrix(float outTransform[16],const sp<GraphicBuffer> & buf,const Rect & cropRect,uint32_t transform,bool filtering)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 
scaleDownCrop(const Rect & crop,uint32_t bufferWidth,uint32_t bufferHeight)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 
getTimestamp()401 nsecs_t SurfaceTexture::getTimestamp() {
402     SFT_LOGV("getTimestamp");
403     Mutex::Autolock lock(mMutex);
404     return mCurrentTimestamp;
405 }
406 
getCurrentDataSpace()407 android_dataspace SurfaceTexture::getCurrentDataSpace() {
408     SFT_LOGV("getCurrentDataSpace");
409     Mutex::Autolock lock(mMutex);
410     return mCurrentDataSpace;
411 }
412 
getFrameNumber()413 uint64_t SurfaceTexture::getFrameNumber() {
414     SFT_LOGV("getFrameNumber");
415     Mutex::Autolock lock(mMutex);
416     return mCurrentFrameNumber;
417 }
418 
getCurrentCrop() const419 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 
getCurrentTransform() const426 uint32_t SurfaceTexture::getCurrentTransform() const {
427     Mutex::Autolock lock(mMutex);
428     return mCurrentTransform;
429 }
430 
getCurrentScalingMode() const431 uint32_t SurfaceTexture::getCurrentScalingMode() const {
432     Mutex::Autolock lock(mMutex);
433     return mCurrentScalingMode;
434 }
435 
getCurrentFence() const436 sp<Fence> SurfaceTexture::getCurrentFence() const {
437     Mutex::Autolock lock(mMutex);
438     return mCurrentFence;
439 }
440 
getCurrentFenceTime() const441 std::shared_ptr<FenceTime> SurfaceTexture::getCurrentFenceTime() const {
442     Mutex::Autolock lock(mMutex);
443     return mCurrentFenceTime;
444 }
445 
freeBufferLocked(int slotIndex)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 
abandonLocked()458 void SurfaceTexture::abandonLocked() {
459     SFT_LOGV("abandonLocked");
460     mEGLConsumer.onAbandonLocked();
461     ConsumerBase::abandonLocked();
462 }
463 
setConsumerUsageBits(uint64_t usage)464 status_t SurfaceTexture::setConsumerUsageBits(uint64_t usage) {
465     return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
466 }
467 
dumpLocked(String8 & result,const char * prefix) const468 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 
dequeueImage(SkMatrix & transformMatrix,bool * queueEmpty,uirenderer::RenderState & renderState)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