changes to SurfaceTexture needed for unification with SF
- implement connect/disconnect - implement missing query - handle texture_2d in addition to texture_external_oes Change-Id: I971a70821f00f22b01f5337de4a7d451177fec4d
This commit is contained in:
parent
626d865d41
commit
7a042bf324
|
@ -127,11 +127,28 @@ public:
|
||||||
// be called from the client.
|
// be called from the client.
|
||||||
status_t setDefaultBufferSize(uint32_t w, uint32_t h);
|
status_t setDefaultBufferSize(uint32_t w, uint32_t h);
|
||||||
|
|
||||||
private:
|
// getCurrentBuffer returns the buffer associated with the current image.
|
||||||
|
sp<GraphicBuffer> getCurrentBuffer() const;
|
||||||
|
|
||||||
|
// getCurrentTextureTarget returns the texture target of the current
|
||||||
|
// texture as returned by updateTexImage().
|
||||||
|
GLenum getCurrentTextureTarget() const;
|
||||||
|
|
||||||
|
// getCurrentCrop returns the cropping rectangle of the current buffer
|
||||||
|
Rect getCurrentCrop() const;
|
||||||
|
|
||||||
|
// getCurrentTransform returns the transform of the current buffer
|
||||||
|
uint32_t getCurrentTransform() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
// freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
|
// freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
|
||||||
// all slots.
|
// all slots.
|
||||||
void freeAllBuffers();
|
void freeAllBuffers();
|
||||||
|
static bool isExternalFormat(uint32_t format);
|
||||||
|
static GLenum getTextureTarget(uint32_t format);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
// createImage creates a new EGLImage from a GraphicBuffer.
|
// createImage creates a new EGLImage from a GraphicBuffer.
|
||||||
EGLImageKHR createImage(EGLDisplay dpy,
|
EGLImageKHR createImage(EGLDisplay dpy,
|
||||||
|
@ -194,6 +211,10 @@ private:
|
||||||
// reset mCurrentTexture to INVALID_BUFFER_SLOT.
|
// reset mCurrentTexture to INVALID_BUFFER_SLOT.
|
||||||
int mCurrentTexture;
|
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
|
// mCurrentTextureBuf is the graphic buffer of the current texture. It's
|
||||||
// possible that this buffer is not associated with any buffer slot, so we
|
// possible that this buffer is not associated with any buffer slot, so we
|
||||||
// must track it separately in order to properly use
|
// must track it separately in order to properly use
|
||||||
|
@ -262,7 +283,7 @@ private:
|
||||||
// mMutex is the mutex used to prevent concurrent access to the member
|
// mMutex is the mutex used to prevent concurrent access to the member
|
||||||
// variables of SurfaceTexture objects. It must be locked whenever the
|
// variables of SurfaceTexture objects. It must be locked whenever the
|
||||||
// member variables are accessed.
|
// member variables are accessed.
|
||||||
Mutex mMutex;
|
mutable Mutex mMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
|
class Surface;
|
||||||
|
|
||||||
class SurfaceTextureClient
|
class SurfaceTextureClient
|
||||||
: public EGLNativeBase<ANativeWindow, SurfaceTextureClient, RefBase>
|
: public EGLNativeBase<ANativeWindow, SurfaceTextureClient, RefBase>
|
||||||
{
|
{
|
||||||
|
@ -36,6 +38,7 @@ public:
|
||||||
sp<ISurfaceTexture> getISurfaceTexture() const;
|
sp<ISurfaceTexture> getISurfaceTexture() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class Surface;
|
||||||
|
|
||||||
// can't be copied
|
// can't be copied
|
||||||
SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
|
SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
|
||||||
|
@ -78,6 +81,8 @@ private:
|
||||||
|
|
||||||
void freeAllBuffers();
|
void freeAllBuffers();
|
||||||
|
|
||||||
|
int getConnectedApi() const;
|
||||||
|
|
||||||
enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
|
enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
|
||||||
enum { MIN_BUFFER_SLOTS = SurfaceTexture::MIN_BUFFER_SLOTS };
|
enum { MIN_BUFFER_SLOTS = SurfaceTexture::MIN_BUFFER_SLOTS };
|
||||||
enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
|
enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
|
||||||
|
@ -121,10 +126,25 @@ private:
|
||||||
// a timestamp is auto-generated when queueBuffer is called.
|
// a timestamp is auto-generated when queueBuffer is called.
|
||||||
int64_t mTimestamp;
|
int64_t mTimestamp;
|
||||||
|
|
||||||
|
// mConnectedApi holds the currently connected API to this surface
|
||||||
|
int mConnectedApi;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
// mMutex is the mutex used to prevent concurrent access to the member
|
// mMutex is the mutex used to prevent concurrent access to the member
|
||||||
// variables of SurfaceTexture objects. It must be locked whenever the
|
// variables of SurfaceTexture objects. It must be locked whenever the
|
||||||
// member variables are accessed.
|
// member variables are accessed.
|
||||||
Mutex mMutex;
|
mutable Mutex mMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace android
|
}; // namespace android
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
|
|
||||||
#include <gui/SurfaceTexture.h>
|
#include <gui/SurfaceTexture.h>
|
||||||
|
|
||||||
|
#include <hardware/hardware.h>
|
||||||
|
|
||||||
#include <surfaceflinger/ISurfaceComposer.h>
|
#include <surfaceflinger/ISurfaceComposer.h>
|
||||||
#include <surfaceflinger/SurfaceComposerClient.h>
|
#include <surfaceflinger/SurfaceComposerClient.h>
|
||||||
#include <surfaceflinger/IGraphicBufferAlloc.h>
|
#include <surfaceflinger/IGraphicBufferAlloc.h>
|
||||||
|
@ -82,6 +84,7 @@ SurfaceTexture::SurfaceTexture(GLuint tex) :
|
||||||
mUseDefaultSize(true),
|
mUseDefaultSize(true),
|
||||||
mBufferCount(MIN_BUFFER_SLOTS),
|
mBufferCount(MIN_BUFFER_SLOTS),
|
||||||
mCurrentTexture(INVALID_BUFFER_SLOT),
|
mCurrentTexture(INVALID_BUFFER_SLOT),
|
||||||
|
mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES),
|
||||||
mCurrentTransform(0),
|
mCurrentTransform(0),
|
||||||
mCurrentTimestamp(0),
|
mCurrentTimestamp(0),
|
||||||
mLastQueued(INVALID_BUFFER_SLOT),
|
mLastQueued(INVALID_BUFFER_SLOT),
|
||||||
|
@ -198,6 +201,7 @@ status_t SurfaceTexture::dequeueBuffer(int *buf) {
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
return ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
|
return ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mUseDefaultSize) &&
|
if ((mUseDefaultSize) &&
|
||||||
((uint32_t(buffer->width) != mDefaultWidth) ||
|
((uint32_t(buffer->width) != mDefaultWidth) ||
|
||||||
(uint32_t(buffer->height) != mDefaultHeight))) {
|
(uint32_t(buffer->height) != mDefaultHeight))) {
|
||||||
|
@ -264,9 +268,6 @@ status_t SurfaceTexture::updateTexImage() {
|
||||||
LOGV("SurfaceTexture::updateTexImage");
|
LOGV("SurfaceTexture::updateTexImage");
|
||||||
Mutex::Autolock lock(mMutex);
|
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,
|
// Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,
|
||||||
// so this check will fail until a buffer gets queued.
|
// so this check will fail until a buffer gets queued.
|
||||||
if (mCurrentTexture != mLastQueued) {
|
if (mCurrentTexture != mLastQueued) {
|
||||||
|
@ -284,7 +285,15 @@ status_t SurfaceTexture::updateTexImage() {
|
||||||
while ((error = glGetError()) != GL_NO_ERROR) {
|
while ((error = glGetError()) != GL_NO_ERROR) {
|
||||||
LOGE("GL error cleared before updating SurfaceTexture: %#04x", error);
|
LOGE("GL error cleared before updating SurfaceTexture: %#04x", error);
|
||||||
}
|
}
|
||||||
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
|
|
||||||
|
GLenum target = getTextureTarget(
|
||||||
|
mSlots[mLastQueued].mGraphicBuffer->format);
|
||||||
|
if (target != mCurrentTextureTarget) {
|
||||||
|
glDeleteTextures(1, &mTexName);
|
||||||
|
}
|
||||||
|
glBindTexture(target, mTexName);
|
||||||
|
glEGLImageTargetTexture2DOES(target, (GLeglImageOES)image);
|
||||||
|
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
while ((error = glGetError()) != GL_NO_ERROR) {
|
while ((error = glGetError()) != GL_NO_ERROR) {
|
||||||
LOGE("error binding external texture image %p (slot %d): %#04x",
|
LOGE("error binding external texture image %p (slot %d): %#04x",
|
||||||
|
@ -297,14 +306,53 @@ status_t SurfaceTexture::updateTexImage() {
|
||||||
|
|
||||||
// Update the SurfaceTexture state.
|
// Update the SurfaceTexture state.
|
||||||
mCurrentTexture = mLastQueued;
|
mCurrentTexture = mLastQueued;
|
||||||
|
mCurrentTextureTarget = target;
|
||||||
mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer;
|
mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer;
|
||||||
mCurrentCrop = mLastQueuedCrop;
|
mCurrentCrop = mLastQueuedCrop;
|
||||||
mCurrentTransform = mLastQueuedTransform;
|
mCurrentTransform = mLastQueuedTransform;
|
||||||
mCurrentTimestamp = mLastQueuedTimestamp;
|
mCurrentTimestamp = mLastQueuedTimestamp;
|
||||||
|
} else {
|
||||||
|
// We always bind the texture even if we don't update its contents.
|
||||||
|
glBindTexture(mCurrentTextureTarget, mTexName);
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SurfaceTexture::isExternalFormat(uint32_t format)
|
||||||
|
{
|
||||||
|
switch (format) {
|
||||||
|
// supported YUV formats
|
||||||
|
case HAL_PIXEL_FORMAT_YV12:
|
||||||
|
// Legacy/deprecated YUV formats
|
||||||
|
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
|
||||||
|
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
|
||||||
|
case HAL_PIXEL_FORMAT_YCbCr_422_I:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any OEM format needs to be considered
|
||||||
|
if (format>=0x100 && format<=0x1FF)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
void SurfaceTexture::getTransformMatrix(float mtx[16]) {
|
void SurfaceTexture::getTransformMatrix(float mtx[16]) {
|
||||||
LOGV("SurfaceTexture::getTransformMatrix");
|
LOGV("SurfaceTexture::getTransformMatrix");
|
||||||
Mutex::Autolock lock(mMutex);
|
Mutex::Autolock lock(mMutex);
|
||||||
|
@ -459,6 +507,22 @@ EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sp<GraphicBuffer> SurfaceTexture::getCurrentBuffer() const {
|
||||||
|
Mutex::Autolock lock(mMutex);
|
||||||
|
return mCurrentTextureBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect SurfaceTexture::getCurrentCrop() const {
|
||||||
|
Mutex::Autolock lock(mMutex);
|
||||||
|
return mCurrentCrop;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SurfaceTexture::getCurrentTransform() const {
|
||||||
|
Mutex::Autolock lock(mMutex);
|
||||||
|
return mCurrentTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void mtxMul(float out[16], const float a[16], const float b[16]) {
|
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[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[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
|
||||||
|
|
|
@ -26,8 +26,10 @@ namespace android {
|
||||||
SurfaceTextureClient::SurfaceTextureClient(
|
SurfaceTextureClient::SurfaceTextureClient(
|
||||||
const sp<ISurfaceTexture>& surfaceTexture):
|
const sp<ISurfaceTexture>& surfaceTexture):
|
||||||
mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
|
mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
|
||||||
mReqHeight(0), mReqFormat(DEFAULT_FORMAT), mReqUsage(0),
|
mReqHeight(0), mReqFormat(0), mReqUsage(0),
|
||||||
mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mMutex() {
|
mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mConnectedApi(0),
|
||||||
|
mQueryWidth(0), mQueryHeight(0), mQueryFormat(0),
|
||||||
|
mMutex() {
|
||||||
// Initialize the ANativeWindow function pointers.
|
// Initialize the ANativeWindow function pointers.
|
||||||
ANativeWindow::setSwapInterval = setSwapInterval;
|
ANativeWindow::setSwapInterval = setSwapInterval;
|
||||||
ANativeWindow::dequeueBuffer = dequeueBuffer;
|
ANativeWindow::dequeueBuffer = dequeueBuffer;
|
||||||
|
@ -101,9 +103,10 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
|
||||||
}
|
}
|
||||||
sp<GraphicBuffer>& gbuf(mSlots[buf]);
|
sp<GraphicBuffer>& gbuf(mSlots[buf]);
|
||||||
if (err == ISurfaceTexture::BUFFER_NEEDS_REALLOCATION ||
|
if (err == ISurfaceTexture::BUFFER_NEEDS_REALLOCATION ||
|
||||||
gbuf == 0 || gbuf->getWidth() != mReqWidth ||
|
gbuf == 0 ||
|
||||||
gbuf->getHeight() != mReqHeight ||
|
(mReqWidth && gbuf->getWidth() != mReqWidth) ||
|
||||||
uint32_t(gbuf->getPixelFormat()) != mReqFormat ||
|
(mReqHeight && gbuf->getHeight() != mReqHeight) ||
|
||||||
|
(mReqFormat && uint32_t(gbuf->getPixelFormat()) != mReqFormat) ||
|
||||||
(gbuf->getUsage() & mReqUsage) != mReqUsage) {
|
(gbuf->getUsage() & mReqUsage) != mReqUsage) {
|
||||||
gbuf = mSurfaceTexture->requestBuffer(buf, mReqWidth, mReqHeight,
|
gbuf = mSurfaceTexture->requestBuffer(buf, mReqWidth, mReqHeight,
|
||||||
mReqFormat, mReqUsage);
|
mReqFormat, mReqUsage);
|
||||||
|
@ -111,6 +114,9 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
|
||||||
LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed");
|
LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed");
|
||||||
return NO_MEMORY;
|
return NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
mQueryWidth = gbuf->width;
|
||||||
|
mQueryHeight = gbuf->height;
|
||||||
|
mQueryFormat = gbuf->format;
|
||||||
}
|
}
|
||||||
*buffer = gbuf.get();
|
*buffer = gbuf.get();
|
||||||
return OK;
|
return OK;
|
||||||
|
@ -159,13 +165,13 @@ int SurfaceTextureClient::query(int what, int* value) {
|
||||||
Mutex::Autolock lock(mMutex);
|
Mutex::Autolock lock(mMutex);
|
||||||
switch (what) {
|
switch (what) {
|
||||||
case NATIVE_WINDOW_WIDTH:
|
case NATIVE_WINDOW_WIDTH:
|
||||||
|
*value = mQueryWidth ? mQueryWidth : mReqWidth;
|
||||||
|
return NO_ERROR;
|
||||||
case NATIVE_WINDOW_HEIGHT:
|
case NATIVE_WINDOW_HEIGHT:
|
||||||
// XXX: How should SurfaceTexture behave if setBuffersGeometry didn't
|
*value = mQueryHeight ? mQueryHeight : mReqHeight;
|
||||||
// override the size?
|
|
||||||
*value = 0;
|
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
case NATIVE_WINDOW_FORMAT:
|
case NATIVE_WINDOW_FORMAT:
|
||||||
*value = DEFAULT_FORMAT;
|
*value = mQueryFormat ? mQueryFormat : mReqFormat;
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
|
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
|
||||||
*value = MIN_UNDEQUEUED_BUFFERS;
|
*value = MIN_UNDEQUEUED_BUFFERS;
|
||||||
|
@ -260,16 +266,49 @@ int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) {
|
||||||
|
|
||||||
int SurfaceTextureClient::connect(int api) {
|
int SurfaceTextureClient::connect(int api) {
|
||||||
LOGV("SurfaceTextureClient::connect");
|
LOGV("SurfaceTextureClient::connect");
|
||||||
// XXX: Implement this!
|
Mutex::Autolock lock(mMutex);
|
||||||
return INVALID_OPERATION;
|
int err = NO_ERROR;
|
||||||
|
switch (api) {
|
||||||
|
case NATIVE_WINDOW_API_EGL:
|
||||||
|
if (mConnectedApi) {
|
||||||
|
err = -EINVAL;
|
||||||
|
} else {
|
||||||
|
mConnectedApi = api;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SurfaceTextureClient::disconnect(int api) {
|
int SurfaceTextureClient::disconnect(int api) {
|
||||||
LOGV("SurfaceTextureClient::disconnect");
|
LOGV("SurfaceTextureClient::disconnect");
|
||||||
// XXX: Implement this!
|
Mutex::Autolock lock(mMutex);
|
||||||
return INVALID_OPERATION;
|
int err = NO_ERROR;
|
||||||
|
switch (api) {
|
||||||
|
case NATIVE_WINDOW_API_EGL:
|
||||||
|
if (mConnectedApi == api) {
|
||||||
|
mConnectedApi = 0;
|
||||||
|
} else {
|
||||||
|
err = -EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SurfaceTextureClient::getConnectedApi() const
|
||||||
|
{
|
||||||
|
Mutex::Autolock lock(mMutex);
|
||||||
|
return mConnectedApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int SurfaceTextureClient::setUsage(uint32_t reqUsage)
|
int SurfaceTextureClient::setUsage(uint32_t reqUsage)
|
||||||
{
|
{
|
||||||
LOGV("SurfaceTextureClient::setUsage");
|
LOGV("SurfaceTextureClient::setUsage");
|
||||||
|
|
Loading…
Reference in New Issue