Commit c505db2c authored by Joe Drew's avatar Joe Drew
Browse files

Bug 724137 - Support GL debug trace printouts for EGL. r=bjacob

parent 373b9ccd
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -64,6 +64,8 @@ namespace gl {
GLContext* GLContext::sCurrentGLContext = nsnull;
#endif

PRUint32 GLContext::sDebugMode = 0;

// define this here since it's global to GLContextProvider, not any
// specific implementation
const ContextFormat ContextFormat::BasicRGBA32Format(ContextFormat::BasicRGBA32);
@@ -529,16 +531,16 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)

#ifdef DEBUG
    if (PR_GetEnv("MOZ_GL_DEBUG"))
        mDebugMode |= DebugEnabled;
        sDebugMode |= DebugEnabled;

    // enables extra verbose output, informing of the start and finish of every GL call.
    // useful e.g. to record information to investigate graphics system crashes/lockups
    if (PR_GetEnv("MOZ_GL_DEBUG_VERBOSE"))
        mDebugMode |= DebugTrace;
        sDebugMode |= DebugTrace;

    // aborts on GL error. Can be useful to debug quicker code that is known not to generate any GL error in principle.
    if (PR_GetEnv("MOZ_GL_DEBUG_ABORT_ON_ERROR"))
        mDebugMode |= DebugAbortOnError;
        sDebugMode |= DebugAbortOnError;
#endif

    if (mInitialized)
+6 −4
Original line number Diff line number Diff line
@@ -548,7 +548,6 @@ public:
        mContextLost(false),
        mVendor(-1),
        mRenderer(-1),
        mDebugMode(0),
        mCreationFormat(aFormat),
        mSharedContext(aSharedContext),
        mOffscreenTexture(0),
@@ -1434,22 +1433,25 @@ protected:
    PRInt32 mVendor;
    PRInt32 mRenderer;

public:
    enum {
        DebugEnabled = 1 << 0,
        DebugTrace = 1 << 1,
        DebugAbortOnError = 1 << 2
    };

    PRUint32 mDebugMode;
    static PRUint32 sDebugMode;

    inline PRUint32 DebugMode() {
    static PRUint32 DebugMode() {
#ifdef DEBUG
        return mDebugMode;
        return sDebugMode;
#else
        return 0;
#endif
    }

protected:

    ContextFormat mCreationFormat;
    nsRefPtr<GLContext> mSharedContext;

+355 −81
Original line number Diff line number Diff line
@@ -252,6 +252,46 @@ is_power_of_two(int v)
    return (v & (v-1)) == 0;
}

#ifdef DEBUG
#undef BEFORE_GL_CALL
#undef AFTER_GL_CALL

#define BEFORE_GL_CALL do {          \
    BeforeGLCall(MOZ_FUNCTION_NAME); \
} while (0)

#define AFTER_GL_CALL do {           \
    AfterGLCall(MOZ_FUNCTION_NAME);  \
} while (0)

static void BeforeGLCall(const char* glFunction)
{
    if (GLContext::DebugMode()) {
        // since the static member variable sCurrentGLContext is not thread-local as it should,
        // we have to assert that we're in the main thread. Note that sCurrentGLContext is only used
        // for the OpenGL debug mode.
        if (!NS_IsMainThread()) {
            NS_ERROR("OpenGL call from non-main thread. While this is fine in itself, "
                     "the OpenGL debug mode, which is currently enabled, doesn't support this. "
                     "It needs to be patched by making GLContext::sCurrentGLContext be thread-local.\n");
            NS_ABORT();
        }
        if (GLContext::DebugMode() & GLContext::DebugTrace)
            printf_stderr("[egl] > %s\n", glFunction);
    }
}

static void AfterGLCall(const char* glFunction)
{
    if (GLContext::DebugMode() & GLContext::DebugTrace) {
        printf_stderr("[egl] < %s\n", glFunction);
    }
}

