1 /**************************************************************************
2 *
3 * Copyright 2011 Jose Fonseca
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 **************************************************************************/
25
26
27 #include "glretrace_wgl.hpp"
28
29 #include "glproc.hpp"
30 #include "retrace.hpp"
31 #include "glretrace.hpp"
32
33
34 using namespace glretrace;
35
36
37 typedef std::map<unsigned long long, glws::Drawable *> DrawableMap;
38 typedef std::map<unsigned long long, Context *> ContextMap;
39 static DrawableMap drawable_map;
40 static DrawableMap pbuffer_map;
41 static ContextMap context_map;
42
43
44 static glws::Drawable *
getDrawable(unsigned long long hdc)45 getDrawable(unsigned long long hdc) {
46 if (hdc == 0) {
47 return NULL;
48 }
49
50 DrawableMap::const_iterator it;
51 it = drawable_map.find(hdc);
52 if (it == drawable_map.end()) {
53 return (drawable_map[hdc] = glretrace::createDrawable());
54 }
55
56 return it->second;
57 }
58
59 static Context *
getContext(unsigned long long context_ptr)60 getContext(unsigned long long context_ptr) {
61 if (context_ptr == 0) {
62 return NULL;
63 }
64
65 ContextMap::const_iterator it;
66 it = context_map.find(context_ptr);
67 if (it == context_map.end()) {
68 assert(false);
69 return NULL;
70 }
71
72 return it->second;
73 }
74
retrace_wglCreateContext(trace::Call & call)75 static void retrace_wglCreateContext(trace::Call &call) {
76 unsigned long long orig_context = call.ret->toUIntPtr();
77 if (!orig_context) {
78 return;
79 }
80
81 Context *context = glretrace::createContext();
82 context_map[orig_context] = context;
83 }
84
retrace_wglDeleteContext(trace::Call & call)85 static void retrace_wglDeleteContext(trace::Call &call) {
86 unsigned long long hglrc = call.arg(0).toUIntPtr();
87
88 ContextMap::iterator it;
89 it = context_map.find(hglrc);
90 if (it == context_map.end()) {
91 return;
92 }
93
94 it->second->release();
95
96 context_map.erase(it);
97 }
98
retrace_wglMakeCurrent(trace::Call & call)99 static void retrace_wglMakeCurrent(trace::Call &call) {
100 bool ret = call.ret->toBool();
101
102 glws::Drawable *new_drawable = NULL;
103 Context *new_context = NULL;
104 if (ret || retrace::ignoreRetvals) {
105 unsigned long long hglrc = call.arg(1).toUIntPtr();
106 if (hglrc) {
107 new_drawable = getDrawable(call.arg(0).toUIntPtr());
108 new_context = getContext(hglrc);
109 }
110 }
111
112 glretrace::makeCurrent(call, new_drawable, new_context);
113 }
114
retrace_wglMakeContextCurrentARB(trace::Call & call)115 static void retrace_wglMakeContextCurrentARB(trace::Call &call) {
116 bool ret = call.ret->toBool();
117
118 glws::Drawable *new_drawable = NULL;
119 glws::Drawable *new_readable = NULL;
120 Context *new_context = NULL;
121 if (ret || retrace::ignoreRetvals) {
122 unsigned long long hglrc = call.arg(2).toUIntPtr();
123 if (hglrc) {
124 new_drawable = getDrawable(call.arg(0).toUIntPtr());
125 new_readable = getDrawable(call.arg(1).toUIntPtr());
126 new_context = getContext(hglrc);
127 }
128 }
129
130 glretrace::makeCurrent(call, new_drawable, new_readable, new_context);
131 }
132
retrace_wglSwapBuffers(trace::Call & call)133 static void retrace_wglSwapBuffers(trace::Call &call) {
134 if (!call.ret) {
135 // incomplete call recorded - return, don't crash
136 return;
137 }
138 bool ret = call.ret->toBool();
139 if (!ret && !retrace::ignoreRetvals) {
140 return;
141 }
142
143 glws::Drawable *drawable = getDrawable(call.arg(0).toUIntPtr());
144
145 frame_complete(call);
146 if (retrace::doubleBuffer) {
147 if (drawable) {
148 drawable->swapBuffers();
149 } else {
150 glretrace::Context *currentContext = glretrace::getCurrentContext();
151 if (currentContext) {
152 currentContext->drawable->swapBuffers();
153 }
154 }
155 } else {
156 glFlush();
157 }
158 }
159
retrace_wglShareLists(trace::Call & call)160 static void retrace_wglShareLists(trace::Call &call) {
161 bool ret = call.ret->toBool();
162 if (!ret && !retrace::ignoreRetvals) {
163 return;
164 }
165
166 unsigned long long hglrc1 = call.arg(0).toUIntPtr();
167 unsigned long long hglrc2 = call.arg(1).toUIntPtr();
168
169 Context *share_context = getContext(hglrc1);
170 Context *old_context = getContext(hglrc2);
171
172 glfeatures::Profile profile = old_context->profile();
173 Context *new_context = glretrace::createContext(share_context, profile);
174 if (new_context) {
175 glretrace::Context *currentContext = glretrace::getCurrentContext();
176 if (currentContext == old_context) {
177 glretrace::makeCurrent(call, currentContext->drawable, new_context);
178 }
179
180 context_map[hglrc2] = new_context;
181
182 old_context->release();
183 }
184 }
185
retrace_wglCreateLayerContext(trace::Call & call)186 static void retrace_wglCreateLayerContext(trace::Call &call) {
187 retrace_wglCreateContext(call);
188 }
189
retrace_wglSwapLayerBuffers(trace::Call & call)190 static void retrace_wglSwapLayerBuffers(trace::Call &call) {
191 retrace_wglSwapBuffers(call);
192 }
193
194 #define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070
195 #define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071
196 #define WGL_TEXTURE_FORMAT_ARB 0x2072
197 #define WGL_TEXTURE_TARGET_ARB 0x2073
198 #define WGL_MIPMAP_TEXTURE_ARB 0x2074
199 #define WGL_TEXTURE_RGB_ARB 0x2075
200 #define WGL_TEXTURE_RGBA_ARB 0x2076
201 #define WGL_NO_TEXTURE_ARB 0x2077
202 #define WGL_TEXTURE_CUBE_MAP_ARB 0x2078
203 #define WGL_TEXTURE_1D_ARB 0x2079
204 #define WGL_TEXTURE_2D_ARB 0x207A
205 #define WGL_NO_TEXTURE_ARB 0x2077
206 #define WGL_MIPMAP_LEVEL_ARB 0x207B
207 #define WGL_CUBE_MAP_FACE_ARB 0x207C
208 #define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D
209 #define WGL_FRONT_LEFT_ARB 0x2083
210 #define WGL_FRONT_RIGHT_ARB 0x2084
211 #define WGL_BACK_LEFT_ARB 0x2085
212 #define WGL_BACK_RIGHT_ARB 0x2086
213 #define WGL_AUX0_ARB 0x2087
214 #define WGL_AUX1_ARB 0x2088
215 #define WGL_AUX2_ARB 0x2089
216 #define WGL_AUX3_ARB 0x208A
217 #define WGL_AUX4_ARB 0x208B
218 #define WGL_AUX5_ARB 0x208C
219 #define WGL_AUX6_ARB 0x208D
220 #define WGL_AUX7_ARB 0x208E
221 #define WGL_AUX8_ARB 0x208F
222 #define WGL_AUX9_ARB 0x2090
223
retrace_wglCreatePbufferARB(trace::Call & call)224 static void retrace_wglCreatePbufferARB(trace::Call &call) {
225 unsigned long long orig_pbuffer = call.ret->toUIntPtr();
226 if (!orig_pbuffer) {
227 return;
228 }
229
230 int iWidth = call.arg(2).toUInt();
231 int iHeight = call.arg(3).toUInt();
232 const trace::Value *attribs = &call.arg(4);
233 glws::pbuffer_info pbInfo = {0, 0, false};
234
235 // XXX parse attrib list to populate pbInfo
236 int k;
237
238 k = parseAttrib(attribs, WGL_TEXTURE_FORMAT_ARB, WGL_NO_TEXTURE_ARB);
239 switch (k) {
240 case WGL_TEXTURE_RGB_ARB:
241 pbInfo.texFormat = GL_RGB;
242 break;
243 case WGL_TEXTURE_RGBA_ARB:
244 pbInfo.texFormat = GL_RGBA;
245 break;
246 case WGL_NO_TEXTURE_ARB:
247 pbInfo.texFormat = GL_NONE;
248 break;
249 default:
250 std::cerr << "error: invalid value for WGL_TEXTURE_FORMAT_ARB\n";
251 pbInfo.texFormat = GL_NONE;
252 }
253
254 k = parseAttrib(attribs, WGL_TEXTURE_TARGET_ARB, WGL_NO_TEXTURE_ARB);
255 switch (k) {
256 case WGL_TEXTURE_CUBE_MAP_ARB:
257 pbInfo.texTarget = GL_TEXTURE_CUBE_MAP;
258 break;
259 case WGL_TEXTURE_1D_ARB:
260 pbInfo.texTarget = GL_TEXTURE_1D;
261 break;
262 case WGL_TEXTURE_2D_ARB:
263 pbInfo.texTarget = GL_TEXTURE_2D;
264 break;
265 case WGL_NO_TEXTURE_ARB:
266 pbInfo.texTarget = GL_NONE;
267 break;
268 default:
269 std::cerr << "error: invalid value for WGL_TEXTURE_TARGET_ARB\n";
270 pbInfo.texTarget = GL_NONE;
271 }
272
273 pbInfo.texMipmap = !!parseAttrib(attribs, WGL_MIPMAP_TEXTURE_ARB, 0);
274
275 // WGL interface needs the HDC
276 pbInfo.hdc_drawable = getDrawable(call.arg(0).toUInt());
277
278 glws::Drawable *drawable = glretrace::createPbuffer(iWidth, iHeight,
279 &pbInfo);
280
281 pbuffer_map[orig_pbuffer] = drawable;
282 }
283
retrace_wglGetPbufferDCARB(trace::Call & call)284 static void retrace_wglGetPbufferDCARB(trace::Call &call) {
285 unsigned long long orig_hdc = call.ret->toUIntPtr();
286 if (!orig_hdc) {
287 return;
288 }
289
290 glws::Drawable *pbuffer = pbuffer_map[call.arg(0).toUIntPtr()];
291
292 drawable_map[orig_hdc] = pbuffer;
293 }
294
retrace_wglCreateContextAttribsARB(trace::Call & call)295 static void retrace_wglCreateContextAttribsARB(trace::Call &call) {
296 unsigned long long orig_context = call.ret->toUIntPtr();
297 if (!orig_context) {
298 return;
299 }
300
301 Context *share_context = getContext(call.arg(1).toUIntPtr());
302
303 const trace::Value * attribList = &call.arg(2);
304 glfeatures::Profile profile = parseContextAttribList(attribList);
305
306 Context *context = glretrace::createContext(share_context, profile);
307 context_map[orig_context] = context;
308 }
309
310
311 static GLenum
wgl_buffer_to_enum(int iBuffer)312 wgl_buffer_to_enum(int iBuffer)
313 {
314 switch (iBuffer) {
315 case WGL_FRONT_LEFT_ARB:
316 return GL_FRONT_LEFT;
317 case WGL_BACK_LEFT_ARB:
318 return GL_BACK_LEFT;
319 case WGL_FRONT_RIGHT_ARB:
320 return GL_FRONT_RIGHT;
321 case WGL_BACK_RIGHT_ARB:
322 return GL_BACK_RIGHT;
323 case WGL_AUX0_ARB:
324 return GL_AUX0;
325 default:
326 std::cerr << "error: invalid iBuffer in wgl_buffer_to_enum()\n";
327 return GL_FRONT_LEFT;
328 }
329 }
330
retrace_wglBindTexImageARB(trace::Call & call)331 static void retrace_wglBindTexImageARB(trace::Call &call) {
332 glws::Drawable *pbuffer = pbuffer_map[call.arg(0).toUIntPtr()];
333 signed long long iBuffer = call.arg(1).toSInt();
334
335 glretrace::bindTexImage(pbuffer, wgl_buffer_to_enum(iBuffer));
336 }
337
retrace_wglReleaseTexImageARB(trace::Call & call)338 static void retrace_wglReleaseTexImageARB(trace::Call &call) {
339 glws::Drawable *pbuffer = pbuffer_map[call.arg(0).toUIntPtr()];
340 signed long long iBuffer = call.arg(1).toSInt();
341
342 glretrace::releaseTexImage(pbuffer, wgl_buffer_to_enum(iBuffer));
343 }
344
retrace_wglSetPbufferAttribARB(trace::Call & call)345 static void retrace_wglSetPbufferAttribARB(trace::Call &call) {
346 glws::Drawable *pbuffer = pbuffer_map[call.arg(0).toUIntPtr()];
347 const trace::Value * attribList = &call.arg(1);
348
349 // call the window system's setPbufferAttrib function.
350 {
351 int attribs[100], j = 0;
352 const trace::Array *attribs_ = attribList ? attribList->toArray() : NULL;
353
354 for (size_t i = 0; i + 1 < attribs_->values.size(); i += 2) {
355 int param_i = attribs_->values[i]->toSInt();
356 if (param_i == 0) {
357 attribs[j] = 0;
358 }
359
360 attribs[j] = param_i;
361 attribs[j+1] = attribs_->values[i+1]->toSInt();
362 }
363
364 glretrace::setPbufferAttrib(pbuffer, attribs);
365 }
366
367 if (!pbuffer || !attribList)
368 return;
369
370 // Update the glws::Drawable's fields
371 const int undefined = -99999;
372 int val;
373
374 val = parseAttrib(attribList, WGL_MIPMAP_LEVEL_ARB, undefined);
375 if (val != undefined) {
376 pbuffer->mipmapLevel = val;
377 }
378
379 val = parseAttrib(attribList, WGL_CUBE_MAP_FACE_ARB, undefined);
380 if (val != undefined) {
381 // Drawable::cubeFace is integer in [0..5]
382 val -= WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
383 if (val < 0 || val > 5) {
384 fprintf(stderr, "Invalid WGL_CUBE_MAP_FACE_ARB value!\n");
385 }
386 else {
387 pbuffer->cubeFace = val;
388 }
389 }
390 }
391
392
retrace_wglUseFontBitmapsAW(trace::Call & call)393 static void retrace_wglUseFontBitmapsAW(trace::Call &call)
394 {
395 bool ret = call.ret->toBool();
396 if (!ret && !retrace::ignoreRetvals) {
397 return;
398 }
399
400 uint32_t first = call.arg(1).toUInt();
401 uint32_t count = call.arg(2).toUInt();
402 uint32_t listBase = call.arg(3).toUInt();
403
404 GLint row_length = 0;
405 GLint alignment = 4;
406 _glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
407 _glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
408
409 for (uint32_t i = 0; i < count; ++i) {
410 uint32_t dwChar = (first + i) % 256;
411 const Bitmap *bm = &wglSystemFontBitmaps[dwChar];
412
413 glPixelStorei(GL_UNPACK_ROW_LENGTH, bm->width);
414 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
415
416 glNewList(listBase + i, GL_COMPILE);
417
418 glBitmap(bm->width, bm->height,
419 bm->xorig, bm->yorig, bm->xmove, bm->ymove,
420 (const GLubyte *)bm->pixels);
421
422 glEndList();
423 }
424
425 glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
426 glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
427 }
428
429
retrace_wglUseFontOutlinesAW(trace::Call & call)430 static void retrace_wglUseFontOutlinesAW(trace::Call &call)
431 {
432 bool ret = call.ret->toBool();
433 if (!ret) {
434 return;
435 }
436
437 uint32_t first = call.arg(1).toUInt();
438 uint32_t count = call.arg(2).toUInt();
439 uint32_t listBase = call.arg(3).toUInt();
440 float extrusion = call.arg(5).toFloat();
441
442 for (uint32_t i = 0; i < count; ++i) {
443 glNewList(listBase + i, GL_COMPILE);
444 wglSystemFontOutlines(first + i, extrusion);
445 glEndList();
446 }
447 }
448
449
450
451 const retrace::Entry glretrace::wgl_callbacks[] = {
452 {"glAddSwapHintRectWIN", &retrace::ignore},
453 {"wglBindTexImageARB", &retrace_wglBindTexImageARB},
454 {"wglChoosePixelFormat", &retrace::ignore},
455 {"wglChoosePixelFormatARB", &retrace::ignore},
456 {"wglChoosePixelFormatEXT", &retrace::ignore},
457 {"wglCreateContext", &retrace_wglCreateContext},
458 {"wglCreateContextAttribsARB", &retrace_wglCreateContextAttribsARB},
459 {"wglCreateLayerContext", &retrace_wglCreateLayerContext},
460 {"wglCreatePbufferARB", &retrace_wglCreatePbufferARB},
461 {"wglDeleteContext", &retrace_wglDeleteContext},
462 {"wglDescribeLayerPlane", &retrace::ignore},
463 {"wglDescribePixelFormat", &retrace::ignore},
464 {"wglDestroyPbufferARB", &retrace::ignore},
465 {"wglGetCurrentContext", &retrace::ignore},
466 {"wglGetCurrentDC", &retrace::ignore},
467 {"wglGetCurrentReadDCARB", &retrace::ignore},
468 {"wglGetCurrentReadDCEXT", &retrace::ignore},
469 {"wglGetDefaultProcAddress", &retrace::ignore},
470 {"wglGetExtensionsStringARB", &retrace::ignore},
471 {"wglGetExtensionsStringEXT", &retrace::ignore},
472 {"wglGetLayerPaletteEntries", &retrace::ignore},
473 {"wglGetPbufferDCARB", &retrace_wglGetPbufferDCARB},
474 {"wglGetPixelFormat", &retrace::ignore},
475 {"wglGetPixelFormatAttribfvARB", &retrace::ignore},
476 {"wglGetPixelFormatAttribfvEXT", &retrace::ignore},
477 {"wglGetPixelFormatAttribivARB", &retrace::ignore},
478 {"wglGetPixelFormatAttribivEXT", &retrace::ignore},
479 {"wglGetProcAddress", &retrace::ignore},
480 {"wglGetSwapIntervalEXT", &retrace::ignore},
481 {"wglMakeContextCurrentARB", &retrace_wglMakeContextCurrentARB},
482 {"wglMakeCurrent", &retrace_wglMakeCurrent},
483 {"wglQueryPbufferARB", &retrace::ignore},
484 {"wglReleasePbufferDCARB", &retrace::ignore},
485 {"wglReleaseTexImageARB", &retrace_wglReleaseTexImageARB},
486 {"wglSetPbufferAttribARB", &retrace_wglSetPbufferAttribARB},
487 {"wglSetPixelFormat", &retrace::ignore},
488 {"wglShareLists", &retrace_wglShareLists},
489 {"wglSwapBuffers", &retrace_wglSwapBuffers},
490 {"wglSwapIntervalEXT", &retrace::ignore},
491 {"wglSwapLayerBuffers", &retrace_wglSwapLayerBuffers},
492 {"wglUseFontBitmapsA", &retrace_wglUseFontBitmapsAW},
493 {"wglUseFontBitmapsW", &retrace_wglUseFontBitmapsAW},
494 {"wglUseFontOutlinesA", &retrace_wglUseFontOutlinesAW},
495 {"wglUseFontOutlinesW", &retrace_wglUseFontOutlinesAW},
496 {NULL, NULL}
497 };
498
499