]> git.cworth.org Git - apitrace/blobdiff - retrace/dxgiretrace.py
d3dretrace: Add state dumping support for ID3D11DeviceContext1
[apitrace] / retrace / dxgiretrace.py
index c7baaf280b701e66f04b3223d97949fd60acd4b1..d6d7e96d3c9454a6523ba177b00be5dfac9af6d4 100644 (file)
@@ -29,6 +29,7 @@
 
 import sys
 from dllretrace import DllRetracer as Retracer
+import specs.dxgi
 from specs.stdapi import API
 from specs.dxgi import dxgi
 from specs.d3d10 import d3d10
@@ -45,13 +46,11 @@ class D3DRetracer(Retracer):
         print r'''
 static void 
 createWindow(DXGI_SWAP_CHAIN_DESC *pSwapChainDesc) {
-    if (pSwapChainDesc->Windowed) {
-        UINT Width  = pSwapChainDesc->BufferDesc.Width;
-        UINT Height = pSwapChainDesc->BufferDesc.Height;
-        if (!Width)  Width = 1024;
-        if (!Height) Height = 768;
-        pSwapChainDesc->OutputWindow = d3dretrace::createWindow(Width, Height);
-    }
+    UINT Width  = pSwapChainDesc->BufferDesc.Width;
+    UINT Height = pSwapChainDesc->BufferDesc.Height;
+    if (!Width)  Width = 1024;
+    if (!Height) Height = 768;
+    pSwapChainDesc->OutputWindow = d3dretrace::createWindow(Width, Height);
 }
 '''
 
