+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(ThreadState) thread_state;
+
+static ThreadState *get_ts(void)
+{
+ ThreadState *ts = thread_state;
+ if (!ts) {
+ thread_state = ts = new ThreadState;
+ }
+
+ 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 = false;
+
+ 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)