Add the concept of synchronous dequeueBuffer in SurfaceTexture
Change-Id: Ic94cbab092953243a0746e04bbe1b2eb0cc930ef
This commit is contained in:
parent
eafabcdc16
commit
b3e518c820
@ -142,6 +142,13 @@ public:
|
|||||||
// getCurrentTransform returns the transform of the current buffer
|
// getCurrentTransform returns the transform of the current buffer
|
||||||
uint32_t getCurrentTransform() const;
|
uint32_t getCurrentTransform() const;
|
||||||
|
|
||||||
|
// setSynchronousMode set whether dequeueBuffer is synchronous or
|
||||||
|
// asynchronous. In synchronous mode, dequeueBuffer blocks until
|
||||||
|
// a buffer is available, the currently bound buffer can be dequeued and
|
||||||
|
// queued buffers will be retired in order.
|
||||||
|
// The default mode is asynchronous.
|
||||||
|
status_t setSynchronousMode(bool enabled);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
|
// freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
|
||||||
@ -159,6 +166,16 @@ private:
|
|||||||
enum { INVALID_BUFFER_SLOT = -1 };
|
enum { INVALID_BUFFER_SLOT = -1 };
|
||||||
|
|
||||||
struct BufferSlot {
|
struct BufferSlot {
|
||||||
|
|
||||||
|
BufferSlot()
|
||||||
|
: mEglImage(EGL_NO_IMAGE_KHR),
|
||||||
|
mEglDisplay(EGL_NO_DISPLAY),
|
||||||
|
mBufferState(BufferSlot::FREE),
|
||||||
|
mRequestBufferCalled(false),
|
||||||
|
mLastQueuedTransform(0),
|
||||||
|
mLastQueuedTimestamp(0) {
|
||||||
|
}
|
||||||
|
|
||||||
// mGraphicBuffer points to the buffer allocated for this slot or is NULL
|
// mGraphicBuffer points to the buffer allocated for this slot or is NULL
|
||||||
// if no buffer has been allocated.
|
// if no buffer has been allocated.
|
||||||
sp<GraphicBuffer> mGraphicBuffer;
|
sp<GraphicBuffer> mGraphicBuffer;
|
||||||
@ -169,11 +186,32 @@ private:
|
|||||||
// mEglDisplay is the EGLDisplay used to create mEglImage.
|
// mEglDisplay is the EGLDisplay used to create mEglImage.
|
||||||
EGLDisplay mEglDisplay;
|
EGLDisplay mEglDisplay;
|
||||||
|
|
||||||
// mOwnedByClient indicates whether the slot is currently accessible to a
|
// mBufferState indicates whether the slot is currently accessible to a
|
||||||
// client and should not be used by the SurfaceTexture object. It gets
|
// 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
|
// set to true when dequeueBuffer returns the slot and is reset to false
|
||||||
// when the client calls either queueBuffer or cancelBuffer on the slot.
|
// when the client calls either queueBuffer or cancelBuffer on the slot.
|
||||||
bool mOwnedByClient;
|
enum { DEQUEUED=-2, FREE=-1, QUEUED=0 };
|
||||||
|
int8_t mBufferState;
|
||||||
|
|
||||||
|
|
||||||
|
// mRequestBufferCalled is used for validating that the client did
|
||||||
|
// call requestBuffer() when told to do so. Technically this is not
|
||||||
|
// needed but useful for debugging and catching client bugs.
|
||||||
|
bool mRequestBufferCalled;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// mLastQueuedTimestamp is the timestamp for the buffer that was most
|
||||||
|
// recently queued. This gets set by queueBuffer.
|
||||||
|
int64_t mLastQueuedTimestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
// mSlots is the array of buffer slots that must be mirrored on the client
|
// mSlots is the array of buffer slots that must be mirrored on the client
|
||||||
@ -230,25 +268,6 @@ private:
|
|||||||
// gets set to mLastQueuedTimestamp each time updateTexImage is called.
|
// gets set to mLastQueuedTimestamp each time updateTexImage is called.
|
||||||
int64_t mCurrentTimestamp;
|
int64_t mCurrentTimestamp;
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// mLastQueuedTimestamp is the timestamp for the buffer that was most
|
|
||||||
// recently queued. This gets set by queueBuffer.
|
|
||||||
int64_t mLastQueuedTimestamp;
|
|
||||||
|
|
||||||
// mNextCrop is the crop rectangle that will be used for the next buffer
|
// mNextCrop is the crop rectangle that will be used for the next buffer
|
||||||
// that gets queued. It is set by calling setCrop.
|
// that gets queued. It is set by calling setCrop.
|
||||||
Rect mNextCrop;
|
Rect mNextCrop;
|
||||||
@ -271,6 +290,16 @@ private:
|
|||||||
// queueBuffer.
|
// queueBuffer.
|
||||||
sp<FrameAvailableListener> mFrameAvailableListener;
|
sp<FrameAvailableListener> mFrameAvailableListener;
|
||||||
|
|
||||||
|
// mSynchronousMode whether we're in synchronous mode or not
|
||||||
|
bool mSynchronousMode;
|
||||||
|
|
||||||
|
// mDequeueCondition condition used for dequeueBuffer in synchronous mode
|
||||||
|
mutable Condition mDequeueCondition;
|
||||||
|
|
||||||
|
// mQueue is a FIFO of queued buffers used in synchronous mode
|
||||||
|
typedef Vector<int> Fifo;
|
||||||
|
Fifo mQueue;
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -86,17 +86,10 @@ SurfaceTexture::SurfaceTexture(GLuint tex) :
|
|||||||
mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES),
|
mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES),
|
||||||
mCurrentTransform(0),
|
mCurrentTransform(0),
|
||||||
mCurrentTimestamp(0),
|
mCurrentTimestamp(0),
|
||||||
mLastQueued(INVALID_BUFFER_SLOT),
|
|
||||||
mLastQueuedTransform(0),
|
|
||||||
mLastQueuedTimestamp(0),
|
|
||||||
mNextTransform(0),
|
mNextTransform(0),
|
||||||
mTexName(tex) {
|
mTexName(tex),
|
||||||
|
mSynchronousMode(false) {
|
||||||
LOGV("SurfaceTexture::SurfaceTexture");
|
LOGV("SurfaceTexture::SurfaceTexture");
|
||||||
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
|
|
||||||
mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
|
|
||||||
mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
|
|
||||||
mSlots[i].mOwnedByClient = false;
|
|
||||||
}
|
|
||||||
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
|
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
|
||||||
mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
|
mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
|
||||||
mNextCrop.makeInvalid();
|
mNextCrop.makeInvalid();
|
||||||
@ -109,16 +102,21 @@ SurfaceTexture::~SurfaceTexture() {
|
|||||||
|
|
||||||
status_t SurfaceTexture::setBufferCount(int bufferCount) {
|
status_t SurfaceTexture::setBufferCount(int bufferCount) {
|
||||||
LOGV("SurfaceTexture::setBufferCount");
|
LOGV("SurfaceTexture::setBufferCount");
|
||||||
|
Mutex::Autolock lock(mMutex);
|
||||||
|
|
||||||
if (bufferCount < MIN_BUFFER_SLOTS) {
|
const int minBufferSlots = mSynchronousMode ?
|
||||||
|
MIN_BUFFER_SLOTS-1 : MIN_BUFFER_SLOTS;
|
||||||
|
|
||||||
|
if (bufferCount < minBufferSlots) {
|
||||||
return BAD_VALUE;
|
return BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mutex::Autolock lock(mMutex);
|
|
||||||
freeAllBuffers();
|
freeAllBuffers();
|
||||||
mBufferCount = bufferCount;
|
mBufferCount = bufferCount;
|
||||||
mCurrentTexture = INVALID_BUFFER_SLOT;
|
mCurrentTexture = INVALID_BUFFER_SLOT;
|
||||||
mLastQueued = INVALID_BUFFER_SLOT;
|
mQueue.clear();
|
||||||
|
mQueue.reserve(mSynchronousMode ? mBufferCount : 1);
|
||||||
|
mDequeueCondition.signal();
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,6 +138,7 @@ sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf) {
|
|||||||
mBufferCount, buf);
|
mBufferCount, buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
mSlots[buf].mRequestBufferCalled = true;
|
||||||
return mSlots[buf].mGraphicBuffer;
|
return mSlots[buf].mGraphicBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,14 +152,44 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Mutex::Autolock lock(mMutex);
|
Mutex::Autolock lock(mMutex);
|
||||||
int found = INVALID_BUFFER_SLOT;
|
int found, foundSync;
|
||||||
|
int dequeuedCount = 0;
|
||||||
|
bool tryAgain = true;
|
||||||
|
while (tryAgain) {
|
||||||
|
found = INVALID_BUFFER_SLOT;
|
||||||
|
foundSync = INVALID_BUFFER_SLOT;
|
||||||
|
dequeuedCount = 0;
|
||||||
for (int i = 0; i < mBufferCount; i++) {
|
for (int i = 0; i < mBufferCount; i++) {
|
||||||
if (!mSlots[i].mOwnedByClient && i != mCurrentTexture && i != mLastQueued) {
|
const int state = mSlots[i].mBufferState;
|
||||||
mSlots[i].mOwnedByClient = true;
|
if (state == BufferSlot::DEQUEUED) {
|
||||||
|
dequeuedCount++;
|
||||||
|
}
|
||||||
|
if (state == BufferSlot::FREE || i == mCurrentTexture) {
|
||||||
|
foundSync = i;
|
||||||
|
if (i != mCurrentTexture) {
|
||||||
found = i;
|
found = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// we're in synchronous mode and didn't find a buffer, we need to wait
|
||||||
|
tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
|
||||||
|
if (tryAgain) {
|
||||||
|
mDequeueCondition.wait(mMutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSynchronousMode) {
|
||||||
|
// we're dequeuing more buffers than allowed in synchronous mode
|
||||||
|
if ((mBufferCount - (dequeuedCount+1)) < MIN_UNDEQUEUED_BUFFERS-1)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
if (found == INVALID_BUFFER_SLOT) {
|
||||||
|
// foundSync guaranteed to be != INVALID_BUFFER_SLOT
|
||||||
|
found = foundSync;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (found == INVALID_BUFFER_SLOT) {
|
if (found == INVALID_BUFFER_SLOT) {
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
@ -181,7 +210,11 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
|
|||||||
format = mPixelFormat;
|
format = mPixelFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
|
// buffer is now in DEQUEUED (but can also be current at the same time,
|
||||||
|
// if we're in synchronous mode)
|
||||||
|
mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
|
||||||
|
|
||||||
|
const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
|
||||||
if ((buffer == NULL) ||
|
if ((buffer == NULL) ||
|
||||||
(uint32_t(buffer->width) != w) ||
|
(uint32_t(buffer->width) != w) ||
|
||||||
(uint32_t(buffer->height) != h) ||
|
(uint32_t(buffer->height) != h) ||
|
||||||
@ -199,6 +232,7 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
|
|||||||
mPixelFormat = format;
|
mPixelFormat = format;
|
||||||
}
|
}
|
||||||
mSlots[buf].mGraphicBuffer = graphicBuffer;
|
mSlots[buf].mGraphicBuffer = graphicBuffer;
|
||||||
|
mSlots[buf].mRequestBufferCalled = false;
|
||||||
if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
|
if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
|
||||||
eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage);
|
eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage);
|
||||||
mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
|
mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
|
||||||
@ -209,44 +243,78 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t SurfaceTexture::setSynchronousMode(bool enabled) {
|
||||||
|
Mutex::Autolock lock(mMutex);
|
||||||
|
if (mSynchronousMode != enabled) {
|
||||||
|
mSynchronousMode = enabled;
|
||||||
|
freeAllBuffers();
|
||||||
|
mCurrentTexture = INVALID_BUFFER_SLOT;
|
||||||
|
mQueue.clear();
|
||||||
|
mQueue.reserve(mSynchronousMode ? mBufferCount : 1);
|
||||||
|
mDequeueCondition.signal();
|
||||||
|
}
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) {
|
status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) {
|
||||||
LOGV("SurfaceTexture::queueBuffer");
|
LOGV("SurfaceTexture::queueBuffer");
|
||||||
Mutex::Autolock lock(mMutex);
|
Mutex::Autolock lock(mMutex);
|
||||||
if (buf < 0 || mBufferCount <= buf) {
|
if (buf < 0 || buf >= mBufferCount) {
|
||||||
LOGE("queueBuffer: slot index out of range [0, %d]: %d",
|
LOGE("queueBuffer: slot index out of range [0, %d]: %d",
|
||||||
mBufferCount, buf);
|
mBufferCount, buf);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
} else if (!mSlots[buf].mOwnedByClient) {
|
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
|
||||||
LOGE("queueBuffer: slot %d is not owned by the client", buf);
|
LOGE("queueBuffer: slot %d is not owned by the client (state=%d)",
|
||||||
|
buf, mSlots[buf].mBufferState);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
} else if (mSlots[buf].mGraphicBuffer == 0) {
|
} else if (!mSlots[buf].mRequestBufferCalled) {
|
||||||
LOGE("queueBuffer: slot %d was enqueued without requesting a buffer",
|
LOGE("queueBuffer: slot %d was enqueued without requesting a buffer",
|
||||||
buf);
|
buf);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
mSlots[buf].mOwnedByClient = false;
|
|
||||||
mLastQueued = buf;
|
if (mSynchronousMode) {
|
||||||
mLastQueuedCrop = mNextCrop;
|
// in synchronous mode we queue all buffers in a FIFO
|
||||||
mLastQueuedTransform = mNextTransform;
|
mQueue.push_back(buf);
|
||||||
mLastQueuedTimestamp = timestamp;
|
} else {
|
||||||
|
// in asynchronous mode we only keep the most recent buffer
|
||||||
|
if (mQueue.empty()) {
|
||||||
|
mQueue.push_back(buf);
|
||||||
|
} else {
|
||||||
|
Fifo::iterator front(mQueue.begin());
|
||||||
|
// buffer currently queued is freed
|
||||||
|
mSlots[*front].mBufferState = BufferSlot::FREE;
|
||||||
|
// and we record the new buffer index in the queued list
|
||||||
|
*front = buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mSlots[buf].mBufferState = BufferSlot::QUEUED;
|
||||||
|
mSlots[buf].mLastQueuedCrop = mNextCrop;
|
||||||
|
mSlots[buf].mLastQueuedTransform = mNextTransform;
|
||||||
|
mSlots[buf].mLastQueuedTimestamp = timestamp;
|
||||||
|
|
||||||
if (mFrameAvailableListener != 0) {
|
if (mFrameAvailableListener != 0) {
|
||||||
mFrameAvailableListener->onFrameAvailable();
|
mFrameAvailableListener->onFrameAvailable();
|
||||||
}
|
}
|
||||||
|
mDequeueCondition.signal();
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfaceTexture::cancelBuffer(int buf) {
|
void SurfaceTexture::cancelBuffer(int buf) {
|
||||||
LOGV("SurfaceTexture::cancelBuffer");
|
LOGV("SurfaceTexture::cancelBuffer");
|
||||||
Mutex::Autolock lock(mMutex);
|
Mutex::Autolock lock(mMutex);
|
||||||
if (buf < 0 || mBufferCount <= buf) {
|
if (buf < 0 || buf >= mBufferCount) {
|
||||||
LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount,
|
LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
|
||||||
buf);
|
mBufferCount, buf);
|
||||||
return;
|
return;
|
||||||
} else if (!mSlots[buf].mOwnedByClient) {
|
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
|
||||||
LOGE("cancelBuffer: slot %d is not owned by the client", buf);
|
LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
|
||||||
|
buf, mSlots[buf].mBufferState);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mSlots[buf].mOwnedByClient = false;
|
mSlots[buf].mBufferState = BufferSlot::FREE;
|
||||||
|
mDequeueCondition.signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t SurfaceTexture::setCrop(const Rect& crop) {
|
status_t SurfaceTexture::setCrop(const Rect& crop) {
|
||||||
@ -267,16 +335,25 @@ status_t SurfaceTexture::updateTexImage() {
|
|||||||
LOGV("SurfaceTexture::updateTexImage");
|
LOGV("SurfaceTexture::updateTexImage");
|
||||||
Mutex::Autolock lock(mMutex);
|
Mutex::Autolock lock(mMutex);
|
||||||
|
|
||||||
// Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,
|
int buf = mCurrentTexture;
|
||||||
|
if (!mQueue.empty()) {
|
||||||
|
// in asynchronous mode the list is guaranteed to be one buffer deep,
|
||||||
|
// while in synchronous mode we use the oldest buffer
|
||||||
|
Fifo::iterator front(mQueue.begin());
|
||||||
|
buf = *front;
|
||||||
|
mQueue.erase(front);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initially both mCurrentTexture and buf 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 != buf) {
|
||||||
// Update the GL texture object.
|
// Update the GL texture object.
|
||||||
EGLImageKHR image = mSlots[mLastQueued].mEglImage;
|
EGLImageKHR image = mSlots[buf].mEglImage;
|
||||||
if (image == EGL_NO_IMAGE_KHR) {
|
if (image == EGL_NO_IMAGE_KHR) {
|
||||||
EGLDisplay dpy = eglGetCurrentDisplay();
|
EGLDisplay dpy = eglGetCurrentDisplay();
|
||||||
image = createImage(dpy, mSlots[mLastQueued].mGraphicBuffer);
|
image = createImage(dpy, mSlots[buf].mGraphicBuffer);
|
||||||
mSlots[mLastQueued].mEglImage = image;
|
mSlots[buf].mEglImage = image;
|
||||||
mSlots[mLastQueued].mEglDisplay = dpy;
|
mSlots[buf].mEglDisplay = dpy;
|
||||||
if (image == EGL_NO_IMAGE_KHR) {
|
if (image == EGL_NO_IMAGE_KHR) {
|
||||||
// NOTE: if dpy was invalid, createImage() is guaranteed to
|
// NOTE: if dpy was invalid, createImage() is guaranteed to
|
||||||
// fail. so we'd end up here.
|
// fail. so we'd end up here.
|
||||||
@ -289,8 +366,7 @@ status_t SurfaceTexture::updateTexImage() {
|
|||||||
LOGE("GL error cleared before updating SurfaceTexture: %#04x", error);
|
LOGE("GL error cleared before updating SurfaceTexture: %#04x", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLenum target = getTextureTarget(
|
GLenum target = getTextureTarget(mSlots[buf].mGraphicBuffer->format);
|
||||||
mSlots[mLastQueued].mGraphicBuffer->format);
|
|
||||||
if (target != mCurrentTextureTarget) {
|
if (target != mCurrentTextureTarget) {
|
||||||
glDeleteTextures(1, &mTexName);
|
glDeleteTextures(1, &mTexName);
|
||||||
}
|
}
|
||||||
@ -300,20 +376,29 @@ status_t SurfaceTexture::updateTexImage() {
|
|||||||
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",
|
||||||
image, mLastQueued, error);
|
image, buf, error);
|
||||||
failed = true;
|
failed = true;
|
||||||
}
|
}
|
||||||
if (failed) {
|
if (failed) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mCurrentTexture != INVALID_BUFFER_SLOT) {
|
||||||
|
// the current buffer becomes FREE if it was still in the queued
|
||||||
|
// state. If it has already been given to the client
|
||||||
|
// (synchronous mode), then it stays in DEQUEUED state.
|
||||||
|
if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED)
|
||||||
|
mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE;
|
||||||
|
}
|
||||||
|
|
||||||
// Update the SurfaceTexture state.
|
// Update the SurfaceTexture state.
|
||||||
mCurrentTexture = mLastQueued;
|
mCurrentTexture = buf;
|
||||||
mCurrentTextureTarget = target;
|
mCurrentTextureTarget = target;
|
||||||
mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer;
|
mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
|
||||||
mCurrentCrop = mLastQueuedCrop;
|
mCurrentCrop = mSlots[buf].mLastQueuedCrop;
|
||||||
mCurrentTransform = mLastQueuedTransform;
|
mCurrentTransform = mSlots[buf].mLastQueuedTransform;
|
||||||
mCurrentTimestamp = mLastQueuedTimestamp;
|
mCurrentTimestamp = mSlots[buf].mLastQueuedTimestamp;
|
||||||
|
mDequeueCondition.signal();
|
||||||
} else {
|
} else {
|
||||||
// We always bind the texture even if we don't update its contents.
|
// We always bind the texture even if we don't update its contents.
|
||||||
glBindTexture(mCurrentTextureTarget, mTexName);
|
glBindTexture(mCurrentTextureTarget, mTexName);
|
||||||
@ -469,7 +554,7 @@ sp<IBinder> SurfaceTexture::getAllocator() {
|
|||||||
void SurfaceTexture::freeAllBuffers() {
|
void SurfaceTexture::freeAllBuffers() {
|
||||||
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
|
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
|
||||||
mSlots[i].mGraphicBuffer = 0;
|
mSlots[i].mGraphicBuffer = 0;
|
||||||
mSlots[i].mOwnedByClient = false;
|
mSlots[i].mBufferState = BufferSlot::FREE;
|
||||||
if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
|
if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
|
||||||
eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
|
eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
|
||||||
mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
|
mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
|
||||||
|
Loading…
Reference in New Issue
Block a user