blob: 6f842067caf7b9af5f58ac52aae73310f664b441 [file] [log] [blame]
Jamie Gennis8ba32fa2010-12-20 11:27:26 -08001/*
2 * Copyright (C) 2010 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#define LOG_TAG "SurfaceTexture"
Jamie Gennise70d8b42011-01-09 13:24:09 -080018//#define LOG_NDEBUG 0
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080019
20#define GL_GLEXT_PROTOTYPES
21#define EGL_EGLEXT_PROTOTYPES
22
23#include <EGL/egl.h>
24#include <EGL/eglext.h>
25#include <GLES2/gl2.h>
26#include <GLES2/gl2ext.h>
27
28#include <gui/SurfaceTexture.h>
29
Mathias Agopian7a042bf2011-04-11 21:19:55 -070030#include <hardware/hardware.h>
31
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080032#include <surfaceflinger/ISurfaceComposer.h>
33#include <surfaceflinger/SurfaceComposerClient.h>
Jamie Gennis9a78c902011-01-12 18:30:40 -080034#include <surfaceflinger/IGraphicBufferAlloc.h>
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080035
36#include <utils/Log.h>
Mathias Agopian68c77942011-05-09 19:08:33 -070037#include <utils/String8.h>
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080038
Mathias Agopian29b57622011-08-17 15:42:04 -070039
40#define ALLOW_DEQUEUE_CURRENT_BUFFER false
41
Jamie Gennisfa28c352011-09-16 17:30:26 -070042// Macros for including the SurfaceTexture name in log messages
43#define ST_LOGV(x, ...) LOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
44#define ST_LOGD(x, ...) LOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
45#define ST_LOGI(x, ...) LOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
46#define ST_LOGW(x, ...) LOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
47#define ST_LOGE(x, ...) LOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
Mathias Agopian29b57622011-08-17 15:42:04 -070048
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080049namespace android {
50
Jamie Gennisf238e282011-01-09 16:33:17 -080051// Transform matrices
52static float mtxIdentity[16] = {
53 1, 0, 0, 0,
54 0, 1, 0, 0,
55 0, 0, 1, 0,
56 0, 0, 0, 1,
57};
58static float mtxFlipH[16] = {
59 -1, 0, 0, 0,
60 0, 1, 0, 0,
61 0, 0, 1, 0,
62 1, 0, 0, 1,
63};
64static float mtxFlipV[16] = {
65 1, 0, 0, 0,
66 0, -1, 0, 0,
67 0, 0, 1, 0,
68 0, 1, 0, 1,
69};
70static float mtxRot90[16] = {
71 0, 1, 0, 0,
72 -1, 0, 0, 0,
73 0, 0, 1, 0,
74 1, 0, 0, 1,
75};
76static float mtxRot180[16] = {
77 -1, 0, 0, 0,
78 0, -1, 0, 0,
79 0, 0, 1, 0,
80 1, 1, 0, 1,
81};
82static float mtxRot270[16] = {
83 0, -1, 0, 0,
84 1, 0, 0, 0,
85 0, 0, 1, 0,
86 0, 1, 0, 1,
87};
88
89static void mtxMul(float out[16], const float a[16], const float b[16]);
90
Jamie Gennisfa28c352011-09-16 17:30:26 -070091// Get an ID that's unique within this process.
92static int32_t createProcessUniqueId() {
93 static volatile int32_t globalCounter = 0;
94 return android_atomic_inc(&globalCounter);
95}
96
Jamie Gennisfb1b5a22011-09-28 12:13:31 -070097SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
98 GLenum texTarget) :
Mathias Agopiana5c75c02011-03-31 19:10:24 -070099 mDefaultWidth(1),
100 mDefaultHeight(1),
101 mPixelFormat(PIXEL_FORMAT_RGBA_8888),
Mathias Agopian80727112011-05-02 19:51:12 -0700102 mBufferCount(MIN_ASYNC_BUFFER_SLOTS),
103 mClientBufferCount(0),
104 mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800105 mCurrentTexture(INVALID_BUFFER_SLOT),
106 mCurrentTransform(0),
107 mCurrentTimestamp(0),
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800108 mNextTransform(0),
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700109 mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700110 mTexName(tex),
Grace Kloba14a0e582011-06-23 21:21:47 -0700111 mSynchronousMode(false),
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700112 mAllowSynchronousMode(allowSynchronousMode),
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700113 mConnectedApi(NO_CONNECTED_API),
Jamie Gennisfb1b5a22011-09-28 12:13:31 -0700114 mAbandoned(false),
115 mTexTarget(texTarget) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700116 // Choose a name using the PID and a process-unique ID.
117 mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
118
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700119 ST_LOGV("SurfaceTexture");
Jamie Gennis9a78c902011-01-12 18:30:40 -0800120 sp<ISurfaceComposer> composer(ComposerService::getComposerService());
121 mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
Mathias Agopiancc57d6f2011-04-27 18:57:33 -0700122 mNextCrop.makeInvalid();
Jamie Gennisfa28c352011-09-16 17:30:26 -0700123 memcpy(mCurrentTransformMatrix, mtxIdentity,
124 sizeof(mCurrentTransformMatrix));
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800125}
126
127SurfaceTexture::~SurfaceTexture() {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700128 ST_LOGV("~SurfaceTexture");
Mathias Agopianef51b992011-08-10 15:28:58 -0700129 freeAllBuffersLocked();
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800130}
131
Mathias Agopian80727112011-05-02 19:51:12 -0700132status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) {
133 if (bufferCount > NUM_BUFFER_SLOTS)
134 return BAD_VALUE;
135
136 // special-case, nothing to do
137 if (bufferCount == mBufferCount)
138 return OK;
139
140 if (!mClientBufferCount &&
141 bufferCount >= mBufferCount) {
142 // easy, we just have more buffers
143 mBufferCount = bufferCount;
144 mServerBufferCount = bufferCount;
145 mDequeueCondition.signal();
146 } else {
147 // we're here because we're either
148 // - reducing the number of available buffers
149 // - or there is a client-buffer-count in effect
150
151 // less than 2 buffers is never allowed
152 if (bufferCount < 2)
153 return BAD_VALUE;
154
155 // when there is non client-buffer-count in effect, the client is not
156 // allowed to dequeue more than one buffer at a time,
157 // so the next time they dequeue a buffer, we know that they don't
158 // own one. the actual resizing will happen during the next
159 // dequeueBuffer.
160
161 mServerBufferCount = bufferCount;
162 }
163 return OK;
164}
165
166status_t SurfaceTexture::setBufferCountServer(int bufferCount) {
167 Mutex::Autolock lock(mMutex);
168 return setBufferCountServerLocked(bufferCount);
169}
170
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800171status_t SurfaceTexture::setBufferCount(int bufferCount) {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700172 ST_LOGV("setBufferCount: count=%d", bufferCount);
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700173 Mutex::Autolock lock(mMutex);
Jamie Gennis9d4d6c12011-02-27 14:10:20 -0800174
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700175 if (mAbandoned) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700176 ST_LOGE("setBufferCount: SurfaceTexture has been abandoned!");
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700177 return NO_INIT;
178 }
Pannag Sanketi292a31a2011-06-24 09:56:27 -0700179 if (bufferCount > NUM_BUFFER_SLOTS) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700180 ST_LOGE("setBufferCount: bufferCount larger than slots available");
Pannag Sanketi292a31a2011-06-24 09:56:27 -0700181 return BAD_VALUE;
182 }
183
Mathias Agopian80727112011-05-02 19:51:12 -0700184 // Error out if the user has dequeued buffers
185 for (int i=0 ; i<mBufferCount ; i++) {
186 if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700187 ST_LOGE("setBufferCount: client owns some buffers");
Mathias Agopian80727112011-05-02 19:51:12 -0700188 return -EINVAL;
189 }
190 }
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700191
Jamie Gennis1c121f62011-07-30 16:00:11 -0700192 const int minBufferSlots = mSynchronousMode ?
193 MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
Mathias Agopian80727112011-05-02 19:51:12 -0700194 if (bufferCount == 0) {
Mathias Agopian80727112011-05-02 19:51:12 -0700195 mClientBufferCount = 0;
196 bufferCount = (mServerBufferCount >= minBufferSlots) ?
197 mServerBufferCount : minBufferSlots;
198 return setBufferCountServerLocked(bufferCount);
199 }
200
Jamie Gennis1c121f62011-07-30 16:00:11 -0700201 if (bufferCount < minBufferSlots) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700202 ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
Jamie Gennis1c121f62011-07-30 16:00:11 -0700203 "minimum (%d)", bufferCount, minBufferSlots);
Jamie Gennis9d4d6c12011-02-27 14:10:20 -0800204 return BAD_VALUE;
205 }
206
Mathias Agopian80727112011-05-02 19:51:12 -0700207 // here we're guaranteed that the client doesn't have dequeued buffers
208 // and will release all of its buffer references.
Mathias Agopianef51b992011-08-10 15:28:58 -0700209 freeAllBuffersLocked();
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800210 mBufferCount = bufferCount;
Mathias Agopian80727112011-05-02 19:51:12 -0700211 mClientBufferCount = bufferCount;
Jamie Gennis67eedd72011-01-09 13:25:39 -0800212 mCurrentTexture = INVALID_BUFFER_SLOT;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700213 mQueue.clear();
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700214 mDequeueCondition.signal();
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800215 return OK;
216}
217
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700218status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
219{
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700220 ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
Mathias Agopian3fbce7c2011-07-25 19:56:08 -0700221 if (!w || !h) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700222 ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
223 w, h);
Mathias Agopian3fbce7c2011-07-25 19:56:08 -0700224 return BAD_VALUE;
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700225 }
Mathias Agopian3fbce7c2011-07-25 19:56:08 -0700226
227 Mutex::Autolock lock(mMutex);
228 mDefaultWidth = w;
229 mDefaultHeight = h;
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700230 return OK;
231}
232
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700233status_t SurfaceTexture::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700234 ST_LOGV("requestBuffer: slot=%d", slot);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800235 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700236 if (mAbandoned) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700237 ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700238 return NO_INIT;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800239 }
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700240 if (slot < 0 || mBufferCount <= slot) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700241 ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700242 mBufferCount, slot);
243 return BAD_VALUE;
244 }
245 mSlots[slot].mRequestBufferCalled = true;
246 *buf = mSlots[slot].mGraphicBuffer;
247 return NO_ERROR;
Mathias Agopianc04f1532011-04-25 20:22:14 -0700248}
249
250status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
251 uint32_t format, uint32_t usage) {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700252 ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
Mathias Agopianc04f1532011-04-25 20:22:14 -0700253
Pannag Sanketi292a31a2011-06-24 09:56:27 -0700254 if ((w && !h) || (!w && h)) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700255 ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
Mathias Agopianc04f1532011-04-25 20:22:14 -0700256 return BAD_VALUE;
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700257 }
258
Mathias Agopianc04f1532011-04-25 20:22:14 -0700259 Mutex::Autolock lock(mMutex);
Mathias Agopian80727112011-05-02 19:51:12 -0700260
261 status_t returnFlags(OK);
262
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700263 int found, foundSync;
264 int dequeuedCount = 0;
265 bool tryAgain = true;
266 while (tryAgain) {
Mathias Agopian2560d142011-08-10 16:33:23 -0700267 if (mAbandoned) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700268 ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
Mathias Agopian2560d142011-08-10 16:33:23 -0700269 return NO_INIT;
270 }
Mathias Agopian2560d142011-08-10 16:33:23 -0700271
Mathias Agopian80727112011-05-02 19:51:12 -0700272 // We need to wait for the FIFO to drain if the number of buffer
273 // needs to change.
274 //
Mathias Agopian2560d142011-08-10 16:33:23 -0700275 // The condition "number of buffers needs to change" is true if
Mathias Agopian80727112011-05-02 19:51:12 -0700276 // - the client doesn't care about how many buffers there are
277 // - AND the actual number of buffer is different from what was
278 // set in the last setBufferCountServer()
279 // - OR -
280 // setBufferCountServer() was set to a value incompatible with
281 // the synchronization mode (for instance because the sync mode
282 // changed since)
283 //
284 // As long as this condition is true AND the FIFO is not empty, we
285 // wait on mDequeueCondition.
286
Mathias Agopian2560d142011-08-10 16:33:23 -0700287 const int minBufferCountNeeded = mSynchronousMode ?
Mathias Agopian80727112011-05-02 19:51:12 -0700288 MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
289
Mathias Agopian2560d142011-08-10 16:33:23 -0700290 const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
Mathias Agopian80727112011-05-02 19:51:12 -0700291 ((mServerBufferCount != mBufferCount) ||
Mathias Agopian2560d142011-08-10 16:33:23 -0700292 (mServerBufferCount < minBufferCountNeeded));
293
294 if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
Mathias Agopian80727112011-05-02 19:51:12 -0700295 // wait for the FIFO to drain
Mathias Agopian2560d142011-08-10 16:33:23 -0700296 mDequeueCondition.wait(mMutex);
297 // NOTE: we continue here because we need to reevaluate our
298 // whole state (eg: we could be abandoned or disconnected)
299 continue;
Mathias Agopian80727112011-05-02 19:51:12 -0700300 }
301
Mathias Agopian2560d142011-08-10 16:33:23 -0700302 if (numberOfBuffersNeedsToChange) {
Mathias Agopian80727112011-05-02 19:51:12 -0700303 // here we're guaranteed that mQueue is empty
Mathias Agopianef51b992011-08-10 15:28:58 -0700304 freeAllBuffersLocked();
Mathias Agopian80727112011-05-02 19:51:12 -0700305 mBufferCount = mServerBufferCount;
306 if (mBufferCount < minBufferCountNeeded)
307 mBufferCount = minBufferCountNeeded;
308 mCurrentTexture = INVALID_BUFFER_SLOT;
309 returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
310 }
311
312 // look for a free buffer to give to the client
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700313 found = INVALID_BUFFER_SLOT;
314 foundSync = INVALID_BUFFER_SLOT;
315 dequeuedCount = 0;
316 for (int i = 0; i < mBufferCount; i++) {
317 const int state = mSlots[i].mBufferState;
318 if (state == BufferSlot::DEQUEUED) {
319 dequeuedCount++;
320 }
Mathias Agopian29b57622011-08-17 15:42:04 -0700321
322 // if buffer is FREE it CANNOT be current
323 LOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
324 "dequeueBuffer: buffer %d is both FREE and current!", i);
325
326 if (ALLOW_DEQUEUE_CURRENT_BUFFER) {
327 if (state == BufferSlot::FREE || i == mCurrentTexture) {
328 foundSync = i;
329 if (i != mCurrentTexture) {
330 found = i;
331 break;
332 }
333 }
334 } else {
335 if (state == BufferSlot::FREE) {
336 foundSync = i;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700337 found = i;
338 break;
339 }
340 }
341 }
Mathias Agopian80727112011-05-02 19:51:12 -0700342
343 // clients are not allowed to dequeue more than one buffer
344 // if they didn't set a buffer count.
345 if (!mClientBufferCount && dequeuedCount) {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700346 ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
347 "setting the buffer count");
Mathias Agopian80727112011-05-02 19:51:12 -0700348 return -EINVAL;
349 }
350
Jamie Gennisc2c8dfd2011-05-23 18:44:04 -0700351 // See whether a buffer has been queued since the last setBufferCount so
352 // we know whether to perform the MIN_UNDEQUEUED_BUFFERS check below.
353 bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
354 if (bufferHasBeenQueued) {
355 // make sure the client is not trying to dequeue more buffers
356 // than allowed.
357 const int avail = mBufferCount - (dequeuedCount+1);
358 if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700359 ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
360 "(dequeued=%d)",
Jamie Gennisc2c8dfd2011-05-23 18:44:04 -0700361 MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
362 dequeuedCount);
363 return -EBUSY;
364 }
Mathias Agopian80727112011-05-02 19:51:12 -0700365 }
366
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700367 // we're in synchronous mode and didn't find a buffer, we need to wait
Mathias Agopian29b57622011-08-17 15:42:04 -0700368 // for some buffers to be consumed
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700369 tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
370 if (tryAgain) {
371 mDequeueCondition.wait(mMutex);
Mathias Agopianc04f1532011-04-25 20:22:14 -0700372 }
373 }
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700374
Mathias Agopian80727112011-05-02 19:51:12 -0700375 if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
376 // foundSync guaranteed to be != INVALID_BUFFER_SLOT
377 found = foundSync;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700378 }
379
Mathias Agopianc04f1532011-04-25 20:22:14 -0700380 if (found == INVALID_BUFFER_SLOT) {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700381 // This should not happen.
382 ST_LOGE("dequeueBuffer: no available buffer slots");
Mathias Agopianc04f1532011-04-25 20:22:14 -0700383 return -EBUSY;
384 }
385
386 const int buf = found;
387 *outBuf = found;
388
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700389 const bool useDefaultSize = !w && !h;
390 if (useDefaultSize) {
391 // use the default size
392 w = mDefaultWidth;
393 h = mDefaultHeight;
394 }
395
396 const bool updateFormat = (format != 0);
397 if (!updateFormat) {
398 // keep the current (or default) format
399 format = mPixelFormat;
400 }
401
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700402 // buffer is now in DEQUEUED (but can also be current at the same time,
403 // if we're in synchronous mode)
404 mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
405
406 const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
Mathias Agopianc04f1532011-04-25 20:22:14 -0700407 if ((buffer == NULL) ||
408 (uint32_t(buffer->width) != w) ||
409 (uint32_t(buffer->height) != h) ||
410 (uint32_t(buffer->format) != format) ||
411 ((uint32_t(buffer->usage) & usage) != usage))
412 {
413 usage |= GraphicBuffer::USAGE_HW_TEXTURE;
Mathias Agopiand9e8c642011-07-01 14:53:49 -0700414 status_t error;
Mathias Agopianc04f1532011-04-25 20:22:14 -0700415 sp<GraphicBuffer> graphicBuffer(
Mathias Agopiand9e8c642011-07-01 14:53:49 -0700416 mGraphicBufferAlloc->createGraphicBuffer(
417 w, h, format, usage, &error));
Mathias Agopianc04f1532011-04-25 20:22:14 -0700418 if (graphicBuffer == 0) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700419 ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
420 "failed");
Mathias Agopiand9e8c642011-07-01 14:53:49 -0700421 return error;
Mathias Agopianc04f1532011-04-25 20:22:14 -0700422 }
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700423 if (updateFormat) {
424 mPixelFormat = format;
425 }
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800426 mSlots[buf].mGraphicBuffer = graphicBuffer;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700427 mSlots[buf].mRequestBufferCalled = false;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800428 if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
429 eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage);
430 mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
431 mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
432 }
Mathias Agopian80727112011-05-02 19:51:12 -0700433 returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700434 }
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700435 ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", buf,
436 mSlots[buf].mGraphicBuffer->handle, returnFlags);
Mathias Agopian80727112011-05-02 19:51:12 -0700437 return returnFlags;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800438}
439
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700440status_t SurfaceTexture::setSynchronousMode(bool enabled) {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700441 ST_LOGV("setSynchronousMode: enabled=%d", enabled);
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700442 Mutex::Autolock lock(mMutex);
Mathias Agopian80727112011-05-02 19:51:12 -0700443
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700444 if (mAbandoned) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700445 ST_LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700446 return NO_INIT;
447 }
448
Mathias Agopian80727112011-05-02 19:51:12 -0700449 status_t err = OK;
Grace Kloba14a0e582011-06-23 21:21:47 -0700450 if (!mAllowSynchronousMode && enabled)
451 return err;
452
Mathias Agopian80727112011-05-02 19:51:12 -0700453 if (!enabled) {
454 // going to asynchronous mode, drain the queue
Mathias Agopian8e19c2e2011-08-10 17:35:09 -0700455 err = drainQueueLocked();
456 if (err != NO_ERROR)
457 return err;
Mathias Agopian80727112011-05-02 19:51:12 -0700458 }
459
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700460 if (mSynchronousMode != enabled) {
Mathias Agopian80727112011-05-02 19:51:12 -0700461 // - if we're going to asynchronous mode, the queue is guaranteed to be
462 // empty here
463 // - if the client set the number of buffers, we're guaranteed that
464 // we have at least 3 (because we don't allow less)
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700465 mSynchronousMode = enabled;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700466 mDequeueCondition.signal();
467 }
Mathias Agopian80727112011-05-02 19:51:12 -0700468 return err;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700469}
470
Mathias Agopian97c602c2011-07-19 15:24:46 -0700471status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp,
472 uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700473 ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp);
Mathias Agopiancf46eb92011-05-11 15:05:29 -0700474
475 sp<FrameAvailableListener> listener;
476
477 { // scope for the lock
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700478 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700479 if (mAbandoned) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700480 ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700481 return NO_INIT;
482 }
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700483 if (buf < 0 || buf >= mBufferCount) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700484 ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700485 mBufferCount, buf);
486 return -EINVAL;
487 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700488 ST_LOGE("queueBuffer: slot %d is not owned by the client "
489 "(state=%d)", buf, mSlots[buf].mBufferState);
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700490 return -EINVAL;
491 } else if (buf == mCurrentTexture) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700492 ST_LOGE("queueBuffer: slot %d is current!", buf);
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700493 return -EINVAL;
494 } else if (!mSlots[buf].mRequestBufferCalled) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700495 ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700496 "buffer", buf);
497 return -EINVAL;
498 }
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700499
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700500 if (mSynchronousMode) {
Jamie Gennis3d8063b2011-06-26 18:27:47 -0700501 // In synchronous mode we queue all buffers in a FIFO.
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700502 mQueue.push_back(buf);
Jamie Gennis3d8063b2011-06-26 18:27:47 -0700503
504 // Synchronous mode always signals that an additional frame should
505 // be consumed.
506 listener = mFrameAvailableListener;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700507 } else {
Jamie Gennis3d8063b2011-06-26 18:27:47 -0700508 // In asynchronous mode we only keep the most recent buffer.
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700509 if (mQueue.empty()) {
510 mQueue.push_back(buf);
Jamie Gennis3d8063b2011-06-26 18:27:47 -0700511
512 // Asynchronous mode only signals that a frame should be
513 // consumed if no previous frame was pending. If a frame were
514 // pending then the consumer would have already been notified.
515 listener = mFrameAvailableListener;
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700516 } else {
517 Fifo::iterator front(mQueue.begin());
518 // buffer currently queued is freed
519 mSlots[*front].mBufferState = BufferSlot::FREE;
520 // and we record the new buffer index in the queued list
521 *front = buf;
522 }
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700523 }
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700524
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700525 mSlots[buf].mBufferState = BufferSlot::QUEUED;
526 mSlots[buf].mCrop = mNextCrop;
527 mSlots[buf].mTransform = mNextTransform;
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700528 mSlots[buf].mScalingMode = mNextScalingMode;
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700529 mSlots[buf].mTimestamp = timestamp;
530 mDequeueCondition.signal();
Mathias Agopian3902be62011-08-17 12:45:40 -0700531
532 *outWidth = mDefaultWidth;
533 *outHeight = mDefaultHeight;
534 *outTransform = 0;
Mathias Agopiancf46eb92011-05-11 15:05:29 -0700535 } // scope for the lock
536
537 // call back without lock held
538 if (listener != 0) {
539 listener->onFrameAvailable();
540 }
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800541 return OK;
542}
543
544void SurfaceTexture::cancelBuffer(int buf) {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700545 ST_LOGV("cancelBuffer: slot=%d", buf);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800546 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700547
548 if (mAbandoned) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700549 ST_LOGW("cancelBuffer: SurfaceTexture has been abandoned!");
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700550 return;
551 }
552
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700553 if (buf < 0 || buf >= mBufferCount) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700554 ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700555 mBufferCount, buf);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800556 return;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700557 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700558 ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700559 buf, mSlots[buf].mBufferState);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800560 return;
561 }
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700562 mSlots[buf].mBufferState = BufferSlot::FREE;
563 mDequeueCondition.signal();
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800564}
565
Jamie Gennisf238e282011-01-09 16:33:17 -0800566status_t SurfaceTexture::setCrop(const Rect& crop) {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700567 ST_LOGV("setCrop: crop=[%d,%d,%d,%d]", crop.left, crop.top, crop.right,
568 crop.bottom);
569
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800570 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700571 if (mAbandoned) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700572 ST_LOGE("setCrop: SurfaceTexture has been abandoned!");
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700573 return NO_INIT;
574 }
Jamie Gennisf238e282011-01-09 16:33:17 -0800575 mNextCrop = crop;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800576 return OK;
577}
578
579status_t SurfaceTexture::setTransform(uint32_t transform) {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700580 ST_LOGV("setTransform: xform=%#x", transform);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800581 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700582 if (mAbandoned) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700583 ST_LOGE("setTransform: SurfaceTexture has been abandoned!");
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700584 return NO_INIT;
585 }
Jamie Gennisf238e282011-01-09 16:33:17 -0800586 mNextTransform = transform;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800587 return OK;
588}
589
Mathias Agopian5bfc2452011-08-08 19:14:03 -0700590status_t SurfaceTexture::connect(int api,
591 uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700592 ST_LOGV("connect: api=%d", api);
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700593 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700594
595 if (mAbandoned) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700596 ST_LOGE("connect: SurfaceTexture has been abandoned!");
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700597 return NO_INIT;
598 }
599
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700600 int err = NO_ERROR;
601 switch (api) {
602 case NATIVE_WINDOW_API_EGL:
603 case NATIVE_WINDOW_API_CPU:
604 case NATIVE_WINDOW_API_MEDIA:
605 case NATIVE_WINDOW_API_CAMERA:
606 if (mConnectedApi != NO_CONNECTED_API) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700607 ST_LOGE("connect: already connected (cur=%d, req=%d)",
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700608 mConnectedApi, api);
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700609 err = -EINVAL;
610 } else {
611 mConnectedApi = api;
Mathias Agopian5bfc2452011-08-08 19:14:03 -0700612 *outWidth = mDefaultWidth;
613 *outHeight = mDefaultHeight;
614 *outTransform = 0;
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700615 }
616 break;
617 default:
618 err = -EINVAL;
619 break;
620 }
621 return err;
622}
623
624status_t SurfaceTexture::disconnect(int api) {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700625 ST_LOGV("disconnect: api=%d", api);
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700626 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700627
628 if (mAbandoned) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700629 ST_LOGE("disconnect: SurfaceTexture has been abandoned!");
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700630 return NO_INIT;
631 }
632
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700633 int err = NO_ERROR;
634 switch (api) {
635 case NATIVE_WINDOW_API_EGL:
636 case NATIVE_WINDOW_API_CPU:
637 case NATIVE_WINDOW_API_MEDIA:
638 case NATIVE_WINDOW_API_CAMERA:
639 if (mConnectedApi == api) {
Mathias Agopian8e19c2e2011-08-10 17:35:09 -0700640 drainQueueAndFreeBuffersLocked();
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700641 mConnectedApi = NO_CONNECTED_API;
Mathias Agopian70e3f812011-08-25 17:03:30 -0700642 mNextCrop.makeInvalid();
643 mNextScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
644 mNextTransform = 0;
Mathias Agopian8e19c2e2011-08-10 17:35:09 -0700645 mDequeueCondition.signal();
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700646 } else {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700647 ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700648 mConnectedApi, api);
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700649 err = -EINVAL;
650 }
651 break;
652 default:
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700653 ST_LOGE("disconnect: unknown API %d", api);
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700654 err = -EINVAL;
655 break;
656 }
657 return err;
658}
659
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700660status_t SurfaceTexture::setScalingMode(int mode) {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700661 ST_LOGV("setScalingMode: mode=%d", mode);
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700662
663 switch (mode) {
664 case NATIVE_WINDOW_SCALING_MODE_FREEZE:
665 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
666 break;
667 default:
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700668 ST_LOGE("unknown scaling mode: %d", mode);
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700669 return BAD_VALUE;
670 }
671
672 Mutex::Autolock lock(mMutex);
673 mNextScalingMode = mode;
674 return OK;
675}
676
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800677status_t SurfaceTexture::updateTexImage() {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700678 ST_LOGV("updateTexImage");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800679 Mutex::Autolock lock(mMutex);
680
Mathias Agopiane47498f2011-08-08 19:35:15 -0700681 if (mAbandoned) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700682 ST_LOGE("calling updateTexImage() on an abandoned SurfaceTexture");
Mathias Agopian8e19c2e2011-08-10 17:35:09 -0700683 return NO_INIT;
Mathias Agopiane47498f2011-08-08 19:35:15 -0700684 }
685
Jamie Gennis50c4efc2011-06-27 15:41:52 -0700686 // In asynchronous mode the list is guaranteed to be one buffer
687 // deep, while in synchronous mode we use the oldest buffer.
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700688 if (!mQueue.empty()) {
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700689 Fifo::iterator front(mQueue.begin());
Jamie Gennis50c4efc2011-06-27 15:41:52 -0700690 int buf = *front;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700691
Jamie Gennisf238e282011-01-09 16:33:17 -0800692 // Update the GL texture object.
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700693 EGLImageKHR image = mSlots[buf].mEglImage;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800694 if (image == EGL_NO_IMAGE_KHR) {
695 EGLDisplay dpy = eglGetCurrentDisplay();
Mathias Agopiane47498f2011-08-08 19:35:15 -0700696 if (mSlots[buf].mGraphicBuffer == 0) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700697 ST_LOGE("buffer at slot %d is null", buf);
Mathias Agopian8e19c2e2011-08-10 17:35:09 -0700698 return BAD_VALUE;
Mathias Agopiane47498f2011-08-08 19:35:15 -0700699 }
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700700 image = createImage(dpy, mSlots[buf].mGraphicBuffer);
701 mSlots[buf].mEglImage = image;
702 mSlots[buf].mEglDisplay = dpy;
Mathias Agopian3cd5a112011-04-26 14:57:40 -0700703 if (image == EGL_NO_IMAGE_KHR) {
704 // NOTE: if dpy was invalid, createImage() is guaranteed to
705 // fail. so we'd end up here.
706 return -EINVAL;
707 }
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800708 }
Jamie Gennis0eb88512011-01-26 11:52:02 -0800709
710 GLint error;
711 while ((error = glGetError()) != GL_NO_ERROR) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700712 ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
Jamie Gennis0eb88512011-01-26 11:52:02 -0800713 }
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700714
Jamie Gennisfb1b5a22011-09-28 12:13:31 -0700715 glBindTexture(mTexTarget, mTexName);
716 glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700717
Jamie Gennis0eb88512011-01-26 11:52:02 -0800718 bool failed = false;
719 while ((error = glGetError()) != GL_NO_ERROR) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700720 ST_LOGE("error binding external texture image %p (slot %d): %#04x",
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700721 image, buf, error);
Jamie Gennis0eb88512011-01-26 11:52:02 -0800722 failed = true;
723 }
724 if (failed) {
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800725 return -EINVAL;
726 }
Jamie Gennis9a78c902011-01-12 18:30:40 -0800727
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700728 ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
729 mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, buf,
730 mSlots[buf].mGraphicBuffer->handle);
731
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700732 if (mCurrentTexture != INVALID_BUFFER_SLOT) {
Jamie Gennis50c4efc2011-06-27 15:41:52 -0700733 // The current buffer becomes FREE if it was still in the queued
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700734 // state. If it has already been given to the client
735 // (synchronous mode), then it stays in DEQUEUED state.
736 if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED)
737 mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE;
738 }
739
Jamie Gennis9a78c902011-01-12 18:30:40 -0800740 // Update the SurfaceTexture state.
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700741 mCurrentTexture = buf;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700742 mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700743 mCurrentCrop = mSlots[buf].mCrop;
744 mCurrentTransform = mSlots[buf].mTransform;
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700745 mCurrentScalingMode = mSlots[buf].mScalingMode;
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700746 mCurrentTimestamp = mSlots[buf].mTimestamp;
Jamie Gennis736aa952011-06-12 17:03:06 -0700747 computeCurrentTransformMatrix();
Jamie Gennis50c4efc2011-06-27 15:41:52 -0700748
749 // Now that we've passed the point at which failures can happen,
750 // it's safe to remove the buffer from the front of the queue.
751 mQueue.erase(front);
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700752 mDequeueCondition.signal();
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700753 } else {
754 // We always bind the texture even if we don't update its contents.
Jamie Gennisfb1b5a22011-09-28 12:13:31 -0700755 glBindTexture(mTexTarget, mTexName);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800756 }
Jamie Gennis50c4efc2011-06-27 15:41:52 -0700757
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800758 return OK;
759}
760
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700761bool SurfaceTexture::isExternalFormat(uint32_t format)
762{
763 switch (format) {
764 // supported YUV formats
765 case HAL_PIXEL_FORMAT_YV12:
766 // Legacy/deprecated YUV formats
767 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
768 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
769 case HAL_PIXEL_FORMAT_YCbCr_422_I:
770 return true;
771 }
772
773 // Any OEM format needs to be considered
774 if (format>=0x100 && format<=0x1FF)
775 return true;
776
777 return false;
778}
779
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700780GLenum SurfaceTexture::getCurrentTextureTarget() const {
Jamie Gennisfb1b5a22011-09-28 12:13:31 -0700781 return mTexTarget;
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700782}
783
Jamie Gennisf238e282011-01-09 16:33:17 -0800784void SurfaceTexture::getTransformMatrix(float mtx[16]) {
Jamie Gennisf238e282011-01-09 16:33:17 -0800785 Mutex::Autolock lock(mMutex);
Jamie Gennis736aa952011-06-12 17:03:06 -0700786 memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
787}
788
789void SurfaceTexture::computeCurrentTransformMatrix() {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700790 ST_LOGV("computeCurrentTransformMatrix");
Jamie Gennisf238e282011-01-09 16:33:17 -0800791
Jamie Gennisa214c642011-01-14 13:53:31 -0800792 float xform[16];
793 for (int i = 0; i < 16; i++) {
794 xform[i] = mtxIdentity[i];
795 }
796 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
797 float result[16];
798 mtxMul(result, xform, mtxFlipH);
799 for (int i = 0; i < 16; i++) {
800 xform[i] = result[i];
801 }
802 }
803 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
804 float result[16];
805 mtxMul(result, xform, mtxFlipV);
806 for (int i = 0; i < 16; i++) {
807 xform[i] = result[i];
808 }
809 }
810 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
811 float result[16];
812 mtxMul(result, xform, mtxRot90);
813 for (int i = 0; i < 16; i++) {
814 xform[i] = result[i];
815 }
Jamie Gennisf238e282011-01-09 16:33:17 -0800816 }
817
818 sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer);
Jamie Gennisa214c642011-01-14 13:53:31 -0800819 float tx, ty, sx, sy;
820 if (!mCurrentCrop.isEmpty()) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800821 // In order to prevent bilinear sampling at the of the crop rectangle we
822 // may need to shrink it by 2 texels in each direction. Normally this
823 // would just need to take 1/2 a texel off each end, but because the
824 // chroma channels will likely be subsampled we need to chop off a whole
825 // texel. This will cause artifacts if someone does nearest sampling
826 // with 1:1 pixel:texel ratio, but it's impossible to simultaneously
827 // accomodate the bilinear and nearest sampling uses.
828 //
829 // If nearest sampling turns out to be a desirable usage of these
830 // textures then we could add the ability to switch a SurfaceTexture to
831 // nearest-mode. Preferably, however, the image producers (video
832 // decoder, camera, etc.) would simply not use a crop rectangle (or at
833 // least not tell the framework about it) so that the GPU can do the
834 // correct edge behavior.
835 int xshrink = 0, yshrink = 0;
836 if (mCurrentCrop.left > 0) {
837 tx = float(mCurrentCrop.left + 1) / float(buf->getWidth());
838 xshrink++;
839 } else {
840 tx = 0.0f;
841 }
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700842 if (mCurrentCrop.right < int32_t(buf->getWidth())) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800843 xshrink++;
844 }
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700845 if (mCurrentCrop.bottom < int32_t(buf->getHeight())) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800846 ty = (float(buf->getHeight() - mCurrentCrop.bottom) + 1.0f) /
847 float(buf->getHeight());
848 yshrink++;
849 } else {
850 ty = 0.0f;
851 }
852 if (mCurrentCrop.top > 0) {
853 yshrink++;
854 }
855 sx = float(mCurrentCrop.width() - xshrink) / float(buf->getWidth());
856 sy = float(mCurrentCrop.height() - yshrink) / float(buf->getHeight());
Jamie Gennisa214c642011-01-14 13:53:31 -0800857 } else {
858 tx = 0.0f;
859 ty = 0.0f;
860 sx = 1.0f;
861 sy = 1.0f;
862 }
Jamie Gennisf238e282011-01-09 16:33:17 -0800863 float crop[16] = {
Jamie Gennisa214c642011-01-14 13:53:31 -0800864 sx, 0, 0, 0,
865 0, sy, 0, 0,
Jamie Gennisf238e282011-01-09 16:33:17 -0800866 0, 0, 1, 0,
Jamie Gennisd99c0882011-03-10 16:24:46 -0800867 tx, ty, 0, 1,
Jamie Gennisf238e282011-01-09 16:33:17 -0800868 };
869
Jamie Gennisa214c642011-01-14 13:53:31 -0800870 float mtxBeforeFlipV[16];
871 mtxMul(mtxBeforeFlipV, crop, xform);
872
873 // SurfaceFlinger expects the top of its window textures to be at a Y
874 // coordinate of 0, so SurfaceTexture must behave the same way. We don't
875 // want to expose this to applications, however, so we must add an
876 // additional vertical flip to the transform after all the other transforms.
Jamie Gennis736aa952011-06-12 17:03:06 -0700877 mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV);
Jamie Gennisf238e282011-01-09 16:33:17 -0800878}
879
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800880nsecs_t SurfaceTexture::getTimestamp() {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700881 ST_LOGV("getTimestamp");
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800882 Mutex::Autolock lock(mMutex);
883 return mCurrentTimestamp;
884}
885
Jamie Gennisc4d4aea2011-01-13 14:43:36 -0800886void SurfaceTexture::setFrameAvailableListener(
Pannag Sanketi292a31a2011-06-24 09:56:27 -0700887 const sp<FrameAvailableListener>& listener) {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700888 ST_LOGV("setFrameAvailableListener");
Jamie Gennisc4d4aea2011-01-13 14:43:36 -0800889 Mutex::Autolock lock(mMutex);
Pannag Sanketi292a31a2011-06-24 09:56:27 -0700890 mFrameAvailableListener = listener;
Jamie Gennisc4d4aea2011-01-13 14:43:36 -0800891}
892
Mathias Agopian8e19c2e2011-08-10 17:35:09 -0700893void SurfaceTexture::freeBufferLocked(int i) {
894 mSlots[i].mGraphicBuffer = 0;
895 mSlots[i].mBufferState = BufferSlot::FREE;
896 if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
897 eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
898 mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
899 mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
900 }
901}
902
Mathias Agopianef51b992011-08-10 15:28:58 -0700903void SurfaceTexture::freeAllBuffersLocked() {
904 LOGW_IF(!mQueue.isEmpty(),
905 "freeAllBuffersLocked called but mQueue is not empty");
Mathias Agopian29b57622011-08-17 15:42:04 -0700906 mCurrentTexture = INVALID_BUFFER_SLOT;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800907 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
Mathias Agopian8e19c2e2011-08-10 17:35:09 -0700908 freeBufferLocked(i);
909 }
910}
911
912void SurfaceTexture::freeAllBuffersExceptHeadLocked() {
913 LOGW_IF(!mQueue.isEmpty(),
914 "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
915 int head = -1;
916 if (!mQueue.empty()) {
917 Fifo::iterator front(mQueue.begin());
918 head = *front;
919 }
Mathias Agopian29b57622011-08-17 15:42:04 -0700920 mCurrentTexture = INVALID_BUFFER_SLOT;
Mathias Agopian8e19c2e2011-08-10 17:35:09 -0700921 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
922 if (i != head) {
923 freeBufferLocked(i);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800924 }
925 }
926}
927
Mathias Agopian8e19c2e2011-08-10 17:35:09 -0700928status_t SurfaceTexture::drainQueueLocked() {
Mathias Agopian2560d142011-08-10 16:33:23 -0700929 while (mSynchronousMode && !mQueue.isEmpty()) {
930 mDequeueCondition.wait(mMutex);
Mathias Agopian8e19c2e2011-08-10 17:35:09 -0700931 if (mAbandoned) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700932 ST_LOGE("drainQueueLocked: SurfaceTexture has been abandoned!");
Mathias Agopian8e19c2e2011-08-10 17:35:09 -0700933 return NO_INIT;
934 }
935 if (mConnectedApi == NO_CONNECTED_API) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700936 ST_LOGE("drainQueueLocked: SurfaceTexture is not connected!");
Mathias Agopian8e19c2e2011-08-10 17:35:09 -0700937 return NO_INIT;
938 }
Mathias Agopian2560d142011-08-10 16:33:23 -0700939 }
Mathias Agopian8e19c2e2011-08-10 17:35:09 -0700940 return NO_ERROR;
941}
942
943status_t SurfaceTexture::drainQueueAndFreeBuffersLocked() {
944 status_t err = drainQueueLocked();
945 if (err == NO_ERROR) {
946 if (mSynchronousMode) {
947 freeAllBuffersLocked();
948 } else {
949 freeAllBuffersExceptHeadLocked();
950 }
951 }
952 return err;
Mathias Agopian2560d142011-08-10 16:33:23 -0700953}
954
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800955EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
956 const sp<GraphicBuffer>& graphicBuffer) {
957 EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
958 EGLint attrs[] = {
959 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
960 EGL_NONE,
961 };
962 EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
963 EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
Mathias Agopian3cd5a112011-04-26 14:57:40 -0700964 if (image == EGL_NO_IMAGE_KHR) {
965 EGLint error = eglGetError();
Jamie Gennisfa28c352011-09-16 17:30:26 -0700966 ST_LOGE("error creating EGLImage: %#x", error);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800967 }
968 return image;
969}
970
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700971sp<GraphicBuffer> SurfaceTexture::getCurrentBuffer() const {
972 Mutex::Autolock lock(mMutex);
973 return mCurrentTextureBuf;
974}
975
976Rect SurfaceTexture::getCurrentCrop() const {
977 Mutex::Autolock lock(mMutex);
978 return mCurrentCrop;
979}
980
981uint32_t SurfaceTexture::getCurrentTransform() const {
982 Mutex::Autolock lock(mMutex);
983 return mCurrentTransform;
984}
985
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700986uint32_t SurfaceTexture::getCurrentScalingMode() const {
987 Mutex::Autolock lock(mMutex);
988 return mCurrentScalingMode;
989}
990
Mathias Agopianeafabcd2011-04-20 14:20:59 -0700991int SurfaceTexture::query(int what, int* outValue)
992{
993 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700994
995 if (mAbandoned) {
Jamie Gennisfa28c352011-09-16 17:30:26 -0700996 ST_LOGE("query: SurfaceTexture has been abandoned!");
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700997 return NO_INIT;
998 }
999
Mathias Agopianeafabcd2011-04-20 14:20:59 -07001000 int value;
1001 switch (what) {
1002 case NATIVE_WINDOW_WIDTH:
1003 value = mDefaultWidth;
Mathias Agopianeafabcd2011-04-20 14:20:59 -07001004 break;
1005 case NATIVE_WINDOW_HEIGHT:
1006 value = mDefaultHeight;
Mathias Agopianeafabcd2011-04-20 14:20:59 -07001007 break;
1008 case NATIVE_WINDOW_FORMAT:
1009 value = mPixelFormat;
1010 break;
1011 case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
1012 value = mSynchronousMode ?
1013 (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS;
1014 break;
1015 default:
1016 return BAD_VALUE;
1017 }
1018 outValue[0] = value;
1019 return NO_ERROR;
1020}
Mathias Agopian7a042bf2011-04-11 21:19:55 -07001021
Jamie Gennis7b305ff2011-07-19 12:08:33 -07001022void SurfaceTexture::abandon() {
1023 Mutex::Autolock lock(mMutex);
Mathias Agopian8e19c2e2011-08-10 17:35:09 -07001024 mQueue.clear();
Jamie Gennis7b305ff2011-07-19 12:08:33 -07001025 mAbandoned = true;
Mathias Agopian97a98842011-08-03 15:18:36 -07001026 mCurrentTextureBuf.clear();
Mathias Agopian8e19c2e2011-08-10 17:35:09 -07001027 freeAllBuffersLocked();
Jamie Gennis7b305ff2011-07-19 12:08:33 -07001028 mDequeueCondition.signal();
1029}
1030
Jamie Gennisfa28c352011-09-16 17:30:26 -07001031void SurfaceTexture::setName(const String8& name) {
1032 mName = name;
1033}
1034
Mathias Agopian68c77942011-05-09 19:08:33 -07001035void SurfaceTexture::dump(String8& result) const
1036{
1037 char buffer[1024];
1038 dump(result, "", buffer, 1024);
1039}
1040
1041void SurfaceTexture::dump(String8& result, const char* prefix,
1042 char* buffer, size_t SIZE) const
1043{
1044 Mutex::Autolock _l(mMutex);
1045 snprintf(buffer, SIZE,
1046 "%smBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
1047 "mPixelFormat=%d, mTexName=%d\n",
Jamie Gennisfa28c352011-09-16 17:30:26 -07001048 prefix, mBufferCount, mSynchronousMode, mDefaultWidth,
1049 mDefaultHeight, mPixelFormat, mTexName);
Mathias Agopian68c77942011-05-09 19:08:33 -07001050 result.append(buffer);
1051
1052 String8 fifo;
1053 int fifoSize = 0;
1054 Fifo::const_iterator i(mQueue.begin());
1055 while (i != mQueue.end()) {
1056 snprintf(buffer, SIZE, "%02d ", *i++);
1057 fifoSize++;
1058 fifo.append(buffer);
1059 }
1060
1061 snprintf(buffer, SIZE,
Jamie Gennis1f8e09f2011-07-19 17:58:43 -07001062 "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n"
Mathias Agopian68c77942011-05-09 19:08:33 -07001063 "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, FIFO(%d)={%s}}\n"
1064 ,
1065 prefix, mCurrentCrop.left,
1066 mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
Jamie Gennis1f8e09f2011-07-19 17:58:43 -07001067 mCurrentTransform, mCurrentTexture,
Jamie Gennisfa28c352011-09-16 17:30:26 -07001068 prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right,
1069 mNextCrop.bottom, mNextTransform, fifoSize, fifo.string()
Mathias Agopian68c77942011-05-09 19:08:33 -07001070 );
1071 result.append(buffer);
1072
1073 struct {
1074 const char * operator()(int state) const {
1075 switch (state) {
1076 case BufferSlot::DEQUEUED: return "DEQUEUED";
1077 case BufferSlot::QUEUED: return "QUEUED";
1078 case BufferSlot::FREE: return "FREE";
1079 default: return "Unknown";
1080 }
1081 }
1082 } stateName;
1083
1084 for (int i=0 ; i<mBufferCount ; i++) {
1085 const BufferSlot& slot(mSlots[i]);
1086 snprintf(buffer, SIZE,
Mathias Agopianad795ba2011-08-08 16:02:13 -07001087 "%s%s[%02d] "
Mathias Agopianad795ba2011-08-08 16:02:13 -07001088 "state=%-8s, crop=[%d,%d,%d,%d], "
Mathias Agopian2db6f0a2011-08-09 15:48:43 -07001089 "transform=0x%02x, timestamp=%lld",
Mathias Agopianad795ba2011-08-08 16:02:13 -07001090 prefix, (i==mCurrentTexture)?">":" ", i,
Mathias Agopianad795ba2011-08-08 16:02:13 -07001091 stateName(slot.mBufferState),
Jamie Gennisfa28c352011-09-16 17:30:26 -07001092 slot.mCrop.left, slot.mCrop.top, slot.mCrop.right,
1093 slot.mCrop.bottom, slot.mTransform, slot.mTimestamp
Mathias Agopian68c77942011-05-09 19:08:33 -07001094 );
1095 result.append(buffer);
Mathias Agopian2db6f0a2011-08-09 15:48:43 -07001096
1097 const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
1098 if (buf != NULL) {
1099 snprintf(buffer, SIZE,
1100 ", %p [%4ux%4u:%4u,%3X]",
Jamie Gennisfa28c352011-09-16 17:30:26 -07001101 buf->handle, buf->width, buf->height, buf->stride,
1102 buf->format);
Mathias Agopian2db6f0a2011-08-09 15:48:43 -07001103 result.append(buffer);
1104 }
1105 result.append("\n");
Mathias Agopian68c77942011-05-09 19:08:33 -07001106 }
1107}
1108
Jamie Gennisf238e282011-01-09 16:33:17 -08001109static void mtxMul(float out[16], const float a[16], const float b[16]) {
1110 out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
1111 out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
1112 out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3];
1113 out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3];
1114
1115 out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7];
1116 out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7];
1117 out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7];
1118 out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7];
1119
1120 out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11];
1121 out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11];
1122 out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11];
1123 out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11];
1124
1125 out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15];
1126 out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15];
1127 out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15];
1128 out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
1129}
1130
Jamie Gennis8ba32fa2010-12-20 11:27:26 -08001131}; // namespace android