// We rely on the fact that GLContext.h #defines BEFORE_GL_CALL and
// AFTER_GL_CALL to nothing if !defined(DEBUG).
#endif

static class EGLLibrary
{
public:
@@ -268,6 +308,7 @@ public:
        mHave_EGL_ANGLE_surface_d3d_texture_2d_share_handle = false;
    }

    struct {
        typedef EGLDisplay (GLAPIENTRY * pfnGetDisplay)(void *display_id);
        pfnGetDisplay fGetDisplay;
        typedef EGLSurface (GLAPIENTRY * pfnGetCurrentSurface)(EGLint);
@@ -342,6 +383,239 @@ public:
        // Lets keep it here for now.
        typedef void (GLAPIENTRY * pfnImageTargetTexture2DOES)(GLenum target, GLeglImageOES image);
        pfnImageTargetTexture2DOES fImageTargetTexture2DOES;
    } mSymbols;

    EGLDisplay fGetDisplay(void* display_id)
    {
        BEFORE_GL_CALL;
        EGLDisplay disp = mSymbols.fGetDisplay(display_id);
        AFTER_GL_CALL;
        return disp;
    }
    EGLSurface fGetCurrentSurface(EGLint id)
    {
        BEFORE_GL_CALL;
        EGLSurface surf = mSymbols.fGetCurrentSurface(id);
        AFTER_GL_CALL;
        return surf;
    }
    EGLContext fGetCurrentContext()
    {
        BEFORE_GL_CALL;
        EGLContext context = mSymbols.fGetCurrentContext();
        AFTER_GL_CALL;
        return context;
    }
    EGLBoolean fMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fMakeCurrent(dpy, draw, read, ctx);
        AFTER_GL_CALL;
        return b;
    }
    EGLBoolean fDestroyContext(EGLDisplay dpy, EGLContext ctx)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fDestroyContext(dpy, ctx);
        AFTER_GL_CALL;
        return b;
    }
    EGLContext fCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
    {
        BEFORE_GL_CALL;
        EGLContext ctx = mSymbols.fCreateContext(dpy, config, share_context, attrib_list);
        AFTER_GL_CALL;
        return ctx;
    }
    EGLBoolean fDestroySurface(EGLDisplay dpy, EGLSurface surface)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fDestroySurface(dpy, surface);
        AFTER_GL_CALL;
        return b;
    }
    EGLSurface fCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
    {
        BEFORE_GL_CALL;
        EGLSurface surf = mSymbols.fCreateWindowSurface(dpy, config, win, attrib_list);
        AFTER_GL_CALL;
        return surf;
    }
    EGLSurface fCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
    {
        BEFORE_GL_CALL;
        EGLSurface surf = mSymbols.fCreatePbufferSurface(dpy, config, attrib_list);
        AFTER_GL_CALL;
        return surf;
    }
    EGLSurface fCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
    {
        BEFORE_GL_CALL;
        EGLSurface surf = mSymbols.fCreatePixmapSurface(dpy, config, pixmap, attrib_list);
        AFTER_GL_CALL;
        return surf;
    }
    EGLBoolean fBindAPI(EGLenum api)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fBindAPI(api);
        AFTER_GL_CALL;
        return b;
    }
    EGLBoolean fInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fInitialize(dpy, major, minor);
        AFTER_GL_CALL;
        return b;
    }
    EGLBoolean fChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fChooseConfig(dpy, attrib_list, configs, config_size, num_config);
        AFTER_GL_CALL;
        return b;
    }
    EGLint fGetError()
    {
        BEFORE_GL_CALL;
        EGLint i = mSymbols.fGetError();
        AFTER_GL_CALL;
        return i;
    }
    EGLBoolean fGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fGetConfigAttrib(dpy, config, attribute, value);
        AFTER_GL_CALL;
        return b;
    }
    EGLBoolean fGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fGetConfigs(dpy, configs, config_size, num_config);
        AFTER_GL_CALL;
        return b;
    }
    EGLBoolean fWaitNative(EGLint engine)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fWaitNative(engine);
        AFTER_GL_CALL;
        return b;
    }
    EGLCastToRelevantPtr fGetProcAddress(const char *procname)
    {
        BEFORE_GL_CALL;
        EGLCastToRelevantPtr p = mSymbols.fGetProcAddress(procname);
        AFTER_GL_CALL;
        return p;
    }
    EGLBoolean fSwapBuffers(EGLDisplay dpy, EGLSurface surface)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fSwapBuffers(dpy, surface);
        AFTER_GL_CALL;
        return b;
    }
    EGLBoolean fCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fCopyBuffers(dpy, surface, target);
        AFTER_GL_CALL;
        return b;
    }
    const GLubyte* fQueryString(EGLDisplay dpy, EGLint name)
    {
        BEFORE_GL_CALL;
        const GLubyte* b = mSymbols.fQueryString(dpy, name);
        AFTER_GL_CALL;
        return b;
    }
    EGLBoolean fQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fQueryContext(dpy, ctx, attribute, value);
        AFTER_GL_CALL;
        return b;
    }
    EGLBoolean fBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fBindTexImage(dpy, surface, buffer);
        AFTER_GL_CALL;
        return b;
    }
    EGLBoolean fReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fReleaseTexImage(dpy, surface, buffer);
        AFTER_GL_CALL;
        return b;
    }
    EGLImageKHR fCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)
    {
         BEFORE_GL_CALL;
         EGLImageKHR i = mSymbols.fCreateImageKHR(dpy, ctx, target, buffer, attrib_list);
         AFTER_GL_CALL;
         return i;
    }
    EGLBoolean fDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fDestroyImageKHR(dpy, image);
        AFTER_GL_CALL;
        return b;
    }
