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