]> git.cworth.org Git - apitrace/blob - wrappers/gltrace_state.cpp
retrace: Implement glxCopySubBufferMESA
[apitrace] / wrappers / gltrace_state.cpp
1 /*********************************************************************
2  *
3  * Copyright 2012 Intel Corporation
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation
8  * files (the "Software"), to deal in the Software without
9  * restriction, including without limitation the rights to use, copy,
10  * modify, merge, publish, distribute, sublicense, and/or sell copies
11  * of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  *
26  *********************************************************************/
27
28 #include <assert.h>
29
30 #include <map>
31 #if defined(_MSC_VER)
32 #include <memory>
33 #else
34 #include <tr1/memory>
35 #endif
36
37 #include <os_thread.hpp>
38 #include <glproc.hpp>
39 #include <gltrace.hpp>
40
41 namespace gltrace {
42
43 typedef std::tr1::shared_ptr<Context> context_ptr_t;
44 static std::map<uintptr_t, context_ptr_t> context_map;
45 static os::recursive_mutex context_map_mutex;
46
47 class ThreadState {
48 public:
49     context_ptr_t current_context;
50     context_ptr_t dummy_context;     /*
51                                       * For cases when there is no current
52                                       * context, but the app still calls some
53                                       * GL function that expects one.
54                                       */
55     ThreadState() : dummy_context(new Context)
56     {
57         current_context = dummy_context;
58     }
59 };
60
61 static OS_THREAD_SPECIFIC_PTR(ThreadState) thread_state;
62
63 static ThreadState *get_ts(void)
64 {
65     ThreadState *ts = thread_state;
66     if (!ts) {
67         thread_state = ts = new ThreadState;
68     }
69
70     return ts;
71 }
72
73 static void _retainContext(context_ptr_t ctx)
74 {
75     ctx->retain_count++;
76 }
77
78 void retainContext(uintptr_t context_id)
79 {
80     context_map_mutex.lock();
81     if (context_map.find(context_id) != context_map.end())
82         _retainContext(context_map[context_id]);
83     context_map_mutex.unlock();
84 }
85
86 static bool _releaseContext(context_ptr_t ctx)
87 {
88     return !(--ctx->retain_count);
89 }
90
91 /*
92  * return true if the context was destroyed, false if only its refcount
93  * got decreased. Note that even if the context was destroyed it may
94  * still live, if it's the currently selected context (by setContext).
95  */
96 bool releaseContext(uintptr_t context_id)
97 {
98     bool res = false;
99
100     context_map_mutex.lock();
101     /*
102      * This can potentially called (from glX) with an invalid context_id,
103      * so don't assert on it being valid.
104      */
105     if (context_map.find(context_id) != context_map.end()) {
106         res = _releaseContext(context_map[context_id]);
107         if (res)
108             context_map.erase(context_id);
109     }
110     context_map_mutex.unlock();
111
112     return res;
113 }
114
115 void createContext(uintptr_t context_id)
116 {
117     // wglCreateContextAttribsARB causes internal calls to wglCreateContext to be
118     // traced, causing context to be defined twice.
119     if (context_map.find(context_id) != context_map.end()) {
120         return;
121     }
122
123     context_ptr_t ctx(new Context);
124
125     context_map_mutex.lock();
126
127     _retainContext(ctx);
128     context_map[context_id] = ctx;
129
130     context_map_mutex.unlock();
131 }
132
133 void setContext(uintptr_t context_id)
134 {
135     ThreadState *ts = get_ts();
136     context_ptr_t ctx;
137
138     context_map_mutex.lock();
139
140     assert(context_map.find(context_id) != context_map.end());
141     ctx = context_map[context_id];
142
143     context_map_mutex.unlock();
144
145     ts->current_context = ctx;
146
147     if (!ctx->bound) {
148         ctx->bound = true;
149
150         /*
151          * The default viewport and scissor state is set when a context is
152          * first made current, with values matching the bound drawable.  Many
153          * applications never thouch the default state ever again.
154          *
155          * Since we currently don't trace window sizes, and rely on viewport
156          * calls to deduct, emit fake calls here so that viewport/scissor state
157          * can be deducated.
158          *
159          * FIXME: don't call the real functions here -- just emit the fake
160          * calls.
161          */
162         GLint viewport[4] = {0, 0, 0, 0};
163         GLint scissor_box[4] = {0, 0, 0, 0};
164         _glGetIntegerv(GL_VIEWPORT, viewport);
165         _glGetIntegerv(GL_SCISSOR_BOX, scissor_box);
166         glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
167         glScissor(scissor_box[0], scissor_box[1], scissor_box[2], scissor_box[3]);
168     }
169 }
170
171 void clearContext(void)
172 {
173     ThreadState *ts = get_ts();
174
175     ts->current_context = ts->dummy_context;
176 }
177
178 Context *getContext(void)
179 {
180     return get_ts()->current_context.get();
181 }
182
183 }