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