blob: d3d4cbafdf862e4192816d810c304a3eeca9f4e7 [file] [log] [blame]
Stan Iliev94a4c4e2019-10-18 19:00:30 -04001/*
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>
Stan Iliev5d6bdb02020-01-13 11:19:44 -050019#include <surfacetexture/ImageConsumer.h>
20#include <surfacetexture/SurfaceTexture.h>
21#include <surfacetexture/surface_texture_platform.h>
Stan Iliev94a4c4e2019-10-18 19:00:30 -040022#include <math/mat4.h>
23#include <system/window.h>
24#include <utils/Trace.h>
25
26namespace 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
34static const mat4 mtxIdentity;
35
36SurfaceTexture::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
61SurfaceTexture::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
86status_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
97status_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
110status_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
124status_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
144status_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
158status_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
181status_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
200void 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
220void 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
236uint32_t SurfaceTexture::getCurrentTextureTarget() const {
237 return mTexTarget;
238}
239
240void SurfaceTexture::getTransformMatrix(float mtx[16]) {
241 Mutex::Autolock lock(mMutex);
242 memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
243}
244
245void 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
263void 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
275void 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
350Rect 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
389nsecs_t SurfaceTexture::getTimestamp() {
390 SFT_LOGV("getTimestamp");
391 Mutex::Autolock lock(mMutex);
392 return mCurrentTimestamp;
393}
394
395android_dataspace SurfaceTexture::getCurrentDataSpace() {
396 SFT_LOGV("getCurrentDataSpace");
397 Mutex::Autolock lock(mMutex);
398 return mCurrentDataSpace;
399}
400
401uint64_t SurfaceTexture::getFrameNumber() {
402 SFT_LOGV("getFrameNumber");
403 Mutex::Autolock lock(mMutex);
404 return mCurrentFrameNumber;
405}
406
407Rect 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
414uint32_t SurfaceTexture::getCurrentTransform() const {
415 Mutex::Autolock lock(mMutex);
416 return mCurrentTransform;
417}
418
419uint32_t SurfaceTexture::getCurrentScalingMode() const {
420 Mutex::Autolock lock(mMutex);
421 return mCurrentScalingMode;
422}
423
424sp<Fence> SurfaceTexture::getCurrentFence() const {
425 Mutex::Autolock lock(mMutex);
426 return mCurrentFence;
427}
428
429std::shared_ptr<FenceTime> SurfaceTexture::getCurrentFenceTime() const {
430 Mutex::Autolock lock(mMutex);
431 return mCurrentFenceTime;
432}
433
434void 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
446void SurfaceTexture::abandonLocked() {
447 SFT_LOGV("abandonLocked");
448 mEGLConsumer.onAbandonLocked();
449 ConsumerBase::abandonLocked();
450}
451
452status_t SurfaceTexture::setConsumerUsageBits(uint64_t usage) {
453 return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
454}
455
456void 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
466sp<GraphicBuffer> SurfaceTexture::dequeueBuffer(int* outSlotid, android_dataspace* outDataspace,
Alec Mouri78fc89a2021-11-21 16:59:30 -0800467 HdrMetadata* outHdrMetadata,
ramindani184a2d32021-08-06 22:35:43 +0000468 float* outTransformMatrix, uint32_t* outTransform,
469 bool* outQueueEmpty,
Stan Iliev94a4c4e2019-10-18 19:00:30 -0400470 SurfaceTexture_createReleaseFence createFence,
471 SurfaceTexture_fenceWait fenceWait,
ramindani184a2d32021-08-06 22:35:43 +0000472 void* fencePassThroughHandle, ARect* currentCrop) {
Stan Iliev94a4c4e2019-10-18 19:00:30 -0400473 Mutex::Autolock _l(mMutex);
474 sp<GraphicBuffer> buffer;
475
476 if (mAbandoned) {
477 SFT_LOGE("dequeueImage: SurfaceTexture is abandoned!");
478 return buffer;
479 }
480
481 if (mOpMode != OpMode::attachedToConsumer) {
482 SFT_LOGE("dequeueImage: SurfaceTexture is not attached to a View");
483 return buffer;
484 }
485
Alec Mouri78fc89a2021-11-21 16:59:30 -0800486 buffer = mImageConsumer.dequeueBuffer(outSlotid, outDataspace, outHdrMetadata, outQueueEmpty,
487 *this, createFence, fenceWait, fencePassThroughHandle);
bsears619eea32021-08-06 15:18:26 +0000488 memcpy(outTransformMatrix, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
ramindani184a2d32021-08-06 22:35:43 +0000489 *outTransform = mCurrentTransform;
490 *currentCrop = mCurrentCrop;
Stan Iliev94a4c4e2019-10-18 19:00:30 -0400491 return buffer;
492}
493
Stan Iliev94a4c4e2019-10-18 19:00:30 -0400494} // namespace android