1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=4 et sw=4 tw=80: */
4 * Copyright (C) 2010 The Android Open Source Project
5 * Copyright (C) 2012 Mozilla Foundation
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
20 #include "base/basictypes.h"
21 #include "GonkCameraHwMgr.h"
22 #include "mozilla/layers/ShadowLayers.h"
23 #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
24 #include "mozilla/layers/ImageBridgeChild.h"
25 #include "GonkNativeWindow.h"
29 * DOM_CAMERA_LOGI() is enabled in debug builds, and turned on by setting
30 * NSPR_LOG_MODULES=Camera:N environment variable, where N >= 3.
32 * CNW_LOGE() is always enabled.
34 #define CNW_LOGD(...) DOM_CAMERA_LOGI(__VA_ARGS__)
35 #define CNW_LOGE(...) {(void)printf_stderr(__VA_ARGS__);}
37 using namespace android
;
38 using namespace mozilla::layers
;
40 GonkNativeWindow::GonkNativeWindow(GonkNativeWindowNewFrameCallback
* aCallback
)
41 : mNewFrameCallback(aCallback
)
43 GonkNativeWindow::init();
46 GonkNativeWindow::GonkNativeWindow()
47 : mNewFrameCallback(nullptr)
49 GonkNativeWindow::init();
52 GonkNativeWindow::~GonkNativeWindow()
54 nsAutoTArray
<SurfaceDescriptor
, NUM_BUFFER_SLOTS
> freeList
;
55 freeAllBuffersLocked(freeList
);
56 releaseBufferFreeListUnlocked(freeList
);
59 void GonkNativeWindow::abandon()
61 nsAutoTArray
<SurfaceDescriptor
, NUM_BUFFER_SLOTS
> freeList
;
63 Mutex::Autolock
lock(mMutex
);
65 freeAllBuffersLocked(freeList
);
68 releaseBufferFreeListUnlocked(freeList
);
69 mDequeueCondition
.signal();
72 void GonkNativeWindow::init()
74 // Initialize the ANativeWindow function pointers.
75 ANativeWindow::setSwapInterval
= hook_setSwapInterval
;
76 ANativeWindow::dequeueBuffer
= hook_dequeueBuffer
;
77 ANativeWindow::cancelBuffer
= hook_cancelBuffer
;
78 ANativeWindow::lockBuffer
= hook_lockBuffer
;
79 ANativeWindow::queueBuffer
= hook_queueBuffer
;
80 ANativeWindow::query
= hook_query
;
81 ANativeWindow::perform
= hook_perform
;
87 mTimestamp
= NATIVE_WINDOW_TIMESTAMP_AUTO
;
88 mBufferCount
= MIN_BUFFER_SLOTS
;
95 int GonkNativeWindow::hook_setSwapInterval(ANativeWindow
* window
, int interval
)
97 GonkNativeWindow
* c
= getSelf(window
);
98 return c
->setSwapInterval(interval
);
101 int GonkNativeWindow::hook_dequeueBuffer(ANativeWindow
* window
,
102 ANativeWindowBuffer
** buffer
)
104 GonkNativeWindow
* c
= getSelf(window
);
105 return c
->dequeueBuffer(buffer
);
108 int GonkNativeWindow::hook_cancelBuffer(ANativeWindow
* window
,
109 ANativeWindowBuffer
* buffer
)
111 GonkNativeWindow
* c
= getSelf(window
);
112 return c
->cancelBuffer(buffer
);
115 int GonkNativeWindow::hook_lockBuffer(ANativeWindow
* window
,
116 ANativeWindowBuffer
* buffer
)
118 GonkNativeWindow
* c
= getSelf(window
);
119 return c
->lockBuffer(buffer
);
122 int GonkNativeWindow::hook_queueBuffer(ANativeWindow
* window
,
123 ANativeWindowBuffer
* buffer
)
125 GonkNativeWindow
* c
= getSelf(window
);
126 return c
->queueBuffer(buffer
);
129 int GonkNativeWindow::hook_query(const ANativeWindow
* window
,
130 int what
, int* value
)
132 const GonkNativeWindow
* c
= getSelf(window
);
133 return c
->query(what
, value
);
136 int GonkNativeWindow::hook_perform(ANativeWindow
* window
, int operation
, ...)
139 va_start(args
, operation
);
140 GonkNativeWindow
* c
= getSelf(window
);
141 return c
->perform(operation
, args
);
144 void GonkNativeWindow::freeAllBuffersLocked(nsTArray
<SurfaceDescriptor
>& freeList
)
146 CNW_LOGD("freeAllBuffersLocked: from generation %d", mGeneration
);
149 for (int i
= 0; i
< NUM_BUFFER_SLOTS
; ++i
) {
150 if (mSlots
[i
].mGraphicBuffer
!= NULL
) {
151 // Don't try to destroy the gralloc buffer if it is still in the
152 // video stream awaiting rendering.
153 if (mSlots
[i
].mBufferState
!= BufferSlot::RENDERING
) {
154 SurfaceDescriptor
* desc
= freeList
.AppendElement();
155 *desc
= mSlots
[i
].mSurfaceDescriptor
;
157 mSlots
[i
].mGraphicBuffer
= NULL
;
158 mSlots
[i
].mBufferState
= BufferSlot::FREE
;
159 mSlots
[i
].mFrameNumber
= 0;
164 void GonkNativeWindow::releaseBufferFreeListUnlocked(nsTArray
<SurfaceDescriptor
>& freeList
)
166 // This function MUST ONLY be called with mMutex unlocked; else there
167 // is a risk of deadlock with the ImageBridge thread.
169 CNW_LOGD("releaseBufferFreeListUnlocked: E");
170 ImageBridgeChild
*ibc
= ImageBridgeChild::GetSingleton();
172 for (uint32_t i
= 0; i
< freeList
.Length(); ++i
) {
173 ibc
->DeallocSurfaceDescriptorGralloc(freeList
[i
]);
177 CNW_LOGD("releaseBufferFreeListUnlocked: X");
180 void GonkNativeWindow::clearRenderingStateBuffersLocked()
184 for (int i
= 0; i
< NUM_BUFFER_SLOTS
; ++i
) {
185 if (mSlots
[i
].mGraphicBuffer
!= NULL
) {
186 // Don't try to destroy the gralloc buffer if it is still in the
187 // video stream awaiting rendering.
188 if (mSlots
[i
].mBufferState
== BufferSlot::RENDERING
) {
189 mSlots
[i
].mGraphicBuffer
= NULL
;
190 mSlots
[i
].mBufferState
= BufferSlot::FREE
;
191 mSlots
[i
].mFrameNumber
= 0;
197 int GonkNativeWindow::setBufferCount(int bufferCount
)
199 CNW_LOGD("setBufferCount: count=%d", bufferCount
);
200 nsAutoTArray
<SurfaceDescriptor
, NUM_BUFFER_SLOTS
> freeList
;
203 Mutex::Autolock
lock(mMutex
);
206 CNW_LOGE("setBufferCount: GonkNativeWindow has been abandoned!");
210 if (bufferCount
> NUM_BUFFER_SLOTS
) {
211 CNW_LOGE("setBufferCount: bufferCount larger than slots available");
215 if (bufferCount
< MIN_BUFFER_SLOTS
) {
216 CNW_LOGE("setBufferCount: requested buffer count (%d) is less than "
217 "minimum (%d)", bufferCount
, MIN_BUFFER_SLOTS
);
221 // Error out if the user has dequeued buffers.
222 for (int i
=0 ; i
<mBufferCount
; i
++) {
223 if (mSlots
[i
].mBufferState
== BufferSlot::DEQUEUED
) {
224 CNW_LOGE("setBufferCount: client owns some buffers");
229 if (bufferCount
>= mBufferCount
) {
230 mBufferCount
= bufferCount
;
231 //clear only buffers in RENDERING state.
232 clearRenderingStateBuffersLocked();
233 mDequeueCondition
.signal();
237 // reducing the number of buffers
238 // here we're guaranteed that the client doesn't have dequeued buffers
239 // and will release all of its buffer references.
240 freeAllBuffersLocked(freeList
);
241 mBufferCount
= bufferCount
;
242 mDequeueCondition
.signal();
245 releaseBufferFreeListUnlocked(freeList
);
249 int GonkNativeWindow::dequeueBuffer(android_native_buffer_t
** buffer
)
251 uint32_t defaultWidth
;
252 uint32_t defaultHeight
;
253 uint32_t pixelFormat
;
257 int buf
= INVALID_BUFFER_SLOT
;
258 SurfaceDescriptor descOld
;
261 Mutex::Autolock
lock(mMutex
);
262 generation
= mGeneration
;
265 int dequeuedCount
= 0;
266 bool tryAgain
= true;
268 CNW_LOGD("dequeueBuffer: E");
271 CNW_LOGE("dequeueBuffer: GonkNativeWindow has been abandoned!");
274 // look for a free buffer to give to the client
275 found
= INVALID_BUFFER_SLOT
;
277 for (int i
= 0; i
< mBufferCount
; i
++) {
278 const int state
= mSlots
[i
].mBufferState
;
279 if (state
== BufferSlot::DEQUEUED
) {
282 else if (state
== BufferSlot::FREE
) {
283 /* We return the oldest of the free buffers to avoid
284 * stalling the producer if possible. This is because
285 * the consumer may still have pending reads of the
289 mSlots
[i
].mFrameNumber
< mSlots
[found
].mFrameNumber
) {
295 // we're in synchronous mode and didn't find a buffer, we need to
296 // wait for some buffers to be consumed
297 tryAgain
= (found
== INVALID_BUFFER_SLOT
);
299 CNW_LOGD("dequeueBuffer: Try again");
300 mDequeueCondition
.wait(mMutex
);
301 CNW_LOGD("dequeueBuffer: Now");
305 if (found
== INVALID_BUFFER_SLOT
) {
306 // This should not happen.
307 CNW_LOGE("dequeueBuffer: no available buffer slots");
313 // buffer is now in DEQUEUED
314 mSlots
[buf
].mBufferState
= BufferSlot::DEQUEUED
;
316 const sp
<GraphicBuffer
>& gbuf(mSlots
[buf
].mGraphicBuffer
);
317 alloc
= (gbuf
== NULL
);
319 ((uint32_t(gbuf
->width
) != mDefaultWidth
) ||
320 (uint32_t(gbuf
->height
) != mDefaultHeight
) ||
321 (uint32_t(gbuf
->format
) != mPixelFormat
) ||
322 ((uint32_t(gbuf
->usage
) & mUsage
) != mUsage
))) {
324 descOld
= mSlots
[buf
].mSurfaceDescriptor
;
328 // get local copies for graphics buffer allocations
329 defaultWidth
= mDefaultWidth
;
330 defaultHeight
= mDefaultHeight
;
331 pixelFormat
= mPixelFormat
;
336 // At this point, the buffer is now marked DEQUEUED, and no one else
337 // should touch it, except for freeAllBuffersLocked(); we handle that
338 // after trying to create the surface descriptor below.
340 // So we don't need mMutex locked, which would otherwise run the risk
341 // of a deadlock on calling AllocSurfaceDescriptorGralloc().
343 SurfaceDescriptor desc
;
344 ImageBridgeChild
* ibc
;
345 sp
<GraphicBuffer
> graphicBuffer
;
348 ibc
= ImageBridgeChild::GetSingleton();
349 CNW_LOGD("dequeueBuffer: about to alloc surface descriptor");
350 ibc
->AllocSurfaceDescriptorGralloc(gfxIntSize(defaultWidth
, defaultHeight
),
354 // We can only use a gralloc buffer here. If we didn't get
355 // one back, something went wrong.
356 CNW_LOGD("dequeueBuffer: got surface descriptor");
357 if (SurfaceDescriptor::TSurfaceDescriptorGralloc
!= desc
.type()) {
358 MOZ_ASSERT(SurfaceDescriptor::T__None
== desc
.type());
359 CNW_LOGE("dequeueBuffer: failed to alloc gralloc buffer");
362 graphicBuffer
= GrallocBufferActor::GetFrom(desc
.get_SurfaceDescriptorGralloc());
363 error
= graphicBuffer
->initCheck();
364 if (error
!= NO_ERROR
) {
365 CNW_LOGE("dequeueBuffer: createGraphicBuffer failed with error %d", error
);
372 Mutex::Autolock
lock(mMutex
);
373 if (generation
== mGeneration
) {
375 mSlots
[buf
].mGraphicBuffer
= graphicBuffer
;
376 mSlots
[buf
].mSurfaceDescriptor
= desc
;
377 mSlots
[buf
].mSurfaceDescriptor
.get_SurfaceDescriptorGralloc().external() = true;
379 *buffer
= mSlots
[buf
].mGraphicBuffer
.get();
381 CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf
,
382 mSlots
[buf
].mGraphicBuffer
->handle
);
389 if (alloc
&& IsSurfaceDescriptorValid(descOld
)) {
390 ibc
->DeallocSurfaceDescriptorGralloc(descOld
);
393 if (alloc
&& tooOld
) {
394 ibc
->DeallocSurfaceDescriptorGralloc(desc
);
397 CNW_LOGD("dequeueBuffer: X");
401 int GonkNativeWindow::getSlotFromBufferLocked(
402 android_native_buffer_t
* buffer
) const
404 if (buffer
== NULL
) {
405 CNW_LOGE("getSlotFromBufferLocked: encountered NULL buffer");
409 for (int i
= 0; i
< NUM_BUFFER_SLOTS
; i
++) {
410 if (mSlots
[i
].mGraphicBuffer
!= NULL
&& mSlots
[i
].mGraphicBuffer
->handle
== buffer
->handle
) {
414 CNW_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer
->handle
);
418 mozilla::layers::SurfaceDescriptor
*
419 GonkNativeWindow::getSurfaceDescriptorFromBuffer(ANativeWindowBuffer
* buffer
)
421 int buf
= getSlotFromBufferLocked(buffer
);
422 if (buf
< 0 || buf
>= mBufferCount
||
423 mSlots
[buf
].mBufferState
!= BufferSlot::DEQUEUED
) {
427 return &mSlots
[buf
].mSurfaceDescriptor
;
430 int GonkNativeWindow::queueBuffer(ANativeWindowBuffer
* buffer
)
433 Mutex::Autolock
lock(mMutex
);
434 CNW_LOGD("queueBuffer: E");
437 CNW_LOGE("queueBuffer: GonkNativeWindow has been abandoned!");
441 int buf
= getSlotFromBufferLocked(buffer
);
443 if (buf
< 0 || buf
>= mBufferCount
) {
444 CNW_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
447 } else if (mSlots
[buf
].mBufferState
!= BufferSlot::DEQUEUED
) {
448 CNW_LOGE("queueBuffer: slot %d is not owned by the client "
449 "(state=%d)", buf
, mSlots
[buf
].mBufferState
);
454 if (mTimestamp
== NATIVE_WINDOW_TIMESTAMP_AUTO
) {
455 timestamp
= systemTime(SYSTEM_TIME_MONOTONIC
);
457 timestamp
= mTimestamp
;
460 mSlots
[buf
].mBufferState
= BufferSlot::QUEUED
;
461 mSlots
[buf
].mTimestamp
= timestamp
;
463 mSlots
[buf
].mFrameNumber
= mFrameCounter
;
465 mDequeueCondition
.signal();
468 // OnNewFrame might call lockCurrentBuffer so we must release the
470 if (mNewFrameCallback
) {
471 mNewFrameCallback
->OnNewFrame();
473 CNW_LOGD("queueBuffer: X");
478 already_AddRefed
<GraphicBufferLocked
>
479 GonkNativeWindow::getCurrentBuffer()
481 CNW_LOGD("GonkNativeWindow::getCurrentBuffer");
482 Mutex::Autolock
lock(mMutex
);
485 CNW_LOGE("getCurrentBuffer: GonkNativeWindow has been abandoned!");
490 for (int i
= 0; i
< mBufferCount
; i
++) {
491 const int state
= mSlots
[i
].mBufferState
;
492 if (state
== BufferSlot::QUEUED
) {
494 mSlots
[i
].mFrameNumber
< mSlots
[found
].mFrameNumber
) {
501 mDequeueCondition
.signal();
505 mSlots
[found
].mBufferState
= BufferSlot::RENDERING
;
507 nsRefPtr
<GraphicBufferLocked
> ret
=
508 new CameraGraphicBuffer(this, found
, mGeneration
, mSlots
[found
].mSurfaceDescriptor
);
509 mDequeueCondition
.signal();
514 GonkNativeWindow::returnBuffer(uint32_t aIndex
, uint32_t aGeneration
)
516 CNW_LOGD("GonkNativeWindow::returnBuffer: slot=%d (generation=%d)", aIndex
, aGeneration
);
517 Mutex::Autolock
lock(mMutex
);
520 CNW_LOGD("returnBuffer: GonkNativeWindow has been abandoned!");
524 if (aGeneration
!= mGeneration
) {
525 CNW_LOGD("returnBuffer: buffer is from generation %d (current is %d)",
526 aGeneration
, mGeneration
);
529 if (aIndex
>= mBufferCount
) {
530 CNW_LOGE("returnBuffer: slot index out of range [0, %d]: %d",
531 mBufferCount
, aIndex
);
534 if (mSlots
[aIndex
].mBufferState
!= BufferSlot::RENDERING
) {
535 CNW_LOGE("returnBuffer: slot %d is not owned by the compositor (state=%d)",
536 aIndex
, mSlots
[aIndex
].mBufferState
);
540 mSlots
[aIndex
].mBufferState
= BufferSlot::FREE
;
541 mDequeueCondition
.signal();
545 int GonkNativeWindow::lockBuffer(ANativeWindowBuffer
* buffer
)
547 CNW_LOGD("GonkNativeWindow::lockBuffer");
548 Mutex::Autolock
lock(mMutex
);
551 CNW_LOGE("lockBuffer: GonkNativeWindow has been abandoned!");
557 int GonkNativeWindow::cancelBuffer(ANativeWindowBuffer
* buffer
)
559 Mutex::Autolock
lock(mMutex
);
562 CNW_LOGD("cancelBuffer: GonkNativeWindow has been abandoned!");
565 int buf
= getSlotFromBufferLocked(buffer
);
567 CNW_LOGD("cancelBuffer: slot=%d", buf
);
568 if (buf
< 0 || buf
>= mBufferCount
) {
569 CNW_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
572 } else if (mSlots
[buf
].mBufferState
!= BufferSlot::DEQUEUED
) {
573 CNW_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
574 buf
, mSlots
[buf
].mBufferState
);
577 mSlots
[buf
].mBufferState
= BufferSlot::FREE
;
578 mSlots
[buf
].mFrameNumber
= 0;
579 mDequeueCondition
.signal();
583 int GonkNativeWindow::perform(int operation
, va_list args
)
586 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
:
587 case NATIVE_WINDOW_SET_BUFFERS_SIZE
:
588 case NATIVE_WINDOW_SET_SCALING_MODE
:
589 case NATIVE_WINDOW_SET_CROP
:
590 case NATIVE_WINDOW_CONNECT
:
591 case NATIVE_WINDOW_DISCONNECT
:
592 // deprecated. must return NO_ERROR.
594 case NATIVE_WINDOW_SET_USAGE
:
595 return dispatchSetUsage(args
);
596 case NATIVE_WINDOW_SET_BUFFER_COUNT
:
597 return dispatchSetBufferCount(args
);
598 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
:
599 return dispatchSetBuffersGeometry(args
);
600 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
:
601 return dispatchSetBuffersTimestamp(args
);
602 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS
:
603 return dispatchSetBuffersDimensions(args
);
604 case NATIVE_WINDOW_SET_BUFFERS_FORMAT
:
605 return dispatchSetBuffersFormat(args
);
606 case NATIVE_WINDOW_LOCK
:
607 case NATIVE_WINDOW_UNLOCK_AND_POST
:
608 case NATIVE_WINDOW_API_CONNECT
:
609 case NATIVE_WINDOW_API_DISCONNECT
:
611 NS_WARNING("Unsupported operation");
612 return INVALID_OPERATION
;
616 int GonkNativeWindow::query(int what
, int* outValue
) const
618 Mutex::Autolock
lock(mMutex
);
621 CNW_LOGE("query: GonkNativeWindow has been abandoned!");
627 case NATIVE_WINDOW_WIDTH
:
628 value
= mDefaultWidth
;
630 case NATIVE_WINDOW_HEIGHT
:
631 value
= mDefaultHeight
;
633 case NATIVE_WINDOW_FORMAT
:
634 value
= mPixelFormat
;
636 case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS
:
637 value
= MIN_UNDEQUEUED_BUFFERS
;
646 int GonkNativeWindow::setSwapInterval(int interval
)
651 int GonkNativeWindow::dispatchSetUsage(va_list args
)
653 int usage
= va_arg(args
, int);
654 return setUsage(usage
);
657 int GonkNativeWindow::dispatchSetBufferCount(va_list args
)
659 size_t bufferCount
= va_arg(args
, size_t);
660 return setBufferCount(bufferCount
);
663 int GonkNativeWindow::dispatchSetBuffersGeometry(va_list args
)
665 int w
= va_arg(args
, int);
666 int h
= va_arg(args
, int);
667 int f
= va_arg(args
, int);
668 int err
= setBuffersDimensions(w
, h
);
672 return setBuffersFormat(f
);
675 int GonkNativeWindow::dispatchSetBuffersDimensions(va_list args
)
677 int w
= va_arg(args
, int);
678 int h
= va_arg(args
, int);
679 return setBuffersDimensions(w
, h
);
682 int GonkNativeWindow::dispatchSetBuffersFormat(va_list args
)
684 int f
= va_arg(args
, int);
685 return setBuffersFormat(f
);
688 int GonkNativeWindow::dispatchSetBuffersTimestamp(va_list args
)
690 int64_t timestamp
= va_arg(args
, int64_t);
691 return setBuffersTimestamp(timestamp
);
694 int GonkNativeWindow::setUsage(uint32_t reqUsage
)
696 CNW_LOGD("GonkNativeWindow::setUsage");
697 Mutex::Autolock
lock(mMutex
);
700 CNW_LOGE("setUsage: GonkNativeWindow has been abandoned!");
707 int GonkNativeWindow::setBuffersDimensions(int w
, int h
)
709 CNW_LOGD("GonkNativeWindow::setBuffersDimensions");
710 Mutex::Autolock
lock(mMutex
);
713 CNW_LOGE("setBuffersDimensions: GonkNativeWindow has been abandoned!");
720 if ((w
&& !h
) || (!w
&& h
))
729 int GonkNativeWindow::setBuffersFormat(int format
)
731 CNW_LOGD("GonkNativeWindow::setBuffersFormat");
732 Mutex::Autolock
lock(mMutex
);
735 CNW_LOGE("setBuffersFormat: GonkNativeWindow has been abandoned!");
742 mPixelFormat
= format
;
747 int GonkNativeWindow::setBuffersTimestamp(int64_t timestamp
)
749 CNW_LOGD("GonkNativeWindow::setBuffersTimestamp");
750 Mutex::Autolock
lock(mMutex
);
753 CNW_LOGE("setBuffersTimestamp: GonkNativeWindow has been abandoned!");
757 mTimestamp
= timestamp
;