Add the SurfaceTexture C++ implementation.

This change adds the C++ implementation of SurfaceTexture and related
classes. The goal of this is for a SurfaceTexture to be passed to
camera service or Stagefright in place of a Surface to allow camera
preview or decoded video frames to be streamed to an OpenGL ES texture
that an application can use.

Change-Id: I55c83a7017f1ecb81c9c9e3252cbd118b914296c
This commit is contained in:
Jamie Gennis 2010-12-20 11:27:26 -08:00
parent 4956334065
commit 8ba32fade1
8 changed files with 1047 additions and 2 deletions

View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_GUI_ISURFACETEXTURE_H
#define ANDROID_GUI_ISURFACETEXTURE_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
namespace android {
// ----------------------------------------------------------------------------
class ISurfaceTexture : public IInterface
{
public:
DECLARE_META_INTERFACE(SurfaceTexture);
// requestBuffer requests a new buffer for the given index. The server (i.e.
// the ISurfaceTexture implementation) assigns the newly created buffer to
// 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, uint32_t w, uint32_t h,
uint32_t format, uint32_t usage) = 0;
// setBufferCount sets the number of buffer slots available. Calling this
// will also cause all buffer slots to be emptied. The caller should empty
// its mirrored copy of the buffer slots when calling this method.
virtual status_t setBufferCount(int bufferCount) = 0;
// dequeueBuffer requests a new buffer slot for the client to use. Ownership
// of the slot is transfered to the client, meaning that the server will not
// use the contents of the buffer associated with that slot. The slot index
// returned may or may not contain a buffer. If the slot is empty the client
// should call requestBuffer to assign a new buffer to that slot. The client
// is expected to either call cancelBuffer on the dequeued slot or to fill
// in the contents of its associated buffer contents and call queueBuffer.
virtual status_t dequeueBuffer(int *slot) = 0;
// queueBuffer indicates that the client has finished filling in the
// contents of the buffer associated with slot and transfers ownership of
// that slot back to the server. It is not valid to call queueBuffer on a
// slot that is not owned by the client or one for which a buffer associated
// via requestBuffer.
virtual status_t queueBuffer(int slot) = 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
// the server.
virtual void cancelBuffer(int slot) = 0;
virtual status_t setCrop(const Rect& reg) = 0;
virtual status_t setTransform(uint32_t transform) = 0;
};
// ----------------------------------------------------------------------------
class BnSurfaceTexture : public BnInterface<ISurfaceTexture>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
// ----------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_GUI_ISURFACETEXTURE_H

View File

