Merge "libgui: have ST::updateTexImage check the GL ctx"
This commit is contained in:
commit
de3b072b12
@ -260,7 +260,6 @@ private:
|
||||
struct EGLSlot {
|
||||
EGLSlot()
|
||||
: mEglImage(EGL_NO_IMAGE_KHR),
|
||||
mEglDisplay(EGL_NO_DISPLAY),
|
||||
mFence(EGL_NO_SYNC_KHR) {
|
||||
}
|
||||
|
||||
@ -269,9 +268,6 @@ private:
|
||||
// mEglImage is the EGLImage created from mGraphicBuffer.
|
||||
EGLImageKHR mEglImage;
|
||||
|
||||
// mEglDisplay is the EGLDisplay used to create mEglImage.
|
||||
EGLDisplay mEglDisplay;
|
||||
|
||||
// mFence is the EGL sync object that must signal before the buffer
|
||||
// associated with this buffer slot may be dequeued. It is initialized
|
||||
// to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
|
||||
@ -279,6 +275,17 @@ private:
|
||||
EGLSyncKHR mFence;
|
||||
};
|
||||
|
||||
// mEglDisplay is the EGLDisplay with which this SurfaceTexture is currently
|
||||
// associated. It is intialized to EGL_NO_DISPLAY and gets set to the
|
||||
// current display when updateTexImage is called for the first time.
|
||||
EGLDisplay mEglDisplay;
|
||||
|
||||
// mEglContext is the OpenGL ES context with which this SurfaceTexture is
|
||||
// currently associated. It is initialized to EGL_NO_CONTEXT and gets set
|
||||
// to the current GL context when updateTexImage is called for the first
|
||||
// time.
|
||||
EGLContext mEglContext;
|
||||
|
||||
// mEGLSlots stores the buffers that have been allocated by the BufferQueue
|
||||
// for each buffer slot. It is initialized to null pointers, and gets
|
||||
// filled in with the result of BufferQueue::acquire when the
|
||||
|
@ -115,6 +115,8 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
|
||||
mUseFenceSync(false),
|
||||
#endif
|
||||
mTexTarget(texTarget),
|
||||
mEglDisplay(EGL_NO_DISPLAY),
|
||||
mEglContext(EGL_NO_CONTEXT),
|
||||
mAbandoned(false),
|
||||
mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT)
|
||||
{
|
||||
@ -178,6 +180,22 @@ status_t SurfaceTexture::updateTexImage() {
|
||||
return NO_INIT;
|
||||
}
|
||||
|
||||
EGLDisplay dpy = eglGetCurrentDisplay();
|
||||
EGLContext ctx = eglGetCurrentContext();
|
||||
|
||||
if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) {
|
||||
ST_LOGE("updateTexImage: invalid current EGLDisplay");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) {
|
||||
ST_LOGE("updateTexImage: invalid current EGLContext");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mEglDisplay = dpy;
|
||||
mEglContext = ctx;
|
||||
|
||||
BufferQueue::BufferItem item;
|
||||
|
||||
// In asynchronous mode the list is guaranteed to be one buffer
|
||||
@ -188,17 +206,14 @@ status_t SurfaceTexture::updateTexImage() {
|
||||
if (item.mGraphicBuffer != NULL) {
|
||||
mEGLSlots[buf].mGraphicBuffer = 0;
|
||||
if (mEGLSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
|
||||
eglDestroyImageKHR(mEGLSlots[buf].mEglDisplay,
|
||||
mEGLSlots[buf].mEglImage);
|
||||
eglDestroyImageKHR(dpy, mEGLSlots[buf].mEglImage);
|
||||
mEGLSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
|
||||
mEGLSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
|
||||
}
|
||||
mEGLSlots[buf].mGraphicBuffer = item.mGraphicBuffer;
|
||||
}
|
||||
|
||||
// Update the GL texture object.
|
||||
EGLImageKHR image = mEGLSlots[buf].mEglImage;
|
||||
EGLDisplay dpy = eglGetCurrentDisplay();
|
||||
if (image == EGL_NO_IMAGE_KHR) {
|
||||
if (item.mGraphicBuffer == 0) {
|
||||
ST_LOGE("buffer at slot %d is null", buf);
|
||||
@ -206,7 +221,6 @@ status_t SurfaceTexture::updateTexImage() {
|
||||
}
|
||||
image = createImage(dpy, item.mGraphicBuffer);
|
||||
mEGLSlots[buf].mEglImage = image;
|
||||
mEGLSlots[buf].mEglDisplay = dpy;
|
||||
if (image == EGL_NO_IMAGE_KHR) {
|
||||
// NOTE: if dpy was invalid, createImage() is guaranteed to
|
||||
// fail. so we'd end up here.
|
||||
@ -229,8 +243,7 @@ status_t SurfaceTexture::updateTexImage() {
|
||||
failed = true;
|
||||
}
|
||||
if (failed) {
|
||||
mBufferQueue->releaseBuffer(buf, mEGLSlots[buf].mEglDisplay,
|
||||
mEGLSlots[buf].mFence);
|
||||
mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -241,7 +254,7 @@ status_t SurfaceTexture::updateTexImage() {
|
||||
if (fence == EGL_NO_SYNC_KHR) {
|
||||
ALOGE("updateTexImage: error creating fence: %#x",
|
||||
eglGetError());
|
||||
mBufferQueue->releaseBuffer(buf, mEGLSlots[buf].mEglDisplay,
|
||||
mBufferQueue->releaseBuffer(buf, dpy,
|
||||
mEGLSlots[buf].mFence);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -256,8 +269,7 @@ status_t SurfaceTexture::updateTexImage() {
|
||||
buf, item.mGraphicBuffer != NULL ? item.mGraphicBuffer->handle : 0);
|
||||
|
||||
// release old buffer
|
||||
mBufferQueue->releaseBuffer(mCurrentTexture,
|
||||
mEGLSlots[mCurrentTexture].mEglDisplay,
|
||||
mBufferQueue->releaseBuffer(mCurrentTexture, dpy,
|
||||
mEGLSlots[mCurrentTexture].mFence);
|
||||
|
||||
// Update the SurfaceTexture state.
|
||||
@ -459,10 +471,9 @@ void SurfaceTexture::freeBufferLocked(int slotIndex) {
|
||||
if (mEGLSlots[slotIndex].mEglImage != EGL_NO_IMAGE_KHR) {
|
||||
EGLImageKHR img = mEGLSlots[slotIndex].mEglImage;
|
||||
if (img != EGL_NO_IMAGE_KHR) {
|
||||
eglDestroyImageKHR(mEGLSlots[slotIndex].mEglDisplay, img);
|
||||
eglDestroyImageKHR(mEglDisplay, img);
|
||||
}
|
||||
mEGLSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
|
||||
mEGLSlots[slotIndex].mEglDisplay = EGL_NO_DISPLAY;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -560,6 +560,27 @@ void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r,
|
||||
}
|
||||
}
|
||||
|
||||
// Produce a single RGBA8 frame by filling a buffer with a checkerboard pattern
|
||||
// using the CPU. This assumes that the ANativeWindow is already configured to
|
||||
// allow this to be done (e.g. the format is set to RGBA8).
|
||||
//
|
||||
// Calls to this function should be wrapped in an ASSERT_NO_FATAL_FAILURE().
|
||||
void produceOneRGBA8Frame(const sp<ANativeWindow>& anw) {
|
||||
android_native_buffer_t* anb;
|
||||
ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &anb));
|
||||
ASSERT_TRUE(anb != NULL);
|
||||
|
||||
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
|
||||
ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf->getNativeBuffer()));
|
||||
|
||||
uint8_t* img = NULL;
|
||||
ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
|
||||
(void**)(&img)));
|
||||
fillRGBA8Buffer(img, buf->getWidth(), buf->getHeight(), buf->getStride());
|
||||
ASSERT_EQ(NO_ERROR, buf->unlock());
|
||||
ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf->getNativeBuffer()));
|
||||
}
|
||||
|
||||
TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
|
||||
const int texWidth = 64;
|
||||
const int texHeight = 66;
|
||||
@ -873,19 +894,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferNpot) {
|
||||
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
|
||||
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
|
||||
|
||||
android_native_buffer_t* anb;
|
||||
ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
|
||||
ASSERT_TRUE(anb != NULL);
|
||||
|
||||
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
|
||||
ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
|
||||
|
||||
// Fill the buffer with the a checkerboard pattern
|
||||
uint8_t* img = NULL;
|
||||
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
|
||||
fillRGBA8Buffer(img, texWidth, texHeight, buf->getStride());
|
||||
buf->unlock();
|
||||
ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
|
||||
ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
|
||||
|
||||
mST->updateTexImage();
|
||||
|
||||
@ -927,19 +936,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) {
|
||||
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
|
||||
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
|
||||
|
||||
android_native_buffer_t* anb;
|
||||
ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
|
||||
ASSERT_TRUE(anb != NULL);
|
||||
|
||||
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
|
||||
ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
|
||||
|
||||
// Fill the buffer with the a checkerboard pattern
|
||||
uint8_t* img = NULL;
|
||||
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
|
||||
fillRGBA8Buffer(img, texWidth, texHeight, buf->getStride());
|
||||
buf->unlock();
|
||||
ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
|
||||
ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
|
||||
|
||||
mST->updateTexImage();
|
||||
|
||||
@ -1095,18 +1092,12 @@ protected:
|
||||
virtual void SetUp() {
|
||||
SurfaceTextureGLTest::SetUp();
|
||||
|
||||
EGLConfig myConfig = {0};
|
||||
EGLint numConfigs = 0;
|
||||
EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
|
||||
1, &numConfigs));
|
||||
ASSERT_EQ(EGL_SUCCESS, eglGetError());
|
||||
|
||||
mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
|
||||
mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
|
||||
mANW.get(), NULL);
|
||||
ASSERT_EQ(EGL_SUCCESS, eglGetError());
|
||||
ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
|
||||
|
||||
mProducerEglContext = eglCreateContext(mEglDisplay, myConfig,
|
||||
mProducerEglContext = eglCreateContext(mEglDisplay, mGlConfig,
|
||||
EGL_NO_CONTEXT, getContextAttribs());
|
||||
ASSERT_EQ(EGL_SUCCESS, eglGetError());
|
||||
ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext);
|
||||
@ -1742,4 +1733,45 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
|
||||
EXPECT_TRUE(checkPixel( 24, 39, 0, 255, 0, 255));
|
||||
}
|
||||
|
||||
class SurfaceTextureMultiContextGLTest : public SurfaceTextureGLTest {
|
||||
protected:
|
||||
SurfaceTextureMultiContextGLTest():
|
||||
mSecondEglContext(EGL_NO_CONTEXT) {
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
SurfaceTextureGLTest::SetUp();
|
||||
|
||||
mSecondEglContext = eglCreateContext(mEglDisplay, mGlConfig,
|
||||
EGL_NO_CONTEXT, getContextAttribs());
|
||||
ASSERT_EQ(EGL_SUCCESS, eglGetError());
|
||||
ASSERT_NE(EGL_NO_CONTEXT, mSecondEglContext);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
if (mSecondEglContext != EGL_NO_CONTEXT) {
|
||||
eglDestroyContext(mEglDisplay, mSecondEglContext);
|
||||
}
|
||||
SurfaceTextureGLTest::TearDown();
|
||||
}
|
||||
|
||||
EGLContext mSecondEglContext;
|
||||
};
|
||||
|
||||
TEST_F(SurfaceTextureMultiContextGLTest, UpdateFromMultipleContextsFails) {
|
||||
sp<FrameWaiter> fw(new FrameWaiter);
|
||||
mST->setFrameAvailableListener(fw);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
|
||||
|
||||
// Latch the texture contents on the primary context.
|
||||
mST->updateTexImage();
|
||||
|
||||
// Attempt to latch the texture on the secondary context.
|
||||
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
|
||||
mSecondEglContext));
|
||||
ASSERT_EQ(EGL_SUCCESS, eglGetError());
|
||||
ASSERT_EQ(-EINVAL, mST->updateTexImage());
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
Loading…
Reference in New Issue
Block a user