Merge changes Ic45929f3,Ic63f4f96,I1e703d36,I691f9507

* changes:
  make sure to reset the framenumber when a buffer is marked FREE
  Make ANW.setSwapInterval(0) work again
  BuffferQueue disconnect is now always asynchrnous
  BufferQueue improvements and APIs changes
This commit is contained in:
Mathias Agopian 2013-07-20 01:02:47 +00:00 committed by Android (Google) Code Review
commit bdce817047
29 changed files with 212 additions and 441 deletions

View File

@ -198,7 +198,7 @@ bool GLHelper::getShaderProgram(const char* name, GLuint* outPgm) {
bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h, bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h,
sp<GLConsumer>* glConsumer, EGLSurface* surface) { sp<GLConsumer>* glConsumer, EGLSurface* surface) {
sp<BufferQueue> bq = new BufferQueue(true, mGraphicBufferAlloc); sp<BufferQueue> bq = new BufferQueue(mGraphicBufferAlloc);
sp<GLConsumer> glc = new GLConsumer(bq, name, sp<GLConsumer> glc = new GLConsumer(bq, name,
GL_TEXTURE_EXTERNAL_OES, false); GL_TEXTURE_EXTERNAL_OES, false);
glc->setDefaultBufferSize(w, h); glc->setDefaultBufferSize(w, h);

View File

@ -51,9 +51,11 @@ class BufferItemConsumer: public ConsumerBase
// the consumer usage flags passed to the graphics allocator. The // the consumer usage flags passed to the graphics allocator. The
// bufferCount parameter specifies how many buffers can be locked for user // bufferCount parameter specifies how many buffers can be locked for user
// access at the same time. // access at the same time.
// controlledByApp tells whether this consumer is controlled by the
// application.
BufferItemConsumer(const sp<BufferQueue>& bq, uint32_t consumerUsage, BufferItemConsumer(const sp<BufferQueue>& bq, uint32_t consumerUsage,
int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS, int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS,
bool synchronousMode = false); bool controlledByApp = false);
virtual ~BufferItemConsumer(); virtual ~BufferItemConsumer();

View File

@ -97,11 +97,9 @@ public:
// BufferQueue manages a pool of gralloc memory slots to be used by // BufferQueue manages a pool of gralloc memory slots to be used by
// producers and consumers. allowSynchronousMode specifies whether or not // producers and consumers. allocator is used to allocate all the
// synchronous mode can be enabled by the producer. allocator is used to // needed gralloc buffers.
// allocate all the needed gralloc buffers. BufferQueue(const sp<IGraphicBufferAlloc>& allocator = NULL);
BufferQueue(bool allowSynchronousMode = true,
const sp<IGraphicBufferAlloc>& allocator = NULL);
virtual ~BufferQueue(); virtual ~BufferQueue();
// Query native window attributes. The "what" values are enumerated in // Query native window attributes. The "what" values are enumerated in
@ -169,7 +167,7 @@ public:
// //
// In both cases, the producer will need to call requestBuffer to get a // In both cases, the producer will need to call requestBuffer to get a
// GraphicBuffer handle for the returned slot. // GraphicBuffer handle for the returned slot.
virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
uint32_t width, uint32_t height, uint32_t format, uint32_t usage); uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
// queueBuffer returns a filled buffer to the BufferQueue. // queueBuffer returns a filled buffer to the BufferQueue.
@ -197,15 +195,6 @@ public:
// will usually be the one obtained from dequeueBuffer. // will usually be the one obtained from dequeueBuffer.
virtual void cancelBuffer(int buf, const sp<Fence>& fence); virtual void cancelBuffer(int buf, const sp<Fence>& fence);
// setSynchronousMode sets whether dequeueBuffer is synchronous or
// asynchronous. In synchronous mode, dequeueBuffer blocks until
// a buffer is available, the currently bound buffer can be dequeued and
// queued buffers will be acquired in order. In asynchronous mode,
// a queued buffer may be replaced by a subsequently queued buffer.
//
// The default mode is asynchronous.
virtual status_t setSynchronousMode(bool enabled);
// connect attempts to connect a producer API to the BufferQueue. This // connect attempts to connect a producer API to the BufferQueue. This
// must be called before any other IGraphicBufferProducer methods are // must be called before any other IGraphicBufferProducer methods are
// called except for getAllocator. A consumer must already be connected. // called except for getAllocator. A consumer must already be connected.
@ -215,7 +204,7 @@ public:
// it's still connected to a producer). // it's still connected to a producer).
// //
// APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU). // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU).
virtual status_t connect(int api, QueueBufferOutput* output); virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output);
// disconnect attempts to disconnect a producer API from the BufferQueue. // disconnect attempts to disconnect a producer API from the BufferQueue.
// Calling this method will cause any subsequent calls to other // Calling this method will cause any subsequent calls to other
@ -234,13 +223,13 @@ public:
// public facing structure for BufferSlot // public facing structure for BufferSlot
struct BufferItem { struct BufferItem {
BufferItem() BufferItem() :
:
mTransform(0), mTransform(0),
mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mTimestamp(0), mTimestamp(0),
mFrameNumber(0), mFrameNumber(0),
mBuf(INVALID_BUFFER_SLOT), mBuf(INVALID_BUFFER_SLOT),
mIsDroppable(false),
mAcquireCalled(false) { mAcquireCalled(false) {
mCrop.makeInvalid(); mCrop.makeInvalid();
} }
@ -271,6 +260,13 @@ public:
// mFence is a fence that will signal when the buffer is idle. // mFence is a fence that will signal when the buffer is idle.
sp<Fence> mFence; sp<Fence> mFence;
// mIsDroppable whether this buffer was queued with the
// property that it can be replaced by a new buffer for the purpose of
// making sure dequeueBuffer() won't block.
// i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer
// was queued.
bool mIsDroppable;
// Indicates whether this buffer has been seen by a consumer yet // Indicates whether this buffer has been seen by a consumer yet
bool mAcquireCalled; bool mAcquireCalled;
}; };
@ -312,9 +308,11 @@ public:
// consumer may be connected, and when that consumer disconnects the // consumer may be connected, and when that consumer disconnects the
// BufferQueue is placed into the "abandoned" state, causing most // BufferQueue is placed into the "abandoned" state, causing most
// interactions with the BufferQueue by the producer to fail. // interactions with the BufferQueue by the producer to fail.
// controlledByApp indicates whether the consumer is controlled by
// the application.
// //
// consumer may not be NULL. // consumer may not be NULL.
status_t consumerConnect(const sp<ConsumerListener>& consumer); status_t consumerConnect(const sp<ConsumerListener>& consumer, bool controlledByApp);
// consumerDisconnect disconnects a consumer from the BufferQueue. All // consumerDisconnect disconnects a consumer from the BufferQueue. All
// buffers will be freed and the BufferQueue is placed in the "abandoned" // buffers will be freed and the BufferQueue is placed in the "abandoned"
@ -347,10 +345,6 @@ public:
// fail if a producer is connected to the BufferQueue. // fail if a producer is connected to the BufferQueue.
status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
// isSynchronousMode returns whether the BufferQueue is currently in
// synchronous mode.
bool isSynchronousMode() const;
// setConsumerName sets the name used in logging // setConsumerName sets the name used in logging
void setConsumerName(const String8& name); void setConsumerName(const String8& name);
@ -379,43 +373,35 @@ private:
// all slots. // all slots.
void freeAllBuffersLocked(); void freeAllBuffersLocked();
// drainQueueLocked waits for the buffer queue to empty if we're in
// synchronous mode, or returns immediately otherwise. It returns NO_INIT
// if the BufferQueue is abandoned (consumer disconnected) or disconnected
// (producer disconnected) during the call.
status_t drainQueueLocked();
// drainQueueAndFreeBuffersLocked drains the buffer queue if we're in
// synchronous mode and free all buffers. In asynchronous mode, all buffers
// are freed except the currently queued buffer (if it exists).
status_t drainQueueAndFreeBuffersLocked();
// setDefaultMaxBufferCountLocked sets the maximum number of buffer slots // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots
// that will be used if the producer does not override the buffer slot // that will be used if the producer does not override the buffer slot
// count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
// The initial default is 2. // The initial default is 2.
status_t setDefaultMaxBufferCountLocked(int count); status_t setDefaultMaxBufferCountLocked(int count);
// getMinUndequeuedBufferCount returns the minimum number of buffers
// that must remain in a state other than DEQUEUED.
// The async parameter tells whether we're in asynchronous mode.
int getMinUndequeuedBufferCount(bool async) const;
// getMinBufferCountLocked returns the minimum number of buffers allowed // getMinBufferCountLocked returns the minimum number of buffers allowed
// given the current BufferQueue state. // given the current BufferQueue state.
int getMinMaxBufferCountLocked() const; // The async parameter tells whether we're in asynchronous mode.
int getMinMaxBufferCountLocked(bool async) const;
// getMinUndequeuedBufferCountLocked returns the minimum number of buffers
// that must remain in a state other than DEQUEUED.
int getMinUndequeuedBufferCountLocked() const;
// getMaxBufferCountLocked returns the maximum number of buffers that can // getMaxBufferCountLocked returns the maximum number of buffers that can
// be allocated at once. This value depends upon the following member // be allocated at once. This value depends upon the following member
// variables: // variables:
// //
// mSynchronousMode // mDequeueBufferCannotBlock
// mMaxAcquiredBufferCount // mMaxAcquiredBufferCount
// mDefaultMaxBufferCount // mDefaultMaxBufferCount
// mOverrideMaxBufferCount // mOverrideMaxBufferCount
// async parameter
// //
// Any time one of these member variables is changed while a producer is // Any time one of these member variables is changed while a producer is
// connected, mDequeueCondition must be broadcast. // connected, mDequeueCondition must be broadcast.
int getMaxBufferCountLocked() const; int getMaxBufferCountLocked(bool async) const;
// stillTracking returns true iff the buffer item is still being tracked // stillTracking returns true iff the buffer item is still being tracked
// in one of the slots. // in one of the slots.
@ -568,12 +554,14 @@ private:
// to NULL and is written by consumerConnect and consumerDisconnect. // to NULL and is written by consumerConnect and consumerDisconnect.
sp<ConsumerListener> mConsumerListener; sp<ConsumerListener> mConsumerListener;
// mSynchronousMode whether we're in synchronous mode or not // mConsumerControlledByApp whether the connected consumer is controlled by the
bool mSynchronousMode; // application.
bool mConsumerControlledByApp;
// mAllowSynchronousMode whether we allow synchronous mode or not. Set // mDequeueBufferCannotBlock whether dequeueBuffer() isn't allowed to block.
// when the BufferQueue is created (by the consumer). // this flag is set durring connect() when both consumer and producer are controlled
const bool mAllowSynchronousMode; // by the application.
bool mDequeueBufferCannotBlock;
// mConnectedApi indicates the producer API that is currently connected // mConnectedApi indicates the producer API that is currently connected
// to this BufferQueue. It defaults to NO_CONNECTED_API (= 0), and gets // to this BufferQueue. It defaults to NO_CONNECTED_API (= 0), and gets