@ -0,0 +1,139 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_GUI_SURFACETEXTURE_H
#define ANDROID_GUI_SURFACETEXTURE_H
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <gui/ISurfaceTexture.h>
#include <ui/GraphicBuffer.h>
#include <utils/threads.h>
#define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture"
namespace android {
// ----------------------------------------------------------------------------
class SurfaceTexture : public BnSurfaceTexture {
public:
enum { MIN_BUFFER_SLOTS = 3 };
enum { NUM_BUFFER_SLOTS = 32 };
// tex indicates the name OpenGL texture to which images are to be streamed.
// This texture name cannot be changed once the SurfaceTexture is created.
SurfaceTexture(GLuint tex);
virtual ~SurfaceTexture();
// setBufferCount updates the number of available buffer slots. After
// calling this all buffer slots are both unallocated and owned by the
// SurfaceTexture object (i.e. they are not owned by the client).
virtual status_t setBufferCount(int bufferCount);
virtual sp<GraphicBuffer> requestBuffer(int buf, uint32_t w, uint32_t h,
uint32_t format, uint32_t usage);
// 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
// pointed to by the buf argument and a status of OK is returned. If no
// slot is available then a status of -EBUSY is returned and buf is
// unmodified.
virtual status_t dequeueBuffer(int *buf);
virtual status_t queueBuffer(int buf);
virtual void cancelBuffer(int buf);
virtual status_t setCrop(const Rect& reg);
virtual status_t setTransform(uint32_t transform);
// updateTexImage sets the image contents of the target texture to that of
// the most recently queued buffer.
//
// This call may only be made while the OpenGL ES context to which the
// target texture belongs is bound to the calling thread.
status_t updateTexImage();
private:
// freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
// all slots.
void freeAllBuffers();
// createImage creates a new EGLImage from a GraphicBuffer.
EGLImageKHR createImage(EGLDisplay dpy,
const sp<GraphicBuffer>& graphicBuffer);
enum { INVALID_BUFFER_SLOT = -1 };
struct BufferSlot {
// mGraphicBuffer points to the buffer allocated for this slot or is NULL
// if no buffer has been allocated.
sp<GraphicBuffer> mGraphicBuffer;
// mEglImage is the EGLImage created from mGraphicBuffer.
EGLImageKHR mEglImage;
// mEglDisplay is the EGLDisplay used to create mEglImage.
EGLDisplay mEglDisplay;
// mOwnedByClient indicates whether the slot is currently accessible to a
// client and should not be used by the SurfaceTexture object. It gets
// set to true when dequeueBuffer returns the slot and is reset to false
// when the client calls either queueBuffer or cancelBuffer on the slot.
bool mOwnedByClient;
};
// mSlots is the array of buffer slots that must be mirrored on the client
// side. This allows buffer ownership to be transferred between the client
// and server without sending a GraphicBuffer over binder. The entire array
// is initialized to NULL at construction time, and buffers are allocated
// for a slot when requestBuffer is called with that slot's index.
BufferSlot mSlots[NUM_BUFFER_SLOTS];
// mBufferCount is the number of buffer slots that the client and server
// must maintain. It defaults to MIN_BUFFER_SLOTS and can be changed by
// calling setBufferCount.
int mBufferCount;
// mCurrentTexture is the buffer slot index of the buffer that is currently
// bound to the OpenGL texture. A value of INVALID_BUFFER_SLOT, indicating
// that no buffer is currently bound to the texture.
int mCurrentTexture;
// 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;
// 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;
// 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.
Mutex mMutex;
};
// ----------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_GUI_SURFACETEXTURE_H

View File

@ -0,0 +1,118 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_GUI_SURFACETEXTURECLIENT_H
#define ANDROID_GUI_SURFACETEXTURECLIENT_H
#include <gui/ISurfaceTexture.h>
#include <gui/SurfaceTexture.h>
#include <ui/egl/android_natives.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
namespace android {
class SurfaceTextureClient
: public EGLNativeBase<ANativeWindow, SurfaceTextureClient, RefBase>
{
public:
SurfaceTextureClient(const sp<ISurfaceTexture>& surfaceTexture);
private:
// can't be copied
SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
SurfaceTextureClient(const SurfaceTextureClient& rhs);
// ANativeWindow hooks
static int setSwapInterval(ANativeWindow* window, int interval);
static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
static int cancelBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
static int query(ANativeWindow* window, int what, int* value);
static int perform(ANativeWindow* window, int operation, ...);
int setSwapInterval(int interval);
int dequeueBuffer(android_native_buffer_t** buffer);
int lockBuffer(android_native_buffer_t* buffer);
int queueBuffer(android_native_buffer_t* buffer);
int cancelBuffer(android_native_buffer_t* buffer);
int query(int what, int* value);
int perform(int operation, va_list args);
int dispatchSetUsage(va_list args);
int dispatchConnect(va_list args);
int dispatchDisconnect(va_list args);
int dispatchSetCrop(va_list args);
int dispatchSetBufferCount(va_list args);
int dispatchSetBuffersGeometry(va_list args);
int dispatchSetBuffersTransform(va_list args);
int connect(int api);
int disconnect(int api);
int setUsage(uint32_t reqUsage);
int setCrop(Rect const* rect);
int setBufferCount(int bufferCount);
int setBuffersGeometry(int w, int h, int format);
int setBuffersTransform(int transform);
void freeAllBuffers();
enum { MIN_BUFFER_SLOTS = SurfaceTexture::MIN_BUFFER_SLOTS };
enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
// 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;
// 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
// slot that has not yet been used. The buffer allocated to a slot will also
// be replaced if the requested buffer usage or geometry differs from that
// of the buffer allocated to a slot.
sp<GraphicBuffer> mSlots[NUM_BUFFER_SLOTS];
// mReqWidth is the buffer width that will be requested at the next dequeue
// operation. It is initialized to 1.
uint32_t mReqWidth;
// mReqHeight is the buffer height that will be requested at the next deuque
// operation. It is initialized to 1.
uint32_t mReqHeight;
// mReqFormat is the buffer pixel format that will be requested at the next
// deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888.
uint32_t mReqFormat;
// mReqUsage is the set of buffer usage flags that will be requested
// at the next deuque operation. It is initialized to 0.
uint32_t mReqUsage;
// 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.
Mutex mMutex;
};
}; // namespace android
#endif // ANDROID_GUI_SURFACETEXTURECLIENT_H

View File

@ -121,6 +121,7 @@ private:
friend class Surface;
friend class BpSurface;
friend class BnSurface;
friend class SurfaceTextureClient;
friend class LightRefBase<GraphicBuffer>;
GraphicBuffer(const GraphicBuffer& rhs);
GraphicBuffer& operator = (const GraphicBuffer& rhs);

View File

@ -4,17 +4,25 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
ISensorEventConnection.cpp \
ISensorServer.cpp \
ISurfaceTexture.cpp \
Sensor.cpp \
SensorChannel.cpp \
SensorEventQueue.cpp \
SensorManager.cpp
SensorManager.cpp \
SurfaceTexture.cpp \
SurfaceTextureClient.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
libhardware \
libhardware_legacy
libhardware_legacy \
libui \
libEGL \
libGLESv2 \
libsurfaceflinger_client
LOCAL_MODULE:= libgui

View File

@ -0,0 +1,204 @@
/*
* 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.
*/
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
#include <utils/Timers.h>
#include <binder/Parcel.h>
#include <binder/IInterface.h>
#include <gui/ISurfaceTexture.h>
namespace android {
// ----------------------------------------------------------------------------
enum {
REQUEST_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
SET_BUFFER_COUNT,
DEQUEUE_BUFFER,
QUEUE_BUFFER,
CANCEL_BUFFER,
SET_CROP,
SET_TRANSFORM,
};
class BpSurfaceTexture : public BpInterface<ISurfaceTexture>
{
public:
BpSurfaceTexture(const sp<IBinder>& impl)
: BpInterface<ISurfaceTexture>(impl)
{
}
virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(bufferIdx);
data.writeInt32(w);
data.writeInt32(h);
data.writeInt32(format);
data.writeInt32(usage);
remote()->transact(REQUEST_BUFFER, data, &reply);
sp<GraphicBuffer> buffer;
bool nonNull = reply.readInt32();
if (nonNull) {
buffer = new GraphicBuffer();
reply.read(*buffer);
}
return buffer;
}
virtual status_t setBufferCount(int bufferCount)
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(bufferCount);
remote()->transact(SET_BUFFER_COUNT, data, &reply);
status_t err = reply.readInt32();
return err;
}
virtual status_t dequeueBuffer(int *buf) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
remote()->transact(DEQUEUE_BUFFER, data, &reply);
*buf = reply.readInt32();
int result = reply.readInt32();
return result;
}
virtual status_t queueBuffer(int buf) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(buf);
remote()->transact(QUEUE_BUFFER, data, &reply);
status_t result = reply.readInt32();
return result;
}
virtual void cancelBuffer(int buf) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(buf);
remote()->transact(CANCEL_BUFFER, data, &reply);
}
virtual status_t setCrop(const Rect& reg) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeFloat(reg.left);
data.writeFloat(reg.top);
data.writeFloat(reg.right);
data.writeFloat(reg.bottom);
remote()->transact(SET_CROP, data, &reply);
status_t result = reply.readInt32();
return result;
}
virtual status_t setTransform(uint32_t transform) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(transform);
remote()->transact(SET_TRANSFORM, data, &reply);
status_t result = reply.readInt32();
return result;
}
};
IMPLEMENT_META_INTERFACE(SurfaceTexture, "android.gui.SurfaceTexture");
// ----------------------------------------------------------------------
status_t BnSurfaceTexture::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case REQUEST_BUFFER: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int bufferIdx = data.readInt32();
uint32_t w = data.readInt32();
uint32_t h = data.readInt32();
uint32_t format = data.readInt32();
uint32_t usage = data.readInt32();
sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format,
usage));
reply->writeInt32(buffer != 0);
if (buffer != 0) {
reply->write(*buffer);
}
return NO_ERROR;
} break;
case SET_BUFFER_COUNT: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int bufferCount = data.readInt32();
int result = setBufferCount(bufferCount);
reply->writeInt32(result);
return NO_ERROR;
} break;
case DEQUEUE_BUFFER: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int buf;
int result = dequeueBuffer(&buf);
reply->writeInt32(buf);
reply->writeInt32(result);
return NO_ERROR;
} break;
case QUEUE_BUFFER: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int buf = data.readInt32();
status_t result = queueBuffer(buf);
reply->writeInt32(result);
return NO_ERROR;
} break;
case CANCEL_BUFFER: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int buf = data.readInt32();
cancelBuffer(buf);
return NO_ERROR;
} break;
case SET_CROP: {
Rect reg;
CHECK_INTERFACE(ISurfaceTexture, data, reply);
reg.left = data.readFloat();
reg.top = data.readFloat();
reg.right = data.readFloat();
reg.bottom = data.readFloat();
status_t result = setCrop(reg);
reply->writeInt32(result);
return NO_ERROR;
} break;
case SET_TRANSFORM: {
Rect reg;
CHECK_INTERFACE(ISurfaceTexture, data, reply);
uint32_t transform = data.readInt32();
status_t result = setTransform(transform);
reply->writeInt32(result);
return NO_ERROR;
} break;
}
return BBinder::onTransact(code, data, reply, flags);
}
// ----------------------------------------------------------------------------
}; // namespace android

