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