View File

@ -87,7 +87,9 @@ protected:
// ConsumerBase constructs a new ConsumerBase object to consume image // ConsumerBase constructs a new ConsumerBase object to consume image
// buffers from the given BufferQueue. // buffers from the given BufferQueue.
ConsumerBase(const sp<BufferQueue> &bufferQueue); // The controlledByApp flag indicates that this consumer is under the application's
// control.
ConsumerBase(const sp<BufferQueue> &bufferQueue, bool controlledByApp = false);
// onLastStrongRef gets called by RefBase just before the dtor of the most // onLastStrongRef gets called by RefBase just before the dtor of the most
// derived class. It is used to clean up the buffers so that ConsumerBase // derived class. It is used to clean up the buffers so that ConsumerBase

View File

@ -67,7 +67,7 @@ class CpuConsumer : public ConsumerBase
// Create a new CPU consumer. The maxLockedBuffers parameter specifies // Create a new CPU consumer. The maxLockedBuffers parameter specifies
// how many buffers can be locked for user access at the same time. // how many buffers can be locked for user access at the same time.
CpuConsumer(const sp<BufferQueue>& bq, CpuConsumer(const sp<BufferQueue>& bq,
uint32_t maxLockedBuffers, bool synchronousMode = true); uint32_t maxLockedBuffers, bool controlledByApp = false);
virtual ~CpuConsumer(); virtual ~CpuConsumer();

View File

