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