Merge "Fix deadlock when cleaning objects in eglTerminate"
This commit is contained in:
commit
aa1667f006
@ -70,8 +70,7 @@ extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
|
|||||||
egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
|
egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
|
||||||
|
|
||||||
egl_display_t::egl_display_t() :
|
egl_display_t::egl_display_t() :
|
||||||
magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0),
|
magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0) {
|
||||||
mWakeCount(0), mHibernating(false), mAttemptHibernation(false) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
egl_display_t::~egl_display_t() {
|
egl_display_t::~egl_display_t() {
|
||||||
@ -253,6 +252,9 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {
|
|||||||
*major = VERSION_MAJOR;
|
*major = VERSION_MAJOR;
|
||||||
if (minor != NULL)
|
if (minor != NULL)
|
||||||
*minor = VERSION_MINOR;
|
*minor = VERSION_MINOR;
|
||||||
|
|
||||||
|
mHibernation.setDisplayValid(true);
|
||||||
|
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,6 +284,8 @@ EGLBoolean egl_display_t::terminate() {
|
|||||||
res = EGL_TRUE;
|
res = EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mHibernation.setDisplayValid(false);
|
||||||
|
|
||||||
// Mark all objects remaining in the list as terminated, unless
|
// Mark all objects remaining in the list as terminated, unless
|
||||||
// there are no reference to them, it which case, we're free to
|
// there are no reference to them, it which case, we're free to
|
||||||
// delete them.
|
// delete them.
|
||||||
@ -351,8 +355,7 @@ EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
|
|||||||
if (result == EGL_TRUE) {
|
if (result == EGL_TRUE) {
|
||||||
c->onMakeCurrent(draw, read);
|
c->onMakeCurrent(draw, read);
|
||||||
if (!cur_c) {
|
if (!cur_c) {
|
||||||
mWakeCount++;
|
mHibernation.incWakeCount(HibernationMachine::STRONG);
|
||||||
mAttemptHibernation = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -360,8 +363,7 @@ EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
|
|||||||
disp.dpy, impl_draw, impl_read, impl_ctx);
|
disp.dpy, impl_draw, impl_read, impl_ctx);
|
||||||
if (result == EGL_TRUE) {
|
if (result == EGL_TRUE) {
|
||||||
cur_c->onLooseCurrent();
|
cur_c->onLooseCurrent();
|
||||||
mWakeCount--;
|
mHibernation.decWakeCount(HibernationMachine::STRONG);
|
||||||
mAttemptHibernation = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,14 +380,26 @@ EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool egl_display_t::enter() {
|
// ----------------------------------------------------------------------------
|
||||||
Mutex::Autolock _l(lock);
|
|
||||||
|
bool egl_display_t::HibernationMachine::incWakeCount(WakeRefStrength strength) {
|
||||||
|
Mutex::Autolock _l(mLock);
|
||||||
ALOGE_IF(mWakeCount < 0 || mWakeCount == INT32_MAX,
|
ALOGE_IF(mWakeCount < 0 || mWakeCount == INT32_MAX,
|
||||||
"Invalid WakeCount (%d) on enter\n", mWakeCount);
|
"Invalid WakeCount (%d) on enter\n", mWakeCount);
|
||||||
|
|
||||||
mWakeCount++;
|
mWakeCount++;
|
||||||
|
if (strength == STRONG)
|
||||||
|
mAttemptHibernation = false;
|
||||||
|
|
||||||
if (CC_UNLIKELY(mHibernating)) {
|
if (CC_UNLIKELY(mHibernating)) {
|
||||||
ALOGV("Awakening\n");
|
ALOGV("Awakening\n");
|
||||||
egl_connection_t* const cnx = &gEGLImpl;
|
egl_connection_t* const cnx = &gEGLImpl;
|
||||||
|
|
||||||
|
// These conditions should be guaranteed before entering hibernation;
|
||||||
|
// we don't want to get into a state where we can't wake up.
|
||||||
|
ALOGD_IF(!mDpyValid || !cnx->egl.eglAwakenProcessIMG,
|
||||||
|
"Invalid hibernation state, unable to awaken\n");
|
||||||
|
|
||||||
if (!cnx->egl.eglAwakenProcessIMG()) {
|
if (!cnx->egl.eglAwakenProcessIMG()) {
|
||||||
ALOGE("Failed to awaken EGL implementation\n");
|
ALOGE("Failed to awaken EGL implementation\n");
|
||||||
return false;
|
return false;
|
||||||
@ -395,13 +409,20 @@ bool egl_display_t::enter() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void egl_display_t::leave() {
|
void egl_display_t::HibernationMachine::decWakeCount(WakeRefStrength strength) {
|
||||||
Mutex::Autolock _l(lock);
|
Mutex::Autolock _l(mLock);
|
||||||
ALOGE_IF(mWakeCount <= 0, "Invalid WakeCount (%d) on leave\n", mWakeCount);
|
ALOGE_IF(mWakeCount <= 0, "Invalid WakeCount (%d) on leave\n", mWakeCount);
|
||||||
if (--mWakeCount == 0 && CC_UNLIKELY(mAttemptHibernation)) {
|
|
||||||
|
mWakeCount--;
|
||||||
|
if (strength == STRONG)
|
||||||
|
mAttemptHibernation = true;
|
||||||
|
|
||||||
|
if (mWakeCount == 0 && CC_UNLIKELY(mAttemptHibernation)) {
|
||||||
egl_connection_t* const cnx = &gEGLImpl;
|
egl_connection_t* const cnx = &gEGLImpl;
|
||||||
mAttemptHibernation = false;
|
mAttemptHibernation = false;
|
||||||
if (cnx->egl.eglHibernateProcessIMG && cnx->egl.eglAwakenProcessIMG) {
|
if (mDpyValid &&
|
||||||
|
cnx->egl.eglHibernateProcessIMG &&
|
||||||
|
cnx->egl.eglAwakenProcessIMG) {
|
||||||
ALOGV("Hibernating\n");
|
ALOGV("Hibernating\n");
|
||||||
if (!cnx->egl.eglHibernateProcessIMG()) {
|
if (!cnx->egl.eglHibernateProcessIMG()) {
|
||||||
ALOGE("Failed to hibernate EGL implementation\n");
|
ALOGE("Failed to hibernate EGL implementation\n");
|
||||||
@ -412,16 +433,9 @@ void egl_display_t::leave() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void egl_display_t::onWindowSurfaceCreated() {
|
void egl_display_t::HibernationMachine::setDisplayValid(bool valid) {
|
||||||
Mutex::Autolock _l(lock);
|
Mutex::Autolock _l(mLock);
|
||||||
mWakeCount++;
|
mDpyValid = valid;
|
||||||
mAttemptHibernation = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void egl_display_t::onWindowSurfaceDestroyed() {
|
|
||||||
Mutex::Autolock _l(lock);
|
|
||||||
mWakeCount--;
|
|
||||||
mAttemptHibernation = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -77,8 +77,12 @@ public:
|
|||||||
// proper hibernate/wakeup sequencing. If a surface destruction triggers
|
// proper hibernate/wakeup sequencing. If a surface destruction triggers
|
||||||
// hibernation, hibernation will be delayed at least until the calling
|
// hibernation, hibernation will be delayed at least until the calling
|
||||||
// thread's egl_display_ptr is destroyed.
|
// thread's egl_display_ptr is destroyed.
|
||||||
void onWindowSurfaceCreated();
|
void onWindowSurfaceCreated() {
|
||||||
void onWindowSurfaceDestroyed();
|
mHibernation.incWakeCount(HibernationMachine::STRONG);
|
||||||
|
}
|
||||||
|
void onWindowSurfaceDestroyed() {
|
||||||
|
mHibernation.decWakeCount(HibernationMachine::STRONG);
|
||||||
|
}
|
||||||
|
|
||||||
static egl_display_t* get(EGLDisplay dpy);
|
static egl_display_t* get(EGLDisplay dpy);
|
||||||
static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp);
|
static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp);
|
||||||
@ -123,8 +127,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
friend class egl_display_ptr;
|
friend class egl_display_ptr;
|
||||||
bool enter();
|
bool enter() { return mHibernation.incWakeCount(HibernationMachine::WEAK); }
|
||||||
void leave();
|
void leave() { return mHibernation.decWakeCount(HibernationMachine::WEAK); }
|
||||||
|
|
||||||
uint32_t refs;
|
uint32_t refs;
|
||||||
mutable Mutex lock;
|
mutable Mutex lock;
|
||||||
@ -133,9 +137,41 @@ private:
|
|||||||
String8 mVersionString;
|
String8 mVersionString;
|
||||||
String8 mClientApiString;
|
String8 mClientApiString;
|
||||||
String8 mExtensionString;
|
String8 mExtensionString;
|
||||||
int32_t mWakeCount;
|
|
||||||
bool mHibernating;
|
// HibernationMachine uses its own internal mutex to protect its own data.
|
||||||
bool mAttemptHibernation;
|
// The owning egl_display_t's lock may be but is not required to be held
|
||||||
|
// when calling HibernationMachine methods. As a result, nothing in this
|
||||||
|
// class may call back up to egl_display_t directly or indirectly.
|
||||||
|
class HibernationMachine {
|
||||||
|
public:
|
||||||
|
// STRONG refs cancel (inc) or initiate (dec) a hibernation attempt
|
||||||
|
// the next time the wakecount reaches zero. WEAK refs don't affect
|
||||||
|
// whether a hibernation attempt will be made. Use STRONG refs only
|
||||||
|
// for infrequent/heavy changes that are likely to indicate the
|
||||||
|
// EGLDisplay is entering or leaving a long-term idle state.
|
||||||
|
enum WakeRefStrength {
|
||||||
|
WEAK = 0,
|
||||||
|
STRONG = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
HibernationMachine(): mWakeCount(0), mHibernating(false),
|
||||||
|
mAttemptHibernation(false), mDpyValid(false)
|
||||||
|
{}
|
||||||
|
~HibernationMachine() {}
|
||||||
|
|
||||||
|
bool incWakeCount(WakeRefStrength strenth);
|
||||||
|
void decWakeCount(WakeRefStrength strenth);
|
||||||
|
|
||||||
|
void setDisplayValid(bool valid);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Mutex mLock;
|
||||||
|
int32_t mWakeCount;
|
||||||
|
bool mHibernating;
|
||||||
|
bool mAttemptHibernation;
|
||||||
|
bool mDpyValid;
|
||||||
|
};
|
||||||
|
HibernationMachine mHibernation;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
Loading…
Reference in New Issue
Block a user