EmuGL: don't [de]queue buffers in eglMakeCurrent

Whenever a surface was attached to a context, it was dequeing a new
buffer, and enqueing it when detached. This has the effect of doing a
SwapBuffers on detach/attach cycle, which is just wrong and
occasionally caused visible glitches (e.g. animations going backwards
for one frame). It also broke some SurfaceTexture tests which
(validly) depend on specific buffer production/consumption counts.

Change-Id: Ibd4761e8842871b79fd9edf52272900193cb672d
This commit is contained in:
Jesse Hall
2012-02-24 15:43:16 -08:00
parent cbc7300cb2
commit 7ef79e49c7

View File

@@ -124,8 +124,6 @@ const char * eglStrError(EGLint err)
#define VALIDATE_SURFACE_RETURN(surface, ret) \ #define VALIDATE_SURFACE_RETURN(surface, ret) \
if (surface != EGL_NO_SURFACE) { \ if (surface != EGL_NO_SURFACE) { \
egl_surface_t* s( static_cast<egl_surface_t*>(surface) ); \ egl_surface_t* s( static_cast<egl_surface_t*>(surface) ); \
if (!s->isValid()) \
setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE); \
if (s->dpy != (EGLDisplay)&s_display) \ if (s->dpy != (EGLDisplay)&s_display) \
setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE); \ setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE); \
} }
@@ -175,49 +173,39 @@ struct egl_surface_t {
egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceType); egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceType);
virtual ~egl_surface_t(); virtual ~egl_surface_t();
virtual EGLBoolean rcCreate() = 0;
virtual EGLBoolean rcDestroy() = 0;
virtual EGLBoolean connect() { return EGL_TRUE; }
virtual void disconnect() {}
virtual void setSwapInterval(int interval) = 0; virtual void setSwapInterval(int interval) = 0;
virtual EGLBoolean swapBuffers() { return EGL_TRUE; } virtual EGLBoolean swapBuffers() = 0;
virtual EGLint getSwapBehavior() const;
void setRcSurface(uint32_t handle){ rcSurface = handle; } EGLint getSwapBehavior() const;
uint32_t getRcSurface(){ return rcSurface; } uint32_t getRcSurface() { return rcSurface; }
EGLint getSurfaceType() { return surfaceType; }
virtual EGLBoolean isValid(){ return valid; }
EGLint getSurfaceType(){ return surfaceType; }
void setWidth(EGLint w){ width = w; }
EGLint getWidth(){ return width; } EGLint getWidth(){ return width; }
void setHeight(EGLint h){ height = h; }
EGLint getHeight(){ return height; } EGLint getHeight(){ return height; }
void setTextureFormat(EGLint _texFormat){ texFormat = _texFormat; } void setTextureFormat(EGLint _texFormat) { texFormat = _texFormat; }
EGLint getTextureFormat(){ return texFormat; } EGLint getTextureFormat() { return texFormat; }
void setTextureTarget(EGLint _texTarget){ texTarget = _texTarget; } void setTextureTarget(EGLint _texTarget) { texTarget = _texTarget; }
EGLint getTextureTarget(){ return texTarget; } EGLint getTextureTarget() { return texTarget; }
private: private:
// //
//Surface attributes //Surface attributes
// //
EGLint width; EGLint width;
EGLint height; EGLint height;
EGLint texFormat; EGLint texFormat;
EGLint texTarget; EGLint texTarget;
protected: protected:
EGLint surfaceType; void setWidth(EGLint w) { width = w; }
EGLBoolean valid; void setHeight(EGLint h) { height = h; }
uint32_t rcSurface; //handle to surface created via remote control
EGLint surfaceType;
uint32_t rcSurface; //handle to surface created via remote control
}; };
egl_surface_t::egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceType) egl_surface_t::egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceType)
: dpy(dpy), config(config), surfaceType(surfaceType), valid(EGL_FALSE), rcSurface(0) : dpy(dpy), config(config), surfaceType(surfaceType), rcSurface(0)
{ {
width = 0; width = 0;
height = 0; height = 0;
@@ -226,7 +214,7 @@ egl_surface_t::egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceTyp
} }
EGLint egl_surface_t::getSwapBehavior() const { EGLint egl_surface_t::getSwapBehavior() const {
return EGL_BUFFER_PRESERVED; return EGL_BUFFER_PRESERVED;
} }
egl_surface_t::~egl_surface_t() egl_surface_t::~egl_surface_t()
@@ -237,32 +225,29 @@ egl_surface_t::~egl_surface_t()
// egl_window_surface_t // egl_window_surface_t
struct egl_window_surface_t : public egl_surface_t { struct egl_window_surface_t : public egl_surface_t {
static egl_window_surface_t* create(
egl_window_surface_t(
EGLDisplay dpy, EGLConfig config, EGLint surfType, EGLDisplay dpy, EGLConfig config, EGLint surfType,
ANativeWindow* window); ANativeWindow* window);
~egl_window_surface_t(); virtual ~egl_window_surface_t();
virtual EGLBoolean rcCreate(); virtual void setSwapInterval(int interval);
virtual EGLBoolean rcDestroy(); virtual EGLBoolean swapBuffers();
virtual EGLBoolean connect();
virtual void disconnect();
virtual void setSwapInterval(int interval);
virtual EGLBoolean swapBuffers();
private: private:
ANativeWindow* nativeWindow; egl_window_surface_t(
android_native_buffer_t* buffer; EGLDisplay dpy, EGLConfig config, EGLint surfType,
ANativeWindow* window);
EGLBoolean init();
ANativeWindow* nativeWindow;
android_native_buffer_t* buffer;
}; };
egl_window_surface_t::egl_window_surface_t ( egl_window_surface_t::egl_window_surface_t (
EGLDisplay dpy, EGLConfig config, EGLint surfType, EGLDisplay dpy, EGLConfig config, EGLint surfType,
ANativeWindow* window) ANativeWindow* window)
: egl_surface_t(dpy, config, surfType), : egl_surface_t(dpy, config, surfType),
nativeWindow(window), nativeWindow(window),
buffer(NULL) buffer(NULL)
{ {
@@ -275,58 +260,48 @@ egl_window_surface_t::egl_window_surface_t (
setHeight(h); setHeight(h);
} }
egl_window_surface_t::~egl_window_surface_t() { EGLBoolean egl_window_surface_t::init()
nativeWindow->common.decRef(&nativeWindow->common);
}
EGLBoolean egl_window_surface_t::rcCreate()
{ {
if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) {
setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE);
}
nativeWindow->lockBuffer(nativeWindow, buffer);
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uint32_t)config, getWidth(), getHeight()); rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uint32_t)config,
getWidth(), getHeight());
if (!rcSurface) { if (!rcSurface) {
LOGE("rcCreateWindowSurface returned 0"); LOGE("rcCreateWindowSurface returned 0");
return EGL_FALSE; return EGL_FALSE;
} }
valid = EGL_TRUE; rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface,
((cb_handle_t*)(buffer->handle))->hostHandle);
return EGL_TRUE; return EGL_TRUE;
} }
EGLBoolean egl_window_surface_t::rcDestroy() egl_window_surface_t* egl_window_surface_t::create(
EGLDisplay dpy, EGLConfig config, EGLint surfType,
ANativeWindow* window)
{ {
if (!rcSurface) { egl_window_surface_t* wnd = new egl_window_surface_t(
LOGE("rcDestroy called on invalid rcSurface"); dpy, config, surfType, window);
return EGL_FALSE; if (wnd && !wnd->init()) {
delete wnd;
wnd = NULL;
} }
return wnd;
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface);
rcSurface = 0;
return EGL_TRUE;
} }
EGLBoolean egl_window_surface_t::connect() egl_window_surface_t::~egl_window_surface_t() {
{ DEFINE_HOST_CONNECTION;
// dequeue a buffer if (rcSurface && rcEnc) {
if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) { rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface);
setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE);
} }
// lock the buffer
nativeWindow->lockBuffer(nativeWindow, buffer);
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, ((cb_handle_t *)(buffer->handle))->hostHandle);
return EGL_TRUE;
}
void egl_window_surface_t::disconnect()
{
if (buffer) { if (buffer) {
nativeWindow->queueBuffer(nativeWindow, buffer); nativeWindow->cancelBuffer(nativeWindow, buffer);
buffer = 0;
} }
nativeWindow->common.decRef(&nativeWindow->common);
} }
void egl_window_surface_t::setSwapInterval(int interval) void egl_window_surface_t::setSwapInterval(int interval)
@@ -336,26 +311,19 @@ void egl_window_surface_t::setSwapInterval(int interval)
EGLBoolean egl_window_surface_t::swapBuffers() EGLBoolean egl_window_surface_t::swapBuffers()
{ {
if (!buffer) {
setErrorReturn(EGL_BAD_ACCESS, EGL_FALSE);
}
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
rcEnc->rcFlushWindowColorBuffer(rcEnc, rcSurface); rcEnc->rcFlushWindowColorBuffer(rcEnc, rcSurface);
//post the back buffer
nativeWindow->queueBuffer(nativeWindow, buffer); nativeWindow->queueBuffer(nativeWindow, buffer);
// dequeue a new buffer
if (nativeWindow->dequeueBuffer(nativeWindow, &buffer)) { if (nativeWindow->dequeueBuffer(nativeWindow, &buffer)) {
buffer = NULL;
setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE); setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE);
} }
// lock the buffer
nativeWindow->lockBuffer(nativeWindow, buffer); nativeWindow->lockBuffer(nativeWindow, buffer);
rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, ((cb_handle_t *)(buffer->handle))->hostHandle); rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface,
((cb_handle_t *)(buffer->handle))->hostHandle);
return EGL_TRUE; return EGL_TRUE;
} }
@@ -364,30 +332,28 @@ EGLBoolean egl_window_surface_t::swapBuffers()
//egl_pbuffer_surface_t //egl_pbuffer_surface_t
struct egl_pbuffer_surface_t : public egl_surface_t { struct egl_pbuffer_surface_t : public egl_surface_t {
static egl_pbuffer_surface_t* create(EGLDisplay dpy, EGLConfig config,
GLenum format; EGLint surfType, int32_t w, int32_t h, GLenum pixelFormat);
egl_pbuffer_surface_t(
EGLDisplay dpy, EGLConfig config, EGLint surfType,
int32_t w, int32_t h, GLenum format);
virtual ~egl_pbuffer_surface_t(); virtual ~egl_pbuffer_surface_t();
virtual EGLBoolean rcCreate();
virtual EGLBoolean rcDestroy();
virtual EGLBoolean connect(); virtual void setSwapInterval(int interval) {}
virtual void setSwapInterval(int interval) {} virtual EGLBoolean swapBuffers() { return EGL_TRUE; }
uint32_t getRcColorBuffer() { return rcColorBuffer; }
uint32_t getRcColorBuffer(){ return rcColorBuffer; }
void setRcColorBuffer(uint32_t colorBuffer){ rcColorBuffer = colorBuffer; }
private: private:
egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfType,
int32_t w, int32_t h);
EGLBoolean init(GLenum format);
uint32_t rcColorBuffer; uint32_t rcColorBuffer;
}; };
egl_pbuffer_surface_t::egl_pbuffer_surface_t( egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config,
EGLDisplay dpy, EGLConfig config, EGLint surfType, EGLint surfType, int32_t w, int32_t h)
int32_t w, int32_t h, GLenum pixelFormat) : egl_surface_t(dpy, config, surfType),
: egl_surface_t(dpy, config, surfType), format(pixelFormat) rcColorBuffer(0)
{ {
setWidth(w); setWidth(w);
setHeight(h); setHeight(h);
@@ -395,50 +361,49 @@ egl_pbuffer_surface_t::egl_pbuffer_surface_t(
egl_pbuffer_surface_t::~egl_pbuffer_surface_t() egl_pbuffer_surface_t::~egl_pbuffer_surface_t()
{ {
rcColorBuffer = 0; DEFINE_HOST_CONNECTION;
if (rcEnc) {
if (rcColorBuffer) rcEnc->rcCloseColorBuffer(rcEnc, rcColorBuffer);
if (rcSurface) rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface);
}
} }
EGLBoolean egl_pbuffer_surface_t::rcCreate() EGLBoolean egl_pbuffer_surface_t::init(GLenum pixelFormat)
{ {
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uint32_t)config, getWidth(), getHeight());
rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uint32_t)config,
getWidth(), getHeight());
if (!rcSurface) { if (!rcSurface) {
LOGE("rcCreateWindowSurface returned 0"); LOGE("rcCreateWindowSurface returned 0");
return EGL_FALSE; return EGL_FALSE;
} }
rcColorBuffer = rcEnc->rcCreateColorBuffer(rcEnc, getWidth(), getHeight(), format);
rcColorBuffer = rcEnc->rcCreateColorBuffer(rcEnc, getWidth(), getHeight(),
pixelFormat);
if (!rcColorBuffer) { if (!rcColorBuffer) {
LOGE("rcCreateColorBuffer returned 0"); LOGE("rcCreateColorBuffer returned 0");
return EGL_FALSE; return EGL_FALSE;
} }
valid = EGL_TRUE;
return EGL_TRUE;
}
EGLBoolean egl_pbuffer_surface_t::rcDestroy()
{
if ((!rcSurface)||(!rcColorBuffer)) {
LOGE("destroyRc called on invalid rcSurface");
return EGL_FALSE;
}
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface);
rcEnc->rcCloseColorBuffer(rcEnc, rcColorBuffer);
rcSurface = 0;
return EGL_TRUE;
}
EGLBoolean egl_pbuffer_surface_t::connect()
{
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, rcColorBuffer); rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, rcColorBuffer);
return EGL_TRUE; return EGL_TRUE;
} }
egl_pbuffer_surface_t* egl_pbuffer_surface_t::create(EGLDisplay dpy,
EGLConfig config, EGLint surfType, int32_t w, int32_t h,
GLenum pixelFormat)
{
egl_pbuffer_surface_t* pb = new egl_pbuffer_surface_t(dpy, config, surfType,
w, h);
if (pb && !pb->init(pixelFormat)) {
delete pb;
pb = NULL;
}
return pb;
}
static const char *getGLString(int glEnum) static const char *getGLString(int glEnum)
{ {
EGLThreadInfo *tInfo = getEGLThreadInfo(); EGLThreadInfo *tInfo = getEGLThreadInfo();
@@ -661,12 +626,9 @@ EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWin
setErrorReturn(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); setErrorReturn(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
} }
egl_surface_t* surface; egl_surface_t* surface = egl_window_surface_t::create(
surface = new egl_window_surface_t(&s_display, config, surfaceType, static_cast<ANativeWindow*>(win)); &s_display, config, surfaceType, static_cast<ANativeWindow*>(win));
if (!surface) if (!surface) {
setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE);
if (!surface->rcCreate()) {
delete surface;
setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE); setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE);
} }
@@ -718,11 +680,9 @@ EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLin
if (s_display.getConfigGLPixelFormat(config, &pixelFormat) == EGL_FALSE) if (s_display.getConfigGLPixelFormat(config, &pixelFormat) == EGL_FALSE)
setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE); setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
egl_surface_t* surface = new egl_pbuffer_surface_t(dpy, config, surfaceType, w, h, pixelFormat); egl_surface_t* surface = egl_pbuffer_surface_t::create(dpy, config,
if (!surface) surfaceType, w, h, pixelFormat);
setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE); if (!surface) {
if (!surface->rcCreate()) {
delete surface;
setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE); setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE);
} }
@@ -748,10 +708,7 @@ EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE); VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE); VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE);
egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) ); egl_surface_t* surface(static_cast<egl_surface_t*>(eglSurface));
surface->disconnect();
surface->rcDestroy();
delete surface; delete surface;
return EGL_TRUE; return EGL_TRUE;
@@ -995,14 +952,6 @@ EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLC
setErrorReturn(EGL_BAD_CONTEXT, EGL_FALSE); setErrorReturn(EGL_BAD_CONTEXT, EGL_FALSE);
} }
//
// Disconnect from the previous drawable
//
if (tInfo->currentContext && tInfo->currentContext->draw) {
egl_surface_t * prevDrawSurf = static_cast<egl_surface_t *>(tInfo->currentContext->draw);
prevDrawSurf->disconnect();
}
//Now make the local bind //Now make the local bind
if (context) { if (context) {
context->draw = draw; context->draw = draw;
@@ -1055,10 +1004,6 @@ EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLC
} }
} }
//connect the color buffer
if (drawSurf)
drawSurf->connect();
return EGL_TRUE; return EGL_TRUE;
} }
@@ -1156,8 +1101,6 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface eglSurface)
DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE); DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
egl_surface_t* d = static_cast<egl_surface_t*>(eglSurface); egl_surface_t* d = static_cast<egl_surface_t*>(eglSurface);
if (!d->isValid())
setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
if (d->dpy != dpy) if (d->dpy != dpy)
setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE); setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE);