add_library (wgltrace MODULE opengl32.def
wgltrace.cpp
glcaps.cpp
+ gltrace_state.cpp
)
add_dependencies (wgltrace glproc)
target_link_libraries (wgltrace
add_library (cgltrace SHARED
cgltrace.cpp
glcaps.cpp
+ gltrace_state.cpp
)
add_dependencies (cgltrace glproc)
add_library (glxtrace SHARED
glxtrace.cpp
glcaps.cpp
+ gltrace_state.cpp
)
add_dependencies (glxtrace glproc)
add_library (egltrace SHARED
egltrace.cpp
glcaps.cpp
+ gltrace_state.cpp
)
add_dependencies (egltrace glproc)
# all OpenGL symbols are visible on MacOSX
return True
+ def traceFunctionImplBody(self, function):
+ if function.name == 'CGLReleaseContext':
+ # Unlike other GL APIs like EGL or GLX, CGL will make the context
+ # not current if it's the current context.
+ print ' if (_CGLGetContextRetainCount(ctx) == 1) {'
+ print ' if (gltrace::releaseContext((uintptr_t)ctx)) {'
+ print ' if (_CGLGetCurrentContext() == ctx) {'
+ print ' gltrace::clearContext();'
+ print ' }'
+ print ' }'
+ print ' }'
+
+ if function.name == 'CGLDestroyContext':
+ # The same rule applies here about the as for CGLReleaseContext.
+ print ' if (gltrace::releaseContext((uintptr_t)ctx)) {'
+ print ' if (_CGLGetCurrentContext() == ctx) {'
+ print ' gltrace::clearContext();'
+ print ' }'
+ print ' }'
+
+ GlTracer.traceFunctionImplBody(self, function)
+
+ if function.name == 'CGLCreateContext':
+ print ' if (_result == kCGLNoError) {'
+ print ' gltrace::createContext((uintptr_t)*ctx);'
+ print ' }'
+
+ if function.name == 'CGLSetCurrentContext':
+ print ' if (_result == kCGLNoError) {'
+ print ' if (ctx != NULL) {'
+ print ' gltrace::setContext((uintptr_t)ctx);'
+ print ' } else {'
+ print ' gltrace::clearContext();'
+ print ' }'
+ print ' }'
+
+ if function.name == 'CGLRetainContext':
+ print ' gltrace::retainContext((uintptr_t)ctx);'
+
if __name__ == '__main__':
print
def traceFunctionImplBody(self, function):
GlTracer.traceFunctionImplBody(self, function)
+ if function.name == 'eglCreateContext':
+ print ' if (_result != EGL_NO_CONTEXT)'
+ print ' gltrace::createContext((uintptr_t)_result);'
+
if function.name == 'eglMakeCurrent':
- print ' // update the profile'
- print ' if (ctx != EGL_NO_CONTEXT) {'
- print ' EGLint api = EGL_OPENGL_ES_API, version = 1;'
- print ' gltrace::Context *tr = gltrace::getContext();'
- print ' _eglQueryContext(dpy, ctx, EGL_CONTEXT_CLIENT_TYPE, &api);'
- print ' _eglQueryContext(dpy, ctx, EGL_CONTEXT_CLIENT_VERSION, &version);'
- print ' if (api == EGL_OPENGL_API)'
- print ' tr->profile = gltrace::PROFILE_COMPAT;'
- print ' else if (version == 1)'
- print ' tr->profile = gltrace::PROFILE_ES1;'
- print ' else'
- print ' tr->profile = gltrace::PROFILE_ES2;'
+ print ' if (_result) {'
+ print ' // update the profile'
+ print ' if (ctx != EGL_NO_CONTEXT) {'
+ print ' EGLint api = EGL_OPENGL_ES_API, version = 1;'
+ print ' gltrace::setContext((uintptr_t)ctx);'
+ print ' gltrace::Context *tr = gltrace::getContext();'
+ print ' _eglQueryContext(dpy, ctx, EGL_CONTEXT_CLIENT_TYPE, &api);'
+ print ' _eglQueryContext(dpy, ctx, EGL_CONTEXT_CLIENT_VERSION, &version);'
+ print ' if (api == EGL_OPENGL_API)'
+ print ' tr->profile = gltrace::PROFILE_COMPAT;'
+ print ' else if (version == 1)'
+ print ' tr->profile = gltrace::PROFILE_ES1;'
+ print ' else'
+ print ' tr->profile = gltrace::PROFILE_ES2;'
+ print ' } else {'
+ print ' gltrace::clearContext();'
+ print ' }'
print ' }'
+ if function.name == 'eglDestroyContext':
+ print ' if (_result) {'
+ print ' gltrace::releaseContext((uintptr_t)ctx);'
+ print ' }'
if __name__ == '__main__':
print '#include <stdlib.h>'
PROFILE_ES2,
};
-struct Context {
+class Context {
+public:
enum Profile profile;
bool user_arrays;
bool user_arrays_arb;
bool user_arrays_nv;
+ unsigned retain_count;
+
+ Context(void) :
+ profile(PROFILE_COMPAT),
+ user_arrays(false),
+ user_arrays_arb(false),
+ user_arrays_nv(false),
+ retain_count(0)
+ { }
};
-
-Context *
+
+void
+createContext(uintptr_t context_id);
+
+void
+retainContext(uintptr_t context_id);
+
+bool
+releaseContext(uintptr_t context_id);
+
+void
+setContext(uintptr_t context_id);
+
+void
+clearContext(void);
+
+gltrace::Context *
getContext(void);
const GLubyte *
print ' VERTEX_ATTRIB_NV,'
print '};'
print
- print 'gltrace::Context *'
- print 'gltrace::getContext(void)'
- print '{'
- print ' // TODO return the context set by other APIs (GLX, EGL, and etc.)'
- print ' static gltrace::Context _ctx = { gltrace::PROFILE_COMPAT, false, false, false };'
- print ' return &_ctx;'
- print '}'
- print
print 'static vertex_attrib _get_vertex_attrib(void) {'
print ' gltrace::Context *ctx = gltrace::getContext();'
print ' if (ctx->user_arrays_arb || ctx->user_arrays_nv) {'
--- /dev/null
+/*********************************************************************
+ *
+ * Copyright 2012 Intel Corporation
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *********************************************************************/
+
+#include <assert.h>
+
+#include <map>
+#if defined(_MSC_VER)
+#include <memory>
+#else
+#include <tr1/memory>
+#endif
+
+#include <gltrace.hpp>
+#include <os_thread.hpp>
+
+namespace gltrace {
+
+typedef std::tr1::shared_ptr<Context> context_ptr_t;
+static std::map<uintptr_t, context_ptr_t> context_map;
+static os::recursive_mutex context_map_mutex;
+
+class ThreadState {
+public:
+ context_ptr_t current_context;
+ context_ptr_t dummy_context; /*
+ * For cases when there is no current
+ * context, but the app still calls some
+ * GL function that expects one.
+ */
+ ThreadState() : dummy_context(new Context)
+ {
+ current_context = dummy_context;
+ }
+};
+
+static os::thread_specific_ptr<struct ThreadState> thread_state;
+
+static ThreadState *get_ts(void)
+{
+ ThreadState *ts = thread_state.get();
+
+ if (!ts) {
+ ts = new ThreadState;
+ thread_state.reset(ts);
+ }
+
+ return ts;
+}
+
+static void _retainContext(context_ptr_t ctx)
+{
+ ctx->retain_count++;
+}
+
+void retainContext(uintptr_t context_id)
+{
+ context_map_mutex.lock();
+ if (context_map.find(context_id) != context_map.end())
+ _retainContext(context_map[context_id]);
+ context_map_mutex.unlock();
+}
+
+static bool _releaseContext(context_ptr_t ctx)
+{
+ return !(--ctx->retain_count);
+}
+
+/*
+ * return true if the context was destroyed, false if only its refcount
+ * got decreased. Note that even if the context was destroyed it may
+ * still live, if it's the currently selected context (by setContext).
+ */
+bool releaseContext(uintptr_t context_id)
+{
+ bool res;
+
+ context_map_mutex.lock();
+ /*
+ * This can potentially called (from glX) with an invalid context_id,
+ * so don't assert on it being valid.
+ */
+ if (context_map.find(context_id) != context_map.end()) {
+ res = _releaseContext(context_map[context_id]);
+ if (res)
+ context_map.erase(context_id);
+ }
+ context_map_mutex.unlock();
+
+ return res;
+}
+
+void createContext(uintptr_t context_id)
+{
+ context_ptr_t ctx(new Context);
+
+ context_map_mutex.lock();
+
+ _retainContext(ctx);
+ assert(context_map.find(context_id) == context_map.end());
+ context_map[context_id] = ctx;
+
+ context_map_mutex.unlock();
+}
+
+void setContext(uintptr_t context_id)
+{
+ ThreadState *ts = get_ts();
+ context_ptr_t ctx;
+
+ context_map_mutex.lock();
+
+ assert(context_map.find(context_id) != context_map.end());
+ ctx = context_map[context_id];
+
+ context_map_mutex.unlock();
+
+ ts->current_context = ctx;
+}
+
+void clearContext(void)
+{
+ ThreadState *ts = get_ts();
+
+ ts->current_context = ts->dummy_context;
+}
+
+Context *getContext(void)
+{
+ return get_ts()->current_context.get();
+}
+
+}
"glXGetProcAddressARB",
]
+ def traceFunctionImplBody(self, function):
+ if function.name == 'glXDestroyContext':
+ print ' gltrace::releaseContext((uintptr_t)ctx);'
+
+ GlTracer.traceFunctionImplBody(self, function)
+
+ if function.name == 'glXCreateContext':
+ print ' if (_result != NULL)'
+ print ' gltrace::createContext((uintptr_t)_result);'
+
+ if function.name == 'glXMakeCurrent':
+ print ' if (_result) {'
+ print ' if (ctx != NULL)'
+ print ' gltrace::setContext((uintptr_t)ctx);'
+ print ' else'
+ print ' gltrace::clearContext();'
+ print ' }'
+
if __name__ == '__main__':
print
"wglGetProcAddress",
]
+ def traceFunctionImplBody(self, function):
+ if function.name == 'wglDeleteContext':
+ # Unlike other GL APIs like EGL or GLX, WGL will make the context
+ # inactive if it's currently the active context.
+ print ' if (_wglGetCurrentContext() == hglrc) {'
+ print ' gltrace::clearContext();'
+ print ' }'
+ print ' gltrace::releaseContext((uintptr_t)hglrc);'
+
+ GlTracer.traceFunctionImplBody(self, function)
+
+ if function.name == 'wglCreateContext':
+ print ' if (_result)'
+ print ' gltrace::createContext((uintptr_t)_result);'
+
+ if function.name == 'wglMakeCurrent':
+ print ' if (_result) {'
+ print ' if (hglrc != NULL)'
+ print ' gltrace::setContext((uintptr_t)hglrc);'
+ print ' else'
+ print ' gltrace::clearContext();'
+ print ' }'
+
if __name__ == '__main__':
print