blob: 806fbb1be8e17845d90628b043f54e6e34d38001 [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
39namespace android {
40
Jamie Gennisf238e282011-01-09 16:33:17 -080041// Transform matrices
42static float mtxIdentity[16] = {
43 1, 0, 0, 0,
44 0, 1, 0, 0,
45 0, 0, 1, 0,
46 0, 0, 0, 1,
47};
48static float mtxFlipH[16] = {
49 -1, 0, 0, 0,
50 0, 1, 0, 0,
51 0, 0, 1, 0,
52 1, 0, 0, 1,
53};
54static float mtxFlipV[16] = {
55 1, 0, 0, 0,
56 0, -1, 0, 0,
57 0, 0, 1, 0,
58 0, 1, 0, 1,
59};
60static float mtxRot90[16] = {
61 0, 1, 0, 0,
62 -1, 0, 0, 0,
63 0, 0, 1, 0,
64 1, 0, 0, 1,
65};
66static float mtxRot180[16] = {
67 -1, 0, 0, 0,
68 0, -1, 0, 0,
69 0, 0, 1, 0,
70 1, 1, 0, 1,
71};
72static float mtxRot270[16] = {
73 0, -1, 0, 0,
74 1, 0, 0, 0,
75 0, 0, 1, 0,
76 0, 1, 0, 1,
77};
78
79static void mtxMul(float out[16], const float a[16], const float b[16]);
80
Grace Kloba14a0e582011-06-23 21:21:47 -070081SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode) :
Mathias Agopiana5c75c02011-03-31 19:10:24 -070082 mDefaultWidth(1),
83 mDefaultHeight(1),
84 mPixelFormat(PIXEL_FORMAT_RGBA_8888),
Mathias Agopian80727112011-05-02 19:51:12 -070085 mBufferCount(MIN_ASYNC_BUFFER_SLOTS),
86 mClientBufferCount(0),
87 mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -080088 mCurrentTexture(INVALID_BUFFER_SLOT),
89 mCurrentTransform(0),
90 mCurrentTimestamp(0),
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -080091 mNextTransform(0),
Mathias Agopian7734ebf2011-07-13 15:24:42 -070092 mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
Mathias Agopianb3e518c2011-04-21 18:52:51 -070093 mTexName(tex),
Grace Kloba14a0e582011-06-23 21:21:47 -070094 mSynchronousMode(false),
Jamie Gennisfe0a87b2011-07-13 19:12:20 -070095 mAllowSynchronousMode(allowSynchronousMode),
Jamie Gennis7b305ff2011-07-19 12:08:33 -070096 mConnectedApi(NO_CONNECTED_API),
97 mAbandoned(false) {
Jamie Gennise70d8b42011-01-09 13:24:09 -080098 LOGV("SurfaceTexture::SurfaceTexture");
Jamie Gennis9a78c902011-01-12 18:30:40 -080099 sp<ISurfaceComposer> composer(ComposerService::getComposerService());
100 mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
Mathias Agopiancc57d6f2011-04-27 18:57:33 -0700101 mNextCrop.makeInvalid();
Jamie Gennis736aa952011-06-12 17:03:06 -0700102 memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix));
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800103}
104
105SurfaceTexture::~SurfaceTexture() {
Jamie Gennise70d8b42011-01-09 13:24:09 -0800106 LOGV("SurfaceTexture::~SurfaceTexture");
Mathias Agopianef51b992011-08-10 15:28:58 -0700107 freeAllBuffersLocked();
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800108}
109
Mathias Agopian80727112011-05-02 19:51:12 -0700110status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) {
111 if (bufferCount > NUM_BUFFER_SLOTS)
112 return BAD_VALUE;
113
114 // special-case, nothing to do
115 if (bufferCount == mBufferCount)
116 return OK;
117
118 if (!mClientBufferCount &&
119 bufferCount >= mBufferCount) {
120 // easy, we just have more buffers
121 mBufferCount = bufferCount;
122 mServerBufferCount = bufferCount;
123 mDequeueCondition.signal();
124 } else {
125 // we're here because we're either
126 // - reducing the number of available buffers
127 // - or there is a client-buffer-count in effect
128
129 // less than 2 buffers is never allowed
130 if (bufferCount < 2)
131 return BAD_VALUE;
132
133 // when there is non client-buffer-count in effect, the client is not
134 // allowed to dequeue more than one buffer at a time,
135 // so the next time they dequeue a buffer, we know that they don't
136 // own one. the actual resizing will happen during the next
137 // dequeueBuffer.
138
139 mServerBufferCount = bufferCount;
140 }
141 return OK;
142}
143
144status_t SurfaceTexture::setBufferCountServer(int bufferCount) {
145 Mutex::Autolock lock(mMutex);
146 return setBufferCountServerLocked(bufferCount);
147}
148
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800149status_t SurfaceTexture::setBufferCount(int bufferCount) {
Jamie Gennise70d8b42011-01-09 13:24:09 -0800150 LOGV("SurfaceTexture::setBufferCount");
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700151 Mutex::Autolock lock(mMutex);
Jamie Gennis9d4d6c12011-02-27 14:10:20 -0800152
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700153 if (mAbandoned) {
154 LOGE("setBufferCount: SurfaceTexture has been abandoned!");
155 return NO_INIT;
156 }
Mathias Agopianef51b992011-08-10 15:28:58 -0700157 if (mConnectedApi == NO_CONNECTED_API) {
158 LOGE("setBufferCount: SurfaceTexture is not connected!");
159 return NO_INIT;
160 }
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700161
Pannag Sanketi292a31a2011-06-24 09:56:27 -0700162 if (bufferCount > NUM_BUFFER_SLOTS) {
163 LOGE("setBufferCount: bufferCount larger than slots available");
164 return BAD_VALUE;
165 }
166
Mathias Agopian80727112011-05-02 19:51:12 -0700167 // Error out if the user has dequeued buffers
168 for (int i=0 ; i<mBufferCount ; i++) {
169 if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
170 LOGE("setBufferCount: client owns some buffers");
171 return -EINVAL;
172 }
173 }
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700174
Jamie Gennis1c121f62011-07-30 16:00:11 -0700175 const int minBufferSlots = mSynchronousMode ?
176 MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
Mathias Agopian80727112011-05-02 19:51:12 -0700177 if (bufferCount == 0) {
Mathias Agopian80727112011-05-02 19:51:12 -0700178 mClientBufferCount = 0;
179 bufferCount = (mServerBufferCount >= minBufferSlots) ?
180 mServerBufferCount : minBufferSlots;
181 return setBufferCountServerLocked(bufferCount);
182 }
183
Jamie Gennis1c121f62011-07-30 16:00:11 -0700184 if (bufferCount < minBufferSlots) {
185 LOGE("setBufferCount: requested buffer count (%d) is less than "
186 "minimum (%d)", bufferCount, minBufferSlots);
Jamie Gennis9d4d6c12011-02-27 14:10:20 -0800187 return BAD_VALUE;
188 }
189
Mathias Agopian80727112011-05-02 19:51:12 -0700190 // here we're guaranteed that the client doesn't have dequeued buffers
191 // and will release all of its buffer references.
Mathias Agopianef51b992011-08-10 15:28:58 -0700192 freeAllBuffersLocked();
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800193 mBufferCount = bufferCount;
Mathias Agopian80727112011-05-02 19:51:12 -0700194 mClientBufferCount = bufferCount;
Jamie Gennis67eedd72011-01-09 13:25:39 -0800195 mCurrentTexture = INVALID_BUFFER_SLOT;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700196 mQueue.clear();
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700197 mDequeueCondition.signal();
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800198 return OK;
199}
200
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700201status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
202{
Mathias Agopian3fbce7c2011-07-25 19:56:08 -0700203 if (!w || !h) {
204 LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", w, h);
205 return BAD_VALUE;
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700206 }
Mathias Agopian3fbce7c2011-07-25 19:56:08 -0700207
208 Mutex::Autolock lock(mMutex);
209 mDefaultWidth = w;
210 mDefaultHeight = h;
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700211 return OK;
212}
213
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700214status_t SurfaceTexture::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
Jamie Gennise70d8b42011-01-09 13:24:09 -0800215 LOGV("SurfaceTexture::requestBuffer");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800216 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700217 if (mAbandoned) {
218 LOGE("requestBuffer: SurfaceTexture has been abandoned!");
219 return NO_INIT;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800220 }
Mathias Agopianef51b992011-08-10 15:28:58 -0700221 if (mConnectedApi == NO_CONNECTED_API) {
222 LOGE("requestBuffer: SurfaceTexture is not connected!");
223 return NO_INIT;
224 }
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700225 if (slot < 0 || mBufferCount <= slot) {
226 LOGE("requestBuffer: slot index out of range [0, %d]: %d",
227 mBufferCount, slot);
228 return BAD_VALUE;
229 }
230 mSlots[slot].mRequestBufferCalled = true;
231 *buf = mSlots[slot].mGraphicBuffer;
232 return NO_ERROR;
Mathias Agopianc04f1532011-04-25 20:22:14 -0700233}
234
235status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
236 uint32_t format, uint32_t usage) {
237 LOGV("SurfaceTexture::dequeueBuffer");
238
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700239 if (mAbandoned) {
240 LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
241 return NO_INIT;
242 }
Mathias Agopianef51b992011-08-10 15:28:58 -0700243 if (mConnectedApi == NO_CONNECTED_API) {
244 LOGE("dequeueBuffer: SurfaceTexture is not connected!");
245 return NO_INIT;
246 }
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700247
Pannag Sanketi292a31a2011-06-24 09:56:27 -0700248 if ((w && !h) || (!w && h)) {
Mathias Agopianc04f1532011-04-25 20:22:14 -0700249 LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
250 return BAD_VALUE;
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700251 }
252
Mathias Agopianc04f1532011-04-25 20:22:14 -0700253 Mutex::Autolock lock(mMutex);
Mathias Agopian80727112011-05-02 19:51:12 -0700254
255 status_t returnFlags(OK);
256
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700257 int found, foundSync;
258 int dequeuedCount = 0;
259 bool tryAgain = true;
260 while (tryAgain) {
Mathias Agopian80727112011-05-02 19:51:12 -0700261 // We need to wait for the FIFO to drain if the number of buffer
262 // needs to change.
263 //
264 // The condition "number of buffer needs to change" is true if
265 // - the client doesn't care about how many buffers there are
266 // - AND the actual number of buffer is different from what was
267 // set in the last setBufferCountServer()
268 // - OR -
269 // setBufferCountServer() was set to a value incompatible with
270 // the synchronization mode (for instance because the sync mode
271 // changed since)
272 //
273 // As long as this condition is true AND the FIFO is not empty, we
274 // wait on mDequeueCondition.
275
276 int minBufferCountNeeded = mSynchronousMode ?
277 MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
278
279 if (!mClientBufferCount &&
280 ((mServerBufferCount != mBufferCount) ||
281 (mServerBufferCount < minBufferCountNeeded))) {
282 // wait for the FIFO to drain
283 while (!mQueue.isEmpty()) {
284 mDequeueCondition.wait(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700285 if (mAbandoned) {
286 LOGE("dequeueBuffer: SurfaceTexture was abandoned while "
287 "blocked!");
288 return NO_INIT;
289 }
Mathias Agopian80727112011-05-02 19:51:12 -0700290 }
291 minBufferCountNeeded = mSynchronousMode ?
292 MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
293 }
294
295
296 if (!mClientBufferCount &&
297 ((mServerBufferCount != mBufferCount) ||
298 (mServerBufferCount < minBufferCountNeeded))) {
299 // here we're guaranteed that mQueue is empty
Mathias Agopianef51b992011-08-10 15:28:58 -0700300 freeAllBuffersLocked();
Mathias Agopian80727112011-05-02 19:51:12 -0700301 mBufferCount = mServerBufferCount;
302 if (mBufferCount < minBufferCountNeeded)
303 mBufferCount = minBufferCountNeeded;
304 mCurrentTexture = INVALID_BUFFER_SLOT;
305 returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
306 }
307
308 // look for a free buffer to give to the client
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700309 found = INVALID_BUFFER_SLOT;
310 foundSync = INVALID_BUFFER_SLOT;
311 dequeuedCount = 0;
312 for (int i = 0; i < mBufferCount; i++) {
313 const int state = mSlots[i].mBufferState;
314 if (state == BufferSlot::DEQUEUED) {
315 dequeuedCount++;
316 }
Mathias Agopiane1220792011-05-04 18:28:07 -0700317 if (state == BufferSlot::FREE /*|| i == mCurrentTexture*/) {
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700318 foundSync = i;
319 if (i != mCurrentTexture) {
320 found = i;
321 break;
322 }
323 }
324 }
Mathias Agopian80727112011-05-02 19:51:12 -0700325
326 // clients are not allowed to dequeue more than one buffer
327 // if they didn't set a buffer count.
328 if (!mClientBufferCount && dequeuedCount) {
329 return -EINVAL;
330 }
331
Jamie Gennisc2c8dfd2011-05-23 18:44:04 -0700332 // See whether a buffer has been queued since the last setBufferCount so
333 // we know whether to perform the MIN_UNDEQUEUED_BUFFERS check below.
334 bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
335 if (bufferHasBeenQueued) {
336 // make sure the client is not trying to dequeue more buffers
337 // than allowed.
338 const int avail = mBufferCount - (dequeuedCount+1);
339 if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
340 LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded (dequeued=%d)",
341 MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
342 dequeuedCount);
343 return -EBUSY;
344 }
Mathias Agopian80727112011-05-02 19:51:12 -0700345 }
346
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700347 // we're in synchronous mode and didn't find a buffer, we need to wait
Mathias Agopian80727112011-05-02 19:51:12 -0700348 // for for some buffers to be consumed
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700349 tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
350 if (tryAgain) {
351 mDequeueCondition.wait(mMutex);
Mathias Agopianc04f1532011-04-25 20:22:14 -0700352 }
353 }
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700354
Mathias Agopian80727112011-05-02 19:51:12 -0700355 if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
356 // foundSync guaranteed to be != INVALID_BUFFER_SLOT
357 found = foundSync;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700358 }
359
Mathias Agopianc04f1532011-04-25 20:22:14 -0700360 if (found == INVALID_BUFFER_SLOT) {
361 return -EBUSY;
362 }
363
364 const int buf = found;
365 *outBuf = found;
366
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700367 const bool useDefaultSize = !w && !h;
368 if (useDefaultSize) {
369 // use the default size
370 w = mDefaultWidth;
371 h = mDefaultHeight;
372 }
373
374 const bool updateFormat = (format != 0);
375 if (!updateFormat) {
376 // keep the current (or default) format
377 format = mPixelFormat;
378 }
379
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700380 // buffer is now in DEQUEUED (but can also be current at the same time,
381 // if we're in synchronous mode)
382 mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
383
384 const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
Mathias Agopianc04f1532011-04-25 20:22:14 -0700385 if ((buffer == NULL) ||
386 (uint32_t(buffer->width) != w) ||
387 (uint32_t(buffer->height) != h) ||
388 (uint32_t(buffer->format) != format) ||
389 ((uint32_t(buffer->usage) & usage) != usage))
390 {
391 usage |= GraphicBuffer::USAGE_HW_TEXTURE;
Mathias Agopiand9e8c642011-07-01 14:53:49 -0700392 status_t error;
Mathias Agopianc04f1532011-04-25 20:22:14 -0700393 sp<GraphicBuffer> graphicBuffer(
Mathias Agopiand9e8c642011-07-01 14:53:49 -0700394 mGraphicBufferAlloc->createGraphicBuffer(
395 w, h, format, usage, &error));
Mathias Agopianc04f1532011-04-25 20:22:14 -0700396 if (graphicBuffer == 0) {
397 LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer failed");
Mathias Agopiand9e8c642011-07-01 14:53:49 -0700398 return error;
Mathias Agopianc04f1532011-04-25 20:22:14 -0700399 }
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700400 if (updateFormat) {
401 mPixelFormat = format;
402 }
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800403 mSlots[buf].mGraphicBuffer = graphicBuffer;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700404 mSlots[buf].mRequestBufferCalled = false;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800405 if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
406 eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage);
407 mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
408 mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
409 }
Mathias Agopian80727112011-05-02 19:51:12 -0700410 returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700411 }
Mathias Agopian80727112011-05-02 19:51:12 -0700412 return returnFlags;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800413}
414
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700415status_t SurfaceTexture::setSynchronousMode(bool enabled) {
416 Mutex::Autolock lock(mMutex);
Mathias Agopian80727112011-05-02 19:51:12 -0700417
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700418 if (mAbandoned) {
419 LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
420 return NO_INIT;
421 }
422
Mathias Agopian80727112011-05-02 19:51:12 -0700423 status_t err = OK;
Grace Kloba14a0e582011-06-23 21:21:47 -0700424 if (!mAllowSynchronousMode && enabled)
425 return err;
426
Mathias Agopian80727112011-05-02 19:51:12 -0700427 if (!enabled) {
428 // going to asynchronous mode, drain the queue
429 while (mSynchronousMode != enabled && !mQueue.isEmpty()) {
430 mDequeueCondition.wait(mMutex);
431 }
432 }
433
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700434 if (mSynchronousMode != enabled) {
Mathias Agopian80727112011-05-02 19:51:12 -0700435 // - if we're going to asynchronous mode, the queue is guaranteed to be
436 // empty here
437 // - if the client set the number of buffers, we're guaranteed that
438 // we have at least 3 (because we don't allow less)
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700439 mSynchronousMode = enabled;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700440 mDequeueCondition.signal();
441 }
Mathias Agopian80727112011-05-02 19:51:12 -0700442 return err;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700443}
444
Mathias Agopian97c602c2011-07-19 15:24:46 -0700445status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp,
446 uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
Jamie Gennise70d8b42011-01-09 13:24:09 -0800447 LOGV("SurfaceTexture::queueBuffer");
Mathias Agopiancf46eb92011-05-11 15:05:29 -0700448
449 sp<FrameAvailableListener> listener;
450
451 { // scope for the lock
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700452 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700453 if (mAbandoned) {
454 LOGE("queueBuffer: SurfaceTexture has been abandoned!");
455 return NO_INIT;
456 }
Mathias Agopianef51b992011-08-10 15:28:58 -0700457 if (mConnectedApi == NO_CONNECTED_API) {
458 LOGE("queueBuffer: SurfaceTexture is not connected!");
459 return NO_INIT;
460 }
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700461 if (buf < 0 || buf >= mBufferCount) {
462 LOGE("queueBuffer: slot index out of range [0, %d]: %d",
463 mBufferCount, buf);
464 return -EINVAL;
465 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
466 LOGE("queueBuffer: slot %d is not owned by the client (state=%d)",
467 buf, mSlots[buf].mBufferState);
468 return -EINVAL;
469 } else if (buf == mCurrentTexture) {
470 LOGE("queueBuffer: slot %d is current!", buf);
471 return -EINVAL;
472 } else if (!mSlots[buf].mRequestBufferCalled) {
473 LOGE("queueBuffer: slot %d was enqueued without requesting a "
474 "buffer", buf);
475 return -EINVAL;
476 }
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700477
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700478 if (mSynchronousMode) {
Jamie Gennis3d8063b2011-06-26 18:27:47 -0700479 // In synchronous mode we queue all buffers in a FIFO.
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700480 mQueue.push_back(buf);
Jamie Gennis3d8063b2011-06-26 18:27:47 -0700481
482 // Synchronous mode always signals that an additional frame should
483 // be consumed.
484 listener = mFrameAvailableListener;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700485 } else {
Jamie Gennis3d8063b2011-06-26 18:27:47 -0700486 // In asynchronous mode we only keep the most recent buffer.
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700487 if (mQueue.empty()) {
488 mQueue.push_back(buf);
Jamie Gennis3d8063b2011-06-26 18:27:47 -0700489
490 // Asynchronous mode only signals that a frame should be
491 // consumed if no previous frame was pending. If a frame were
492 // pending then the consumer would have already been notified.
493 listener = mFrameAvailableListener;
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700494 } else {
495 Fifo::iterator front(mQueue.begin());
496 // buffer currently queued is freed
497 mSlots[*front].mBufferState = BufferSlot::FREE;
498 // and we record the new buffer index in the queued list
499 *front = buf;
500 }
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700501 }
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700502
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700503 mSlots[buf].mBufferState = BufferSlot::QUEUED;
504 mSlots[buf].mCrop = mNextCrop;
505 mSlots[buf].mTransform = mNextTransform;
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700506 mSlots[buf].mScalingMode = mNextScalingMode;
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700507 mSlots[buf].mTimestamp = timestamp;
508 mDequeueCondition.signal();
Mathias Agopiancf46eb92011-05-11 15:05:29 -0700509 } // scope for the lock
510
511 // call back without lock held
512 if (listener != 0) {
513 listener->onFrameAvailable();
514 }
Mathias Agopian97c602c2011-07-19 15:24:46 -0700515
516 *outWidth = mDefaultWidth;
517 *outHeight = mDefaultHeight;
518 *outTransform = 0;
519
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800520 return OK;
521}
522
523void SurfaceTexture::cancelBuffer(int buf) {
Jamie Gennise70d8b42011-01-09 13:24:09 -0800524 LOGV("SurfaceTexture::cancelBuffer");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800525 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700526
527 if (mAbandoned) {
528 LOGW("cancelBuffer: SurfaceTexture has been abandoned!");
529 return;
530 }
Mathias Agopianef51b992011-08-10 15:28:58 -0700531 if (mConnectedApi == NO_CONNECTED_API) {
532 LOGE("cancelBuffer: SurfaceTexture is not connected!");
533 return;
534 }
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700535
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700536 if (buf < 0 || buf >= mBufferCount) {
537 LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
538 mBufferCount, buf);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800539 return;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700540 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
541 LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
542 buf, mSlots[buf].mBufferState);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800543 return;
544 }
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700545 mSlots[buf].mBufferState = BufferSlot::FREE;
546 mDequeueCondition.signal();
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800547}
548
Jamie Gennisf238e282011-01-09 16:33:17 -0800549status_t SurfaceTexture::setCrop(const Rect& crop) {
Jamie Gennise70d8b42011-01-09 13:24:09 -0800550 LOGV("SurfaceTexture::setCrop");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800551 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700552 if (mAbandoned) {
553 LOGE("setCrop: SurfaceTexture has been abandoned!");
554 return NO_INIT;
555 }
Mathias Agopianef51b992011-08-10 15:28:58 -0700556 if (mConnectedApi == NO_CONNECTED_API) {
557 LOGE("setCrop: SurfaceTexture is not connected!");
558 return NO_INIT;
559 }
Jamie Gennisf238e282011-01-09 16:33:17 -0800560 mNextCrop = crop;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800561 return OK;
562}
563
564status_t SurfaceTexture::setTransform(uint32_t transform) {
Jamie Gennise70d8b42011-01-09 13:24:09 -0800565 LOGV("SurfaceTexture::setTransform");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800566 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700567 if (mAbandoned) {
568 LOGE("setTransform: SurfaceTexture has been abandoned!");
569 return NO_INIT;
570 }
Mathias Agopianef51b992011-08-10 15:28:58 -0700571 if (mConnectedApi == NO_CONNECTED_API) {
572 LOGE("setTransform: SurfaceTexture is not connected!");
573 return NO_INIT;
574 }
Jamie Gennisf238e282011-01-09 16:33:17 -0800575 mNextTransform = transform;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800576 return OK;
577}
578
Mathias Agopian5bfc2452011-08-08 19:14:03 -0700579status_t SurfaceTexture::connect(int api,
580 uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700581 LOGV("SurfaceTexture::connect(this=%p, %d)", this, api);
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700582 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700583
584 if (mAbandoned) {
585 LOGE("connect: SurfaceTexture has been abandoned!");
586 return NO_INIT;
587 }
588
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700589 int err = NO_ERROR;
590 switch (api) {
591 case NATIVE_WINDOW_API_EGL:
592 case NATIVE_WINDOW_API_CPU:
593 case NATIVE_WINDOW_API_MEDIA:
594 case NATIVE_WINDOW_API_CAMERA:
595 if (mConnectedApi != NO_CONNECTED_API) {
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700596 LOGE("connect: already connected (cur=%d, req=%d)",
597 mConnectedApi, api);
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700598 err = -EINVAL;
599 } else {
600 mConnectedApi = api;
Mathias Agopian5bfc2452011-08-08 19:14:03 -0700601 *outWidth = mDefaultWidth;
602 *outHeight = mDefaultHeight;
603 *outTransform = 0;
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700604 }
605 break;
606 default:
607 err = -EINVAL;
608 break;
609 }
610 return err;
611}
612
613status_t SurfaceTexture::disconnect(int api) {
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700614 LOGV("SurfaceTexture::disconnect(this=%p, %d)", this, api);
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700615 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700616
617 if (mAbandoned) {
618 LOGE("connect: SurfaceTexture has been abandoned!");
619 return NO_INIT;
620 }
621
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700622 int err = NO_ERROR;
623 switch (api) {
624 case NATIVE_WINDOW_API_EGL:
625 case NATIVE_WINDOW_API_CPU:
626 case NATIVE_WINDOW_API_MEDIA:
627 case NATIVE_WINDOW_API_CAMERA:
628 if (mConnectedApi == api) {
629 mConnectedApi = NO_CONNECTED_API;
Mathias Agopianef51b992011-08-10 15:28:58 -0700630 freeAllBuffersLocked();
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700631 } else {
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700632 LOGE("disconnect: connected to another api (cur=%d, req=%d)",
633 mConnectedApi, api);
Jamie Gennisfe0a87b2011-07-13 19:12:20 -0700634 err = -EINVAL;
635 }
636 break;
637 default:
638 err = -EINVAL;
639 break;
640 }
641 return err;
642}
643
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700644status_t SurfaceTexture::setScalingMode(int mode) {
Mathias Agopian933389f2011-07-18 16:15:08 -0700645 LOGV("SurfaceTexture::setScalingMode(%d)", mode);
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700646
647 switch (mode) {
648 case NATIVE_WINDOW_SCALING_MODE_FREEZE:
649 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
650 break;
651 default:
652 return BAD_VALUE;
653 }
654
655 Mutex::Autolock lock(mMutex);
656 mNextScalingMode = mode;
657 return OK;
658}
659
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800660status_t SurfaceTexture::updateTexImage() {
Jamie Gennise70d8b42011-01-09 13:24:09 -0800661 LOGV("SurfaceTexture::updateTexImage");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800662 Mutex::Autolock lock(mMutex);
663
Mathias Agopiane47498f2011-08-08 19:35:15 -0700664 if (mAbandoned) {
665 LOGE("calling updateTexImage() on an abandoned SurfaceTexture");
666 //return NO_INIT;
667 }
668
Jamie Gennis50c4efc2011-06-27 15:41:52 -0700669 // In asynchronous mode the list is guaranteed to be one buffer
670 // deep, while in synchronous mode we use the oldest buffer.
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700671 if (!mQueue.empty()) {
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700672 Fifo::iterator front(mQueue.begin());
Jamie Gennis50c4efc2011-06-27 15:41:52 -0700673 int buf = *front;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700674
Mathias Agopiane47498f2011-08-08 19:35:15 -0700675 if (uint32_t(buf) >= NUM_BUFFER_SLOTS) {
676 LOGE("buffer index out of range (index=%d)", buf);
677 //return BAD_VALUE;
678 }
679
Jamie Gennisf238e282011-01-09 16:33:17 -0800680 // Update the GL texture object.
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700681 EGLImageKHR image = mSlots[buf].mEglImage;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800682 if (image == EGL_NO_IMAGE_KHR) {
683 EGLDisplay dpy = eglGetCurrentDisplay();
Mathias Agopiane47498f2011-08-08 19:35:15 -0700684
685 if (mSlots[buf].mGraphicBuffer == 0) {
686 LOGE("buffer at slot %d is null", buf);
687 //return BAD_VALUE;
688 }
689
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700690 image = createImage(dpy, mSlots[buf].mGraphicBuffer);
691 mSlots[buf].mEglImage = image;
692 mSlots[buf].mEglDisplay = dpy;
Mathias Agopian3cd5a112011-04-26 14:57:40 -0700693 if (image == EGL_NO_IMAGE_KHR) {
694 // NOTE: if dpy was invalid, createImage() is guaranteed to
695 // fail. so we'd end up here.
696 return -EINVAL;
697 }
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800698 }
Jamie Gennis0eb88512011-01-26 11:52:02 -0800699
700 GLint error;
701 while ((error = glGetError()) != GL_NO_ERROR) {
Mathias Agopiancf46eb92011-05-11 15:05:29 -0700702 LOGW("updateTexImage: clearing GL error: %#04x", error);
Jamie Gennis0eb88512011-01-26 11:52:02 -0800703 }
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700704
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700705 glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
706 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700707
Jamie Gennis0eb88512011-01-26 11:52:02 -0800708 bool failed = false;
709 while ((error = glGetError()) != GL_NO_ERROR) {
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800710 LOGE("error binding external texture image %p (slot %d): %#04x",
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700711 image, buf, error);
Jamie Gennis0eb88512011-01-26 11:52:02 -0800712 failed = true;
713 }
714 if (failed) {
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800715 return -EINVAL;
716 }
Jamie Gennis9a78c902011-01-12 18:30:40 -0800717
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700718 if (mCurrentTexture != INVALID_BUFFER_SLOT) {
Jamie Gennis50c4efc2011-06-27 15:41:52 -0700719 // The current buffer becomes FREE if it was still in the queued
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700720 // state. If it has already been given to the client
721 // (synchronous mode), then it stays in DEQUEUED state.
722 if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED)
723 mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE;
724 }
725
Jamie Gennis9a78c902011-01-12 18:30:40 -0800726 // Update the SurfaceTexture state.
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700727 mCurrentTexture = buf;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700728 mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700729 mCurrentCrop = mSlots[buf].mCrop;
730 mCurrentTransform = mSlots[buf].mTransform;
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700731 mCurrentScalingMode = mSlots[buf].mScalingMode;
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700732 mCurrentTimestamp = mSlots[buf].mTimestamp;
Jamie Gennis736aa952011-06-12 17:03:06 -0700733 computeCurrentTransformMatrix();
Jamie Gennis50c4efc2011-06-27 15:41:52 -0700734
735 // Now that we've passed the point at which failures can happen,
736 // it's safe to remove the buffer from the front of the queue.
737 mQueue.erase(front);
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700738 mDequeueCondition.signal();
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700739 } else {
740 // We always bind the texture even if we don't update its contents.
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700741 glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800742 }
Jamie Gennis50c4efc2011-06-27 15:41:52 -0700743
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800744 return OK;
745}
746
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700747bool SurfaceTexture::isExternalFormat(uint32_t format)
748{
749 switch (format) {
750 // supported YUV formats
751 case HAL_PIXEL_FORMAT_YV12:
752 // Legacy/deprecated YUV formats
753 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
754 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
755 case HAL_PIXEL_FORMAT_YCbCr_422_I:
756 return true;
757 }
758
759 // Any OEM format needs to be considered
760 if (format>=0x100 && format<=0x1FF)
761 return true;
762
763 return false;
764}
765
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700766GLenum SurfaceTexture::getCurrentTextureTarget() const {
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700767 return GL_TEXTURE_EXTERNAL_OES;
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700768}
769
Jamie Gennisf238e282011-01-09 16:33:17 -0800770void SurfaceTexture::getTransformMatrix(float mtx[16]) {
Jamie Gennisf238e282011-01-09 16:33:17 -0800771 Mutex::Autolock lock(mMutex);
Jamie Gennis736aa952011-06-12 17:03:06 -0700772 memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
773}
774
775void SurfaceTexture::computeCurrentTransformMatrix() {
776 LOGV("SurfaceTexture::computeCurrentTransformMatrix");
Jamie Gennisf238e282011-01-09 16:33:17 -0800777
Jamie Gennisa214c642011-01-14 13:53:31 -0800778 float xform[16];
779 for (int i = 0; i < 16; i++) {
780 xform[i] = mtxIdentity[i];
781 }
782 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
783 float result[16];
784 mtxMul(result, xform, mtxFlipH);
785 for (int i = 0; i < 16; i++) {
786 xform[i] = result[i];
787 }
788 }
789 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
790 float result[16];
791 mtxMul(result, xform, mtxFlipV);
792 for (int i = 0; i < 16; i++) {
793 xform[i] = result[i];
794 }
795 }
796 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
797 float result[16];
798 mtxMul(result, xform, mtxRot90);
799 for (int i = 0; i < 16; i++) {
800 xform[i] = result[i];
801 }
Jamie Gennisf238e282011-01-09 16:33:17 -0800802 }
803
804 sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer);
Jamie Gennisa214c642011-01-14 13:53:31 -0800805 float tx, ty, sx, sy;
806 if (!mCurrentCrop.isEmpty()) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800807 // In order to prevent bilinear sampling at the of the crop rectangle we
808 // may need to shrink it by 2 texels in each direction. Normally this
809 // would just need to take 1/2 a texel off each end, but because the
810 // chroma channels will likely be subsampled we need to chop off a whole
811 // texel. This will cause artifacts if someone does nearest sampling
812 // with 1:1 pixel:texel ratio, but it's impossible to simultaneously
813 // accomodate the bilinear and nearest sampling uses.
814 //
815 // If nearest sampling turns out to be a desirable usage of these
816 // textures then we could add the ability to switch a SurfaceTexture to
817 // nearest-mode. Preferably, however, the image producers (video
818 // decoder, camera, etc.) would simply not use a crop rectangle (or at
819 // least not tell the framework about it) so that the GPU can do the
820 // correct edge behavior.
821 int xshrink = 0, yshrink = 0;
822 if (mCurrentCrop.left > 0) {
823 tx = float(mCurrentCrop.left + 1) / float(buf->getWidth());
824 xshrink++;
825 } else {
826 tx = 0.0f;
827 }
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700828 if (mCurrentCrop.right < int32_t(buf->getWidth())) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800829 xshrink++;
830 }
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700831 if (mCurrentCrop.bottom < int32_t(buf->getHeight())) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800832 ty = (float(buf->getHeight() - mCurrentCrop.bottom) + 1.0f) /
833 float(buf->getHeight());
834 yshrink++;
835 } else {
836 ty = 0.0f;
837 }
838 if (mCurrentCrop.top > 0) {
839 yshrink++;
840 }
841 sx = float(mCurrentCrop.width() - xshrink) / float(buf->getWidth());
842 sy = float(mCurrentCrop.height() - yshrink) / float(buf->getHeight());
Jamie Gennisa214c642011-01-14 13:53:31 -0800843 } else {
844 tx = 0.0f;
845 ty = 0.0f;
846 sx = 1.0f;
847 sy = 1.0f;
848 }
Jamie Gennisf238e282011-01-09 16:33:17 -0800849 float crop[16] = {
Jamie Gennisa214c642011-01-14 13:53:31 -0800850 sx, 0, 0, 0,
851 0, sy, 0, 0,
Jamie Gennisf238e282011-01-09 16:33:17 -0800852 0, 0, 1, 0,
Jamie Gennisd99c0882011-03-10 16:24:46 -0800853 tx, ty, 0, 1,
Jamie Gennisf238e282011-01-09 16:33:17 -0800854 };
855
Jamie Gennisa214c642011-01-14 13:53:31 -0800856 float mtxBeforeFlipV[16];
857 mtxMul(mtxBeforeFlipV, crop, xform);
858
859 // SurfaceFlinger expects the top of its window textures to be at a Y
860 // coordinate of 0, so SurfaceTexture must behave the same way. We don't
861 // want to expose this to applications, however, so we must add an
862 // additional vertical flip to the transform after all the other transforms.
Jamie Gennis736aa952011-06-12 17:03:06 -0700863 mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV);
Jamie Gennisf238e282011-01-09 16:33:17 -0800864}
865
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800866nsecs_t SurfaceTexture::getTimestamp() {
867 LOGV("SurfaceTexture::getTimestamp");
868 Mutex::Autolock lock(mMutex);
869 return mCurrentTimestamp;
870}
871
Jamie Gennisc4d4aea2011-01-13 14:43:36 -0800872void SurfaceTexture::setFrameAvailableListener(
Pannag Sanketi292a31a2011-06-24 09:56:27 -0700873 const sp<FrameAvailableListener>& listener) {
Jamie Gennisc4d4aea2011-01-13 14:43:36 -0800874 LOGV("SurfaceTexture::setFrameAvailableListener");
875 Mutex::Autolock lock(mMutex);
Pannag Sanketi292a31a2011-06-24 09:56:27 -0700876 mFrameAvailableListener = listener;
Jamie Gennisc4d4aea2011-01-13 14:43:36 -0800877}
878
Mathias Agopianef51b992011-08-10 15:28:58 -0700879void SurfaceTexture::freeAllBuffersLocked() {
880 LOGW_IF(!mQueue.isEmpty(),
881 "freeAllBuffersLocked called but mQueue is not empty");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800882 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
883 mSlots[i].mGraphicBuffer = 0;
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700884 mSlots[i].mBufferState = BufferSlot::FREE;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800885 if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
886 eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
887 mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
888 mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
889 }
890 }
891}
892
893EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
894 const sp<GraphicBuffer>& graphicBuffer) {
895 EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
896 EGLint attrs[] = {
897 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
898 EGL_NONE,
899 };
900 EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
901 EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
Mathias Agopian3cd5a112011-04-26 14:57:40 -0700902 if (image == EGL_NO_IMAGE_KHR) {
903 EGLint error = eglGetError();
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800904 LOGE("error creating EGLImage: %#x", error);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800905 }
906 return image;
907}
908
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700909sp<GraphicBuffer> SurfaceTexture::getCurrentBuffer() const {
910 Mutex::Autolock lock(mMutex);
911 return mCurrentTextureBuf;
912}
913
914Rect SurfaceTexture::getCurrentCrop() const {
915 Mutex::Autolock lock(mMutex);
916 return mCurrentCrop;
917}
918
919uint32_t SurfaceTexture::getCurrentTransform() const {
920 Mutex::Autolock lock(mMutex);
921 return mCurrentTransform;
922}
923
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700924uint32_t SurfaceTexture::getCurrentScalingMode() const {
925 Mutex::Autolock lock(mMutex);
926 return mCurrentScalingMode;
927}
928
Mathias Agopianeafabcd2011-04-20 14:20:59 -0700929int SurfaceTexture::query(int what, int* outValue)
930{
931 Mutex::Autolock lock(mMutex);
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700932
933 if (mAbandoned) {
934 LOGE("query: SurfaceTexture has been abandoned!");
935 return NO_INIT;
936 }
937
Mathias Agopianeafabcd2011-04-20 14:20:59 -0700938 int value;
939 switch (what) {
940 case NATIVE_WINDOW_WIDTH:
941 value = mDefaultWidth;
Mathias Agopianeafabcd2011-04-20 14:20:59 -0700942 break;
943 case NATIVE_WINDOW_HEIGHT:
944 value = mDefaultHeight;
Mathias Agopianeafabcd2011-04-20 14:20:59 -0700945 break;
946 case NATIVE_WINDOW_FORMAT:
947 value = mPixelFormat;
948 break;
949 case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
950 value = mSynchronousMode ?
951 (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS;
952 break;
953 default:
954 return BAD_VALUE;
955 }
956 outValue[0] = value;
957 return NO_ERROR;
958}
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700959
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700960void SurfaceTexture::abandon() {
961 Mutex::Autolock lock(mMutex);
Mathias Agopianef51b992011-08-10 15:28:58 -0700962 freeAllBuffersLocked();
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700963 mAbandoned = true;
Mathias Agopian97a98842011-08-03 15:18:36 -0700964 mCurrentTextureBuf.clear();
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700965 mDequeueCondition.signal();
966}
967
Mathias Agopian68c77942011-05-09 19:08:33 -0700968void SurfaceTexture::dump(String8& result) const
969{
970 char buffer[1024];
971 dump(result, "", buffer, 1024);
972}
973
974void SurfaceTexture::dump(String8& result, const char* prefix,
975 char* buffer, size_t SIZE) const
976{
977 Mutex::Autolock _l(mMutex);
978 snprintf(buffer, SIZE,
979 "%smBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
980 "mPixelFormat=%d, mTexName=%d\n",
981 prefix, mBufferCount, mSynchronousMode, mDefaultWidth, mDefaultHeight,
982 mPixelFormat, mTexName);
983 result.append(buffer);
984
985 String8 fifo;
986 int fifoSize = 0;
987 Fifo::const_iterator i(mQueue.begin());
988 while (i != mQueue.end()) {
989 snprintf(buffer, SIZE, "%02d ", *i++);
990 fifoSize++;
991 fifo.append(buffer);
992 }
993
994 snprintf(buffer, SIZE,
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700995 "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n"
Mathias Agopian68c77942011-05-09 19:08:33 -0700996 "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, FIFO(%d)={%s}}\n"
997 ,
998 prefix, mCurrentCrop.left,
999 mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
Jamie Gennis1f8e09f2011-07-19 17:58:43 -07001000 mCurrentTransform, mCurrentTexture,
Mathias Agopian68c77942011-05-09 19:08:33 -07001001 prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right, mNextCrop.bottom,
1002 mCurrentTransform, fifoSize, fifo.string()
1003 );
1004 result.append(buffer);
1005
1006 struct {
1007 const char * operator()(int state) const {
1008 switch (state) {
1009 case BufferSlot::DEQUEUED: return "DEQUEUED";
1010 case BufferSlot::QUEUED: return "QUEUED";
1011 case BufferSlot::FREE: return "FREE";
1012 default: return "Unknown";
1013 }
1014 }
1015 } stateName;
1016
1017 for (int i=0 ; i<mBufferCount ; i++) {
1018 const BufferSlot& slot(mSlots[i]);
1019 snprintf(buffer, SIZE,
Mathias Agopianad795ba2011-08-08 16:02:13 -07001020 "%s%s[%02d] "
Mathias Agopianad795ba2011-08-08 16:02:13 -07001021 "state=%-8s, crop=[%d,%d,%d,%d], "
Mathias Agopian2db6f0a2011-08-09 15:48:43 -07001022 "transform=0x%02x, timestamp=%lld",
Mathias Agopianad795ba2011-08-08 16:02:13 -07001023 prefix, (i==mCurrentTexture)?">":" ", i,
Mathias Agopianad795ba2011-08-08 16:02:13 -07001024 stateName(slot.mBufferState),
Jamie Gennis8cd5ba42011-05-19 13:33:00 -07001025 slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, slot.mCrop.bottom,
1026 slot.mTransform, slot.mTimestamp
Mathias Agopian68c77942011-05-09 19:08:33 -07001027 );
1028 result.append(buffer);
Mathias Agopian2db6f0a2011-08-09 15:48:43 -07001029
1030 const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
1031 if (buf != NULL) {
1032 snprintf(buffer, SIZE,
1033 ", %p [%4ux%4u:%4u,%3X]",
1034 buf->handle, buf->width, buf->height, buf->stride, buf->format);
1035 result.append(buffer);
1036 }
1037 result.append("\n");
Mathias Agopian68c77942011-05-09 19:08:33 -07001038 }
1039}
1040
Jamie Gennisf238e282011-01-09 16:33:17 -08001041static void mtxMul(float out[16], const float a[16], const float b[16]) {
1042 out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
1043 out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
1044 out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3];
1045 out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3];
1046
1047 out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7];
1048 out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7];
1049 out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7];
1050 out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7];
1051
1052 out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11];
1053 out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11];
1054 out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11];
1055 out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11];
1056
1057 out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15];
1058 out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15];
1059 out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15];
1060 out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
1061}
1062
Jamie Gennis8ba32fa2010-12-20 11:27:26 -08001063}; // namespace android