]> git.cworth.org Git - apitrace/blob - retrace/dxgiretrace.py
dxgi(re)trace: Organize mapping info into a structure.
[apitrace] / retrace / dxgiretrace.py
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 """D3D retracer generator."""
28
29
30 import sys
31 from dllretrace import DllRetracer as Retracer
32 import specs.dxgi
33 from specs.stdapi import API
34 from specs.dxgi import dxgi
35 from specs.d3d10 import d3d10
36 from specs.d3d10_1 import d3d10_1
37 from specs.d3d11 import d3d11
38
39
40 class D3DRetracer(Retracer):
41
42     def retraceApi(self, api):
43         print '// Swizzling mapping for lock addresses'
44         print 'static std::map<void *, void *> _maps;'
45         print
46         print r'''
47 static void 
48 createWindow(DXGI_SWAP_CHAIN_DESC *pSwapChainDesc) {
49     UINT Width  = pSwapChainDesc->BufferDesc.Width;
50     UINT Height = pSwapChainDesc->BufferDesc.Height;
51     if (!Width)  Width = 1024;
52     if (!Height) Height = 768;
53     pSwapChainDesc->OutputWindow = d3dretrace::createWindow(Width, Height);
54 }
55 '''
56
57         self.table_name = 'd3dretrace::dxgi_callbacks'
58
59         Retracer.retraceApi(self, api)
60
61     createDeviceFunctionNames = [
62         "D3D10CreateDevice",
63         "D3D10CreateDeviceAndSwapChain",
64         "D3D10CreateDevice1",
65         "D3D10CreateDeviceAndSwapChain1",
66         "D3D11CreateDevice",
67         "D3D11CreateDeviceAndSwapChain",
68     ]
69
70     def invokeFunction(self, function):
71         if function.name in self.createDeviceFunctionNames:
72             # create windows as neccessary
73             if 'pSwapChainDesc' in function.argNames():
74                 print r'    createWindow(pSwapChainDesc);'
75
76             # Compensate for the fact we don't trace DXGI object creation
77             if function.name.startswith('D3D11CreateDevice'):
78                 print r'    if (DriverType == D3D_DRIVER_TYPE_UNKNOWN && !pAdapter) {'
79                 print r'        DriverType = D3D_DRIVER_TYPE_HARDWARE;'
80                 print r'    }'
81
82             if function.name.startswith('D3D10CreateDevice'):
83                 # Toggle debugging
84                 print r'    Flags &= ~D3D10_CREATE_DEVICE_DEBUG;'
85                 print r'    if (retrace::debug) {'
86                 print r'        if (LoadLibraryA("d3d10sdklayers")) {'
87                 print r'            Flags |= D3D10_CREATE_DEVICE_DEBUG;'
88                 print r'        }'
89                 print r'    }'
90
91                 # Force driver
92                 self.forceDriver('D3D10_DRIVER_TYPE')
93
94             if function.name.startswith('D3D11CreateDevice'):
95                 # Toggle debugging
96                 print r'    Flags &= ~D3D11_CREATE_DEVICE_DEBUG;'
97                 print r'    if (retrace::debug) {'
98                 print r'        OSVERSIONINFO osvi;'
99                 print r'        BOOL bIsWindows8orLater;'
100                 print r'        ZeroMemory(&osvi, sizeof osvi);'
101                 print r'        osvi.dwOSVersionInfoSize = sizeof osvi;'
102                 print r'        GetVersionEx(&osvi);'
103                 print r'        bIsWindows8orLater = '
104                 print r'            (osvi.dwMajorVersion > 6) ||'
105                 print r'            (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion >= 2);'
106                 print r'        const char *szD3d11SdkLayers = bIsWindows8orLater ? "d3d11_1sdklayers" : "d3d11sdklayers";'
107                 print r'        if (LoadLibraryA(szD3d11SdkLayers)) {'
108                 print r'            Flags |= D3D11_CREATE_DEVICE_DEBUG;'
109                 print r'        }'
110                 print r'    }'
111
112                 # Force driver
113                 self.forceDriver('D3D_DRIVER_TYPE')
114
115         Retracer.invokeFunction(self, function)
116
117         if function.name in self.createDeviceFunctionNames:
118             print r'    if (FAILED(_result)) {'
119
120             if function.name.startswith('D3D10CreateDevice'):
121                 print r'        if (_result == E_FAIL && (Flags & D3D10_CREATE_DEVICE_DEBUG)) {'
122                 print r'            retrace::warning(call) << "debug layer (d3d10sdklayers.dll) not installed\n";'
123                 print r'        }'
124
125             if function.name.startswith('D3D11CreateDevice'):
126                 print r'        if (_result == E_FAIL && (Flags & D3D11_CREATE_DEVICE_DEBUG)) {'
127                 print r'            retrace::warning(call) << "debug layer (d3d11sdklayers.dll for Windows 7, d3d11_1sdklayers.dll for Windows 8 or Windows 7 with KB 2670838) not properly installed\n";'
128                 print r'        }'
129
130             print r'        exit(1);'
131             print r'    }'
132
133     def forceDriver(self, enum):
134         # This can only work when pAdapter is NULL. For non-NULL pAdapter we
135         # need to override inside the EnumAdapters call below
136         print r'    if (pAdapter == NULL) {'
137         print r'        switch (retrace::driver) {'
138         print r'        case retrace::DRIVER_HARDWARE:'
139         print r'            DriverType = %s_HARDWARE;' % enum
140         print r'            Software = NULL;'
141         print r'            break;'
142         print r'        case retrace::DRIVER_SOFTWARE:'
143         print r'            DriverType = %s_WARP;' % enum
144         print r'            Software = NULL;'
145         print r'            break;'
146         print r'        case retrace::DRIVER_REFERENCE:'
147         print r'            DriverType = %s_REFERENCE;' % enum
148         print r'            Software = NULL;'
149         print r'            break;'
150         print r'        case retrace::DRIVER_NULL:'
151         print r'            DriverType = %s_NULL;' % enum
152         print r'            Software = NULL;'
153         print r'            break;'
154         print r'        case retrace::DRIVER_MODULE:'
155         print r'            DriverType = %s_SOFTWARE;' % enum
156         print r'            Software = LoadLibraryA(retrace::driverModule);'
157         print r'            if (!Software) {'
158         print r'                retrace::warning(call) << "failed to load " << retrace::driverModule << "\n";'
159         print r'            }'
160         print r'            break;'
161         print r'        default:'
162         print r'            assert(0);'
163         print r'            /* fall-through */'
164         print r'        case retrace::DRIVER_DEFAULT:'
165         print r'            if (DriverType == %s_SOFTWARE) {' % enum
166         print r'                Software = LoadLibraryA("d3d10warp");'
167         print r'                if (!Software) {'
168         print r'                    retrace::warning(call) << "failed to load d3d10warp.dll\n";'
169         print r'                }'
170         print r'            }'
171         print r'            break;'
172         print r'        }'
173         print r'    } else {'
174         print r'        Software = NULL;'
175         print r'    }'
176
177     def invokeInterfaceMethod(self, interface, method):
178         # keep track of the last used device for state dumping
179         if interface.name in ('ID3D10Device', 'ID3D10Device1'):
180             if method.name == 'Release':
181                 print r'    d3d10Dumper.unbindDevice(_this);'
182             else:
183                 print r'    d3d10Dumper.bindDevice(_this);'
184         if interface.name in ('ID3D11DeviceContext', 'ID3D11DeviceContext1'):
185             if method.name == 'Release':
186                 print r'    d3d11Dumper.unbindDevice(_this);'
187             else:
188                 print r'    d3d11Dumper.bindDevice(_this);'
189
190         if interface.name == 'IDXGIFactory' and method.name == 'QueryInterface':
191             print r'    if (riid == IID_IDXGIFactoryDWM) {'
192             print r'        _this->AddRef();'
193             print r'        *ppvObj = new d3dretrace::CDXGIFactoryDWM(_this);'
194             print r'        _result = S_OK;'
195             print r'    } else {'
196             Retracer.invokeInterfaceMethod(self, interface, method)
197             print r'    }'
198             return
199
200         # create windows as neccessary
201         if method.name == 'CreateSwapChain':
202             print r'    createWindow(pDesc);'
203
204         # notify frame has been completed
205         if method.name == 'Present':
206             print r'    retrace::frameComplete(call);'
207
208         if 'pSharedResource' in method.argNames():
209             print r'    if (pSharedResource) {'
210             print r'        retrace::warning(call) << "shared surfaces unsupported\n";'
211             print r'        pSharedResource = NULL;'
212             print r'    }'
213
214         # Force driver
215         if interface.name.startswith('IDXGIFactory') and method.name == 'EnumAdapters':
216             print r'    const char *szSoftware = NULL;'
217             print r'    switch (retrace::driver) {'
218             print r'    case retrace::DRIVER_REFERENCE:'
219             print r'    case retrace::DRIVER_SOFTWARE:'
220             print r'        szSoftware = "d3d10warp.dll";'
221             print r'        break;'
222             print r'    case retrace::DRIVER_MODULE:'
223             print r'        szSoftware = retrace::driverModule;'
224             print r'        break;'
225             print r'    default:'
226             print r'        break;'
227             print r'    }'
228             print r'    HMODULE hSoftware = NULL;'
229             print r'    if (szSoftware) {'
230             print r'        hSoftware = LoadLibraryA(szSoftware);'
231             print r'        if (!hSoftware) {'
232             print r'            retrace::warning(call) << "failed to load " << szSoftware << "\n";'
233             print r'        }'
234             print r'    }'
235             print r'    if (hSoftware) {'
236             print r'        _result = _this->CreateSoftwareAdapter(hSoftware, ppAdapter);'
237             print r'    } else {'
238             Retracer.invokeInterfaceMethod(self, interface, method)
239             print r'    }'
240             return
241
242         if interface.name.startswith('ID3D10Device') and method.name == 'OpenSharedResource':
243             print r'    retrace::warning(call) << "replacing shared resource with checker pattern\n";'
244             print r'    D3D10_TEXTURE2D_DESC Desc;'
245             print r'    memset(&Desc, 0, sizeof Desc);'
246             print r'    Desc.Width = 8;'
247             print r'    Desc.Height = 8;'
248             print r'    Desc.MipLevels = 1;'
249             print r'    Desc.ArraySize = 1;'
250             print r'    Desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;'
251             print r'    Desc.SampleDesc.Count = 1;'
252             print r'    Desc.SampleDesc.Quality = 0;'
253             print r'    Desc.Usage = D3D10_USAGE_DEFAULT;'
254             print r'    Desc.BindFlags = D3D10_BIND_SHADER_RESOURCE | D3D10_BIND_RENDER_TARGET;'
255             print r'    Desc.CPUAccessFlags = 0x0;'
256             print r'    Desc.MiscFlags = 0 /* D3D10_RESOURCE_MISC_SHARED */;'
257             print r'''
258             const DWORD Checker[8][8] = {
259                { 0, ~0,  0, ~0,  0, ~0,  0, ~0, },
260                {~0,  0, ~0,  0, ~0,  0, ~0,  0, },
261                { 0, ~0,  0, ~0,  0, ~0,  0, ~0, },
262                {~0,  0, ~0,  0, ~0,  0, ~0,  0, },
263                { 0, ~0,  0, ~0,  0, ~0,  0, ~0, },
264                {~0,  0, ~0,  0, ~0,  0, ~0,  0, },
265                { 0, ~0,  0, ~0,  0, ~0,  0, ~0, },
266                {~0,  0, ~0,  0, ~0,  0, ~0,  0, }
267             };
268             const D3D10_SUBRESOURCE_DATA InitialData = {Checker, sizeof Checker[0], sizeof Checker};
269             '''
270             print r'    _result = _this->CreateTexture2D(&Desc, &InitialData, (ID3D10Texture2D**)ppResource);'
271             self.checkResult(method.type)
272             return
273
274         if method.name == 'Map':
275             # Reset _DO_NOT_WAIT flags. Otherwise they may fail, and we have no
276             # way to cope with it (other than retry).
277             mapFlagsArg = method.getArgByName('MapFlags')
278             for flag in mapFlagsArg.type.values:
279                 if flag.endswith('_MAP_FLAG_DO_NOT_WAIT'):
280                     print r'    MapFlags &= ~%s;' % flag
281
282         Retracer.invokeInterfaceMethod(self, interface, method)
283
284         # process events after presents
285         if method.name == 'Present':
286             print r'    d3dretrace::processEvents();'
287
288         if method.name == 'Map':
289             print '    _MAP_DESC _MapDesc;'
290             print '    _getMapDesc(_this, %s, _MapDesc);' % ', '.join(method.argNames())
291             print '    size_t _MappedSize = _MapDesc.Size;'
292             print '    if (_MapDesc.Size) {'
293             print '        _maps[_this] = _MapDesc.pData;'
294             print '    } else {'
295             print '        return;'
296             print '    }'
297         
298         if method.name == 'Unmap':
299             print '    VOID *_pbData = 0;'
300             print '    _pbData = _maps[_this];'
301             print '    if (_pbData) {'
302             print '        retrace::delRegionByPointer(_pbData);'
303             print '        _maps[_this] = 0;'
304             print '    }'
305
306         # Attach shader byte code for lookup
307         if 'pShaderBytecode' in method.argNames():
308             ppShader = method.args[-1]
309             assert ppShader.output
310             print r'    if (retrace::dumpingState && SUCCEEDED(_result)) {'
311             print r'        (*%s)->SetPrivateData(d3dstate::GUID_D3DSTATE, BytecodeLength, pShaderBytecode);' % ppShader.name
312             print r'    }'
313
314
315 def main():
316     print r'#define INITGUID'
317     print
318     print r'#include <string.h>'
319     print
320     print r'#include <iostream>'
321     print
322     print r'#include "d3dretrace.hpp"'
323     print
324
325     moduleNames = sys.argv[1:]
326
327     api = API()
328     
329     if moduleNames:
330         print r'#include "d3dretrace_dxgi.hpp"'
331         api.addModule(dxgi)
332     
333     if 'd3d10' in moduleNames:
334         if 'd3d10_1' in moduleNames:
335             print r'#include "d3d10_1imports.hpp"'
336             api.addModule(d3d10_1)
337         else:
338             print r'#include "d3d10imports.hpp"'
339         print r'#include "d3d10size.hpp"'
340         api.addModule(d3d10)
341         print
342         print '''static d3dretrace::D3DDumper<ID3D10Device> d3d10Dumper;'''
343         print
344
345     if 'd3d11' in moduleNames:
346         print r'#include "d3d11imports.hpp"'
347         if 'd3d11_1' in moduleNames:
348             print '#include <d3d11_1.h>'
349             import specs.d3d11_1
350         print r'#include "d3d11size.hpp"'
351         print r'#include "d3dstate.hpp"'
352         api.addModule(d3d11)
353         
354         print
355         print '''static d3dretrace::D3DDumper<ID3D11DeviceContext> d3d11Dumper;'''
356         print
357
358     retracer = D3DRetracer()
359     retracer.retraceApi(api)
360
361
362 if __name__ == '__main__':
363     main()