@@ -74,22 +73,82 @@ createWindow(DXGI_SWAP_CHAIN_DESC *pSwapChainDesc) {
             if 'pSwapChainDesc' in function.argNames():
                 print r'    createWindow(pSwapChainDesc);'
 
-            # Compensate for the fact we don't trace the software renderer
-            # module LoadLibrary call
-            if 'Software' in function.argNames():
-                print r'    if (Software) {'
-                print r'        retrace::warning(call) << "using WARP for software device\n";'
-                print r'        Software = LoadLibraryA("d3d10warp");'
-                print r'    }'
-
             # Compensate for the fact we don't trace DXGI object creation
             if function.name.startswith('D3D11CreateDevice'):
                 print r'    if (DriverType == D3D_DRIVER_TYPE_UNKNOWN && !pAdapter) {'
                 print r'        DriverType = D3D_DRIVER_TYPE_HARDWARE;'
                 print r'    }'
 
+            if function.name.startswith('D3D10CreateDevice'):
+                # Toggle debugging
+                print r'    Flags &= ~D3D10_CREATE_DEVICE_DEBUG;'
+                print r'    if (retrace::debug) {'
+                print r'        if (LoadLibraryA("d3d10sdklayers")) {'
+                print r'            Flags |= D3D10_CREATE_DEVICE_DEBUG;'
+                print r'        }'
+                print r'    }'
+
+                # Force driver
+                self.forceDriver('D3D10_DRIVER_TYPE')
+
+            if function.name.startswith('D3D11CreateDevice'):
+                # Toggle debugging
+                print r'    Flags &= ~D3D11_CREATE_DEVICE_DEBUG;'
+                print r'    if (retrace::debug) {'
+                print r'        if (LoadLibraryA("d3d11sdklayers")) {'
+                print r'            Flags |= D3D11_CREATE_DEVICE_DEBUG;'
+                print r'        }'
+                print r'    }'
+
+                # Force driver
+                self.forceDriver('D3D_DRIVER_TYPE')
+
         Retracer.invokeFunction(self, function)
 
+    def forceDriver(self, enum):
+        # This can only work when pAdapter is NULL. For non-NULL pAdapter we
+        # need to override inside the EnumAdapters call below
+        print r'    if (pAdapter == NULL) {'
+        print r'        switch (retrace::driver) {'
+        print r'        case retrace::DRIVER_HARDWARE:'
+        print r'            DriverType = %s_HARDWARE;' % enum
+        print r'            Software = NULL;'
+        print r'            break;'
+        print r'        case retrace::DRIVER_SOFTWARE:'
+        print r'            DriverType = %s_WARP;' % enum
+        print r'            Software = NULL;'
+        print r'            break;'
+        print r'        case retrace::DRIVER_REFERENCE:'
+        print r'            DriverType = %s_REFERENCE;' % enum
+        print r'            Software = NULL;'
+        print r'            break;'
+        print r'        case retrace::DRIVER_NULL:'
+        print r'            DriverType = %s_NULL;' % enum
+        print r'            Software = NULL;'
+        print r'            break;'
+        print r'        case retrace::DRIVER_MODULE:'
+        print r'            DriverType = %s_SOFTWARE;' % enum
+        print r'            Software = LoadLibraryA(retrace::driverModule);'
+        print r'            if (!Software) {'
+        print r'                retrace::warning(call) << "failed to load " << retrace::driverModule << "\n";'
+        print r'            }'
+        print r'            break;'
+        print r'        default:'
+        print r'            assert(0);'
+        print r'            /* fall-through */'
+        print r'        case retrace::DRIVER_DEFAULT:'
+        print r'            if (DriverType == %s_SOFTWARE) {' % enum
+        print r'                Software = LoadLibraryA("d3d10warp");'
+        print r'                if (!Software) {'
+        print r'                    retrace::warning(call) << "failed to load d3d10warp.dll\n";'
+        print r'                }'
+        print r'            }'
+        print r'            break;'
+        print r'        }'
+        print r'    } else {'
+        print r'        Software = NULL;'
+        print r'    }'
+
     def invokeInterfaceMethod(self, interface, method):
         # keep track of the last used device for state dumping
         if interface.name in ('ID3D10Device', 'ID3D10Device1'):
@@ -97,12 +156,22 @@ createWindow(DXGI_SWAP_CHAIN_DESC *pSwapChainDesc) {
                 print r'    d3d10Dumper.unbindDevice(_this);'
             else:
                 print r'    d3d10Dumper.bindDevice(_this);'
-        if interface.name in ('ID3D11DeviceContext',):
+        if interface.name in ('ID3D11DeviceContext', 'ID3D11DeviceContext1'):
             if method.name == 'Release':
                 print r'    d3d11Dumper.unbindDevice(_this);'
             else:
                 print r'    d3d11Dumper.bindDevice(_this);'
 
+        if interface.name == 'IDXGIFactory' and method.name == 'QueryInterface':
+            print r'    if (riid == IID_IDXGIFactoryDWM) {'
+            print r'        _this->AddRef();'
+            print r'        *ppvObj = new d3dretrace::CDXGIFactoryDWM(_this);'
+            print r'        _result = S_OK;'
+            print r'    } else {'
+            Retracer.invokeInterfaceMethod(self, interface, method)
+            print r'    }'
+            return
+
         # create windows as neccessary
         if method.name == 'CreateSwapChain':
             print r'    createWindow(pDesc);'
@@ -117,6 +186,74 @@ createWindow(DXGI_SWAP_CHAIN_DESC *pSwapChainDesc) {
             print r'        pSharedResource = NULL;'
             print r'    }'
 
+        # Force driver
+        if interface.name.startswith('IDXGIFactory') and method.name == 'EnumAdapters':
+            print r'    const char *szSoftware = NULL;'
+            print r'    switch (retrace::driver) {'
+            print r'    case retrace::DRIVER_REFERENCE:'
+            print r'    case retrace::DRIVER_SOFTWARE:'
+            print r'        szSoftware = "d3d10warp.dll";'
+            print r'        break;'
+            print r'    case retrace::DRIVER_MODULE:'
+            print r'        szSoftware = retrace::driverModule;'
+            print r'        break;'
+            print r'    default:'
+            print r'        break;'
+            print r'    }'
+            print r'    HMODULE hSoftware = NULL;'
+            print r'    if (szSoftware) {'
+            print r'        hSoftware = LoadLibraryA(szSoftware);'
+            print r'        if (!hSoftware) {'
+            print r'            retrace::warning(call) << "failed to load " << szSoftware << "\n";'
+            print r'        }'
+            print r'    }'
+            print r'    if (hSoftware) {'
+            print r'        _result = _this->CreateSoftwareAdapter(hSoftware, ppAdapter);'
+            print r'    } else {'
+            Retracer.invokeInterfaceMethod(self, interface, method)
+            print r'    }'
+            return
+
+        if interface.name.startswith('ID3D10Device') and method.name == 'OpenSharedResource':
+            print r'    retrace::warning(call) << "replacing shared resource with checker pattern\n";'
+            print r'    D3D10_TEXTURE2D_DESC Desc;'
+            print r'    memset(&Desc, 0, sizeof Desc);'
+            print r'    Desc.Width = 8;'
+            print r'    Desc.Height = 8;'
+            print r'    Desc.MipLevels = 1;'
+            print r'    Desc.ArraySize = 1;'
+            print r'    Desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;'
+            print r'    Desc.SampleDesc.Count = 1;'
+            print r'    Desc.SampleDesc.Quality = 0;'
+            print r'    Desc.Usage = D3D10_USAGE_DEFAULT;'
+            print r'    Desc.BindFlags = D3D10_BIND_SHADER_RESOURCE | D3D10_BIND_RENDER_TARGET;'
+            print r'    Desc.CPUAccessFlags = 0x0;'
+            print r'    Desc.MiscFlags = 0 /* D3D10_RESOURCE_MISC_SHARED */;'
+            print r'''
+            const DWORD Checker[8][8] = {
+               { 0, ~0,  0, ~0,  0, ~0,  0, ~0, },
+               {~0,  0, ~0,  0, ~0,  0, ~0,  0, },
+               { 0, ~0,  0, ~0,  0, ~0,  0, ~0, },
+               {~0,  0, ~0,  0, ~0,  0, ~0,  0, },
+               { 0, ~0,  0, ~0,  0, ~0,  0, ~0, },
+               {~0,  0, ~0,  0, ~0,  0, ~0,  0, },
+               { 0, ~0,  0, ~0,  0, ~0,  0, ~0, },
+               {~0,  0, ~0,  0, ~0,  0, ~0,  0, }
+            };
+            const D3D10_SUBRESOURCE_DATA InitialData = {Checker, sizeof Checker[0], sizeof Checker};
+            '''
+            print r'    _result = _this->CreateTexture2D(&Desc, &InitialData, (ID3D10Texture2D**)ppResource);'
+            self.checkResult(method.type)
+            return
+
+        if method.name == 'Map':
+            # Reset _DO_NOT_WAIT flags. Otherwise they may fail, and we have no
+            # way to cope with it (other than retry).
+            mapFlagsArg = method.getArgByName('MapFlags')
+            for flag in mapFlagsArg.type.values:
+                if flag.endswith('_MAP_FLAG_DO_NOT_WAIT'):
+                    print r'    MapFlags &= ~%s;' % flag
+
         Retracer.invokeInterfaceMethod(self, interface, method)
 
         # process events after presents
@@ -141,8 +278,18 @@ createWindow(DXGI_SWAP_CHAIN_DESC *pSwapChainDesc) {
             print '        _maps[_this] = 0;'
             print '    }'
 
+        # Attach shader byte code for lookup
+        if 'pShaderBytecode' in method.argNames():
+            ppShader = method.args[-1]
+            assert ppShader.output
+            print r'    if (retrace::dumpingState && SUCCEEDED(_result)) {'
+            print r'        (*%s)->SetPrivateData(d3dstate::GUID_D3DSTATE, BytecodeLength, pShaderBytecode);' % ppShader.name
+            print r'    }'
+
 
 def main():
+    print r'#define INITGUID'
+    print
     print r'#include <string.h>'
     print
     print r'#include <iostream>'
@@ -155,13 +302,12 @@ def main():
     api = API()
     
     if moduleNames:
+        print r'#include "d3dretrace_dxgi.hpp"'
         api.addModule(dxgi)
     
     if 'd3d10' in moduleNames:
         if 'd3d10_1' in moduleNames:
             print r'#include "d3d10_1imports.hpp"'
-            # D3D10CreateBlob is duplicated in d3d10 and d3d10_1
-            d3d10_1.functions = [function for function in d3d10_1.functions if function.name != 'D3D10CreateBlob']
             api.addModule(d3d10_1)
         else:
             print r'#include "d3d10imports.hpp"'