Merge "docs: OpenGL ES 1.0 and 2.0 Tutorials"
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index 5b5b731..50626a0 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -51,7 +51,7 @@
// the given slot index, and the client is expected to mirror the
// slot->buffer mapping so that it's not necessary to transfer a
// GraphicBuffer for every dequeue operation.
- virtual sp<GraphicBuffer> requestBuffer(int slot) = 0;
+ virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0;
// setBufferCount sets the number of buffer slots available. Calling this
// will also cause all buffer slots to be emptied. The caller should empty
@@ -78,7 +78,12 @@
// client for this buffer. The timestamp is measured in nanoseconds, and
// must be monotonically increasing. Its other properties (zero point, etc)
// are client-dependent, and should be documented by the client.
- virtual status_t queueBuffer(int slot, int64_t timestamp) = 0;
+ //
+ // outWidth, outHeight and outTransform are filled with the default width
+ // and height of the window and current transform applied to buffers,
+ // respectively.
+ virtual status_t queueBuffer(int slot, int64_t timestamp,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) = 0;
// cancelBuffer indicates that the client does not wish to fill in the
// buffer associated with slot and transfers ownership of the slot back to
@@ -87,12 +92,7 @@
virtual status_t setCrop(const Rect& reg) = 0;
virtual status_t setTransform(uint32_t transform) = 0;
-
- // getAllocator retrieves the binder object that must be referenced as long
- // as the GraphicBuffers dequeued from this ISurfaceTexture are referenced.
- // Holding this binder reference prevents SurfaceFlinger from freeing the
- // buffers before the client is done with them.
- virtual sp<IBinder> getAllocator() = 0;
+ virtual status_t setScalingMode(int mode) = 0;
// query retrieves some information for this surface
// 'what' tokens allowed are that of android_natives.h
@@ -111,7 +111,12 @@
//
// This method will fail if the connect was previously called on the
// SurfaceTexture and no corresponding disconnect call was made.
- virtual status_t connect(int api) = 0;
+ //
+ // outWidth, outHeight and outTransform are filled with the default width
+ // and height of the window and current transform applied to buffers,
+ // respectively.
+ virtual status_t connect(int api,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) = 0;
// disconnect attempts to disconnect a client API from the SurfaceTexture.
// Calling this method will cause any subsequent calls to other
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 4080f27..a6fb12e 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -69,7 +69,7 @@
// SurfaceTexture object (i.e. they are not owned by the client).
virtual status_t setBufferCount(int bufferCount);
- virtual sp<GraphicBuffer> requestBuffer(int buf);
+ virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
// dequeueBuffer gets the next buffer slot index for the client to use. If a
// buffer slot is available then that slot index is written to the location
@@ -84,10 +84,12 @@
// nanoseconds, and must be monotonically increasing. Its other semantics
// (zero point, etc) are client-dependent and should be documented by the
// client.
- virtual status_t queueBuffer(int buf, int64_t timestamp);
+ virtual status_t queueBuffer(int buf, int64_t timestamp,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
virtual void cancelBuffer(int buf);
virtual status_t setCrop(const Rect& reg);
virtual status_t setTransform(uint32_t transform);
+ virtual status_t setScalingMode(int mode);
virtual int query(int what, int* value);
@@ -104,7 +106,8 @@
//
// This method will fail if the connect was previously called on the
// SurfaceTexture and no corresponding disconnect call was made.
- virtual status_t connect(int api);
+ virtual status_t connect(int api,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
// disconnect attempts to disconnect a client API from the SurfaceTexture.
// Calling this method will cause any subsequent calls to other
@@ -185,17 +188,49 @@
// getCurrentTransform returns the transform of the current buffer
uint32_t getCurrentTransform() const;
+ // getCurrentScalingMode returns the scaling mode of the current buffer
+ uint32_t getCurrentScalingMode() const;
+
+ // abandon frees all the buffers and puts the SurfaceTexture into the
+ // 'abandoned' state. Once put in this state the SurfaceTexture 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 SurfaceTexture, 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();
+
// dump our state in a String
void dump(String8& result) const;
void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
protected:
- // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
- // all slots.
- void freeAllBuffers();
+ // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage)
+ // for the given slot.
+ void freeBufferLocked(int index);
+
+ // freeAllBuffersLocked frees the resources (both GraphicBuffer and
+ // EGLImage) for all slots.
+ void freeAllBuffersLocked();
+
+ // freeAllBuffersExceptHeadLocked frees the resources (both GraphicBuffer
+ // and EGLImage) for all slots except the head of mQueue
+ void freeAllBuffersExceptHeadLocked();
+
+ // drainQueueLocked drains the buffer queue if we're in synchronous mode
+ // returns immediately otherwise. return NO_INIT if SurfaceTexture
+ // became abandoned or disconnected during this 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 current buffer.
+ status_t drainQueueAndFreeBuffersLocked();
+
static bool isExternalFormat(uint32_t format);
- static GLenum getTextureTarget(uint32_t format);
private:
@@ -220,6 +255,7 @@
mBufferState(BufferSlot::FREE),
mRequestBufferCalled(false),
mTransform(0),
+ mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mTimestamp(0) {
mCrop.makeInvalid();
}
@@ -281,6 +317,11 @@
// slot.
uint32_t mTransform;
+ // mScalingMode is the current scaling mode for this buffer slot. This
+ // gets set to mNextScalingMode each time queueBuffer gets called for
+ // this slot.
+ uint32_t mScalingMode;
+
// mTimestamp is the current timestamp for this buffer slot. This gets
// to set by queueBuffer each time this slot is queued.
int64_t mTimestamp;
@@ -326,31 +367,30 @@
// reset mCurrentTexture to INVALID_BUFFER_SLOT.
int mCurrentTexture;
- // mCurrentTextureTarget is the GLES texture target to be used with the
- // current texture.
- GLenum mCurrentTextureTarget;
-
// mCurrentTextureBuf is the graphic buffer of the current texture. It's
// possible that this buffer is not associated with any buffer slot, so we
- // must track it separately in order to properly use
- // IGraphicBufferAlloc::freeAllGraphicBuffersExcept.
+ // must track it separately in order to support the getCurrentBuffer method.
sp<GraphicBuffer> mCurrentTextureBuf;
// mCurrentCrop is the crop rectangle that applies to the current texture.
- // It gets set to mLastQueuedCrop each time updateTexImage is called.
+ // It gets set each time updateTexImage is called.
Rect mCurrentCrop;
// mCurrentTransform is the transform identifier for the current texture. It
- // gets set to mLastQueuedTransform each time updateTexImage is called.
+ // gets set each time updateTexImage is called.
uint32_t mCurrentTransform;
+ // mCurrentScalingMode is the scaling mode for the current texture. It gets
+ // set to each time updateTexImage is called.
+ uint32_t mCurrentScalingMode;
+
// mCurrentTransformMatrix is the transform matrix for the current texture.
// It gets computed by computeTransformMatrix each time updateTexImage is
// called.
float mCurrentTransformMatrix[16];
// mCurrentTimestamp is the timestamp for the current texture. It
- // gets set to mLastQueuedTimestamp each time updateTexImage is called.
+ // gets set each time updateTexImage is called.
int64_t mCurrentTimestamp;
// mNextCrop is the crop rectangle that will be used for the next buffer
@@ -361,6 +401,10 @@
// buffer that gets queued. It is set by calling setTransform.
uint32_t mNextTransform;
+ // mNextScalingMode is the scaling mode that will be used for the next
+ // buffers that get queued. It is set by calling setScalingMode.
+ int mNextScalingMode;
+
// mTexName is the name of the OpenGL texture to which streamed images will
// be bound when updateTexImage is called. It is set at construction time
// changed with a call to setTexName.
@@ -393,6 +437,13 @@
typedef Vector<int> Fifo;
Fifo mQueue;
+ // mAbandoned indicates that the SurfaceTexture 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
+ // SurfaceTexture that has been abandoned will return the NO_INIT error from
+ // all ISurfaceTexture methods capable of returning an error.
+ bool mAbandoned;
+
// mMutex is the mutex used to prevent concurrent access to the member
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 5ec469e..57f9e15 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -21,6 +21,7 @@
#include <gui/SurfaceTexture.h>
#include <ui/egl/android_natives.h>
+#include <ui/Region.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
@@ -37,29 +38,24 @@
sp<ISurfaceTexture> getISurfaceTexture() const;
-private:
- friend class Surface;
+protected:
+ SurfaceTextureClient();
+ void setISurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture);
+private:
// can't be copied
SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
SurfaceTextureClient(const SurfaceTextureClient& rhs);
+ void init();
// ANativeWindow hooks
- static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
- static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int perform(ANativeWindow* window, int operation, ...);
- static int query(const ANativeWindow* window, int what, int* value);
- static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int setSwapInterval(ANativeWindow* window, int interval);
-
- int cancelBuffer(ANativeWindowBuffer* buffer);
- int dequeueBuffer(ANativeWindowBuffer** buffer);
- int lockBuffer(ANativeWindowBuffer* buffer);
- int perform(int operation, va_list args);
- int query(int what, int* value) const;
- int queueBuffer(ANativeWindowBuffer* buffer);
- int setSwapInterval(int interval);
+ static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+ static int hook_lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_perform(ANativeWindow* window, int operation, ...);
+ static int hook_query(const ANativeWindow* window, int what, int* value);
+ static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_setSwapInterval(ANativeWindow* window, int interval);
int dispatchConnect(va_list args);
int dispatchDisconnect(va_list args);
@@ -67,39 +63,49 @@
int dispatchSetBuffersGeometry(va_list args);
int dispatchSetBuffersDimensions(va_list args);
int dispatchSetBuffersFormat(va_list args);
+ int dispatchSetScalingMode(va_list args);
int dispatchSetBuffersTransform(va_list args);
int dispatchSetBuffersTimestamp(va_list args);
int dispatchSetCrop(va_list args);
int dispatchSetUsage(va_list args);
+ int dispatchLock(va_list args);
+ int dispatchUnlockAndPost(va_list args);
- int connect(int api);
- int disconnect(int api);
- int setBufferCount(int bufferCount);
- int setBuffersDimensions(int w, int h);
- int setBuffersFormat(int format);
- int setBuffersTransform(int transform);
- int setBuffersTimestamp(int64_t timestamp);
- int setCrop(Rect const* rect);
- int setUsage(uint32_t reqUsage);
+protected:
+ virtual int cancelBuffer(ANativeWindowBuffer* buffer);
+ virtual int dequeueBuffer(ANativeWindowBuffer** buffer);
+ virtual int lockBuffer(ANativeWindowBuffer* buffer);
+ virtual int perform(int operation, va_list args);
+ virtual int query(int what, int* value) const;
+ virtual int queueBuffer(ANativeWindowBuffer* buffer);
+ virtual int setSwapInterval(int interval);
- void freeAllBuffers();
- int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
-
- int getConnectedApi() const;
+ virtual int connect(int api);
+ virtual int disconnect(int api);
+ virtual int setBufferCount(int bufferCount);
+ virtual int setBuffersDimensions(int w, int h);
+ virtual int setBuffersFormat(int format);
+ virtual int setScalingMode(int mode);
+ virtual int setBuffersTransform(int transform);
+ virtual int setBuffersTimestamp(int64_t timestamp);
+ virtual int setCrop(Rect const* rect);
+ virtual int setUsage(uint32_t reqUsage);
+ virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
+ virtual int unlockAndPost();
enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
+private:
+ void freeAllBuffers();
+ int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
+
// mSurfaceTexture is the interface to the surface texture server. All
// operations on the surface texture client ultimately translate into
// interactions with the server using this interface.
sp<ISurfaceTexture> mSurfaceTexture;
- // mAllocator is the binder object that is referenced to prevent the
- // dequeued buffers from being freed prematurely.
- sp<IBinder> mAllocator;
-
// mSlots stores the buffers that have been allocated for each buffer slot.
// It is initialized to null pointers, and gets filled in with the result of
// ISurfaceTexture::requestBuffer when the client dequeues a buffer from a
@@ -129,22 +135,28 @@
// a timestamp is auto-generated when queueBuffer is called.
int64_t mTimestamp;
- // mQueryWidth is the width returned by query(). It is set to width
- // of the last dequeued buffer or to mReqWidth if no buffer was dequeued.
- uint32_t mQueryWidth;
+ // mDefaultWidth is default width of the window, regardless of the
+ // native_window_set_buffers_dimensions call
+ uint32_t mDefaultWidth;
- // mQueryHeight is the height returned by query(). It is set to height
- // of the last dequeued buffer or to mReqHeight if no buffer was dequeued.
- uint32_t mQueryHeight;
+ // mDefaultHeight is default width of the window, regardless of the
+ // native_window_set_buffers_dimensions call
+ uint32_t mDefaultHeight;
- // mQueryFormat is the format returned by query(). It is set to the last
- // dequeued format or to mReqFormat if no buffer was dequeued.
- uint32_t mQueryFormat;
+ // mTransformHint is the transform probably applied to buffers of this
+ // window. this is only a hint, actual transform may differ.
+ uint32_t mTransformHint;
// mMutex is the mutex used to prevent concurrent access to the member
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
mutable Mutex mMutex;
+
+ // must be used from the lock/unlock thread
+ sp<GraphicBuffer> mLockedBuffer;
+ sp<GraphicBuffer> mPostedBuffer;
+ mutable Region mOldDirtyRegion;
+ bool mConnectedToCpu;
};
}; // namespace android
diff --git a/include/surfaceflinger/ISurfaceComposerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h
index 6e9a654..02cabc1 100644
--- a/include/surfaceflinger/ISurfaceComposerClient.h
+++ b/include/surfaceflinger/ISurfaceComposerClient.h
@@ -45,9 +45,6 @@
struct surface_data_t {
int32_t token;
int32_t identity;
- uint32_t width;
- uint32_t height;
- uint32_t format;
status_t readFromParcel(const Parcel& parcel);
status_t writeToParcel(Parcel* parcel) const;
};
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index dc2a845..0460bbd 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -28,6 +28,8 @@
#include <ui/Region.h>
#include <ui/egl/android_natives.h>
+#include <gui/SurfaceTextureClient.h>
+
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/ISurfaceComposerClient.h>
@@ -37,14 +39,9 @@
// ---------------------------------------------------------------------------
-class GraphicBuffer;
-class GraphicBufferMapper;
-class IOMX;
class ISurfaceTexture;
-class Rect;
class Surface;
class SurfaceComposerClient;
-class SurfaceTextureClient;
// ---------------------------------------------------------------------------
@@ -60,7 +57,6 @@
static bool isSameSurface(
const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
- uint32_t getFlags() const { return mFlags; }
uint32_t getIdentity() const { return mIdentity; }
// release surface data from java
@@ -89,25 +85,13 @@
SurfaceControl& operator = (SurfaceControl& rhs);
SurfaceControl(const SurfaceControl& rhs);
-
friend class SurfaceComposerClient;
-
- // camera and camcorder need access to the ISurface binder interface for preview
- friend class CameraService;
- friend class MediaRecorder;
- // mediaplayer needs access to ISurface for display
- friend class MediaPlayer;
- // for testing
- friend class Test;
- // videoEditor preview classes
- friend class VideoEditorPreviewController;
friend class Surface;
SurfaceControl(
const sp<SurfaceComposerClient>& client,
const sp<ISurface>& surface,
- const ISurfaceComposerClient::surface_data_t& data,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+ const ISurfaceComposerClient::surface_data_t& data);
~SurfaceControl();
@@ -118,10 +102,6 @@
sp<ISurface> mSurface;
SurfaceID mToken;
uint32_t mIdentity;
- uint32_t mWidth;
- uint32_t mHeight;
- PixelFormat mFormat;
- uint32_t mFlags;
mutable Mutex mLock;
mutable sp<Surface> mSurfaceData;
@@ -129,8 +109,7 @@
// ---------------------------------------------------------------------------
-class Surface
- : public EGLNativeBase<ANativeWindow, Surface, RefBase>
+class Surface : public SurfaceTextureClient
{
public:
struct SurfaceInfo {
@@ -143,112 +122,50 @@
uint32_t reserved[2];
};
- static status_t writeToParcel(
- const sp<Surface>& control, Parcel* parcel);
+ explicit Surface(const sp<ISurfaceTexture>& st);
+
+ static status_t writeToParcel(const sp<Surface>& control, Parcel* parcel);
static sp<Surface> readFromParcel(const Parcel& data);
-
static bool isValid(const sp<Surface>& surface) {
return (surface != 0) && surface->isValid();
}
bool isValid();
- uint32_t getFlags() const { return mFlags; }
uint32_t getIdentity() const { return mIdentity; }
sp<ISurfaceTexture> getSurfaceTexture();
// the lock/unlock APIs must be used from the same thread
- status_t lock(SurfaceInfo* info, bool blocking = true);
- status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
+ status_t lock(SurfaceInfo* info, Region* dirty = NULL);
status_t unlockAndPost();
sp<IBinder> asBinder() const;
private:
- /*
- * Android frameworks friends
- * (eventually this should go away and be replaced by proper APIs)
- */
- // camera and camcorder need access to the ISurface binder interface for preview
- friend class CameraService;
- friend class MediaRecorder;
- // MediaPlayer needs access to ISurface for display
- friend class MediaPlayer;
- friend class IOMX;
- friend class SoftwareRenderer;
// this is just to be able to write some unit tests
friend class Test;
- // videoEditor preview classes
- friend class VideoEditorPreviewController;
- friend class PreviewRenderer;
-
-private:
- friend class SurfaceComposerClient;
friend class SurfaceControl;
// can't be copied
Surface& operator = (Surface& rhs);
Surface(const Surface& rhs);
- Surface(const sp<SurfaceControl>& control);
+ explicit Surface(const sp<SurfaceControl>& control);
Surface(const Parcel& data, const sp<IBinder>& ref);
~Surface();
-
- /*
- * ANativeWindow hooks
- */
- static int setSwapInterval(ANativeWindow* window, int interval);
- static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
- static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int query(const ANativeWindow* window, int what, int* value);
- static int perform(ANativeWindow* window, int operation, ...);
-
- int setSwapInterval(int interval);
- int dequeueBuffer(ANativeWindowBuffer** buffer);
- int lockBuffer(ANativeWindowBuffer* buffer);
- int queueBuffer(ANativeWindowBuffer* buffer);
- int cancelBuffer(ANativeWindowBuffer* buffer);
- int query(int what, int* value) const;
- int perform(int operation, va_list args);
-
/*
* private stuff...
*/
- void init();
- status_t validate(bool inCancelBuffer = false) const;
+ void init(const sp<ISurfaceTexture>& surfaceTexture);
- int getConnectedApi() const;
-
static void cleanCachedSurfacesLocked();
+ virtual int query(int what, int* value) const;
+
// constants
- status_t mInitCheck;
sp<ISurface> mSurface;
- sp<SurfaceTextureClient> mSurfaceTextureClient;
uint32_t mIdentity;
- PixelFormat mFormat;
- uint32_t mFlags;
-
- // protected by mSurfaceLock. These are also used from lock/unlock
- // but in that case, they must be called form the same thread.
- mutable Region mDirtyRegion;
-
- // must be used from the lock/unlock thread
- sp<GraphicBuffer> mLockedBuffer;
- sp<GraphicBuffer> mPostedBuffer;
- mutable Region mOldDirtyRegion;
- bool mReserved;
-
- // query() must be called from dequeueBuffer() thread
- uint32_t mWidth;
- uint32_t mHeight;
-
- // Inherently thread-safe
- mutable Mutex mSurfaceLock;
- mutable Mutex mApiLock;
// A cache of Surface objects that have been deserialized into this process.
static Mutex sCachedSurfacesLock;
diff --git a/include/ui/Input.h b/include/ui/Input.h
index c9f694a..f1385a0 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -206,10 +206,17 @@
float getAxisValue(int32_t axis) const;
status_t setAxisValue(int32_t axis, float value);
- float* editAxisValue(int32_t axis);
void scale(float scale);
+ inline float getX() const {
+ return getAxisValue(AMOTION_EVENT_AXIS_X);
+ }
+
+ inline float getY() const {
+ return getAxisValue(AMOTION_EVENT_AXIS_Y);
+ }
+
#ifdef HAVE_ANDROID_OS
status_t readFromParcel(Parcel* parcel);
status_t writeToParcel(Parcel* parcel) const;
diff --git a/include/ui/PixelFormat.h b/include/ui/PixelFormat.h
index f46f25c..848c5a1 100644
--- a/include/ui/PixelFormat.h
+++ b/include/ui/PixelFormat.h
@@ -55,7 +55,7 @@
PIXEL_FORMAT_OPAQUE = -1,
// System chooses an opaque format (no alpha bits required)
-
+
// real pixel formats supported for rendering -----------------------------
PIXEL_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, // 4x8-bit RGBA
@@ -84,7 +84,7 @@
INDEX_GREEN = 2,
INDEX_BLUE = 3
};
-
+
enum { // components
ALPHA = 1,
RGB = 2,
@@ -98,10 +98,10 @@
uint8_t h;
uint8_t l;
};
-
+
inline PixelFormatInfo() : version(sizeof(PixelFormatInfo)) { }
size_t getScanlineSize(unsigned int width) const;
- size_t getSize(size_t ci) const {
+ size_t getSize(size_t ci) const {
return (ci <= 3) ? (cinfo[ci].h - cinfo[ci].l) : 0;
}
size_t version;
@@ -112,7 +112,7 @@
szinfo cinfo[4];
struct {
uint8_t h_alpha;
- uint8_t l_alpha;
+ uint8_t l_alpha;
uint8_t h_red;
uint8_t l_red;
uint8_t h_green;
diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h
index 600017e..9452e86 100644
--- a/include/utils/BitSet.h
+++ b/include/utils/BitSet.h
@@ -68,6 +68,30 @@
// Result is undefined if all bits are unmarked.
inline uint32_t lastMarkedBit() const { return 31 - __builtin_ctz(value); }
+ // Finds the first marked bit in the set and clears it. Returns the bit index.
+ // Result is undefined if all bits are unmarked.
+ inline uint32_t clearFirstMarkedBit() {
+ uint32_t n = firstMarkedBit();
+ clearBit(n);
+ return n;
+ }
+
+ // Finds the first unmarked bit in the set and marks it. Returns the bit index.
+ // Result is undefined if all bits are marked.
+ inline uint32_t markFirstUnmarkedBit() {
+ uint32_t n = firstUnmarkedBit();
+ markBit(n);
+ return n;
+ }
+
+ // Finds the last marked bit in the set and clears it. Returns the bit index.
+ // Result is undefined if all bits are unmarked.
+ inline uint32_t clearLastMarkedBit() {
+ uint32_t n = lastMarkedBit();
+ clearBit(n);
+ return n;
+ }
+
// Gets the index of the specified bit in the set, which is the number of
// marked bits that appear before the specified bit.
inline uint32_t getIndexOfBit(uint32_t n) const {
diff --git a/include/utils/Pool.h b/include/utils/Pool.h
deleted file mode 100644
index 2ee768e..0000000
--- a/include/utils/Pool.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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 UTILS_POOL_H
-#define UTILS_POOL_H
-
-#include <utils/TypeHelpers.h>
-
-namespace android {
-
-class PoolImpl {
-public:
- PoolImpl(size_t objSize);
- ~PoolImpl();
-
- void* allocImpl();
- void freeImpl(void* obj);
-
-private:
- size_t mObjSize;
-};
-
-/*
- * A homogeneous typed memory pool for fixed size objects.
- * Not intended to be thread-safe.
- */
-template<typename T>
-class Pool : private PoolImpl {
-public:
- /* Creates an initially empty pool. */
- Pool() : PoolImpl(sizeof(T)) { }
-
- /* Destroys the pool.
- * Assumes that the pool is empty. */
- ~Pool() { }
-
- /* Allocates an object from the pool, growing the pool if needed. */
- inline T* alloc() {
- void* mem = allocImpl();
- if (! traits<T>::has_trivial_ctor) {
- return new (mem) T();
- } else {
- return static_cast<T*>(mem);
- }
- }
-
- /* Frees an object from the pool. */
- inline void free(T* obj) {
- if (! traits<T>::has_trivial_dtor) {
- obj->~T();
- }
- freeImpl(obj);
- }
-};
-
-} // namespace android
-
-#endif // UTILS_POOL_H
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index ca17082..c7a9b78 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -80,9 +80,12 @@
void incWeak(const void* id);
void decWeak(const void* id);
+ // acquires a strong reference if there is already one.
bool attemptIncStrong(const void* id);
- //! This is only safe if you have set OBJECT_LIFETIME_FOREVER.
+ // acquires a weak reference if there is already one.
+ // This is not always safe. see ProcessState.cpp and BpBinder.cpp
+ // for proper use.
bool attemptIncWeak(const void* id);
//! DEBUGGING ONLY: Get current weak ref count.
@@ -116,28 +119,15 @@
typedef RefBase basetype;
- // used to override the RefBase destruction.
- class Destroyer {
- friend class RefBase;
- friend class weakref_type;
- public:
- virtual ~Destroyer();
- private:
- virtual void destroy(RefBase const* base) = 0;
- };
-
- // Make sure to never acquire a strong reference from this function. The
- // same restrictions than for destructors apply.
- void setDestroyer(Destroyer* destroyer);
-
protected:
RefBase();
virtual ~RefBase();
//! Flags for extendObjectLifetime()
enum {
+ OBJECT_LIFETIME_STRONG = 0x0000,
OBJECT_LIFETIME_WEAK = 0x0001,
- OBJECT_LIFETIME_FOREVER = 0x0003
+ OBJECT_LIFETIME_MASK = 0x0001
};
void extendObjectLifetime(int32_t mode);
@@ -163,7 +153,7 @@
RefBase(const RefBase& o);
RefBase& operator=(const RefBase& o);
-
+
weakref_impl* const mRefs;
};
diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h
index 3a99979..547e36a 100644
--- a/include/utils/ZipFileRO.h
+++ b/include/utils/ZipFileRO.h
@@ -38,6 +38,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <time.h>
namespace android {
@@ -174,6 +175,20 @@
size_t uncompLen, size_t compLen);
/*
+ * Utility function to convert ZIP's time format to a timespec struct.
+ */
+ static inline void zipTimeToTimespec(long when, struct tm* timespec) {
+ const long date = when >> 16;
+ timespec->tm_year = ((date >> 9) & 0x7F) + 80; // Zip is years since 1980
+ timespec->tm_mon = (date >> 5) & 0x0F;
+ timespec->tm_mday = date & 0x1F;
+
+ timespec->tm_hour = (when >> 11) & 0x1F;
+ timespec->tm_min = (when >> 5) & 0x3F;
+ timespec->tm_sec = (when & 0x1F) << 1;
+ }
+
+ /*
* Some basic functions for raw data manipulation. "LE" means
* Little Endian.
*/
diff --git a/include/utils/threads.h b/include/utils/threads.h
index c8e9c04..c84a9b4 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <time.h>
+#include <system/graphics.h>
#if defined(HAVE_PTHREADS)
# include <pthread.h>
@@ -42,8 +43,8 @@
* ** Keep in sync with android.os.Process.java **
* ***********************************************
*
- * This maps directly to the "nice" priorites we use in Android.
- * A thread priority should be chosen inverse-proportinally to
+ * This maps directly to the "nice" priorities we use in Android.
+ * A thread priority should be chosen inverse-proportionally to
* the amount of work the thread is expected to do. The more work
* a thread will do, the less favorable priority it should get so that
* it doesn't starve the system. Threads not behaving properly might
@@ -66,7 +67,7 @@
ANDROID_PRIORITY_DISPLAY = -4,
/* ui service treads might want to run at a urgent display (uncommon) */
- ANDROID_PRIORITY_URGENT_DISPLAY = -8,
+ ANDROID_PRIORITY_URGENT_DISPLAY = HAL_PRIORITY_URGENT_DISPLAY,
/* all normal audio threads */
ANDROID_PRIORITY_AUDIO = -16,
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index bc97cac..ace16aa 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -132,9 +132,6 @@
{
token = parcel.readInt32();
identity = parcel.readInt32();
- width = parcel.readInt32();
- height = parcel.readInt32();
- format = parcel.readInt32();
return NO_ERROR;
}
@@ -142,9 +139,6 @@
{
parcel->writeInt32(token);
parcel->writeInt32(identity);
- parcel->writeInt32(width);
- parcel->writeInt32(height);
- parcel->writeInt32(format);
return NO_ERROR;
}
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index 41434a4..babd2c0 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -38,11 +38,11 @@
CANCEL_BUFFER,
SET_CROP,
SET_TRANSFORM,
- GET_ALLOCATOR,
QUERY,
SET_SYNCHRONOUS_MODE,
CONNECT,
DISCONNECT,
+ SET_SCALING_MODE,
};
@@ -54,18 +54,18 @@
{
}
- virtual sp<GraphicBuffer> requestBuffer(int bufferIdx) {
+ virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(bufferIdx);
remote()->transact(REQUEST_BUFFER, data, &reply);
- sp<GraphicBuffer> buffer;
bool nonNull = reply.readInt32();
if (nonNull) {
- buffer = new GraphicBuffer();
- reply.read(*buffer);
+ *buf = new GraphicBuffer();
+ reply.read(**buf);
}
- return buffer;
+ status_t result = reply.readInt32();
+ return result;
}
virtual status_t setBufferCount(int bufferCount)
@@ -92,12 +92,16 @@
return result;
}
- virtual status_t queueBuffer(int buf, int64_t timestamp) {
+ virtual status_t queueBuffer(int buf, int64_t timestamp,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(buf);
data.writeInt64(timestamp);
remote()->transact(QUEUE_BUFFER, data, &reply);
+ *outWidth = reply.readInt32();
+ *outHeight = reply.readInt32();
+ *outTransform = reply.readInt32();
status_t result = reply.readInt32();
return result;
}
@@ -130,11 +134,13 @@
return result;
}
- virtual sp<IBinder> getAllocator() {
+ virtual status_t setScalingMode(int mode) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
- remote()->transact(GET_ALLOCATOR, data, &reply);
- return reply.readStrongBinder();
+ data.writeInt32(mode);
+ remote()->transact(SET_SCALING_MODE, data, &reply);
+ status_t result = reply.readInt32();
+ return result;
}
virtual int query(int what, int* value) {
@@ -156,11 +162,15 @@
return result;
}
- virtual status_t connect(int api) {
+ virtual status_t connect(int api,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(api);
remote()->transact(CONNECT, data, &reply);
+ *outWidth = reply.readInt32();
+ *outHeight = reply.readInt32();
+ *outTransform = reply.readInt32();
status_t result = reply.readInt32();
return result;
}
@@ -186,11 +196,13 @@
case REQUEST_BUFFER: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int bufferIdx = data.readInt32();
- sp<GraphicBuffer> buffer(requestBuffer(bufferIdx));
+ sp<GraphicBuffer> buffer;
+ int result = requestBuffer(bufferIdx, &buffer);
reply->writeInt32(buffer != 0);
if (buffer != 0) {
reply->write(*buffer);
}
+ reply->writeInt32(result);
return NO_ERROR;
} break;
case SET_BUFFER_COUNT: {
@@ -216,7 +228,12 @@
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int buf = data.readInt32();
int64_t timestamp = data.readInt64();
- status_t result = queueBuffer(buf, timestamp);
+ uint32_t outWidth, outHeight, outTransform;
+ status_t result = queueBuffer(buf, timestamp,
+ &outWidth, &outHeight, &outTransform);
+ reply->writeInt32(outWidth);
+ reply->writeInt32(outHeight);
+ reply->writeInt32(outTransform);
reply->writeInt32(result);
return NO_ERROR;
} break;
@@ -244,10 +261,11 @@
reply->writeInt32(result);
return NO_ERROR;
} break;
- case GET_ALLOCATOR: {
+ case SET_SCALING_MODE: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
- sp<IBinder> result = getAllocator();
- reply->writeStrongBinder(result);
+ int mode = data.readInt32();
+ status_t result = setScalingMode(mode);
+ reply->writeInt32(result);
return NO_ERROR;
} break;
case QUERY: {
@@ -269,7 +287,12 @@
case CONNECT: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int api = data.readInt32();
- status_t res = connect(api);
+ uint32_t outWidth, outHeight, outTransform;
+ status_t res = connect(api,
+ &outWidth, &outHeight, &outTransform);
+ reply->writeInt32(outWidth);
+ reply->writeInt32(outHeight);
+ reply->writeInt32(outTransform);
reply->writeInt32(res);
return NO_ERROR;
} break;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 9185e1e..2c70251 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -26,15 +26,12 @@
#include <utils/Log.h>
#include <utils/threads.h>
-#include <binder/IMemory.h>
#include <binder/IPCThreadState.h>
#include <gui/SurfaceTextureClient.h>
#include <ui/DisplayInfo.h>
#include <ui/GraphicBuffer.h>
-#include <ui/GraphicBufferMapper.h>
-#include <ui/GraphicLog.h>
#include <ui/Rect.h>
#include <surfaceflinger/ISurface.h>
@@ -42,63 +39,8 @@
#include <surfaceflinger/Surface.h>
#include <surfaceflinger/SurfaceComposerClient.h>
-#include <private/surfaceflinger/LayerState.h>
-
namespace android {
-// ----------------------------------------------------------------------
-
-static status_t copyBlt(
- const sp<GraphicBuffer>& dst,
- const sp<GraphicBuffer>& src,
- const Region& reg)
-{
- // src and dst with, height and format must be identical. no verification
- // is done here.
- status_t err;
- uint8_t const * src_bits = NULL;
- err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
- LOGE_IF(err, "error locking src buffer %s", strerror(-err));
-
- uint8_t* dst_bits = NULL;
- err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
- LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
-
- Region::const_iterator head(reg.begin());
- Region::const_iterator tail(reg.end());
- if (head != tail && src_bits && dst_bits) {
- const size_t bpp = bytesPerPixel(src->format);
- const size_t dbpr = dst->stride * bpp;
- const size_t sbpr = src->stride * bpp;
-
- while (head != tail) {
- const Rect& r(*head++);
- ssize_t h = r.height();
- if (h <= 0) continue;
- size_t size = r.width() * bpp;
- uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
- uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
- if (dbpr==sbpr && size==sbpr) {
- size *= h;
- h = 1;
- }
- do {
- memcpy(d, s, size);
- d += dbpr;
- s += sbpr;
- } while (--h > 0);
- }
- }
-
- if (src_bits)
- src->unlock();
-
- if (dst_bits)
- dst->unlock();
-
- return err;
-}
-
// ============================================================================
// SurfaceControl
// ============================================================================
@@ -106,12 +48,9 @@
SurfaceControl::SurfaceControl(
const sp<SurfaceComposerClient>& client,
const sp<ISurface>& surface,
- const ISurfaceComposerClient::surface_data_t& data,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+ const ISurfaceComposerClient::surface_data_t& data)
: mClient(client), mSurface(surface),
- mToken(data.token), mIdentity(data.identity),
- mWidth(data.width), mHeight(data.height), mFormat(data.format),
- mFlags(flags)
+ mToken(data.token), mIdentity(data.identity)
{
}
@@ -240,24 +179,13 @@
{
sp<ISurface> sur;
uint32_t identity = 0;
- uint32_t width = 0;
- uint32_t height = 0;
- uint32_t format = 0;
- uint32_t flags = 0;
if (SurfaceControl::isValid(control)) {
sur = control->mSurface;
identity = control->mIdentity;
- width = control->mWidth;
- height = control->mHeight;
- format = control->mFormat;
- flags = control->mFlags;
}
parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
+ parcel->writeStrongBinder(NULL); // NULL ISurfaceTexture in this case.
parcel->writeInt32(identity);
- parcel->writeInt32(width);
- parcel->writeInt32(height);
- parcel->writeInt32(format);
- parcel->writeInt32(flags);
return NO_ERROR;
}
@@ -265,7 +193,8 @@
{
Mutex::Autolock _l(mLock);
if (mSurfaceData == 0) {
- mSurfaceData = new Surface(const_cast<SurfaceControl*>(this));
+ sp<SurfaceControl> surface_control(const_cast<SurfaceControl*>(this));
+ mSurfaceData = new Surface(surface_control);
}
return mSurfaceData;
}
@@ -277,57 +206,63 @@
// ---------------------------------------------------------------------------
Surface::Surface(const sp<SurfaceControl>& surface)
- : mInitCheck(NO_INIT),
+ : SurfaceTextureClient(),
mSurface(surface->mSurface),
- mIdentity(surface->mIdentity),
- mFormat(surface->mFormat), mFlags(surface->mFlags),
- mWidth(surface->mWidth), mHeight(surface->mHeight)
+ mIdentity(surface->mIdentity)
{
- init();
+ sp<ISurfaceTexture> st;
+ if (mSurface != NULL) {
+ st = mSurface->getSurfaceTexture();
+ }
+ init(st);
}
Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
- : mInitCheck(NO_INIT)
+ : SurfaceTextureClient()
{
- mSurface = interface_cast<ISurface>(ref);
+ mSurface = interface_cast<ISurface>(ref);
+ sp<IBinder> st_binder(parcel.readStrongBinder());
+ sp<ISurfaceTexture> st;
+ if (st_binder != NULL) {
+ st = interface_cast<ISurfaceTexture>(st_binder);
+ } else if (mSurface != NULL) {
+ st = mSurface->getSurfaceTexture();
+ }
+
mIdentity = parcel.readInt32();
- mWidth = parcel.readInt32();
- mHeight = parcel.readInt32();
- mFormat = parcel.readInt32();
- mFlags = parcel.readInt32();
- init();
+ init(st);
+}
+
+Surface::Surface(const sp<ISurfaceTexture>& st)
+ : SurfaceTextureClient(),
+ mSurface(NULL),
+ mIdentity(0)
+{
+ init(st);
}
status_t Surface::writeToParcel(
const sp<Surface>& surface, Parcel* parcel)
{
sp<ISurface> sur;
+ sp<ISurfaceTexture> st;
uint32_t identity = 0;
- uint32_t width = 0;
- uint32_t height = 0;
- uint32_t format = 0;
- uint32_t flags = 0;
if (Surface::isValid(surface)) {
sur = surface->mSurface;
+ st = surface->getISurfaceTexture();
identity = surface->mIdentity;
- width = surface->mWidth;
- height = surface->mHeight;
- format = surface->mFormat;
- flags = surface->mFlags;
- } else if (surface != 0 && surface->mSurface != 0) {
- LOGW("Parceling invalid surface with non-NULL ISurface as NULL: "
- "mSurface = %p, mIdentity = %d, mWidth = %d, mHeight = %d, "
- "mFormat = %d, mFlags = 0x%08x, mInitCheck = %d",
- surface->mSurface.get(), surface->mIdentity, surface->mWidth,
- surface->mHeight, surface->mFormat, surface->mFlags,
- surface->mInitCheck);
+ } else if (surface != 0 &&
+ (surface->mSurface != NULL ||
+ surface->getISurfaceTexture() != NULL)) {
+ LOGE("Parceling invalid surface with non-NULL ISurface/ISurfaceTexture as NULL: "
+ "mSurface = %p, surfaceTexture = %p, mIdentity = %d, ",
+ surface->mSurface.get(), surface->getISurfaceTexture().get(),
+ surface->mIdentity);
}
- parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
+
+ parcel->writeStrongBinder(sur != NULL ? sur->asBinder() : NULL);
+ parcel->writeStrongBinder(st != NULL ? st->asBinder() : NULL);
parcel->writeInt32(identity);
- parcel->writeInt32(width);
- parcel->writeInt32(height);
- parcel->writeInt32(format);
- parcel->writeInt32(flags);
return NO_ERROR;
}
@@ -342,9 +277,14 @@
if (surface == 0) {
surface = new Surface(data, binder);
sCachedSurfaces.add(binder, surface);
+ } else {
+ // The Surface was found in the cache, but we still should clear any
+ // remaining data from the parcel.
+ data.readStrongBinder(); // ISurfaceTexture
+ data.readInt32(); // identity
}
- if (surface->mSurface == 0) {
- surface = 0;
+ if (surface->mSurface == NULL && surface->getISurfaceTexture() == NULL) {
+ surface = 0;
}
cleanCachedSurfacesLocked();
return surface;
@@ -361,40 +301,20 @@
}
}
-void Surface::init()
+void Surface::init(const sp<ISurfaceTexture>& surfaceTexture)
{
- ANativeWindow::setSwapInterval = setSwapInterval;
- ANativeWindow::dequeueBuffer = dequeueBuffer;
- ANativeWindow::cancelBuffer = cancelBuffer;
- ANativeWindow::lockBuffer = lockBuffer;
- ANativeWindow::queueBuffer = queueBuffer;
- ANativeWindow::query = query;
- ANativeWindow::perform = perform;
-
- if (mSurface != NULL) {
- sp<ISurfaceTexture> surfaceTexture(mSurface->getSurfaceTexture());
+ if (mSurface != NULL || surfaceTexture != NULL) {
LOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");
if (surfaceTexture != NULL) {
- mSurfaceTextureClient = new SurfaceTextureClient(surfaceTexture);
- mSurfaceTextureClient->setUsage(GraphicBuffer::USAGE_HW_RENDER);
+ setISurfaceTexture(surfaceTexture);
+ setUsage(GraphicBuffer::USAGE_HW_RENDER);
}
DisplayInfo dinfo;
SurfaceComposerClient::getDisplayInfo(0, &dinfo);
const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
-
- const_cast<int&>(ANativeWindow::minSwapInterval) =
- mSurfaceTextureClient->minSwapInterval;
-
- const_cast<int&>(ANativeWindow::maxSwapInterval) =
- mSurfaceTextureClient->maxSwapInterval;
-
const_cast<uint32_t&>(ANativeWindow::flags) = 0;
-
- if (mSurfaceTextureClient != 0) {
- mInitCheck = NO_ERROR;
- }
}
}
@@ -402,27 +322,16 @@
{
// clear all references and trigger an IPC now, to make sure things
// happen without delay, since these resources are quite heavy.
- mSurfaceTextureClient.clear();
mSurface.clear();
IPCThreadState::self()->flushCommands();
}
bool Surface::isValid() {
- return mInitCheck == NO_ERROR;
-}
-
-status_t Surface::validate(bool inCancelBuffer) const
-{
- // check that we initialized ourself properly
- if (mInitCheck != NO_ERROR) {
- LOGE("invalid token (identity=%u)", mIdentity);
- return mInitCheck;
- }
- return NO_ERROR;
+ return getISurfaceTexture() != NULL;
}
sp<ISurfaceTexture> Surface::getSurfaceTexture() {
- return mSurface != NULL ? mSurface->getSurfaceTexture() : NULL;
+ return getISurfaceTexture();
}
sp<IBinder> Surface::asBinder() const {
@@ -431,219 +340,45 @@
// ----------------------------------------------------------------------------
-int Surface::setSwapInterval(ANativeWindow* window, int interval) {
- Surface* self = getSelf(window);
- return self->setSwapInterval(interval);
-}
-
-int Surface::dequeueBuffer(ANativeWindow* window,
- ANativeWindowBuffer** buffer) {
- Surface* self = getSelf(window);
- return self->dequeueBuffer(buffer);
-}
-
-int Surface::cancelBuffer(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- Surface* self = getSelf(window);
- return self->cancelBuffer(buffer);
-}
-
-int Surface::lockBuffer(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- Surface* self = getSelf(window);
- return self->lockBuffer(buffer);
-}
-
-int Surface::queueBuffer(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- Surface* self = getSelf(window);
- return self->queueBuffer(buffer);
-}
-
-int Surface::query(const ANativeWindow* window,
- int what, int* value) {
- const Surface* self = getSelf(window);
- return self->query(what, value);
-}
-
-int Surface::perform(ANativeWindow* window,
- int operation, ...) {
- va_list args;
- va_start(args, operation);
- Surface* self = getSelf(window);
- int res = self->perform(operation, args);
- va_end(args);
- return res;
-}
-
-// ----------------------------------------------------------------------------
-
-int Surface::setSwapInterval(int interval) {
- return mSurfaceTextureClient->setSwapInterval(interval);
-}
-
-int Surface::dequeueBuffer(ANativeWindowBuffer** buffer) {
- status_t err = mSurfaceTextureClient->dequeueBuffer(buffer);
- if (err == NO_ERROR) {
- mDirtyRegion.set(buffer[0]->width, buffer[0]->height);
- }
- return err;
-}
-
-int Surface::cancelBuffer(ANativeWindowBuffer* buffer) {
- return mSurfaceTextureClient->cancelBuffer(buffer);
-}
-
-int Surface::lockBuffer(ANativeWindowBuffer* buffer) {
- return mSurfaceTextureClient->lockBuffer(buffer);
-}
-
-int Surface::queueBuffer(ANativeWindowBuffer* buffer) {
- return mSurfaceTextureClient->queueBuffer(buffer);
-}
-
int Surface::query(int what, int* value) const {
switch (what) {
case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
- // TODO: this is not needed anymore
*value = 1;
return NO_ERROR;
case NATIVE_WINDOW_CONCRETE_TYPE:
- // TODO: this is not needed anymore
*value = NATIVE_WINDOW_SURFACE;
return NO_ERROR;
}
- return mSurfaceTextureClient->query(what, value);
-}
-
-int Surface::perform(int operation, va_list args) {
- return mSurfaceTextureClient->perform(operation, args);
+ return SurfaceTextureClient::query(what, value);
}
// ----------------------------------------------------------------------------
-int Surface::getConnectedApi() const {
- return mSurfaceTextureClient->getConnectedApi();
-}
+status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn) {
+ ANativeWindow_Buffer outBuffer;
-// ----------------------------------------------------------------------------
-
-status_t Surface::lock(SurfaceInfo* info, bool blocking) {
- return Surface::lock(info, NULL, blocking);
-}
-
-status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
-{
- if (getConnectedApi()) {
- LOGE("Surface::lock(%p) failed. Already connected to another API",
- (ANativeWindow*)this);
- CallStack stack;
- stack.update();
- stack.dump("");
- return INVALID_OPERATION;
+ ARect temp;
+ ARect* inOutDirtyBounds = NULL;
+ if (dirtyIn) {
+ temp = dirtyIn->getBounds();
+ inOutDirtyBounds = &temp;
}
- if (mApiLock.tryLock() != NO_ERROR) {
- LOGE("calling Surface::lock from different threads!");
- CallStack stack;
- stack.update();
- stack.dump("");
- return WOULD_BLOCK;
- }
+ status_t err = SurfaceTextureClient::lock(&outBuffer, inOutDirtyBounds);
- /* Here we're holding mApiLock */
-
- if (mLockedBuffer != 0) {
- LOGE("Surface::lock failed, already locked");
- mApiLock.unlock();
- return INVALID_OPERATION;
- }
-
- // we're intending to do software rendering from this point
- mSurfaceTextureClient->setUsage(
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
-
- ANativeWindowBuffer* out;
- status_t err = mSurfaceTextureClient->dequeueBuffer(&out);
- LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
- sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
- err = mSurfaceTextureClient->lockBuffer(backBuffer.get());
- LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
- backBuffer->handle, strerror(-err));
- if (err == NO_ERROR) {
- const Rect bounds(backBuffer->width, backBuffer->height);
- const Region boundsRegion(bounds);
- Region scratch(boundsRegion);
- Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
- newDirtyRegion &= boundsRegion;
-
- // figure out if we can copy the frontbuffer back
- const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
- const bool canCopyBack = (frontBuffer != 0 &&
- backBuffer->width == frontBuffer->width &&
- backBuffer->height == frontBuffer->height &&
- backBuffer->format == frontBuffer->format &&
- !(mFlags & ISurfaceComposer::eDestroyBackbuffer));
-
- // the dirty region we report to surfaceflinger is the one
- // given by the user (as opposed to the one *we* return to the
- // user).
- mDirtyRegion = newDirtyRegion;
-
- if (canCopyBack) {
- // copy the area that is invalid and not repainted this round
- const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
- if (!copyback.isEmpty())
- copyBlt(backBuffer, frontBuffer, copyback);
- } else {
- // if we can't copy-back anything, modify the user's dirty
- // region to make sure they redraw the whole buffer
- newDirtyRegion = boundsRegion;
- }
-
- // keep track of the are of the buffer that is "clean"
- // (ie: that will be redrawn)
- mOldDirtyRegion = newDirtyRegion;
-
- void* vaddr;
- status_t res = backBuffer->lock(
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- newDirtyRegion.bounds(), &vaddr);
-
- LOGW_IF(res, "failed locking buffer (handle = %p)",
- backBuffer->handle);
-
- mLockedBuffer = backBuffer;
- other->w = backBuffer->width;
- other->h = backBuffer->height;
- other->s = backBuffer->stride;
- other->usage = backBuffer->usage;
- other->format = backBuffer->format;
- other->bits = vaddr;
- }
+ other->w = uint32_t(outBuffer.width);
+ other->h = uint32_t(outBuffer.height);
+ other->s = uint32_t(outBuffer.stride);
+ other->usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+ other->format = uint32_t(outBuffer.format);
+ other->bits = outBuffer.bits;
}
- mApiLock.unlock();
return err;
}
-
-status_t Surface::unlockAndPost()
-{
- if (mLockedBuffer == 0) {
- LOGE("Surface::unlockAndPost failed, no locked buffer");
- return INVALID_OPERATION;
- }
- status_t err = mLockedBuffer->unlock();
- LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
-
- err = mSurfaceTextureClient->queueBuffer(mLockedBuffer.get());
- LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
- mLockedBuffer->handle, strerror(-err));
-
- mPostedBuffer = mLockedBuffer;
- mLockedBuffer = 0;
- return err;
+status_t Surface::unlockAndPost() {
+ return SurfaceTextureClient::unlockAndPost();
}
// ----------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 8cead80..3b0ffea 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -339,7 +339,7 @@
sp<ISurface> surface = mClient->createSurface(&data, name,
display, w, h, format, flags);
if (surface != 0) {
- result = new SurfaceControl(this, surface, data, w, h, format, flags);
+ result = new SurfaceControl(this, surface, data);
}
}
return result;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 1410481..7ac4343 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -86,14 +86,15 @@
mClientBufferCount(0),
mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
mCurrentTexture(INVALID_BUFFER_SLOT),
- mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES),
mCurrentTransform(0),
mCurrentTimestamp(0),
mNextTransform(0),
+ mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mTexName(tex),
mSynchronousMode(false),
mAllowSynchronousMode(allowSynchronousMode),
- mConnectedApi(NO_CONNECTED_API) {
+ mConnectedApi(NO_CONNECTED_API),
+ mAbandoned(false) {
LOGV("SurfaceTexture::SurfaceTexture");
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
@@ -103,7 +104,7 @@
SurfaceTexture::~SurfaceTexture() {
LOGV("SurfaceTexture::~SurfaceTexture");
- freeAllBuffers();
+ freeAllBuffersLocked();
}
status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) {
@@ -149,6 +150,10 @@
LOGV("SurfaceTexture::setBufferCount");
Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ LOGE("setBufferCount: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
if (bufferCount > NUM_BUFFER_SLOTS) {
LOGE("setBufferCount: bufferCount larger than slots available");
return BAD_VALUE;
@@ -162,24 +167,24 @@
}
}
+ const int minBufferSlots = mSynchronousMode ?
+ MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
if (bufferCount == 0) {
- const int minBufferSlots = mSynchronousMode ?
- MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
mClientBufferCount = 0;
bufferCount = (mServerBufferCount >= minBufferSlots) ?
mServerBufferCount : minBufferSlots;
return setBufferCountServerLocked(bufferCount);
}
- // We don't allow the client to set a buffer-count less than
- // MIN_ASYNC_BUFFER_SLOTS (3), there is no reason for it.
- if (bufferCount < MIN_ASYNC_BUFFER_SLOTS) {
+ if (bufferCount < minBufferSlots) {
+ LOGE("setBufferCount: requested buffer count (%d) is less than "
+ "minimum (%d)", bufferCount, minBufferSlots);
return BAD_VALUE;
}
// here we're guaranteed that the client doesn't have dequeued buffers
// and will release all of its buffer references.
- freeAllBuffers();
+ freeAllBuffersLocked();
mBufferCount = bufferCount;
mClientBufferCount = bufferCount;
mCurrentTexture = INVALID_BUFFER_SLOT;
@@ -190,24 +195,32 @@
status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
{
- Mutex::Autolock lock(mMutex);
- if ((w != mDefaultWidth) || (h != mDefaultHeight)) {
- mDefaultWidth = w;
- mDefaultHeight = h;
+ if (!w || !h) {
+ LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", w, h);
+ return BAD_VALUE;
}
+
+ Mutex::Autolock lock(mMutex);
+ mDefaultWidth = w;
+ mDefaultHeight = h;
return OK;
}
-sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf) {
+status_t SurfaceTexture::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
LOGV("SurfaceTexture::requestBuffer");
Mutex::Autolock lock(mMutex);
- if (buf < 0 || mBufferCount <= buf) {
- LOGE("requestBuffer: slot index out of range [0, %d]: %d",
- mBufferCount, buf);
- return 0;
+ if (mAbandoned) {
+ LOGE("requestBuffer: SurfaceTexture has been abandoned!");
+ return NO_INIT;
}
- mSlots[buf].mRequestBufferCalled = true;
- return mSlots[buf].mGraphicBuffer;
+ if (slot < 0 || mBufferCount <= slot) {
+ LOGE("requestBuffer: slot index out of range [0, %d]: %d",
+ mBufferCount, slot);
+ return BAD_VALUE;
+ }
+ mSlots[slot].mRequestBufferCalled = true;
+ *buf = mSlots[slot].mGraphicBuffer;
+ return NO_ERROR;
}
status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
@@ -227,10 +240,15 @@
int dequeuedCount = 0;
bool tryAgain = true;
while (tryAgain) {
+ if (mAbandoned) {
+ LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
// We need to wait for the FIFO to drain if the number of buffer
// needs to change.
//
- // The condition "number of buffer needs to change" is true if
+ // The condition "number of buffers needs to change" is true if
// - the client doesn't care about how many buffers there are
// - AND the actual number of buffer is different from what was
// set in the last setBufferCountServer()
@@ -242,26 +260,24 @@
// As long as this condition is true AND the FIFO is not empty, we
// wait on mDequeueCondition.
- int minBufferCountNeeded = mSynchronousMode ?
+ const int minBufferCountNeeded = mSynchronousMode ?
MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
- if (!mClientBufferCount &&
+ const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
((mServerBufferCount != mBufferCount) ||
- (mServerBufferCount < minBufferCountNeeded))) {
+ (mServerBufferCount < minBufferCountNeeded));
+
+ if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
// wait for the FIFO to drain
- while (!mQueue.isEmpty()) {
- mDequeueCondition.wait(mMutex);
- }
- minBufferCountNeeded = mSynchronousMode ?
- MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
+ mDequeueCondition.wait(mMutex);
+ // NOTE: we continue here because we need to reevaluate our
+ // whole state (eg: we could be abandoned or disconnected)
+ continue;
}
-
- if (!mClientBufferCount &&
- ((mServerBufferCount != mBufferCount) ||
- (mServerBufferCount < minBufferCountNeeded))) {
+ if (numberOfBuffersNeedsToChange) {
// here we're guaranteed that mQueue is empty
- freeAllBuffers();
+ freeAllBuffersLocked();
mBufferCount = mServerBufferCount;
if (mBufferCount < minBufferCountNeeded)
mBufferCount = minBufferCountNeeded;
@@ -379,15 +395,20 @@
status_t SurfaceTexture::setSynchronousMode(bool enabled) {
Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
status_t err = OK;
if (!mAllowSynchronousMode && enabled)
return err;
if (!enabled) {
// going to asynchronous mode, drain the queue
- while (mSynchronousMode != enabled && !mQueue.isEmpty()) {
- mDequeueCondition.wait(mMutex);
- }
+ err = drainQueueLocked();
+ if (err != NO_ERROR)
+ return err;
}
if (mSynchronousMode != enabled) {
@@ -401,13 +422,18 @@
return err;
}
-status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) {
+status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
LOGV("SurfaceTexture::queueBuffer");
sp<FrameAvailableListener> listener;
{ // scope for the lock
Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ LOGE("queueBuffer: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
if (buf < 0 || buf >= mBufferCount) {
LOGE("queueBuffer: slot index out of range [0, %d]: %d",
mBufferCount, buf);
@@ -453,6 +479,7 @@
mSlots[buf].mBufferState = BufferSlot::QUEUED;
mSlots[buf].mCrop = mNextCrop;
mSlots[buf].mTransform = mNextTransform;
+ mSlots[buf].mScalingMode = mNextScalingMode;
mSlots[buf].mTimestamp = timestamp;
mDequeueCondition.signal();
} // scope for the lock
@@ -461,12 +488,23 @@
if (listener != 0) {
listener->onFrameAvailable();
}
+
+ *outWidth = mDefaultWidth;
+ *outHeight = mDefaultHeight;
+ *outTransform = 0;
+
return OK;
}
void SurfaceTexture::cancelBuffer(int buf) {
LOGV("SurfaceTexture::cancelBuffer");
Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ LOGW("cancelBuffer: SurfaceTexture has been abandoned!");
+ return;
+ }
+
if (buf < 0 || buf >= mBufferCount) {
LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
mBufferCount, buf);
@@ -483,6 +521,10 @@
status_t SurfaceTexture::setCrop(const Rect& crop) {
LOGV("SurfaceTexture::setCrop");
Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ LOGE("setCrop: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
mNextCrop = crop;
return OK;
}
@@ -490,13 +532,24 @@
status_t SurfaceTexture::setTransform(uint32_t transform) {
LOGV("SurfaceTexture::setTransform");
Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ LOGE("setTransform: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
mNextTransform = transform;
return OK;
}
-status_t SurfaceTexture::connect(int api) {
- LOGV("SurfaceTexture::connect");
+status_t SurfaceTexture::connect(int api,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+ LOGV("SurfaceTexture::connect(this=%p, %d)", this, api);
Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ LOGE("connect: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
int err = NO_ERROR;
switch (api) {
case NATIVE_WINDOW_API_EGL:
@@ -504,9 +557,14 @@
case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA:
if (mConnectedApi != NO_CONNECTED_API) {
+ LOGE("connect: already connected (cur=%d, req=%d)",
+ mConnectedApi, api);
err = -EINVAL;
} else {
mConnectedApi = api;
+ *outWidth = mDefaultWidth;
+ *outHeight = mDefaultHeight;
+ *outTransform = 0;
}
break;
default:
@@ -517,8 +575,14 @@
}
status_t SurfaceTexture::disconnect(int api) {
- LOGV("SurfaceTexture::disconnect");
+ LOGV("SurfaceTexture::disconnect(this=%p, %d)", this, api);
Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ LOGE("connect: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
int err = NO_ERROR;
switch (api) {
case NATIVE_WINDOW_API_EGL:
@@ -526,8 +590,12 @@
case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA:
if (mConnectedApi == api) {
+ drainQueueAndFreeBuffersLocked();
mConnectedApi = NO_CONNECTED_API;
+ mDequeueCondition.signal();
} else {
+ LOGE("disconnect: connected to another api (cur=%d, req=%d)",
+ mConnectedApi, api);
err = -EINVAL;
}
break;
@@ -538,10 +606,31 @@
return err;
}
+status_t SurfaceTexture::setScalingMode(int mode) {
+ LOGV("SurfaceTexture::setScalingMode(%d)", mode);
+
+ switch (mode) {
+ case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+ case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mMutex);
+ mNextScalingMode = mode;
+ return OK;
+}
+
status_t SurfaceTexture::updateTexImage() {
LOGV("SurfaceTexture::updateTexImage");
Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ LOGE("calling updateTexImage() on an abandoned SurfaceTexture");
+ return NO_INIT;
+ }
+
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
if (!mQueue.empty()) {
@@ -552,6 +641,10 @@
EGLImageKHR image = mSlots[buf].mEglImage;
if (image == EGL_NO_IMAGE_KHR) {
EGLDisplay dpy = eglGetCurrentDisplay();
+ if (mSlots[buf].mGraphicBuffer == 0) {
+ LOGE("buffer at slot %d is null", buf);
+ return BAD_VALUE;
+ }
image = createImage(dpy, mSlots[buf].mGraphicBuffer);
mSlots[buf].mEglImage = image;
mSlots[buf].mEglDisplay = dpy;
@@ -567,12 +660,8 @@
LOGW("updateTexImage: clearing GL error: %#04x", error);
}
- GLenum target = getTextureTarget(mSlots[buf].mGraphicBuffer->format);
- if (target != mCurrentTextureTarget) {
- glDeleteTextures(1, &mTexName);
- }
- glBindTexture(target, mTexName);
- glEGLImageTargetTexture2DOES(target, (GLeglImageOES)image);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
bool failed = false;
while ((error = glGetError()) != GL_NO_ERROR) {
@@ -594,10 +683,10 @@
// Update the SurfaceTexture state.
mCurrentTexture = buf;
- mCurrentTextureTarget = target;
mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
mCurrentCrop = mSlots[buf].mCrop;
mCurrentTransform = mSlots[buf].mTransform;
+ mCurrentScalingMode = mSlots[buf].mScalingMode;
mCurrentTimestamp = mSlots[buf].mTimestamp;
computeCurrentTransformMatrix();
@@ -607,7 +696,7 @@
mDequeueCondition.signal();
} else {
// We always bind the texture even if we don't update its contents.
- glBindTexture(mCurrentTextureTarget, mTexName);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
}
return OK;
@@ -632,20 +721,8 @@
return false;
}
-GLenum SurfaceTexture::getTextureTarget(uint32_t format)
-{
- GLenum target = GL_TEXTURE_2D;
-#if defined(GL_OES_EGL_image_external)
- if (isExternalFormat(format)) {
- target = GL_TEXTURE_EXTERNAL_OES;
- }
-#endif
- return target;
-}
-
GLenum SurfaceTexture::getCurrentTextureTarget() const {
- Mutex::Autolock lock(mMutex);
- return mCurrentTextureTarget;
+ return GL_TEXTURE_EXTERNAL_OES;
}
void SurfaceTexture::getTransformMatrix(float mtx[16]) {
@@ -757,23 +834,66 @@
mFrameAvailableListener = listener;
}
-sp<IBinder> SurfaceTexture::getAllocator() {
- LOGV("SurfaceTexture::getAllocator");
- return mGraphicBufferAlloc->asBinder();
+void SurfaceTexture::freeBufferLocked(int i) {
+ mSlots[i].mGraphicBuffer = 0;
+ mSlots[i].mBufferState = BufferSlot::FREE;
+ if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
+ mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+ mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+ }
}
-void SurfaceTexture::freeAllBuffers() {
+void SurfaceTexture::freeAllBuffersLocked() {
+ LOGW_IF(!mQueue.isEmpty(),
+ "freeAllBuffersLocked called but mQueue is not empty");
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
- mSlots[i].mGraphicBuffer = 0;
- mSlots[i].mBufferState = BufferSlot::FREE;
- if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
- mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
- mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+ freeBufferLocked(i);
+ }
+}
+
+void SurfaceTexture::freeAllBuffersExceptHeadLocked() {
+ LOGW_IF(!mQueue.isEmpty(),
+ "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
+ int head = -1;
+ if (!mQueue.empty()) {
+ Fifo::iterator front(mQueue.begin());
+ head = *front;
+ }
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ if (i != head) {
+ freeBufferLocked(i);
}
}
}
+status_t SurfaceTexture::drainQueueLocked() {
+ while (mSynchronousMode && !mQueue.isEmpty()) {
+ mDequeueCondition.wait(mMutex);
+ if (mAbandoned) {
+ LOGE("drainQueueLocked: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+ if (mConnectedApi == NO_CONNECTED_API) {
+ LOGE("drainQueueLocked: SurfaceTexture is not connected!");
+ return NO_INIT;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t SurfaceTexture::drainQueueAndFreeBuffersLocked() {
+ status_t err = drainQueueLocked();
+ if (err == NO_ERROR) {
+ if (mSynchronousMode) {
+ freeAllBuffersLocked();
+ } else {
+ freeAllBuffersExceptHeadLocked();
+ }
+ }
+ return err;
+}
+
EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
const sp<GraphicBuffer>& graphicBuffer) {
EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
@@ -805,20 +925,27 @@
return mCurrentTransform;
}
+uint32_t SurfaceTexture::getCurrentScalingMode() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentScalingMode;
+}
+
int SurfaceTexture::query(int what, int* outValue)
{
Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ LOGE("query: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
int value;
switch (what) {
case NATIVE_WINDOW_WIDTH:
value = mDefaultWidth;
- if (!mDefaultWidth && !mDefaultHeight && mCurrentTextureBuf!=0)
- value = mCurrentTextureBuf->width;
break;
case NATIVE_WINDOW_HEIGHT:
value = mDefaultHeight;
- if (!mDefaultWidth && !mDefaultHeight && mCurrentTextureBuf!=0)
- value = mCurrentTextureBuf->height;
break;
case NATIVE_WINDOW_FORMAT:
value = mPixelFormat;
@@ -834,6 +961,15 @@
return NO_ERROR;
}
+void SurfaceTexture::abandon() {
+ Mutex::Autolock lock(mMutex);
+ mQueue.clear();
+ mAbandoned = true;
+ mCurrentTextureBuf.clear();
+ freeAllBuffersLocked();
+ mDequeueCondition.signal();
+}
+
void SurfaceTexture::dump(String8& result) const
{
char buffer[1024];
@@ -861,12 +997,12 @@
}
snprintf(buffer, SIZE,
- "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d, target=0x%04x}\n"
+ "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n"
"%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, FIFO(%d)={%s}}\n"
,
prefix, mCurrentCrop.left,
mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
- mCurrentTransform, mCurrentTexture, mCurrentTextureTarget,
+ mCurrentTransform, mCurrentTexture,
prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right, mNextCrop.bottom,
mCurrentTransform, fifoSize, fifo.string()
);
@@ -886,13 +1022,24 @@
for (int i=0 ; i<mBufferCount ; i++) {
const BufferSlot& slot(mSlots[i]);
snprintf(buffer, SIZE,
- "%s%s[%02d] state=%-8s, crop=[%d,%d,%d,%d], transform=0x%02x, "
- "timestamp=%lld\n",
- prefix, (i==mCurrentTexture)?">":" ", i, stateName(slot.mBufferState),
+ "%s%s[%02d] "
+ "state=%-8s, crop=[%d,%d,%d,%d], "
+ "transform=0x%02x, timestamp=%lld",
+ prefix, (i==mCurrentTexture)?">":" ", i,
+ stateName(slot.mBufferState),
slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, slot.mCrop.bottom,
slot.mTransform, slot.mTimestamp
);
result.append(buffer);
+
+ const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
+ if (buf != NULL) {
+ snprintf(buffer, SIZE,
+ ", %p [%4ux%4u:%4u,%3X]",
+ buf->handle, buf->width, buf->height, buf->stride, buf->format);
+ result.append(buffer);
+ }
+ result.append("\n");
}
}
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index f39cabf..e91be84 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -24,68 +24,86 @@
namespace android {
SurfaceTextureClient::SurfaceTextureClient(
- const sp<ISurfaceTexture>& surfaceTexture):
- mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
- mReqHeight(0), mReqFormat(0), mReqUsage(0),
- mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO),
- mQueryWidth(0), mQueryHeight(0), mQueryFormat(0),
- mMutex() {
+ const sp<ISurfaceTexture>& surfaceTexture)
+{
+ SurfaceTextureClient::init();
+ SurfaceTextureClient::setISurfaceTexture(surfaceTexture);
+}
+
+SurfaceTextureClient::SurfaceTextureClient() {
+ SurfaceTextureClient::init();
+}
+
+void SurfaceTextureClient::init() {
// Initialize the ANativeWindow function pointers.
- ANativeWindow::setSwapInterval = setSwapInterval;
- ANativeWindow::dequeueBuffer = dequeueBuffer;
- ANativeWindow::cancelBuffer = cancelBuffer;
- ANativeWindow::lockBuffer = lockBuffer;
- ANativeWindow::queueBuffer = queueBuffer;
- ANativeWindow::query = query;
- ANativeWindow::perform = perform;
+ ANativeWindow::setSwapInterval = hook_setSwapInterval;
+ ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
+ ANativeWindow::cancelBuffer = hook_cancelBuffer;
+ ANativeWindow::lockBuffer = hook_lockBuffer;
+ ANativeWindow::queueBuffer = hook_queueBuffer;
+ ANativeWindow::query = hook_query;
+ ANativeWindow::perform = hook_perform;
const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
- // Get a reference to the allocator.
- mAllocator = mSurfaceTexture->getAllocator();
+ mReqWidth = 0;
+ mReqHeight = 0;
+ mReqFormat = 0;
+ mReqUsage = 0;
+ mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
+ mDefaultWidth = 0;
+ mDefaultHeight = 0;
+ mTransformHint = 0;
+ mConnectedToCpu = false;
+}
+
+void SurfaceTextureClient::setISurfaceTexture(
+ const sp<ISurfaceTexture>& surfaceTexture)
+{
+ mSurfaceTexture = surfaceTexture;
}
sp<ISurfaceTexture> SurfaceTextureClient::getISurfaceTexture() const {
return mSurfaceTexture;
}
-int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) {
+int SurfaceTextureClient::hook_setSwapInterval(ANativeWindow* window, int interval) {
SurfaceTextureClient* c = getSelf(window);
return c->setSwapInterval(interval);
}
-int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_dequeueBuffer(ANativeWindow* window,
ANativeWindowBuffer** buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->dequeueBuffer(buffer);
}
-int SurfaceTextureClient::cancelBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_cancelBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->cancelBuffer(buffer);
}
-int SurfaceTextureClient::lockBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_lockBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->lockBuffer(buffer);
}
-int SurfaceTextureClient::queueBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->queueBuffer(buffer);
}
-int SurfaceTextureClient::query(const ANativeWindow* window,
+int SurfaceTextureClient::hook_query(const ANativeWindow* window,
int what, int* value) {
const SurfaceTextureClient* c = getSelf(window);
return c->query(what, value);
}
-int SurfaceTextureClient::perform(ANativeWindow* window, int operation, ...) {
+int SurfaceTextureClient::hook_perform(ANativeWindow* window, int operation, ...) {
va_list args;
va_start(args, operation);
SurfaceTextureClient* c = getSelf(window);
@@ -127,14 +145,12 @@
}
if ((result & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
- gbuf = mSurfaceTexture->requestBuffer(buf);
- if (gbuf == 0) {
- LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed");
- return NO_MEMORY;
+ result = mSurfaceTexture->requestBuffer(buf, &gbuf);
+ if (result != NO_ERROR) {
+ LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed: %d",
+ result);
+ return result;
}
- mQueryWidth = gbuf->width;
- mQueryHeight = gbuf->height;
- mQueryFormat = gbuf->format;
}
*buffer = gbuf.get();
return OK;
@@ -201,27 +217,38 @@
if (i < 0) {
return i;
}
- mSurfaceTexture->queueBuffer(i, timestamp);
+ mSurfaceTexture->queueBuffer(i, timestamp,
+ &mDefaultWidth, &mDefaultHeight, &mTransformHint);
return OK;
}
int SurfaceTextureClient::query(int what, int* value) const {
LOGV("SurfaceTextureClient::query");
- switch (what) {
- case NATIVE_WINDOW_FORMAT:
- if (mReqFormat) {
- *value = mReqFormat;
- return NO_ERROR;
+ { // scope for the lock
+ Mutex::Autolock lock(mMutex);
+ switch (what) {
+ case NATIVE_WINDOW_FORMAT:
+ if (mReqFormat) {
+ *value = mReqFormat;
+ return NO_ERROR;
+ }
+ break;
+ case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+ *value = 0;
+ return NO_ERROR;
+ case NATIVE_WINDOW_CONCRETE_TYPE:
+ *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
+ return NO_ERROR;
+ case NATIVE_WINDOW_DEFAULT_WIDTH:
+ *value = mDefaultWidth;
+ return NO_ERROR;
+ case NATIVE_WINDOW_DEFAULT_HEIGHT:
+ *value = mDefaultHeight;
+ return NO_ERROR;
+ case NATIVE_WINDOW_TRANSFORM_HINT:
+ *value = mTransformHint;
+ return NO_ERROR;
}
- break;
- case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
- // TODO: this is not needed anymore
- *value = 0;
- return NO_ERROR;
- case NATIVE_WINDOW_CONCRETE_TYPE:
- // TODO: this is not needed anymore
- *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
- return NO_ERROR;
}
return mSurfaceTexture->query(what, value);
}
@@ -231,10 +258,10 @@
int res = NO_ERROR;
switch (operation) {
case NATIVE_WINDOW_CONNECT:
- res = dispatchConnect(args);
+ // deprecated. must return NO_ERROR.
break;
case NATIVE_WINDOW_DISCONNECT:
- res = dispatchDisconnect(args);
+ // deprecated. must return NO_ERROR.
break;
case NATIVE_WINDOW_SET_USAGE:
res = dispatchSetUsage(args);
@@ -260,6 +287,21 @@
case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
res = dispatchSetBuffersFormat(args);
break;
+ case NATIVE_WINDOW_LOCK:
+ res = dispatchLock(args);
+ break;
+ case NATIVE_WINDOW_UNLOCK_AND_POST:
+ res = dispatchUnlockAndPost(args);
+ break;
+ case NATIVE_WINDOW_SET_SCALING_MODE:
+ res = dispatchSetScalingMode(args);
+ break;
+ case NATIVE_WINDOW_API_CONNECT:
+ res = dispatchConnect(args);
+ break;
+ case NATIVE_WINDOW_API_DISCONNECT:
+ res = dispatchDisconnect(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -314,6 +356,11 @@
return setBuffersFormat(f);
}
+int SurfaceTextureClient::dispatchSetScalingMode(va_list args) {
+ int m = va_arg(args, int);
+ return setScalingMode(m);
+}
+
int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) {
int transform = va_arg(args, int);
return setBuffersTransform(transform);
@@ -324,28 +371,38 @@
return setBuffersTimestamp(timestamp);
}
+int SurfaceTextureClient::dispatchLock(va_list args) {
+ ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
+ ARect* inOutDirtyBounds = va_arg(args, ARect*);
+ return lock(outBuffer, inOutDirtyBounds);
+}
+
+int SurfaceTextureClient::dispatchUnlockAndPost(va_list args) {
+ return unlockAndPost();
+}
+
+
int SurfaceTextureClient::connect(int api) {
LOGV("SurfaceTextureClient::connect");
Mutex::Autolock lock(mMutex);
- return mSurfaceTexture->connect(api);
+ int err = mSurfaceTexture->connect(api,
+ &mDefaultWidth, &mDefaultHeight, &mTransformHint);
+ if (!err && api == NATIVE_WINDOW_API_CPU) {
+ mConnectedToCpu = true;
+ }
+ return err;
}
int SurfaceTextureClient::disconnect(int api) {
LOGV("SurfaceTextureClient::disconnect");
Mutex::Autolock lock(mMutex);
- return mSurfaceTexture->disconnect(api);
+ int err = mSurfaceTexture->disconnect(api);
+ if (!err && api == NATIVE_WINDOW_API_CPU) {
+ mConnectedToCpu = false;
+ }
+ return err;
}
-int SurfaceTextureClient::getConnectedApi() const
-{
- // XXX: This method will be going away shortly, and is currently bogus. It
- // always returns "nothing is connected". It will go away once Surface gets
- // updated to actually connect as the 'CPU' API when locking a buffer.
- Mutex::Autolock lock(mMutex);
- return 0;
-}
-
-
int SurfaceTextureClient::setUsage(uint32_t reqUsage)
{
LOGV("SurfaceTextureClient::setUsage");
@@ -421,6 +478,18 @@
return NO_ERROR;
}
+int SurfaceTextureClient::setScalingMode(int mode)
+{
+ LOGV("SurfaceTextureClient::setScalingMode(%d)", mode);
+ Mutex::Autolock lock(mMutex);
+ // mode is validated on the server
+ status_t err = mSurfaceTexture->setScalingMode(mode);
+ LOGE_IF(err, "ISurfaceTexture::setScalingMode(%d) returned %s",
+ mode, strerror(-err));
+
+ return err;
+}
+
int SurfaceTextureClient::setBuffersTransform(int transform)
{
LOGV("SurfaceTextureClient::setBuffersTransform");
@@ -443,4 +512,160 @@
}
}
+// ----------------------------------------------------------------------
+// the lock/unlock APIs must be used from the same thread
+
+static status_t copyBlt(
+ const sp<GraphicBuffer>& dst,
+ const sp<GraphicBuffer>& src,
+ const Region& reg)
+{
+ // src and dst with, height and format must be identical. no verification
+ // is done here.
+ status_t err;
+ uint8_t const * src_bits = NULL;
+ err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
+ LOGE_IF(err, "error locking src buffer %s", strerror(-err));
+
+ uint8_t* dst_bits = NULL;
+ err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
+ LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
+
+ Region::const_iterator head(reg.begin());
+ Region::const_iterator tail(reg.end());
+ if (head != tail && src_bits && dst_bits) {
+ const size_t bpp = bytesPerPixel(src->format);
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
+
+ while (head != tail) {
+ const Rect& r(*head++);
+ ssize_t h = r.height();
+ if (h <= 0) continue;
+ size_t size = r.width() * bpp;
+ uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+ uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
+ size *= h;
+ h = 1;
+ }
+ do {
+ memcpy(d, s, size);
+ d += dbpr;
+ s += sbpr;
+ } while (--h > 0);
+ }
+ }
+
+ if (src_bits)
+ src->unlock();
+
+ if (dst_bits)
+ dst->unlock();
+
+ return err;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t SurfaceTextureClient::lock(
+ ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
+{
+ if (mLockedBuffer != 0) {
+ LOGE("Surface::lock failed, already locked");
+ return INVALID_OPERATION;
+ }
+
+ if (!mConnectedToCpu) {
+ int err = SurfaceTextureClient::connect(NATIVE_WINDOW_API_CPU);
+ if (err) {
+ return err;
+ }
+ // we're intending to do software rendering from this point
+ setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+ }
+
+ ANativeWindowBuffer* out;
+ status_t err = dequeueBuffer(&out);
+ LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
+ if (err == NO_ERROR) {
+ sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
+ err = lockBuffer(backBuffer.get());
+ LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
+ backBuffer->handle, strerror(-err));
+ if (err == NO_ERROR) {
+ const Rect bounds(backBuffer->width, backBuffer->height);
+
+ Region newDirtyRegion;
+ if (inOutDirtyBounds) {
+ newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
+ newDirtyRegion.andSelf(bounds);
+ } else {
+ newDirtyRegion.set(bounds);
+ }
+
+ // figure out if we can copy the frontbuffer back
+ const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
+ const bool canCopyBack = (frontBuffer != 0 &&
+ backBuffer->width == frontBuffer->width &&
+ backBuffer->height == frontBuffer->height &&
+ backBuffer->format == frontBuffer->format);
+
+ if (canCopyBack) {
+ // copy the area that is invalid and not repainted this round
+ const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
+ if (!copyback.isEmpty())
+ copyBlt(backBuffer, frontBuffer, copyback);
+ } else {
+ // if we can't copy-back anything, modify the user's dirty
+ // region to make sure they redraw the whole buffer
+ newDirtyRegion.set(bounds);
+ }
+
+ // keep track of the are of the buffer that is "clean"
+ // (ie: that will be redrawn)
+ mOldDirtyRegion = newDirtyRegion;
+
+ if (inOutDirtyBounds) {
+ *inOutDirtyBounds = newDirtyRegion.getBounds();
+ }
+
+ void* vaddr;
+ status_t res = backBuffer->lock(
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ newDirtyRegion.bounds(), &vaddr);
+
+ LOGW_IF(res, "failed locking buffer (handle = %p)",
+ backBuffer->handle);
+
+ mLockedBuffer = backBuffer;
+ outBuffer->width = backBuffer->width;
+ outBuffer->height = backBuffer->height;
+ outBuffer->stride = backBuffer->stride;
+ outBuffer->format = backBuffer->format;
+ outBuffer->bits = vaddr;
+ }
+ }
+ return err;
+}
+
+status_t SurfaceTextureClient::unlockAndPost()
+{
+ if (mLockedBuffer == 0) {
+ LOGE("Surface::unlockAndPost failed, no locked buffer");
+ return INVALID_OPERATION;
+ }
+
+ status_t err = mLockedBuffer->unlock();
+ LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
+
+ err = queueBuffer(mLockedBuffer.get());
+ LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
+ mLockedBuffer->handle, strerror(-err));
+
+ mPostedBuffer = mLockedBuffer;
+ mLockedBuffer = 0;
+ return err;
+}
+
}; // namespace android
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 519b40e..c1a3c98 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -116,11 +116,6 @@
EXPECT_EQ(NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT, result);
}
-TEST_F(SurfaceTextureClientTest, ANativeWindowLockFails) {
- ANativeWindow_Buffer buf;
- ASSERT_EQ(BAD_VALUE, ANativeWindow_lock(mANW.get(), &buf, NULL));
-}
-
TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceSucceeds) {
EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
@@ -613,4 +608,90 @@
}
}
+class MultiSurfaceTextureClientTest : public ::testing::Test {
+
+public:
+ MultiSurfaceTextureClientTest() :
+ mEglDisplay(EGL_NO_DISPLAY),
+ mEglContext(EGL_NO_CONTEXT) {
+ for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+ mEglSurfaces[i] = EGL_NO_CONTEXT;
+ }
+ }
+
+protected:
+
+ enum { NUM_SURFACE_TEXTURES = 32 };
+
+ virtual void SetUp() {
+ mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
+
+ EGLint majorVersion, minorVersion;
+ EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ EGLConfig myConfig;
+ EGLint numConfigs = 0;
+ EGLint configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE
+ };
+ EXPECT_TRUE(eglChooseConfig(mEglDisplay, configAttribs, &myConfig, 1,
+ &numConfigs));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT,
+ 0);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
+
+ for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+ sp<SurfaceTexture> st(new SurfaceTexture(i));
+ sp<SurfaceTextureClient> stc(new SurfaceTextureClient(st));
+ mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
+ static_cast<ANativeWindow*>(stc.get()), NULL);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, mEglSurfaces[i]);
+ }
+ }
+
+ virtual void TearDown() {
+ eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT);
+
+ for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+ if (mEglSurfaces[i] != EGL_NO_SURFACE) {
+ eglDestroySurface(mEglDisplay, mEglSurfaces[i]);
+ }
+ }
+
+ if (mEglContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(mEglDisplay, mEglContext);
+ }
+
+ if (mEglDisplay != EGL_NO_DISPLAY) {
+ eglTerminate(mEglDisplay);
+ }
+ }
+
+ EGLDisplay mEglDisplay;
+ EGLSurface mEglSurfaces[NUM_SURFACE_TEXTURES];
+ EGLContext mEglContext;
+};
+
+// XXX: This test is disabled because it causes a hang on some devices. See bug
+// 5015672.
+TEST_F(MultiSurfaceTextureClientTest, DISABLED_MakeCurrentBetweenSurfacesWorks) {
+ for (int iter = 0; iter < 8; iter++) {
+ for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+ eglMakeCurrent(mEglDisplay, mEglSurfaces[i], mEglSurfaces[i],
+ mEglContext);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(mEglDisplay, mEglSurfaces[i]);
+ }
+ }
+}
+
} // namespace android
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 9abe89d..44babcf 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -832,9 +832,7 @@
pt->requestExitAndWait();
}
-// XXX: This test is disabled because there are currently no drivers that can
-// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
-TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferNpot) {
+TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferNpot) {
const int texWidth = 64;
const int texHeight = 66;
@@ -871,26 +869,24 @@
EXPECT_TRUE(checkPixel( 0, 65, 35, 35, 35, 35));
EXPECT_TRUE(checkPixel(15, 10, 35, 231, 231, 231));
- EXPECT_TRUE(checkPixel(24, 63, 38, 228, 231, 35));
+ EXPECT_TRUE(checkPixel(23, 65, 231, 35, 231, 35));
EXPECT_TRUE(checkPixel(19, 40, 35, 231, 35, 35));
EXPECT_TRUE(checkPixel(38, 30, 231, 35, 35, 35));
EXPECT_TRUE(checkPixel(42, 54, 35, 35, 35, 231));
- EXPECT_TRUE(checkPixel(37, 33, 228, 38, 38, 38));
+ EXPECT_TRUE(checkPixel(37, 34, 35, 231, 231, 231));
EXPECT_TRUE(checkPixel(31, 8, 231, 35, 35, 231));
- EXPECT_TRUE(checkPixel(36, 47, 228, 35, 231, 231));
- EXPECT_TRUE(checkPixel(24, 63, 38, 228, 231, 35));
- EXPECT_TRUE(checkPixel(48, 3, 228, 228, 38, 35));
+ EXPECT_TRUE(checkPixel(37, 47, 231, 35, 231, 231));
+ EXPECT_TRUE(checkPixel(25, 38, 35, 35, 35, 35));
+ EXPECT_TRUE(checkPixel(49, 6, 35, 231, 35, 35));
EXPECT_TRUE(checkPixel(54, 50, 35, 231, 231, 231));
- EXPECT_TRUE(checkPixel(24, 25, 41, 41, 231, 231));
- EXPECT_TRUE(checkPixel(10, 9, 38, 38, 231, 231));
+ EXPECT_TRUE(checkPixel(27, 26, 231, 231, 231, 231));
+ EXPECT_TRUE(checkPixel(10, 6, 35, 35, 231, 231));
EXPECT_TRUE(checkPixel(29, 4, 35, 35, 35, 231));
- EXPECT_TRUE(checkPixel(56, 31, 38, 228, 231, 35));
+ EXPECT_TRUE(checkPixel(55, 28, 35, 35, 231, 35));
EXPECT_TRUE(checkPixel(58, 55, 35, 35, 231, 231));
}
-// XXX: This test is disabled because there are currently no drivers that can
-// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
-TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferPow2) {
+TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) {
const int texWidth = 64;
const int texHeight = 64;
@@ -944,9 +940,7 @@
EXPECT_TRUE(checkPixel( 3, 52, 35, 231, 35, 35));
}
-// XXX: This test is disabled because there are currently no drivers that can
-// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
-TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromGLFilledRGBABufferPow2) {
+TEST_F(SurfaceTextureGLTest, TexturingFromGLFilledRGBABufferPow2) {
const int texWidth = 64;
const int texHeight = 64;
@@ -956,7 +950,7 @@
EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
mANW.get(), NULL);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
- ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
+ ASSERT_NE(EGL_NO_SURFACE, stcEglSurface);
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface,
mEglContext));
@@ -980,6 +974,8 @@
eglSwapBuffers(mEglDisplay, stcEglSurface);
+ eglDestroySurface(mEglDisplay, stcEglSurface);
+
// Do the consumer side of things
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
@@ -1018,6 +1014,83 @@
EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
}
+TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
+ class ProducerThread : public Thread {
+ public:
+ ProducerThread(const sp<ANativeWindow>& anw):
+ mANW(anw),
+ mDequeueError(NO_ERROR) {
+ }
+
+ virtual ~ProducerThread() {
+ }
+
+ virtual bool threadLoop() {
+ Mutex::Autolock lock(mMutex);
+ ANativeWindowBuffer* anb;
+
+ // Frame 1
+ if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+ return false;
+ }
+ if (anb == NULL) {
+ return false;
+ }
+ if (mANW->queueBuffer(mANW.get(), anb)
+ != NO_ERROR) {
+ return false;
+ }
+
+ // Frame 2
+ if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+ return false;
+ }
+ if (anb == NULL) {
+ return false;
+ }
+ if (mANW->queueBuffer(mANW.get(), anb)
+ != NO_ERROR) {
+ return false;
+ }
+
+ // Frame 3 - error expected
+ mDequeueError = mANW->dequeueBuffer(mANW.get(), &anb);
+ return false;
+ }
+
+ status_t getDequeueError() {
+ Mutex::Autolock lock(mMutex);
+ return mDequeueError;
+ }
+
+ private:
+ sp<ANativeWindow> mANW;
+ status_t mDequeueError;
+ Mutex mMutex;
+ };
+
+ sp<FrameWaiter> fw(new FrameWaiter);
+ mST->setFrameAvailableListener(fw);
+ ASSERT_EQ(OK, mST->setSynchronousMode(true));
+ ASSERT_EQ(OK, mST->setBufferCountServer(2));
+
+ sp<Thread> pt(new ProducerThread(mANW));
+ pt->run();
+
+ fw->waitForFrame();
+ fw->waitForFrame();
+
+ // Sleep for 100ms to allow the producer thread's dequeueBuffer call to
+ // block waiting for a buffer to become available.
+ usleep(100000);
+
+ mST->abandon();
+
+ pt->requestExitAndWait();
+ ASSERT_EQ(NO_INIT,
+ reinterpret_cast<ProducerThread*>(pt.get())->getDequeueError());
+}
+
/*
* This test is for testing GL -> GL texture streaming via SurfaceTexture. It
* contains functionality to create a producer thread that will perform GL
@@ -1205,7 +1278,7 @@
sp<FrameCondition> mFC;
};
-TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageBeforeFrameFinishedWorks) {
+TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageBeforeFrameFinishedCompletes) {
class PT : public ProducerThread {
virtual void render() {
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
@@ -1223,7 +1296,7 @@
// TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
}
-TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageAfterFrameFinishedWorks) {
+TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageAfterFrameFinishedCompletes) {
class PT : public ProducerThread {
virtual void render() {
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
@@ -1241,7 +1314,7 @@
// TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
}
-TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageBeforeFrameFinishedWorks) {
+TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageBeforeFrameFinishedCompletes) {
enum { NUM_ITERATIONS = 1024 };
class PT : public ProducerThread {
@@ -1269,7 +1342,7 @@
}
}
-TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageAfterFrameFinishedWorks) {
+TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageAfterFrameFinishedCompletes) {
enum { NUM_ITERATIONS = 1024 };
class PT : public ProducerThread {
@@ -1297,4 +1370,70 @@
}
}
+// XXX: This test is disabled because it is currently hanging on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedSwapBuffersWhileDequeueStalledCompletes) {
+ enum { NUM_ITERATIONS = 64 };
+
+ class PT : public ProducerThread {
+ virtual void render() {
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ LOGV("+swapBuffers");
+ swapBuffers();
+ LOGV("-swapBuffers");
+ }
+ }
+ };
+
+ ASSERT_EQ(OK, mST->setSynchronousMode(true));
+ ASSERT_EQ(OK, mST->setBufferCountServer(2));
+
+ runProducerThread(new PT());
+
+ // Allow three frames to be rendered and queued before starting the
+ // rendering in this thread. For the latter two frames we don't call
+ // updateTexImage so the next dequeue from the producer thread will block
+ // waiting for a frame to become available.
+ mFC->waitForFrame();
+ mFC->finishFrame();
+
+ // We must call updateTexImage to consume the first frame so that the
+ // SurfaceTexture is able to reduce the buffer count to 2. This is because
+ // the GL driver may dequeue a buffer when the EGLSurface is created, and
+ // that happens before we call setBufferCountServer. It's possible that the
+ // driver does not dequeue a buffer at EGLSurface creation time, so we
+ // cannot rely on this to cause the second dequeueBuffer call to block.
+ mST->updateTexImage();
+
+ mFC->waitForFrame();
+ mFC->finishFrame();
+ mFC->waitForFrame();
+ mFC->finishFrame();
+
+ // Sleep for 100ms to allow the producer thread's dequeueBuffer call to
+ // block waiting for a buffer to become available.
+ usleep(100000);
+
+ // Render and present a number of images. This thread should not be blocked
+ // by the fact that the producer thread is blocking in dequeue.
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(mEglDisplay, mEglSurface);
+ }
+
+ // Consume the two pending buffers to unblock the producer thread.
+ mST->updateTexImage();
+ mST->updateTexImage();
+
+ // Consume the remaining buffers from the producer thread.
+ for (int i = 0; i < NUM_ITERATIONS-3; i++) {
+ mFC->waitForFrame();
+ mFC->finishFrame();
+ LOGV("+updateTexImage");
+ mST->updateTexImage();
+ LOGV("-updateTexImage");
+ }
+}
+
} // namespace android
diff --git a/libs/ui/EGLUtils.cpp b/libs/ui/EGLUtils.cpp
index 020646b..f24a71d 100644
--- a/libs/ui/EGLUtils.cpp
+++ b/libs/ui/EGLUtils.cpp
@@ -24,8 +24,6 @@
#include <EGL/egl.h>
-#include <system/graphics.h>
-
#include <private/ui/android_natives_priv.h>
// ----------------------------------------------------------------------------
@@ -69,49 +67,31 @@
return BAD_VALUE;
// Get all the "potential match" configs...
- if (eglChooseConfig(dpy, attrs, 0, 0, &numConfigs) == EGL_FALSE)
+ if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE)
return BAD_VALUE;
- if (numConfigs) {
- EGLConfig* const configs = new EGLConfig[numConfigs];
- if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
- delete [] configs;
- return BAD_VALUE;
- }
-
- bool hasAlpha = false;
- switch (format) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_BGRA_8888:
- case HAL_PIXEL_FORMAT_RGBA_5551:
- case HAL_PIXEL_FORMAT_RGBA_4444:
- hasAlpha = true;
- break;
- }
-
- // The first config is guaranteed to over-satisfy the constraints
- EGLConfig config = configs[0];
-
- // go through the list and skip configs that over-satisfy our needs
- int i;
- for (i=0 ; i<n ; i++) {
- if (!hasAlpha) {
- EGLint alphaSize;
- eglGetConfigAttrib(dpy, configs[i], EGL_ALPHA_SIZE, &alphaSize);
- if (alphaSize > 0) {
- continue;
- }
- }
+ EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);
+ if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
+ free(configs);
+ return BAD_VALUE;
+ }
+
+ int i;
+ EGLConfig config = NULL;
+ for (i=0 ; i<n ; i++) {
+ EGLint nativeVisualId = 0;
+ eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
+ if (nativeVisualId>0 && format == nativeVisualId) {
config = configs[i];
break;
}
+ }
- delete [] configs;
-
- if (i<n) {
- *outConfig = config;
- return NO_ERROR;
- }
+ free(configs);
+
+ if (i<n) {
+ *outConfig = config;
+ return NO_ERROR;
}
return NAME_NOT_FOUND;
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 9c10c75..8949730 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -289,6 +289,18 @@
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_DEFAULT_WIDTH:
+ *value = fb->width;
+ return NO_ERROR;
+ case NATIVE_WINDOW_DEFAULT_HEIGHT:
+ *value = fb->height;
+ return NO_ERROR;
+ case NATIVE_WINDOW_TRANSFORM_HINT:
+ *value = 0;
+ return NO_ERROR;
}
*value = 0;
return BAD_VALUE;
@@ -298,15 +310,27 @@
int operation, ...)
{
switch (operation) {
- case NATIVE_WINDOW_SET_USAGE:
- case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
case NATIVE_WINDOW_CONNECT:
case NATIVE_WINDOW_DISCONNECT:
- break;
- default:
- return NAME_NOT_FOUND;
+ case NATIVE_WINDOW_SET_USAGE:
+ case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+ case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+ case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+ case NATIVE_WINDOW_API_CONNECT:
+ case NATIVE_WINDOW_API_DISCONNECT:
+ // TODO: we should implement these
+ return NO_ERROR;
+
+ case NATIVE_WINDOW_LOCK:
+ case NATIVE_WINDOW_UNLOCK_AND_POST:
+ case NATIVE_WINDOW_SET_CROP:
+ case NATIVE_WINDOW_SET_BUFFER_COUNT:
+ case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
+ case NATIVE_WINDOW_SET_SCALING_MODE:
+ return INVALID_OPERATION;
}
- return NO_ERROR;
+ return NAME_NOT_FOUND;
}
// ----------------------------------------------------------------------------
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 33ef1fc..e75415b 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -61,13 +61,19 @@
const size_t c = list.size();
for (size_t i=0 ; i<c ; i++) {
const alloc_rec_t& rec(list.valueAt(i));
- snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x\n",
- list.keyAt(i), rec.size/1024.0f,
- rec.w, rec.s, rec.h, rec.format, rec.usage);
+ if (rec.size) {
+ snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x\n",
+ list.keyAt(i), rec.size/1024.0f,
+ rec.w, rec.s, rec.h, rec.format, rec.usage);
+ } else {
+ snprintf(buffer, SIZE, "%10p: unknown | %4u (%4u) x %4u | %8X | 0x%08x\n",
+ list.keyAt(i),
+ rec.w, rec.s, rec.h, rec.format, rec.usage);
+ }
result.append(buffer);
total += rec.size;
}
- snprintf(buffer, SIZE, "Total allocated: %.2f KB\n", total/1024.0f);
+ snprintf(buffer, SIZE, "Total allocated (estimate): %.2f KB\n", total/1024.0f);
result.append(buffer);
if (mAllocDev->common.version >= 1 && mAllocDev->dump) {
mAllocDev->dump(mAllocDev, buffer, SIZE);
@@ -101,13 +107,19 @@
if (err == NO_ERROR) {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ int bpp = bytesPerPixel(format);
+ if (bpp < 0) {
+ // probably a HAL custom format. in any case, we don't know
+ // what its pixel size is.
+ bpp = 0;
+ }
alloc_rec_t rec;
rec.w = w;
rec.h = h;
rec.s = *stride;
rec.format = format;
rec.usage = usage;
- rec.size = h * stride[0] * bytesPerPixel(format);
+ rec.size = h * stride[0] * bpp;
list.add(*handle, rec);
}
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 0af7f80..688b998 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -280,6 +280,9 @@
uint64_t axisBit = 1LL << axis;
uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
if (!(bits & axisBit)) {
+ if (value == 0) {
+ return OK; // axes with value 0 do not need to be stored
+ }
uint32_t count = __builtin_popcountll(bits);
if (count >= MAX_AXES) {
tooManyAxes(axis);
@@ -294,23 +297,10 @@
return OK;
}
-float* PointerCoords::editAxisValue(int32_t axis) {
- if (axis < 0 || axis > 63) {
- return NULL;
- }
-
- uint64_t axisBit = 1LL << axis;
- if (!(bits & axisBit)) {
- return NULL;
- }
- uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
- return &values[index];
-}
-
static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) {
- float* value = c.editAxisValue(axis);
- if (value) {
- *value *= scaleFactor;
+ float value = c.getAxisValue(axis);
+ if (value != 0) {
+ c.setAxisValue(axis, value * scaleFactor);
}
}
@@ -574,20 +564,14 @@
size_t numSamples = mSamplePointerCoords.size();
for (size_t i = 0; i < numSamples; i++) {
PointerCoords& c = mSamplePointerCoords.editItemAt(i);
- float* xPtr = c.editAxisValue(AMOTION_EVENT_AXIS_X);
- float* yPtr = c.editAxisValue(AMOTION_EVENT_AXIS_Y);
- if (xPtr && yPtr) {
- float x = *xPtr + oldXOffset;
- float y = *yPtr + oldYOffset;
- matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), & point);
- *xPtr = SkScalarToFloat(point.fX) - newXOffset;
- *yPtr = SkScalarToFloat(point.fY) - newYOffset;
- }
+ float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset;
+ float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset;
+ matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point);
+ c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset);
+ c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset);
- float* orientationPtr = c.editAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
- if (orientationPtr) {
- *orientationPtr = transformAngle(matrix, *orientationPtr);
- }
+ float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
+ c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation));
}
}
@@ -727,7 +711,7 @@
}
while (idBits.count() > MAX_POINTERS) {
- idBits.clearBit(idBits.lastMarkedBit());
+ idBits.clearLastMarkedBit();
}
Movement& movement = mMovements[mIndex];
@@ -776,7 +760,7 @@
// We do this on down instead of on up because the client may want to query the
// final velocity for a pointer that just went up.
BitSet32 downIdBits;
- downIdBits.markBit(event->getActionIndex());
+ downIdBits.markBit(event->getPointerId(event->getActionIndex()));
clearPointers(downIdBits);
break;
}
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
index 693a32a..700b604 100644
--- a/libs/ui/tests/Android.mk
+++ b/libs/ui/tests/Android.mk
@@ -45,4 +45,4 @@
)
# Build the manual test programs.
-include $(call all-subdir-makefiles)
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/libs/ui/tests/InputEvent_test.cpp b/libs/ui/tests/InputEvent_test.cpp
index e48d5b7..e21c464 100644
--- a/libs/ui/tests/InputEvent_test.cpp
+++ b/libs/ui/tests/InputEvent_test.cpp
@@ -52,9 +52,6 @@
ASSERT_EQ(0, coords.getAxisValue(1))
<< "getAxisValue should return zero because axis is not present";
- ASSERT_EQ(NULL, coords.editAxisValue(0))
- << "editAxisValue should return null because axis is not present";
-
// Set first axis.
ASSERT_EQ(OK, coords.setAxisValue(1, 5));
ASSERT_EQ(0x00000002ULL, coords.bits);
@@ -96,26 +93,17 @@
ASSERT_EQ(2, coords.getAxisValue(3))
<< "getAxisValue should return value of axis";
- // Edit an existing axis value in place.
- valuePtr = coords.editAxisValue(1);
- ASSERT_EQ(5, *valuePtr)
- << "editAxisValue should return pointer to axis value";
-
- *valuePtr = 7;
- ASSERT_EQ(7, coords.getAxisValue(1))
- << "getAxisValue should return value of axis";
-
// Set an axis with an id between the others. (inserting value in the middle)
ASSERT_EQ(OK, coords.setAxisValue(2, 1));
ASSERT_EQ(0x0000000fULL, coords.bits);
ASSERT_EQ(4, coords.values[0]);
- ASSERT_EQ(7, coords.values[1]);
+ ASSERT_EQ(5, coords.values[1]);
ASSERT_EQ(1, coords.values[2]);
ASSERT_EQ(2, coords.values[3]);
ASSERT_EQ(4, coords.getAxisValue(0))
<< "getAxisValue should return value of axis";
- ASSERT_EQ(7, coords.getAxisValue(1))
+ ASSERT_EQ(5, coords.getAxisValue(1))
<< "getAxisValue should return value of axis";
ASSERT_EQ(1, coords.getAxisValue(2))
<< "getAxisValue should return value of axis";
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index f633357..e4eadbd 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -29,7 +29,6 @@
Flattenable.cpp \
LinearTransform.cpp \
ObbFile.cpp \
- Pool.cpp \
PropertyMap.cpp \
RefBase.cpp \
ResourceTypes.cpp \
diff --git a/libs/utils/Pool.cpp b/libs/utils/Pool.cpp
deleted file mode 100644
index 8f18cb9..0000000
--- a/libs/utils/Pool.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-// A simple memory pool.
-//
-#define LOG_TAG "Pool"
-
-//#define LOG_NDEBUG 0
-
-#include <cutils/log.h>
-#include <utils/Pool.h>
-
-#include <stdlib.h>
-
-namespace android {
-
-// TODO Provide a real implementation of a pool. This is just a stub for initial development.
-
-PoolImpl::PoolImpl(size_t objSize) :
- mObjSize(objSize) {
-}
-
-PoolImpl::~PoolImpl() {
-}
-
-void* PoolImpl::allocImpl() {
- void* ptr = malloc(mObjSize);
- LOG_ALWAYS_FATAL_IF(ptr == NULL, "Cannot allocate new pool object.");
- return ptr;
-}
-
-void PoolImpl::freeImpl(void* obj) {
- LOG_ALWAYS_FATAL_IF(obj == NULL, "Caller attempted to free NULL pool object.");
- return free(obj);
-}
-
-} // namespace android
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index 8db2009..37d061c 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -49,11 +49,6 @@
// ---------------------------------------------------------------------------
-RefBase::Destroyer::~Destroyer() {
-}
-
-// ---------------------------------------------------------------------------
-
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
@@ -61,7 +56,6 @@
volatile int32_t mWeak;
RefBase* const mBase;
volatile int32_t mFlags;
- Destroyer* mDestroyer;
#if !DEBUG_REFS
@@ -70,7 +64,6 @@
, mWeak(0)
, mBase(base)
, mFlags(0)
- , mDestroyer(0)
{
}
@@ -113,7 +106,7 @@
LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
refs->stack.dump();
-#endif;
+#endif
refs = refs->next;
}
}
@@ -131,7 +124,7 @@
LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
refs->stack.dump();
-#endif;
+#endif
refs = refs->next;
}
}
@@ -193,7 +186,7 @@
String8 text;
{
- Mutex::Autolock _l(const_cast<weakref_impl*>(this)->mMutex);
+ Mutex::Autolock _l(mMutex);
char buf[128];
sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
text.append(buf);
@@ -318,7 +311,7 @@
}
}
- Mutex mMutex;
+ mutable Mutex mMutex;
ref_entry* mStrongRefs;
ref_entry* mWeakRefs;
@@ -348,7 +341,7 @@
}
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
- const_cast<RefBase*>(this)->onFirstRef();
+ refs->mBase->onFirstRef();
}
void RefBase::decStrong(const void* id) const
@@ -361,13 +354,9 @@
#endif
LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
if (c == 1) {
- const_cast<RefBase*>(this)->onLastStrongRef(id);
- if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
- if (refs->mDestroyer) {
- refs->mDestroyer->destroy(this);
- } else {
- delete this;
- }
+ refs->mBase->onLastStrongRef(id);
+ if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
+ delete this;
}
}
refs->decWeak(id);
@@ -391,7 +380,7 @@
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
// fall through...
case 0:
- const_cast<RefBase*>(this)->onFirstRef();
+ refs->mBase->onFirstRef();
}
}
@@ -400,10 +389,6 @@
return mRefs->mStrong;
}
-void RefBase::setDestroyer(RefBase::Destroyer* destroyer) {
- mRefs->mDestroyer = destroyer;
-}
-
RefBase* RefBase::weakref_type::refBase() const
{
return static_cast<const weakref_impl*>(this)->mBase;
@@ -417,6 +402,7 @@
LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
+
void RefBase::weakref_type::decWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
@@ -424,30 +410,27 @@
const int32_t c = android_atomic_dec(&impl->mWeak);
LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
if (c != 1) return;
-
- if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
+
+ if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
+ // This is the regular lifetime case. The object is destroyed
+ // when the last strong reference goes away. Since weakref_impl
+ // outlive the object, it is not destroyed in the dtor, and
+ // we'll have to do it here.
if (impl->mStrong == INITIAL_STRONG_VALUE) {
- if (impl->mBase) {
- if (impl->mDestroyer) {
- impl->mDestroyer->destroy(impl->mBase);
- } else {
- delete impl->mBase;
- }
- }
+ // Special case: we never had a strong reference, so we need to
+ // destroy the object now.
+ delete impl->mBase;
} else {
// LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
delete impl;
}
} else {
+ // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
impl->mBase->onLastWeakRef(id);
- if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
- if (impl->mBase) {
- if (impl->mDestroyer) {
- impl->mDestroyer->destroy(impl->mBase);
- } else {
- delete impl->mBase;
- }
- }
+ if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
+ // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
+ // is gone, we can destroy the object.
+ delete impl->mBase;
}
}
}
@@ -569,11 +552,23 @@
RefBase::~RefBase()
{
- if ((mRefs->mFlags & OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK) {
- if (mRefs->mWeak == 0) {
- delete mRefs;
+ if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
+ // we never acquired a strong (and/or weak) reference on this object.
+ delete mRefs;
+ } else {
+ // life-time of this object is extended to WEAK or FOREVER, in
+ // which case weakref_impl doesn't out-live the object and we
+ // can free it now.
+ if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
+ // It's possible that the weak count is not 0 if the object
+ // re-acquired a weak reference in its destructor
+ if (mRefs->mWeak == 0) {
+ delete mRefs;
+ }
}
}
+ // for debugging purposes, clear this.
+ const_cast<weakref_impl*&>(mRefs) = NULL;
}
void RefBase::extendObjectLifetime(int32_t mode)
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index cb6c246..6cf01c8 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -4346,7 +4346,8 @@
| (0x0000ffff & (entryIndex));
resource_name resName;
if (!this->getResourceName(resID, &resName)) {
- return UNKNOWN_ERROR;
+ LOGW("idmap: resource 0x%08x has spec but lacks values, skipping\n", resID);
+ continue;
}
const String16 overlayType(resName.type, resName.typeLen);
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 8726a53..b97f52f 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -8,7 +8,8 @@
ObbFile_test.cpp \
Looper_test.cpp \
String8_test.cpp \
- Unicode_test.cpp
+ Unicode_test.cpp \
+ ZipFileRO_test.cpp \
shared_libraries := \
libz \
diff --git a/libs/utils/tests/ZipFileRO_test.cpp b/libs/utils/tests/ZipFileRO_test.cpp
new file mode 100644
index 0000000..7a1d0bd
--- /dev/null
+++ b/libs/utils/tests/ZipFileRO_test.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 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 "ZipFileRO_test"
+#include <utils/Log.h>
+#include <utils/ZipFileRO.h>
+
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <string.h>
+
+namespace android {
+
+class ZipFileROTest : public testing::Test {
+protected:
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+};
+
+TEST_F(ZipFileROTest, ZipTimeConvertSuccess) {
+ struct tm t;
+
+ // 2011-06-29 14:40:40
+ long when = 0x3EDD7514;
+
+ ZipFileRO::zipTimeToTimespec(when, &t);
+
+ EXPECT_EQ(2011, t.tm_year + 1900)
+ << "Year was improperly converted.";
+
+ EXPECT_EQ(6, t.tm_mon)
+ << "Month was improperly converted.";
+
+ EXPECT_EQ(29, t.tm_mday)
+ << "Day was improperly converted.";
+
+ EXPECT_EQ(14, t.tm_hour)
+ << "Hour was improperly converted.";
+
+ EXPECT_EQ(40, t.tm_min)
+ << "Minute was improperly converted.";
+
+ EXPECT_EQ(40, t.tm_sec)
+ << "Second was improperly converted.";
+}
+
+}
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 1123e16..6a199db 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -226,7 +226,7 @@
#ifndef EGL_ANDROID_image_native_buffer
#define EGL_ANDROID_image_native_buffer 1
struct ANativeWindowBuffer;
-#define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */
+#define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */
#endif
#ifndef EGL_ANDROID_swap_rectangle
@@ -237,6 +237,11 @@
typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSWAPRECTANGLEANDROIDPROC) (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
#endif
+#ifndef EGL_ANDROID_recordable
+#define EGL_ANDROID_recordable 1
+#define EGL_RECORDABLE_ANDROID 0x3142 /* EGLConfig attribute */
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index ba5d29a..10cea22 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -363,6 +363,12 @@
EGLConfig iConfig = dp->configs[intptr_t(config)].config;
EGLint format;
+ if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
+ LOGE("EGLNativeWindowType %p already connected to another API",
+ window);
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+
// set the native window's buffers format to match this config
if (cnx->egl.eglGetConfigAttrib(iDpy,
iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
@@ -371,6 +377,7 @@
if (err != 0) {
LOGE("error setting native window pixel format: %s (%d)",
strerror(-err), err);
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
}
}
@@ -383,6 +390,10 @@
dp->configs[intptr_t(config)].impl, cnx);
return s;
}
+
+ // EGLSurface creation failed
+ native_window_set_buffers_format(window, 0);
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
}
return EGL_NO_SURFACE;
}
@@ -443,8 +454,12 @@
EGLBoolean result = s->cnx->egl.eglDestroySurface(
dp->disp[s->impl].dpy, s->surface);
if (result == EGL_TRUE) {
- if (s->win != NULL) {
- native_window_set_buffers_geometry(s->win.get(), 0, 0, 0);
+ ANativeWindow* const window = s->win.get();
+ if (window != NULL) {
+ native_window_set_buffers_format(window, 0);
+ if (native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL)) {
+ LOGE("EGLNativeWindowType %p disconnected failed", window);
+ }
}
_s.terminate();
}
diff --git a/opengl/specs/EGL_ANDROID_recordable.txt b/opengl/specs/EGL_ANDROID_recordable.txt
index cf44465..8dbd26f 100644
--- a/opengl/specs/EGL_ANDROID_recordable.txt
+++ b/opengl/specs/EGL_ANDROID_recordable.txt
@@ -55,7 +55,7 @@
Accepted by the <attribute> parameter of eglGetConfigAttrib and
the <attrib_list> parameter of eglChooseConfig:
- EGL_RECORDABLE_ANDROID 0xXXXX
+ EGL_RECORDABLE_ANDROID 0x3142
Changes to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
@@ -103,11 +103,38 @@
RESOLVED: It should not affect sorting. Some implementations may not have
any drawback associated with using a recordable EGLConfig. Such
- implementations should not have to double-up some of their configs to one sort earlier than .
- Implementations that do have drawbacks can use the existing caveat
- mechanism to report this drawback to the client.
+ implementations should not have to double-up some of their configs to one
+ sort earlier than . Implementations that do have drawbacks can use the
+ existing caveat mechanism to report this drawback to the client.
+
+ 3. How is this extension expected to be implemented?
+
+ RESPONSE: There are two basic approaches to implementing this extension
+ that were considered during its design. In both cases it is assumed that a
+ color space conversion must be performed at some point because most video
+ encoding formats use a YUV color space. The two approaches are
+ distinguished by the point at which this color space conversion is
+ performed.
+
+ One approach involves performing the color space conversion as part of the
+ eglSwapBuffers call before queuing the rendered image to the ANativeWindow.
+ In this case, the VisualID of the EGLConfig would correspond to a YUV
+ Android HAL pixel format from which the video encoder can read. The
+ EGLConfig would likely have the EGL_SLOW_CONFIG caveat because using that
+ config to render normal window contents would result in an RGB -> YUV color
+ space conversion when rendering the frame as well as a YUV -> RGB
+ conversion when compositing the window.
+
+ The other approach involves performing the color space conversion in the
+ video encoder. In this case, the VisualID of the EGLConfig would
+ correspond to an RGB HAL pixel format from which the video encoder can
+ read. The EGLConfig would likely not need to have any caveat set, as using
+ this config for normal window rendering would not have any added cost.
Revision History
+#2 (Jamie Gennis, July 15, 2011)
+ - Added issue 3.
+
#1 (Jamie Gennis, July 8, 2011)
- Initial draft.
diff --git a/opengl/tests/gl2_copyTexImage/Android.mk b/opengl/tests/gl2_copyTexImage/Android.mk
new file mode 100644
index 0000000..bef1f90
--- /dev/null
+++ b/opengl/tests/gl2_copyTexImage/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ gl2_copyTexImage.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv2 \
+ libui
+
+LOCAL_MODULE:= test-opengl-gl2_copyTexImage
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
new file mode 100644
index 0000000..c2bfdec
--- /dev/null
+++ b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <utils/Timers.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+static void printGLString(const char *name, GLenum s) {
+ // fprintf(stderr, "printGLString %s, %d\n", name, s);
+ const char *v = (const char *) glGetString(s);
+ // int error = glGetError();
+ // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error,
+ // (unsigned int) v);
+ // if ((v < (const char*) 0) || (v > (const char*) 0x10000))
+ // fprintf(stderr, "GL %s = %s\n", name, v);
+ // else
+ // fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v);
+ fprintf(stderr, "GL %s = %s\n", name, v);
+}
+
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+ if (returnVal != EGL_TRUE) {
+ fprintf(stderr, "%s() returned %d\n", op, returnVal);
+ }
+
+ for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+ = eglGetError()) {
+ fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
+ error);
+ }
+}
+
+static void checkGlError(const char* op) {
+ for (GLint error = glGetError(); error; error
+ = glGetError()) {
+ fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
+ }
+}
+
+static const char gVertexShader[] = "attribute vec4 vPosition;\n"
+ "void main() {\n"
+ " gl_Position = vPosition;\n"
+ "}\n";
+
+static const char gFragmentShader[] = "precision mediump float;\n"
+ "void main() {\n"
+ " gl_FragColor = vec4(0.0, 1.0, 0.0, 0.5);\n"
+ "}\n";
+
+GLuint loadShader(GLenum shaderType, const char* pSource) {
+ GLuint shader = glCreateShader(shaderType);
+ if (shader) {
+ glShaderSource(shader, 1, &pSource, NULL);
+ glCompileShader(shader);
+ GLint compiled = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLint infoLen = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen) {
+ char* buf = (char*) malloc(infoLen);
+ if (buf) {
+ glGetShaderInfoLog(shader, infoLen, NULL, buf);
+ fprintf(stderr, "Could not compile shader %d:\n%s\n",
+ shaderType, buf);
+ free(buf);
+ }
+ glDeleteShader(shader);
+ shader = 0;
+ }
+ }
+ }
+ return shader;
+}
+
+GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
+ GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+ if (!vertexShader) {
+ return 0;
+ }
+
+ GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+ if (!pixelShader) {
+ return 0;
+ }
+
+ GLuint program = glCreateProgram();
+ if (program) {
+ glAttachShader(program, vertexShader);
+ checkGlError("glAttachShader");
+ glAttachShader(program, pixelShader);
+ checkGlError("glAttachShader");
+ glLinkProgram(program);
+ GLint linkStatus = GL_FALSE;
+ glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+ if (linkStatus != GL_TRUE) {
+ GLint bufLength = 0;
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+ if (bufLength) {
+ char* buf = (char*) malloc(bufLength);
+ if (buf) {
+ glGetProgramInfoLog(program, bufLength, NULL, buf);
+ fprintf(stderr, "Could not link program:\n%s\n", buf);
+ free(buf);
+ }
+ }
+ glDeleteProgram(program);
+ program = 0;
+ }
+ }
+ return program;
+}
+
+GLuint gProgram;
+GLuint gTextureProgram;
+GLuint gvPositionHandle;
+GLuint gvTexturePositionHandle;
+GLuint gvTextureTexCoordsHandle;
+GLuint gvTextureSamplerHandle;
+GLuint gFbo;
+GLuint gTexture;
+GLuint gBufferTexture;
+
+static const char gSimpleVS[] =
+ "attribute vec4 position;\n"
+ "attribute vec2 texCoords;\n"
+ "varying vec2 outTexCoords;\n"
+ "\nvoid main(void) {\n"
+ " outTexCoords = texCoords;\n"
+ " gl_Position = position;\n"
+ "}\n\n";
+static const char gSimpleFS[] =
+ "precision mediump float;\n\n"
+ "varying vec2 outTexCoords;\n"
+ "uniform sampler2D texture;\n"
+ "\nvoid main(void) {\n"
+ " gl_FragColor = texture2D(texture, outTexCoords);\n"
+ "}\n\n";
+
+bool setupGraphics(int w, int h) {
+ gProgram = createProgram(gVertexShader, gFragmentShader);
+ if (!gProgram) {
+ return false;
+ }
+ gvPositionHandle = glGetAttribLocation(gProgram, "vPosition");
+ checkGlError("glGetAttribLocation");
+ fprintf(stderr, "glGetAttribLocation(\"vPosition\") = %d\n", gvPositionHandle);
+
+ gTextureProgram = createProgram(gSimpleVS, gSimpleFS);
+ if (!gTextureProgram) {
+ return false;
+ }
+ gvTexturePositionHandle = glGetAttribLocation(gTextureProgram, "position");
+ checkGlError("glGetAttribLocation");
+ gvTextureTexCoordsHandle = glGetAttribLocation(gTextureProgram, "texCoords");
+ checkGlError("glGetAttribLocation");
+ gvTextureSamplerHandle = glGetUniformLocation(gTextureProgram, "texture");
+ checkGlError("glGetAttribLocation");
+
+ glActiveTexture(GL_TEXTURE0);
+
+ glGenTextures(1, &gTexture);
+ glBindTexture(GL_TEXTURE_2D, gTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glGenTextures(1, &gBufferTexture);
+ glBindTexture(GL_TEXTURE_2D, gBufferTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glGenFramebuffers(1, &gFbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, gFbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gTexture, 0);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ glViewport(0, 0, w, h);
+ checkGlError("glViewport");
+ return true;
+}
+
+const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f,
+ 0.5f, -0.5f };
+
+const GLint FLOAT_SIZE_BYTES = 4;
+const GLint TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
+const GLfloat gTriangleVerticesData[] = {
+ // X, Y, Z, U, V
+ -1.0f, -1.0f, 0, 0.f, 0.f,
+ 1.0f, -1.0f, 0, 1.f, 0.f,
+ -1.0f, 1.0f, 0, 0.f, 1.f,
+ 1.0f, 1.0f, 0, 1.f, 1.f,
+};
+
+void renderFrame(GLint w, GLint h) {
+ glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+ checkGlError("glClearColor");
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ checkGlError("glClear");
+
+ // Bind FBO and draw into it
+ glBindFramebuffer(GL_FRAMEBUFFER, gFbo);
+ checkGlError("glBindFramebuffer");
+
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ checkGlError("glClearColor");
+ glClear(GL_COLOR_BUFFER_BIT);
+ checkGlError("glClear");
+
+ glUseProgram(gProgram);
+ checkGlError("glUseProgram");
+
+ glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
+ checkGlError("glVertexAttribPointer");
+ glEnableVertexAttribArray(gvPositionHandle);
+ checkGlError("glEnableVertexAttribArray");
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+ checkGlError("glDrawArrays");
+
+ // Copy content of FBO into a texture
+ glBindTexture(GL_TEXTURE_2D, gBufferTexture);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w / 2, h / 2);
+ checkGlError("glCopyTexSubImage2D");
+
+ // Back to the display
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ checkGlError("glBindFramebuffer");
+
+ // Draw copied content on the screen
+ glUseProgram(gTextureProgram);
+ checkGlError("glUseProgram");
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ glVertexAttribPointer(gvTexturePositionHandle, 3, GL_FLOAT, GL_FALSE,
+ TRIANGLE_VERTICES_DATA_STRIDE_BYTES, gTriangleVerticesData);
+ checkGlError("glVertexAttribPointer");
+ glVertexAttribPointer(gvTextureTexCoordsHandle, 2, GL_FLOAT, GL_FALSE,
+ TRIANGLE_VERTICES_DATA_STRIDE_BYTES, &gTriangleVerticesData[3]);
+ checkGlError("glVertexAttribPointer");
+ glEnableVertexAttribArray(gvTexturePositionHandle);
+ glEnableVertexAttribArray(gvTextureTexCoordsHandle);
+ checkGlError("glEnableVertexAttribArray");
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ checkGlError("glDrawArrays");
+}
+
+void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
+
+#define X(VAL) {VAL, #VAL}
+ struct {EGLint attribute; const char* name;} names[] = {
+ X(EGL_BUFFER_SIZE),
+ X(EGL_ALPHA_SIZE),
+ X(EGL_BLUE_SIZE),
+ X(EGL_GREEN_SIZE),
+ X(EGL_RED_SIZE),
+ X(EGL_DEPTH_SIZE),
+ X(EGL_STENCIL_SIZE),
+ X(EGL_CONFIG_CAVEAT),
+ X(EGL_CONFIG_ID),
+ X(EGL_LEVEL),
+ X(EGL_MAX_PBUFFER_HEIGHT),
+ X(EGL_MAX_PBUFFER_PIXELS),
+ X(EGL_MAX_PBUFFER_WIDTH),
+ X(EGL_NATIVE_RENDERABLE),
+ X(EGL_NATIVE_VISUAL_ID),
+ X(EGL_NATIVE_VISUAL_TYPE),
+ X(EGL_SAMPLES),
+ X(EGL_SAMPLE_BUFFERS),
+ X(EGL_SURFACE_TYPE),
+ X(EGL_TRANSPARENT_TYPE),
+ X(EGL_TRANSPARENT_RED_VALUE),
+ X(EGL_TRANSPARENT_GREEN_VALUE),
+ X(EGL_TRANSPARENT_BLUE_VALUE),
+ X(EGL_BIND_TO_TEXTURE_RGB),
+ X(EGL_BIND_TO_TEXTURE_RGBA),
+ X(EGL_MIN_SWAP_INTERVAL),
+ X(EGL_MAX_SWAP_INTERVAL),
+ X(EGL_LUMINANCE_SIZE),
+ X(EGL_ALPHA_MASK_SIZE),
+ X(EGL_COLOR_BUFFER_TYPE),
+ X(EGL_RENDERABLE_TYPE),
+ X(EGL_CONFORMANT),
+ };
+#undef X
+
+ for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
+ EGLint value = -1;
+ EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
+ EGLint error = eglGetError();
+ if (returnVal && error == EGL_SUCCESS) {
+ printf(" %s: ", names[j].name);
+ printf("%d (0x%x)", value, value);
+ }
+ }
+ printf("\n");
+}
+
+int printEGLConfigurations(EGLDisplay dpy) {
+ EGLint numConfig = 0;
+ EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig);
+ checkEglError("eglGetConfigs", returnVal);
+ if (!returnVal) {
+ return false;
+ }
+
+ printf("Number of EGL configuration: %d\n", numConfig);
+
+ EGLConfig* configs = (EGLConfig*) malloc(sizeof(EGLConfig) * numConfig);
+ if (! configs) {
+ printf("Could not allocate configs.\n");
+ return false;
+ }
+
+ returnVal = eglGetConfigs(dpy, configs, numConfig, &numConfig);
+ checkEglError("eglGetConfigs", returnVal);
+ if (!returnVal) {
+ free(configs);
+ return false;
+ }
+
+ for(int i = 0; i < numConfig; i++) {
+ printf("Configuration %d\n", i);
+ printEGLConfiguration(dpy, configs[i]);
+ }
+
+ free(configs);
+ return true;
+}
+
+int main(int argc, char** argv) {
+ EGLBoolean returnValue;
+ EGLConfig myConfig = {0};
+
+ EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ EGLint s_configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_NONE };
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLSurface surface;
+ EGLint w, h;
+
+ EGLDisplay dpy;
+
+ checkEglError("<init>");
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ checkEglError("eglGetDisplay");
+ if (dpy == EGL_NO_DISPLAY) {
+ printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
+ return 0;
+ }
+
+ returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
+ checkEglError("eglInitialize", returnValue);
+ fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion);
+ if (returnValue != EGL_TRUE) {
+ printf("eglInitialize failed\n");
+ return 0;
+ }
+
+ if (!printEGLConfigurations(dpy)) {
+ printf("printEGLConfigurations failed\n");
+ return 0;
+ }
+
+ checkEglError("printEGLConfigurations");
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+ EGLint numConfigs = -1, n = 0;
+ eglChooseConfig(dpy, s_configAttribs, 0, 0, &numConfigs);
+ if (numConfigs) {
+ EGLConfig* const configs = new EGLConfig[numConfigs];
+ eglChooseConfig(dpy, s_configAttribs, configs, numConfigs, &n);
+ myConfig = configs[0];
+ delete[] configs;
+ }
+
+ checkEglError("EGLUtils::selectConfigForNativeWindow");
+
+ printf("Chose this configuration:\n");
+ printEGLConfiguration(dpy, myConfig);
+
+ surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
+ checkEglError("eglCreateWindowSurface");
+ if (surface == EGL_NO_SURFACE) {
+ printf("gelCreateWindowSurface failed.\n");
+ return 0;
+ }
+
+ context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs);
+ checkEglError("eglCreateContext");
+ if (context == EGL_NO_CONTEXT) {
+ printf("eglCreateContext failed\n");
+ return 0;
+ }
+ returnValue = eglMakeCurrent(dpy, surface, surface, context);
+ checkEglError("eglMakeCurrent", returnValue);
+ if (returnValue != EGL_TRUE) {
+ return 0;
+ }
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ checkEglError("eglQuerySurface");
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+ checkEglError("eglQuerySurface");
+ GLint dim = w < h ? w : h;
+
+ fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
+
+ printGLString("Version", GL_VERSION);
+ printGLString("Vendor", GL_VENDOR);
+ printGLString("Renderer", GL_RENDERER);
+ printGLString("Extensions", GL_EXTENSIONS);
+
+ if(!setupGraphics(w, h)) {
+ fprintf(stderr, "Could not set up graphics.\n");
+ return 0;
+ }
+
+ for (;;) {
+ renderFrame(w, h);
+ eglSwapBuffers(dpy, surface);
+ checkEglError("eglSwapBuffers");
+ }
+
+ return 0;
+}
diff --git a/opengl/tests/swapinterval/swapinterval.cpp b/opengl/tests/swapinterval/swapinterval.cpp
index df53b62..8ca031b 100644
--- a/opengl/tests/swapinterval/swapinterval.cpp
+++ b/opengl/tests/swapinterval/swapinterval.cpp
@@ -48,31 +48,35 @@
EGLNativeWindowType window = android_createDisplaySurface();
dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(dpy, 0 ,0) ;//&majorVersion, &minorVersion);
+ eglInitialize(dpy, &majorVersion, &minorVersion);
eglGetConfigs(dpy, NULL, 0, &numConfigs);
printf("# configs = %d\n", numConfigs);
status_t err = EGLUtils::selectConfigForNativeWindow(
dpy, configAttribs, window, &config);
if (err) {
- fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ fprintf(stderr, "error: %s", EGLUtils::strerror(eglGetError()));
+ eglTerminate(dpy);
return 0;
}
- EGLint r,g,b,a;
+ EGLint r,g,b,a, vid;
eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r);
eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g);
eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b);
eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a);
+ eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &vid);
surface = eglCreateWindowSurface(dpy, config, window, NULL);
if (surface == EGL_NO_SURFACE) {
EGLint err = eglGetError();
- fprintf(stderr, "%s, config=%p, format = %d-%d-%d-%d\n",
- EGLUtils::strerror(err), config, r,g,b,a);
+ fprintf(stderr, "error: %s, config=%p, format = %d-%d-%d-%d, visual-id = %d\n",
+ EGLUtils::strerror(err), config, r,g,b,a, vid);
+ eglTerminate(dpy);
return 0;
} else {
- printf("config=%p, format = %d-%d-%d-%d\n", config, r,g,b,a);
+ printf("config=%p, format = %d-%d-%d-%d, visual-id = %d\n",
+ config, r,g,b,a, vid);
}
context = eglCreateContext(dpy, config, NULL, NULL);
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index f67c82e..b178e49 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -22,7 +22,7 @@
LOCAL_CFLAGS += -DNO_RGBX_8888
endif
ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
- LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
+ LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY -DNEVER_DEFAULT_TO_ASYNC_MODE
endif
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 7bf3e0a..f4be168 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -40,6 +40,7 @@
#include "GLExtensions.h"
#include "HWComposer.h"
+#include "SurfaceFlinger.h"
using namespace android;
@@ -75,7 +76,7 @@
const sp<SurfaceFlinger>& flinger,
uint32_t dpy)
: DisplayHardwareBase(flinger, dpy),
- mFlags(0), mHwc(0)
+ mFlinger(flinger), mFlags(0), mHwc(0)
{
init(dpy);
}
@@ -310,7 +311,7 @@
// initialize the H/W composer
- mHwc = new HWComposer();
+ mHwc = new HWComposer(mFlinger);
if (mHwc->initCheck() == NO_ERROR) {
mHwc->setFrameBuffer(mDisplay, mSurface);
}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index cdf89fd..40a6f1e 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -95,6 +95,7 @@
void init(uint32_t displayIndex) __attribute__((noinline));
void fini() __attribute__((noinline));
+ sp<SurfaceFlinger> mFlinger;
EGLDisplay mDisplay;
EGLSurface mSurface;
EGLContext mContext;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
index 30eb258..3ebc7b6 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -37,7 +37,7 @@
~DisplayHardwareBase();
- // console managment
+ // console management
void releaseScreen() const;
void acquireScreen() const;
bool isScreenAcquired() const;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 4a3b20d..7d1bdf0 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -30,12 +30,14 @@
#include <EGL/egl.h>
#include "HWComposer.h"
+#include "SurfaceFlinger.h"
namespace android {
// ---------------------------------------------------------------------------
-HWComposer::HWComposer()
- : mModule(0), mHwc(0), mList(0), mCapacity(0),
+HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger)
+ : mFlinger(flinger),
+ mModule(0), mHwc(0), mList(0), mCapacity(0),
mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE)
{
int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
@@ -44,6 +46,13 @@
err = hwc_open(mModule, &mHwc);
LOGE_IF(err, "%s device failed to initialize (%s)",
HWC_HARDWARE_COMPOSER, strerror(-err));
+ if (err == 0) {
+ if (mHwc->registerProcs) {
+ mCBContext.hwc = this;
+ mCBContext.procs.invalidate = &hook_invalidate;
+ mHwc->registerProcs(mHwc, &mCBContext.procs);
+ }
+ }
}
}
@@ -58,6 +67,14 @@
return mHwc ? NO_ERROR : NO_INIT;
}
+void HWComposer::hook_invalidate(struct hwc_procs* procs) {
+ reinterpret_cast<cb_context *>(procs)->hwc->invalidate();
+}
+
+void HWComposer::invalidate() {
+ mFlinger->signalEvent();
+}
+
void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) {
mDpy = (hwc_display_t)dpy;
mSur = (hwc_surface_t)sur;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 5a9e9eb..983898a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -24,16 +24,19 @@
#include <hardware/hwcomposer.h>
+#include <utils/StrongPointer.h>
+
namespace android {
// ---------------------------------------------------------------------------
class String8;
+class SurfaceFlinger;
class HWComposer
{
public:
- HWComposer();
+ HWComposer(const sp<SurfaceFlinger>& flinger);
~HWComposer();
status_t initCheck() const;
@@ -60,12 +63,21 @@
void dump(String8& out, char* scratch, size_t SIZE) const;
private:
+ struct cb_context {
+ hwc_procs_t procs;
+ HWComposer* hwc;
+ };
+ static void hook_invalidate(struct hwc_procs* procs);
+ void invalidate();
+
+ sp<SurfaceFlinger> mFlinger;
hw_module_t const* mModule;
hwc_composer_device_t* mHwc;
hwc_layer_list_t* mList;
size_t mCapacity;
hwc_display_t mDpy;
hwc_surface_t mSur;
+ cb_context mCBContext;
};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f3b6c4d..0425fc3 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -44,10 +44,6 @@
namespace android {
-template <typename T> inline T min(T a, T b) {
- return a<b ? a : b;
-}
-
// ---------------------------------------------------------------------------
Layer::Layer(SurfaceFlinger* flinger,
@@ -56,27 +52,22 @@
mTextureName(-1U),
mQueuedFrames(0),
mCurrentTransform(0),
+ mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mCurrentOpacity(true),
mFormat(PIXEL_FORMAT_NONE),
mGLExtensions(GLExtensions::getInstance()),
mOpaqueLayer(true),
mNeedsDithering(false),
mSecure(false),
- mProtectedByApp(false),
- mFixedSize(false)
+ mProtectedByApp(false)
{
mCurrentCrop.makeInvalid();
glGenTextures(1, &mTextureName);
}
-void Layer::destroy(RefBase const* base) {
- mFlinger->destroyLayer(static_cast<LayerBase const*>(base));
-}
-
void Layer::onFirstRef()
{
LayerBaseClient::onFirstRef();
- setDestroyer(this);
struct FrameQueuedListener : public SurfaceTexture::FrameAvailableListener {
FrameQueuedListener(Layer* layer) : mLayer(layer) { }
@@ -97,7 +88,16 @@
Layer::~Layer()
{
- glDeleteTextures(1, &mTextureName);
+ class MessageDestroyGLState : public MessageBase {
+ GLuint texture;
+ public:
+ MessageDestroyGLState(GLuint texture) : texture(texture) { }
+ virtual bool handler() {
+ glDeleteTextures(1, &texture);
+ return true;
+ }
+ };
+ mFlinger->postMessageAsync( new MessageDestroyGLState(mTextureName) );
}
void Layer::onFrameQueued() {
@@ -109,6 +109,7 @@
// in the purgatory list
void Layer::onRemoved()
{
+ mSurfaceTexture->abandon();
}
sp<ISurface> Layer::createSurface()
@@ -175,17 +176,14 @@
void Layer::setGeometry(hwc_layer_t* hwcl)
{
- hwcl->compositionType = HWC_FRAMEBUFFER;
- hwcl->hints = 0;
- hwcl->flags = 0;
- hwcl->transform = 0;
- hwcl->blending = HWC_BLENDING_NONE;
+ LayerBaseClient::setGeometry(hwcl);
+
+ hwcl->flags &= ~HWC_SKIP_LAYER;
// we can't do alpha-fade with the hwc HAL
const State& s(drawingState());
if (s.alpha < 0xFF) {
hwcl->flags = HWC_SKIP_LAYER;
- return;
}
/*
@@ -193,14 +191,13 @@
* 1) buffer orientation/flip/mirror
* 2) state transformation (window manager)
* 3) layer orientation (screen orientation)
+ * mOrientation is already the composition of (2) and (3)
* (NOTE: the matrices are multiplied in reverse order)
*/
const Transform bufferOrientation(mCurrentTransform);
- const Transform& stateTransform(s.transform);
const Transform layerOrientation(mOrientation);
-
- const Transform tr(layerOrientation * stateTransform * bufferOrientation);
+ const Transform tr(layerOrientation * bufferOrientation);
// this gives us only the "orientation" component of the transform
const uint32_t finalTransform = tr.getOrientation();
@@ -208,26 +205,9 @@
// we can only handle simple transformation
if (finalTransform & Transform::ROT_INVALID) {
hwcl->flags = HWC_SKIP_LAYER;
- return;
+ } else {
+ hwcl->transform = finalTransform;
}
-
- hwcl->transform = finalTransform;
-
- if (!isOpaque()) {
- hwcl->blending = mPremultipliedAlpha ?
- HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
- }
-
- // scaling is already applied in mTransformedBounds
- hwcl->displayFrame.left = mTransformedBounds.left;
- hwcl->displayFrame.top = mTransformedBounds.top;
- hwcl->displayFrame.right = mTransformedBounds.right;
- hwcl->displayFrame.bottom = mTransformedBounds.bottom;
-
- hwcl->visibleRegionScreen.rects =
- reinterpret_cast<hwc_rect_t const *>(
- visibleRegionScreen.getArray(
- &hwcl->visibleRegionScreen.numRects));
}
void Layer::setPerFrameData(hwc_layer_t* hwcl) {
@@ -238,9 +218,9 @@
// HWC handle it.
hwcl->flags |= HWC_SKIP_LAYER;
hwcl->handle = NULL;
- return;
+ } else {
+ hwcl->handle = buffer->handle;
}
- hwcl->handle = buffer->handle;
if (isCropped()) {
hwcl->sourceCrop.left = mCurrentCrop.left;
@@ -250,8 +230,13 @@
} else {
hwcl->sourceCrop.left = 0;
hwcl->sourceCrop.top = 0;
- hwcl->sourceCrop.right = buffer->width;
- hwcl->sourceCrop.bottom = buffer->height;
+ if (buffer != NULL) {
+ hwcl->sourceCrop.right = buffer->width;
+ hwcl->sourceCrop.bottom = buffer->height;
+ } else {
+ hwcl->sourceCrop.right = mTransformedBounds.width();
+ hwcl->sourceCrop.bottom = mTransformedBounds.height();
+ }
}
}
@@ -330,8 +315,9 @@
{
// if we don't have a buffer yet, we're translucent regardless of the
// layer's opaque flag.
- if (mActiveBuffer == 0)
+ if (mActiveBuffer == 0) {
return false;
+ }
// if the layer has the opaque flag, then we're always opaque,
// otherwise we use the current buffer's format.
@@ -356,12 +342,13 @@
if (sizeChanged) {
// the size changed, we need to ask our client to request a new buffer
LOGD_IF(DEBUG_RESIZE,
+ "doTransaction: "
"resize (layer=%p), requested (%dx%d), drawing (%d,%d), "
- "fixedSize=%d",
+ "scalingMode=%d",
this,
int(temp.requested_w), int(temp.requested_h),
int(front.requested_w), int(front.requested_h),
- isFixedSize());
+ mCurrentScalingMode);
if (!isFixedSize()) {
// we're being resized and there is a freeze display request,
@@ -400,14 +387,7 @@
}
bool Layer::isFixedSize() const {
- Mutex::Autolock _l(mLock);
- return mFixedSize;
-}
-
-void Layer::setFixedSize(bool fixedSize)
-{
- Mutex::Autolock _l(mLock);
- mFixedSize = fixedSize;
+ return mCurrentScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
}
bool Layer::isCropped() const {
@@ -421,6 +401,8 @@
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
{
if (mQueuedFrames > 0) {
+ const bool oldOpacity = isOpaque();
+
// signal another event if we have more frames pending
if (android_atomic_dec(&mQueuedFrames) > 1) {
mFlinger->signalEvent();
@@ -437,15 +419,19 @@
const Rect crop(mSurfaceTexture->getCurrentCrop());
const uint32_t transform(mSurfaceTexture->getCurrentTransform());
- if ((crop != mCurrentCrop) || (transform != mCurrentTransform)) {
+ const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode());
+ if ((crop != mCurrentCrop) ||
+ (transform != mCurrentTransform) ||
+ (scalingMode != mCurrentScalingMode))
+ {
mCurrentCrop = crop;
mCurrentTransform = transform;
+ mCurrentScalingMode = scalingMode;
mFlinger->invalidateHwcGeometry();
}
- const bool opacity(getOpacityForFormat(mActiveBuffer->format));
- if (opacity != mCurrentOpacity) {
- mCurrentOpacity = opacity;
+ mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
+ if (oldOpacity != isOpaque()) {
recomputeVisibleRegions = true;
}
@@ -459,13 +445,22 @@
// FIXME: mPostedDirtyRegion = dirty & bounds
mPostedDirtyRegion.set(front.w, front.h);
- sp<GraphicBuffer> newFrontBuffer(mActiveBuffer);
- if ((newFrontBuffer->getWidth() == front.requested_w &&
- newFrontBuffer->getHeight() == front.requested_h) ||
- isFixedSize())
+
+ if ((front.w != front.requested_w) ||
+ (front.h != front.requested_h))
{
- if ((front.w != front.requested_w) ||
- (front.h != front.requested_h))
+ // check that we received a buffer of the right size
+ // (Take the buffer's orientation into account)
+ sp<GraphicBuffer> newFrontBuffer(mActiveBuffer);
+ uint32_t bufWidth = newFrontBuffer->getWidth();
+ uint32_t bufHeight = newFrontBuffer->getHeight();
+ if (mCurrentTransform & Transform::ROT_90) {
+ swap(bufWidth, bufHeight);
+ }
+
+ if (isFixedSize() ||
+ (bufWidth == front.requested_w &&
+ bufHeight == front.requested_h))
{
// Here we pretend the transaction happened by updating the
// current and drawing states. Drawing state is only accessed
@@ -485,10 +480,18 @@
// recompute visible region
recomputeVisibleRegions = true;
+
+ // we now have the correct size, unfreeze the screen
+ mFreezeLock.clear();
}
- // we now have the correct size, unfreeze the screen
- mFreezeLock.clear();
+ LOGD_IF(DEBUG_RESIZE,
+ "lockPageFlip : "
+ " (layer=%p), buffer (%ux%u, tr=%02x), "
+ "requested (%dx%d)",
+ this,
+ bufWidth, bufHeight, mCurrentTransform,
+ front.requested_w, front.requested_h);
}
}
}
@@ -533,7 +536,7 @@
}
snprintf(buffer, SIZE,
" "
- "format=%2d, activeBuffer=[%3ux%3u:%3u,%3u],"
+ "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
" freezeLock=%p, queued-frames=%d\n",
mFormat, w0, h0, s0,f0,
getFreezeLock().get(), mQueuedFrames);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index e3fc13d..d3ddab4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -45,7 +45,7 @@
// ---------------------------------------------------------------------------
-class Layer : public LayerBaseClient, private RefBase::Destroyer
+class Layer : public LayerBaseClient
{
public:
Layer(SurfaceFlinger* flinger, DisplayID display,
@@ -59,7 +59,6 @@
status_t setBuffers(uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags=0);
- // Set this Layer's buffers size
bool isFixedSize() const;
// LayerBase interface
@@ -79,7 +78,6 @@
inline const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; }
protected:
- virtual void destroy(RefBase const* base);
virtual void onFirstRef();
virtual void dump(String8& result, char* scratch, size_t size) const;
@@ -88,7 +86,6 @@
void onFrameQueued();
virtual sp<ISurface> createSurface();
uint32_t getEffectiveUsage(uint32_t usage) const;
- void setFixedSize(bool fixedSize);
bool isCropped() const;
static bool getOpacityForFormat(uint32_t format);
@@ -106,6 +103,7 @@
GLfloat mTextureMatrix[16];
Rect mCurrentCrop;
uint32_t mCurrentTransform;
+ uint32_t mCurrentScalingMode;
bool mCurrentOpacity;
// constants
@@ -124,7 +122,6 @@
// binder thread, transaction thread
mutable Mutex mLock;
- bool mFixedSize;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index c86c659..e04c533 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -302,13 +302,47 @@
}
}
-void LayerBase::setGeometry(hwc_layer_t* hwcl) {
- hwcl->flags |= HWC_SKIP_LAYER;
+void LayerBase::setGeometry(hwc_layer_t* hwcl)
+{
+ hwcl->compositionType = HWC_FRAMEBUFFER;
+ hwcl->hints = 0;
+ hwcl->flags = HWC_SKIP_LAYER;
+ hwcl->transform = 0;
+ hwcl->blending = HWC_BLENDING_NONE;
+
+ // this gives us only the "orientation" component of the transform
+ const State& s(drawingState());
+ const uint32_t finalTransform = s.transform.getOrientation();
+ // we can only handle simple transformation
+ if (finalTransform & Transform::ROT_INVALID) {
+ hwcl->flags = HWC_SKIP_LAYER;
+ } else {
+ hwcl->transform = finalTransform;
+ }
+
+ if (!isOpaque()) {
+ hwcl->blending = mPremultipliedAlpha ?
+ HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
+ }
+
+ // scaling is already applied in mTransformedBounds
+ hwcl->displayFrame.left = mTransformedBounds.left;
+ hwcl->displayFrame.top = mTransformedBounds.top;
+ hwcl->displayFrame.right = mTransformedBounds.right;
+ hwcl->displayFrame.bottom = mTransformedBounds.bottom;
+ hwcl->visibleRegionScreen.rects =
+ reinterpret_cast<hwc_rect_t const *>(
+ visibleRegionScreen.getArray(
+ &hwcl->visibleRegionScreen.numRects));
}
void LayerBase::setPerFrameData(hwc_layer_t* hwcl) {
hwcl->compositionType = HWC_FRAMEBUFFER;
hwcl->handle = NULL;
+ hwcl->sourceCrop.left = 0;
+ hwcl->sourceCrop.top = 0;
+ hwcl->sourceCrop.right = mTransformedBounds.width();
+ hwcl->sourceCrop.bottom = mTransformedBounds.height();
}
void LayerBase::setFiltering(bool filtering)
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 680814c..082effe 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -402,9 +402,6 @@
{
waitForEvent();
- // call Layer's destructor
- handleDestroyLayers();
-
// check for transactions
if (UNLIKELY(mConsoleSignals)) {
handleConsoleEvents();
@@ -597,31 +594,6 @@
commitTransaction();
}
-void SurfaceFlinger::destroyLayer(LayerBase const* layer)
-{
- Mutex::Autolock _l(mDestroyedLayerLock);
- mDestroyedLayers.add(layer);
- signalEvent();
-}
-
-void SurfaceFlinger::handleDestroyLayers()
-{
- Vector<LayerBase const *> destroyedLayers;
-
- { // scope for the lock
- Mutex::Autolock _l(mDestroyedLayerLock);
- destroyedLayers = mDestroyedLayers;
- mDestroyedLayers.clear();
- }
-
- // call destructors without a lock held
- const size_t count = destroyedLayers.size();
- for (size_t i=0 ; i<count ; i++) {
- //LOGD("destroying %s", destroyedLayers[i]->getName().string());
- delete destroyedLayers[i];
- }
-}
-
sp<FreezeLock> SurfaceFlinger::getFreezeLock() const
{
return new FreezeLock(const_cast<SurfaceFlinger *>(this));
@@ -1318,9 +1290,6 @@
if (surfaceHandle != 0) {
params->token = token;
params->identity = layer->getIdentity();
- params->width = w;
- params->height = h;
- params->format = format;
if (normalLayer != 0) {
Mutex::Autolock _l(mStateLock);
mLayerMap.add(layer->getSurfaceBinder(), normalLayer);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 15661f0..6f93f5b 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -189,7 +189,6 @@
status_t addLayer(const sp<LayerBase>& layer);
status_t invalidateLayerVisibility(const sp<LayerBase>& layer);
void invalidateHwcGeometry();
- void destroyLayer(LayerBase const* layer);
sp<Layer> getLayer(const sp<ISurface>& sur) const;
@@ -266,7 +265,6 @@
void handleConsoleEvents();
void handleTransaction(uint32_t transactionFlags);
void handleTransactionLocked(uint32_t transactionFlags);
- void handleDestroyLayers();
void computeVisibleRegions(
const LayerVector& currentLayers,
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 60fa965..79cd0c3 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -52,6 +52,24 @@
return res;
}
+status_t SurfaceTextureLayer::queueBuffer(int buf, int64_t timestamp,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+
+ status_t res = SurfaceTexture::queueBuffer(buf, timestamp,
+ outWidth, outHeight, outTransform);
+
+ sp<Layer> layer(mLayer.promote());
+ if (layer != NULL) {
+ uint32_t orientation = layer->getOrientation();
+ if (orientation & Transform::ROT_INVALID) {
+ orientation = 0;
+ }
+ *outTransform = orientation;
+ }
+
+ return res;
+}
+
status_t SurfaceTextureLayer::dequeueBuffer(int *buf,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
@@ -64,13 +82,46 @@
//LOGD("%s, w=%u, h=%u, format=%u, usage=%08x, effectiveUsage=%08x",
// __PRETTY_FUNCTION__, w, h, format, usage, effectiveUsage);
res = SurfaceTexture::dequeueBuffer(buf, w, h, format, effectiveUsage);
- if (res == NO_ERROR) {
- layer->setFixedSize(w && h);
- }
}
return res;
}
+status_t SurfaceTextureLayer::connect(int api,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+ status_t err = SurfaceTexture::connect(api,
+ outWidth, outHeight, outTransform);
+ if (err == NO_ERROR) {
+ sp<Layer> layer(mLayer.promote());
+ if (layer != NULL) {
+ uint32_t orientation = layer->getOrientation();
+ if (orientation & Transform::ROT_INVALID) {
+ orientation = 0;
+ }
+ *outTransform = orientation;
+ }
+ 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.
+ deafult:
+ err = setSynchronousMode(true);
+ break;
+ }
+ if (err != NO_ERROR) {
+ disconnect(api);
+ }
+ }
+ return err;
+}
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceTextureLayer.h b/services/surfaceflinger/SurfaceTextureLayer.h
index 7faff54..9508524 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.h
+++ b/services/surfaceflinger/SurfaceTextureLayer.h
@@ -45,8 +45,14 @@
virtual status_t setBufferCount(int bufferCount);
protected:
+ virtual status_t queueBuffer(int buf, int64_t timestamp,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
+
virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
uint32_t format, uint32_t usage);
+
+ virtual status_t connect(int api,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index 4cedcbf..05b7527 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -20,6 +20,7 @@
#include <utils/String8.h>
#include <ui/Region.h>
+#include "clz.h"
#include "Transform.h"
// ---------------------------------------------------------------------------
@@ -28,42 +29,6 @@
// ---------------------------------------------------------------------------
-template <typename T>
-static inline T min(T a, T b) {
- return a<b ? a : b;
-}
-template <typename T>
-static inline T min(T a, T b, T c) {
- return min(a, min(b, c));
-}
-template <typename T>
-static inline T min(T a, T b, T c, T d) {
- return min(a, b, min(c, d));
-}
-
-template <typename T>
-static inline T max(T a, T b) {
- return a>b ? a : b;
-}
-template <typename T>
-static inline T max(T a, T b, T c) {
- return max(a, max(b, c));
-}
-template <typename T>
-static inline T max(T a, T b, T c, T d) {
- return max(a, b, max(c, d));
-}
-
-template <typename T>
-static inline
-void swap(T& a, T& b) {
- T t(a);
- a = b;
- b = t;
-}
-
-// ---------------------------------------------------------------------------
-
Transform::Transform() {
reset();
}
@@ -343,7 +308,7 @@
bool Transform::preserveRects() const
{
- return (type() & ROT_INVALID) ? false : true;
+ return (getOrientation() & ROT_INVALID) ? false : true;
}
void Transform::dump(const char* name) const
diff --git a/services/surfaceflinger/clz.h b/services/surfaceflinger/clz.h
index ca44555..a4c5262 100644
--- a/services/surfaceflinger/clz.h
+++ b/services/surfaceflinger/clz.h
@@ -24,6 +24,41 @@
return __builtin_clz(x);
}
+template <typename T>
+static inline T min(T a, T b) {
+ return a<b ? a : b;
+}
+template <typename T>
+static inline T min(T a, T b, T c) {
+ return min(a, min(b, c));
+}
+template <typename T>
+static inline T min(T a, T b, T c, T d) {
+ return min(a, b, min(c, d));
+}
+
+template <typename T>
+static inline T max(T a, T b) {
+ return a>b ? a : b;
+}
+template <typename T>
+static inline T max(T a, T b, T c) {
+ return max(a, max(b, c));
+}
+template <typename T>
+static inline T max(T a, T b, T c, T d) {
+ return max(a, b, max(c, d));
+}
+
+template <typename T>
+static inline
+void swap(T& a, T& b) {
+ T t(a);
+ a = b;
+ b = t;
+}
+
+
}; // namespace android
#endif /* ANDROID_SURFACE_FLINGER_CLZ_H */