blob: 36a81a6661d838047e69bb19231ed6ced72e97fb [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 "SurfaceTextureClient"
Jamie Gennis1c8e95c2012-02-23 19:27:23 -080018#define ATRACE_TAG ATRACE_TAG_GRAPHICS
Jamie Gennise5366c52011-01-12 20:22:41 -080019//#define LOG_NDEBUG 0
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080020
Mathias Agopianb0e76f42012-03-23 14:15:44 -070021#include <android/native_window.h>
22
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080023#include <utils/Log.h>
Jamie Gennis1c8e95c2012-02-23 19:27:23 -080024#include <utils/Trace.h>
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080025
Mathias Agopian90ac7992012-02-25 18:48:35 -080026#include <gui/ISurfaceComposer.h>
27#include <gui/SurfaceComposerClient.h>
Mathias Agopianb0e76f42012-03-23 14:15:44 -070028#include <gui/SurfaceTexture.h>
Mathias Agopian90ac7992012-02-25 18:48:35 -080029#include <gui/SurfaceTextureClient.h>
30
Mathias Agopian41f673c2011-11-17 17:48:35 -080031#include <private/gui/ComposerService.h>
32
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080033namespace android {
34
35SurfaceTextureClient::SurfaceTextureClient(
Mathias Agopian8f9dbf92011-07-13 17:39:11 -070036 const sp<ISurfaceTexture>& surfaceTexture)
37{
38 SurfaceTextureClient::init();
39 SurfaceTextureClient::setISurfaceTexture(surfaceTexture);
40}
41
Daniel Lamb2675792012-02-23 14:35:13 -080042// see SurfaceTextureClient.h
43SurfaceTextureClient::SurfaceTextureClient(const
44 sp<SurfaceTexture>& surfaceTexture)
45{
46 SurfaceTextureClient::init();
47 SurfaceTextureClient::setISurfaceTexture(surfaceTexture->getBufferQueue());
48}
49
Mathias Agopian8f9dbf92011-07-13 17:39:11 -070050SurfaceTextureClient::SurfaceTextureClient() {
51 SurfaceTextureClient::init();
52}
53
Mathias Agopiana36bcd52011-11-17 18:46:09 -080054SurfaceTextureClient::~SurfaceTextureClient() {
55 if (mConnectedToCpu) {
56 SurfaceTextureClient::disconnect(NATIVE_WINDOW_API_CPU);
57 }
58}
59
Mathias Agopian8f9dbf92011-07-13 17:39:11 -070060void SurfaceTextureClient::init() {
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080061 // Initialize the ANativeWindow function pointers.
Mathias Agopian8f9dbf92011-07-13 17:39:11 -070062 ANativeWindow::setSwapInterval = hook_setSwapInterval;
63 ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
64 ANativeWindow::cancelBuffer = hook_cancelBuffer;
65 ANativeWindow::lockBuffer = hook_lockBuffer;
66 ANativeWindow::queueBuffer = hook_queueBuffer;
67 ANativeWindow::query = hook_query;
68 ANativeWindow::perform = hook_perform;
Jamie Gennis1b20cde2011-02-02 15:31:47 -080069
Mathias Agopian80727112011-05-02 19:51:12 -070070 const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
71 const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
72
Mathias Agopian8f9dbf92011-07-13 17:39:11 -070073 mReqWidth = 0;
74 mReqHeight = 0;
75 mReqFormat = 0;
76 mReqUsage = 0;
77 mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
Mathias Agopian851ef8f2012-03-29 17:10:08 -070078 mCrop.clear();
79 mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
80 mTransform = 0;
Mathias Agopianbb66c9b2011-07-21 14:50:29 -070081 mDefaultWidth = 0;
82 mDefaultHeight = 0;
Michael I. Gold55a70142012-04-09 19:46:29 -070083 mUserWidth = 0;
84 mUserHeight = 0;
Mathias Agopianbb66c9b2011-07-21 14:50:29 -070085 mTransformHint = 0;
Mathias Agopian2488b202012-04-20 17:19:28 -070086 mConsumerRunningBehind = false;
Mathias Agopian8f9dbf92011-07-13 17:39:11 -070087 mConnectedToCpu = false;
88}
89
90void SurfaceTextureClient::setISurfaceTexture(
91 const sp<ISurfaceTexture>& surfaceTexture)
92{
93 mSurfaceTexture = surfaceTexture;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080094}
95
Jamie Gennisbae774e2011-03-14 15:08:53 -070096sp<ISurfaceTexture> SurfaceTextureClient::getISurfaceTexture() const {
97 return mSurfaceTexture;
98}
99
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700100int SurfaceTextureClient::hook_setSwapInterval(ANativeWindow* window, int interval) {
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800101 SurfaceTextureClient* c = getSelf(window);
102 return c->setSwapInterval(interval);
103}
104
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700105int SurfaceTextureClient::hook_dequeueBuffer(ANativeWindow* window,
Iliyan Malchev697526b2011-05-01 11:33:26 -0700106 ANativeWindowBuffer** buffer) {
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800107 SurfaceTextureClient* c = getSelf(window);
108 return c->dequeueBuffer(buffer);
109}
110
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700111int SurfaceTextureClient::hook_cancelBuffer(ANativeWindow* window,
Iliyan Malchev697526b2011-05-01 11:33:26 -0700112 ANativeWindowBuffer* buffer) {
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800113 SurfaceTextureClient* c = getSelf(window);
114 return c->cancelBuffer(buffer);
115}
116
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700117int SurfaceTextureClient::hook_lockBuffer(ANativeWindow* window,
Iliyan Malchev697526b2011-05-01 11:33:26 -0700118 ANativeWindowBuffer* buffer) {
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800119 SurfaceTextureClient* c = getSelf(window);
120 return c->lockBuffer(buffer);
121}
122
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700123int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window,
Iliyan Malchev697526b2011-05-01 11:33:26 -0700124 ANativeWindowBuffer* buffer) {
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800125 SurfaceTextureClient* c = getSelf(window);
126 return c->queueBuffer(buffer);
127}
128
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700129int SurfaceTextureClient::hook_query(const ANativeWindow* window,
Iliyan Malchev41abd672011-04-14 16:54:38 -0700130 int what, int* value) {
131 const SurfaceTextureClient* c = getSelf(window);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800132 return c->query(what, value);
133}
134
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700135int SurfaceTextureClient::hook_perform(ANativeWindow* window, int operation, ...) {
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800136 va_list args;
137 va_start(args, operation);
138 SurfaceTextureClient* c = getSelf(window);
139 return c->perform(operation, args);
140}
141
142int SurfaceTextureClient::setSwapInterval(int interval) {
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800143 ATRACE_CALL();
Mathias Agopian80727112011-05-02 19:51:12 -0700144 // EGL specification states:
145 // interval is silently clamped to minimum and maximum implementation
146 // dependent values before being stored.
147 // Although we don't have to, we apply the same logic here.
148
149 if (interval < minSwapInterval)
150 interval = minSwapInterval;
151
152 if (interval > maxSwapInterval)
153 interval = maxSwapInterval;
154
155 status_t res = mSurfaceTexture->setSynchronousMode(interval ? true : false);
156
157 return res;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800158}
159
160int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800161 ATRACE_CALL();
Steve Block6807e592011-10-20 11:56:00 +0100162 ALOGV("SurfaceTextureClient::dequeueBuffer");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800163 Mutex::Autolock lock(mMutex);
164 int buf = -1;
Michael I. Gold55a70142012-04-09 19:46:29 -0700165 int reqW = mReqWidth ? mReqWidth : mUserWidth;
166 int reqH = mReqHeight ? mReqHeight : mUserHeight;
167 status_t result = mSurfaceTexture->dequeueBuffer(&buf, reqW, reqH,
Mathias Agopianc04f1532011-04-25 20:22:14 -0700168 mReqFormat, mReqUsage);
Mathias Agopian80727112011-05-02 19:51:12 -0700169 if (result < 0) {
Steve Block6807e592011-10-20 11:56:00 +0100170 ALOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)"
Jamie Gennis8cd5ba42011-05-19 13:33:00 -0700171 "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,
172 result);
Mathias Agopian80727112011-05-02 19:51:12 -0700173 return result;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800174 }
Mathias Agopianac6035a2012-04-12 16:32:37 -0700175 sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
Mathias Agopian80727112011-05-02 19:51:12 -0700176 if (result & ISurfaceTexture::RELEASE_ALL_BUFFERS) {
177 freeAllBuffers();
178 }
179
180 if ((result & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700181 result = mSurfaceTexture->requestBuffer(buf, &gbuf);
182 if (result != NO_ERROR) {
Steve Blocke6f43dd2012-01-06 19:20:56 +0000183 ALOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed: %d",
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700184 result);
185 return result;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800186 }
187 }
188 *buffer = gbuf.get();
189 return OK;
190}
191
192int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) {
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800193 ATRACE_CALL();
Steve Block6807e592011-10-20 11:56:00 +0100194 ALOGV("SurfaceTextureClient::cancelBuffer");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800195 Mutex::Autolock lock(mMutex);
Jamie Gennis1c441402011-06-20 12:04:09 -0700196 int i = getSlotFromBufferLocked(buffer);
197 if (i < 0) {
198 return i;
199 }
200 mSurfaceTexture->cancelBuffer(i);
201 return OK;
202}
203
204int SurfaceTextureClient::getSlotFromBufferLocked(
205 android_native_buffer_t* buffer) const {
206 bool dumpedState = false;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800207 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
Mathias Agopianac6035a2012-04-12 16:32:37 -0700208 if (mSlots[i].buffer != NULL &&
209 mSlots[i].buffer->handle == buffer->handle) {
Jamie Gennis1c441402011-06-20 12:04:09 -0700210 return i;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800211 }
212 }
Steve Blocke6f43dd2012-01-06 19:20:56 +0000213 ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800214 return BAD_VALUE;
215}
216
217int SurfaceTextureClient::lockBuffer(android_native_buffer_t* buffer) {
Steve Block6807e592011-10-20 11:56:00 +0100218 ALOGV("SurfaceTextureClient::lockBuffer");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800219 Mutex::Autolock lock(mMutex);
220 return OK;
221}
222
223int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800224 ATRACE_CALL();
Steve Block6807e592011-10-20 11:56:00 +0100225 ALOGV("SurfaceTextureClient::queueBuffer");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800226 Mutex::Autolock lock(mMutex);
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800227 int64_t timestamp;
228 if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
229 timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
Steve Block6807e592011-10-20 11:56:00 +0100230 ALOGV("SurfaceTextureClient::queueBuffer making up timestamp: %.2f ms",
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800231 timestamp / 1000000.f);
232 } else {
233 timestamp = mTimestamp;
234 }
Jamie Gennis1c441402011-06-20 12:04:09 -0700235 int i = getSlotFromBufferLocked(buffer);
236 if (i < 0) {
237 return i;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800238 }
Mathias Agopianf0bc2f12012-04-09 16:14:01 -0700239
Jamie Gennisd72f2332012-05-07 13:50:11 -0700240 // Make sure the crop rectangle is entirely inside the buffer.
Jamie Gennisb7a6b962012-05-13 19:41:35 -0700241 Rect crop;
242 mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
Jamie Gennisd72f2332012-05-07 13:50:11 -0700243
Mathias Agopianf0bc2f12012-04-09 16:14:01 -0700244 ISurfaceTexture::QueueBufferOutput output;
Jamie Gennisd72f2332012-05-07 13:50:11 -0700245 ISurfaceTexture::QueueBufferInput input(timestamp, crop, mScalingMode,
246 mTransform);
Mathias Agopianf0bc2f12012-04-09 16:14:01 -0700247 status_t err = mSurfaceTexture->queueBuffer(i, input, &output);
Pannag Sanketi66378c62011-09-02 17:37:29 -0700248 if (err != OK) {
Steve Blocke6f43dd2012-01-06 19:20:56 +0000249 ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
Pannag Sanketi66378c62011-09-02 17:37:29 -0700250 }
Mathias Agopian2488b202012-04-20 17:19:28 -0700251 uint32_t numPendingBuffers = 0;
252 output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
253 &numPendingBuffers);
254
255 mConsumerRunningBehind = (numPendingBuffers >= 2);
256
Pannag Sanketi66378c62011-09-02 17:37:29 -0700257 return err;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800258}
259
Iliyan Malchev41abd672011-04-14 16:54:38 -0700260int SurfaceTextureClient::query(int what, int* value) const {
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800261 ATRACE_CALL();
Steve Block6807e592011-10-20 11:56:00 +0100262 ALOGV("SurfaceTextureClient::query");
Mathias Agopian97c602c2011-07-19 15:24:46 -0700263 { // scope for the lock
264 Mutex::Autolock lock(mMutex);
265 switch (what) {
266 case NATIVE_WINDOW_FORMAT:
267 if (mReqFormat) {
268 *value = mReqFormat;
269 return NO_ERROR;
270 }
271 break;
Mathias Agopian2488b202012-04-20 17:19:28 -0700272 case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
273 sp<ISurfaceComposer> composer(
274 ComposerService::getComposerService());
275 if (composer->authenticateSurfaceTexture(mSurfaceTexture)) {
276 *value = 1;
277 } else {
278 *value = 0;
Jamie Gennis582270d2011-08-17 18:19:00 -0700279 }
Mathias Agopian97c602c2011-07-19 15:24:46 -0700280 return NO_ERROR;
Mathias Agopian2488b202012-04-20 17:19:28 -0700281 }
Mathias Agopian97c602c2011-07-19 15:24:46 -0700282 case NATIVE_WINDOW_CONCRETE_TYPE:
283 *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
284 return NO_ERROR;
285 case NATIVE_WINDOW_DEFAULT_WIDTH:
Michael I. Gold55a70142012-04-09 19:46:29 -0700286 *value = mUserWidth ? mUserWidth : mDefaultWidth;
Mathias Agopian97c602c2011-07-19 15:24:46 -0700287 return NO_ERROR;
288 case NATIVE_WINDOW_DEFAULT_HEIGHT:
Michael I. Gold55a70142012-04-09 19:46:29 -0700289 *value = mUserHeight ? mUserHeight : mDefaultHeight;
Mathias Agopian97c602c2011-07-19 15:24:46 -0700290 return NO_ERROR;
291 case NATIVE_WINDOW_TRANSFORM_HINT:
292 *value = mTransformHint;
293 return NO_ERROR;
Mathias Agopian2488b202012-04-20 17:19:28 -0700294 case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: {
295 status_t err = NO_ERROR;
296 if (!mConsumerRunningBehind) {
297 *value = 0;
298 } else {
299 err = mSurfaceTexture->query(what, value);
300 if (err == NO_ERROR) {
301 mConsumerRunningBehind = *value;
302 }
303 }
304 return err;
305 }
Mathias Agopiana67932f2011-04-20 14:20:59 -0700306 }
Jamie Gennis9d4d6c12011-02-27 14:10:20 -0800307 }
Mathias Agopianeafabcd2011-04-20 14:20:59 -0700308 return mSurfaceTexture->query(what, value);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800309}
310
311int SurfaceTextureClient::perform(int operation, va_list args)
312{
313 int res = NO_ERROR;
314 switch (operation) {
315 case NATIVE_WINDOW_CONNECT:
Mathias Agopian81a63352011-07-29 17:55:48 -0700316 // deprecated. must return NO_ERROR.
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800317 break;
318 case NATIVE_WINDOW_DISCONNECT:
Mathias Agopian81a63352011-07-29 17:55:48 -0700319 // deprecated. must return NO_ERROR.
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800320 break;
321 case NATIVE_WINDOW_SET_USAGE:
322 res = dispatchSetUsage(args);
323 break;
324 case NATIVE_WINDOW_SET_CROP:
325 res = dispatchSetCrop(args);
326 break;
327 case NATIVE_WINDOW_SET_BUFFER_COUNT:
328 res = dispatchSetBufferCount(args);
329 break;
330 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
331 res = dispatchSetBuffersGeometry(args);
332 break;
333 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
334 res = dispatchSetBuffersTransform(args);
335 break;
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800336 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
337 res = dispatchSetBuffersTimestamp(args);
338 break;
Jamie Gennisbee205f2011-07-01 13:12:07 -0700339 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
340 res = dispatchSetBuffersDimensions(args);
341 break;
Michael I. Gold55a70142012-04-09 19:46:29 -0700342 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
343 res = dispatchSetBuffersUserDimensions(args);
344 break;
Jamie Gennisbee205f2011-07-01 13:12:07 -0700345 case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
346 res = dispatchSetBuffersFormat(args);
347 break;
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700348 case NATIVE_WINDOW_LOCK:
349 res = dispatchLock(args);
350 break;
351 case NATIVE_WINDOW_UNLOCK_AND_POST:
352 res = dispatchUnlockAndPost(args);
353 break;
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700354 case NATIVE_WINDOW_SET_SCALING_MODE:
355 res = dispatchSetScalingMode(args);
356 break;
Mathias Agopian81a63352011-07-29 17:55:48 -0700357 case NATIVE_WINDOW_API_CONNECT:
358 res = dispatchConnect(args);
359 break;
360 case NATIVE_WINDOW_API_DISCONNECT:
361 res = dispatchDisconnect(args);
362 break;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800363 default:
364 res = NAME_NOT_FOUND;
365 break;
366 }
367 return res;
368}
369
370int SurfaceTextureClient::dispatchConnect(va_list args) {
371 int api = va_arg(args, int);
372 return connect(api);
373}
374
375int SurfaceTextureClient::dispatchDisconnect(va_list args) {
376 int api = va_arg(args, int);
377 return disconnect(api);
378}
379
380int SurfaceTextureClient::dispatchSetUsage(va_list args) {
381 int usage = va_arg(args, int);
382 return setUsage(usage);
383}
384
385int SurfaceTextureClient::dispatchSetCrop(va_list args) {
386 android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
387 return setCrop(reinterpret_cast<Rect const*>(rect));
388}
389
390int SurfaceTextureClient::dispatchSetBufferCount(va_list args) {
391 size_t bufferCount = va_arg(args, size_t);
392 return setBufferCount(bufferCount);
393}
394
395int SurfaceTextureClient::dispatchSetBuffersGeometry(va_list args) {
396 int w = va_arg(args, int);
397 int h = va_arg(args, int);
398 int f = va_arg(args, int);
Jamie Gennisbee205f2011-07-01 13:12:07 -0700399 int err = setBuffersDimensions(w, h);
400 if (err != 0) {
401 return err;
402 }
403 return setBuffersFormat(f);
404}
405
406int SurfaceTextureClient::dispatchSetBuffersDimensions(va_list args) {
407 int w = va_arg(args, int);
408 int h = va_arg(args, int);
409 return setBuffersDimensions(w, h);
410}
411
Michael I. Gold55a70142012-04-09 19:46:29 -0700412int SurfaceTextureClient::dispatchSetBuffersUserDimensions(va_list args) {
413 int w = va_arg(args, int);
414 int h = va_arg(args, int);
415 return setBuffersUserDimensions(w, h);
416}
417
Jamie Gennisbee205f2011-07-01 13:12:07 -0700418int SurfaceTextureClient::dispatchSetBuffersFormat(va_list args) {
419 int f = va_arg(args, int);
420 return setBuffersFormat(f);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800421}
422
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700423int SurfaceTextureClient::dispatchSetScalingMode(va_list args) {
424 int m = va_arg(args, int);
425 return setScalingMode(m);
426}
427
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800428int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) {
429 int transform = va_arg(args, int);
430 return setBuffersTransform(transform);
431}
432
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800433int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) {
434 int64_t timestamp = va_arg(args, int64_t);
435 return setBuffersTimestamp(timestamp);
436}
437
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700438int SurfaceTextureClient::dispatchLock(va_list args) {
439 ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
440 ARect* inOutDirtyBounds = va_arg(args, ARect*);
441 return lock(outBuffer, inOutDirtyBounds);
442}
443
444int SurfaceTextureClient::dispatchUnlockAndPost(va_list args) {
445 return unlockAndPost();
446}
447
448
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800449int SurfaceTextureClient::connect(int api) {
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800450 ATRACE_CALL();
Steve Block6807e592011-10-20 11:56:00 +0100451 ALOGV("SurfaceTextureClient::connect");
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700452 Mutex::Autolock lock(mMutex);
Mathias Agopian24202f52012-04-23 14:28:58 -0700453 ISurfaceTexture::QueueBufferOutput output;
454 int err = mSurfaceTexture->connect(api, &output);
Mathias Agopian2488b202012-04-20 17:19:28 -0700455 if (err == NO_ERROR) {
456 uint32_t numPendingBuffers = 0;
457 output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
458 &numPendingBuffers);
459 mConsumerRunningBehind = (numPendingBuffers >= 2);
460 }
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700461 if (!err && api == NATIVE_WINDOW_API_CPU) {
462 mConnectedToCpu = true;
463 }
464 return err;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800465}
466
467int SurfaceTextureClient::disconnect(int api) {
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800468 ATRACE_CALL();
Steve Block6807e592011-10-20 11:56:00 +0100469 ALOGV("SurfaceTextureClient::disconnect");
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700470 Mutex::Autolock lock(mMutex);
Jamie Gennis13c5ca32011-10-18 17:14:33 -0700471 freeAllBuffers();
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700472 int err = mSurfaceTexture->disconnect(api);
Mathias Agopian70e3f812011-08-25 17:03:30 -0700473 if (!err) {
Mathias Agopian70e3f812011-08-25 17:03:30 -0700474 mReqFormat = 0;
475 mReqWidth = 0;
476 mReqHeight = 0;
477 mReqUsage = 0;
Mathias Agopian851ef8f2012-03-29 17:10:08 -0700478 mCrop.clear();
479 mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
480 mTransform = 0;
Mathias Agopian70e3f812011-08-25 17:03:30 -0700481 if (api == NATIVE_WINDOW_API_CPU) {
482 mConnectedToCpu = false;
483 }
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700484 }
485 return err;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800486}
487
488int SurfaceTextureClient::setUsage(uint32_t reqUsage)
489{
Steve Block6807e592011-10-20 11:56:00 +0100490 ALOGV("SurfaceTextureClient::setUsage");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800491 Mutex::Autolock lock(mMutex);
492 mReqUsage = reqUsage;
493 return OK;
494}
495
496int SurfaceTextureClient::setCrop(Rect const* rect)
497{
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800498 ATRACE_CALL();
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800499
Jamie Gennis68f91272011-01-28 18:21:54 -0800500 Rect realRect;
501 if (rect == NULL || rect->isEmpty()) {
Mathias Agopian851ef8f2012-03-29 17:10:08 -0700502 realRect.clear();
Jamie Gennis68f91272011-01-28 18:21:54 -0800503 } else {
504 realRect = *rect;
505 }
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800506
Jamie Genniscd1806e2012-05-10 02:22:33 -0700507 ALOGV("SurfaceTextureClient::setCrop rect=[%d %d %d %d]",
508 realRect.left, realRect.top, realRect.right, realRect.bottom);
509
Mathias Agopian851ef8f2012-03-29 17:10:08 -0700510 Mutex::Autolock lock(mMutex);
Jamie Gennisefc7ab62012-04-17 19:36:18 -0700511 mCrop = realRect;
Mathias Agopian851ef8f2012-03-29 17:10:08 -0700512 return NO_ERROR;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800513}
514
515int SurfaceTextureClient::setBufferCount(int bufferCount)
516{
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800517 ATRACE_CALL();
Steve Block6807e592011-10-20 11:56:00 +0100518 ALOGV("SurfaceTextureClient::setBufferCount");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800519 Mutex::Autolock lock(mMutex);
520
521 status_t err = mSurfaceTexture->setBufferCount(bufferCount);
Steve Blocke6f43dd2012-01-06 19:20:56 +0000522 ALOGE_IF(err, "ISurfaceTexture::setBufferCount(%d) returned %s",
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800523 bufferCount, strerror(-err));
524
525 if (err == NO_ERROR) {
526 freeAllBuffers();
527 }
528
529 return err;
530}
531
Jamie Gennisbee205f2011-07-01 13:12:07 -0700532int SurfaceTextureClient::setBuffersDimensions(int w, int h)
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800533{
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800534 ATRACE_CALL();
Steve Block6807e592011-10-20 11:56:00 +0100535 ALOGV("SurfaceTextureClient::setBuffersDimensions");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800536
Jamie Gennisbee205f2011-07-01 13:12:07 -0700537 if (w<0 || h<0)
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800538 return BAD_VALUE;
539
540 if ((w && !h) || (!w && h))
541 return BAD_VALUE;
542
Mathias Agopian851ef8f2012-03-29 17:10:08 -0700543 Mutex::Autolock lock(mMutex);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800544 mReqWidth = w;
545 mReqHeight = h;
Mathias Agopian851ef8f2012-03-29 17:10:08 -0700546 return NO_ERROR;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800547}
548
Michael I. Gold55a70142012-04-09 19:46:29 -0700549int SurfaceTextureClient::setBuffersUserDimensions(int w, int h)
550{
551 ATRACE_CALL();
552 ALOGV("SurfaceTextureClient::setBuffersUserDimensions");
553
554 if (w<0 || h<0)
555 return BAD_VALUE;
556
557 if ((w && !h) || (!w && h))
558 return BAD_VALUE;
559
560 Mutex::Autolock lock(mMutex);
561 mUserWidth = w;
562 mUserHeight = h;
Michael I. Gold55a70142012-04-09 19:46:29 -0700563 return NO_ERROR;
564}
565
Jamie Gennisbee205f2011-07-01 13:12:07 -0700566int SurfaceTextureClient::setBuffersFormat(int format)
567{
Steve Block6807e592011-10-20 11:56:00 +0100568 ALOGV("SurfaceTextureClient::setBuffersFormat");
Jamie Gennisbee205f2011-07-01 13:12:07 -0700569
570 if (format<0)
571 return BAD_VALUE;
572
Mathias Agopian851ef8f2012-03-29 17:10:08 -0700573 Mutex::Autolock lock(mMutex);
Jamie Gennisbee205f2011-07-01 13:12:07 -0700574 mReqFormat = format;
Jamie Gennisbee205f2011-07-01 13:12:07 -0700575 return NO_ERROR;
576}
577
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700578int SurfaceTextureClient::setScalingMode(int mode)
579{
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800580 ATRACE_CALL();
Steve Block6807e592011-10-20 11:56:00 +0100581 ALOGV("SurfaceTextureClient::setScalingMode(%d)", mode);
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700582
Mathias Agopian851ef8f2012-03-29 17:10:08 -0700583 switch (mode) {
584 case NATIVE_WINDOW_SCALING_MODE_FREEZE:
585 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
Daniel Lam016c8cb2012-04-03 15:54:58 -0700586 case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
Mathias Agopian851ef8f2012-03-29 17:10:08 -0700587 break;
588 default:
589 ALOGE("unknown scaling mode: %d", mode);
590 return BAD_VALUE;
591 }
592
593 Mutex::Autolock lock(mMutex);
594 mScalingMode = mode;
595 return NO_ERROR;
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700596}
597
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800598int SurfaceTextureClient::setBuffersTransform(int transform)
599{
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800600 ATRACE_CALL();
Steve Block6807e592011-10-20 11:56:00 +0100601 ALOGV("SurfaceTextureClient::setBuffersTransform");
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800602 Mutex::Autolock lock(mMutex);
Mathias Agopian851ef8f2012-03-29 17:10:08 -0700603 mTransform = transform;
604 return NO_ERROR;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800605}
606
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800607int SurfaceTextureClient::setBuffersTimestamp(int64_t timestamp)
608{
Steve Block6807e592011-10-20 11:56:00 +0100609 ALOGV("SurfaceTextureClient::setBuffersTimestamp");
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800610 Mutex::Autolock lock(mMutex);
611 mTimestamp = timestamp;
612 return NO_ERROR;
613}
614
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800615void SurfaceTextureClient::freeAllBuffers() {
616 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
Mathias Agopianac6035a2012-04-12 16:32:37 -0700617 mSlots[i].buffer = 0;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800618 }
619}
620
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700621// ----------------------------------------------------------------------
622// the lock/unlock APIs must be used from the same thread
623
624static status_t copyBlt(
625 const sp<GraphicBuffer>& dst,
626 const sp<GraphicBuffer>& src,
627 const Region& reg)
628{
629 // src and dst with, height and format must be identical. no verification
630 // is done here.
631 status_t err;
632 uint8_t const * src_bits = NULL;
633 err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
Steve Blocke6f43dd2012-01-06 19:20:56 +0000634 ALOGE_IF(err, "error locking src buffer %s", strerror(-err));
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700635
636 uint8_t* dst_bits = NULL;
637 err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
Steve Blocke6f43dd2012-01-06 19:20:56 +0000638 ALOGE_IF(err, "error locking dst buffer %s", strerror(-err));
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700639
640 Region::const_iterator head(reg.begin());
641 Region::const_iterator tail(reg.end());
642 if (head != tail && src_bits && dst_bits) {
643 const size_t bpp = bytesPerPixel(src->format);
644 const size_t dbpr = dst->stride * bpp;
645 const size_t sbpr = src->stride * bpp;
646
647 while (head != tail) {
648 const Rect& r(*head++);
649 ssize_t h = r.height();
650 if (h <= 0) continue;
651 size_t size = r.width() * bpp;
652 uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
653 uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
654 if (dbpr==sbpr && size==sbpr) {
655 size *= h;
656 h = 1;
657 }
658 do {
659 memcpy(d, s, size);
660 d += dbpr;
661 s += sbpr;
662 } while (--h > 0);
663 }
664 }
665
666 if (src_bits)
667 src->unlock();
668
669 if (dst_bits)
670 dst->unlock();
671
672 return err;
673}
674
675// ----------------------------------------------------------------------------
676
677status_t SurfaceTextureClient::lock(
678 ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
679{
680 if (mLockedBuffer != 0) {
Steve Blocke6f43dd2012-01-06 19:20:56 +0000681 ALOGE("Surface::lock failed, already locked");
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700682 return INVALID_OPERATION;
683 }
684
685 if (!mConnectedToCpu) {
686 int err = SurfaceTextureClient::connect(NATIVE_WINDOW_API_CPU);
687 if (err) {
688 return err;
689 }
690 // we're intending to do software rendering from this point
691 setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
692 }
693
694 ANativeWindowBuffer* out;
695 status_t err = dequeueBuffer(&out);
Steve Blocke6f43dd2012-01-06 19:20:56 +0000696 ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700697 if (err == NO_ERROR) {
698 sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
699 err = lockBuffer(backBuffer.get());
Steve Blocke6f43dd2012-01-06 19:20:56 +0000700 ALOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700701 backBuffer->handle, strerror(-err));
702 if (err == NO_ERROR) {
703 const Rect bounds(backBuffer->width, backBuffer->height);
704
705 Region newDirtyRegion;
706 if (inOutDirtyBounds) {
707 newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
708 newDirtyRegion.andSelf(bounds);
709 } else {
710 newDirtyRegion.set(bounds);
711 }
712
713 // figure out if we can copy the frontbuffer back
714 const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
715 const bool canCopyBack = (frontBuffer != 0 &&
716 backBuffer->width == frontBuffer->width &&
717 backBuffer->height == frontBuffer->height &&
718 backBuffer->format == frontBuffer->format);
719
720 if (canCopyBack) {
721 // copy the area that is invalid and not repainted this round
Mathias Agopianac6035a2012-04-12 16:32:37 -0700722 const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700723 if (!copyback.isEmpty())
724 copyBlt(backBuffer, frontBuffer, copyback);
725 } else {
726 // if we can't copy-back anything, modify the user's dirty
727 // region to make sure they redraw the whole buffer
728 newDirtyRegion.set(bounds);
Mathias Agopianac6035a2012-04-12 16:32:37 -0700729 mDirtyRegion.clear();
730 Mutex::Autolock lock(mMutex);
731 for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
732 mSlots[i].dirtyRegion.clear();
733 }
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700734 }
735
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700736
Mathias Agopianac6035a2012-04-12 16:32:37 -0700737 { // scope for the lock
738 Mutex::Autolock lock(mMutex);
739 int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
740 if (backBufferSlot >= 0) {
741 Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion);
742 mDirtyRegion.subtract(dirtyRegion);
743 dirtyRegion = newDirtyRegion;
744 }
745 }
746
747 mDirtyRegion.orSelf(newDirtyRegion);
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700748 if (inOutDirtyBounds) {
749 *inOutDirtyBounds = newDirtyRegion.getBounds();
750 }
751
752 void* vaddr;
753 status_t res = backBuffer->lock(
754 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
755 newDirtyRegion.bounds(), &vaddr);
756
Steve Block32397c12012-01-05 23:22:43 +0000757 ALOGW_IF(res, "failed locking buffer (handle = %p)",
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700758 backBuffer->handle);
759
760 mLockedBuffer = backBuffer;
761 outBuffer->width = backBuffer->width;
762 outBuffer->height = backBuffer->height;
763 outBuffer->stride = backBuffer->stride;
764 outBuffer->format = backBuffer->format;
765 outBuffer->bits = vaddr;
766 }
767 }
768 return err;
769}
770
771status_t SurfaceTextureClient::unlockAndPost()
772{
773 if (mLockedBuffer == 0) {
Steve Blocke6f43dd2012-01-06 19:20:56 +0000774 ALOGE("Surface::unlockAndPost failed, no locked buffer");
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700775 return INVALID_OPERATION;
776 }
777
778 status_t err = mLockedBuffer->unlock();
Steve Blocke6f43dd2012-01-06 19:20:56 +0000779 ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700780
781 err = queueBuffer(mLockedBuffer.get());
Steve Blocke6f43dd2012-01-06 19:20:56 +0000782 ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
Mathias Agopian8f9dbf92011-07-13 17:39:11 -0700783 mLockedBuffer->handle, strerror(-err));
784
785 mPostedBuffer = mLockedBuffer;
786 mLockedBuffer = 0;
787 return err;
788}
789
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800790}; // namespace android