199
libs/gui/SurfaceTexture.cpp Normal file
View File

@ -0,0 +1,199 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "SurfaceTexture"
#define GL_GLEXT_PROTOTYPES
#define EGL_EGLEXT_PROTOTYPES
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <gui/SurfaceTexture.h>
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#include <utils/Log.h>
namespace android {
SurfaceTexture::SurfaceTexture(GLuint tex) :
mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT),
mLastQueued(INVALID_BUFFER_SLOT), mTexName(tex) {
}
SurfaceTexture::~SurfaceTexture() {
freeAllBuffers();
}
status_t SurfaceTexture::setBufferCount(int bufferCount) {
Mutex::Autolock lock(mMutex);
freeAllBuffers();
mBufferCount = bufferCount;
return OK;
}
sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
Mutex::Autolock lock(mMutex);
if (buf < 0 || mBufferCount <= buf) {
LOGE("requestBuffer: slot index out of range [0, %d]: %d",
mBufferCount, buf);
return 0;
}
usage |= GraphicBuffer::USAGE_HW_TEXTURE;
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
sp<GraphicBuffer> graphicBuffer(composer->createGraphicBuffer(w, h,
format, usage));
if (graphicBuffer == 0) {
LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed");
} else {
mSlots[buf].mGraphicBuffer = graphicBuffer;
if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage);
mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
}
}
return graphicBuffer;
}
status_t SurfaceTexture::dequeueBuffer(int *buf) {
Mutex::Autolock lock(mMutex);
int found = INVALID_BUFFER_SLOT;
for (int i = 0; i < mBufferCount; i++) {
if (!mSlots[i].mOwnedByClient && i != mCurrentTexture) {
mSlots[i].mOwnedByClient = true;
found = i;
break;
}
}
if (found == INVALID_BUFFER_SLOT) {
return -EBUSY;
}
*buf = found;
return OK;
}
status_t SurfaceTexture::queueBuffer(int buf) {
Mutex::Autolock lock(mMutex);
if (buf < 0 || mBufferCount <= buf) {
LOGE("queueBuffer: slot index out of range [0, %d]: %d",
mBufferCount, buf);
return -EINVAL;
} else if (!mSlots[buf].mOwnedByClient) {
LOGE("queueBuffer: slot %d is not owned by the client", buf);
return -EINVAL;
} else if (mSlots[buf].mGraphicBuffer == 0) {
LOGE("queueBuffer: slot %d was enqueued without requesting a buffer",
buf);
return -EINVAL;
}
mSlots[buf].mOwnedByClient = false;
mLastQueued = buf;
return OK;
}
void SurfaceTexture::cancelBuffer(int buf) {
Mutex::Autolock lock(mMutex);
if (buf < 0 || mBufferCount <= buf) {
LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount,
buf);
return;
} else if (!mSlots[buf].mOwnedByClient) {
LOGE("cancelBuffer: slot %d is not owned by the client", buf);
return;
}
mSlots[buf].mOwnedByClient = false;
}
status_t SurfaceTexture::setCrop(const Rect& reg) {
Mutex::Autolock lock(mMutex);
// XXX: How should we handle crops?
return OK;
}
status_t SurfaceTexture::setTransform(uint32_t transform) {
Mutex::Autolock lock(mMutex);
// XXX: How should we handle transforms?
return OK;
}
status_t SurfaceTexture::updateTexImage() {
Mutex::Autolock lock(mMutex);
// We always bind the texture even if we don't update its contents.
glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
// 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;
if (image == EGL_NO_IMAGE_KHR) {
EGLDisplay dpy = eglGetCurrentDisplay();
sp<GraphicBuffer> graphicBuffer = mSlots[mCurrentTexture].mGraphicBuffer;
image = createImage(dpy, graphicBuffer);
mSlots[mCurrentTexture].mEglImage = image;
mSlots[mCurrentTexture].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);
return -EINVAL;
}
}
return OK;
}
void SurfaceTexture::freeAllBuffers() {
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
mSlots[i].mGraphicBuffer = 0;
mSlots[i].mOwnedByClient = false;
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;
}
}
}
EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
const sp<GraphicBuffer>& graphicBuffer) {
EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
EGLint attrs[] = {
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
EGL_NONE,
};
EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
EGLint error = eglGetError();
if (error != EGL_SUCCESS) {
LOGE("error creating EGLImage: %#x", error);
} else if (image == EGL_NO_IMAGE_KHR) {
LOGE("no error reported, but no image was returned by "
"eglCreateImageKHR");
}
return image;
}
}; // namespace android