@ -1,46 +0,0 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_GUI_DUMMYCONSUMER_H
#define ANDROID_GUI_DUMMYCONSUMER_H
#include <gui/BufferQueue.h>
namespace android {
// ----------------------------------------------------------------------------
// The DummyConsumer does not keep a reference to BufferQueue
// unlike GLConsumer. This prevents a circular reference from
// forming without having to use a ProxyConsumerListener
class DummyConsumer : public BufferQueue::ConsumerListener {
public:
DummyConsumer();
virtual ~DummyConsumer();
protected:
// Implementation of the BufferQueue::ConsumerListener interface. These
// calls are used to notify the GLConsumer of asynchronous events in the
// BufferQueue.
virtual void onFrameAvailable();
virtual void onBuffersReleased();
};
// ----------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_GUI_DUMMYCONSUMER_H

View File

@ -87,7 +87,7 @@ public:
// requirement that either of these methods be called. // requirement that either of these methods be called.
GLConsumer(const sp<BufferQueue>& bq, GLConsumer(const sp<BufferQueue>& bq,
GLuint tex, GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, GLuint tex, GLenum texTarget = GL_TEXTURE_EXTERNAL_OES,
bool useFenceSync = true); bool useFenceSync = true, bool isControlledByApp = false);
// updateTexImage acquires the most recently queued buffer, and sets the // updateTexImage acquires the most recently queued buffer, and sets the
// image contents of the target texture to it. // image contents of the target texture to it.
@ -177,10 +177,6 @@ public:
// current texture buffer. // current texture buffer.
status_t doGLFenceWait() const; status_t doGLFenceWait() const;
// isSynchronousMode returns whether the GLConsumer is currently in
// synchronous mode.
bool isSynchronousMode() const;
// set the name of the GLConsumer that will be used to identify it in // set the name of the GLConsumer that will be used to identify it in
// log messages. // log messages.
void setName(const String8& name); void setName(const String8& name);
@ -190,7 +186,6 @@ public:
status_t setDefaultBufferFormat(uint32_t defaultFormat); status_t setDefaultBufferFormat(uint32_t defaultFormat);
status_t setConsumerUsageBits(uint32_t usage); status_t setConsumerUsageBits(uint32_t usage);
status_t setTransformHint(uint32_t hint); status_t setTransformHint(uint32_t hint);
virtual status_t setSynchronousMode(bool enabled);
// getBufferQueue returns the BufferQueue object to which this // getBufferQueue returns the BufferQueue object to which this
// GLConsumer is connected. // GLConsumer is connected.

View File

@ -84,7 +84,10 @@ public:
// the buffer. The contents of the buffer must not be overwritten until the // the buffer. The contents of the buffer must not be overwritten until the
// fence signals. If the fence is NULL, the buffer may be written // fence signals. If the fence is NULL, the buffer may be written
// immediately. // immediately.
virtual status_t dequeueBuffer(int *slot, sp<Fence>* fence, //
// The async parameter sets whether we're in asynchrnous mode for this
// deququeBuffer() call.
virtual status_t dequeueBuffer(int *slot, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0; uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
// queueBuffer indicates that the client has finished filling in the // queueBuffer indicates that the client has finished filling in the
@ -96,6 +99,8 @@ public:
// must be monotonically increasing. Its other properties (zero point, etc) // must be monotonically increasing. Its other properties (zero point, etc)
// are client-dependent, and should be documented by the client. // are client-dependent, and should be documented by the client.
// //
// The async parameter sets whether we're queuing a buffer in asynchronous mode.
//
// outWidth, outHeight and outTransform are filled with the default width // outWidth, outHeight and outTransform are filled with the default width
// and height of the window and current transform applied to buffers, // and height of the window and current transform applied to buffers,
// respectively. // respectively.
@ -103,17 +108,18 @@ public:
struct QueueBufferInput : public Flattenable { struct QueueBufferInput : public Flattenable {
inline QueueBufferInput(const Parcel& parcel); inline QueueBufferInput(const Parcel& parcel);
inline QueueBufferInput(int64_t timestamp, inline QueueBufferInput(int64_t timestamp,
const Rect& crop, int scalingMode, uint32_t transform, const Rect& crop, int scalingMode, uint32_t transform, bool async,
sp<Fence> fence) const sp<Fence>& fence)
: timestamp(timestamp), crop(crop), scalingMode(scalingMode), : timestamp(timestamp), crop(crop), scalingMode(scalingMode),
transform(transform), fence(fence) { } transform(transform), async(async), fence(fence) { }
inline void deflate(int64_t* outTimestamp, Rect* outCrop, inline void deflate(int64_t* outTimestamp, Rect* outCrop,
int* outScalingMode, uint32_t* outTransform, int* outScalingMode, uint32_t* outTransform, bool* outAsync,
sp<Fence>* outFence) const { sp<Fence>* outFence) const {
*outTimestamp = timestamp; *outTimestamp = timestamp;
*outCrop = crop; *outCrop = crop;
*outScalingMode = scalingMode; *outScalingMode = scalingMode;
*outTransform = transform; *outTransform = transform;
*outAsync = bool(async);
*outFence = fence; *outFence = fence;
} }
@ -130,6 +136,7 @@ public:
Rect crop; Rect crop;
int scalingMode; int scalingMode;
uint32_t transform; uint32_t transform;
int async;
sp<Fence> fence; sp<Fence> fence;
}; };
@ -171,13 +178,6 @@ public:
// 'what' tokens allowed are that of android_natives.h // 'what' tokens allowed are that of android_natives.h
virtual int query(int what, int* value) = 0; virtual int query(int what, int* value) = 0;
// setSynchronousMode set whether dequeueBuffer is synchronous or
// asynchronous. In synchronous mode, dequeueBuffer blocks until
// a buffer is available, the currently bound buffer can be dequeued and
// queued buffers will be retired in order.
// The default mode is asynchronous.
virtual status_t setSynchronousMode(bool enabled) = 0;
// connect attempts to connect a client API to the IGraphicBufferProducer. // connect attempts to connect a client API to the IGraphicBufferProducer.
// This must be called before any other IGraphicBufferProducer methods are // This must be called before any other IGraphicBufferProducer methods are
// called except for getAllocator. // called except for getAllocator.
@ -188,7 +188,7 @@ public:
// outWidth, outHeight and outTransform are filled with the default width // outWidth, outHeight and outTransform are filled with the default width
// and height of the window and current transform applied to buffers, // and height of the window and current transform applied to buffers,
// respectively. // respectively.
virtual status_t connect(int api, QueueBufferOutput* output) = 0; virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output) = 0;
// disconnect attempts to disconnect a client API from the // disconnect attempts to disconnect a client API from the
// IGraphicBufferProducer. Calling this method will cause any subsequent // IGraphicBufferProducer. Calling this method will cause any subsequent

View File

@ -61,8 +61,11 @@ public:
* However, once a Surface is connected, it'll prevent other Surfaces * However, once a Surface is connected, it'll prevent other Surfaces
* referring to the same IGraphicBufferProducer to become connected and * referring to the same IGraphicBufferProducer to become connected and
* therefore prevent them to be used as actual producers of buffers. * therefore prevent them to be used as actual producers of buffers.
*
* the controlledByApp flag indicates that this Surface (producer) is
* controlled by the application. This flag is used at connect time.
*/ */
Surface(const sp<IGraphicBufferProducer>& bufferProducer); Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false);
/* getIGraphicBufferProducer() returns the IGraphicBufferProducer this /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this
* Surface was created with. Usually it's an error to use the * Surface was created with. Usually it's an error to use the
@ -228,6 +231,14 @@ private:
// window. this is only a hint, actual transform may differ. // window. this is only a hint, actual transform may differ.
uint32_t mTransformHint; uint32_t mTransformHint;
// mProducerControlledByApp whether this buffer producer is controlled
// by the application
bool mProducerControlledByApp;
// mSwapIntervalZero set if we should drop buffers at queue() time to
// achieve an asynchronous swap interval
bool mSwapIntervalZero;
// mConsumerRunningBehind whether the consumer is running more than // mConsumerRunningBehind whether the consumer is running more than
// one buffer behind the producer. // one buffer behind the producer.
mutable bool mConsumerRunningBehind; mutable bool mConsumerRunningBehind;

View File

@ -8,7 +8,6 @@ LOCAL_SRC_FILES:= \
ConsumerBase.cpp \ ConsumerBase.cpp \
CpuConsumer.cpp \ CpuConsumer.cpp \
DisplayEventReceiver.cpp \ DisplayEventReceiver.cpp \
DummyConsumer.cpp \
GLConsumer.cpp \ GLConsumer.cpp \
GraphicBufferAlloc.cpp \ GraphicBufferAlloc.cpp \
GuiConfig.cpp \ GuiConfig.cpp \

View File

@ -30,11 +30,10 @@
namespace android { namespace android {
BufferItemConsumer::BufferItemConsumer(const sp<BufferQueue>& bq, BufferItemConsumer::BufferItemConsumer(const sp<BufferQueue>& bq,
uint32_t consumerUsage, int bufferCount, bool synchronousMode) : uint32_t consumerUsage, int bufferCount, bool controlledByApp) :
ConsumerBase(bq) ConsumerBase(bq, controlledByApp)
{ {
mBufferQueue->setConsumerUsageBits(consumerUsage); mBufferQueue->setConsumerUsageBits(consumerUsage);
mBufferQueue->setSynchronousMode(synchronousMode);
mBufferQueue->setMaxAcquiredBufferCount(bufferCount); mBufferQueue->setMaxAcquiredBufferCount(bufferCount);
} }

View File

@ -30,6 +30,7 @@
#include <utils/Log.h> #include <utils/Log.h>
#include <utils/Trace.h> #include <utils/Trace.h>
#include <utils/CallStack.h>
// Macros for including the BufferQueue name in log messages // Macros for including the BufferQueue name in log messages
#define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) #define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
@ -63,15 +64,14 @@ static const char* scalingModeName(int scalingMode) {
} }
} }
BufferQueue::BufferQueue(bool allowSynchronousMode, BufferQueue::BufferQueue(const sp<IGraphicBufferAlloc>& allocator) :
const sp<IGraphicBufferAlloc>& allocator) :
mDefaultWidth(1), mDefaultWidth(1),
mDefaultHeight(1), mDefaultHeight(1),
mMaxAcquiredBufferCount(1), mMaxAcquiredBufferCount(1),
mDefaultMaxBufferCount(2), mDefaultMaxBufferCount(2),
mOverrideMaxBufferCount(0), mOverrideMaxBufferCount(0),
mSynchronousMode(false), mConsumerControlledByApp(false),
mAllowSynchronousMode(allowSynchronousMode), mDequeueBufferCannotBlock(false),
mConnectedApi(NO_CONNECTED_API), mConnectedApi(NO_CONNECTED_API),
mAbandoned(false), mAbandoned(false),
mFrameCounter(0), mFrameCounter(0),
@ -109,11 +109,6 @@ status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) {
return NO_ERROR; return NO_ERROR;
} }
bool BufferQueue::isSynchronousMode() const {
Mutex::Autolock lock(mMutex);
return mSynchronousMode;
}
void BufferQueue::setConsumerName(const String8& name) { void BufferQueue::setConsumerName(const String8& name) {
Mutex::Autolock lock(mMutex); Mutex::Autolock lock(mMutex);
mConsumerName = name; mConsumerName = name;
@ -156,21 +151,21 @@ status_t BufferQueue::setBufferCount(int bufferCount) {
} }
// Error out if the user has dequeued buffers // Error out if the user has dequeued buffers
int maxBufferCount = getMaxBufferCountLocked(); for (int i=0 ; i<NUM_BUFFER_SLOTS; i++) {
for (int i=0 ; i<maxBufferCount; i++) {
if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
ST_LOGE("setBufferCount: client owns some buffers"); ST_LOGE("setBufferCount: client owns some buffers");
return -EINVAL; return -EINVAL;
} }
} }
const int minBufferSlots = getMinMaxBufferCountLocked();
if (bufferCount == 0) { if (bufferCount == 0) {
mOverrideMaxBufferCount = 0; mOverrideMaxBufferCount = 0;
mDequeueCondition.broadcast(); mDequeueCondition.broadcast();
return NO_ERROR; return NO_ERROR;
} }
// fine to assume async to false before we're setting the buffer count
const int minBufferSlots = getMinMaxBufferCountLocked(false);
if (bufferCount < minBufferSlots) { if (bufferCount < minBufferSlots) {
ST_LOGE("setBufferCount: requested buffer count (%d) is less than " ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
"minimum (%d)", bufferCount, minBufferSlots); "minimum (%d)", bufferCount, minBufferSlots);
@ -215,7 +210,7 @@ int BufferQueue::query(int what, int* outValue)
value = mDefaultBufferFormat; value = mDefaultBufferFormat;
break; break;
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
value = getMinUndequeuedBufferCountLocked(); value = getMinUndequeuedBufferCount(false);
break; break;
case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
value = (mQueue.size() >= 2); value = (mQueue.size() >= 2);
@ -235,15 +230,11 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
ST_LOGE("requestBuffer: BufferQueue has been abandoned!"); ST_LOGE("requestBuffer: BufferQueue has been abandoned!");
return NO_INIT; return NO_INIT;
} }
int maxBufferCount = getMaxBufferCountLocked(); if (slot < 0 || slot >= NUM_BUFFER_SLOTS) {
if (slot < 0 || maxBufferCount <= slot) {
ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d", ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
maxBufferCount, slot); NUM_BUFFER_SLOTS, slot);
return BAD_VALUE; return BAD_VALUE;
} else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
// XXX: I vaguely recall there was some reason this can be valid, but
// for the life of me I can't recall under what circumstances that's
// the case.
ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)", ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)",
slot, mSlots[slot].mBufferState); slot, mSlots[slot].mBufferState);
return BAD_VALUE; return BAD_VALUE;
@ -253,7 +244,7 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
return NO_ERROR; return NO_ERROR;
} }
status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
ATRACE_CALL(); ATRACE_CALL();
ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
@ -285,7 +276,16 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence,
return NO_INIT; return NO_INIT;
} }
const int maxBufferCount = getMaxBufferCountLocked(); const int maxBufferCount = getMaxBufferCountLocked(async);
if (async && mOverrideMaxBufferCount) {
// FIXME: some drivers are manually setting the buffer-count (which they
// shouldn't), so we do this extra test here to handle that case.
// This is TEMPORARY, until we get this fixed.
if (mOverrideMaxBufferCount < maxBufferCount) {
ST_LOGE("dequeueBuffer: async mode is invalid with buffercount override");
return BAD_VALUE;
}
}
// Free up any buffers that are in slots beyond the max buffer // Free up any buffers that are in slots beyond the max buffer
// count. // count.
@ -334,7 +334,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence,
// make sure the client is not trying to dequeue more buffers // make sure the client is not trying to dequeue more buffers
// than allowed. // than allowed.
const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1); const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
const int minUndequeuedCount = getMinUndequeuedBufferCountLocked(); const int minUndequeuedCount = getMinUndequeuedBufferCount(async);
if (newUndequeuedCount < minUndequeuedCount) { if (newUndequeuedCount < minUndequeuedCount) {
ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) " ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
"exceeded (dequeued=%d undequeudCount=%d)", "exceeded (dequeued=%d undequeudCount=%d)",
@ -348,6 +348,10 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence,
// the max buffer count to change. // the max buffer count to change.
tryAgain = found == INVALID_BUFFER_SLOT; tryAgain = found == INVALID_BUFFER_SLOT;
if (tryAgain) { if (tryAgain) {
if (mDequeueBufferCannotBlock) {
ST_LOGE("dequeueBuffer: would block! returning an error instead.");
return WOULD_BLOCK;
}
mDequeueCondition.wait(mMutex); mDequeueCondition.wait(mMutex);
} }
} }
@ -441,38 +445,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence,
return returnFlags; return returnFlags;
} }
status_t BufferQueue::setSynchronousMode(bool enabled) {
ATRACE_CALL();
ST_LOGV("setSynchronousMode: enabled=%d", enabled);
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
ST_LOGE("setSynchronousMode: BufferQueue has been abandoned!");
return NO_INIT;
}
status_t err = OK;
if (!mAllowSynchronousMode && enabled)
return err;
if (!enabled) {
// going to asynchronous mode, drain the queue
err = drainQueueLocked();
if (err != NO_ERROR)
return err;
}
if (mSynchronousMode != enabled) {
// - if we're going to asynchronous mode, the queue is guaranteed to be
// empty here
// - if the client set the number of buffers, we're guaranteed that
// we have at least 3 (because we don't allow less)
mSynchronousMode = enabled;
mDequeueCondition.broadcast();
}
return err;
}
status_t BufferQueue::queueBuffer(int buf, status_t BufferQueue::queueBuffer(int buf,
const QueueBufferInput& input, QueueBufferOutput* output) { const QueueBufferInput& input, QueueBufferOutput* output) {
ATRACE_CALL(); ATRACE_CALL();
@ -482,9 +454,10 @@ status_t BufferQueue::queueBuffer(int buf,
uint32_t transform; uint32_t transform;
int scalingMode; int scalingMode;
int64_t timestamp; int64_t timestamp;
bool async;
sp<Fence> fence; sp<Fence> fence;
input.deflate(&timestamp, &crop, &scalingMode, &transform, &fence); input.deflate(&timestamp, &crop, &scalingMode, &transform, &async, &fence);
if (fence == NULL) { if (fence == NULL) {
ST_LOGE("queueBuffer: fence is NULL"); ST_LOGE("queueBuffer: fence is NULL");
@ -511,7 +484,17 @@ status_t BufferQueue::queueBuffer(int buf,
ST_LOGE("queueBuffer: BufferQueue has been abandoned!"); ST_LOGE("queueBuffer: BufferQueue has been abandoned!");
return NO_INIT; return NO_INIT;
} }
int maxBufferCount = getMaxBufferCountLocked();
const int maxBufferCount = getMaxBufferCountLocked(async);
if (async && mOverrideMaxBufferCount) {
// FIXME: some drivers are manually setting the buffer-count (which they
// shouldn't), so we do this extra test here to handle that case.
// This is TEMPORARY, until we get this fixed.
if (mOverrideMaxBufferCount < maxBufferCount) {
ST_LOGE("queueBuffer: async mode is invalid with buffercount override");
return BAD_VALUE;
}
}
if (buf < 0 || buf >= maxBufferCount) { if (buf < 0 || buf >= maxBufferCount) {
ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d", ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
maxBufferCount, buf); maxBufferCount, buf);
@ -557,31 +540,30 @@ status_t BufferQueue::queueBuffer(int buf,
item.mFrameNumber = mFrameCounter; item.mFrameNumber = mFrameCounter;
item.mBuf = buf; item.mBuf = buf;
item.mFence = fence; item.mFence = fence;
item.mIsDroppable = mDequeueBufferCannotBlock || async;
if (mSynchronousMode) { if (mQueue.empty()) {
// In synchronous mode we queue all buffers in a FIFO. // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and
// simply queue this buffer.
mQueue.push_back(item); mQueue.push_back(item);
// Synchronous mode always signals that an additional frame should
// be consumed.
listener = mConsumerListener; listener = mConsumerListener;
} else { } else {
// In asynchronous mode we only keep the most recent buffer. // when the queue is not empty, we need to look at the front buffer
if (mQueue.empty()) { // state and see if we need to replace it.
mQueue.push_back(item); Fifo::iterator front(mQueue.begin());
if (front->mIsDroppable) {
// Asynchronous mode only signals that a frame should be
// consumed if no previous frame was pending. If a frame were
// pending then the consumer would have already been notified.
listener = mConsumerListener;
} else {
Fifo::iterator front(mQueue.begin());
// buffer slot currently queued is marked free if still tracked // buffer slot currently queued is marked free if still tracked
if (stillTracking(front)) { if (stillTracking(front)) {
mSlots[front->mBuf].mBufferState = BufferSlot::FREE; mSlots[front->mBuf].mBufferState = BufferSlot::FREE;
// reset the frame number of the freed buffer so that it is the first in
// line to be dequeued again.
mSlots[front->mBuf].mFrameNumber = 0;
} }
// and we record the new buffer index in the queued list // and we record the new buffer in the queued list
*front = item; *front = item;
} else {
mQueue.push_back(item);
listener = mConsumerListener;
} }
} }
@ -611,10 +593,9 @@ void BufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
return; return;
} }
int maxBufferCount = getMaxBufferCountLocked(); if (buf < 0 || buf >= NUM_BUFFER_SLOTS) {
if (buf < 0 || buf >= maxBufferCount) {
ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d", ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
maxBufferCount, buf); NUM_BUFFER_SLOTS, buf);
return; return;
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
@ -630,7 +611,7 @@ void BufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
mDequeueCondition.broadcast(); mDequeueCondition.broadcast();
} }
status_t BufferQueue::connect(int api, QueueBufferOutput* output) { status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBufferOutput* output) {
ATRACE_CALL(); ATRACE_CALL();
ST_LOGV("connect: api=%d", api); ST_LOGV("connect: api=%d", api);
Mutex::Autolock lock(mMutex); Mutex::Autolock lock(mMutex);
@ -667,6 +648,7 @@ status_t BufferQueue::connect(int api, QueueBufferOutput* output) {
} }
mBufferHasBeenQueued = false; mBufferHasBeenQueued = false;
mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp;
return err; return err;
} }
@ -693,7 +675,7 @@ status_t BufferQueue::disconnect(int api) {
case NATIVE_WINDOW_API_MEDIA: case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA: case NATIVE_WINDOW_API_CAMERA:
if (mConnectedApi == api) { if (mConnectedApi == api) {
drainQueueAndFreeBuffersLocked(); freeAllBuffersLocked();
mConnectedApi = NO_CONNECTED_API; mConnectedApi = NO_CONNECTED_API;
mDequeueCondition.broadcast(); mDequeueCondition.broadcast();
listener = mConsumerListener; listener = mConsumerListener;
@ -739,12 +721,11 @@ void BufferQueue::dump(String8& result, const char* prefix) const {
fifoSize++; fifoSize++;
} }
int maxBufferCount = getMaxBufferCountLocked();
result.appendFormat( result.appendFormat(
"%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " "%s-BufferQueue mMaxAcquiredBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], "
"default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n", "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n",
prefix, maxBufferCount, mSynchronousMode, mDefaultWidth, prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, mDefaultWidth,
mDefaultHeight, mDefaultBufferFormat, mTransformHint, mDefaultHeight, mDefaultBufferFormat, mTransformHint,
fifoSize, fifo.string()); fifoSize, fifo.string());
@ -760,16 +741,25 @@ void BufferQueue::dump(String8& result, const char* prefix) const {
} }
} stateName; } stateName;
// just trim the free buffers to not spam the dump
int maxBufferCount = 0;
for (int i=NUM_BUFFER_SLOTS-1 ; i>=0 ; i--) {
const BufferSlot& slot(mSlots[i]);
if ((slot.mBufferState != BufferSlot::FREE) || (slot.mGraphicBuffer != NULL)) {
maxBufferCount = i+1;
break;
}
}
for (int i=0 ; i<maxBufferCount ; i++) { for (int i=0 ; i<maxBufferCount ; i++) {
const BufferSlot& slot(mSlots[i]); const BufferSlot& slot(mSlots[i]);
const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
result.appendFormat( result.appendFormat(
"%s%s[%02d:%p] state=%-8s", "%s%s[%02d:%p] state=%-8s",
prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, buf.get(),
slot.mGraphicBuffer.get(),
stateName(slot.mBufferState) stateName(slot.mBufferState)
); );
const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
if (buf != NULL) { if (buf != NULL) {
result.appendFormat( result.appendFormat(
", %p [%4ux%4u:%4u,%3X]", ", %p [%4ux%4u:%4u,%3X]",
@ -799,8 +789,6 @@ void BufferQueue::freeBufferLocked(int slot) {
} }
void BufferQueue::freeAllBuffersLocked() { void BufferQueue::freeAllBuffersLocked() {
ALOGD_IF(!mQueue.isEmpty(),
"freeAllBuffersLocked called with non-empty mQueue");
mBufferHasBeenQueued = false; mBufferHasBeenQueued = false;
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
freeBufferLocked(i); freeBufferLocked(i);
@ -950,7 +938,8 @@ status_t BufferQueue::releaseBuffer(
return NO_ERROR; return NO_ERROR;
} }
status_t BufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListener) { status_t BufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListener,
bool controlledByApp) {
ST_LOGV("consumerConnect"); ST_LOGV("consumerConnect");
Mutex::Autolock lock(mMutex); Mutex::Autolock lock(mMutex);
@ -964,6 +953,7 @@ status_t BufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListen
} }
mConsumerListener = consumerListener; mConsumerListener = consumerListener;
mConsumerControlledByApp = controlledByApp;
return NO_ERROR; return NO_ERROR;
} }
@ -1053,40 +1043,17 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
return NO_ERROR; return NO_ERROR;
} }
status_t BufferQueue::drainQueueLocked() { int BufferQueue::getMinUndequeuedBufferCount(bool async) const {
while (mSynchronousMode && mQueue.size() > 1) { return (mDequeueBufferCannotBlock || async) ?
mDequeueCondition.wait(mMutex); mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount;
if (mAbandoned) {
ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!");
return NO_INIT;
}
if (mConnectedApi == NO_CONNECTED_API) {
ST_LOGE("drainQueueLocked: BufferQueue is not connected!");
return NO_INIT;
}
}
return NO_ERROR;
} }
status_t BufferQueue::drainQueueAndFreeBuffersLocked() { int BufferQueue::getMinMaxBufferCountLocked(bool async) const {
status_t err = drainQueueLocked(); return getMinUndequeuedBufferCount(async) + 1;
if (err == NO_ERROR) {
freeAllBuffersLocked();
}
return err;
} }
int BufferQueue::getMinMaxBufferCountLocked() const { int BufferQueue::getMaxBufferCountLocked(bool async) const {
return getMinUndequeuedBufferCountLocked() + 1; int minMaxBufferCount = getMinMaxBufferCountLocked(async);
}
int BufferQueue::getMinUndequeuedBufferCountLocked() const {
return mSynchronousMode ? mMaxAcquiredBufferCount :
mMaxAcquiredBufferCount + 1;
}
int BufferQueue::getMaxBufferCountLocked() const {
int minMaxBufferCount = getMinMaxBufferCountLocked();
int maxBufferCount = mDefaultMaxBufferCount; int maxBufferCount = mDefaultMaxBufferCount;
if (maxBufferCount < minMaxBufferCount) { if (maxBufferCount < minMaxBufferCount) {

View File

@ -51,7 +51,7 @@ static int32_t createProcessUniqueId() {
return android_atomic_inc(&globalCounter); return android_atomic_inc(&globalCounter);
} }
ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) : ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue, bool controlledByApp) :
mAbandoned(false), mAbandoned(false),
mBufferQueue(bufferQueue) { mBufferQueue(bufferQueue) {
// Choose a name using the PID and a process-unique ID. // Choose a name using the PID and a process-unique ID.
@ -66,7 +66,7 @@ ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) :
listener = static_cast<BufferQueue::ConsumerListener*>(this); listener = static_cast<BufferQueue::ConsumerListener*>(this);
proxy = new BufferQueue::ProxyConsumerListener(listener); proxy = new BufferQueue::ProxyConsumerListener(listener);
status_t err = mBufferQueue->consumerConnect(proxy); status_t err = mBufferQueue->consumerConnect(proxy, controlledByApp);
if (err != NO_ERROR) { if (err != NO_ERROR) {
CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)", CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)",
strerror(-err), err); strerror(-err), err);

View File

@ -31,15 +31,14 @@
namespace android { namespace android {
CpuConsumer::CpuConsumer(const sp<BufferQueue>& bq, CpuConsumer::CpuConsumer(const sp<BufferQueue>& bq,
uint32_t maxLockedBuffers, bool synchronousMode) : uint32_t maxLockedBuffers, bool controlledByApp) :
ConsumerBase(bq), ConsumerBase(bq, controlledByApp),
mMaxLockedBuffers(maxLockedBuffers), mMaxLockedBuffers(maxLockedBuffers),
mCurrentLockedBuffers(0) mCurrentLockedBuffers(0)
{ {
// Create tracking entries for locked buffers // Create tracking entries for locked buffers
mAcquiredBuffers.insertAt(0, maxLockedBuffers); mAcquiredBuffers.insertAt(0, maxLockedBuffers);
mBufferQueue->setSynchronousMode(synchronousMode);
mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN); mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
mBufferQueue->setMaxAcquiredBufferCount(maxLockedBuffers); mBufferQueue->setMaxAcquiredBufferCount(maxLockedBuffers);
} }

View File

@ -1,43 +0,0 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "DummyConsumer"
// #define LOG_NDEBUG 0
#include <gui/DummyConsumer.h>
#include <utils/Log.h>
#include <utils/String8.h>
namespace android {
DummyConsumer::DummyConsumer() {
ALOGV("DummyConsumer");
}
DummyConsumer::~DummyConsumer() {
ALOGV("~DummyConsumer");
}
void DummyConsumer::onFrameAvailable() {
ALOGV("onFrameAvailable");
}
void DummyConsumer::onBuffersReleased() {
ALOGV("onBuffersReleased");
}
}; // namespace android

View File

@ -79,8 +79,8 @@ static void mtxMul(float out[16], const float a[16], const float b[16]);
GLConsumer::GLConsumer(const sp<BufferQueue>& bq, GLuint tex, GLConsumer::GLConsumer(const sp<BufferQueue>& bq, GLuint tex,
GLenum texTarget, bool useFenceSync) : GLenum texTarget, bool useFenceSync, bool isControlledByApp) :
ConsumerBase(bq), ConsumerBase(bq, isControlledByApp),
mCurrentTransform(0), mCurrentTransform(0),
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mCurrentFence(Fence::NO_FENCE), mCurrentFence(Fence::NO_FENCE),
@ -844,11 +844,6 @@ status_t GLConsumer::doGLFenceWaitLocked() const {
return NO_ERROR; return NO_ERROR;
} }
bool GLConsumer::isSynchronousMode() const {
Mutex::Autolock lock(mMutex);
return mBufferQueue->isSynchronousMode();
}
void GLConsumer::freeBufferLocked(int slotIndex) { void GLConsumer::freeBufferLocked(int slotIndex) {
ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
if (slotIndex == mCurrentTexture) { if (slotIndex == mCurrentTexture) {
@ -891,13 +886,6 @@ status_t GLConsumer::setTransformHint(uint32_t hint) {
return mBufferQueue->setTransformHint(hint); return mBufferQueue->setTransformHint(hint);
} }
// Used for refactoring BufferQueue from GLConsumer
// Should not be in final interface once users of GLConsumer are clean up.
status_t GLConsumer::setSynchronousMode(bool enabled) {
Mutex::Autolock lock(mMutex);
return mBufferQueue->setSynchronousMode(enabled);
}
void GLConsumer::dumpLocked(String8& result, const char* prefix) const void GLConsumer::dumpLocked(String8& result, const char* prefix) const
{ {
result.appendFormat( result.appendFormat(

View File

@ -37,7 +37,6 @@ enum {
QUEUE_BUFFER, QUEUE_BUFFER,
CANCEL_BUFFER, CANCEL_BUFFER,
QUERY, QUERY,
SET_SYNCHRONOUS_MODE,
CONNECT, CONNECT,
DISCONNECT, DISCONNECT,
}; };
@ -81,10 +80,11 @@ public:
return result; return result;
} }
virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
Parcel data, reply; Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(async);
data.writeInt32(w); data.writeInt32(w);
data.writeInt32(h); data.writeInt32(h);
data.writeInt32(format); data.writeInt32(format);
@ -142,22 +142,11 @@ public:
return result; return result;
} }
virtual status_t setSynchronousMode(bool enabled) { virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(enabled);
status_t result = remote()->transact(SET_SYNCHRONOUS_MODE, data, &reply);
if (result != NO_ERROR) {
return result;
}
result = reply.readInt32();
return result;
}
virtual status_t connect(int api, QueueBufferOutput* output) {
Parcel data, reply; Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(api); data.writeInt32(api);
data.writeInt32(producerControlledByApp);
status_t result = remote()->transact(CONNECT, data, &reply); status_t result = remote()->transact(CONNECT, data, &reply);
if (result != NO_ERROR) { if (result != NO_ERROR) {
return result; return result;
@ -209,13 +198,14 @@ status_t BnGraphicBufferProducer::onTransact(
} break; } break;
case DEQUEUE_BUFFER: { case DEQUEUE_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply); CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
bool async = data.readInt32();
uint32_t w = data.readInt32(); uint32_t w = data.readInt32();
uint32_t h = data.readInt32(); uint32_t h = data.readInt32();
uint32_t format = data.readInt32(); uint32_t format = data.readInt32();
uint32_t usage = data.readInt32(); uint32_t usage = data.readInt32();
int buf; int buf;
sp<Fence> fence; sp<Fence> fence;
int result = dequeueBuffer(&buf, &fence, w, h, format, usage); int result = dequeueBuffer(&buf, &fence, async, w, h, format, usage);
reply->writeInt32(buf); reply->writeInt32(buf);
reply->writeInt32(fence != NULL); reply->writeInt32(fence != NULL);
if (fence != NULL) { if (fence != NULL) {
@ -252,20 +242,14 @@ status_t BnGraphicBufferProducer::onTransact(
reply->writeInt32(res); reply->writeInt32(res);
return NO_ERROR; return NO_ERROR;
} break; } break;
case SET_SYNCHRONOUS_MODE: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
bool enabled = data.readInt32();
status_t res = setSynchronousMode(enabled);
reply->writeInt32(res);
return NO_ERROR;
} break;
case CONNECT: { case CONNECT: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply); CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
int api = data.readInt32(); int api = data.readInt32();
bool producerControlledByApp = data.readInt32();
QueueBufferOutput* const output = QueueBufferOutput* const output =
reinterpret_cast<QueueBufferOutput *>( reinterpret_cast<QueueBufferOutput *>(
reply->writeInplace(sizeof(QueueBufferOutput))); reply->writeInplace(sizeof(QueueBufferOutput)));
status_t res = connect(api, output); status_t res = connect(api, producerControlledByApp, output);
reply->writeInt32(res); reply->writeInt32(res);
return NO_ERROR; return NO_ERROR;
} break; } break;
@ -292,6 +276,7 @@ size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const
+ sizeof(crop) + sizeof(crop)
+ sizeof(scalingMode) + sizeof(scalingMode)
+ sizeof(transform) + sizeof(transform)
+ sizeof(async)
+ fence->getFlattenedSize(); + fence->getFlattenedSize();
} }
@ -309,6 +294,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten(void* buffer, size_t
memcpy(p, &crop, sizeof(crop)); p += sizeof(crop); memcpy(p, &crop, sizeof(crop)); p += sizeof(crop);
memcpy(p, &scalingMode, sizeof(scalingMode)); p += sizeof(scalingMode); memcpy(p, &scalingMode, sizeof(scalingMode)); p += sizeof(scalingMode);
memcpy(p, &transform, sizeof(transform)); p += sizeof(transform); memcpy(p, &transform, sizeof(transform)); p += sizeof(transform);
memcpy(p, &async, sizeof(async)); p += sizeof(async);
err = fence->flatten(p, size - (p - (char*)buffer), fds, count); err = fence->flatten(p, size - (p - (char*)buffer), fds, count);
return err; return err;
} }
@ -322,6 +308,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten(void const* buffer,
memcpy(&crop, p, sizeof(crop)); p += sizeof(crop); memcpy(&crop, p, sizeof(crop)); p += sizeof(crop);
memcpy(&scalingMode, p, sizeof(scalingMode)); p += sizeof(scalingMode); memcpy(&scalingMode, p, sizeof(scalingMode)); p += sizeof(scalingMode);
memcpy(&transform, p, sizeof(transform)); p += sizeof(transform); memcpy(&transform, p, sizeof(transform)); p += sizeof(transform);
memcpy(&async, p, sizeof(async)); p += sizeof(async);
fence = new Fence(); fence = new Fence();
err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count); err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count);
return err; return err;

View File

@ -37,7 +37,8 @@
namespace android { namespace android {
Surface::Surface( Surface::Surface(
const sp<IGraphicBufferProducer>& bufferProducer) const sp<IGraphicBufferProducer>& bufferProducer,
bool controlledByApp)
: mGraphicBufferProducer(bufferProducer) : mGraphicBufferProducer(bufferProducer)
{ {
// Initialize the ANativeWindow function pointers. // Initialize the ANativeWindow function pointers.
@ -71,6 +72,8 @@ Surface::Surface(
mTransformHint = 0; mTransformHint = 0;
mConsumerRunningBehind = false; mConsumerRunningBehind = false;
mConnectedToCpu = false; mConnectedToCpu = false;
mProducerControlledByApp = true;
mSwapIntervalZero = false;
} }
Surface::~Surface() { Surface::~Surface() {
@ -160,7 +163,6 @@ int Surface::setSwapInterval(int interval) {
// EGL specification states: // EGL specification states:
// interval is silently clamped to minimum and maximum implementation // interval is silently clamped to minimum and maximum implementation
// dependent values before being stored. // dependent values before being stored.
// Although we don't have to, we apply the same logic here.
if (interval < minSwapInterval) if (interval < minSwapInterval)
interval = minSwapInterval; interval = minSwapInterval;
@ -168,9 +170,9 @@ int Surface::setSwapInterval(int interval) {
if (interval > maxSwapInterval) if (interval > maxSwapInterval)
interval = maxSwapInterval; interval = maxSwapInterval;
status_t res = mGraphicBufferProducer->setSynchronousMode(interval ? true : false); mSwapIntervalZero = (interval == 0);
return res; return NO_ERROR;
} }
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int Surface::dequeueBuffer(android_native_buffer_t** buffer,
@ -182,7 +184,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer,
int reqW = mReqWidth ? mReqWidth : mUserWidth; int reqW = mReqWidth ? mReqWidth : mUserWidth;
int reqH = mReqHeight ? mReqHeight : mUserHeight; int reqH = mReqHeight ? mReqHeight : mUserHeight;
sp<Fence> fence; sp<Fence> fence;
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, mSwapIntervalZero,
reqW, reqH, mReqFormat, mReqUsage); reqW, reqH, mReqFormat, mReqUsage);
if (result < 0) { if (result < 0) {
ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)" ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)"
@ -278,7 +280,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferOutput output;
IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode, IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode,
mTransform, fence); mTransform, mSwapIntervalZero, fence);
status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
if (err != OK) { if (err != OK) {
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
@ -486,7 +488,7 @@ int Surface::connect(int api) {
ALOGV("Surface::connect"); ALOGV("Surface::connect");
Mutex::Autolock lock(mMutex); Mutex::Autolock lock(mMutex);
IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferOutput output;
int err = mGraphicBufferProducer->connect(api, &output); int err = mGraphicBufferProducer->connect(api, mProducerControlledByApp, &output);
if (err == NO_ERROR) { if (err == NO_ERROR) {
uint32_t numPendingBuffers = 0; uint32_t numPendingBuffers = 0;
output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint, output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,

View File

@ -62,21 +62,21 @@ struct DummyConsumer : public BufferQueue::ConsumerListener {
TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
sp<DummyConsumer> dc(new DummyConsumer); sp<DummyConsumer> dc(new DummyConsumer);
mBQ->consumerConnect(dc); mBQ->consumerConnect(dc, false);
IGraphicBufferProducer::QueueBufferOutput qbo; IGraphicBufferProducer::QueueBufferOutput qbo;
mBQ->connect(NATIVE_WINDOW_API_CPU, &qbo); mBQ->connect(NATIVE_WINDOW_API_CPU, false, &qbo);
mBQ->setBufferCount(4); mBQ->setBufferCount(4);
int slot; int slot;
sp<Fence> fence; sp<Fence> fence;
sp<GraphicBuffer> buf; sp<GraphicBuffer> buf;
IGraphicBufferProducer::QueueBufferInput qbi(0, Rect(0, 0, 1, 1), IGraphicBufferProducer::QueueBufferInput qbi(0, Rect(0, 0, 1, 1),
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE);
BufferQueue::BufferItem item; BufferQueue::BufferItem item;
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
mBQ->dequeueBuffer(&slot, &fence, 1, 1, 0, mBQ->dequeueBuffer(&slot, &fence, false, 1, 1, 0,
GRALLOC_USAGE_SW_READ_OFTEN)); GRALLOC_USAGE_SW_READ_OFTEN));
ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
@ -84,7 +84,7 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
} }
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
mBQ->dequeueBuffer(&slot, &fence, 1, 1, 0, mBQ->dequeueBuffer(&slot, &fence, false, 1, 1, 0,
GRALLOC_USAGE_SW_READ_OFTEN)); GRALLOC_USAGE_SW_READ_OFTEN));
ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
@ -95,7 +95,7 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) { TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) {
sp<DummyConsumer> dc(new DummyConsumer); sp<DummyConsumer> dc(new DummyConsumer);
mBQ->consumerConnect(dc); mBQ->consumerConnect(dc, false);
ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(0)); ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(0));
ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(-3)); ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(-3));
@ -106,7 +106,7 @@ TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError)
TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) { TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) {
sp<DummyConsumer> dc(new DummyConsumer); sp<DummyConsumer> dc(new DummyConsumer);
mBQ->consumerConnect(dc); mBQ->consumerConnect(dc, false);
ASSERT_EQ(OK, mBQ->setMaxAcquiredBufferCount(1)); ASSERT_EQ(OK, mBQ->setMaxAcquiredBufferCount(1));
ASSERT_EQ(OK, mBQ->setMaxAcquiredBufferCount(2)); ASSERT_EQ(OK, mBQ->setMaxAcquiredBufferCount(2));

View File

@ -338,7 +338,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) {
TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) { TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) {
android_native_buffer_t* buf[3]; android_native_buffer_t* buf[3];
ASSERT_EQ(OK, mST->setSynchronousMode(false)); ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 0));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
@ -346,7 +346,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) {
EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(OK, mST->updateTexImage());
ASSERT_EQ(OK, mST->setSynchronousMode(true)); ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
@ -361,7 +361,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) {
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) {
android_native_buffer_t* buf[3]; android_native_buffer_t* buf[3];
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
@ -382,7 +381,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) {
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) {
android_native_buffer_t* buf[3]; android_native_buffer_t* buf[3];
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
@ -403,7 +401,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) {
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) {
android_native_buffer_t* buf[3]; android_native_buffer_t* buf[3];
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
@ -429,7 +426,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) {
TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) { TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) {
android_native_buffer_t* buf[3]; android_native_buffer_t* buf[3];
android_native_buffer_t* firstBuf; android_native_buffer_t* firstBuf;
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf));
ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1)); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1));
@ -449,7 +445,6 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent)
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) {
android_native_buffer_t* buf[3]; android_native_buffer_t* buf[3];
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
// We should be able to dequeue all the buffers before we've queued mANWy. // We should be able to dequeue all the buffers before we've queued mANWy.
@ -528,7 +523,6 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) {
}; };
android_native_buffer_t* buf[3]; android_native_buffer_t* buf[3];
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
// dequeue/queue/update so we have a current buffer // dequeue/queue/update so we have a current buffer
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));

View File

@ -944,7 +944,6 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
enum { texHeight = 16 }; enum { texHeight = 16 };
enum { numFrames = 1024 }; enum { numFrames = 1024 };
ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2)); ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
texWidth, texHeight, HAL_PIXEL_FORMAT_YV12)); texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
@ -1211,10 +1210,8 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) {
sp<ANativeWindow> mANW; sp<ANativeWindow> mANW;
}; };
ASSERT_EQ(OK, mST->setSynchronousMode(true));
sp<DisconnectWaiter> dw(new DisconnectWaiter()); sp<DisconnectWaiter> dw(new DisconnectWaiter());
mST->getBufferQueue()->consumerConnect(dw); mST->getBufferQueue()->consumerConnect(dw, false);
sp<Thread> pt(new ProducerThread(mANW)); sp<Thread> pt(new ProducerThread(mANW));
@ -1237,8 +1234,6 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) {
// when it is disconnected and reconnected. Otherwise it will // when it is disconnected and reconnected. Otherwise it will
// attempt to release a buffer that it does not owned // attempt to release a buffer that it does not owned
TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) { TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) {
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_api_connect(mANW.get(), ASSERT_EQ(OK, native_window_api_connect(mANW.get(),
NATIVE_WINDOW_API_EGL)); NATIVE_WINDOW_API_EGL));
@ -1258,8 +1253,6 @@ TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) {
ASSERT_EQ(OK, native_window_api_connect(mANW.get(), ASSERT_EQ(OK, native_window_api_connect(mANW.get(),
NATIVE_WINDOW_API_EGL)); NATIVE_WINDOW_API_EGL));
ASSERT_EQ(OK, mST->setSynchronousMode(true));
EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
@ -1272,8 +1265,6 @@ TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) {
} }
TEST_F(SurfaceTextureGLTest, ScaleToWindowMode) { TEST_F(SurfaceTextureGLTest, ScaleToWindowMode) {
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_scaling_mode(mANW.get(), ASSERT_EQ(OK, native_window_set_scaling_mode(mANW.get(),
NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)); NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW));
@ -1306,8 +1297,6 @@ TEST_F(SurfaceTextureGLTest, ScaleToWindowMode) {
// the image such that it has the same aspect ratio as the // the image such that it has the same aspect ratio as the
// default buffer size // default buffer size
TEST_F(SurfaceTextureGLTest, CroppedScalingMode) { TEST_F(SurfaceTextureGLTest, CroppedScalingMode) {
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_scaling_mode(mANW.get(), ASSERT_EQ(OK, native_window_set_scaling_mode(mANW.get(),
NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)); NATIVE_WINDOW_SCALING_MODE_SCALE_CROP));
@ -1417,7 +1406,6 @@ TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
Mutex mMutex; Mutex mMutex;
}; };
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2)); ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2));
sp<Thread> pt(new ProducerThread(mANW)); sp<Thread> pt(new ProducerThread(mANW));
@ -1810,32 +1798,6 @@ TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentAfterConsumerDeathUnrefsBuffers)
EXPECT_EQ(1, buffer->getStrongCount()); EXPECT_EQ(1, buffer->getStrongCount());
} }
TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) {
// This test requires 3 buffers to run on a single thread.
mST->setDefaultMaxBufferCount(3);
ASSERT_TRUE(mST->isSynchronousMode());
for (int i = 0; i < 10; i++) {
// Produce a frame
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
mProducerEglSurface, mProducerEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
// Consume a frame
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_EQ(NO_ERROR, mST->updateTexImage());
}
ASSERT_TRUE(mST->isSynchronousMode());
}
TEST_F(SurfaceTextureGLToGLTest, TexturingFromUserSizedGLFilledBuffer) { TEST_F(SurfaceTextureGLToGLTest, TexturingFromUserSizedGLFilledBuffer) {
enum { texWidth = 64 }; enum { texWidth = 64 };
enum { texHeight = 64 }; enum { texHeight = 64 };
@ -2285,7 +2247,6 @@ TEST_F(SurfaceTextureGLThreadToGLTest,
} }
}; };
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2)); ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2));
runProducerThread(new PT()); runProducerThread(new PT());
@ -2826,7 +2787,6 @@ TEST_F(SurfaceTextureMultiContextGLTest,
TEST_F(SurfaceTextureMultiContextGLTest, TEST_F(SurfaceTextureMultiContextGLTest,
UpdateTexImageSucceedsForBufferConsumedBeforeDetach) { UpdateTexImageSucceedsForBufferConsumedBeforeDetach) {
ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2)); ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
// produce two frames and consume them both on the primary context // produce two frames and consume them both on the primary context

View File

@ -20,7 +20,6 @@
#include <EGL/egl.h> #include <EGL/egl.h>
#include <gui/Surface.h> #include <gui/Surface.h>
#include <gui/DummyConsumer.h>
namespace android { namespace android {
@ -101,9 +100,14 @@ TEST_F(EGLTest, EGLTerminateSucceedsWithRemainingObjects) {
}; };
EXPECT_TRUE(eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs)); EXPECT_TRUE(eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs));
struct DummyConsumer : public BufferQueue::ConsumerListener {
virtual void onFrameAvailable() {}
virtual void onBuffersReleased() {}
};
// Create a EGLSurface // Create a EGLSurface
sp<BufferQueue> bq = new BufferQueue(); sp<BufferQueue> bq = new BufferQueue();
bq->consumerConnect(new DummyConsumer()); bq->consumerConnect(new DummyConsumer, false);
sp<Surface> mSTC = new Surface(static_cast<sp<IGraphicBufferProducer> >( bq)); sp<Surface> mSTC = new Surface(static_cast<sp<IGraphicBufferProducer> >( bq));
sp<ANativeWindow> mANW = mSTC; sp<ANativeWindow> mANW = mSTC;

View File

@ -36,7 +36,6 @@ ifeq ($(TARGET_BOARD_PLATFORM),omap4)
endif endif
ifeq ($(TARGET_BOARD_PLATFORM),s5pc110) ifeq ($(TARGET_BOARD_PLATFORM),s5pc110)
LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
LOCAL_CFLAGS += -DNEVER_DEFAULT_TO_ASYNC_MODE
endif endif
ifeq ($(TARGET_DISABLE_TRIPLE_BUFFERING),true) ifeq ($(TARGET_DISABLE_TRIPLE_BUFFERING),true)

View File

@ -51,7 +51,7 @@ namespace android {
*/ */
FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp) : FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp) :
ConsumerBase(new BufferQueue(true, new GraphicBufferAlloc())), ConsumerBase(new BufferQueue(new GraphicBufferAlloc())),
mDisplayType(disp), mDisplayType(disp),
mCurrentBufferSlot(-1), mCurrentBufferSlot(-1),
mCurrentBuffer(0), mCurrentBuffer(0),
@ -64,7 +64,6 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp) :
GRALLOC_USAGE_HW_COMPOSER); GRALLOC_USAGE_HW_COMPOSER);
mBufferQueue->setDefaultBufferFormat(mHwc.getFormat(disp)); mBufferQueue->setDefaultBufferFormat(mHwc.getFormat(disp));
mBufferQueue->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp)); mBufferQueue->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp));
mBufferQueue->setSynchronousMode(true);
mBufferQueue->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS); mBufferQueue->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
} }

