From: Imre Deak Date: Mon, 7 May 2012 06:10:26 +0000 (+0300) Subject: mt trace: add helper to track GL contexts on a per-thread basis X-Git-Url: https://git.cworth.org/git?a=commitdiff_plain;h=a150c4a0cf9e47931f0e79986f5f79b85aa5905e;hp=e90cac47697d2c26ac3a6d5292de101519b46f95;p=apitrace mt trace: add helper to track GL contexts on a per-thread basis This is needed for muti-threaded tracing to work properly. Tracing multi-threaded GL apps requires that we track the lifetime of the GL context objects and store thread specific state like the currently active GL context on thread-local memory area. Also add 'retain_count' to the context needed by the CGL retain/release context calls. Needed by the 4 upcoming GL API specific patches. Signed-off-by: Imre Deak --- diff --git a/wrappers/gltrace.hpp b/wrappers/gltrace.hpp index cd602cb..49d8631 100644 --- a/wrappers/gltrace.hpp +++ b/wrappers/gltrace.hpp @@ -39,14 +39,38 @@ enum Profile { 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); + +bool +destroyContext(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 * diff --git a/wrappers/gltrace_state.cpp b/wrappers/gltrace_state.cpp index 6b73d7a..6bd20c0 100644 --- a/wrappers/gltrace_state.cpp +++ b/wrappers/gltrace_state.cpp @@ -1,10 +1,131 @@ #include +#include +#include +#include -gltrace::Context * -gltrace::getContext(void) +namespace gltrace { + +typedef std::tr1::shared_ptr context_ptr_t; +static std::map 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 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(); +} + +/* + * return true if the context has been destroyed, false otherwise. See + * the note at releaseContext about the actual ccontext lifetime. + */ +bool destroyContext(uintptr_t context_id) +{ + return releaseContext(context_id); +} + +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) { - // TODO return the context set by other APIs (GLX, EGL, and etc.) - static gltrace::Context _ctx = { gltrace::PROFILE_COMPAT, false, false, false }; - return &_ctx; + ThreadState *ts = get_ts(); + + ts->current_context = ts->dummy_context; } +Context *getContext(void) +{ + return get_ts()->current_context.get(); +} + +}