am 14bd369e
: Merge changes Ic3d35a93,I46ec942d into jb-mr1-dev
* commit '14bd369e4b711bfb267279c2161358542ed75b29': SurfaceTexture: fix an out of bounds array access surfaceflinger: refactor FrambufferSurface
This commit is contained in:
commit
a9311c17f6
@ -422,10 +422,6 @@ private:
|
|||||||
// in requestBuffers() if a width and height of zero is specified.
|
// in requestBuffers() if a width and height of zero is specified.
|
||||||
uint32_t mDefaultHeight;
|
uint32_t mDefaultHeight;
|
||||||
|
|
||||||
// mPixelFormat holds the pixel format of allocated buffers. It is used
|
|
||||||
// in requestBuffers() if a format of zero is specified.
|
|
||||||
uint32_t mPixelFormat;
|
|
||||||
|
|
||||||
// mMinUndequeuedBuffers is a constraint on the number of buffers
|
// mMinUndequeuedBuffers is a constraint on the number of buffers
|
||||||
// not dequeued at any time
|
// not dequeued at any time
|
||||||
int mMinUndequeuedBuffers;
|
int mMinUndequeuedBuffers;
|
||||||
|
209
include/gui/ConsumerBase.h
Normal file
209
include/gui/ConsumerBase.h
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 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_CONSUMERBASE_H
|
||||||
|
#define ANDROID_GUI_CONSUMERBASE_H
|
||||||
|
|
||||||
|
#include <gui/BufferQueue.h>
|
||||||
|
|
||||||
|
#include <ui/GraphicBuffer.h>
|
||||||
|
|
||||||
|
#include <utils/String8.h>
|
||||||
|
#include <utils/Vector.h>
|
||||||
|
#include <utils/threads.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class String8;
|
||||||
|
|
||||||
|
// ConsumerBase is a base class for BufferQueue consumer end-points. It
|
||||||
|
// handles common tasks like management of the connection to the BufferQueue
|
||||||
|
// and the buffer pool.
|
||||||
|
class ConsumerBase : public virtual RefBase,
|
||||||
|
protected BufferQueue::ConsumerListener {
|
||||||
|
public:
|
||||||
|
struct FrameAvailableListener : public virtual RefBase {
|
||||||
|
// onFrameAvailable() is called each time an additional frame becomes
|
||||||
|
// available for consumption. This means that frames that are queued
|
||||||
|
// while in asynchronous mode only trigger the callback if no previous
|
||||||
|
// frames are pending. Frames queued while in synchronous mode always
|
||||||
|
// trigger the callback.
|
||||||
|
//
|
||||||
|
// This is called without any lock held and can be called concurrently
|
||||||
|
// by multiple threads.
|
||||||
|
virtual void onFrameAvailable() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~ConsumerBase();
|
||||||
|
|
||||||
|
// abandon frees all the buffers and puts the ConsumerBase into the
|
||||||
|
// 'abandoned' state. Once put in this state the ConsumerBase can never
|
||||||
|
// leave it. When in the 'abandoned' state, all methods of the
|
||||||
|
// ISurfaceTexture interface will fail with the NO_INIT error.
|
||||||
|
//
|
||||||
|
// Note that while calling this method causes all the buffers to be freed
|
||||||
|
// from the perspective of the the ConsumerBase, if there are additional
|
||||||
|
// references on the buffers (e.g. if a buffer is referenced by a client
|
||||||
|
// or by OpenGL ES as a texture) then those buffer will remain allocated.
|
||||||
|
void abandon();
|
||||||
|
|
||||||
|
// set the name of the ConsumerBase that will be used to identify it in
|
||||||
|
// log messages.
|
||||||
|
void setName(const String8& name);
|
||||||
|
|
||||||
|
// getBufferQueue returns the BufferQueue object to which this
|
||||||
|
// ConsumerBase is connected.
|
||||||
|
sp<BufferQueue> getBufferQueue() const;
|
||||||
|
|
||||||
|
// dump writes the current state to a string. These methods should NOT be
|
||||||
|
// overridden by child classes. Instead they should override the
|
||||||
|
// dumpLocked method, which is called by these methods after locking the
|
||||||
|
// mutex.
|
||||||
|
void dump(String8& result) const;
|
||||||
|
void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
|
||||||
|
|
||||||
|
// setFrameAvailableListener sets the listener object that will be notified
|
||||||
|
// when a new frame becomes available.
|
||||||
|
void setFrameAvailableListener(const sp<FrameAvailableListener>& listener);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ConsumerBase(const ConsumerBase&);
|
||||||
|
void operator=(const ConsumerBase&);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// TODO: Fix this comment
|
||||||
|
// ConsumerBase constructs a new ConsumerBase object. tex indicates the
|
||||||
|
// name of the OpenGL ES texture to which images are to be streamed.
|
||||||
|
// allowSynchronousMode specifies whether or not synchronous mode can be
|
||||||
|
// enabled. texTarget specifies the OpenGL ES texture target to which the
|
||||||
|
// texture will be bound in updateTexImage. useFenceSync specifies whether
|
||||||
|
// fences should be used to synchronize access to buffers if that behavior
|
||||||
|
// is enabled at compile-time. A custom bufferQueue can be specified
|
||||||
|
// if behavior for queue/dequeue/connect etc needs to be customized.
|
||||||
|
// Otherwise a default BufferQueue will be created and used.
|
||||||
|
//
|
||||||
|
// For legacy reasons, the ConsumerBase is created in a state where it is
|
||||||
|
// considered attached to an OpenGL ES context for the purposes of the
|
||||||
|
// attachToContext and detachFromContext methods. However, despite being
|
||||||
|
// considered "attached" to a context, the specific OpenGL ES context
|
||||||
|
// doesn't get latched until the first call to updateTexImage. After that
|
||||||
|
// point, all calls to updateTexImage must be made with the same OpenGL ES
|
||||||
|
// context current.
|
||||||
|
//
|
||||||
|
// A ConsumerBase may be detached from one OpenGL ES context and then
|
||||||
|
// attached to a different context using the detachFromContext and
|
||||||
|
// attachToContext methods, respectively. The intention of these methods is
|
||||||
|
// purely to allow a ConsumerBase to be transferred from one consumer
|
||||||
|
// context to another. If such a transfer is not needed there is no
|
||||||
|
// requirement that either of these methods be called.
|
||||||
|
ConsumerBase(const sp<BufferQueue> &bufferQueue);
|
||||||
|
|
||||||
|
// Implementation of the BufferQueue::ConsumerListener interface. These
|
||||||
|
// calls are used to notify the ConsumerBase of asynchronous events in the
|
||||||
|
// BufferQueue.
|
||||||
|
virtual void onFrameAvailable();
|
||||||
|
virtual void onBuffersReleased();
|
||||||
|
|
||||||
|
// freeBufferLocked frees up the given buffer slot. If the slot has been
|
||||||
|
// initialized this will release the reference to the GraphicBuffer in that
|
||||||
|
// slot and destroy the EGLImage in that slot. Otherwise it has no effect.
|
||||||
|
//
|
||||||
|
// This method must be called with mMutex locked.
|
||||||
|
virtual void freeBufferLocked(int slotIndex);
|
||||||
|
|
||||||
|
// abandonLocked puts the BufferQueue into the abandoned state, causing
|
||||||
|
// all future operations on it to fail. This method rather than the public
|
||||||
|
// abandon method should be overridden by child classes to add abandon-
|
||||||
|
// time behavior.
|
||||||
|
//
|
||||||
|
// This method must be called with mMutex locked.
|
||||||
|
virtual void abandonLocked();
|
||||||
|
|
||||||
|
virtual void dumpLocked(String8& result, const char* prefix, char* buffer,
|
||||||
|
size_t SIZE) const;
|
||||||
|
|
||||||
|
// acquireBufferLocked fetches the next buffer from the BufferQueue and
|
||||||
|
// updates the buffer slot for the buffer returned.
|
||||||
|
virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item);
|
||||||
|
|
||||||
|
// releaseBufferLocked relinquishes control over a buffer, returning that
|
||||||
|
// control to the BufferQueue.
|
||||||
|
virtual status_t releaseBufferLocked(int buf, EGLDisplay display,
|
||||||
|
EGLSyncKHR eglFence, const sp<Fence>& fence);
|
||||||
|
|
||||||
|
// Slot contains the information and object references that
|
||||||
|
// ConsumerBase maintains about a BufferQueue buffer slot.
|
||||||
|
struct Slot {
|
||||||
|
// mGraphicBuffer is the Gralloc buffer store in the slot or NULL if
|
||||||
|
// no Gralloc buffer is in the slot.
|
||||||
|
sp<GraphicBuffer> mGraphicBuffer;
|
||||||
|
|
||||||
|
// mFence is a fence which will signal when the buffer associated with
|
||||||
|
// this buffer slot is no longer being used by the consumer and can be
|
||||||
|
// overwritten. The buffer can be dequeued before the fence signals;
|
||||||
|
// the producer is responsible for delaying writes until it signals.
|
||||||
|
sp<Fence> mFence;
|
||||||
|
};
|
||||||
|
|
||||||
|
// mSlots stores the buffers that have been allocated by the BufferQueue
|
||||||
|
// for each buffer slot. It is initialized to null pointers, and gets
|
||||||
|
// filled in with the result of BufferQueue::acquire when the
|
||||||
|
// client dequeues a buffer from a
|
||||||
|
// slot that has not yet been used. The buffer allocated to a slot will also
|
||||||
|
// be replaced if the requested buffer usage or geometry differs from that
|
||||||
|
// of the buffer allocated to a slot.
|
||||||
|
Slot mSlots[BufferQueue::NUM_BUFFER_SLOTS];
|
||||||
|
|
||||||
|
// mAbandoned indicates that the BufferQueue will no longer be used to
|
||||||
|
// consume images buffers pushed to it using the ISurfaceTexture
|
||||||
|
// interface. It is initialized to false, and set to true in the abandon
|
||||||
|
// method. A BufferQueue that has been abandoned will return the NO_INIT
|
||||||
|
// error from all IConsumerBase methods capable of returning an error.
|
||||||
|
bool mAbandoned;
|
||||||
|
|
||||||
|
// mName is a string used to identify the ConsumerBase in log messages.
|
||||||
|
// It can be set by the setName method.
|
||||||
|
String8 mName;
|
||||||
|
|
||||||
|
// mFrameAvailableListener is the listener object that will be called when a
|
||||||
|
// new frame becomes available. If it is not NULL it will be called from
|
||||||
|
// queueBuffer.
|
||||||
|
sp<FrameAvailableListener> mFrameAvailableListener;
|
||||||
|
|
||||||
|
// The ConsumerBase has-a BufferQueue and is responsible for creating this object
|
||||||
|
// if none is supplied
|
||||||
|
sp<BufferQueue> mBufferQueue;
|
||||||
|
|
||||||
|
// mAttached indicates whether the ConsumerBase is currently attached to
|
||||||
|
// an OpenGL ES context. For legacy reasons, this is initialized to true,
|
||||||
|
// indicating that the ConsumerBase is considered to be attached to
|
||||||
|
// whatever context is current at the time of the first updateTexImage call.
|
||||||
|
// It is set to false by detachFromContext, and then set to true again by
|
||||||
|
// attachToContext.
|
||||||
|
bool mAttached;
|
||||||
|
|
||||||
|
// mMutex is the mutex used to prevent concurrent access to the member
|
||||||
|
// variables of ConsumerBase objects. It must be locked whenever the
|
||||||
|
// member variables are accessed.
|
||||||
|
mutable Mutex mMutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
}; // namespace android
|
||||||
|
|
||||||
|
#endif // ANDROID_GUI_CONSUMERBASE_H
|
@ -4,6 +4,7 @@ include $(CLEAR_VARS)
|
|||||||
LOCAL_SRC_FILES:= \
|
LOCAL_SRC_FILES:= \
|
||||||
BitTube.cpp \
|
BitTube.cpp \
|
||||||
BufferQueue.cpp \
|
BufferQueue.cpp \
|
||||||
|
ConsumerBase.cpp \
|
||||||
DisplayEventReceiver.cpp \
|
DisplayEventReceiver.cpp \
|
||||||
IDisplayEventConnection.cpp \
|
IDisplayEventConnection.cpp \
|
||||||
ISensorEventConnection.cpp \
|
ISensorEventConnection.cpp \
|
||||||
|
@ -85,7 +85,6 @@ BufferQueue::BufferQueue(bool allowSynchronousMode, int bufferCount,
|
|||||||
const sp<IGraphicBufferAlloc>& allocator) :
|
const sp<IGraphicBufferAlloc>& allocator) :
|
||||||
mDefaultWidth(1),
|
mDefaultWidth(1),
|
||||||
mDefaultHeight(1),
|
mDefaultHeight(1),
|
||||||
mPixelFormat(PIXEL_FORMAT_RGBA_8888),
|
|
||||||
mMinUndequeuedBuffers(bufferCount),
|
mMinUndequeuedBuffers(bufferCount),
|
||||||
mMinAsyncBufferSlots(bufferCount + 1),
|
mMinAsyncBufferSlots(bufferCount + 1),
|
||||||
mMinSyncBufferSlots(bufferCount),
|
mMinSyncBufferSlots(bufferCount),
|
||||||
@ -98,7 +97,7 @@ BufferQueue::BufferQueue(bool allowSynchronousMode, int bufferCount,
|
|||||||
mAbandoned(false),
|
mAbandoned(false),
|
||||||
mFrameCounter(0),
|
mFrameCounter(0),
|
||||||
mBufferHasBeenQueued(false),
|
mBufferHasBeenQueued(false),
|
||||||
mDefaultBufferFormat(0),
|
mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
|
||||||
mConsumerUsageBits(0),
|
mConsumerUsageBits(0),
|
||||||
mTransformHint(0)
|
mTransformHint(0)
|
||||||
{
|
{
|
||||||
@ -125,7 +124,8 @@ status_t BufferQueue::setBufferCountServerLocked(int bufferCount) {
|
|||||||
if (bufferCount > NUM_BUFFER_SLOTS)
|
if (bufferCount > NUM_BUFFER_SLOTS)
|
||||||
return BAD_VALUE;
|
return BAD_VALUE;
|
||||||
|
|
||||||
// special-case, nothing to do
|
mServerBufferCount = bufferCount;
|
||||||
|
|
||||||
if (bufferCount == mBufferCount)
|
if (bufferCount == mBufferCount)
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
@ -133,7 +133,6 @@ status_t BufferQueue::setBufferCountServerLocked(int bufferCount) {
|
|||||||
bufferCount >= mBufferCount) {
|
bufferCount >= mBufferCount) {
|
||||||
// easy, we just have more buffers
|
// easy, we just have more buffers
|
||||||
mBufferCount = bufferCount;
|
mBufferCount = bufferCount;
|
||||||
mServerBufferCount = bufferCount;
|
|
||||||
mDequeueCondition.broadcast();
|
mDequeueCondition.broadcast();
|
||||||
} else {
|
} else {
|
||||||
// we're here because we're either
|
// we're here because we're either
|
||||||
@ -150,7 +149,6 @@ status_t BufferQueue::setBufferCountServerLocked(int bufferCount) {
|
|||||||
// own one. the actual resizing will happen during the next
|
// own one. the actual resizing will happen during the next
|
||||||
// dequeueBuffer.
|
// dequeueBuffer.
|
||||||
|
|
||||||
mServerBufferCount = bufferCount;
|
|
||||||
mDequeueCondition.broadcast();
|
mDequeueCondition.broadcast();
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
@ -260,7 +258,7 @@ int BufferQueue::query(int what, int* outValue)
|
|||||||
value = mDefaultHeight;
|
value = mDefaultHeight;
|
||||||
break;
|
break;
|
||||||
case NATIVE_WINDOW_FORMAT:
|
case NATIVE_WINDOW_FORMAT:
|
||||||
value = mPixelFormat;
|
value = mDefaultBufferFormat;
|
||||||
break;
|
break;
|
||||||
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
|
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
|
||||||
value = mSynchronousMode ?
|
value = mSynchronousMode ?
|
||||||
@ -447,12 +445,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
|
|||||||
h = mDefaultHeight;
|
h = mDefaultHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool updateFormat = (format != 0);
|
|
||||||
if (!updateFormat) {
|
|
||||||
// keep the current (or default) format
|
|
||||||
format = mPixelFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
// buffer is now in DEQUEUED (but can also be current at the same time,
|
// buffer is now in DEQUEUED (but can also be current at the same time,
|
||||||
// if we're in synchronous mode)
|
// if we're in synchronous mode)
|
||||||
mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
|
mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
|
||||||
@ -473,9 +465,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
|
|||||||
"failed");
|
"failed");
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
if (updateFormat) {
|
|
||||||
mPixelFormat = format;
|
|
||||||
}
|
|
||||||
|
|
||||||
mSlots[buf].mAcquireCalled = false;
|
mSlots[buf].mAcquireCalled = false;
|
||||||
mSlots[buf].mGraphicBuffer = graphicBuffer;
|
mSlots[buf].mGraphicBuffer = graphicBuffer;
|
||||||
@ -791,9 +780,9 @@ void BufferQueue::dump(String8& result, const char* prefix,
|
|||||||
|
|
||||||
snprintf(buffer, SIZE,
|
snprintf(buffer, SIZE,
|
||||||
"%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
|
"%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
|
||||||
"mPixelFormat=%d, FIFO(%d)={%s}\n",
|
"default-format=%d, FIFO(%d)={%s}\n",
|
||||||
prefix, mBufferCount, mSynchronousMode, mDefaultWidth,
|
prefix, mBufferCount, mSynchronousMode, mDefaultWidth,
|
||||||
mDefaultHeight, mPixelFormat, fifoSize, fifo.string());
|
mDefaultHeight, mDefaultBufferFormat, fifoSize, fifo.string());
|
||||||
result.append(buffer);
|
result.append(buffer);
|
||||||
|
|
||||||
|
|
||||||
@ -835,21 +824,22 @@ void BufferQueue::dump(String8& result, const char* prefix,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferQueue::freeBufferLocked(int i) {
|
void BufferQueue::freeBufferLocked(int slot) {
|
||||||
mSlots[i].mGraphicBuffer = 0;
|
ST_LOGV("freeBufferLocked: slot=%d", slot);
|
||||||
if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
|
mSlots[slot].mGraphicBuffer = 0;
|
||||||
mSlots[i].mNeedsCleanupOnRelease = true;
|
if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
|
||||||
|
mSlots[slot].mNeedsCleanupOnRelease = true;
|
||||||
}
|
}
|
||||||
mSlots[i].mBufferState = BufferSlot::FREE;
|
mSlots[slot].mBufferState = BufferSlot::FREE;
|
||||||
mSlots[i].mFrameNumber = 0;
|
mSlots[slot].mFrameNumber = 0;
|
||||||
mSlots[i].mAcquireCalled = false;
|
mSlots[slot].mAcquireCalled = false;
|
||||||
|
|
||||||
// destroy fence as BufferQueue now takes ownership
|
// destroy fence as BufferQueue now takes ownership
|
||||||
if (mSlots[i].mEglFence != EGL_NO_SYNC_KHR) {
|
if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
|
||||||
eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mEglFence);
|
eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
|
||||||
mSlots[i].mEglFence = EGL_NO_SYNC_KHR;
|
mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
|
||||||
}
|
}
|
||||||
mSlots[i].mFence.clear();
|
mSlots[slot].mFence.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferQueue::freeAllBuffersLocked() {
|
void BufferQueue::freeAllBuffersLocked() {
|
||||||
@ -886,12 +876,14 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
|
|||||||
buffer->mTimestamp = mSlots[buf].mTimestamp;
|
buffer->mTimestamp = mSlots[buf].mTimestamp;
|
||||||
buffer->mBuf = buf;
|
buffer->mBuf = buf;
|
||||||
buffer->mFence = mSlots[buf].mFence;
|
buffer->mFence = mSlots[buf].mFence;
|
||||||
mSlots[buf].mAcquireCalled = true;
|
|
||||||
|
|
||||||
|
mSlots[buf].mAcquireCalled = true;
|
||||||
|
mSlots[buf].mNeedsCleanupOnRelease = false;
|
||||||
mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
|
mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
|
||||||
|
mSlots[buf].mFence.clear();
|
||||||
|
|
||||||
mQueue.erase(front);
|
mQueue.erase(front);
|
||||||
mDequeueCondition.broadcast();
|
mDequeueCondition.broadcast();
|
||||||
mSlots[buf].mFence.clear();
|
|
||||||
|
|
||||||
ATRACE_INT(mConsumerName.string(), mQueue.size());
|
ATRACE_INT(mConsumerName.string(), mQueue.size());
|
||||||
} else {
|
} else {
|
||||||
|
205
libs/gui/ConsumerBase.cpp
Normal file
205
libs/gui/ConsumerBase.cpp
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 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 "ConsumerBase"
|
||||||
|
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
|
||||||
|
//#define LOG_NDEBUG 0
|
||||||
|
|
||||||
|
#define GL_GLEXT_PROTOTYPES
|
||||||
|
#define EGL_EGLEXT_PROTOTYPES
|
||||||
|
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <EGL/eglext.h>
|
||||||
|
|
||||||
|
#include <hardware/hardware.h>
|
||||||
|
|
||||||
|
#include <gui/IGraphicBufferAlloc.h>
|
||||||
|
#include <gui/ISurfaceComposer.h>
|
||||||
|
#include <gui/SurfaceComposerClient.h>
|
||||||
|
#include <gui/ConsumerBase.h>
|
||||||
|
|
||||||
|
#include <private/gui/ComposerService.h>
|
||||||
|
|
||||||
|
#include <utils/Log.h>
|
||||||
|
#include <utils/String8.h>
|
||||||
|
#include <utils/Trace.h>
|
||||||
|
|
||||||
|
// Macros for including the ConsumerBase name in log messages
|
||||||
|
#define CB_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
|
||||||
|
#define CB_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
|
||||||
|
#define CB_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
|
||||||
|
#define CB_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
|
||||||
|
#define CB_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
// Get an ID that's unique within this process.
|
||||||
|
static int32_t createProcessUniqueId() {
|
||||||
|
static volatile int32_t globalCounter = 0;
|
||||||
|
return android_atomic_inc(&globalCounter);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) :
|
||||||
|
mBufferQueue(bufferQueue) {
|
||||||
|
// Choose a name using the PID and a process-unique ID.
|
||||||
|
mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
|
||||||
|
|
||||||
|
// Note that we can't create an sp<...>(this) in a ctor that will not keep a
|
||||||
|
// reference once the ctor ends, as that would cause the refcount of 'this'
|
||||||
|
// dropping to 0 at the end of the ctor. Since all we need is a wp<...>
|
||||||
|
// that's what we create.
|
||||||
|
wp<BufferQueue::ConsumerListener> listener;
|
||||||
|
sp<BufferQueue::ConsumerListener> proxy;
|
||||||
|
listener = static_cast<BufferQueue::ConsumerListener*>(this);
|
||||||
|
proxy = new BufferQueue::ProxyConsumerListener(listener);
|
||||||
|
|
||||||
|
status_t err = mBufferQueue->consumerConnect(proxy);
|
||||||
|
if (err != NO_ERROR) {
|
||||||
|
CB_LOGE("SurfaceTexture: error connecting to BufferQueue: %s (%d)",
|
||||||
|
strerror(-err), err);
|
||||||
|
} else {
|
||||||
|
mBufferQueue->setConsumerName(mName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsumerBase::~ConsumerBase() {
|
||||||
|
CB_LOGV("~ConsumerBase");
|
||||||
|
abandon();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerBase::freeBufferLocked(int slotIndex) {
|
||||||
|
CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
|
||||||
|
mSlots[slotIndex].mGraphicBuffer = 0;
|
||||||
|
mSlots[slotIndex].mFence = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for refactoring, should not be in final interface
|
||||||
|
sp<BufferQueue> ConsumerBase::getBufferQueue() const {
|
||||||
|
Mutex::Autolock lock(mMutex);
|
||||||
|
return mBufferQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerBase::onFrameAvailable() {
|
||||||
|
CB_LOGV("onFrameAvailable");
|
||||||
|
|
||||||
|
sp<FrameAvailableListener> listener;
|
||||||
|
{ // scope for the lock
|
||||||
|
Mutex::Autolock lock(mMutex);
|
||||||
|
listener = mFrameAvailableListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listener != NULL) {
|
||||||
|
CB_LOGV("actually calling onFrameAvailable");
|
||||||
|
listener->onFrameAvailable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerBase::onBuffersReleased() {
|
||||||
|
Mutex::Autolock lock(mMutex);
|
||||||
|
|
||||||
|
CB_LOGV("onBuffersReleased");
|
||||||
|
|
||||||
|
if (mAbandoned) {
|
||||||
|
// Nothing to do if we're already abandoned.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mask = 0;
|
||||||
|
mBufferQueue->getReleasedBuffers(&mask);
|
||||||
|
for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
|
||||||
|
if (mask & (1 << i)) {
|
||||||
|
freeBufferLocked(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerBase::abandon() {
|
||||||
|
CB_LOGV("abandon");
|
||||||
|
Mutex::Autolock lock(mMutex);
|
||||||
|
|
||||||
|
if (!mAbandoned) {
|
||||||
|
abandonLocked();
|
||||||
|
mAbandoned = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerBase::abandonLocked() {
|
||||||
|
CB_LOGV("abandonLocked");
|
||||||
|
for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
|
||||||
|
freeBufferLocked(i);
|
||||||
|
}
|
||||||
|
// disconnect from the BufferQueue
|
||||||
|
mBufferQueue->consumerDisconnect();
|
||||||
|
mBufferQueue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerBase::setFrameAvailableListener(
|
||||||
|
const sp<FrameAvailableListener>& listener) {
|
||||||
|
CB_LOGV("setFrameAvailableListener");
|
||||||
|
Mutex::Autolock lock(mMutex);
|
||||||
|
mFrameAvailableListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerBase::dump(String8& result) const {
|
||||||
|
char buffer[1024];
|
||||||
|
dump(result, "", buffer, 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerBase::dump(String8& result, const char* prefix,
|
||||||
|
char* buffer, size_t size) const {
|
||||||
|
Mutex::Autolock _l(mMutex);
|
||||||
|
dumpLocked(result, prefix, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerBase::dumpLocked(String8& result, const char* prefix,
|
||||||
|
char* buffer, size_t SIZE) const {
|
||||||
|
snprintf(buffer, SIZE, "%smAbandoned=%d\n", prefix, int(mAbandoned));
|
||||||
|
result.append(buffer);
|
||||||
|
|
||||||
|
if (!mAbandoned) {
|
||||||
|
mBufferQueue->dump(result, prefix, buffer, SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item) {
|
||||||
|
status_t err = mBufferQueue->acquireBuffer(item);
|
||||||
|
if (err != NO_ERROR) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item->mGraphicBuffer != NULL) {
|
||||||
|
mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display,
|
||||||
|
EGLSyncKHR eglFence, const sp<Fence>& fence) {
|
||||||
|
CB_LOGV("releaseBufferLocked: slot=%d", slot);
|
||||||
|
status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence, fence);
|
||||||
|
if (err == BufferQueue::STALE_BUFFER_SLOT) {
|
||||||
|
freeBufferLocked(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
mSlots[slot].mFence.clear();
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace android
|
@ -316,7 +316,7 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
|
|||||||
computeCurrentTransformMatrix();
|
computeCurrentTransformMatrix();
|
||||||
} else {
|
} else {
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
ALOGE("updateTexImage failed on acquire %d", err);
|
ST_LOGE("updateTexImage failed on acquire %d", err);
|
||||||
}
|
}
|
||||||
// We always bind the texture even if we don't update its contents.
|
// We always bind the texture even if we don't update its contents.
|
||||||
glBindTexture(mTexTarget, mTexName);
|
glBindTexture(mTexTarget, mTexName);
|
||||||
@ -327,7 +327,7 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SurfaceTexture::setReleaseFence(int fenceFd) {
|
void SurfaceTexture::setReleaseFence(int fenceFd) {
|
||||||
if (fenceFd == -1)
|
if (fenceFd == -1 || mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT)
|
||||||
return;
|
return;
|
||||||
sp<Fence> fence(new Fence(fenceFd));
|
sp<Fence> fence(new Fence(fenceFd));
|
||||||
if (!mEGLSlots[mCurrentTexture].mReleaseFence.get()) {
|
if (!mEGLSlots[mCurrentTexture].mReleaseFence.get()) {
|
||||||
@ -337,7 +337,7 @@ void SurfaceTexture::setReleaseFence(int fenceFd) {
|
|||||||
String8("SurfaceTexture merged release"),
|
String8("SurfaceTexture merged release"),
|
||||||
mEGLSlots[mCurrentTexture].mReleaseFence, fence);
|
mEGLSlots[mCurrentTexture].mReleaseFence, fence);
|
||||||
if (!mergedFence.get()) {
|
if (!mergedFence.get()) {
|
||||||
ALOGE("failed to merge release fences");
|
ST_LOGE("failed to merge release fences");
|
||||||
// synchronization is broken, the best we can do is hope fences
|
// synchronization is broken, the best we can do is hope fences
|
||||||
// signal in order so the new fence will act like a union
|
// signal in order so the new fence will act like a union
|
||||||
mEGLSlots[mCurrentTexture].mReleaseFence = fence;
|
mEGLSlots[mCurrentTexture].mReleaseFence = fence;
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#include <ui/DisplayInfo.h>
|
#include <ui/DisplayInfo.h>
|
||||||
#include <ui/PixelFormat.h>
|
#include <ui/PixelFormat.h>
|
||||||
|
|
||||||
|
#include <gui/SurfaceTextureClient.h>
|
||||||
|
|
||||||
#include <GLES/gl.h>
|
#include <GLES/gl.h>
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#include <EGL/eglext.h>
|
#include <EGL/eglext.h>
|
||||||
@ -100,11 +102,13 @@ void checkEGLErrors(const char* token)
|
|||||||
DisplayDevice::DisplayDevice(
|
DisplayDevice::DisplayDevice(
|
||||||
const sp<SurfaceFlinger>& flinger,
|
const sp<SurfaceFlinger>& flinger,
|
||||||
int display,
|
int display,
|
||||||
const sp<ANativeWindow>& surface,
|
const sp<ANativeWindow>& nativeWindow,
|
||||||
|
const sp<FramebufferSurface>& framebufferSurface,
|
||||||
EGLConfig config)
|
EGLConfig config)
|
||||||
: mFlinger(flinger),
|
: mFlinger(flinger),
|
||||||
mId(display),
|
mId(display),
|
||||||
mNativeWindow(surface),
|
mNativeWindow(nativeWindow),
|
||||||
|
mFramebufferSurface(framebufferSurface),
|
||||||
mDisplay(EGL_NO_DISPLAY),
|
mDisplay(EGL_NO_DISPLAY),
|
||||||
mSurface(EGL_NO_SURFACE),
|
mSurface(EGL_NO_SURFACE),
|
||||||
mContext(EGL_NO_CONTEXT),
|
mContext(EGL_NO_CONTEXT),
|
||||||
@ -164,12 +168,6 @@ void DisplayDevice::init(EGLConfig config)
|
|||||||
{
|
{
|
||||||
ANativeWindow* const window = mNativeWindow.get();
|
ANativeWindow* const window = mNativeWindow.get();
|
||||||
|
|
||||||
int concreteType;
|
|
||||||
window->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &concreteType);
|
|
||||||
if (concreteType == NATIVE_WINDOW_FRAMEBUFFER) {
|
|
||||||
mFramebufferSurface = static_cast<FramebufferSurface *>(mNativeWindow.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
int format;
|
int format;
|
||||||
window->query(window, NATIVE_WINDOW_FORMAT, &format);
|
window->query(window, NATIVE_WINDOW_FORMAT, &format);
|
||||||
mDpiX = window->xdpi;
|
mDpiX = window->xdpi;
|
||||||
@ -216,16 +214,6 @@ void DisplayDevice::init(EGLConfig config)
|
|||||||
eglQuerySurface(display, surface, EGL_WIDTH, &mDisplayWidth);
|
eglQuerySurface(display, surface, EGL_WIDTH, &mDisplayWidth);
|
||||||
eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight);
|
eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight);
|
||||||
|
|
||||||
if (mFramebufferSurface != NULL) {
|
|
||||||
if (mFramebufferSurface->isUpdateOnDemand()) {
|
|
||||||
mFlags |= PARTIAL_UPDATES;
|
|
||||||
// if we have partial updates, we definitely don't need to
|
|
||||||
// preserve the backbuffer, which may be costly.
|
|
||||||
eglSurfaceAttrib(display, surface,
|
|
||||||
EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mDisplay = display;
|
mDisplay = display;
|
||||||
mSurface = surface;
|
mSurface = surface;
|
||||||
mFormat = format;
|
mFormat = format;
|
||||||
@ -262,12 +250,6 @@ void DisplayDevice::flip(const Region& dirty) const
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (mFlags & PARTIAL_UPDATES) {
|
|
||||||
if (mFramebufferSurface != NULL) {
|
|
||||||
mFramebufferSurface->setUpdateRectangle(dirty.getBounds());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mPageFlipCount++;
|
mPageFlipCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,8 @@ public:
|
|||||||
DisplayDevice(
|
DisplayDevice(
|
||||||
const sp<SurfaceFlinger>& flinger,
|
const sp<SurfaceFlinger>& flinger,
|
||||||
int dpy,
|
int dpy,
|
||||||
const sp<ANativeWindow>& surface,
|
const sp<ANativeWindow>& nativeWindow,
|
||||||
|
const sp<FramebufferSurface>& framebufferSurface,
|
||||||
EGLConfig config);
|
EGLConfig config);
|
||||||
|
|
||||||
~DisplayDevice();
|
~DisplayDevice();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
**
|
**
|
||||||
** Copyright 2007 The Android Open Source Project
|
** Copyright 2012 The Android Open Source Project
|
||||||
**
|
**
|
||||||
** Licensed under the Apache License Version 2.0(the "License");
|
** Licensed under the Apache License Version 2.0(the "License");
|
||||||
** you may not use this file except in compliance with the License.
|
** you may not use this file except in compliance with the License.
|
||||||
@ -48,17 +48,33 @@ sp<FramebufferSurface> FramebufferSurface::create() {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class GraphicBufferAlloc : public BnGraphicBufferAlloc {
|
||||||
|
public:
|
||||||
|
GraphicBufferAlloc() { };
|
||||||
|
virtual ~GraphicBufferAlloc() { };
|
||||||
|
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
|
||||||
|
PixelFormat format, uint32_t usage, status_t* error) {
|
||||||
|
sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
|
||||||
|
return graphicBuffer;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This implements the (main) framebuffer management. This class is used
|
* This implements the (main) framebuffer management. This class is used
|
||||||
* mostly by SurfaceFlinger, but also by command line GL application.
|
* mostly by SurfaceFlinger, but also by command line GL application.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FramebufferSurface::FramebufferSurface()
|
FramebufferSurface::FramebufferSurface():
|
||||||
: SurfaceTextureClient(),
|
ConsumerBase(new BufferQueue(true, NUM_FRAME_BUFFERS,
|
||||||
fbDev(0), mCurrentBufferIndex(-1), mUpdateOnDemand(false)
|
new GraphicBufferAlloc())),
|
||||||
|
fbDev(0),
|
||||||
|
mCurrentBufferSlot(-1),
|
||||||
|
mCurrentBuffer(0)
|
||||||
{
|
{
|
||||||
hw_module_t const* module;
|
hw_module_t const* module;
|
||||||
|
|
||||||
if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
|
if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
|
||||||
int stride;
|
int stride;
|
||||||
int err;
|
int err;
|
||||||
@ -70,85 +86,64 @@ FramebufferSurface::FramebufferSurface()
|
|||||||
if (!fbDev)
|
if (!fbDev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mUpdateOnDemand = (fbDev->setUpdateRect != 0);
|
mName = "FramebufferSurface";
|
||||||
|
mBufferQueue->setConsumerName(mName);
|
||||||
const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
|
mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
|
||||||
const_cast<int&>(ANativeWindow::minSwapInterval) = fbDev->minSwapInterval;
|
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER);
|
||||||
const_cast<int&>(ANativeWindow::maxSwapInterval) = fbDev->maxSwapInterval;
|
mBufferQueue->setDefaultBufferFormat(fbDev->format);
|
||||||
|
mBufferQueue->setDefaultBufferSize(fbDev->width, fbDev->height);
|
||||||
if (fbDev->xdpi == 0 || fbDev->ydpi == 0) {
|
mBufferQueue->setSynchronousMode(true);
|
||||||
ALOGE("invalid screen resolution from fb HAL (xdpi=%f, ydpi=%f), "
|
mBufferQueue->setBufferCountServer(NUM_FRAME_BUFFERS);
|
||||||
"defaulting to 160 dpi", fbDev->xdpi, fbDev->ydpi);
|
|
||||||
const_cast<float&>(ANativeWindow::xdpi) = 160;
|
|
||||||
const_cast<float&>(ANativeWindow::ydpi) = 160;
|
|
||||||
} else {
|
|
||||||
const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
|
|
||||||
const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ALOGE("Couldn't get gralloc module");
|
ALOGE("Couldn't get gralloc module");
|
||||||
}
|
}
|
||||||
|
|
||||||
class GraphicBufferAlloc : public BnGraphicBufferAlloc {
|
|
||||||
public:
|
|
||||||
GraphicBufferAlloc() { };
|
|
||||||
virtual ~GraphicBufferAlloc() { };
|
|
||||||
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
|
|
||||||
PixelFormat format, uint32_t usage, status_t* error) {
|
|
||||||
sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
|
|
||||||
return graphicBuffer;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
mBufferQueue = new BufferQueue(true, NUM_FRAME_BUFFERS, new GraphicBufferAlloc());
|
|
||||||
mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB|GRALLOC_USAGE_HW_RENDER|GRALLOC_USAGE_HW_COMPOSER);
|
|
||||||
mBufferQueue->setDefaultBufferFormat(fbDev->format);
|
|
||||||
mBufferQueue->setDefaultBufferSize(fbDev->width, fbDev->height);
|
|
||||||
mBufferQueue->setSynchronousMode(true);
|
|
||||||
mBufferQueue->setBufferCountServer(NUM_FRAME_BUFFERS);
|
|
||||||
setISurfaceTexture(mBufferQueue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramebufferSurface::onFirstRef() {
|
status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>* buffer) {
|
||||||
class Listener : public BufferQueue::ConsumerListener {
|
Mutex::Autolock lock(mMutex);
|
||||||
const wp<FramebufferSurface> that;
|
|
||||||
virtual ~Listener() { }
|
|
||||||
virtual void onBuffersReleased() { }
|
|
||||||
void onFrameAvailable() {
|
|
||||||
sp<FramebufferSurface> self = that.promote();
|
|
||||||
if (self != NULL) {
|
|
||||||
BufferQueue::BufferItem item;
|
|
||||||
status_t err = self->mBufferQueue->acquireBuffer(&item);
|
|
||||||
if (err == 0) {
|
|
||||||
if (item.mGraphicBuffer != 0) {
|
|
||||||
self->mBuffers[item.mBuf] = item.mGraphicBuffer;
|
|
||||||
}
|
|
||||||
if (item.mFence.get()) {
|
|
||||||
err = item.mFence->wait(Fence::TIMEOUT_NEVER);
|
|
||||||
if (err) {
|
|
||||||
ALOGE("failed waiting for buffer's fence: %d", err);
|
|
||||||
self->mBufferQueue->releaseBuffer(item.mBuf,
|
|
||||||
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
|
|
||||||
item.mFence);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self->fbDev->post(self->fbDev, self->mBuffers[item.mBuf]->handle);
|
|
||||||
if (self->mCurrentBufferIndex >= 0) {
|
|
||||||
self->mBufferQueue->releaseBuffer(self->mCurrentBufferIndex,
|
|
||||||
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
|
|
||||||
}
|
|
||||||
self->mCurrentBufferIndex = item.mBuf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
Listener(const sp<FramebufferSurface>& that) : that(that) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
mBufferQueue->setConsumerName(String8("FramebufferSurface"));
|
BufferQueue::BufferItem item;
|
||||||
mBufferQueue->consumerConnect(new Listener(this));
|
status_t err = acquireBufferLocked(&item);
|
||||||
|
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
|
||||||
|
if (buffer != NULL) {
|
||||||
|
*buffer = mCurrentBuffer;
|
||||||
|
}
|
||||||
|
return NO_ERROR;
|
||||||
|
} else if (err != NO_ERROR) {
|
||||||
|
ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the BufferQueue has freed and reallocated a buffer in mCurrentSlot
|
||||||
|
// then we may have acquired the slot we already own. If we had released
|
||||||
|
// our current buffer before we call acquireBuffer then that release call
|
||||||
|
// would have returned STALE_BUFFER_SLOT, and we would have called
|
||||||
|
// freeBufferLocked on that slot. Because the buffer slot has already
|
||||||
|
// been overwritten with the new buffer all we have to do is skip the
|
||||||
|
// releaseBuffer call and we should be in the same state we'd be in if we
|
||||||
|
// had released the old buffer first.
|
||||||
|
if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT &&
|
||||||
|
item.mBuf != mCurrentBufferSlot) {
|
||||||
|
// Release the previous buffer.
|
||||||
|
err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY,
|
||||||
|
EGL_NO_SYNC_KHR, Fence::NO_FENCE);
|
||||||
|
if (err != NO_ERROR && err != BufferQueue::STALE_BUFFER_SLOT) {
|
||||||
|
ALOGE("error releasing buffer: %s (%d)", strerror(-err), err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentBufferSlot = item.mBuf;
|
||||||
|
mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
|
||||||
|
if (item.mFence != NULL) {
|
||||||
|
item.mFence->wait(Fence::TIMEOUT_NEVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer != NULL) {
|
||||||
|
*buffer = mCurrentBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
FramebufferSurface::~FramebufferSurface() {
|
FramebufferSurface::~FramebufferSurface() {
|
||||||
@ -157,6 +152,29 @@ FramebufferSurface::~FramebufferSurface() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FramebufferSurface::onFrameAvailable() {
|
||||||
|
// XXX: The following code is here temporarily as part of the transition
|
||||||
|
// away from the framebuffer HAL.
|
||||||
|
sp<GraphicBuffer> buf;
|
||||||
|
status_t err = nextBuffer(&buf);
|
||||||
|
if (err != NO_ERROR) {
|
||||||
|
ALOGE("error latching next FramebufferSurface buffer: %s (%d)",
|
||||||
|
strerror(-err), err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
err = fbDev->post(fbDev, buf->handle);
|
||||||
|
if (err != NO_ERROR) {
|
||||||
|
ALOGE("error posting framebuffer: %d", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramebufferSurface::freeBufferLocked(int slotIndex) {
|
||||||
|
ConsumerBase::freeBufferLocked(slotIndex);
|
||||||
|
if (slotIndex == mCurrentBufferSlot) {
|
||||||
|
mCurrentBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float FramebufferSurface::getRefreshRate() const {
|
float FramebufferSurface::getRefreshRate() const {
|
||||||
/* FIXME: REFRESH_RATE is a temporary HACK until we are able to report the
|
/* FIXME: REFRESH_RATE is a temporary HACK until we are able to report the
|
||||||
* refresh rate properly from the HAL. The WindowManagerService now relies
|
* refresh rate properly from the HAL. The WindowManagerService now relies
|
||||||
@ -172,10 +190,7 @@ float FramebufferSurface::getRefreshRate() const {
|
|||||||
|
|
||||||
status_t FramebufferSurface::setUpdateRectangle(const Rect& r)
|
status_t FramebufferSurface::setUpdateRectangle(const Rect& r)
|
||||||
{
|
{
|
||||||
if (!mUpdateOnDemand) {
|
return INVALID_OPERATION;
|
||||||
return INVALID_OPERATION;
|
|
||||||
}
|
|
||||||
return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t FramebufferSurface::compositionComplete()
|
status_t FramebufferSurface::compositionComplete()
|
||||||
@ -190,38 +205,10 @@ void FramebufferSurface::dump(String8& result) {
|
|||||||
if (fbDev->common.version >= 1 && fbDev->dump) {
|
if (fbDev->common.version >= 1 && fbDev->dump) {
|
||||||
const size_t SIZE = 4096;
|
const size_t SIZE = 4096;
|
||||||
char buffer[SIZE];
|
char buffer[SIZE];
|
||||||
|
|
||||||
fbDev->dump(fbDev, buffer, SIZE);
|
fbDev->dump(fbDev, buffer, SIZE);
|
||||||
result.append(buffer);
|
result.append(buffer);
|
||||||
}
|
}
|
||||||
}
|
ConsumerBase::dump(result);
|
||||||
|
|
||||||
int FramebufferSurface::query(int what, int* value) const {
|
|
||||||
Mutex::Autolock _l(mLock);
|
|
||||||
framebuffer_device_t* fb = fbDev;
|
|
||||||
switch (what) {
|
|
||||||
case NATIVE_WINDOW_DEFAULT_WIDTH:
|
|
||||||
case NATIVE_WINDOW_WIDTH:
|
|
||||||
*value = fb->width;
|
|
||||||
return NO_ERROR;
|
|
||||||
case NATIVE_WINDOW_DEFAULT_HEIGHT:
|
|
||||||
case NATIVE_WINDOW_HEIGHT:
|
|
||||||
*value = fb->height;
|
|
||||||
return NO_ERROR;
|
|
||||||
case NATIVE_WINDOW_FORMAT:
|
|
||||||
*value = fb->format;
|
|
||||||
return NO_ERROR;
|
|
||||||
case NATIVE_WINDOW_CONCRETE_TYPE:
|
|
||||||
*value = NATIVE_WINDOW_FRAMEBUFFER;
|
|
||||||
return NO_ERROR;
|
|
||||||
case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
|
|
||||||
*value = 0;
|
|
||||||
return NO_ERROR;
|
|
||||||
case NATIVE_WINDOW_TRANSFORM_HINT:
|
|
||||||
*value = 0;
|
|
||||||
return NO_ERROR;
|
|
||||||
}
|
|
||||||
return SurfaceTextureClient::query(what, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -20,9 +20,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <EGL/egl.h>
|
#include <gui/ConsumerBase.h>
|
||||||
|
|
||||||
#include <gui/SurfaceTextureClient.h>
|
|
||||||
|
|
||||||
#define NUM_FRAME_BUFFERS 2
|
#define NUM_FRAME_BUFFERS 2
|
||||||
|
|
||||||
@ -35,7 +33,7 @@ class String8;
|
|||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
class FramebufferSurface : public SurfaceTextureClient {
|
class FramebufferSurface : public ConsumerBase {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static sp<FramebufferSurface> create();
|
static sp<FramebufferSurface> create();
|
||||||
@ -43,28 +41,34 @@ public:
|
|||||||
// TODO: this should be coming from HWC
|
// TODO: this should be coming from HWC
|
||||||
float getRefreshRate() const;
|
float getRefreshRate() const;
|
||||||
|
|
||||||
bool isUpdateOnDemand() const { return mUpdateOnDemand; }
|
bool isUpdateOnDemand() const { return false; }
|
||||||
status_t setUpdateRectangle(const Rect& updateRect);
|
status_t setUpdateRectangle(const Rect& updateRect);
|
||||||
status_t compositionComplete();
|
status_t compositionComplete();
|
||||||
|
|
||||||
void dump(String8& result);
|
virtual void dump(String8& result);
|
||||||
|
|
||||||
protected:
|
// nextBuffer waits for and then latches the next buffer from the
|
||||||
virtual void onFirstRef();
|
// BufferQueue and releases the previously latched buffer to the
|
||||||
|
// BufferQueue. The new buffer is returned in the 'buffer' argument.
|
||||||
|
status_t nextBuffer(sp<GraphicBuffer>* buffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FramebufferSurface();
|
FramebufferSurface();
|
||||||
virtual ~FramebufferSurface(); // this class cannot be overloaded
|
virtual ~FramebufferSurface(); // this class cannot be overloaded
|
||||||
virtual int query(int what, int* value) const;
|
|
||||||
|
virtual void onFrameAvailable();
|
||||||
|
virtual void freeBufferLocked(int slotIndex);
|
||||||
|
|
||||||
framebuffer_device_t* fbDev;
|
framebuffer_device_t* fbDev;
|
||||||
|
|
||||||
sp<BufferQueue> mBufferQueue;
|
// mCurrentBufferIndex is the slot index of the current buffer or
|
||||||
int mCurrentBufferIndex;
|
// INVALID_BUFFER_SLOT to indicate that either there is no current buffer
|
||||||
sp<GraphicBuffer> mBuffers[NUM_FRAME_BUFFERS];
|
// or the buffer is not associated with a slot.
|
||||||
|
int mCurrentBufferSlot;
|
||||||
|
|
||||||
mutable Mutex mLock;
|
// mCurrentBuffer is the current buffer or NULL to indicate that there is
|
||||||
bool mUpdateOnDemand;
|
// no current buffer.
|
||||||
|
sp<GraphicBuffer> mCurrentBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
@ -42,6 +42,7 @@ namespace android {
|
|||||||
|
|
||||||
class GraphicBuffer;
|
class GraphicBuffer;
|
||||||
class LayerBase;
|
class LayerBase;
|
||||||
|
class Region;
|
||||||
class String8;
|
class String8;
|
||||||
class SurfaceFlinger;
|
class SurfaceFlinger;
|
||||||
|
|
||||||
|
@ -34,8 +34,9 @@
|
|||||||
|
|
||||||
#include <ui/DisplayInfo.h>
|
#include <ui/DisplayInfo.h>
|
||||||
|
|
||||||
#include <gui/IDisplayEventConnection.h>
|
|
||||||
#include <gui/BitTube.h>
|
#include <gui/BitTube.h>
|
||||||
|
#include <gui/BufferQueue.h>
|
||||||
|
#include <gui/IDisplayEventConnection.h>
|
||||||
#include <gui/SurfaceTextureClient.h>
|
#include <gui/SurfaceTextureClient.h>
|
||||||
|
|
||||||
#include <ui/GraphicBufferAllocator.h>
|
#include <ui/GraphicBufferAllocator.h>
|
||||||
@ -351,22 +352,24 @@ status_t SurfaceFlinger::readyToRun()
|
|||||||
|
|
||||||
// Initialize the main display
|
// Initialize the main display
|
||||||
// create native window to main display
|
// create native window to main display
|
||||||
sp<FramebufferSurface> anw = FramebufferSurface::create();
|
sp<FramebufferSurface> fbs = FramebufferSurface::create();
|
||||||
ANativeWindow* const window = anw.get();
|
if (fbs == NULL) {
|
||||||
if (!window) {
|
|
||||||
ALOGE("Display subsystem failed to initialize. check logs. exiting...");
|
ALOGE("Display subsystem failed to initialize. check logs. exiting...");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sp<SurfaceTextureClient> stc(new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >(fbs->getBufferQueue())));
|
||||||
|
|
||||||
// initialize the config and context
|
// initialize the config and context
|
||||||
int format;
|
int format;
|
||||||
window->query(window, NATIVE_WINDOW_FORMAT, &format);
|
ANativeWindow* const anw = stc.get();
|
||||||
|
anw->query(anw, NATIVE_WINDOW_FORMAT, &format);
|
||||||
mEGLConfig = selectEGLConfig(mEGLDisplay, format);
|
mEGLConfig = selectEGLConfig(mEGLDisplay, format);
|
||||||
mEGLContext = createGLContext(mEGLDisplay, mEGLConfig);
|
mEGLContext = createGLContext(mEGLDisplay, mEGLConfig);
|
||||||
|
|
||||||
// initialize our main display hardware
|
// initialize our main display hardware
|
||||||
mCurrentState.displays.add(DisplayDevice::DISPLAY_ID_MAIN, DisplayDeviceState());
|
mCurrentState.displays.add(DisplayDevice::DISPLAY_ID_MAIN, DisplayDeviceState());
|
||||||
sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_ID_MAIN, anw, mEGLConfig);
|
sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_ID_MAIN, anw, fbs, mEGLConfig);
|
||||||
mDisplays.add(DisplayDevice::DISPLAY_ID_MAIN, hw);
|
mDisplays.add(DisplayDevice::DISPLAY_ID_MAIN, hw);
|
||||||
|
|
||||||
// initialize OpenGL ES
|
// initialize OpenGL ES
|
||||||
@ -868,7 +871,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
|
|||||||
for (size_t i=0 ; i<cc ; i++) {
|
for (size_t i=0 ; i<cc ; i++) {
|
||||||
if (mDrawingState.displays.indexOfKey(curr[i].id) < 0) {
|
if (mDrawingState.displays.indexOfKey(curr[i].id) < 0) {
|
||||||
// FIXME: we need to pass the surface here
|
// FIXME: we need to pass the surface here
|
||||||
sp<DisplayDevice> disp = new DisplayDevice(this, curr[i].id, 0, mEGLConfig);
|
sp<DisplayDevice> disp = new DisplayDevice(this, curr[i].id, 0, 0, mEGLConfig);
|
||||||
mDisplays.add(curr[i].id, disp);
|
mDisplays.add(curr[i].id, disp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user