[PATCH v3 02/18] mt trace: add helper to track GL contexts on a per-thread basis

Imre Deak imre.deak at intel.com
Wed May 23 02:05:16 PDT 2012


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 <imre.deak at intel.com>
---
 wrappers/gltrace.hpp       |   30 +++++++++-
 wrappers/gltrace_state.cpp |  131 ++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 153 insertions(+), 8 deletions(-)

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 <gltrace.hpp>
+#include <os_thread.hpp>
+#include <assert.h>
+#include <tr1/memory>
 
-gltrace::Context *
-gltrace::getContext(void)
+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();
+}
+
+/*
+ * 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();
+}
+
+}
-- 
1.7.5.4



More information about the apitrace mailing list