#ifdef MOZ_WIDGET_GONK
    EGLBoolean fSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface surface, EGLint left, EGLint top, EGLint width, EGLint height)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fSetSwapRectangleANDROID(dpy, surface, left, top, width, height);
        AFTER_GL_CALL;
        return b;
    }
#endif

    // New extension which allow us to lock texture and get raw image pointer
    EGLBoolean fLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fLockSurfaceKHR(dpy, surface, attrib_list);
        AFTER_GL_CALL;
        return b;
    }

    EGLBoolean fUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fUnlockSurfaceKHR(dpy, surface);
        AFTER_GL_CALL;
        return b;
    }
    EGLBoolean fQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fQuerySurface(dpy, surface, attribute, value);
        AFTER_GL_CALL;
        return b;
    }
    EGLBoolean fQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value)
    {
        BEFORE_GL_CALL;
        EGLBoolean b = mSymbols.fQuerySurfacePointerANGLE(dpy, surface, attribute, value);
        AFTER_GL_CALL;
        return b;
    }

    // This is EGL specific GL ext symbol "glEGLImageTargetTexture2DOES"
    // Lets keep it here for now.
    void fImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
    {
        BEFORE_GL_CALL;
        mSymbols.fImageTargetTexture2DOES(target, image);
        AFTER_GL_CALL;
    }

    bool EnsureInitialized()
    {
@@ -399,7 +673,7 @@ public:
        }

