]> git.cworth.org Git - apitrace/blob - retrace/dxgiretrace.py
d3dretrace: Handle deferred d3d11 contexts better.
[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'    if (_this->GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE) {'
189                 print r'        d3d11Dumper.bindDevice(_this);'
190                 print r'    }'
191
192         if interface.name == 'IDXGIFactory' and method.name == 'QueryInterface':
193             print r'    if (riid == IID_IDXGIFactoryDWM) {'
194             print r'        _this->AddRef();'
195             print r'        *ppvObj = new d3dretrace::CDXGIFactoryDWM(_this);'
196             print r'        _result = S_OK;'
197             print r'    } else {'
198             Retracer.invokeInterfaceMethod(self, interface, method)
199             print r'    }'
200             return
201
202         # create windows as neccessary
203         if method.name == 'CreateSwapChain':
204             print r'    createWindow(pDesc);'
205
206         # notify frame has been completed
207         if method.name == 'Present':
208             print r'    retrace::frameComplete(call);'
209
210         if 'pSharedResource' in method.argNames():
211             print r'    if (pSharedResource) {'
212             print r'        retrace::warning(call) << "shared surfaces unsupported\n";'
213             print r'        pSharedResource = NULL;'
214             print r'    }'
215
216         # Force driver
217         if interface.name.startswith('IDXGIFactory') and method.name == 'EnumAdapters':
218             print r'    const char *szSoftware = NULL;'
219             print r'    switch (retrace::driver) {'
220             print r'    case retrace::DRIVER_REFERENCE:'
221             print r'    case retrace::DRIVER_SOFTWARE:'
222             print r'        szSoftware = "d3d10warp.dll";'
223             print r'        break;'
224             print r'    case retrace::DRIVER_MODULE:'
225             print r'        szSoftware = retrace::driverModule;'
226             print r'        break;'
227             print r'    default:'
228             print r'        break;'
229             print r'    }'
230             print r'    HMODULE hSoftware = NULL;'
231             print r'    if (szSoftware) {'
232             print r'        hSoftware = LoadLibraryA(szSoftware);'
233             print r'        if (!hSoftware) {'
234             print r'            retrace::warning(call) << "failed to load " << szSoftware << "\n";'
235             print r'        }'
236             print r'    }'
237             print r'    if (hSoftware) {'
238             print r'        _result = _this->CreateSoftwareAdapter(hSoftware, ppAdapter);'
239             print r'    } else {'
240             Retracer.invokeInterfaceMethod(self, interface, method)
241             print r'    }'
242             return
243
244         if interface.name.startswith('ID3D10Device') and method.name == 'OpenSharedResource':
245             print r'    retrace::warning(call) << "replacing shared resource with checker pattern\n";'
246             print r'    D3D10_TEXTURE2D_DESC Desc;'
247             print r'    memset(&Desc, 0, sizeof Desc);'
248             print r'    Desc.Width = 8;'
249             print r'    Desc.Height = 8;'
250             print r'    Desc.MipLevels = 1;'
251             print r'    Desc.ArraySize = 1;'
252             print r'    Desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;'
253             print r'    Desc.SampleDesc.Count = 1;'
254             print r'    Desc.SampleDesc.Quality = 0;'
255             print r'    Desc.Usage = D3D10_USAGE_DEFAULT;'
256             print r'    Desc.BindFlags = D3D10_BIND_SHADER_RESOURCE | D3D10_BIND_RENDER_TARGET;'
257             print r'    Desc.CPUAccessFlags = 0x0;'
258             print r'    Desc.MiscFlags = 0 /* D3D10_RESOURCE_MISC_SHARED */;'
259             print r'''
260             const DWORD Checker[8][8] = {
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                { 0, ~0,  0, ~0,  0, ~0,  0, ~0, },
268                {~0,  0, ~0,  0, ~0,  0, ~0,  0, }
269             };
270             const D3D10_SUBRESOURCE_DATA InitialData = {Checker, sizeof Checker[0], sizeof Checker};
271             '''
272             print r'    _result = _this->CreateTexture2D(&Desc, &InitialData, (ID3D10Texture2D**)ppResource);'
273             self.checkResult(method.type)
274             return
275
276         if method.name == 'Map':
277             # Reset _DO_NOT_WAIT flags. Otherwise they may fail, and we have no
278             # way to cope with it (other than retry).
279             mapFlagsArg = method.getArgByName('MapFlags')
280             for flag in mapFlagsArg.type.values:
281                 if flag.endswith('_MAP_FLAG_DO_NOT_WAIT'):
282                     print r'    MapFlags &= ~%s;' % flag
283
284         Retracer.invokeInterfaceMethod(self, interface, method)
285
286         # process events after presents
287         if method.name == 'Present':
288             print r'    d3dretrace::processEvents();'
289
290         if method.name == 'Map':
291             print '    _MAP_DESC _MapDesc;'
292             print '    _getMapDesc(_this, %s, _MapDesc);' % ', '.join(method.argNames())
293             print '    size_t _MappedSize = _MapDesc.Size;'
294             print '    if (_MapDesc.Size) {'
295             print '        _maps[_this] = _MapDesc.pData;'
296             print '    } else {'
297             print '        return;'
298             print '    }'
299         
300         if method.name == 'Unmap':
301             print '    VOID *_pbData = 0;'
302             print '    _pbData = _maps[_this];'
303             print '    if (_pbData) {'
304             print '        retrace::delRegionByPointer(_pbData);'
305             print '        _maps[_this] = 0;'
306             print '    }'
307
308         # Attach shader byte code for lookup
309         if 'pShaderBytecode' in method.argNames():
310             ppShader = method.args[-1]
311             assert ppShader.output
312             print r'    if (retrace::dumpingState && SUCCEEDED(_result)) {'
313             print r'        (*%s)->SetPrivateData(d3dstate::GUID_D3DSTATE, BytecodeLength, pShaderBytecode);' % ppShader.name
314             print r'    }'
315
316
317 def main():
318     print r'#define INITGUID'
319     print
320     print r'#include <string.h>'
321     print
322     print r'#include <iostream>'
323     print
324     print r'#include "d3dretrace.hpp"'
325     print
326
327     moduleNames = sys.argv[1:]
328
329     api = API()
330     
331     if moduleNames:
332         print r'#include "d3dretrace_dxgi.hpp"'
333         api.addModule(dxgi)
334     
335     if 'd3d10' in moduleNames:
336         if 'd3d10_1' in moduleNames:
337             print r'#include "d3d10_1imports.hpp"'
338             api.addModule(d3d10_1)
339         else:
340             print r'#include "d3d10imports.hpp"'
341         print r'#include "d3d10size.hpp"'
342         api.addModule(d3d10)
343         print
344         print '''static d3dretrace::D3DDumper<ID3D10Device> d3d10Dumper;'''
345         print
346
347     if 'd3d11' in moduleNames:
348         print r'#include "d3d11imports.hpp"'
349         if 'd3d11_1' in moduleNames:
350             print '#include <d3d11_1.h>'
351             import specs.d3d11_1
352         print r'#include "d3d11size.hpp"'
353         print r'#include "d3dstate.hpp"'
354         api.addModule(d3d11)
355         
356         print
357         print '''static d3dretrace::D3DDumper<ID3D11DeviceContext> d3d11Dumper;'''
358         print
359
360     retracer = D3DRetracer()
361     retracer.retraceApi(api)
362
363
364 if __name__ == '__main__':
365     main()