View File

@ -41,7 +41,7 @@ static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) {
VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
const sp<IGraphicBufferProducer>& sink, const String8& name) const sp<IGraphicBufferProducer>& sink, const String8& name)
: ConsumerBase(new BufferQueue(true)), : ConsumerBase(new BufferQueue()),
mHwc(hwc), mHwc(hwc),
mDisplayId(dispId), mDisplayId(dispId),
mDisplayName(name), mDisplayName(name),
@ -126,7 +126,7 @@ status_t VirtualDisplaySurface::advanceFrame() {
mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight, mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight,
&transformHint, &numPendingBuffers); &transformHint, &numPendingBuffers);
int sslot; int sslot;
result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &outFence); result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &outFence, false);
if (result < 0) if (result < 0)
return result; return result;
mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot); mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
@ -196,7 +196,7 @@ void VirtualDisplaySurface::onFrameCommitted() {
status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
QueueBufferInput(systemTime(), QueueBufferInput(systemTime(),
Rect(mSinkBufferWidth, mSinkBufferHeight), Rect(mSinkBufferWidth, mSinkBufferHeight),
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, outFence), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, outFence),
&qbo); &qbo);
if (result == NO_ERROR) { if (result == NO_ERROR) {
updateQueueBufferOutput(qbo); updateQueueBufferOutput(qbo);
@ -224,8 +224,8 @@ status_t VirtualDisplaySurface::setBufferCount(int bufferCount) {
} }
status_t VirtualDisplaySurface::dequeueBuffer(Source source, status_t VirtualDisplaySurface::dequeueBuffer(Source source,
uint32_t format, int* sslot, sp<Fence>* fence) { uint32_t format, int* sslot, sp<Fence>* fence, bool async) {
status_t result = mSource[source]->dequeueBuffer(sslot, fence, status_t result = mSource[source]->dequeueBuffer(sslot, fence, async,
mSinkBufferWidth, mSinkBufferHeight, format, mProducerUsage); mSinkBufferWidth, mSinkBufferHeight, format, mProducerUsage);
if (result < 0) if (result < 0)
return result; return result;
@ -257,7 +257,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source,
return result; return result;
} }
status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
"Unexpected dequeueBuffer() in %s state", dbgStateStr()); "Unexpected dequeueBuffer() in %s state", dbgStateStr());
@ -273,7 +273,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence,
} }
int sslot; int sslot;
status_t result = dequeueBuffer(source, format, &sslot, fence); status_t result = dequeueBuffer(source, format, &sslot, fence, async);
if (result >= 0) { if (result >= 0) {
*pslot = mapSource2ProducerSlot(source, sslot); *pslot = mapSource2ProducerSlot(source, sslot);
} }
@ -321,8 +321,9 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot,
Rect crop; Rect crop;
int scalingMode; int scalingMode;
uint32_t transform; uint32_t transform;
bool async;
input.deflate(&timestamp, &crop, &scalingMode, &transform, input.deflate(&timestamp, &crop, &scalingMode, &transform,
&mFbFence); &async, &mFbFence);
mFbProducerSlot = pslot; mFbProducerSlot = pslot;
} }
@ -345,13 +346,10 @@ int VirtualDisplaySurface::query(int what, int* value) {
return mSource[SOURCE_SINK]->query(what, value); return mSource[SOURCE_SINK]->query(what, value);
} }
status_t VirtualDisplaySurface::setSynchronousMode(bool enabled) { status_t VirtualDisplaySurface::connect(int api, bool producerControlledByApp,
return mSource[SOURCE_SINK]->setSynchronousMode(enabled); QueueBufferOutput* output) {
}
status_t VirtualDisplaySurface::connect(int api, QueueBufferOutput* output) {
QueueBufferOutput qbo; QueueBufferOutput qbo;
status_t result = mSource[SOURCE_SINK]->connect(api, &qbo); status_t result = mSource[SOURCE_SINK]->connect(api, producerControlledByApp, &qbo);
if (result == NO_ERROR) { if (result == NO_ERROR) {
updateQueueBufferOutput(qbo); updateQueueBufferOutput(qbo);
*output = mQueueBufferOutput; *output = mQueueBufferOutput;

View File

@ -95,14 +95,13 @@ private:
// //
virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf); virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf);
virtual status_t setBufferCount(int bufferCount); virtual status_t setBufferCount(int bufferCount);
virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage); uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
virtual status_t queueBuffer(int pslot, virtual status_t queueBuffer(int pslot,
const QueueBufferInput& input, QueueBufferOutput* output); const QueueBufferInput& input, QueueBufferOutput* output);
virtual void cancelBuffer(int pslot, const sp<Fence>& fence); virtual void cancelBuffer(int pslot, const sp<Fence>& fence);
virtual int query(int what, int* value); virtual int query(int what, int* value);
virtual status_t setSynchronousMode(bool enabled); virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output);
virtual status_t connect(int api, QueueBufferOutput* output);
virtual status_t disconnect(int api); virtual status_t disconnect(int api);
// //
@ -110,7 +109,7 @@ private:
// //
static Source fbSourceForCompositionType(CompositionType type); static Source fbSourceForCompositionType(CompositionType type);
status_t dequeueBuffer(Source source, uint32_t format, status_t dequeueBuffer(Source source, uint32_t format,
int* sslot, sp<Fence>* fence); int* sslot, sp<Fence>* fence, bool async);
void updateQueueBufferOutput(const QueueBufferOutput& qbo); void updateQueueBufferOutput(const QueueBufferOutput& qbo);
void resetPerFrameState(); void resetPerFrameState();