#define SYMBOL(name) \
    { (PRFuncPtr*) &f##name, { "egl" #name, NULL } }
    { (PRFuncPtr*) &mSymbols.f##name, { "egl" #name, NULL } }

        LibrarySymbolLoader::SymLoadStruct earlySymbols[] = {
            SYMBOL(GetDisplay),
@@ -489,49 +763,49 @@ public:

        if (hasKHRImage) {
            LibrarySymbolLoader::SymLoadStruct khrSymbols[] = {
                { (PRFuncPtr*) &fCreateImageKHR, { "eglCreateImageKHR", NULL } },
                { (PRFuncPtr*) &fDestroyImageKHR, { "eglDestroyImageKHR", NULL } },
                { (PRFuncPtr*) &fImageTargetTexture2DOES, { "glEGLImageTargetTexture2DOES", NULL } },
                { (PRFuncPtr*) &mSymbols.fCreateImageKHR, { "eglCreateImageKHR", NULL } },
                { (PRFuncPtr*) &mSymbols.fDestroyImageKHR, { "eglDestroyImageKHR", NULL } },
                { (PRFuncPtr*) &mSymbols.fImageTargetTexture2DOES, { "glEGLImageTargetTexture2DOES", NULL } },
                { NULL, { NULL } }
            };

            LibrarySymbolLoader::LoadSymbols(mEGLLibrary, &khrSymbols[0],
                                             (LibrarySymbolLoader::PlatformLookupFunction)fGetProcAddress);
                                             (LibrarySymbolLoader::PlatformLookupFunction)mSymbols.fGetProcAddress);
        }

        if (mHave_EGL_KHR_lock_surface) {
            LibrarySymbolLoader::SymLoadStruct lockSymbols[] = {
                { (PRFuncPtr*) &fLockSurfaceKHR, { "eglLockSurfaceKHR", NULL } },
                { (PRFuncPtr*) &fUnlockSurfaceKHR, { "eglUnlockSurfaceKHR", NULL } },
                { (PRFuncPtr*) &mSymbols.fLockSurfaceKHR, { "eglLockSurfaceKHR", NULL } },
                { (PRFuncPtr*) &mSymbols.fUnlockSurfaceKHR, { "eglUnlockSurfaceKHR", NULL } },
                { NULL, { NULL } }
            };

            LibrarySymbolLoader::LoadSymbols(mEGLLibrary, &lockSymbols[0],
                                             (LibrarySymbolLoader::PlatformLookupFunction)fGetProcAddress);
            if (!fLockSurfaceKHR) {
                                             (LibrarySymbolLoader::PlatformLookupFunction)mSymbols.fGetProcAddress);
            if (!mSymbols.fLockSurfaceKHR) {
                mHave_EGL_KHR_lock_surface = false;
            }
        }

        if (!fCreateImageKHR) {
        if (!mSymbols.fCreateImageKHR) {
            mHave_EGL_KHR_image_base = false;
            mHave_EGL_KHR_image_pixmap = false;
            mHave_EGL_KHR_gl_texture_2D_image = false;
        }

        if (!fImageTargetTexture2DOES) {
        if (!mSymbols.fImageTargetTexture2DOES) {
            mHave_EGL_KHR_gl_texture_2D_image = false;
        }

        if (strstr(extensions, "EGL_ANGLE_surface_d3d_texture_2d_share_handle")) {
            LibrarySymbolLoader::SymLoadStruct d3dSymbols[] = {
                { (PRFuncPtr*) &fQuerySurfacePointerANGLE, { "eglQuerySurfacePointerANGLE", NULL } },
                { (PRFuncPtr*) &mSymbols.fQuerySurfacePointerANGLE, { "eglQuerySurfacePointerANGLE", NULL } },
                { NULL, { NULL } }
            };

            LibrarySymbolLoader::LoadSymbols(mEGLLibrary, &d3dSymbols[0],
                                             (LibrarySymbolLoader::PlatformLookupFunction)fGetProcAddress);
            if (fQuerySurfacePointerANGLE) {
                                             (LibrarySymbolLoader::PlatformLookupFunction)mSymbols.fGetProcAddress);
            if (mSymbols.fQuerySurfacePointerANGLE) {
                mHave_EGL_ANGLE_surface_d3d_texture_2d_share_handle = true;
            }
        }
@@ -911,7 +1185,7 @@ public:

    bool SetupLookupFunction()
    {
        mLookupFunc = (PlatformLookupFunction)sEGLLibrary.fGetProcAddress;
        mLookupFunc = (PlatformLookupFunction)sEGLLibrary.mSymbols.fGetProcAddress;
        return true;
    }