blob: f3539779050c329262a5dd6e687693259dd5c0ab [file] [log] [blame]
José Fonseca7ad40262009-09-30 17:17:12 +01001##########################################################################
José Fonseca36e25aa2009-04-13 14:08:08 +01002#
José Fonseca7ad40262009-09-30 17:17:12 +01003# Copyright 2008-2009 VMware, Inc.
4# All Rights Reserved.
José Fonseca36e25aa2009-04-13 14:08:08 +01005#
José Fonseca7ad40262009-09-30 17:17:12 +01006# 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:
José Fonseca36e25aa2009-04-13 14:08:08 +010012#
José Fonseca7ad40262009-09-30 17:17:12 +010013# The above copyright notice and this permission notice shall be included in
14# all copies or substantial portions of the Software.
José Fonseca36e25aa2009-04-13 14:08:08 +010015#
José Fonseca7ad40262009-09-30 17:17:12 +010016# 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.
José Fonseca36e25aa2009-04-13 14:08:08 +010023#
José Fonseca7ad40262009-09-30 17:17:12 +010024##########################################################################/
José Fonseca36e25aa2009-04-13 14:08:08 +010025
José Fonseca36e25aa2009-04-13 14:08:08 +010026
José Fonseca4a826ed2010-11-30 16:58:22 +000027"""WGL tracing code generator."""
28
29
José Fonseca452d3252012-04-14 15:55:40 +010030from gltrace import GlTracer
José Fonseca0a25d022014-05-28 17:08:56 +010031from specs.stdapi import Module, API, Void
José Fonsecabd86a222011-09-27 09:21:38 +010032from specs.glapi import glapi
33from specs.wglapi import wglapi
José Fonseca36e25aa2009-04-13 14:08:08 +010034
José Fonseca36e25aa2009-04-13 14:08:08 +010035
José Fonseca669b1222011-02-20 09:05:10 +000036class WglTracer(GlTracer):
José Fonseca36e25aa2009-04-13 14:08:08 +010037
José Fonseca1b6c8752012-04-15 14:33:00 +010038 getProcAddressFunctionNames = [
39 "wglGetProcAddress",
40 ]
José Fonsecac77023d2009-05-04 12:53:50 +010041
José Fonsecaa67ed0a2012-08-02 20:00:28 +010042 createContextFunctionNames = [
43 'wglCreateContext',
44 'wglCreateContextAttribsARB',
45 'wglCreateLayerContext',
46 ]
47
48 destroyContextFunctionNames = [
49 'wglDeleteContext',
50 ]
51
52 makeCurrentFunctionNames = [
53 'wglMakeCurrent',
54 'wglMakeContextCurrentARB',
55 'wglMakeContextCurrentEXT',
56 ]
57
Imre Deak2f75bb42012-05-23 10:57:12 +030058 def traceFunctionImplBody(self, function):
José Fonseca0a25d022014-05-28 17:08:56 +010059 if function.name.startswith('wgl'):
60 # When implementing WGL extensions OpenGL ICDs often have no
61 # alternative to calling back into OPENGL32.DLL's wgl* entry points
62 # due to lack of extensibility in the ICD interface. These
63 # internal calls are not only visually confusing but can actually
64 # cause problems when tracing, and replaying. A particularly nasty
65 # case is wglCreateContextAttribsARB which ends up calling
66 # wglCreateContext/wglCreateLayerContext to obtain a HGLRC that's
67 # recognizable by OPENGL32.DLL. Therefore we need to detect and
68 # dispatch internal calls, without further ado.
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +010069 print(r' if (_reentrant) {')
José Fonseca0a25d022014-05-28 17:08:56 +010070 self.invokeFunction(function)
71 if function.type is not Void:
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +010072 print(' return _result;')
73 print(r' }')
74 print(r' ReentryScope _reentry;')
75 print(r' (void)_reentry;')
76 print()
José Fonseca0a25d022014-05-28 17:08:56 +010077
José Fonsecaa67ed0a2012-08-02 20:00:28 +010078 if function.name in self.destroyContextFunctionNames:
José Fonseca41b89a52012-07-09 10:36:01 +010079 # Unlike other GL APIs like EGL or GLX, WGL will make the context
80 # inactive if it's currently the active context.
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +010081 print(' if (_wglGetCurrentContext() == hglrc) {')
82 print(' gltrace::clearContext();')
83 print(' }')
84 print(' gltrace::releaseContext((uintptr_t)hglrc);')
José Fonseca41b89a52012-07-09 10:36:01 +010085
Jose Fonsecae9916d52016-08-31 18:34:12 +010086 # Emit a fake string marker describing the current GDI font
87 if function.name.startswith('wglUseFont'):
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +010088 print(r' HFONT hFont = static_cast<HFONT>(GetCurrentObject(hdc, OBJ_FONT));')
89 print(r' if (hFont != nullptr) {')
90 print(r' LOGFONT lf;')
91 print(r' if (GetObject(hFont, sizeof lf, &lf) != 0) {')
92 print(r' std::ostringstream ss;')
93 print(r' ss << "lfFaceName = " << lf.lfFaceName')
94 print(r' << ", lfHeight = " << lf.lfHeight')
95 print(r' << ", lfWeight = " << lf.lfWeight;')
96 print(r' if (lf.lfItalic) ss << ", lfItalic = 1";')
97 print(r' if (lf.lfUnderline) ss << ", lfUnderline = 1";')
98 print(r' if (lf.lfStrikeOut) ss << ", lfStrikeOut = 1";')
99 print(r' _fakeStringMarker(ss.str());')
100 print(r' }')
101 print(r' }')
102 print()
Jose Fonsecae9916d52016-08-31 18:34:12 +0100103
Jose Fonseca6ef9b3c2016-01-27 23:18:52 +0000104 # Emit fake glBitmap calls in the trace on wglUseFontBitmapsA.
105 # This enables to capture the real bitmaps and replay them outside Windows.
106 #
107 # XXX: In spite what
108 # https://msdn.microsoft.com/en-us/library/windows/desktop/dd374392.aspx
109 # implies, GetGlyphOutline(GGO_BITMAP) does not seem to work with
110 # certain fonts. The only solution is to draw the font charactors with
111 # a HBITMAP like the old Mesa fxwgl.c code used to do. That too, seems
112 # to be the way that opengl32.dll implements wglUseFontBitmaps.
113 #
114 if function.name == 'wglUseFontBitmapsA':
115
116 self.invokeFunction(function)
117
118 # Emit a fake string marker with the original call
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100119 print(r' {')
120 print(r' std::ostringstream ss;')
121 print(r' ss << __FUNCTION__ << "(hdc = " << hdc << ", first = " << first << ", count = " << count << ", listBase = " << listBase << ") = " << (_result ? "TRUE" : "FALSE");')
122 print(r' _fakeStringMarker(ss.str());')
123 print(r' }')
124 print()
Jose Fonseca6ef9b3c2016-01-27 23:18:52 +0000125
126 glNewList = glapi.getFunctionByName('glNewList')
127 glBitmap = glapi.getFunctionByName('glBitmap')
128 glEndList = glapi.getFunctionByName('glEndList')
129
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100130 print(r' if (_result) {')
Jose Fonseca6ef9b3c2016-01-27 23:18:52 +0000131
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100132 print(r' assert(hFont != nullptr);')
133 print()
Jose Fonseca6ef9b3c2016-01-27 23:18:52 +0000134
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100135 print(r' BOOL bRet;')
136 print(r' TEXTMETRIC tm;')
137 print(r' bRet = GetTextMetricsA(hdc, &tm);')
138 print(r' assert(bRet);')
139 print()
140 print(r' HDC memDC = CreateCompatibleDC(hdc);')
141 print()
142 print(r' SetMapMode(memDC, MM_TEXT);')
143 print(r' SetTextAlign(memDC, TA_BASELINE);')
144 print(r' SetBkColor(memDC, RGB(0, 0, 0));')
145 print(r' SetBkMode(memDC, OPAQUE);')
146 print(r' SetTextColor(memDC, RGB(255,255,255));')
147 print()
148 print(r' BITMAPINFO * bmi = (BITMAPINFO *)malloc(offsetof(BITMAPINFO, bmiColors[2]));')
149 print(r' ZeroMemory(&bmi->bmiHeader, sizeof bmi->bmiHeader);')
150 print(r' bmi->bmiHeader.biSize = sizeof bmi->bmiHeader;')
151 print(r' bmi->bmiHeader.biPlanes = 1;')
152 print(r' bmi->bmiHeader.biBitCount = 1;')
153 print(r' bmi->bmiHeader.biCompression = BI_RGB;')
154 print(r' bmi->bmiColors[0].rgbBlue = 0;')
155 print(r' bmi->bmiColors[0].rgbGreen = 0;')
156 print(r' bmi->bmiColors[0].rgbRed = 0;')
157 print(r' bmi->bmiColors[0].rgbReserved = 0;')
158 print(r' bmi->bmiColors[1].rgbBlue = 255;')
159 print(r' bmi->bmiColors[1].rgbGreen = 255;')
160 print(r' bmi->bmiColors[1].rgbRed = 255;')
161 print(r' bmi->bmiColors[1].rgbReserved = 0;')
162 print()
163 print(r' for (DWORD i = 0; i < count; ++i) {')
164 print(r' _fake_glNewList(listBase + i, GL_COMPILE);')
165 print()
166 print(r' char cChar = first + i;')
167 print()
168 print(r' // TODO: Use GetCharABSWidths')
169 print(r' // http://www.codeproject.com/Articles/14915/Width-of-text-in-italic-font')
170 print(r' // https://support.microsoft.com/en-us/kb/94646')
171 print(r' SIZE size;')
172 print(r' bRet = GetTextExtentPoint32A(hdc, &cChar, 1, &size);')
173 print(r' if (bRet) {')
174 print(r' assert(size.cx >= 0);')
175 print(r' assert(size.cy >= 0);')
176 print()
177 print(r' // Round width to 32 pixels')
178 print(r' int nWidth = (size.cx + 0x1f) & ~0x1f;')
179 print(r' int nHeight = size.cy;')
180 print()
181 print(r' DWORD dwBytes = nWidth / 8 * nHeight;')
182 print(r' LPVOID lpvBits = NULL;')
183 print(r' if (dwBytes) {')
184 print(r' lpvBits = malloc(dwBytes);')
185 print()
186 print(r' HBITMAP memBM = CreateCompatibleBitmap(memDC, nWidth, nHeight);')
187 print()
188 print(r' HGDIOBJ origBM = SelectObject(memDC, memBM);')
189 print()
190 print(r' PatBlt(memDC, 0, 0, nWidth, nHeight, BLACKNESS);')
191 print(r' SelectObject(memDC, hFont);')
192 print()
193 print(r' bmi->bmiHeader.biWidth = nWidth;')
194 print(r' bmi->bmiHeader.biHeight = nHeight;')
195 print()
196 print(r' bRet = TextOutA(memDC, 0, tm.tmAscent, &cChar, 1);')
197 print(r' assert(bRet);')
198 print()
199 print(r' SelectObject(memDC, origBM);')
200 print()
201 print(r' int nScanLines = GetDIBits(memDC, memBM, 0, nHeight, lpvBits, bmi, DIB_RGB_COLORS);')
202 print(r' assert(nScanLines == nHeight);')
203 print()
204 print(r' DeleteObject(memBM);')
205 print(r' }')
206 print()
207 print(r' GLsizei width = nWidth;')
208 print(r' GLfloat height = nHeight;')
209 print(r' GLfloat xorig = 0;')
210 print(r' GLfloat yorig = tm.tmDescent;')
211 print(r' GLfloat xmove = size.cx;')
212 print(r' GLfloat ymove = 0;')
213 print(r' const GLubyte *bitmap = (const GLubyte *)lpvBits;')
214 print(r' if (bitmap == NULL) {')
215 print(r' // We still need to emit an empty glBitmap for empty characters like spaces;')
216 print(r' width = height = xorig = yorig = 0;')
217 print(r' }')
Jose Fonseca6ef9b3c2016-01-27 23:18:52 +0000218
219 # FIXME: glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
220 # FIXME: glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100221 print()
222 print(r' _fake_glBitmap(width, height, xorig, yorig, xmove, ymove, bitmap);')
223 print()
224 print(r' free(lpvBits);')
225 print(r' }')
226 print(r' _fake_glEndList();')
227 print(r' }')
228 print()
229 print(r' DeleteDC(memDC);')
230 print(r' free(bmi);')
Jose Fonseca6ef9b3c2016-01-27 23:18:52 +0000231
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100232 print(r' } // _result')
Jose Fonseca6ef9b3c2016-01-27 23:18:52 +0000233 return
234
Imre Deak2f75bb42012-05-23 10:57:12 +0300235 GlTracer.traceFunctionImplBody(self, function)
236
Robert Tarasov6ccf5bb2020-01-10 12:31:25 -0800237 if function.name == 'wglCreateContextAttribsARB':
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100238 print(' if (_result)')
Robert Tarasov6ccf5bb2020-01-10 12:31:25 -0800239 print(' gltrace::createContext((uintptr_t)_result, (uintptr_t)hShareContext);')
240 elif function.name in self.createContextFunctionNames:
241 print(' if (_result)')
Jose Fonsecadfec0432020-01-30 14:26:37 +0000242 print(' gltrace::createContext((uintptr_t)_result, 0);')
Imre Deak2f75bb42012-05-23 10:57:12 +0300243
José Fonsecaa67ed0a2012-08-02 20:00:28 +0100244 if function.name in self.makeCurrentFunctionNames:
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100245 print(' if (_result) {')
246 print(' if (hglrc != NULL)')
247 print(' gltrace::setContext((uintptr_t)hglrc);')
248 print(' else')
249 print(' gltrace::clearContext();')
250 print(' }')
Imre Deak2f75bb42012-05-23 10:57:12 +0300251
José Fonsecac77023d2009-05-04 12:53:50 +0100252
José Fonseca36e25aa2009-04-13 14:08:08 +0100253if __name__ == '__main__':
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100254 print()
255 print('#define _GDI32_')
256 print()
257 print('#include <string.h>')
258 print('#include <windows.h>')
259 print()
260 print('#include <sstream>')
261 print()
262 print('#include "trace_writer_local.hpp"')
263 print('#include "os.hpp"')
264 print()
265 print('// To validate our prototypes')
266 print('#define GL_GLEXT_PROTOTYPES')
267 print('#define WGL_GLXEXT_PROTOTYPES')
268 print()
269 print('#include "glproc.hpp"')
270 print('#include "glsize.hpp"')
271 print()
272 print('static OS_THREAD_LOCAL uintptr_t _reentrant;')
273 print()
274 print('// Helper class to track reentries in function scope.')
275 print('struct ReentryScope {')
276 print('inline ReentryScope() { _reentrant = 1; }')
277 print('inline ~ReentryScope() { _reentrant = 0; }')
278 print('};')
279 print()
José Fonseca81301932012-11-11 00:10:20 +0000280 module = Module()
281 module.mergeModule(glapi)
282 module.mergeModule(wglapi)
José Fonseca68ec4122011-02-20 11:25:25 +0000283 api = API()
José Fonseca81301932012-11-11 00:10:20 +0000284 api.addModule(module)
José Fonseca8fbdd3a2010-11-23 20:55:07 +0000285 tracer = WglTracer()
José Fonseca1b6c8752012-04-15 14:33:00 +0100286 tracer.traceApi(api)