Merge "Fix NPE, caller may not pass loginOptions." into honeycomb
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index cbc15d8..002e48b 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -26,12 +26,15 @@
#include <ui/GraphicBuffer.h>
#include <utils/threads.h>
+#include <utils/Vector.h>
#define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture"
namespace android {
// ----------------------------------------------------------------------------
+class IGraphicBufferAlloc;
+
class SurfaceTexture : public BnSurfaceTexture {
public:
enum { MIN_BUFFER_SLOTS = 3 };
@@ -70,6 +73,26 @@
// target texture belongs is bound to the calling thread.
status_t updateTexImage();
+ // getTransformMatrix retrieves the 4x4 texture coordinate transform matrix
+ // associated with the texture image set by the most recent call to
+ // updateTexImage.
+ //
+ // This transform matrix maps 2D homogeneous texture coordinates of the form
+ // (s, t, 0, 1) with s and t in the inclusive range [0, 1] to the texture
+ // coordinate that should be used to sample that location from the texture.
+ // Sampling the texture outside of the range of this transform is undefined.
+ //
+ // This transform is necessary to compensate for transforms that the stream
+ // content producer may implicitly apply to the content. By forcing users of
+ // a SurfaceTexture to apply this transform we avoid performing an extra
+ // copy of the data that would be needed to hide the transform from the
+ // user.
+ //
+ // The matrix is stored in column-major order so that it may be passed
+ // directly to OpenGL ES via the glLoadMatrixf or glUniformMatrix4fv
+ // functions.
+ void getTransformMatrix(float mtx[16]);
+
private:
// freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
@@ -120,16 +143,58 @@
// reset mCurrentTexture to INVALID_BUFFER_SLOT.
int mCurrentTexture;
+ // 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.
+ sp<GraphicBuffer> mCurrentTextureBuf;
+
+ // mCurrentCrop is the crop rectangle that applies to the current texture.
+ // It gets set to mLastQueuedCrop 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.
+ uint32_t mCurrentTransform;
+
// mLastQueued is the buffer slot index of the most recently enqueued buffer.
// At construction time it is initialized to INVALID_BUFFER_SLOT, and is
// updated each time queueBuffer is called.
int mLastQueued;
+ // mLastQueuedCrop is the crop rectangle for the buffer that was most
+ // recently queued. This gets set to mNextCrop each time queueBuffer gets
+ // called.
+ Rect mLastQueuedCrop;
+
+ // mLastQueuedTransform is the transform identifier for the buffer that was
+ // most recently queued. This gets set to mNextTransform each time
+ // queueBuffer gets called.
+ uint32_t mLastQueuedTransform;
+
+ // mNextCrop is the crop rectangle that will be used for the next buffer
+ // that gets queued. It is set by calling setCrop.
+ Rect mNextCrop;
+
+ // mNextTransform is the transform identifier that will be used for the next
+ // buffer that gets queued. It is set by calling setTransform.
+ uint32_t mNextTransform;
+
// 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.
const GLuint mTexName;
+ // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
+ // allocate new GraphicBuffer objects.
+ sp<IGraphicBufferAlloc> mGraphicBufferAlloc;
+
+ // mAllocdBuffers is mirror of the list of buffers that SurfaceFlinger is
+ // referencing. This is kept so that gralloc implementations do not need to
+ // properly handle the case where SurfaceFlinger no longer holds a reference
+ // to a buffer, but other processes do.
+ Vector<sp<GraphicBuffer> > mAllocdBuffers;
+
// 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/surfaceflinger/IGraphicBufferAlloc.h b/include/surfaceflinger/IGraphicBufferAlloc.h
new file mode 100644
index 0000000..d996af7
--- /dev/null
+++ b/include/surfaceflinger/IGraphicBufferAlloc.h
@@ -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.
+ */
+
+#ifndef ANDROID_SF_IGRAPHIC_BUFFER_ALLOC_H
+#define ANDROID_SF_IGRAPHIC_BUFFER_ALLOC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+
+#include <binder/IInterface.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class IGraphicBufferAlloc : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(GraphicBufferAlloc);
+
+ /* Create a new GraphicBuffer for the client to use. The server will
+ * maintain a reference to the newly created GraphicBuffer until
+ * freeAllGraphicBuffers is called.
+ */
+ virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t usage) = 0;
+
+ /* Free all but one of the GraphicBuffer objects that the server is
+ * currently referencing. If bufIndex is not a valid index of the buffers
+ * the server is referencing, then all buffers are freed.
+ */
+ virtual void freeAllGraphicBuffersExcept(int bufIndex) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnGraphicBufferAlloc : public BnInterface<IGraphicBufferAlloc>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_SF_IGRAPHIC_BUFFER_ALLOC_H
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 1bab7d7..56ed3a4 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -28,6 +28,7 @@
#include <ui/PixelFormat.h>
#include <surfaceflinger/ISurfaceComposerClient.h>
+#include <surfaceflinger/IGraphicBufferAlloc.h>
namespace android {
// ----------------------------------------------------------------------------
@@ -96,6 +97,10 @@
*/
virtual sp<ISurfaceComposerClient> createClientConnection() = 0;
+ /* create a graphic buffer allocator
+ */
+ virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc() = 0;
+
/* retrieve the control block */
virtual sp<IMemoryHeap> getCblk() const = 0;
@@ -131,13 +136,6 @@
* This is an ASYNCHRONOUS call.
*/
virtual void signal() const = 0;
-
- /* Create a new GraphicBuffer for the client to use. SurfaceFlinger will
- * not maintain a reference to the GraphicBuffer, so the underlying native
- * handle will be freed once the client references are released.
- */
- virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t usage) const = 0;
};
// ----------------------------------------------------------------------------
@@ -151,7 +149,7 @@
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
CREATE_CONNECTION,
CREATE_CLIENT_CONNECTION,
- CREATE_GRAPHIC_BUFFER,
+ CREATE_GRAPHIC_BUFFER_ALLOC,
GET_CBLK,
OPEN_GLOBAL_TRANSACTION,
CLOSE_GLOBAL_TRANSACTION,
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 11a48d9..447de76 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -29,11 +29,52 @@
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/SurfaceComposerClient.h>
+#include <surfaceflinger/IGraphicBufferAlloc.h>
#include <utils/Log.h>
namespace android {
+// Transform matrices
+static float mtxIdentity[16] = {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1,
+};
+static float mtxFlipH[16] = {
+ -1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 1, 0, 0, 1,
+};
+static float mtxFlipV[16] = {
+ 1, 0, 0, 0,
+ 0, -1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 1, 0, 1,
+};
+static float mtxRot90[16] = {
+ 0, 1, 0, 0,
+ -1, 0, 0, 0,
+ 0, 0, 1, 0,
+ 1, 0, 0, 1,
+};
+static float mtxRot180[16] = {
+ -1, 0, 0, 0,
+ 0, -1, 0, 0,
+ 0, 0, 1, 0,
+ 1, 1, 0, 1,
+};
+static float mtxRot270[16] = {
+ 0, -1, 0, 0,
+ 1, 0, 0, 0,
+ 0, 0, 1, 0,
+ 0, 1, 0, 1,
+};
+
+static void mtxMul(float out[16], const float a[16], const float b[16]);
+
SurfaceTexture::SurfaceTexture(GLuint tex) :
mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT),
mLastQueued(INVALID_BUFFER_SLOT), mTexName(tex) {
@@ -43,6 +84,8 @@
mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
mSlots[i].mOwnedByClient = false;
}
+ sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+ mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
}
SurfaceTexture::~SurfaceTexture() {
@@ -70,9 +113,8 @@
return 0;
}
usage |= GraphicBuffer::USAGE_HW_TEXTURE;
- sp<ISurfaceComposer> composer(ComposerService::getComposerService());
- sp<GraphicBuffer> graphicBuffer(composer->createGraphicBuffer(w, h,
- format, usage));
+ sp<GraphicBuffer> graphicBuffer(
+ mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage));
if (graphicBuffer == 0) {
LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed");
} else {
@@ -82,6 +124,7 @@
mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
}
+ mAllocdBuffers.add(graphicBuffer);
}
return graphicBuffer;
}
@@ -91,7 +134,7 @@
Mutex::Autolock lock(mMutex);
int found = INVALID_BUFFER_SLOT;
for (int i = 0; i < mBufferCount; i++) {
- if (!mSlots[i].mOwnedByClient && i != mCurrentTexture) {
+ if (!mSlots[i].mOwnedByClient && i != mCurrentTexture && i != mLastQueued) {
mSlots[i].mOwnedByClient = true;
found = i;
break;
@@ -121,6 +164,8 @@
}
mSlots[buf].mOwnedByClient = false;
mLastQueued = buf;
+ mLastQueuedCrop = mNextCrop;
+ mLastQueuedTransform = mNextTransform;
return OK;
}
@@ -138,17 +183,17 @@
mSlots[buf].mOwnedByClient = false;
}
-status_t SurfaceTexture::setCrop(const Rect& reg) {
+status_t SurfaceTexture::setCrop(const Rect& crop) {
LOGV("SurfaceTexture::setCrop");
Mutex::Autolock lock(mMutex);
- // XXX: How should we handle crops?
+ mNextCrop = crop;
return OK;
}
status_t SurfaceTexture::setTransform(uint32_t transform) {
LOGV("SurfaceTexture::setTransform");
Mutex::Autolock lock(mMutex);
- // XXX: How should we handle transforms?
+ mNextTransform = transform;
return OK;
}
@@ -162,27 +207,75 @@
// Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,
// so this check will fail until a buffer gets queued.
if (mCurrentTexture != mLastQueued) {
- // XXX: Figure out the right target.
- mCurrentTexture = mLastQueued;
- EGLImageKHR image = mSlots[mCurrentTexture].mEglImage;
+ // Update the GL texture object.
+ EGLImageKHR image = mSlots[mLastQueued].mEglImage;
if (image == EGL_NO_IMAGE_KHR) {
EGLDisplay dpy = eglGetCurrentDisplay();
- sp<GraphicBuffer> graphicBuffer = mSlots[mCurrentTexture].mGraphicBuffer;
+ sp<GraphicBuffer> graphicBuffer = mSlots[mLastQueued].mGraphicBuffer;
image = createImage(dpy, graphicBuffer);
- mSlots[mCurrentTexture].mEglImage = image;
- mSlots[mCurrentTexture].mEglDisplay = dpy;
+ mSlots[mLastQueued].mEglImage = image;
+ mSlots[mLastQueued].mEglDisplay = dpy;
}
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
GLint error = glGetError();
if (error != GL_NO_ERROR) {
LOGE("error binding external texture image %p (slot %d): %#04x",
- image, mCurrentTexture, error);
+ image, mLastQueued, error);
return -EINVAL;
}
+
+ // Update the SurfaceTexture state.
+ mCurrentTexture = mLastQueued;
+ mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer;
+ mCurrentCrop = mLastQueuedCrop;
+ mCurrentTransform = mLastQueuedTransform;
}
return OK;
}
+void SurfaceTexture::getTransformMatrix(float mtx[16]) {
+ LOGV("SurfaceTexture::updateTexImage");
+ Mutex::Autolock lock(mMutex);
+
+ float* xform = mtxIdentity;
+ switch (mCurrentTransform) {
+ case 0:
+ xform = mtxIdentity;
+ break;
+ case NATIVE_WINDOW_TRANSFORM_FLIP_H:
+ xform = mtxFlipH;
+ break;
+ case NATIVE_WINDOW_TRANSFORM_FLIP_V:
+ xform = mtxFlipV;
+ break;
+ case NATIVE_WINDOW_TRANSFORM_ROT_90:
+ xform = mtxRot90;
+ break;
+ case NATIVE_WINDOW_TRANSFORM_ROT_180:
+ xform = mtxRot180;
+ break;
+ case NATIVE_WINDOW_TRANSFORM_ROT_270:
+ xform = mtxRot270;
+ break;
+ default:
+ LOGE("getTransformMatrix: unknown transform: %d", mCurrentTransform);
+ }
+
+ sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer);
+ float tx = float(mCurrentCrop.left) / float(buf->getWidth());
+ float ty = float(mCurrentCrop.bottom) / float(buf->getHeight());
+ float sx = float(mCurrentCrop.width()) / float(buf->getWidth());
+ float sy = float(mCurrentCrop.height()) / float(buf->getHeight());
+ float crop[16] = {
+ sx, 0, 0, sx*tx,
+ 0, sy, 0, sy*ty,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1,
+ };
+
+ mtxMul(mtx, crop, xform);
+}
+
void SurfaceTexture::freeAllBuffers() {
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
mSlots[i].mGraphicBuffer = 0;
@@ -193,6 +286,19 @@
mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
}
}
+
+ int exceptBuf = -1;
+ for (size_t i = 0; i < mAllocdBuffers.size(); i++) {
+ if (mAllocdBuffers[i] == mCurrentTextureBuf) {
+ exceptBuf = i;
+ break;
+ }
+ }
+ mAllocdBuffers.clear();
+ if (exceptBuf >= 0) {
+ mAllocdBuffers.add(mCurrentTextureBuf);
+ }
+ mGraphicBufferAlloc->freeAllGraphicBuffersExcept(exceptBuf);
}
EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
@@ -214,4 +320,26 @@
return image;
}
+static void mtxMul(float out[16], const float a[16], const float b[16]) {
+ out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
+ out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
+ out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3];
+ out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3];
+
+ out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7];
+ out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7];
+ out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7];
+ out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7];
+
+ out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11];
+ out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11];
+ out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11];
+ out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11];
+
+ out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15];
+ out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15];
+ out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15];
+ out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
+}
+
}; // namespace android
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 8a59144..24cee24 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "SurfaceTextureClient"
+//#define LOG_NDEBUG 0
#include <gui/SurfaceTextureClient.h>
@@ -82,10 +83,12 @@
}
int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
+ LOGV("SurfaceTextureClient::dequeueBuffer");
Mutex::Autolock lock(mMutex);
int buf = -1;
status_t err = mSurfaceTexture->dequeueBuffer(&buf);
if (err < 0) {
+ LOGE("dequeueBuffer: ISurfaceTexture::dequeueBuffer failed: %d", err);
return err;
}
sp<GraphicBuffer>& gbuf(mSlots[buf]);
@@ -96,6 +99,7 @@
gbuf = mSurfaceTexture->requestBuffer(buf, mReqWidth, mReqHeight,
mReqFormat, mReqUsage);
if (gbuf == 0) {
+ LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed");
return NO_MEMORY;
}
}
@@ -104,6 +108,7 @@
}
int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) {
+ LOGV("SurfaceTextureClient::cancelBuffer");
Mutex::Autolock lock(mMutex);
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
if (mSlots[i].get() == buffer) {
@@ -115,11 +120,13 @@
}
int SurfaceTextureClient::lockBuffer(android_native_buffer_t* buffer) {
+ LOGV("SurfaceTextureClient::lockBuffer");
Mutex::Autolock lock(mMutex);
return OK;
}
int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
+ LOGV("SurfaceTextureClient::queueBuffer");
Mutex::Autolock lock(mMutex);
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
if (mSlots[i].get() == GraphicBuffer::getSelf(buffer)) {
@@ -131,6 +138,7 @@
}
int SurfaceTextureClient::query(int what, int* value) {
+ LOGV("SurfaceTextureClient::query");
Mutex::Autolock lock(mMutex);
// XXX: Implement this!
return INVALID_OPERATION;
@@ -206,17 +214,20 @@
}
int SurfaceTextureClient::connect(int api) {
+ LOGV("SurfaceTextureClient::connect");
// XXX: Implement this!
return INVALID_OPERATION;
}
int SurfaceTextureClient::disconnect(int api) {
+ LOGV("SurfaceTextureClient::disconnect");
// XXX: Implement this!
return INVALID_OPERATION;
}
int SurfaceTextureClient::setUsage(uint32_t reqUsage)
{
+ LOGV("SurfaceTextureClient::setUsage");
Mutex::Autolock lock(mMutex);
mReqUsage = reqUsage;
return OK;
@@ -224,6 +235,7 @@
int SurfaceTextureClient::setCrop(Rect const* rect)
{
+ LOGV("SurfaceTextureClient::setCrop");
Mutex::Autolock lock(mMutex);
// empty/invalid rects are not allowed
@@ -239,6 +251,7 @@
int SurfaceTextureClient::setBufferCount(int bufferCount)
{
+ LOGV("SurfaceTextureClient::setBufferCount");
Mutex::Autolock lock(mMutex);
status_t err = mSurfaceTexture->setBufferCount(bufferCount);
@@ -254,6 +267,7 @@
int SurfaceTextureClient::setBuffersGeometry(int w, int h, int format)
{
+ LOGV("SurfaceTextureClient::setBuffersGeometry");
Mutex::Autolock lock(mMutex);
if (w<0 || h<0 || format<0)
@@ -271,6 +285,7 @@
int SurfaceTextureClient::setBuffersTransform(int transform)
{
+ LOGV("SurfaceTextureClient::setBuffersTransform");
Mutex::Autolock lock(mMutex);
status_t err = mSurfaceTexture->setTransform(transform);
return err;
diff --git a/libs/surfaceflinger_client/Android.mk b/libs/surfaceflinger_client/Android.mk
index ce3c71a..4a0faf0 100644
--- a/libs/surfaceflinger_client/Android.mk
+++ b/libs/surfaceflinger_client/Android.mk
@@ -5,6 +5,7 @@
ISurfaceComposer.cpp \
ISurface.cpp \
ISurfaceComposerClient.cpp \
+ IGraphicBufferAlloc.cpp \
LayerState.cpp \
SharedBufferStack.cpp \
Surface.cpp \
diff --git a/libs/surfaceflinger_client/IGraphicBufferAlloc.cpp b/libs/surfaceflinger_client/IGraphicBufferAlloc.cpp
new file mode 100644
index 0000000..e05da72
--- /dev/null
+++ b/libs/surfaceflinger_client/IGraphicBufferAlloc.cpp
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+// tag as surfaceflinger
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <surfaceflinger/IGraphicBufferAlloc.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+enum {
+ CREATE_GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+ FREE_ALL_GRAPHIC_BUFFERS_EXCEPT,
+};
+
+class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc>
+{
+public:
+ BpGraphicBufferAlloc(const sp<IBinder>& impl)
+ : BpInterface<IGraphicBufferAlloc>(impl)
+ {
+ }
+
+ virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t usage) {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IGraphicBufferAlloc::getInterfaceDescriptor());
+ data.writeInt32(w);
+ data.writeInt32(h);
+ data.writeInt32(format);
+ data.writeInt32(usage);
+ remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply);
+ sp<GraphicBuffer> graphicBuffer;
+ bool nonNull = (bool)reply.readInt32();
+ if (nonNull) {
+ graphicBuffer = new GraphicBuffer();
+ reply.read(*graphicBuffer);
+ }
+ return graphicBuffer;
+ }
+
+ virtual void freeAllGraphicBuffersExcept(int bufIdx) {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IGraphicBufferAlloc::getInterfaceDescriptor());
+ data.writeInt32(bufIdx);
+ remote()->transact(FREE_ALL_GRAPHIC_BUFFERS_EXCEPT, data, &reply);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(GraphicBufferAlloc, "android.ui.IGraphicBufferAlloc");
+
+// ----------------------------------------------------------------------
+
+status_t BnGraphicBufferAlloc::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ // codes that don't require permission check
+
+ switch(code) {
+ case CREATE_GRAPHIC_BUFFER: {
+ CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);
+ uint32_t w = data.readInt32();
+ uint32_t h = data.readInt32();
+ PixelFormat format = data.readInt32();
+ uint32_t usage = data.readInt32();
+ sp<GraphicBuffer> result(createGraphicBuffer(w, h, format, usage));
+ reply->writeInt32(result != 0);
+ if (result != 0) {
+ reply->write(*result);
+ }
+ return NO_ERROR;
+ } break;
+ case FREE_ALL_GRAPHIC_BUFFERS_EXCEPT: {
+ CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);
+ int bufIdx = data.readInt32();
+ freeAllGraphicBuffersExcept(bufIdx);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index a42b49d..2216824 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -26,7 +26,6 @@
#include <binder/IServiceManager.h>
#include <ui/DisplayInfo.h>
-#include <ui/GraphicBuffer.h>
#include <surfaceflinger/ISurfaceComposer.h>
@@ -65,6 +64,15 @@
return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
}
+ virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc()
+ {
+ uint32_t n;
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, data, &reply);
+ return interface_cast<IGraphicBufferAlloc>(reply.readStrongBinder());
+ }
+
virtual sp<IMemoryHeap> getCblk() const
{
Parcel data, reply;
@@ -170,25 +178,6 @@
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY);
}
-
- virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t usage) const {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeInt32(w);
- data.writeInt32(h);
- data.writeInt32(format);
- data.writeInt32(usage);
- remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER, data,
- &reply);
- sp<GraphicBuffer> graphicBuffer;
- bool nonNull = (bool)reply.readInt32();
- if (nonNull) {
- graphicBuffer = new GraphicBuffer();
- reply.read(*graphicBuffer);
- }
- return graphicBuffer;
- }
};
IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -209,6 +198,11 @@
sp<IBinder> b = createClientConnection()->asBinder();
reply->writeStrongBinder(b);
} break;
+ case CREATE_GRAPHIC_BUFFER_ALLOC: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> b = createGraphicBufferAlloc()->asBinder();
+ reply->writeStrongBinder(b);
+ } break;
case OPEN_GLOBAL_TRANSACTION: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
openGlobalTransaction();
@@ -267,18 +261,6 @@
reply->writeInt32(f);
reply->writeInt32(res);
} break;
- case CREATE_GRAPHIC_BUFFER: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- uint32_t w = data.readInt32();
- uint32_t h = data.readInt32();
- PixelFormat format = data.readInt32();
- uint32_t usage = data.readInt32();
- sp<GraphicBuffer> result(createGraphicBuffer(w, h, format, usage));
- reply->writeInt32(result != 0);
- if (result != 0) {
- reply->write(*result);
- }
- } break;
case TURN_ELECTRON_BEAM_OFF: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
int32_t mode = data.readInt32();
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index f6c55e4..ad9a94f 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -774,6 +774,9 @@
self->mExitPending = true;
self->mLock.lock();
self->mRunning = false;
+ // clear thread ID so that requestExitAndWait() does not exit if
+ // called by a new thread using the same thread ID as this one.
+ self->mThread = thread_id_t(-1);
self->mThreadExitedCondition.broadcast();
self->mLock.unlock();
break;
diff --git a/opengl/tests/hwc/hwcCommit.cpp b/opengl/tests/hwc/hwcCommit.cpp
index ed74cbe..66ccdae 100644
--- a/opengl/tests/hwc/hwcCommit.cpp
+++ b/opengl/tests/hwc/hwcCommit.cpp
@@ -76,6 +76,7 @@
#include <cmath>
#include <cstdlib>
#include <ctime>
+#include <iomanip>
#include <istream>
#include <libgen.h>
#include <list>
@@ -125,6 +126,7 @@
const struct hwc_rect defaultDisplayFrame = {0, 0, 100, 100};
// Global Constants
+const uint32_t printFieldWidth = 2;
const struct searchLimits {
uint32_t numOverlays;
HwcTestDim sourceCrop;
@@ -233,6 +235,8 @@
static EGLDisplay dpy;
static EGLSurface surface;
static EGLint width, height;
+static size_t maxHeadingLen;
+static vector<string> formats;
// Measurements
struct meas {
@@ -264,6 +268,9 @@
HwcTestDim vScaleBestDf;
HwcTestDim vScaleBestSc;
} sc;
+ vector<uint32_t> overlapBlendNone;
+ vector<uint32_t> overlapBlendPremult;
+ vector<uint32_t> overlapBlendCoverage;
};
vector<meas> measurements;
@@ -292,9 +299,14 @@
const HwcTestDim& dfMin, const HwcTestDim& dfMax,
const HwcTestDim& scMin, const HwcTestDim& scMax,
HwcTestDim& outBestDf, HwcTestDim& outBestSc);
+uint32_t numOverlapping(uint32_t backgroundFormat, uint32_t foregroundFormat,
+ uint32_t backgroundBlend, uint32_t foregroundBlend);
string transformList2str(const list<uint32_t>& transformList);
string blendList2str(const list<uint32_t>& blendList);
void init(void);
+void printFormatHeadings(size_t indent);
+void printOverlapLine(size_t indent, const string formatStr,
+ const vector<uint32_t>& results);
void printSyntax(const char *cmd);
// Command-line option settings
@@ -332,7 +344,6 @@
bool error;
string str;
char cmd[MAXCMD];
- list<string> formats;
list<Rectangle> rectList;
testSetLogCatTag(LOG_TAG);
@@ -395,6 +406,13 @@
}
}
+ // Determine length of longest specified graphic format.
+ // This value is used for output formating
+ for (vector<string>::iterator it = formats.begin();
+ it != formats.end(); ++it) {
+ maxHeadingLen = max(maxHeadingLen, it->length());
+ }
+
// Stop framework
rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK);
if (rv >= (signed) sizeof(cmd) - 1) {
@@ -411,7 +429,7 @@
init();
// For each of the graphic formats
- for (list<string>::iterator itFormat = formats.begin();
+ for (vector<string>::iterator itFormat = formats.begin();
itFormat != formats.end(); ++itFormat) {
// Locate hwcTestLib structure that describes this format
@@ -539,8 +557,66 @@
testPrintI(" VScale Best Source Crop: %s",
((string) measPtr->sc.vScaleBestSc).c_str());
+ // Overlap two graphic formats and different blends
+ // Results displayed after all overlap measurments with
+ // current format in the foreground
+ // TODO: make measurments with background blend other than
+ // none. All of these measurements are done with a
+ // background blend of HWC_BLENDING_NONE, with the
+ // blend type of the foregound being varied.
+ uint32_t foregroundFormat = format->format;
+ for (vector<string>::iterator it = formats.begin();
+ it != formats.end(); ++it) {
+ uint32_t num;
+
+ const struct hwcTestGraphicFormat *backgroundFormatPtr
+ = hwcTestGraphicFormatLookup((*it).c_str());
+ uint32_t backgroundFormat = backgroundFormatPtr->format;
+
+ num = numOverlapping(backgroundFormat, foregroundFormat,
+ HWC_BLENDING_NONE, HWC_BLENDING_NONE);
+ measPtr->overlapBlendNone.push_back(num);
+
+ num = numOverlapping(backgroundFormat, foregroundFormat,
+ HWC_BLENDING_NONE, HWC_BLENDING_PREMULT);
+ measPtr->overlapBlendPremult.push_back(num);
+
+ num = numOverlapping(backgroundFormat, foregroundFormat,
+ HWC_BLENDING_NONE, HWC_BLENDING_COVERAGE);
+ measPtr->overlapBlendCoverage.push_back(num);
+ }
+
}
+ // Display overlap results
+ size_t indent = 2;
+ testPrintI("overlapping blend: none");
+ printFormatHeadings(indent);
+ for (vector<string>::iterator it = formats.begin();
+ it != formats.end(); ++it) {
+ printOverlapLine(indent, *it, measurements[it
+ - formats.begin()].overlapBlendNone);
+ }
+ testPrintI("");
+
+ testPrintI("overlapping blend: premult");
+ printFormatHeadings(indent);
+ for (vector<string>::iterator it = formats.begin();
+ it != formats.end(); ++it) {
+ printOverlapLine(indent, *it, measurements[it
+ - formats.begin()].overlapBlendPremult);
+ }
+ testPrintI("");
+
+ testPrintI("overlapping blend: coverage");
+ printFormatHeadings(indent);
+ for (vector<string>::iterator it = formats.begin();
+ it != formats.end(); ++it) {
+ printOverlapLine(indent, *it, measurements[it
+ - formats.begin()].overlapBlendCoverage);
+ }
+ testPrintI("");
+
// Start framework
rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK);
if (rv >= (signed) sizeof(cmd) - 1) {
@@ -1204,6 +1280,33 @@
return best;
}
+uint32_t numOverlapping(uint32_t backgroundFormat, uint32_t foregroundFormat,
+ uint32_t backgroundBlend, uint32_t foregroundBlend)
+{
+ list<Rectangle> rectList;
+
+ Rectangle background(backgroundFormat, startDim, startDim);
+ background.blend = backgroundBlend;
+ rectList.push_back(background);
+
+ // TODO: Handle cases where startDim is so small that adding 5
+ // causes frames not to overlap.
+ // TODO: Handle cases where startDim is so large that adding 5
+ // cause a portion or all of the foreground displayFrame
+ // to be off the display.
+ Rectangle foreground(foregroundFormat, startDim, startDim);
+ foreground.displayFrame.left += 5;
+ foreground.displayFrame.top += 5;
+ foreground.displayFrame.right += 5;
+ foreground.displayFrame.bottom += 5;
+ background.blend = foregroundBlend;
+ rectList.push_back(foreground);
+
+ uint32_t num = numOverlays(rectList);
+
+ return num;
+}
+
Rectangle::Rectangle(uint32_t graphicFormat, HwcTestDim dfDim,
HwcTestDim sDim) :
format(graphicFormat), transform(defaultTransform),
@@ -1405,6 +1508,45 @@
hwcTestOpenHwc(&hwcDevice);
}
+void printFormatHeadings(size_t indent)
+{
+ for (size_t row = 0; row <= maxHeadingLen; row++) {
+ ostringstream line;
+ for(vector<string>::iterator it = formats.begin();
+ it != formats.end(); ++it) {
+ if ((maxHeadingLen - row) <= it->length()) {
+ if (row != maxHeadingLen) {
+ char ch = (*it)[it->length() - (maxHeadingLen - row)];
+ line << ' ' << setw(printFieldWidth) << ch;
+ } else {
+ line << ' ' << string(printFieldWidth, '-');
+ }
+ } else {
+ line << ' ' << setw(printFieldWidth) << "";
+ }
+ }
+ testPrintI("%*s%s", indent + maxHeadingLen, "",
+ line.str().c_str());
+ }
+}
+
+void printOverlapLine(size_t indent, const string formatStr,
+ const vector<uint32_t>& results)
+{
+ ostringstream line;
+
+ line << setw(indent + maxHeadingLen - formatStr.length()) << "";
+
+ line << formatStr;
+
+ for (vector<uint32_t>::const_iterator it = results.begin();
+ it != results.end(); ++it) {
+ line << ' ' << setw(printFieldWidth) << *it;
+ }
+
+ testPrintI("%s", line.str().c_str());
+}
+
void printSyntax(const char *cmd)
{
testPrintE(" %s [options] [graphicFormat] ...",
diff --git a/opengl/tests/hwc/hwcTestLib.cpp b/opengl/tests/hwc/hwcTestLib.cpp
index a468a92..925405e 100644
--- a/opengl/tests/hwc/hwcTestLib.cpp
+++ b/opengl/tests/hwc/hwcTestLib.cpp
@@ -475,14 +475,14 @@
testPrintI(" displayFrame: %s",
hwcTestRect2str(list->hwLayers[layer].displayFrame).c_str());
testPrintI(" scaleFactor: [%f, %f]",
- (float) (list->hwLayers[layer].displayFrame.right
- - list->hwLayers[layer].displayFrame.left)
- / (float) (list->hwLayers[layer].sourceCrop.right
- - list->hwLayers[layer].sourceCrop.left),
- (float) (list->hwLayers[layer].displayFrame.bottom
- - list->hwLayers[layer].displayFrame.top)
- / (float) (list->hwLayers[layer].sourceCrop.bottom
- - list->hwLayers[layer].sourceCrop.top));
+ (float) (list->hwLayers[layer].sourceCrop.right
+ - list->hwLayers[layer].sourceCrop.left)
+ / (float) (list->hwLayers[layer].displayFrame.right
+ - list->hwLayers[layer].displayFrame.left),
+ (float) (list->hwLayers[layer].sourceCrop.bottom
+ - list->hwLayers[layer].sourceCrop.top)
+ / (float) (list->hwLayers[layer].displayFrame.bottom
+ - list->hwLayers[layer].displayFrame.top));
}
}
@@ -494,7 +494,11 @@
*/
void hwcTestDisplayListPrepareModifiable(hwc_layer_list_t *list)
{
+ uint32_t numOverlays = 0;
for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
+ if (list->hwLayers[layer].compositionType == HWC_OVERLAY) {
+ numOverlays++;
+ }
testPrintI(" layer %u compositionType: %#x%s%s", layer,
list->hwLayers[layer].compositionType,
(list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER)
@@ -508,6 +512,7 @@
(list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB)
? " CLEAR_FB" : "");
}
+ testPrintI(" numOverlays: %u", numOverlays);
}
/*
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c982ea5..967ff1a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -144,6 +144,11 @@
return bclient;
}
+sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
+{
+ sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
+ return gba;
+}
const GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) const
{
@@ -2267,25 +2272,6 @@
// ---------------------------------------------------------------------------
-sp<GraphicBuffer> SurfaceFlinger::createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t usage) const {
- // XXX: HACK HACK HACK!!! This should NOT be static, but it is to fix a
- // race between SurfaceFlinger unref'ing the buffer and the client ref'ing
- // it.
- static sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
- status_t err = graphicBuffer->initCheck();
- if (err != 0) {
- LOGE("createGraphicBuffer: init check failed: %d", err);
- return 0;
- } else if (graphicBuffer->handle == 0) {
- LOGE("createGraphicBuffer: unable to create GraphicBuffer");
- return 0;
- }
- return graphicBuffer;
-}
-
-// ---------------------------------------------------------------------------
-
Client::Client(const sp<SurfaceFlinger>& flinger)
: mFlinger(flinger), mNameGenerator(1)
{
@@ -2465,6 +2451,39 @@
// ---------------------------------------------------------------------------
+GraphicBufferAlloc::GraphicBufferAlloc() {}
+
+GraphicBufferAlloc::~GraphicBufferAlloc() {}
+
+sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t usage) {
+ sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
+ status_t err = graphicBuffer->initCheck();
+ if (err != 0) {
+ LOGE("createGraphicBuffer: init check failed: %d", err);
+ return 0;
+ } else if (graphicBuffer->handle == 0) {
+ LOGE("createGraphicBuffer: unable to create GraphicBuffer");
+ return 0;
+ }
+ Mutex::Autolock _l(mLock);
+ mBuffers.add(graphicBuffer);
+ return graphicBuffer;
+}
+
+void GraphicBufferAlloc::freeAllGraphicBuffersExcept(int bufIdx) {
+ Mutex::Autolock _l(mLock);
+ if (0 <= bufIdx && bufIdx < mBuffers.size()) {
+ sp<GraphicBuffer> b(mBuffers[bufIdx]);
+ mBuffers.clear();
+ mBuffers.add(b);
+ } else {
+ mBuffers.clear();
+ }
+}
+
+// ---------------------------------------------------------------------------
+
GraphicPlane::GraphicPlane()
: mHw(0)
{
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 48642d4..2f2977a 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -34,6 +34,7 @@
#include <ui/PixelFormat.h>
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/ISurfaceComposerClient.h>
+#include <surfaceflinger/IGraphicBufferAlloc.h>
#include "Barrier.h"
#include "Layer.h"
@@ -119,6 +120,21 @@
sp<SurfaceFlinger> mFlinger;
};
+class GraphicBufferAlloc : public BnGraphicBufferAlloc
+{
+public:
+ GraphicBufferAlloc();
+ virtual ~GraphicBufferAlloc();
+
+ virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t usage);
+ virtual void freeAllGraphicBuffersExcept(int bufIdx);
+
+private:
+ Vector<sp<GraphicBuffer> > mBuffers;
+ Mutex mLock;
+};
+
// ---------------------------------------------------------------------------
class GraphicPlane
@@ -184,6 +200,7 @@
// ISurfaceComposer interface
virtual sp<ISurfaceComposerClient> createConnection();
virtual sp<ISurfaceComposerClient> createClientConnection();
+ virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc();
virtual sp<IMemoryHeap> getCblk() const;
virtual void bootFinished();
virtual void openGlobalTransaction();
@@ -322,8 +339,6 @@
status_t electronBeamOnAnimationImplLocked();
status_t renderScreenToTextureLocked(DisplayID dpy,
GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
- sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t usage) const;
friend class FreezeLock;
sp<FreezeLock> getFreezeLock() const;