]> git.cworth.org Git - apitrace/blob - retrace/dxgiretrace.py
d3dretrace: Add state dumping support for ID3D11DeviceContext1
[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'        if (LoadLibraryA("d3d11sdklayers")) {'
99                 print r'            Flags |= D3D11_CREATE_DEVICE_DEBUG;'
100                 print r'        }'
101                 print r'    }'
102
103                 # Force driver
104                 self.forceDriver('D3D_DRIVER_TYPE')
105
106         Retracer.invokeFunction(self, function)
107
108     def forceDriver(self, enum):
109         # This can only work when pAdapter is NULL. For non-NULL pAdapter we
110         # need to override inside the EnumAdapters call below
111         print r'    if (pAdapter == NULL) {'
112         print r'        switch (retrace::driver) {'
113         print r'        case retrace::DRIVER_HARDWARE:'
114         print r'            DriverType = %s_HARDWARE;' % enum
115         print r'            Software = NULL;'
116         print r'            break;'
117         print r'        case retrace::DRIVER_SOFTWARE:'
118         print r'            DriverType = %s_WARP;' % enum
119         print r'            Software = NULL;'
120         print r'            break;'
121         print r'        case retrace::DRIVER_REFERENCE:'
122         print r'            DriverType = %s_REFERENCE;' % enum
123         print r'            Software = NULL;'
124         print r'            break;'
125         print r'        case retrace::DRIVER_NULL:'
126         print r'            DriverType = %s_NULL;' % enum
127         print r'            Software = NULL;'
128         print r'            break;'
129         print r'        case retrace::DRIVER_MODULE:'
130         print r'            DriverType = %s_SOFTWARE;' % enum
131         print r'            Software = LoadLibraryA(retrace::driverModule);'
132         print r'            if (!Software) {'
133         print r'                retrace::warning(call) << "failed to load " << retrace::driverModule << "\n";'
134         print r'            }'
135         print r'            break;'
136         print r'        default:'
137         print r'            assert(0);'
138         print r'            /* fall-through */'
139         print r'        case retrace::DRIVER_DEFAULT:'
140         print r'            if (DriverType == %s_SOFTWARE) {' % enum
141         print r'                Software = LoadLibraryA("d3d10warp");'
142         print r'                if (!Software) {'
143         print r'                    retrace::warning(call) << "failed to load d3d10warp.dll\n";'
144         print r'                }'
145         print r'            }'
146         print r'            break;'
147         print r'        }'
148         print r'    } else {'
149         print r'        Software = NULL;'
150         print r'    }'
151
152     def invokeInterfaceMethod(self, interface, method):
153         # keep track of the last used device for state dumping
154         if interface.name in ('ID3D10Device', 'ID3D10Device1'):
155             if method.name == 'Release':
156                 print r'    d3d10Dumper.unbindDevice(_this);'
157             else:
158                 print r'    d3d10Dumper.bindDevice(_this);'
159         if interface.name in ('ID3D11DeviceContext', 'ID3D11DeviceContext1'):
160             if method.name == 'Release':
161                 print r'    d3d11Dumper.unbindDevice(_this);'
162             else:
163                 print r'    d3d11Dumper.bindDevice(_this);'
164
165         if interface.name == 'IDXGIFactory' and method.name == 'QueryInterface':
166             print r'    if (riid == IID_IDXGIFactoryDWM) {'
167             print r'        _this->AddRef();'
168             print r'        *ppvObj = new d3dretrace::CDXGIFactoryDWM(_this);'
169             print r'        _result = S_OK;'
170             print r'    } else {'
171             Retracer.invokeInterfaceMethod(self, interface, method)
172             print r'    }'
173             return
174
175         # create windows as neccessary
176         if method.name == 'CreateSwapChain':
177             print r'    createWindow(pDesc);'
178
179         # notify frame has been completed
180         if method.name == 'Present':
181             print r'    retrace::frameComplete(call);'
182
183         if 'pSharedResource' in method.argNames():
184             print r'    if (pSharedResource) {'
185             print r'        retrace::warning(call) << "shared surfaces unsupported\n";'
186             print r'        pSharedResource = NULL;'
187             print r'    }'
188
189         # Force driver
190         if interface.name.startswith('IDXGIFactory') and method.name == 'EnumAdapters':
191             print r'    const char *szSoftware = NULL;'
192             print r'    switch (retrace::driver) {'
193             print r'    case retrace::DRIVER_REFERENCE:'
194             print r'    case retrace::DRIVER_SOFTWARE:'
195             print r'        szSoftware = "d3d10warp.dll";'
196             print r'        break;'
197             print r'    case retrace::DRIVER_MODULE:'
198             print r'        szSoftware = retrace::driverModule;'
199             print r'        break;'
200             print r'    default:'
201             print r'        break;'
202             print r'    }'
203             print r'    HMODULE hSoftware = NULL;'
204             print r'    if (szSoftware) {'
205             print r'        hSoftware = LoadLibraryA(szSoftware);'
206             print r'        if (!hSoftware) {'
207             print r'            retrace::warning(call) << "failed to load " << szSoftware << "\n";'
208             print r'        }'
209             print r'    }'
210             print r'    if (hSoftware) {'
211             print r'        _result = _this->CreateSoftwareAdapter(hSoftware, ppAdapter);'
212             print r'    } else {'
213             Retracer.invokeInterfaceMethod(self, interface, method)
214             print r'    }'
215             return
216
217         if interface.name.startswith('ID3D10Device') and method.name == 'OpenSharedResource':
218             print r'    retrace::warning(call) << "replacing shared resource with checker pattern\n";'
219             print r'    D3D10_TEXTURE2D_DESC Desc;'
220             print r'    memset(&Desc, 0, sizeof Desc);'
221             print r'    Desc.Width = 8;'
222             print r'    Desc.Height = 8;'
223             print r'    Desc.MipLevels = 1;'
224             print r'    Desc.ArraySize = 1;'
225             print r'    Desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;'
226             print r'    Desc.SampleDesc.Count = 1;'
227             print r'    Desc.SampleDesc.Quality = 0;'
228             print r'    Desc.Usage = D3D10_USAGE_DEFAULT;'
229             print r'    Desc.BindFlags = D3D10_BIND_SHADER_RESOURCE | D3D10_BIND_RENDER_TARGET;'
230             print r'    Desc.CPUAccessFlags = 0x0;'
231             print r'    Desc.MiscFlags = 0 /* D3D10_RESOURCE_MISC_SHARED */;'
232             print r'''
233             const DWORD Checker[8][8] = {
234                { 0, ~0,  0, ~0,  0, ~0,  0, ~0, },
235                {~0,  0, ~0,  0, ~0,  0, ~0,  0, },
236                { 0, ~0,  0, ~0,  0, ~0,  0, ~0, },
237                {~0,  0, ~0,  0, ~0,  0, ~0,  0, },
238                { 0, ~0,  0, ~0,  0, ~0,  0, ~0, },
239                {~0,  0, ~0,  0, ~0,  0, ~0,  0, },
240                { 0, ~0,  0, ~0,  0, ~0,  0, ~0, },
241                {~0,  0, ~0,  0, ~0,  0, ~0,  0, }
242             };
243             const D3D10_SUBRESOURCE_DATA InitialData = {Checker, sizeof Checker[0], sizeof Checker};
244             '''
245             print r'    _result = _this->CreateTexture2D(&Desc, &InitialData, (ID3D10Texture2D**)ppResource);'
246             self.checkResult(method.type)
247             return
248
249         if method.name == 'Map':
250             # Reset _DO_NOT_WAIT flags. Otherwise they may fail, and we have no
251             # way to cope with it (other than retry).
252             mapFlagsArg = method.getArgByName('MapFlags')
253             for flag in mapFlagsArg.type.values:
254                 if flag.endswith('_MAP_FLAG_DO_NOT_WAIT'):
255                     print r'    MapFlags &= ~%s;' % flag
256
257         Retracer.invokeInterfaceMethod(self, interface, method)
258
259         # process events after presents
260         if method.name == 'Present':
261             print r'    d3dretrace::processEvents();'
262
263         if method.name == 'Map':
264             print '    VOID *_pbData = NULL;'
265             print '    size_t _MappedSize = 0;'
266             print '    _getMapInfo(_this, %s, _pbData, _MappedSize);' % ', '.join(method.argNames())
267             print '    if (_MappedSize) {'
268             print '        _maps[_this] = _pbData;'
269             print '    } else {'
270             print '        return;'
271             print '    }'
272         
273         if method.name == 'Unmap':
274             print '    VOID *_pbData = 0;'
275             print '    _pbData = _maps[_this];'
276             print '    if (_pbData) {'
277             print '        retrace::delRegionByPointer(_pbData);'
278             print '        _maps[_this] = 0;'
279             print '    }'
280
281         # Attach shader byte code for lookup
282         if 'pShaderBytecode' in method.argNames():
283             ppShader = method.args[-1]
284             assert ppShader.output
285             print r'    if (retrace::dumpingState && SUCCEEDED(_result)) {'
286             print r'        (*%s)->SetPrivateData(d3dstate::GUID_D3DSTATE, BytecodeLength, pShaderBytecode);' % ppShader.name
287             print r'    }'
288
289
290 def main():
291     print r'#define INITGUID'
292     print
293     print r'#include <string.h>'
294     print
295     print r'#include <iostream>'
296     print
297     print r'#include "d3dretrace.hpp"'
298     print
299
300     moduleNames = sys.argv[1:]
301
302     api = API()
303     
304     if moduleNames:
305         print r'#include "d3dretrace_dxgi.hpp"'
306         api.addModule(dxgi)
307     
308     if 'd3d10' in moduleNames:
309         if 'd3d10_1' in moduleNames:
310             print r'#include "d3d10_1imports.hpp"'
311             api.addModule(d3d10_1)
312         else:
313             print r'#include "d3d10imports.hpp"'
314         print r'#include "d3d10size.hpp"'
315         api.addModule(d3d10)
316         print
317         print '''static d3dretrace::D3DDumper<ID3D10Device> d3d10Dumper;'''
318         print
319
320     if 'd3d11' in moduleNames:
321         print r'#include "d3d11imports.hpp"'
322         if 'd3d11_1' in moduleNames:
323             print '#include <d3d11_1.h>'
324             import specs.d3d11_1
325         print r'#include "d3d11size.hpp"'
326         print r'#include "d3dstate.hpp"'
327         api.addModule(d3d11)
328         
329         print
330         print '''static d3dretrace::D3DDumper<ID3D11DeviceContext> d3d11Dumper;'''
331         print
332
333     retracer = D3DRetracer()
334     retracer.retraceApi(api)
335
336
337 if __name__ == '__main__':
338     main()