|
1 /* |
|
2 * Copyright (C) 2012 The Android Open Source Project |
|
3 * Copyright (C) 2013 Mozilla Foundation |
|
4 * |
|
5 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
6 * you may not use this file except in compliance with the License. |
|
7 * You may obtain a copy of the License at |
|
8 * |
|
9 * http://www.apache.org/licenses/LICENSE-2.0 |
|
10 * |
|
11 * Unless required by applicable law or agreed to in writing, software |
|
12 * distributed under the License is distributed on an "AS IS" BASIS, |
|
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 * See the License for the specific language governing permissions and |
|
15 * limitations under the License. |
|
16 */ |
|
17 |
|
18 #define LOG_TAG "GonkBufferQueue" |
|
19 #define ATRACE_TAG ATRACE_TAG_GRAPHICS |
|
20 #define LOG_NDEBUG 0 |
|
21 |
|
22 #define GL_GLEXT_PROTOTYPES |
|
23 #define EGL_EGLEXT_PROTOTYPES |
|
24 |
|
25 #include <utils/Log.h> |
|
26 |
|
27 #include "mozilla/layers/GrallocTextureClient.h" |
|
28 #include "mozilla/layers/ImageBridgeChild.h" |
|
29 |
|
30 #include "GonkBufferQueueJB.h" |
|
31 |
|
32 // Macros for including the GonkBufferQueue name in log messages |
|
33 #define ST_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) |
|
34 #define ST_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) |
|
35 #define ST_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) |
|
36 #define ST_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) |
|
37 #define ST_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) |
|
38 |
|
39 #define ATRACE_BUFFER_INDEX(index) |
|
40 |
|
41 using namespace mozilla; |
|
42 using namespace mozilla::gfx; |
|
43 using namespace mozilla::layers; |
|
44 |
|
45 namespace android { |
|
46 |
|
47 // Get an ID that's unique within this process. |
|
48 static int32_t createProcessUniqueId() { |
|
49 static volatile int32_t globalCounter = 0; |
|
50 return android_atomic_inc(&globalCounter); |
|
51 } |
|
52 |
|
53 static const char* scalingModeName(int scalingMode) { |
|
54 switch (scalingMode) { |
|
55 case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE"; |
|
56 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW"; |
|
57 case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP"; |
|
58 default: return "Unknown"; |
|
59 } |
|
60 } |
|
61 |
|
62 class nsProxyReleaseTask : public Task |
|
63 { |
|
64 public: |
|
65 nsProxyReleaseTask(TextureClient* aClient) |
|
66 : mTextureClient(aClient) { |
|
67 } |
|
68 |
|
69 virtual void Run() MOZ_OVERRIDE |
|
70 { |
|
71 mTextureClient = nullptr; |
|
72 } |
|
73 |
|
74 private: |
|
75 mozilla::RefPtr<TextureClient> mTextureClient; |
|
76 }; |
|
77 |
|
78 GonkBufferQueue::GonkBufferQueue(bool allowSynchronousMode, |
|
79 const sp<IGraphicBufferAlloc>& allocator) : |
|
80 mDefaultWidth(1), |
|
81 mDefaultHeight(1), |
|
82 mMaxAcquiredBufferCount(1), |
|
83 mDefaultMaxBufferCount(2), |
|
84 mOverrideMaxBufferCount(0), |
|
85 mSynchronousMode(true), // GonkBufferQueue always works in sync mode. |
|
86 mAllowSynchronousMode(allowSynchronousMode), |
|
87 mConnectedApi(NO_CONNECTED_API), |
|
88 mAbandoned(false), |
|
89 mFrameCounter(0), |
|
90 mBufferHasBeenQueued(false), |
|
91 mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), |
|
92 mConsumerUsageBits(0), |
|
93 mTransformHint(0) |
|
94 { |
|
95 // Choose a name using the PID and a process-unique ID. |
|
96 mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); |
|
97 |
|
98 ST_LOGV("GonkBufferQueue"); |
|
99 } |
|
100 |
|
101 GonkBufferQueue::~GonkBufferQueue() { |
|
102 ST_LOGV("~GonkBufferQueue"); |
|
103 } |
|
104 |
|
105 status_t GonkBufferQueue::setDefaultMaxBufferCountLocked(int count) { |
|
106 if (count < 2 || count > NUM_BUFFER_SLOTS) |
|
107 return BAD_VALUE; |
|
108 |
|
109 mDefaultMaxBufferCount = count; |
|
110 mDequeueCondition.broadcast(); |
|
111 |
|
112 return NO_ERROR; |
|
113 } |
|
114 |
|
115 bool GonkBufferQueue::isSynchronousMode() const { |
|
116 Mutex::Autolock lock(mMutex); |
|
117 return mSynchronousMode; |
|
118 } |
|
119 |
|
120 void GonkBufferQueue::setConsumerName(const String8& name) { |
|
121 Mutex::Autolock lock(mMutex); |
|
122 mConsumerName = name; |
|
123 } |
|
124 |
|
125 status_t GonkBufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) { |
|
126 Mutex::Autolock lock(mMutex); |
|
127 mDefaultBufferFormat = defaultFormat; |
|
128 return NO_ERROR; |
|
129 } |
|
130 |
|
131 status_t GonkBufferQueue::setConsumerUsageBits(uint32_t usage) { |
|
132 Mutex::Autolock lock(mMutex); |
|
133 mConsumerUsageBits = usage; |
|
134 return NO_ERROR; |
|
135 } |
|
136 |
|
137 status_t GonkBufferQueue::setTransformHint(uint32_t hint) { |
|
138 ST_LOGV("setTransformHint: %02x", hint); |
|
139 Mutex::Autolock lock(mMutex); |
|
140 mTransformHint = hint; |
|
141 return NO_ERROR; |
|
142 } |
|
143 |
|
144 TemporaryRef<TextureClient> |
|
145 GonkBufferQueue::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) |
|
146 { |
|
147 Mutex::Autolock _l(mMutex); |
|
148 if (buffer == NULL) { |
|
149 ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer"); |
|
150 return nullptr; |
|
151 } |
|
152 |
|
153 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { |
|
154 if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) { |
|
155 return mSlots[i].mTextureClient; |
|
156 } |
|
157 } |
|
158 ST_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); |
|
159 return nullptr; |
|
160 } |
|
161 |
|
162 int GonkBufferQueue::getSlotFromTextureClientLocked( |
|
163 TextureClient* client) const |
|
164 { |
|
165 if (client == NULL) { |
|
166 ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer"); |
|
167 return BAD_VALUE; |
|
168 } |
|
169 |
|
170 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { |
|
171 if (mSlots[i].mTextureClient == client) { |
|
172 return i; |
|
173 } |
|
174 } |
|
175 ST_LOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client); |
|
176 return BAD_VALUE; |
|
177 } |
|
178 |
|
179 |
|
180 status_t GonkBufferQueue::setBufferCount(int bufferCount) { |
|
181 ST_LOGV("setBufferCount: count=%d", bufferCount); |
|
182 |
|
183 sp<ConsumerListener> listener; |
|
184 { |
|
185 Mutex::Autolock lock(mMutex); |
|
186 |
|
187 if (mAbandoned) { |
|
188 ST_LOGE("setBufferCount: GonkBufferQueue has been abandoned!"); |
|
189 return NO_INIT; |
|
190 } |
|
191 if (bufferCount > NUM_BUFFER_SLOTS) { |
|
192 ST_LOGE("setBufferCount: bufferCount too large (max %d)", |
|
193 NUM_BUFFER_SLOTS); |
|
194 return BAD_VALUE; |
|
195 } |
|
196 |
|
197 // Error out if the user has dequeued buffers |
|
198 int maxBufferCount = getMaxBufferCountLocked(); |
|
199 for (int i=0 ; i<maxBufferCount; i++) { |
|
200 if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { |
|
201 ST_LOGE("setBufferCount: client owns some buffers"); |
|
202 return -EINVAL; |
|
203 } |
|
204 } |
|
205 |
|
206 const int minBufferSlots = getMinMaxBufferCountLocked(); |
|
207 if (bufferCount == 0) { |
|
208 mOverrideMaxBufferCount = 0; |
|
209 mDequeueCondition.broadcast(); |
|
210 return NO_ERROR; |
|
211 } |
|
212 |
|
213 if (bufferCount < minBufferSlots) { |
|
214 ST_LOGE("setBufferCount: requested buffer count (%d) is less than " |
|
215 "minimum (%d)", bufferCount, minBufferSlots); |
|
216 return BAD_VALUE; |
|
217 } |
|
218 |
|
219 // here we're guaranteed that the client doesn't have dequeued buffers |
|
220 // and will release all of its buffer references. |
|
221 // |
|
222 // XXX: Should this use drainQueueAndFreeBuffersLocked instead? |
|
223 freeAllBuffersLocked(); |
|
224 mOverrideMaxBufferCount = bufferCount; |
|
225 mBufferHasBeenQueued = false; |
|
226 mDequeueCondition.broadcast(); |
|
227 listener = mConsumerListener; |
|
228 } // scope for lock |
|
229 |
|
230 if (listener != NULL) { |
|
231 listener->onBuffersReleased(); |
|
232 } |
|
233 |
|
234 return NO_ERROR; |
|
235 } |
|
236 |
|
237 int GonkBufferQueue::query(int what, int* outValue) |
|
238 { |
|
239 Mutex::Autolock lock(mMutex); |
|
240 |
|
241 if (mAbandoned) { |
|
242 ST_LOGE("query: GonkBufferQueue has been abandoned!"); |
|
243 return NO_INIT; |
|
244 } |
|
245 |
|
246 int value; |
|
247 switch (what) { |
|
248 case NATIVE_WINDOW_WIDTH: |
|
249 value = mDefaultWidth; |
|
250 break; |
|
251 case NATIVE_WINDOW_HEIGHT: |
|
252 value = mDefaultHeight; |
|
253 break; |
|
254 case NATIVE_WINDOW_FORMAT: |
|
255 value = mDefaultBufferFormat; |
|
256 break; |
|
257 case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: |
|
258 value = getMinUndequeuedBufferCountLocked(); |
|
259 break; |
|
260 case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: |
|
261 value = (mQueue.size() >= 2); |
|
262 break; |
|
263 default: |
|
264 return BAD_VALUE; |
|
265 } |
|
266 outValue[0] = value; |
|
267 return NO_ERROR; |
|
268 } |
|
269 |
|
270 status_t GonkBufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) { |
|
271 ST_LOGV("requestBuffer: slot=%d", slot); |
|
272 Mutex::Autolock lock(mMutex); |
|
273 if (mAbandoned) { |
|
274 ST_LOGE("requestBuffer: GonkBufferQueue has been abandoned!"); |
|
275 return NO_INIT; |
|
276 } |
|
277 int maxBufferCount = getMaxBufferCountLocked(); |
|
278 if (slot < 0 || maxBufferCount <= slot) { |
|
279 ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d", |
|
280 maxBufferCount, slot); |
|
281 return BAD_VALUE; |
|
282 } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { |
|
283 // XXX: I vaguely recall there was some reason this can be valid, but |
|
284 // for the life of me I can't recall under what circumstances that's |
|
285 // the case. |
|
286 ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)", |
|
287 slot, mSlots[slot].mBufferState); |
|
288 return BAD_VALUE; |
|
289 } |
|
290 mSlots[slot].mRequestBufferCalled = true; |
|
291 *buf = mSlots[slot].mGraphicBuffer; |
|
292 return NO_ERROR; |
|
293 } |
|
294 |
|
295 status_t GonkBufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, |
|
296 uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { |
|
297 ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); |
|
298 |
|
299 if ((w && !h) || (!w && h)) { |
|
300 ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); |
|
301 return BAD_VALUE; |
|
302 } |
|
303 |
|
304 status_t returnFlags(OK); |
|
305 int buf = INVALID_BUFFER_SLOT; |
|
306 |
|
307 { // Scope for the lock |
|
308 Mutex::Autolock lock(mMutex); |
|
309 |
|
310 if (format == 0) { |
|
311 format = mDefaultBufferFormat; |
|
312 } |
|
313 // turn on usage bits the consumer requested |
|
314 usage |= mConsumerUsageBits; |
|
315 |
|
316 int found = -1; |
|
317 int dequeuedCount = 0; |
|
318 bool tryAgain = true; |
|
319 while (tryAgain) { |
|
320 if (mAbandoned) { |
|
321 ST_LOGE("dequeueBuffer: GonkBufferQueue has been abandoned!"); |
|
322 return NO_INIT; |
|
323 } |
|
324 |
|
325 const int maxBufferCount = getMaxBufferCountLocked(); |
|
326 |
|
327 // Free up any buffers that are in slots beyond the max buffer |
|
328 // count. |
|
329 //for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { |
|
330 // assert(mSlots[i].mBufferState == BufferSlot::FREE); |
|
331 // if (mSlots[i].mGraphicBuffer != NULL) { |
|
332 // freeBufferLocked(i); |
|
333 // returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS; |
|
334 // } |
|
335 //} |
|
336 |
|
337 // look for a free buffer to give to the client |
|
338 found = INVALID_BUFFER_SLOT; |
|
339 dequeuedCount = 0; |
|
340 for (int i = 0; i < maxBufferCount; i++) { |
|
341 const int state = mSlots[i].mBufferState; |
|
342 if (state == BufferSlot::DEQUEUED) { |
|
343 dequeuedCount++; |
|
344 } |
|
345 |
|
346 if (state == BufferSlot::FREE) { |
|
347 /* We return the oldest of the free buffers to avoid |
|
348 * stalling the producer if possible. This is because |
|
349 * the consumer may still have pending reads of the |
|
350 * buffers in flight. |
|
351 */ |
|
352 if ((found < 0) || |
|
353 mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) { |
|
354 found = i; |
|
355 } |
|
356 } |
|
357 } |
|
358 |
|
359 // clients are not allowed to dequeue more than one buffer |
|
360 // if they didn't set a buffer count. |
|
361 if (!mOverrideMaxBufferCount && dequeuedCount) { |
|
362 ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without " |
|
363 "setting the buffer count"); |
|
364 return -EINVAL; |
|
365 } |
|
366 |
|
367 // See whether a buffer has been queued since the last |
|
368 // setBufferCount so we know whether to perform the min undequeued |
|
369 // buffers check below. |
|
370 if (mBufferHasBeenQueued) { |
|
371 // make sure the client is not trying to dequeue more buffers |
|
372 // than allowed. |
|
373 const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1); |
|
374 const int minUndequeuedCount = getMinUndequeuedBufferCountLocked(); |
|
375 if (newUndequeuedCount < minUndequeuedCount) { |
|
376 ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) " |
|
377 "exceeded (dequeued=%d undequeudCount=%d)", |
|
378 minUndequeuedCount, dequeuedCount, |
|
379 newUndequeuedCount); |
|
380 return -EBUSY; |
|
381 } |
|
382 } |
|
383 |
|
384 // If no buffer is found, wait for a buffer to be released or for |
|
385 // the max buffer count to change. |
|
386 tryAgain = found == INVALID_BUFFER_SLOT; |
|
387 if (tryAgain) { |
|
388 mDequeueCondition.wait(mMutex); |
|
389 } |
|
390 } |
|
391 |
|
392 |
|
393 if (found == INVALID_BUFFER_SLOT) { |
|
394 // This should not happen. |
|
395 ST_LOGE("dequeueBuffer: no available buffer slots"); |
|
396 return -EBUSY; |
|
397 } |
|
398 |
|
399 buf = found; |
|
400 *outBuf = found; |
|
401 |
|
402 const bool useDefaultSize = !w && !h; |
|
403 if (useDefaultSize) { |
|
404 // use the default size |
|
405 w = mDefaultWidth; |
|
406 h = mDefaultHeight; |
|
407 } |
|
408 |
|
409 mSlots[buf].mBufferState = BufferSlot::DEQUEUED; |
|
410 |
|
411 const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer); |
|
412 if ((buffer == NULL) || |
|
413 (uint32_t(buffer->width) != w) || |
|
414 (uint32_t(buffer->height) != h) || |
|
415 (uint32_t(buffer->format) != format) || |
|
416 ((uint32_t(buffer->usage) & usage) != usage)) |
|
417 { |
|
418 mSlots[buf].mAcquireCalled = false; |
|
419 mSlots[buf].mGraphicBuffer = NULL; |
|
420 mSlots[buf].mRequestBufferCalled = false; |
|
421 mSlots[buf].mFence = Fence::NO_FENCE; |
|
422 if (mSlots[buf].mTextureClient) { |
|
423 mSlots[buf].mTextureClient->ClearRecycleCallback(); |
|
424 // release TextureClient in ImageBridge thread |
|
425 nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[buf].mTextureClient); |
|
426 mSlots[buf].mTextureClient = NULL; |
|
427 ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task); |
|
428 } |
|
429 returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION; |
|
430 } |
|
431 |
|
432 *outFence = mSlots[buf].mFence; |
|
433 mSlots[buf].mFence = Fence::NO_FENCE; |
|
434 } // end lock scope |
|
435 |
|
436 sp<GraphicBuffer> graphicBuffer; |
|
437 if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { |
|
438 RefPtr<GrallocTextureClientOGL> textureClient = |
|
439 new GrallocTextureClientOGL(ImageBridgeChild::GetSingleton(), |
|
440 gfx::SurfaceFormat::UNKNOWN, |
|
441 gfx::BackendType::NONE, |
|
442 TEXTURE_DEALLOCATE_CLIENT); |
|
443 usage |= GraphicBuffer::USAGE_HW_TEXTURE; |
|
444 bool result = textureClient->AllocateGralloc(IntSize(w, h), format, usage); |
|
445 sp<GraphicBuffer> graphicBuffer = textureClient->GetGraphicBuffer(); |
|
446 if (!result || !graphicBuffer.get()) { |
|
447 ST_LOGE("dequeueBuffer: failed to alloc gralloc buffer"); |
|
448 return -ENOMEM; |
|
449 } |
|
450 |
|
451 { // Scope for the lock |
|
452 Mutex::Autolock lock(mMutex); |
|
453 |
|
454 if (mAbandoned) { |
|
455 ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); |
|
456 return NO_INIT; |
|
457 } |
|
458 |
|
459 mSlots[buf].mGraphicBuffer = graphicBuffer; |
|
460 mSlots[buf].mTextureClient = textureClient; |
|
461 ST_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf, |
|
462 mSlots[buf].mGraphicBuffer->handle); |
|
463 //mSlots[*outBuf].mGraphicBuffer = graphicBuffer; |
|
464 } |
|
465 } |
|
466 |
|
467 ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf, |
|
468 mSlots[*outBuf].mGraphicBuffer->handle, returnFlags); |
|
469 |
|
470 return returnFlags; |
|
471 } |
|
472 |
|
473 status_t GonkBufferQueue::setSynchronousMode(bool enabled) { |
|
474 return NO_ERROR; |
|
475 } |
|
476 |
|
477 status_t GonkBufferQueue::queueBuffer(int buf, |
|
478 const QueueBufferInput& input, QueueBufferOutput* output) { |
|
479 |
|
480 Rect crop; |
|
481 uint32_t transform; |
|
482 int scalingMode; |
|
483 int64_t timestamp; |
|
484 sp<Fence> fence; |
|
485 |
|
486 input.deflate(×tamp, &crop, &scalingMode, &transform, &fence); |
|
487 |
|
488 #if ANDROID_VERSION >= 18 |
|
489 if (fence == NULL) { |
|
490 ST_LOGE("queueBuffer: fence is NULL"); |
|
491 return BAD_VALUE; |
|
492 } |
|
493 #endif |
|
494 |
|
495 ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x " |
|
496 "scale=%s", |
|
497 buf, timestamp, crop.left, crop.top, crop.right, crop.bottom, |
|
498 transform, scalingModeName(scalingMode)); |
|
499 |
|
500 sp<ConsumerListener> listener; |
|
501 |
|
502 { // scope for the lock |
|
503 Mutex::Autolock lock(mMutex); |
|
504 if (mAbandoned) { |
|
505 ST_LOGE("queueBuffer: GonkBufferQueue has been abandoned!"); |
|
506 return NO_INIT; |
|
507 } |
|
508 int maxBufferCount = getMaxBufferCountLocked(); |
|
509 if (buf < 0 || buf >= maxBufferCount) { |
|
510 ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d", |
|
511 maxBufferCount, buf); |
|
512 return -EINVAL; |
|
513 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { |
|
514 ST_LOGE("queueBuffer: slot %d is not owned by the client " |
|
515 "(state=%d)", buf, mSlots[buf].mBufferState); |
|
516 return -EINVAL; |
|
517 } else if (!mSlots[buf].mRequestBufferCalled) { |
|
518 ST_LOGE("queueBuffer: slot %d was enqueued without requesting a " |
|
519 "buffer", buf); |
|
520 return -EINVAL; |
|
521 } |
|
522 |
|
523 const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer); |
|
524 Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); |
|
525 Rect croppedCrop; |
|
526 crop.intersect(bufferRect, &croppedCrop); |
|
527 if (croppedCrop != crop) { |
|
528 ST_LOGE("queueBuffer: crop rect is not contained within the " |
|
529 "buffer in slot %d", buf); |
|
530 return -EINVAL; |
|
531 } |
|
532 |
|
533 if (mSynchronousMode) { |
|
534 // In synchronous mode we queue all buffers in a FIFO. |
|
535 mQueue.push_back(buf); |
|
536 |
|
537 // Synchronous mode always signals that an additional frame should |
|
538 // be consumed. |
|
539 listener = mConsumerListener; |
|
540 } else { |
|
541 // In asynchronous mode we only keep the most recent buffer. |
|
542 if (mQueue.empty()) { |
|
543 mQueue.push_back(buf); |
|
544 |
|
545 // Asynchronous mode only signals that a frame should be |
|
546 // consumed if no previous frame was pending. If a frame were |
|
547 // pending then the consumer would have already been notified. |
|
548 listener = mConsumerListener; |
|
549 } else { |
|
550 Fifo::iterator front(mQueue.begin()); |
|
551 // buffer currently queued is freed |
|
552 mSlots[*front].mBufferState = BufferSlot::FREE; |
|
553 // and we record the new buffer index in the queued list |
|
554 *front = buf; |
|
555 } |
|
556 } |
|
557 |
|
558 mSlots[buf].mTimestamp = timestamp; |
|
559 mSlots[buf].mCrop = crop; |
|
560 mSlots[buf].mTransform = transform; |
|
561 mSlots[buf].mFence = fence; |
|
562 |
|
563 switch (scalingMode) { |
|
564 case NATIVE_WINDOW_SCALING_MODE_FREEZE: |
|
565 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: |
|
566 case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: |
|
567 break; |
|
568 default: |
|
569 ST_LOGE("unknown scaling mode: %d (ignoring)", scalingMode); |
|
570 scalingMode = mSlots[buf].mScalingMode; |
|
571 break; |
|
572 } |
|
573 |
|
574 mSlots[buf].mBufferState = BufferSlot::QUEUED; |
|
575 mSlots[buf].mScalingMode = scalingMode; |
|
576 mFrameCounter++; |
|
577 mSlots[buf].mFrameNumber = mFrameCounter; |
|
578 |
|
579 mBufferHasBeenQueued = true; |
|
580 mDequeueCondition.broadcast(); |
|
581 |
|
582 output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, |
|
583 mQueue.size()); |
|
584 } // scope for the lock |
|
585 |
|
586 // call back without lock held |
|
587 if (listener != 0) { |
|
588 listener->onFrameAvailable(); |
|
589 } |
|
590 return NO_ERROR; |
|
591 } |
|
592 |
|
593 #if ANDROID_VERSION == 17 |
|
594 void GonkBufferQueue::cancelBuffer(int buf, sp<Fence> fence) { |
|
595 #else |
|
596 void GonkBufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) { |
|
597 #endif |
|
598 |
|
599 ST_LOGV("cancelBuffer: slot=%d", buf); |
|
600 Mutex::Autolock lock(mMutex); |
|
601 |
|
602 if (mAbandoned) { |
|
603 ST_LOGW("cancelBuffer: GonkBufferQueue has been abandoned!"); |
|
604 return; |
|
605 } |
|
606 |
|
607 int maxBufferCount = getMaxBufferCountLocked(); |
|
608 if (buf < 0 || buf >= maxBufferCount) { |
|
609 ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d", |
|
610 maxBufferCount, buf); |
|
611 return; |
|
612 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { |
|
613 ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", |
|
614 buf, mSlots[buf].mBufferState); |
|
615 return; |
|
616 #if ANDROID_VERSION >= 18 |
|
617 } else if (fence == NULL) { |
|
618 ST_LOGE("cancelBuffer: fence is NULL"); |
|
619 return; |
|
620 #endif |
|
621 } |
|
622 mSlots[buf].mBufferState = BufferSlot::FREE; |
|
623 mSlots[buf].mFrameNumber = 0; |
|
624 mSlots[buf].mFence = fence; |
|
625 mDequeueCondition.broadcast(); |
|
626 } |
|
627 |
|
628 status_t GonkBufferQueue::connect(int api, QueueBufferOutput* output) { |
|
629 ST_LOGV("connect: api=%d", api); |
|
630 Mutex::Autolock lock(mMutex); |
|
631 |
|
632 if (mAbandoned) { |
|
633 ST_LOGE("connect: GonkBufferQueue has been abandoned!"); |
|
634 return NO_INIT; |
|
635 } |
|
636 |
|
637 if (mConsumerListener == NULL) { |
|
638 ST_LOGE("connect: GonkBufferQueue has no consumer!"); |
|
639 return NO_INIT; |
|
640 } |
|
641 |
|
642 int err = NO_ERROR; |
|
643 switch (api) { |
|
644 case NATIVE_WINDOW_API_EGL: |
|
645 case NATIVE_WINDOW_API_CPU: |
|
646 case NATIVE_WINDOW_API_MEDIA: |
|
647 case NATIVE_WINDOW_API_CAMERA: |
|
648 if (mConnectedApi != NO_CONNECTED_API) { |
|
649 ST_LOGE("connect: already connected (cur=%d, req=%d)", |
|
650 mConnectedApi, api); |
|
651 err = -EINVAL; |
|
652 } else { |
|
653 mConnectedApi = api; |
|
654 output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, |
|
655 mQueue.size()); |
|
656 } |
|
657 break; |
|
658 default: |
|
659 err = -EINVAL; |
|
660 break; |
|
661 } |
|
662 |
|
663 mBufferHasBeenQueued = false; |
|
664 |
|
665 return err; |
|
666 } |
|
667 |
|
668 status_t GonkBufferQueue::disconnect(int api) { |
|
669 ST_LOGV("disconnect: api=%d", api); |
|
670 |
|
671 int err = NO_ERROR; |
|
672 sp<ConsumerListener> listener; |
|
673 |
|
674 { // Scope for the lock |
|
675 Mutex::Autolock lock(mMutex); |
|
676 |
|
677 if (mAbandoned) { |
|
678 // it is not really an error to disconnect after the surface |
|
679 // has been abandoned, it should just be a no-op. |
|
680 return NO_ERROR; |
|
681 } |
|
682 |
|
683 switch (api) { |
|
684 case NATIVE_WINDOW_API_EGL: |
|
685 case NATIVE_WINDOW_API_CPU: |
|
686 case NATIVE_WINDOW_API_MEDIA: |
|
687 case NATIVE_WINDOW_API_CAMERA: |
|
688 if (mConnectedApi == api) { |
|
689 freeAllBuffersLocked(); |
|
690 mConnectedApi = NO_CONNECTED_API; |
|
691 mDequeueCondition.broadcast(); |
|
692 listener = mConsumerListener; |
|
693 } else { |
|
694 ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)", |
|
695 mConnectedApi, api); |
|
696 err = -EINVAL; |
|
697 } |
|
698 break; |
|
699 default: |
|
700 ST_LOGE("disconnect: unknown API %d", api); |
|
701 err = -EINVAL; |
|
702 break; |
|
703 } |
|
704 } |
|
705 |
|
706 if (listener != NULL) { |
|
707 listener->onBuffersReleased(); |
|
708 } |
|
709 |
|
710 return err; |
|
711 } |
|
712 |
|
713 void GonkBufferQueue::dump(String8& result) const |
|
714 { |
|
715 char buffer[1024]; |
|
716 GonkBufferQueue::dump(result, "", buffer, 1024); |
|
717 } |
|
718 |
|
719 void GonkBufferQueue::dump(String8& result, const char* prefix, |
|
720 char* buffer, size_t SIZE) const |
|
721 { |
|
722 Mutex::Autolock _l(mMutex); |
|
723 |
|
724 String8 fifo; |
|
725 int fifoSize = 0; |
|
726 Fifo::const_iterator i(mQueue.begin()); |
|
727 while (i != mQueue.end()) { |
|
728 snprintf(buffer, SIZE, "%02d ", *i++); |
|
729 fifoSize++; |
|
730 fifo.append(buffer); |
|
731 } |
|
732 |
|
733 int maxBufferCount = getMaxBufferCountLocked(); |
|
734 |
|
735 snprintf(buffer, SIZE, |
|
736 "%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " |
|
737 "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n", |
|
738 prefix, maxBufferCount, mSynchronousMode, mDefaultWidth, |
|
739 mDefaultHeight, mDefaultBufferFormat, mTransformHint, |
|
740 fifoSize, fifo.string()); |
|
741 result.append(buffer); |
|
742 |
|
743 |
|
744 struct { |
|
745 const char * operator()(int state) const { |
|
746 switch (state) { |
|
747 case BufferSlot::DEQUEUED: return "DEQUEUED"; |
|
748 case BufferSlot::QUEUED: return "QUEUED"; |
|
749 case BufferSlot::FREE: return "FREE"; |
|
750 case BufferSlot::ACQUIRED: return "ACQUIRED"; |
|
751 default: return "Unknown"; |
|
752 } |
|
753 } |
|
754 } stateName; |
|
755 |
|
756 for (int i=0 ; i<maxBufferCount ; i++) { |
|
757 const BufferSlot& slot(mSlots[i]); |
|
758 snprintf(buffer, SIZE, |
|
759 "%s%s[%02d] " |
|
760 "state=%-8s, crop=[%d,%d,%d,%d], " |
|
761 "xform=0x%02x, time=%#llx, scale=%s", |
|
762 prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, |
|
763 stateName(slot.mBufferState), |
|
764 slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, |
|
765 slot.mCrop.bottom, slot.mTransform, slot.mTimestamp, |
|
766 scalingModeName(slot.mScalingMode) |
|
767 ); |
|
768 result.append(buffer); |
|
769 |
|
770 const sp<GraphicBuffer>& buf(slot.mGraphicBuffer); |
|
771 if (buf != NULL) { |
|
772 snprintf(buffer, SIZE, |
|
773 ", %p [%4ux%4u:%4u,%3X]", |
|
774 buf->handle, buf->width, buf->height, buf->stride, |
|
775 buf->format); |
|
776 result.append(buffer); |
|
777 } |
|
778 result.append("\n"); |
|
779 } |
|
780 } |
|
781 |
|
782 void GonkBufferQueue::freeAllBuffersLocked() |
|
783 { |
|
784 ALOGW_IF(!mQueue.isEmpty(), |
|
785 "freeAllBuffersLocked called but mQueue is not empty"); |
|
786 mQueue.clear(); |
|
787 mBufferHasBeenQueued = false; |
|
788 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { |
|
789 mSlots[i].mGraphicBuffer = 0; |
|
790 if (mSlots[i].mTextureClient) { |
|
791 mSlots[i].mTextureClient->ClearRecycleCallback(); |
|
792 // release TextureClient in ImageBridge thread |
|
793 nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient); |
|
794 mSlots[i].mTextureClient = NULL; |
|
795 ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task); |
|
796 } |
|
797 if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) { |
|
798 mSlots[i].mNeedsCleanupOnRelease = true; |
|
799 } |
|
800 mSlots[i].mBufferState = BufferSlot::FREE; |
|
801 mSlots[i].mFrameNumber = 0; |
|
802 mSlots[i].mAcquireCalled = false; |
|
803 // destroy fence as GonkBufferQueue now takes ownership |
|
804 mSlots[i].mFence = Fence::NO_FENCE; |
|
805 } |
|
806 } |
|
807 |
|
808 status_t GonkBufferQueue::acquireBuffer(BufferItem *buffer) { |
|
809 Mutex::Autolock _l(mMutex); |
|
810 |
|
811 // Check that the consumer doesn't currently have the maximum number of |
|
812 // buffers acquired. We allow the max buffer count to be exceeded by one |
|
813 // buffer, so that the consumer can successfully set up the newly acquired |
|
814 // buffer before releasing the old one. |
|
815 int numAcquiredBuffers = 0; |
|
816 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { |
|
817 if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) { |
|
818 numAcquiredBuffers++; |
|
819 } |
|
820 } |
|
821 if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) { |
|
822 ST_LOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)", |
|
823 numAcquiredBuffers, mMaxAcquiredBufferCount); |
|
824 return INVALID_OPERATION; |
|
825 } |
|
826 |
|
827 // check if queue is empty |
|
828 // In asynchronous mode the list is guaranteed to be one buffer |
|
829 // deep, while in synchronous mode we use the oldest buffer. |
|
830 if (!mQueue.empty()) { |
|
831 Fifo::iterator front(mQueue.begin()); |
|
832 int buf = *front; |
|
833 |
|
834 // In android, when the buffer is aquired by BufferConsumer, |
|
835 // BufferQueue releases a reference to the buffer and |
|
836 // it's ownership moves to the BufferConsumer. |
|
837 // In b2g, GonkBufferQueue continues to have a buffer ownership. |
|
838 // It is necessary to free buffer via ImageBridgeChild. |
|
839 |
|
840 //if (mSlots[buf].mAcquireCalled) { |
|
841 // buffer->mGraphicBuffer = NULL; |
|
842 //} else { |
|
843 // buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; |
|
844 //} |
|
845 buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; |
|
846 buffer->mCrop = mSlots[buf].mCrop; |
|
847 buffer->mTransform = mSlots[buf].mTransform; |
|
848 buffer->mScalingMode = mSlots[buf].mScalingMode; |
|
849 buffer->mFrameNumber = mSlots[buf].mFrameNumber; |
|
850 buffer->mTimestamp = mSlots[buf].mTimestamp; |
|
851 buffer->mBuf = buf; |
|
852 buffer->mFence = mSlots[buf].mFence; |
|
853 |
|
854 mSlots[buf].mAcquireCalled = true; |
|
855 mSlots[buf].mNeedsCleanupOnRelease = false; |
|
856 mSlots[buf].mBufferState = BufferSlot::ACQUIRED; |
|
857 mSlots[buf].mFence = Fence::NO_FENCE; |
|
858 |
|
859 mQueue.erase(front); |
|
860 mDequeueCondition.broadcast(); |
|
861 } else { |
|
862 return NO_BUFFER_AVAILABLE; |
|
863 } |
|
864 |
|
865 return NO_ERROR; |
|
866 } |
|
867 |
|
868 status_t GonkBufferQueue::releaseBuffer(int buf, const sp<Fence>& fence) { |
|
869 Mutex::Autolock _l(mMutex); |
|
870 |
|
871 #if ANDROID_VERSION == 17 |
|
872 if (buf == INVALID_BUFFER_SLOT) { |
|
873 #else |
|
874 if (buf == INVALID_BUFFER_SLOT || fence == NULL) { |
|
875 #endif |
|
876 return BAD_VALUE; |
|
877 } |
|
878 |
|
879 mSlots[buf].mFence = fence; |
|
880 |
|
881 // The buffer can now only be released if its in the acquired state |
|
882 if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { |
|
883 mSlots[buf].mBufferState = BufferSlot::FREE; |
|
884 } else if (mSlots[buf].mNeedsCleanupOnRelease) { |
|
885 ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState); |
|
886 mSlots[buf].mNeedsCleanupOnRelease = false; |
|
887 return STALE_BUFFER_SLOT; |
|
888 } else { |
|
889 ST_LOGE("attempted to release buf %d but its state was %d", buf, mSlots[buf].mBufferState); |
|
890 return -EINVAL; |
|
891 } |
|
892 |
|
893 mDequeueCondition.broadcast(); |
|
894 return NO_ERROR; |
|
895 } |
|
896 |
|
897 status_t GonkBufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListener) { |
|
898 ST_LOGV("consumerConnect"); |
|
899 Mutex::Autolock lock(mMutex); |
|
900 |
|
901 if (mAbandoned) { |
|
902 ST_LOGE("consumerConnect: GonkBufferQueue has been abandoned!"); |
|
903 return NO_INIT; |
|
904 } |
|
905 if (consumerListener == NULL) { |
|
906 ST_LOGE("consumerConnect: consumerListener may not be NULL"); |
|
907 return BAD_VALUE; |
|
908 } |
|
909 |
|
910 mConsumerListener = consumerListener; |
|
911 |
|
912 return NO_ERROR; |
|
913 } |
|
914 |
|
915 status_t GonkBufferQueue::consumerDisconnect() { |
|
916 ST_LOGV("consumerDisconnect"); |
|
917 Mutex::Autolock lock(mMutex); |
|
918 |
|
919 if (mConsumerListener == NULL) { |
|
920 ST_LOGE("consumerDisconnect: No consumer is connected!"); |
|
921 return -EINVAL; |
|
922 } |
|
923 |
|
924 mAbandoned = true; |
|
925 mConsumerListener = NULL; |
|
926 mQueue.clear(); |
|
927 freeAllBuffersLocked(); |
|
928 mDequeueCondition.broadcast(); |
|
929 return NO_ERROR; |
|
930 } |
|
931 |
|
932 status_t GonkBufferQueue::getReleasedBuffers(uint32_t* slotMask) { |
|
933 ST_LOGV("getReleasedBuffers"); |
|
934 Mutex::Autolock lock(mMutex); |
|
935 |
|
936 if (mAbandoned) { |
|
937 ST_LOGE("getReleasedBuffers: GonkBufferQueue has been abandoned!"); |
|
938 return NO_INIT; |
|
939 } |
|
940 |
|
941 uint32_t mask = 0; |
|
942 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { |
|
943 if (!mSlots[i].mAcquireCalled) { |
|
944 mask |= 1 << i; |
|
945 } |
|
946 } |
|
947 *slotMask = mask; |
|
948 |
|
949 ST_LOGV("getReleasedBuffers: returning mask %#x", mask); |
|
950 return NO_ERROR; |
|
951 } |
|
952 |
|
953 status_t GonkBufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) |
|
954 { |
|
955 ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h); |
|
956 if (!w || !h) { |
|
957 ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", |
|
958 w, h); |
|
959 return BAD_VALUE; |
|
960 } |
|
961 |
|
962 Mutex::Autolock lock(mMutex); |
|
963 mDefaultWidth = w; |
|
964 mDefaultHeight = h; |
|
965 return NO_ERROR; |
|
966 } |
|
967 |
|
968 status_t GonkBufferQueue::setDefaultMaxBufferCount(int bufferCount) { |
|
969 Mutex::Autolock lock(mMutex); |
|
970 return setDefaultMaxBufferCountLocked(bufferCount); |
|
971 } |
|
972 |
|
973 status_t GonkBufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { |
|
974 Mutex::Autolock lock(mMutex); |
|
975 if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > MAX_MAX_ACQUIRED_BUFFERS) { |
|
976 ST_LOGE("setMaxAcquiredBufferCount: invalid count specified: %d", |
|
977 maxAcquiredBuffers); |
|
978 return BAD_VALUE; |
|
979 } |
|
980 if (mConnectedApi != NO_CONNECTED_API) { |
|
981 return INVALID_OPERATION; |
|
982 } |
|
983 mMaxAcquiredBufferCount = maxAcquiredBuffers; |
|
984 return NO_ERROR; |
|
985 } |
|
986 |
|
987 int GonkBufferQueue::getMinMaxBufferCountLocked() const { |
|
988 return getMinUndequeuedBufferCountLocked() + 1; |
|
989 } |
|
990 |
|
991 int GonkBufferQueue::getMinUndequeuedBufferCountLocked() const { |
|
992 return mSynchronousMode ? mMaxAcquiredBufferCount : |
|
993 mMaxAcquiredBufferCount + 1; |
|
994 } |
|
995 |
|
996 int GonkBufferQueue::getMaxBufferCountLocked() const { |
|
997 int minMaxBufferCount = getMinMaxBufferCountLocked(); |
|
998 |
|
999 int maxBufferCount = mDefaultMaxBufferCount; |
|
1000 if (maxBufferCount < minMaxBufferCount) { |
|
1001 maxBufferCount = minMaxBufferCount; |
|
1002 } |
|
1003 if (mOverrideMaxBufferCount != 0) { |
|
1004 assert(mOverrideMaxBufferCount >= minMaxBufferCount); |
|
1005 maxBufferCount = mOverrideMaxBufferCount; |
|
1006 } |
|
1007 |
|
1008 // Any buffers that are dequeued by the producer or sitting in the queue |
|
1009 // waiting to be consumed need to have their slots preserved. Such |
|
1010 // buffers will temporarily keep the max buffer count up until the slots |
|
1011 // no longer need to be preserved. |
|
1012 for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { |
|
1013 BufferSlot::BufferState state = mSlots[i].mBufferState; |
|
1014 if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) { |
|
1015 maxBufferCount = i + 1; |
|
1016 } |
|
1017 } |
|
1018 |
|
1019 return maxBufferCount; |
|
1020 } |
|
1021 |
|
1022 GonkBufferQueue::ProxyConsumerListener::ProxyConsumerListener( |
|
1023 const wp<GonkBufferQueue::ConsumerListener>& consumerListener): |
|
1024 mConsumerListener(consumerListener) {} |
|
1025 |
|
1026 GonkBufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} |
|
1027 |
|
1028 void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable() { |
|
1029 sp<GonkBufferQueue::ConsumerListener> listener(mConsumerListener.promote()); |
|
1030 if (listener != NULL) { |
|
1031 listener->onFrameAvailable(); |
|
1032 } |
|
1033 } |
|
1034 |
|
1035 void GonkBufferQueue::ProxyConsumerListener::onBuffersReleased() { |
|
1036 sp<GonkBufferQueue::ConsumerListener> listener(mConsumerListener.promote()); |
|
1037 if (listener != NULL) { |
|
1038 listener->onBuffersReleased(); |
|
1039 } |
|
1040 } |
|
1041 |
|
1042 }; // namespace android |