View File

@ -0,0 +1,285 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "SurfaceTextureClient"
#include <gui/SurfaceTextureClient.h>
#include <utils/Log.h>
namespace android {
SurfaceTextureClient::SurfaceTextureClient(
const sp<ISurfaceTexture>& surfaceTexture):
mSurfaceTexture(surfaceTexture), mReqWidth(1), mReqHeight(1),
mReqFormat(DEFAULT_FORMAT), mReqUsage(0), mMutex() {
// 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;
}
int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) {
SurfaceTextureClient* c = getSelf(window);
return c->setSwapInterval(interval);
}
int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window,
android_native_buffer_t** buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->dequeueBuffer(buffer);
}
int SurfaceTextureClient::cancelBuffer(ANativeWindow* window,
android_native_buffer_t* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->cancelBuffer(buffer);
}
int SurfaceTextureClient::lockBuffer(ANativeWindow* window,
android_native_buffer_t* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->lockBuffer(buffer);
}
int SurfaceTextureClient::queueBuffer(ANativeWindow* window,
android_native_buffer_t* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->queueBuffer(buffer);
}
int SurfaceTextureClient::query(ANativeWindow* window, int what, int* value) {
SurfaceTextureClient* c = getSelf(window);
return c->query(what, value);
}
int SurfaceTextureClient::perform(ANativeWindow* window, int operation, ...) {
va_list args;
va_start(args, operation);
SurfaceTextureClient* c = getSelf(window);
return c->perform(operation, args);
}
int SurfaceTextureClient::setSwapInterval(int interval) {
return INVALID_OPERATION;
}
int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
Mutex::Autolock lock(mMutex);
int buf = -1;
status_t err = mSurfaceTexture->dequeueBuffer(&buf);
if (err < 0) {
return err;
}
sp<GraphicBuffer>& gbuf(mSlots[buf]);
if (gbuf == 0 || gbuf->getWidth() != mReqWidth ||
gbuf->getHeight() != mReqHeight ||
uint32_t(gbuf->getPixelFormat()) != mReqFormat ||
(gbuf->getUsage() & mReqUsage) != mReqUsage) {
gbuf = mSurfaceTexture->requestBuffer(buf, mReqWidth, mReqHeight,
mReqFormat, mReqUsage);
if (gbuf == 0) {
return NO_MEMORY;
}
}
*buffer = gbuf.get();
return OK;
}
int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) {
Mutex::Autolock lock(mMutex);
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
if (mSlots[i].get() == buffer) {
mSurfaceTexture->cancelBuffer(i);
return OK;
}
}
return BAD_VALUE;
}
int SurfaceTextureClient::lockBuffer(android_native_buffer_t* buffer) {
Mutex::Autolock lock(mMutex);
return OK;
}
int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
Mutex::Autolock lock(mMutex);
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
if (mSlots[i].get() == GraphicBuffer::getSelf(buffer)) {
return mSurfaceTexture->queueBuffer(i);
}
}
LOGE("queueBuffer: unknown buffer queued");
return BAD_VALUE;
}
int SurfaceTextureClient::query(int what, int* value) {
Mutex::Autolock lock(mMutex);
// XXX: Implement this!
return INVALID_OPERATION;
}
int SurfaceTextureClient::perform(int operation, va_list args)
{
int res = NO_ERROR;
switch (operation) {
case NATIVE_WINDOW_CONNECT:
res = dispatchConnect(args);
break;
case NATIVE_WINDOW_DISCONNECT:
res = dispatchDisconnect(args);
break;
case NATIVE_WINDOW_SET_USAGE:
res = dispatchSetUsage(args);
break;
case NATIVE_WINDOW_SET_CROP:
res = dispatchSetCrop(args);
break;
case NATIVE_WINDOW_SET_BUFFER_COUNT:
res = dispatchSetBufferCount(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
res = dispatchSetBuffersGeometry(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
res = dispatchSetBuffersTransform(args);
break;
default:
res = NAME_NOT_FOUND;
break;
}
return res;
}
int SurfaceTextureClient::dispatchConnect(va_list args) {
int api = va_arg(args, int);
return connect(api);
}
int SurfaceTextureClient::dispatchDisconnect(va_list args) {
int api = va_arg(args, int);
return disconnect(api);
}
int SurfaceTextureClient::dispatchSetUsage(va_list args) {
int usage = va_arg(args, int);
return setUsage(usage);
}
int SurfaceTextureClient::dispatchSetCrop(va_list args) {
android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
return setCrop(reinterpret_cast<Rect const*>(rect));
}
int SurfaceTextureClient::dispatchSetBufferCount(va_list args) {
size_t bufferCount = va_arg(args, size_t);
return setBufferCount(bufferCount);
}
int SurfaceTextureClient::dispatchSetBuffersGeometry(va_list args) {
int w = va_arg(args, int);
int h = va_arg(args, int);
int f = va_arg(args, int);
return setBuffersGeometry(w, h, f);
}
int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) {
int transform = va_arg(args, int);
return setBuffersTransform(transform);
}
int SurfaceTextureClient::connect(int api) {
// XXX: Implement this!
return INVALID_OPERATION;
}
int SurfaceTextureClient::disconnect(int api) {
// XXX: Implement this!
return INVALID_OPERATION;
}
int SurfaceTextureClient::setUsage(uint32_t reqUsage)
{
Mutex::Autolock lock(mMutex);
mReqUsage = reqUsage;
return OK;
}
int SurfaceTextureClient::setCrop(Rect const* rect)
{
Mutex::Autolock lock(mMutex);
// empty/invalid rects are not allowed
if (rect->isEmpty())
return BAD_VALUE;
status_t err = mSurfaceTexture->setCrop(*rect);
LOGE_IF(err, "ISurfaceTexture::setCrop(...) returned %s",
strerror(-err));
return err;
}
int SurfaceTextureClient::setBufferCount(int bufferCount)
{
Mutex::Autolock lock(mMutex);
status_t err = mSurfaceTexture->setBufferCount(bufferCount);
LOGE_IF(err, "ISurfaceTexture::setBufferCount(%d) returned %s",
bufferCount, strerror(-err));
if (err == NO_ERROR) {
freeAllBuffers();
}
return err;
}
int SurfaceTextureClient::setBuffersGeometry(int w, int h, int format)
{
Mutex::Autolock lock(mMutex);
if (w<0 || h<0 || format<0)
return BAD_VALUE;
if ((w && !h) || (!w && h))
return BAD_VALUE;
mReqWidth = w;
mReqHeight = h;
mReqFormat = format;
return NO_ERROR;
}
int SurfaceTextureClient::setBuffersTransform(int transform)
{
Mutex::Autolock lock(mMutex);
status_t err = mSurfaceTexture->setTransform(transform);
return err;
}
void SurfaceTextureClient::freeAllBuffers() {
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
mSlots[i] = 0;
}
}
}; // namespace android