Fix remote GraphicBuffer allocation in SurfaceFlinger.
This change fixes a horrible hack that I did to allow application
processes to create GraphicBuffer objects by making a binder call to
SurfaceFlinger. This change introduces a new binder interface
specifically for doing this, and does it in such a way that
SurfaceFlinger will maintain a reference to the buffers until the app is
done with them.
Change-Id: Icb240397c6c206d7f69124c1497a829f051cb49b
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 09cf2a2..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 };
@@ -140,6 +143,12 @@
// 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;
@@ -176,6 +185,16 @@
// 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 1389ed6..447de76 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -29,6 +29,7 @@
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/SurfaceComposerClient.h>
+#include <surfaceflinger/IGraphicBufferAlloc.h>
#include <utils/Log.h>
@@ -83,6 +84,8 @@
mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
mSlots[i].mOwnedByClient = false;
}
+ sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+ mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
}
SurfaceTexture::~SurfaceTexture() {
@@ -110,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 {
@@ -122,6 +124,7 @@
mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
}
+ mAllocdBuffers.add(graphicBuffer);
}
return graphicBuffer;
}
@@ -204,27 +207,28 @@
// Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,
// so this check will fail until a buffer gets queued.
if (mCurrentTexture != mLastQueued) {
- // Update the SurfaceTexture state.
- mCurrentTexture = mLastQueued;
- mCurrentCrop = mLastQueuedCrop;
- mCurrentTransform = mLastQueuedTransform;
-
// Update the GL texture object.
- EGLImageKHR image = mSlots[mCurrentTexture].mEglImage;
+ 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;
}
@@ -282,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,
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/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;