Bug 749678 - 1/5 - Switch GLContext to use mozilla::tls for current context - r=jrmuizel

See comment above class GLContextTLSStorage
This commit is contained in:
Benoit Jacob 2012-05-08 09:47:34 -04:00
parent 802a3dc0cf
commit 1ba7e7e4c1
3 changed files with 96 additions and 33 deletions

View File

@ -64,9 +64,8 @@ using namespace mozilla::gfx;
namespace mozilla {
namespace gl {
#ifdef DEBUG
PRUintn GLContext::sCurrentGLContextTLS = -1;
#endif
tls::key GLContextTLSStorage::sTLSKey;
bool GLContextTLSStorage::sTLSKeyAlreadyCreated = false;
PRUint32 GLContext::sDebugMode = 0;

View File

@ -67,6 +67,7 @@
#include "nsRegion.h"
#include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "thread_helper.h"
typedef char realGLboolean;
@ -509,6 +510,71 @@ struct THEBES_API ContextFormat
int colorBits() const { return red + green + blue; }
};
/*
* This is a helper class to do the little bit of TLS storage that we need
* to allow GLContext to keep track of the current GLContext for a given thread.
*
* This is mostly an optimization to avoid calling MakeCurrent on an
* already-current context,which depending on OpenGL libraries/drivers can be
* very expensive. An earlier optimization consisted in calling
* getCurrentContext to check if the context was already current, but
* even that was shown to be very slow at least on Mac and on Linux NVIDIA,
* see bug 749678.
*
* In a general setting, we would have to do a TLS lookup on every MakeCurrent
* call. But in GLContext, we currently assume that we only ever make GL calls
* on a given GLContext in the same thread that created it (the "owning thread").
* That assumption allows us to avoid doing a TLS lookup on every MakeCurrent
* call. It's checked by assertions in MOZ_GL_DEBUG mode.
*
* The way this works is that inside each GLContext, we store a pointer to the
* TLS pointer to the current context for this thread. This pointer-to-pointer
* (mStorage->mCurrentGLContext) is set during GL context creation: that's where
* we rely on the assumption that all GL calls on a given context are made on
* the same thread that created that context.
*/
class GLContextTLSStorage
{
struct Storage
{
GLContext *mCurrentGLContext;
NS_INLINE_DECL_REFCOUNTING(Storage)
Storage() : mCurrentGLContext(nsnull) {}
};
nsRefPtr<Storage> mStorage;
static tls::key sTLSKey;
static bool sTLSKeyAlreadyCreated;
public:
GLContextTLSStorage() {
if (!sTLSKeyAlreadyCreated) {
tls::create(&sTLSKey);
sTLSKeyAlreadyCreated = true;
}
mStorage = tls::get<Storage>(sTLSKey);
if (!mStorage) {
mStorage = new Storage;
tls::set<Storage>(sTLSKey, mStorage);
}
}
~GLContextTLSStorage() {
}
GLContext *CurrentGLContext() const {
return mStorage->mCurrentGLContext;
}
void SetCurrentGLContext(GLContext *c) {
mStorage->mCurrentGLContext = c;
}
};
class GLContext
: public GLLibraryLoader
{
@ -560,7 +626,7 @@ public:
}
virtual ~GLContext() {
NS_ASSERTION(IsDestroyed(), "GLContext implementation must call MarkDestroyed in destructor!");
NS_ABORT_IF_FALSE(IsDestroyed(), "GLContext implementation must call MarkDestroyed in destructor!");
#ifdef DEBUG
if (mSharedContext) {
GLContext *tip = mSharedContext;
@ -570,6 +636,8 @@ public:
tip->ReportOutstandingNames();
}
#endif
if (this == CurrentGLContext())
SetCurrentGLContext(nsnull);
}
enum ContextFlags {
@ -590,17 +658,18 @@ public:
virtual bool MakeCurrentImpl(bool aForce = false) = 0;
#ifdef DEBUG
static void StaticInit() {
PR_NewThreadPrivateIndex(&sCurrentGLContextTLS, NULL);
}
#endif
bool MakeCurrent(bool aForce = false) {
#ifdef DEBUG
PR_SetThreadPrivate(sCurrentGLContextTLS, this);
#endif
return MakeCurrentImpl(aForce);
if (!aForce &&
this == CurrentGLContext())
{
return true;
}
bool success = MakeCurrentImpl(aForce);
if (success) {
SetCurrentGLContext(this);
}
return success;
}
bool IsContextLost() { return mContextLost; }
@ -1087,6 +1156,16 @@ public:
}
private:
GLContext *CurrentGLContext() const {
return mTLSStorage.CurrentGLContext();
}
void SetCurrentGLContext(GLContext *c) {
mTLSStorage.SetCurrentGLContext(c);
}
bool mOffscreenFBOsDirty;
void GetShaderPrecisionFormatNonES2(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
@ -1612,15 +1691,6 @@ protected:
GLContextSymbols mSymbols;
#ifdef DEBUG
// GLDebugMode will check that we don't send call
// to a GLContext that isn't current on the current
// thread.
// Store the current context when binding to thread local
// storage to support DebugMode on an arbitrary thread.
static PRUintn sCurrentGLContextTLS;
#endif
void UpdateActualFormat();
ContextFormat mActualFormat;
@ -1629,6 +1699,8 @@ protected:
GLuint mOffscreenTexture;
bool mFlipped;
GLContextTLSStorage mTLSStorage;
// lazy-initialized things
GLuint mBlitProgram, mBlitFramebuffer;
void UseBlitProgram();
@ -1805,16 +1877,12 @@ public:
void BeforeGLCall(const char* glFunction) {
if (DebugMode()) {
GLContext *currentGLContext = NULL;
currentGLContext = (GLContext*)PR_GetThreadPrivate(sCurrentGLContextTLS);
if (DebugMode() & DebugTrace)
printf_stderr("[gl:%p] > %s\n", this, glFunction);
if (this != currentGLContext) {
if (this != CurrentGLContext()) {
printf_stderr("Fatal: %s called on non-current context %p. "
"The current context for this thread is %p.\n",
glFunction, this, currentGLContext);
glFunction, this, CurrentGLContext());
NS_ABORT();
}
}

View File

@ -301,10 +301,6 @@ gfxPlatform::Init()
#error "No gfxPlatform implementation available"
#endif
#ifdef DEBUG
mozilla::gl::GLContext::StaticInit();
#endif
nsresult rv;
#if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID) // temporary, until this is implemented on others