def invokeFunction(self, function): if function.name in self.createDeviceFunctionNames: # create windows as neccessary if 'pSwapChainDesc' in function.argNames(): print r' d3dretrace::createWindowForSwapChain(pSwapChainDesc);' # 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' if (retrace::debug >= 2) {' print r' Flags |= D3D10_CREATE_DEVICE_DEBUG;' print r' } else if (retrace::debug < 0) {' print r' Flags &= ~D3D10_CREATE_DEVICE_DEBUG;' print r' }' # Force driver self.forceDriver('D3D10_DRIVER_TYPE') if function.name.startswith('D3D11CreateDevice'): # Toggle debugging print r' if (retrace::debug >= 2) {' print r' Flags |= D3D11_CREATE_DEVICE_DEBUG;' print r' } else if (retrace::debug < 0) {' print r' Flags &= ~D3D11_CREATE_DEVICE_DEBUG;' print r' }' # Force driver self.forceDriver('D3D_DRIVER_TYPE') Retracer.invokeFunction(self, function)
def retraceApi(self, api): print '// Swizzling mapping for lock addresses' print 'typedef std::pair<void *, UINT> MappingKey;' print 'static std::map<MappingKey, void *> _maps;' print Retracer.retraceApi(self, api)
def invokeFunction(self, function): if function.name in self.createDeviceFunctionNames: # create windows as neccessary if 'pSwapChainDesc' in function.argNames(): print r' d3dretrace::createWindowForSwapChain(pSwapChainDesc);' # 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' if (retrace::debug) {' print r' Flags |= D3D10_CREATE_DEVICE_DEBUG;' print r' } else {' print r' Flags &= ~D3D10_CREATE_DEVICE_DEBUG;' print r' }' # Force driver self.forceDriver('D3D10_DRIVER_TYPE') if function.name.startswith('D3D11CreateDevice'): # Toggle debugging print r' if (retrace::debug) {' print r' Flags |= D3D11_CREATE_DEVICE_DEBUG;' print r' } else {' print r' Flags &= ~D3D11_CREATE_DEVICE_DEBUG;' print r' }' # Force driver self.forceDriver('D3D_DRIVER_TYPE') Retracer.invokeFunction(self, function)
def retraceApi(self, api): print '// Swizzling mapping for lock addresses' print 'static std::map<void *, void *> _maps;' print self.table_name = 'd3dretrace::dxgi_callbacks' Retracer.retraceApi(self, api)
def retraceApi(self, api): print 'static const GUID GUID_D3DRETRACE = {0x7D71CAC9,0x7F58,0x432C,{0xA9,0x75,0xA1,0x9F,0xCF,0xCE,0xFD,0x14}};' print self.table_name = 'd3dretrace::%s_callbacks' % api.name.lower() Retracer.retraceApi(self, api)
def handleFailure(self, interface, methodOrFunction): # Catch when device is removed, and report the reason. if interface is not None: print(r' if (_result == DXGI_ERROR_DEVICE_REMOVED) {') print(r' d3dretrace::deviceRemoved(call, _this);') print(r' }') Retracer.handleFailure(self, interface, methodOrFunction)
def retraceApi(self, api): print '// Swizzling mapping for lock addresses, mapping a (pDeviceContext, pResource, Subresource) -> void *' print 'typedef std::pair< IUnknown *, UINT > SubresourceKey;' print 'static std::map< IUnknown *, std::map< SubresourceKey, void * > > g_Maps;' print self.table_name = 'd3dretrace::dxgi_callbacks' Retracer.retraceApi(self, api)
def doInvokeInterfaceMethod(self, interface, method): Retracer.doInvokeInterfaceMethod(self, interface, method) # Keep retrying IDirectXVideoDecoder::BeginFrame when returns E_PENDING if interface.name == 'IDirectXVideoDecoder' and method.name == 'BeginFrame': print r' while (_result == E_PENDING) {' print r' Sleep(1);' Retracer.doInvokeInterfaceMethod(self, interface, method) print r' }'
def invokeFunction(self, function): if function.name in self.createDeviceFunctionNames: # create windows as neccessary if 'pSwapChainDesc' in function.argNames(): print(r' if (pSwapChainDesc) {') print(r' d3dretrace::createWindowForSwapChain(pSwapChainDesc);') 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' if (retrace::debug >= 2) {') print(r' Flags |= D3D10_CREATE_DEVICE_DEBUG;') print(r' } else if (retrace::debug < 0) {') print(r' Flags &= ~D3D10_CREATE_DEVICE_DEBUG;') print(r' }') # Force driver self.forceDriver('D3D10_DRIVER_TYPE') if function.name.startswith('D3D11CreateDevice'): # Toggle debugging print(r' if (retrace::debug >= 2) {') print(r' Flags |= D3D11_CREATE_DEVICE_DEBUG;') print(r' } else if (retrace::debug < 0) {') print(r' Flags &= ~D3D11_CREATE_DEVICE_DEBUG;') print(r' }') print(r' if (IsWindows8OrGreater()) {') print(r' Flags |= D3D11_CREATE_DEVICE_DISABLE_GPU_TIMEOUT;') print(r' }') # Force driver self.forceDriver('D3D_DRIVER_TYPE') Retracer.invokeFunction(self, function) if function.name in self.createDeviceFunctionNames: print(r''' if (retrace::driver != retrace::DRIVER_DEFAULT && ppDevice && *ppDevice) { com_ptr<IDXGIDevice> pDXGIDevice; HRESULT hr = (*ppDevice)->QueryInterface(IID_IDXGIDevice, (void **)&pDXGIDevice); assert(SUCCEEDED(hr)); com_ptr<IDXGIAdapter> pDXGIAdapter; hr = pDXGIDevice->GetAdapter(&pDXGIAdapter); assert(SUCCEEDED(hr)); DXGI_ADAPTER_DESC AdapterDesc; hr = pDXGIAdapter->GetDesc(&AdapterDesc); assert(SUCCEEDED(hr)); std::wcerr << L"info: using " << AdapterDesc.Description << std::endl; } ''')
def retraceApi(self, api): print '// Swizzling mapping for lock addresses' print 'static std::map<void *, void *> _maps;' print # TODO: Keep a table of windows print 'static HWND g_hWnd;' print Retracer.retraceApi(self, api)
def doInvokeInterfaceMethod(self, interface, method): Retracer.doInvokeInterfaceMethod(self, interface, method) # Keep retrying ID3D11VideoContext::DecoderBeginFrame when returns E_PENDING if interface.name == 'ID3D11VideoContext' and method.name == 'DecoderBeginFrame': print r' while (_result == D3DERR_WASSTILLDRAWING || _result == E_PENDING) {' print r' Sleep(1);' Retracer.doInvokeInterfaceMethod(self, interface, method) print r' }'
def invokeFunction(self, function): if function.name in self.createDeviceFunctionNames: # create windows as neccessary if 'pSwapChainDesc' in function.argNames(): print(r' if (pSwapChainDesc) {') print( r' d3dretrace::createWindowForSwapChain(pSwapChainDesc);' ) 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' if (retrace::debug >= 2) {') print(r' Flags |= D3D10_CREATE_DEVICE_DEBUG;') print(r' } else if (retrace::debug < 0) {') print(r' Flags &= ~D3D10_CREATE_DEVICE_DEBUG;') print(r' }') # D3D10CreateDevice(D3D10_DRIVER_TYPE_REFERENCE) fails with # DXGI_ERROR_UNSUPPORTED on 64bits. print(r'#ifdef _WIN64') print(r' if (DriverType == D3D10_DRIVER_TYPE_REFERENCE) {') print(r' DriverType = D3D10_DRIVER_TYPE_WARP;') print(r' }') print(r'#endif') # Force driver self.forceDriver('D3D10_DRIVER_TYPE_HARDWARE') if function.name.startswith('D3D11CreateDevice'): # Toggle debugging print(r' if (retrace::debug >= 2) {') print(r' Flags |= D3D11_CREATE_DEVICE_DEBUG;') print(r' } else if (retrace::debug < 0) {') print(r' Flags &= ~D3D11_CREATE_DEVICE_DEBUG;') print(r' }') print(r' if (IsWindows8OrGreater()) {') print( r' Flags |= D3D11_CREATE_DEVICE_DISABLE_GPU_TIMEOUT;' ) print(r' }') # Force driver self.forceDriver('D3D_DRIVER_TYPE_UNKNOWN') Retracer.invokeFunction(self, function)
def extractArg(self, function, arg, arg_type, lvalue, rvalue): # Handle DDCREATE_* flags if arg.type is DDCREATE_LPGUID: print ' if (%s.toArray()) {' % rvalue Retracer.extractArg(self, function, arg, arg_type, lvalue, rvalue) print ' } else {' print ' %s = static_cast<%s>(%s.toPointer());' % (lvalue, arg_type, rvalue) print ' }' return Retracer.extractArg(self, function, arg, arg_type, lvalue, rvalue)
def handleFailure(self, interface, methodOrFunction): # Catch when device is removed, and report the reason. if interface is not None: getDeviceRemovedReasonMethod = interface.getMethodByName("GetDeviceRemovedReason") if getDeviceRemovedReasonMethod is not None: print r' if (_result == DXGI_ERROR_DEVICE_REMOVED) {' print r' HRESULT _reason = _this->GetDeviceRemovedReason();' print r' retrace::failed(call, _reason);' print r' exit(EXIT_FAILURE);' print r' }' Retracer.handleFailure(self, interface, methodOrFunction)
def invokeInterfaceMethod(self, interface, method): # keep track of the last used device for state dumping if interface.name in ('IDirect3DDevice9', 'IDirect3DDevice9Ex'): print r' d3dretrace::pLastDirect3DDevice9 = _this;' # create windows as neccessary if method.name in ('CreateDevice', 'CreateDeviceEx', 'CreateAdditionalSwapChain'): print r' HWND hWnd = d3dretrace::createWindow(pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight);' print r' pPresentationParameters->hDeviceWindow = hWnd;' if 'hFocusWindow' in method.argNames(): print r' hFocusWindow = hWnd;' if method.name in ('Reset', 'ResetEx'): print r' if (pPresentationParameters->Windowed) {' print r' d3dretrace::resizeWindow(pPresentationParameters->hDeviceWindow, pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight);' print r' }' # notify frame has been completed if method.name == 'Present': print r' retrace::frameComplete(call);' print r' hDestWindowOverride = NULL;' if 'pSharedHandle' in method.argNames(): print r' if (pSharedHandle) {' print r' retrace::warning(call) << "shared surfaces unsupported\n";' print r' pSharedHandle = NULL;' print r' }' Retracer.invokeInterfaceMethod(self, interface, method) # process events after presents if method.name == 'Present': print r' d3dretrace::processEvents();' # check errors if str(method.type) == 'HRESULT': print r' if (FAILED(_result)) {' print r' retrace::warning(call) << "failed\n";' print r' }' if method.name in ('Lock', 'LockRect', 'LockBox'): print ' VOID *_pbData = NULL;' print ' size_t _LockedSize = 0;' print ' _getLockInfo(_this, %s, _pbData, _LockedSize);' % ', '.join(method.argNames()[:-1]) print ' _this->SetPrivateData(GUID_D3DRETRACE, &_pbData, sizeof _pbData, 0);' if method.name in ('Unlock', 'UnlockRect', 'UnlockBox'): print ' VOID *_pbData = 0;' print ' DWORD dwSizeOfData = sizeof _pbData;' print ' _this->GetPrivateData(GUID_D3DRETRACE, &_pbData, &dwSizeOfData);' print ' if (_pbData) {' print ' retrace::delRegionByPointer(_pbData);' print ' }'
def handleFailure(self, interface, methodOrFunction): if methodOrFunction.name in self.createDeviceMethodNames: print r' exit(EXIT_FAILURE);' return # https://msdn.microsoft.com/en-us/library/windows/desktop/bb324479.aspx if methodOrFunction.name in ('Present', 'PresentEx'): print r' if (_result == D3DERR_DEVICELOST) {' print r' exit(EXIT_FAILURE);' print r' }' Retracer.handleFailure(self, interface, methodOrFunction)
def extractArg(self, function, arg, arg_type, lvalue, rvalue): # Handle DDCREATE_* flags if arg.type is DDCREATE_LPGUID: print ' if (%s.toArray()) {' % rvalue Retracer.extractArg(self, function, arg, arg_type, lvalue, rvalue) print ' } else {' print ' %s = static_cast<%s>(%s.toPointer());' % ( lvalue, arg_type, rvalue) print ' }' return Retracer.extractArg(self, function, arg, arg_type, lvalue, rvalue)
def invokeFunction(self, function): if function.name in ('Direct3DCreate9', 'Direct3DCreate9Ex'): print 'if (retrace::debug && !g_szD3D9DllName) {' print ' /* ' print ' * XXX: D3D9D only works for simple things, it often introduces errors' print ' * on complex traces, or traces which use unofficial D3D9 features.' print ' */' print ' if (0) {' print ' g_szD3D9DllName = "d3d9d.dll";' print ' }' print '}' Retracer.invokeFunction(self, function)
def retraceInterfaceMethodBody(self, interface, method): Retracer.retraceInterfaceMethodBody(self, interface, method) # Add pitch swizzling information to the region if method.name == 'Map' and interface.name not in ('ID3D10Buffer', 'ID3D10Texture1D'): if interface.name.startswith('ID3D11DeviceContext'): outArg = method.getArgByName('pMappedResource') memberNames = ('pData', 'RowPitch', 'DepthPitch') elif interface.name.startswith('ID3D10'): outArg = method.args[-1] memberNames = ('pData', 'RowPitch', 'DepthPitch') elif interface.name == 'IDXGISurface': outArg = method.getArgByName('pLockedRect') memberNames = ('pBits', 'Pitch', None) else: raise NotImplementedError struct = outArg.type.type dataMemberName, rowPitchMemberName, depthPitchMemberName = memberNames dataMemberIndex = struct.getMemberByName(dataMemberName) rowPitchMemberIndex = struct.getMemberByName(rowPitchMemberName) print r' if (_pbData && %s->%s != 0) {' % (outArg.name, rowPitchMemberName) print r' const trace::Array *_%s = call.arg(%u).toArray();' % ( outArg.name, outArg.index) print r' if (%s) {' % outArg.name print r' const trace::Struct *_struct = _%s->values[0]->toStruct();' % ( outArg.name) print r' if (_struct) {' print r' unsigned long long traceAddress = _struct->members[%u]->toUIntPtr();' % dataMemberIndex print r' int traceRowPitch = _struct->members[%u]->toSInt();' % rowPitchMemberIndex print r' int realRowPitch = %s->%s;' % ( outArg.name, rowPitchMemberName) print r' if (realRowPitch && traceRowPitch != realRowPitch) {' print r' retrace::setRegionPitch(traceAddress, 2, traceRowPitch, realRowPitch);' print r' }' try: depthPitchMemberIndex = struct.getMemberByName( depthPitchMemberName) except ValueError: assert len(struct.members) < 3 pass else: assert depthPitchMemberName == 'DepthPitch' print r' if (%s->DepthPitch) {' % outArg.name print r' retrace::checkMismatch(call, "DepthPitch", _struct->members[%u], %s->DepthPitch);' % ( struct.getMemberByName('DepthPitch'), outArg.name) print r' }' print r' }' print r' }' print r' }'
def extractArg(self, function, arg, arg_type, lvalue, rvalue): # Set object names if function.name == 'SetPrivateData' and arg.name == 'pData': iid = function.args[0].name print r' if (%s != WKPDID_D3DDebugObjectName) {' % iid print r' return;' print r' }' # Interpret argument as string Retracer.extractArg(self, function, arg, LPCSTR, lvalue, rvalue) print r' assert(pData);' print r' assert(DataSize == strlen((const char *)pData));' return Retracer.extractArg(self, function, arg, arg_type, lvalue, rvalue)
def invokeFunction(self, function): if function.name in ('Direct3DCreate9', 'Direct3DCreate9Ex'): print 'if (retrace::debug >= 2 && !g_szD3D9DllName && LoadLibraryA("d3d9d.dll")) {' print ' /*' print ' * D3D9D only works for simple applications, it will often report bogus errors' print ' * on complex traces, or traces which use unofficial D3D9 features.' print ' */' print ' g_szD3D9DllName = "d3d9d.dll";' print ' SDKVersion |= 0x80000000;' print '} else {' print ' SDKVersion &= ~0x80000000;' print '}' Retracer.invokeFunction(self, function)
def extractArg(self, function, arg, arg_type, lvalue, rvalue): # Set object names if function.name == "SetPrivateData" and arg.name == "pData": iid = function.args[0].name print r" if (%s != WKPDID_D3DDebugObjectName) {" % iid print r" return;" print r" }" # Interpret argument as string Retracer.extractArg(self, function, arg, LPCSTR, lvalue, rvalue) print r" assert(pData);" print r" assert(DataSize == strlen((const char *)pData));" return Retracer.extractArg(self, function, arg, arg_type, lvalue, rvalue)
def invokeInterfaceMethod(self, interface, method): # keep track of the last used device for state dumping if interface.name in ('IDirect3DDevice9', 'IDirect3DDevice9Ex'): print r' d3dretrace::pLastDirect3DDevice9 = _this;' # create windows as neccessary if method.name in ('CreateDevice', 'CreateDeviceEx', 'CreateAdditionalSwapChain'): print r' HWND hWnd = d3dretrace::createWindow(pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight);' print r' pPresentationParameters->hDeviceWindow = hWnd;' if 'hFocusWindow' in method.argNames(): print r' hFocusWindow = hWnd;' # notify frame has been completed if method.name == 'Present': print r' retrace::frameComplete(call);' print r' hDestWindowOverride = NULL;' if 'pSharedHandle' in method.argNames(): print r' if (pSharedHandle) {' print r' retrace::warning(call) << "shared surfaces unsupported\n";' print r' pSharedHandle = NULL;' print r' }' Retracer.invokeInterfaceMethod(self, interface, method) # check errors if str(method.type) == 'HRESULT': print r' if (FAILED(_result)) {' print r' retrace::warning(call) << "failed\n";' print r' }' if method.name in ('Lock', 'LockRect', 'LockBox'): print ' VOID *_pbData = NULL;' print ' size_t _LockedSize = 0;' print ' _getLockInfo(_this, %s, _pbData, _LockedSize);' % ', '.join( method.argNames()[:-1]) print ' _this->SetPrivateData(GUID_D3DRETRACE, &_pbData, sizeof _pbData, 0);' if method.name in ('Unlock', 'UnlockRect', 'UnlockBox'): print ' VOID *_pbData = 0;' print ' DWORD dwSizeOfData = sizeof _pbData;' print ' _this->GetPrivateData(GUID_D3DRETRACE, &_pbData, &dwSizeOfData);' print ' if (_pbData) {' print ' retrace::delRegionByPointer(_pbData);' print ' }'
def checkResult(self, interface, methodOrFunction): # Catch when device is removed, and report the reason. if str(methodOrFunction.type) == 'HRESULT': if interface is not None: getDeviceRemovedReasonMethod = interface.getMethodByName("GetDeviceRemovedReason") if getDeviceRemovedReasonMethod is not None: print r' if (FAILED(_result)) {' print r' retrace::failed(call, _result);' print r' if (_result == DXGI_ERROR_DEVICE_REMOVED) {' print r' HRESULT _reason = _this->GetDeviceRemovedReason();' print r' retrace::failed(call, _reason);' print r' exit(1);' print r' }' print r' return;' print r' }' return Retracer.checkResult(self, interface, methodOrFunction)
def checkResult(self, interface, methodOrFunction): if interface is not None and interface.name == 'IDXGIKeyedMutex' and methodOrFunction.name == 'AcquireSync': print(r' if (_result != S_OK) {') print(r' retrace::failed(call, _result);') self.handleFailure(interface, methodOrFunction) print(r' }') return return Retracer.checkResult(self, interface, methodOrFunction)
def handleFailure(self, interface, methodOrFunction): # Catch when device is removed, and report the reason. if interface is not None: print r' if (_result == DXGI_ERROR_DEVICE_REMOVED) {' getDeviceRemovedReasonMethod = interface.getMethodByName("GetDeviceRemovedReason") if getDeviceRemovedReasonMethod is not None: print r' HRESULT _reason = _this->GetDeviceRemovedReason();' print r' retrace::failed(call, _reason);' getDeviceMethod = interface.getMethodByName("GetDevice") if getDeviceMethod is not None and len(getDeviceMethod.args) == 1: print r' com_ptr<%s> _pDevice;' % getDeviceMethod.args[0].type.type.type print r' _this->GetDevice(&_pDevice);' print r' HRESULT _reason = _pDevice->GetDeviceRemovedReason();' print r' retrace::failed(call, _reason);' print r' exit(EXIT_FAILURE);' print r' }' Retracer.handleFailure(self, interface, methodOrFunction)
def extractArg(self, function, arg, arg_type, lvalue, rvalue): # Set object names if function.name == 'SetPrivateData' and arg.name == 'pData': iid = function.args[0].name print r' if (%s != WKPDID_D3DDebugObjectName) {' % iid print r' return;' print r' }' # Interpret argument as string Retracer.extractArg(self, function, arg, LPCSTR, lvalue, rvalue) print r' if (!pData) {' print r' return;' print r' }' print r' assert(DataSize >= strlen((const char *)pData));' print r' // Some applications include the trailing zero terminator in the data' print r' DataSize = strlen((const char *)pData);' return Retracer.extractArg(self, function, arg, arg_type, lvalue, rvalue)
def retraceApi(self, api): print '// Swizzling mapping for lock addresses' print 'static std::map<void *, void *> _maps;' print print r''' static void createWindow(DXGI_SWAP_CHAIN_DESC *pSwapChainDesc) { UINT Width = pSwapChainDesc->BufferDesc.Width; UINT Height = pSwapChainDesc->BufferDesc.Height; if (!Width) Width = 1024; if (!Height) Height = 768; pSwapChainDesc->OutputWindow = d3dretrace::createWindow(Width, Height); } ''' self.table_name = 'd3dretrace::dxgi_callbacks' Retracer.retraceApi(self, api)
def invokeFunction(self, function): if function.name in self.createDeviceFunctionNames: # create windows as neccessary if 'pSwapChainDesc' in function.argNames(): print r' d3dretrace::createWindowForSwapChain(pSwapChainDesc);' # 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' HMODULE hD3d10SdkLayers = LoadLibraryA("d3d10sdklayers");' print r' if (hD3d10SdkLayers) {' print r' FreeLibrary(hD3d10SdkLayers);' print r' Flags |= D3D10_CREATE_DEVICE_DEBUG;' print r' } else {' print r' retrace::warning(call) << "Direct3D 10.x SDK Debug Layer (d3d10sdklayers.dll) not available, continuing without debug output\n";' 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' HRESULT hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_NULL, 0, D3D11_CREATE_DEVICE_DEBUG, NULL, 0, D3D11_SDK_VERSION, NULL, NULL, NULL);' print r' if (SUCCEEDED(hr)) {' print r' Flags |= D3D11_CREATE_DEVICE_DEBUG;' print r' } else {' print r' retrace::warning(call) << "Direct3D 11.x SDK Debug Layer (d3d11*sdklayers.dll) not available, continuing without debug output\n";' print r' }' print r' }' # Force driver self.forceDriver('D3D_DRIVER_TYPE') Retracer.invokeFunction(self, function)
def retraceInterfaceMethodBody(self, interface, method): Retracer.retraceInterfaceMethodBody(self, interface, method) # Add pitch swizzling information to the region if method.name == 'Map' and interface.name not in ('ID3D10Buffer', 'ID3D10Texture1D'): if interface.name.startswith('ID3D11DeviceContext'): outArg = method.getArgByName('pMappedResource') memberNames = ('pData', 'RowPitch', 'DepthPitch') elif interface.name.startswith('ID3D10'): outArg = method.args[-1] memberNames = ('pData', 'RowPitch', 'DepthPitch') elif interface.name == 'IDXGISurface': outArg = method.getArgByName('pLockedRect') memberNames = ('pBits', 'Pitch', None) else: raise NotImplementedError struct = outArg.type.type dataMemberName, rowPitchMemberName, depthPitchMemberName = memberNames dataMemberIndex = struct.getMemberByName(dataMemberName) rowPitchMemberIndex = struct.getMemberByName(rowPitchMemberName) print r' if (_pbData && %s->%s != 0) {' % (outArg.name, rowPitchMemberName) print r' const trace::Array *_%s = call.arg(%u).toArray();' % (outArg.name, outArg.index) print r' if (%s) {' % outArg.name print r' const trace::Struct *_struct = _%s->values[0]->toStruct();' % (outArg.name) print r' if (_struct) {' print r' unsigned long long traceAddress = _struct->members[%u]->toUIntPtr();' % dataMemberIndex print r' int traceRowPitch = _struct->members[%u]->toSInt();' % rowPitchMemberIndex print r' int realRowPitch = %s->%s;' % (outArg.name, rowPitchMemberName) print r' if (realRowPitch && traceRowPitch != realRowPitch) {' print r' retrace::setRegionPitch(traceAddress, 2, traceRowPitch, realRowPitch);' print r' }' try: depthPitchMemberIndex = struct.getMemberByName(depthPitchMemberName) except ValueError: assert len(struct.members) < 3 pass else: assert depthPitchMemberName == 'DepthPitch' print r' if (%s->DepthPitch) {' % outArg.name print r' retrace::checkMismatch(call, "DepthPitch", _struct->members[%u], %s->DepthPitch);' % (struct.getMemberByName('DepthPitch'), outArg.name) print r' }' print r' }' print r' }' print r' }'
def invokeInterfaceMethod(self, interface, method): if interface.name == 'IDirect3D9' and method.name == 'CreateDevice': print 'HWND hWnd = createWindow(pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight);' print 'pPresentationParameters->hDeviceWindow = hWnd;' print 'hFocusWindow = hWnd;' Retracer.invokeInterfaceMethod(self, interface, method) if str(method.type) == 'HRESULT': print r' if (__result != S_OK) {' print r' retrace::warning(call) << "failed\n";' print r' }' if interface.name == 'IDirect3DVertexBuffer9' and method.name == 'Lock': print ' if (!SizeToLock) {' print ' D3DVERTEXBUFFER_DESC Desc;' print ' _this->GetDesc(&Desc);' print ' SizeToLock = Desc.Size;' print ' }'
def invokeFunction(self, function): if function.name in ("Direct3DCreate9", "Direct3DCreate9Ex"): print 'if (retrace::debug >= 2 && !g_szD3D9DllName && LoadLibraryA("d3d9d.dll")) {' print " /*" print " * D3D9D only works for simple applications, it will often report bogus errors" print " * on complex traces, or traces which use unofficial D3D9 features." print " */" print ' g_szD3D9DllName = "d3d9d.dll";' print " SDKVersion |= 0x80000000;" print "} else {" print " SDKVersion &= ~0x80000000;" print "}" # d3d8d.dll can be found in the Aug 2007 DXSDK. It works on XP, but # not on Windows 7. if function.name in ("Direct3DCreate8"): print 'if (retrace::debug >= 2 && !g_szD3D8DllName && LoadLibraryA("d3d8d.dll")) {' print ' g_szD3D8DllName = "d3d8d.dll";' print "}" Retracer.invokeFunction(self, function)
def doInvokeFunction(self, function): Retracer.doInvokeFunction(self, function) # Handle missing debug layer. While it's possible to detect whether # the debug layers are present, by creating a null device, and checking # the result. It's simpler to retry. if function.name.startswith('D3D10CreateDevice'): print( r' if ((_result == E_FAIL || _result == DXGI_ERROR_SDK_COMPONENT_MISSING) && (Flags & D3D10_CREATE_DEVICE_DEBUG)) {' ) print( r' retrace::warning(call) << "Direct3D 10.x SDK Debug Layer (d3d10sdklayers.dll) not available, continuing without debug output\n";' ) print(r' Flags &= ~D3D10_CREATE_DEVICE_DEBUG;') Retracer.doInvokeFunction(self, function) print(r' }') if function.name.startswith('D3D11CreateDevice'): print( r' if ((_result == E_FAIL || _result == DXGI_ERROR_SDK_COMPONENT_MISSING) && (Flags & D3D11_CREATE_DEVICE_DEBUG)) {' ) print( r' retrace::warning(call) << "Direct3D 11.x SDK Debug Layer (d3d11*sdklayers.dll) not available, continuing without debug output\n";' ) print(r' Flags &= ~D3D11_CREATE_DEVICE_DEBUG;') Retracer.doInvokeFunction(self, function) print(r' }')
def invokeFunction(self, function): if function.name in self.createDeviceFunctionNames: # create windows as neccessary if "pSwapChainDesc" in function.argNames(): print r" createWindow(pSwapChainDesc);" # 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 doInvokeFunction(self, function): Retracer.doInvokeFunction(self, function) # Handle missing debug layer. While it's possible to detect whether # the debug layers are present, by creating a null device, and checking # the result. It's simpler to retry. if function.name.startswith('D3D10CreateDevice'): print r' if ((_result == E_FAIL || _result == DXGI_ERROR_SDK_COMPONENT_MISSING) && (Flags & D3D10_CREATE_DEVICE_DEBUG)) {' print r' retrace::warning(call) << "Direct3D 10.x SDK Debug Layer (d3d10sdklayers.dll) not available, continuing without debug output\n";' print r' Flags &= ~D3D10_CREATE_DEVICE_DEBUG;' Retracer.doInvokeFunction(self, function) print r' }' if function.name.startswith('D3D11CreateDevice'): print r' if ((_result == E_FAIL || _result == DXGI_ERROR_SDK_COMPONENT_MISSING) && (Flags & D3D11_CREATE_DEVICE_DEBUG)) {' print r' retrace::warning(call) << "Direct3D 11.x SDK Debug Layer (d3d11*sdklayers.dll) not available, continuing without debug output\n";' print r' Flags &= ~D3D11_CREATE_DEVICE_DEBUG;' Retracer.doInvokeFunction(self, function) print r' }'
def invokeFunction(self, function): if function.name.startswith('Direct3DCreate9'): print r' if (retrace::debug >= 3 && !g_szD3D9DllName && LoadLibraryA("d3d9d.dll")) {' print r' /*' print r' * D3D9D only works for simple applications, it will often report bogus errors' print r' * on complex traces, or traces which use unofficial D3D9 features.' print r' */' print r' g_szD3D9DllName = "d3d9d.dll";' print r' SDKVersion |= 0x80000000;' print r' } else {' print r' SDKVersion &= ~0x80000000;' print r' }' # d3d8d.dll can be found in the Aug 2007 DXSDK. It works on XP, but # not on Windows 7. if function.name.startswith('Direct3DCreate8'): print r' if (retrace::debug >= 3 && !g_szD3D8DllName && LoadLibraryA("d3d8d.dll")) {' print r' g_szD3D8DllName = "d3d8d.dll";' print r' }' if function.name.startswith('Direct3DCreate9'): print r' // 0: default' print r' // 1: force discrete' print r' // 2/3: force integrated' print r' UINT uHybrid = 0;' print r' if (retrace::driver == retrace::DRIVER_DISCRETE) {' print r' uHybrid = 1;' print r' }' print r' if (retrace::driver == retrace::DRIVER_INTEGRATED) {' print r' uHybrid = 2;' print r' }' print r' if (uHybrid != 0) {' print r' HMODULE hD3D9 = LoadLibraryA("D3D9");' print r' assert(hD3D9);' print r' typedef void (WINAPI *PFNDIRECT3D9FORCEHYBRIDENUMERATION)(UINT);' print r' PFNDIRECT3D9FORCEHYBRIDENUMERATION pfnDirect3D9ForceHybridEnumeration =' print r' (PFNDIRECT3D9FORCEHYBRIDENUMERATION)GetProcAddress(hD3D9, MAKEINTRESOURCEA(16));' print r' if (pfnDirect3D9ForceHybridEnumeration) {' print r' pfnDirect3D9ForceHybridEnumeration(uHybrid);' print r' }' print r' }' Retracer.invokeFunction(self, function) if function.name.startswith('Direct3DCreate'): print r' if (retrace::driver == retrace::DRIVER_DISCRETE ||' print r' retrace::driver == retrace::DRIVER_INTEGRATED) {' if function.name == 'Direct3DCreate9Ex': print r' auto pD3D = SUCCEEDED(_result) ? *ppD3D : nullptr;' else: print r' auto pD3D = _result;' if function.name.startswith('Direct3DCreate9'): print r' D3DADAPTER_IDENTIFIER9 Identifier;' else: assert function.name.startswith('Direct3DCreate8') print r' D3DADAPTER_IDENTIFIER8 Identifier;' print r' if (pD3D) {' print r' if (SUCCEEDED(pD3D->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &Identifier))) {' print r' std::cerr << "info: using " << Identifier.Description << std::endl;' print r' }' print r' }' print r' }'
def invokeInterfaceMethod(self, interface, method): # keep track of the last used device for state dumping if interface.name in ('IDirect3DDevice9', 'IDirect3DDevice9Ex'): if method.name == 'Release': print r' if (call.ret->toUInt() == 0) {' print r' d3d9Dumper.unbindDevice(_this);' print r' }' else: print r' d3d9Dumper.bindDevice(_this);' if interface.name in ('IDirect3DDevice8', 'IDirect3DDevice8Ex'): if method.name == 'Release': print r' if (call.ret->toUInt() == 0) {' print r' d3d8Dumper.unbindDevice(_this);' print r' }' else: print r' d3d8Dumper.bindDevice(_this);' if method.name in self.createDeviceMethodNames: # override the device type print r' switch (retrace::driver) {' print r' case retrace::DRIVER_HARDWARE:' print r' case retrace::DRIVER_DISCRETE:' print r' case retrace::DRIVER_INTEGRATED:' print r' DeviceType = D3DDEVTYPE_HAL;' print r' break;' print r' case retrace::DRIVER_SOFTWARE:' print r' BehaviorFlags &= ~D3DCREATE_PUREDEVICE;' print r' BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;' print r' BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;' print r' break;' print r' case retrace::DRIVER_REFERENCE:' print r' DeviceType = D3DDEVTYPE_REF;' print r' BehaviorFlags &= ~D3DCREATE_PUREDEVICE;' print r' BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;' print r' BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;' print r' break;' print r' case retrace::DRIVER_NULL:' if interface.name.startswith('IDirect3D9'): print r' DeviceType = D3DDEVTYPE_NULLREF;' else: print r' retrace::warning(call) << "null driver not supported\n";' print r' break;' print r' case retrace::DRIVER_MODULE:' print r' retrace::warning(call) << "driver module not supported\n";' print r' break;' print r' default:' print r' assert(0);' print r' /* fall-through */' print r' case retrace::DRIVER_DEFAULT:' print r' break;' print r' }' # create windows as neccessary if method.name in ('CreateDevice', 'CreateDeviceEx', 'CreateAdditionalSwapChain'): print r' HWND hWnd = pPresentationParameters->hDeviceWindow;' if 'hFocusWindow' in method.argNames(): print r' if (hWnd == NULL) {' print r' hWnd = hFocusWindow;' print r' }' print r' hWnd = d3dretrace::createWindow(hWnd, pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight);' print r' pPresentationParameters->hDeviceWindow = hWnd;' if 'hFocusWindow' in method.argNames(): print r' hFocusWindow = hWnd;' # force windowed mode print r' if (retrace::forceWindowed) {' print r' pPresentationParameters->Windowed = TRUE;' print r' pPresentationParameters->FullScreen_RefreshRateInHz = 0;' if interface.name.startswith('IDirect3D8'): print r' pPresentationParameters->FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;' print r' }' if 'BehaviorFlags' in method.argNames(): print r' if (retrace::dumpingState) {' print r' BehaviorFlags &= ~D3DCREATE_PUREDEVICE;' print r' }' # On D3D8, ensure we use BackBufferFormat compatible with the # current DisplayFormat. # # TODO: BackBufferFormat doesn't need to be always exectly to # DisplayFormat. For example, if DisplayFormat is D3DFMT_X1R5G5B5, # valid values for BackBufferFormat include D3DFMT_X1R5G5B5 and # D3DFMT_A1R5G5B5, but exclude D3DFMT_R5G6B5. if interface.name.startswith('IDirect3D8'): print r' if (pPresentationParameters->Windowed) {' print r' D3DDISPLAYMODE Mode;' print r' HRESULT hr;' print r' hr = _this->GetAdapterDisplayMode(Adapter, &Mode);' print r' assert(SUCCEEDED(hr));' print r' hr = _this->CheckDeviceType(Adapter, DeviceType, Mode.Format, pPresentationParameters->BackBufferFormat, pPresentationParameters->Windowed);' print r' if (hr == D3DERR_NOTAVAILABLE) {' print r' retrace::warning(call) << "forcing back buffer format to match display mode format\n";' print r' pPresentationParameters->BackBufferFormat = Mode.Format;' print r' }' print r' }' if method.name in ('Reset', 'ResetEx'): # force windowed mode print r' if (retrace::forceWindowed) {' print r' pPresentationParameters->Windowed = TRUE;' print r' pPresentationParameters->FullScreen_RefreshRateInHz = 0;' print r' }' # resize window print r' if (pPresentationParameters->Windowed) {' print r' d3dretrace::resizeWindow(pPresentationParameters->hDeviceWindow, pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight);' print r' }' # notify frame has been completed if method.name in ('Present', 'PresentEx'): if interface.name.startswith('IDirect3DSwapChain9'): print r' d3d9scDumper.bindDevice(_this);' print r' retrace::frameComplete(call);' print r' hDestWindowOverride = NULL;' # Ensure textures can be locked when dumping # TODO: Pre-check with CheckDeviceFormat if method.name in ('CreateTexture', 'CreateCubeTexture', 'CreateVolumeTexture'): print r' if (retrace::dumpingState &&' print r' Pool == D3DPOOL_DEFAULT &&' print r' !(Usage & (D3DUSAGE_RENDERTARGET|D3DUSAGE_DEPTHSTENCIL))) {' print r' Usage |= D3DUSAGE_DYNAMIC;' print r' }' # Deal with shared surfaces # https://msdn.microsoft.com/en-us/library/windows/desktop/bb219800.aspx # https://msdn.microsoft.com/en-gb/library/windows/desktop/ee913554.aspx pSharedHandleArg = method.getArgByName('pSharedHandle') if pSharedHandleArg: print r' if (pSharedHandle) {' if method.name == 'CreateTexture': # Some applications (e.g., DOTA2) create shared resources within the same process. # https://msdn.microsoft.com/en-us/library/windows/desktop/bb219800.aspx#Textures print r' if (Pool == D3DPOOL_SYSTEMMEM) {' print r' // Ensure the memory stays around.' print r' trace::Blob *blob = call.arg(%u).toArray()->values[0]->toBlob();' % pSharedHandleArg.index print r' if (blob) {' print r' blob->toPointer(true);' print r' } else {' print r' retrace::warning(call) << "invalid system memory\n";' print r' pSharedHandle = NULL;' print r' }' print r' } else {' print r' retrace::warning(call) << "shared surfaces unsupported\n";' print r' pSharedHandle = NULL;' if method.name == 'CreateTexture': print r' }' print r' }' if method.name in ('Lock', 'LockRect', 'LockBox'): # Reset _DONOTWAIT flags. Otherwise they may fail, and we have no # way to cope with it (other than retry). mapFlagsArg = method.getArgByName('Flags') for flag in mapFlagsArg.type.values: if flag.endswith('_DONOTWAIT'): print r' Flags &= ~%s;' % flag Retracer.invokeInterfaceMethod(self, interface, method) # process events after presents if method.name == 'Present': print r' d3dretrace::processEvents();' def mapping_subkey(): # A single texture object might have multiple mappings. This key # allows to tell them apart. if 'FaceType' in method.argNames(): return ('static_cast<UINT>(FaceType) + Level*6',) elif 'Level' in method.argNames(): return ('Level',) else: return ('0',) if method.name in ('Lock', 'LockRect', 'LockBox'): print ' VOID *_pbData = nullptr;' print ' size_t _MappedSize = 0;' if method.name == 'Lock': # Ignore D3DLOCK_READONLY for buffers. # https://github.com/apitrace/apitrace/issues/435 print ' if (true) {' else: print ' if (!(Flags & D3DLOCK_READONLY)) {' print ' _getMapInfo(_this, %s, _pbData, _MappedSize);' % ', '.join(method.argNames()[:-1]) print ' }' print ' if (_MappedSize) {' print ' _maps[MappingKey(_this, %s)] = _pbData;' % mapping_subkey() self.checkPitchMismatch(method) print ' } else {' print ' return;' print ' }' if method.name in ('Unlock', 'UnlockRect', 'UnlockBox'): print ' VOID *_pbData = nullptr;' print ' MappingKey _mappingKey(_this, %s);' % mapping_subkey() print ' _pbData = _maps[_mappingKey];' print ' if (_pbData) {' print ' retrace::delRegionByPointer(_pbData);' print ' _maps[_mappingKey] = nullptr;' print ' }' if interface.name == 'IDirectXVideoDecoder': if method.name == 'GetBuffer': print ' if (*ppBuffer && *pBufferSize) {' print ' _maps[MappingKey(_this, BufferType)] = *ppBuffer;' print ' }' if method.name == 'ReleaseBuffer': print ' MappingKey _mappingKey(_this, BufferType);' print ' void *_pBuffer = _maps[_mappingKey];' print ' if (_pBuffer) {' print ' retrace::delRegionByPointer(_pBuffer);' print ' _maps[_mappingKey] = nullptr;' print ' }'
def invokeInterfaceMethod(self, interface, method): # keep track of the last used device for state dumping if interface.name in ('IDirect3DDevice7',): if method.name == 'Release': print r' if (call.ret->toUInt() == 0) {' print r' d3d7Dumper.unbindDevice(_this);' print r' }' else: print r' d3d7Dumper.bindDevice(_this);' # create windows as neccessary hWndArg = method.getArgByType(HWND) if hWndArg is not None: # FIXME: Try to guess the window size (e.g., from IDirectDrawSurface7::Blt) print r' if (!g_hWnd) {' print r' g_hWnd = d3dretrace::createWindow(512, 512);' print r' }' print r' %s = g_hWnd;' % hWndArg.name if method.name == 'Lock': # Reset _DONOTWAIT flags. Otherwise they may fail, and we have no # way to cope with it (other than retry). mapFlagsArg = method.getArgByName('dwFlags') if mapFlagsArg is not None: print r' dwFlags &= DDLOCK_DONOTWAIT;' print r' dwFlags |= DDLOCK_WAIT;' Retracer.invokeInterfaceMethod(self, interface, method) if method.name == 'CreateDevice': print r' if (FAILED(_result)) {' print r' exit(1);' print r' }' # notify frame has been completed # process events after presents if interface.name == 'IDirectDrawSurface7' and method.name == 'Blt': print r' DDSCAPS2 ddsCaps;' print r' if (SUCCEEDED(_this->GetCaps(&ddsCaps)) &&' print r' (ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)) {' print r' retrace::frameComplete(call);' print r' d3dretrace::processEvents();' print r' }' if method.name == 'Lock': print ' VOID *_pbData = NULL;' print ' size_t _MappedSize = 0;' # FIXME: determine the mapping size #print ' _getMapInfo(_this, %s, _pbData, _MappedSize);' % ', '.join(method.argNames()[:-1]) print ' if (_MappedSize) {' print ' _maps[_this] = _pbData;' # TODO: check pitches match print ' } else {' print ' return;' print ' }' if method.name == 'Unlock': print ' VOID *_pbData = 0;' print ' _pbData = _maps[_this];' print ' if (_pbData) {' print ' retrace::delRegionByPointer(_pbData);' print ' _maps[_this] = 0;' print ' }'
def invokeFunction(self, function): if function.name in self.createDeviceFunctionNames: # create windows as neccessary if 'pSwapChainDesc' in function.argNames(): print r' createWindow(pSwapChainDesc);' # 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' const char *szD3d11SdkLayers = IsWindows8OrGreater() ? "d3d11_1sdklayers" : "d3d11sdklayers";' print r' if (LoadLibraryA(szD3d11SdkLayers)) {' print r' Flags |= D3D11_CREATE_DEVICE_DEBUG;' print r' }' print r' }' # Force driver self.forceDriver('D3D_DRIVER_TYPE') Retracer.invokeFunction(self, function) # Debug layers with Windows 8 or Windows 7 Platform update are a mess. # It's not possible to know before hand whether they are or not # available, so always retry with debug flag off.. if function.name in self.createDeviceFunctionNames: print r' if (FAILED(_result)) {' if function.name.startswith('D3D10CreateDevice'): print r' if (_result == E_FAIL && (Flags & D3D10_CREATE_DEVICE_DEBUG)) {' print r' retrace::warning(call) << "debug layer (d3d10sdklayers.dll) not installed\n";' print r' Flags &= ~D3D10_CREATE_DEVICE_DEBUG;' Retracer.invokeFunction(self, function) print r' }' elif function.name.startswith('D3D11CreateDevice'): print r' if (_result == E_FAIL && (Flags & D3D11_CREATE_DEVICE_DEBUG)) {' 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";' print r' Flags &= ~D3D11_CREATE_DEVICE_DEBUG;' Retracer.invokeFunction(self, function) print r' }' else: assert False print r' if (FAILED(_result)) {' print r' exit(1);' print r' }' print r' }'
def invokeInterfaceMethod(self, interface, method): # keep track of the last used device for state dumping if interface.name in ('ID3D10Device', 'ID3D10Device1'): if method.name == 'Release': print r' if (call.ret->toUInt() == 0) {' print r' d3d10Dumper.unbindDevice(_this);' print r' }' else: print r' d3d10Dumper.bindDevice(_this);' if interface.name.startswith('ID3D11DeviceContext'): if method.name == 'Release': print r' if (call.ret->toUInt() == 0) {' print r' d3d11Dumper.unbindDevice(_this);' print r' }' else: print r' d3d11Dumper.bindDevice(_this);' # intercept private interfaces if method.name == 'QueryInterface': print r' if (!d3dretrace::overrideQueryInterface(_this, riid, ppvObj, &_result)) {' Retracer.invokeInterfaceMethod(self, interface, method) print r' }' return # create windows as neccessary if method.name == 'CreateSwapChain': print r' d3dretrace::createWindowForSwapChain(pDesc);' if method.name == 'CreateSwapChainForHwnd': print r' WindowHandle = d3dretrace::createWindow(pDesc->Width, pDesc->Height);' print r' // DXGI_SCALING_NONE is only supported on Win8 and beyond' print r' if (pDesc->Scaling == DXGI_SCALING_NONE && !IsWindows8OrGreater()) {' print r' pDesc->Scaling = DXGI_SCALING_STRETCH;' print r' }' if method.name == 'CreateSwapChainForComposition': print r' HWND hWnd = d3dretrace::createWindow(pDesc->Width, pDesc->Height);' print r' _result = _this->CreateSwapChainForHwnd(pDevice, hWnd, pDesc, NULL, pRestrictToOutput, ppSwapChain);' self.checkResult(interface, method) return if method.name == 'CreateTargetForHwnd': print r' hwnd = d3dretrace::createWindow(1024, 768);' if method.name == 'SetFullscreenState': print r' if (retrace::forceWindowed) {' print r' Fullscreen = FALSE;' print r' pTarget = NULL;' print r' }' # notify frame has been completed if interface.name.startswith( 'IDXGISwapChain') and method.name.startswith('Present'): if interface.name.startswith('IDXGISwapChainDWM'): print r' com_ptr<IDXGISwapChain> pSwapChain;' print r' if (SUCCEEDED(_this->QueryInterface(IID_IDXGISwapChain, (void **) &pSwapChain))) {' print r' dxgiDumper.bindDevice(pSwapChain);' print r' } else {' print r' assert(0);' print r' }' else: print r' dxgiDumper.bindDevice(_this);' print r' retrace::frameComplete(call);' if 'pSharedResource' in method.argNames(): print r' if (pSharedResource) {' print r' retrace::warning(call) << "shared surfaces unsupported\n";' print r' pSharedResource = NULL;' print r' }' # Force driver if interface.name.startswith( 'IDXGIFactory') and method.name.startswith('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, reinterpret_cast<IDXGIAdapter **>(ppAdapter));' print r' } else {' Retracer.invokeInterfaceMethod(self, interface, method) print r' }' return if interface.name.startswith( 'ID3D10Device') and method.name.startswith( 'OpenSharedResource'): print r' retrace::warning(call) << "replacing shared resource with checker pattern\n";' print r' _result = d3dretrace::createSharedResource(_this, ReturnedInterface, ppResource);' self.checkResult(interface, method) return if interface.name.startswith( 'ID3D11Device') and method.name == 'OpenSharedResource': # Some applications (e.g., video playing in IE11) create shared resources within the same process. # TODO: Generalize to other OpenSharedResource variants print r' retrace::map<HANDLE>::const_iterator it = _shared_handle_map.find(hResource);' print r' if (it == _shared_handle_map.end()) {' print r' retrace::warning(call) << "replacing shared resource with checker pattern\n";' print r' _result = d3dretrace::createSharedResource(_this, ReturnedInterface, ppResource);' self.checkResult(interface, method) print r' } else {' print r' hResource = it->second;' Retracer.invokeInterfaceMethod(self, interface, method) print r' }' return if interface.name.startswith( 'ID3D11Device') and method.name.startswith( 'OpenSharedResource'): print r' retrace::warning(call) << "replacing shared resource with checker pattern\n";' print r' _result = d3dretrace::createSharedResource(_this, ReturnedInterface, ppResource);' if method.name == 'OpenSharedResourceByName': print r' (void)lpName;' print r' (void)dwDesiredAccess;' else: print r' (void)hResource;' self.checkResult(interface, method) 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 if method.name.startswith('UpdateSubresource'): # The D3D10 debug layer is buggy (or at least inconsistent with the # runtime), as it seems to estimate and enforce the data size based on the # SrcDepthPitch, even for non 3D textures, but in some traces # SrcDepthPitch is garbagge for non 3D textures. # XXX: It also seems to expect padding bytes at the end of the last # row, but we never record (or allocate) those... print r' if (retrace::debug && pDstBox && pDstBox->front == 0 && pDstBox->back == 1) {' print r' SrcDepthPitch = 0;' print r' }' if method.name == 'SetGammaControl': # This method is only supported while in full-screen mode print r' if (retrace::forceWindowed) {' print r' return;' print r' }' if method.name == 'GetData': print r' pData = _allocator.alloc(DataSize);' print r' do {' self.doInvokeInterfaceMethod(interface, method) print r' GetDataFlags = 0; // Prevent infinite loop' print r' } while (_result == S_FALSE);' self.checkResult(interface, method) print r' return;' Retracer.invokeInterfaceMethod(self, interface, method) if method.name in ('AcquireSync', 'ReleaseSync'): print r' if (SUCCEEDED(_result) && _result != S_OK) {' print r' retrace::warning(call) << " returned " << _result << "\n";' print r' }' # process events after presents if interface.name.startswith( 'IDXGISwapChain') and method.name.startswith('Present'): print r' d3dretrace::processEvents();' if method.name in ('Map', 'Unmap'): if interface.name.startswith('ID3D11DeviceContext'): print ' void * & _pbData = g_Maps[_this][SubresourceKey(pResource, Subresource)];' else: subresourceArg = method.getArgByName('Subresource') if subresourceArg is None: print ' UINT Subresource = 0;' print ' void * & _pbData = g_Maps[0][SubresourceKey(_this, Subresource)];' if method.name == 'Map': print ' _MAP_DESC _MapDesc;' print ' _getMapDesc(_this, %s, _MapDesc);' % ', '.join( method.argNames()) print ' size_t _MappedSize = _MapDesc.Size;' print ' if (_MapDesc.Size) {' print ' _pbData = _MapDesc.pData;' if interface.name.startswith('ID3D11DeviceContext'): # Prevent false warnings on 1D and 2D resources, since the # pitches are often junk there... print ' _normalizeMap(pResource, pMappedResource);' else: print ' _pbData = _MapDesc.pData;' print ' } else {' print ' return;' print ' }' if method.name == 'Unmap': print ' if (_pbData) {' print ' retrace::delRegionByPointer(_pbData);' print ' _pbData = 0;' print ' }' if interface.name.startswith('ID3D11VideoContext'): if method.name == 'GetDecoderBuffer': print ' if (*ppBuffer && *pBufferSize) {' print ' g_Maps[nullptr][SubresourceKey(_this, Type)] = *ppBuffer;' print ' }' if method.name == 'ReleaseDecoderBuffer': print ' SubresourceKey _mappingKey(_this, Type);' print ' void *_pBuffer = g_Maps[nullptr][_mappingKey];' print ' if (_pBuffer) {' print ' retrace::delRegionByPointer(_pBuffer);' print ' g_Maps[nullptr][_mappingKey] = 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 invokeInterfaceMethod(self, interface, method): # keep track of the last used device for state dumping if interface.name in ('IDirect3DDevice9', 'IDirect3DDevice9Ex'): if method.name == 'Release': print r' if (call.ret->toUInt() == 0) {' print r' d3d9Dumper.unbindDevice(_this);' print r' }' else: print r' d3d9Dumper.bindDevice(_this);' if interface.name in ('IDirect3DDevice8', 'IDirect3DDevice8Ex'): if method.name == 'Release': print r' if (call.ret->toUInt() == 0) {' print r' d3d8Dumper.unbindDevice(_this);' print r' }' else: print r' d3d8Dumper.bindDevice(_this);' # create windows as neccessary if method.name in ('CreateDevice', 'CreateDeviceEx', 'CreateAdditionalSwapChain'): print r' HWND hWnd = d3dretrace::createWindow(pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight);' print r' pPresentationParameters->hDeviceWindow = hWnd;' if 'hFocusWindow' in method.argNames(): print r' hFocusWindow = hWnd;' # force windowed mode print r' if (retrace::forceWindowed) {' print r' pPresentationParameters->Windowed = TRUE;' print r' pPresentationParameters->FullScreen_RefreshRateInHz = 0;' print r' }' if method.name in self.createDeviceMethodNames: # override the device type print r' switch (retrace::driver) {' print r' case retrace::DRIVER_HARDWARE:' print r' DeviceType = D3DDEVTYPE_HAL;' print r' break;' print r' case retrace::DRIVER_SOFTWARE:' print r' case retrace::DRIVER_REFERENCE:' print r' DeviceType = D3DDEVTYPE_REF;' print r' break;' print r' case retrace::DRIVER_NULL:' if interface.name.startswith('IDirect3D9'): print r' DeviceType = D3DDEVTYPE_NULLREF;' else: print r' retrace::warning(call) << "null driver not supported\n";' print r' break;' print r' case retrace::DRIVER_MODULE:' print r' retrace::warning(call) << "driver module not supported\n";' print r' break;' print r' default:' print r' assert(0);' print r' /* fall-through */' print r' case retrace::DRIVER_DEFAULT:' print r' break;' print r' }' if method.name in ('Reset', 'ResetEx'): # force windowed mode print r' if (retrace::forceWindowed) {' print r' pPresentationParameters->Windowed = TRUE;' print r' pPresentationParameters->FullScreen_RefreshRateInHz = 0;' print r' }' # resize window print r' if (pPresentationParameters->Windowed) {' print r' d3dretrace::resizeWindow(pPresentationParameters->hDeviceWindow, pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight);' print r' }' # notify frame has been completed if method.name in ('Present', 'PresentEx'): print r' retrace::frameComplete(call);' print r' hDestWindowOverride = NULL;' if 'pSharedHandle' in method.argNames(): print r' if (pSharedHandle) {' print r' retrace::warning(call) << "shared surfaces unsupported\n";' print r' pSharedHandle = NULL;' print r' }' if method.name in ('Lock', 'LockRect', 'LockBox'): # Reset _DONOTWAIT flags. Otherwise they may fail, and we have no # way to cope with it (other than retry). mapFlagsArg = method.getArgByName('Flags') for flag in mapFlagsArg.type.values: if flag.endswith('_DONOTWAIT'): print r' Flags &= ~%s;' % flag Retracer.invokeInterfaceMethod(self, interface, method) if method.name in self.createDeviceMethodNames: print r' if (FAILED(_result)) {' print r' exit(1);' print r' }' # process events after presents if method.name == 'Present': print r' d3dretrace::processEvents();' if method.name in ('Lock', 'LockRect', 'LockBox'): print ' VOID *_pbData = NULL;' print ' size_t _MappedSize = 0;' print ' _getMapInfo(_this, %s, _pbData, _MappedSize);' % ', '.join(method.argNames()[:-1]) print ' if (_MappedSize) {' print ' _maps[_this] = _pbData;' print ' } else {' print ' return;' print ' }' if method.name in ('Unlock', 'UnlockRect', 'UnlockBox'): print ' VOID *_pbData = 0;' print ' _pbData = _maps[_this];' print ' if (_pbData) {' print ' retrace::delRegionByPointer(_pbData);' print ' _maps[_this] = 0;' print ' }'