View File

@ -115,7 +115,6 @@ void Layer::onFirstRef()
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0)); mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setFrameAvailableListener(this); mSurfaceFlingerConsumer->setFrameAvailableListener(this);
mSurfaceFlingerConsumer->setSynchronousMode(true);
mSurfaceFlingerConsumer->setName(mName); mSurfaceFlingerConsumer->setName(mName);
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING #ifdef TARGET_DISABLE_TRIPLE_BUFFERING

View File

@ -28,7 +28,7 @@ namespace android {
SurfaceTextureLayer::SurfaceTextureLayer(const sp<SurfaceFlinger>& flinger) SurfaceTextureLayer::SurfaceTextureLayer(const sp<SurfaceFlinger>& flinger)
: BufferQueue(true), flinger(flinger) { : BufferQueue(), flinger(flinger) {
} }
SurfaceTextureLayer::~SurfaceTextureLayer() { SurfaceTextureLayer::~SurfaceTextureLayer() {
@ -51,32 +51,5 @@ SurfaceTextureLayer::~SurfaceTextureLayer() {
flinger->postMessageAsync( new MessageCleanUpList(flinger, this) ); flinger->postMessageAsync( new MessageCleanUpList(flinger, this) );
} }
status_t SurfaceTextureLayer::connect(int api, QueueBufferOutput* output) {
status_t err = BufferQueue::connect(api, output);
if (err == NO_ERROR) {
switch(api) {
case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA:
// Camera preview and videos are rate-limited on the producer
// side. If enabled for this build, we use async mode to always
// show the most recent frame at the cost of requiring an
// additional buffer.
#ifndef NEVER_DEFAULT_TO_ASYNC_MODE
err = setSynchronousMode(false);
break;
#endif
// fall through to set synchronous mode when not defaulting to
// async mode.
default:
err = setSynchronousMode(true);
break;
}
if (err != NO_ERROR) {
disconnect(api);
}
}
return err;
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
}; // namespace android }; // namespace android

View File

@ -38,10 +38,6 @@ class SurfaceTextureLayer : public BufferQueue {
public: public:
SurfaceTextureLayer(const sp<SurfaceFlinger>& flinger); SurfaceTextureLayer(const sp<SurfaceFlinger>& flinger);
virtual ~SurfaceTextureLayer(); virtual ~SurfaceTextureLayer();
// After calling the superclass connect(), set or clear synchronous
// mode appropriately for the specified API.
virtual status_t connect(int api, QueueBufferOutput* output);
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------