| ########################################################################## |
| # |
| # Copyright 2011 Jose Fonseca |
| # All Rights Reserved. |
| # |
| # Permission is hereby granted, free of charge, to any person obtaining a copy |
| # of this software and associated documentation files (the "Software"), to deal |
| # in the Software without restriction, including without limitation the rights |
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| # copies of the Software, and to permit persons to whom the Software is |
| # furnished to do so, subject to the following conditions: |
| # |
| # The above copyright notice and this permission notice shall be included in |
| # all copies or substantial portions of the Software. |
| # |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| # THE SOFTWARE. |
| # |
| ##########################################################################/ |
| |
| |
| """D3D retracer generator.""" |
| |
| |
| import sys |
| from dllretrace import DllRetracer as Retracer |
| import specs.dxgi |
| from specs.stdapi import API |
| from specs.winapi import LPCSTR |
| from specs.dxgi import dxgi |
| from specs.d3d10 import d3d10, d3d10_1 |
| from specs.d3d11 import d3d11 |
| from specs.dcomp import dcomp |
| |
| |
| class D3DRetracer(Retracer): |
| |
| 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) |
| |
| createDeviceFunctionNames = [ |
| "D3D10CreateDevice", |
| "D3D10CreateDeviceAndSwapChain", |
| "D3D10CreateDevice1", |
| "D3D10CreateDeviceAndSwapChain1", |
| "D3D11CreateDevice", |
| "D3D11CreateDeviceAndSwapChain", |
| ] |
| |
| 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_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 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 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 forceDriver(self, driverType): |
| # This can only work when pAdapter is NULL. For non-NULL pAdapter we |
| # need to override inside the EnumAdapters call below |
| print(r' com_ptr<IDXGIFactory1> _pFactory;') |
| print(r' com_ptr<IDXGIAdapter> _pAdapter;') |
| print(r' if (pAdapter == nullptr && retrace::driver != retrace::DRIVER_DEFAULT) {') |
| print(r' _result = CreateDXGIFactory1(IID_IDXGIFactory1, (void **)&_pFactory);') |
| print(r' assert(SUCCEEDED(_result));') |
| print(r' _result = d3dretrace::createAdapter(_pFactory, IID_IDXGIAdapter1, (void **)&_pAdapter);') |
| print(r' pAdapter = _pAdapter;') |
| print(r' DriverType = %s;' % driverType) |
| print(r' Software = NULL;') |
| print(r' }') |
| |
| def doInvokeInterfaceMethod(self, interface, method): |
| if interface.name.startswith('IDXGIAdapter') and method.name == 'EnumOutputs': |
| print(r' if (Output != 0) {') |
| print(r' retrace::warning(call) << "ignoring output " << Output << "\n";') |
| print(r' Output = 0;') |
| print(r' }') |
| |
| # GPU counters are vendor specific and likely to fail, so use a |
| # timestamp query instead, which is guaranteed to succeed |
| if method.name == 'CreateCounter': |
| if interface.name.startswith('ID3D10'): |
| print(r' D3D10_QUERY_DESC _queryDesc;') |
| print(r' _queryDesc.Query = D3D10_QUERY_TIMESTAMP;') |
| print(r' _queryDesc.MiscFlags = 0;') |
| print(r' _result = _this->CreateQuery(&_queryDesc, reinterpret_cast<ID3D10Query **>(ppCounter));') |
| return |
| if interface.name.startswith('ID3D11'): |
| print(r' D3D11_QUERY_DESC _queryDesc;') |
| print(r' _queryDesc.Query = D3D11_QUERY_TIMESTAMP;') |
| print(r' _queryDesc.MiscFlags = 0;') |
| print(r' _result = _this->CreateQuery(&_queryDesc, reinterpret_cast<ID3D11Query **>(ppCounter));') |
| return |
| |
| Retracer.doInvokeInterfaceMethod(self, interface, method) |
| |
| # Force driver |
| if interface.name.startswith('IDXGIFactory') and method.name.startswith('EnumAdapters'): |
| print(r' if (Adapter != 0) {') |
| print(r' retrace::warning(call) << "ignoring non-default adapter " << Adapter << "\n";') |
| print(r' Adapter = 0;') |
| print(r' }') |
| print(r' if (retrace::driver != retrace::DRIVER_DEFAULT) {') |
| print(r' _result = d3dretrace::createAdapter(_this, IID_IDXGIAdapter1, (void **)ppAdapter);') |
| print(r' } else {') |
| Retracer.doInvokeInterfaceMethod(self, interface, method) |
| print(r' }') |
| return |
| |
| if interface.name.startswith('IDXGIFactory') and method.name == 'CreateSoftwareAdapter': |
| print(r' const char *szSoftware = NULL;') |
| print(r' switch (retrace::driver) {') |
| print(r' case retrace::DRIVER_REFERENCE:') |
| print(r' szSoftware = "d3d11ref.dll";') |
| print(r' break;') |
| print(r' case retrace::DRIVER_MODULE:') |
| print(r' szSoftware = retrace::driverModule;') |
| print(r' break;') |
| print(r' case retrace::DRIVER_SOFTWARE:') |
| print(r' default:') |
| print(r' szSoftware = "d3d10warp.dll";') |
| print(r' break;') |
| print(r' }') |
| print(r' Module = LoadLibraryA("d3d10warp");') |
| print(r' if (!Module) {') |
| print(r' retrace::warning(call) << "failed to load " << szSoftware << "\n";') |
| print(r' }') |
| 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 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' hWnd = 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' DXGI_SWAP_CHAIN_DESC Desc;') |
| print(r' _this->GetDesc(&Desc);') |
| print(r' if (Desc.BufferDesc.Format != DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM) {') |
| print(r' Fullscreen = FALSE;') |
| print(r' pTarget = nullptr;') |
| print(r' }') |
| 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' if ((Flags & DXGI_PRESENT_TEST) == 0) {') |
| print(r' retrace::frameComplete(call);') |
| print(r' }') |
| |
| if 'pSharedResource' in method.argNames(): |
| print(r' if (pSharedResource) {') |
| print(r' retrace::warning(call) << "shared surfaces unsupported\n";') |
| print(r' pSharedResource = NULL;') |
| print(r' }') |
| |
| 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 >= 2 && 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;') |
| |
| if method.name in ('CreateTexture1D', 'CreateTexture2D', 'CreateTexture3D', 'CreateBuffer'): |
| # We don't capture multiple processes, so ignore keyed mutexes to avoid deadlocks |
| print(r' if (pDesc->MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) {') |
| print(r' pDesc->MiscFlags &= ~D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;') |
| print(r' pDesc->MiscFlags |= D3D11_RESOURCE_MISC_SHARED;') |
| print(r' }') |
| |
| if method.name == 'ReleaseSync': |
| # We must flush the device that used this surface, as per |
| # https://docs.microsoft.com/en-us/windows/win32/api/d3d10/nf-d3d10-id3d10device-opensharedresource |
| print(r''' |
| com_ptr<ID3D11DeviceChild> pDeviceChild; |
| com_ptr<ID3D11Device> pDevice; |
| com_ptr<ID3D11DeviceContext> pDeviceContext; |
| HRESULT hr = _this->QueryInterface(IID_ID3D11DeviceChild, (void **)&pDeviceChild); |
| if (SUCCEEDED(hr)) { |
| pDeviceChild->GetDevice(&pDevice); |
| pDevice->GetImmediateContext(&pDeviceContext); |
| pDeviceContext->Flush(); |
| } else { |
| retrace::warning(call) << "ReleaseSync without D3D11 device\n"; |
| } |
| (void)Key; |
| (void)_result; |
| ''') |
| return |
| |
| Retracer.invokeInterfaceMethod(self, interface, method) |
| |
| # 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' }') |
| |
| if method.name == 'CreateBuffer': |
| ppBuffer = method.args[-1] |
| print(r' if (retrace::dumpingState && SUCCEEDED(_result)) {') |
| print(r' char label[32];') |
| print(r' _snprintf(label, sizeof label, "0x%%llx", call.arg(%u).toArray()->values[0]->toUIntPtr());' % ppBuffer.index) |
| print(r' (*%s)->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(label)+1, label);' % ppBuffer.name) |
| print(r' }') |
| |
| 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' 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 main(): |
| print(r'#define INITGUID') |
| print() |
| print(r'#include <string.h>') |
| print() |
| print(r'#include <iostream>') |
| print() |
| print(r'#include "d3dretrace.hpp"') |
| print(r'#include "os_version.hpp"') |
| print() |
| print(r'#include "d3dretrace_dxgi.hpp"') |
| print(r'#include "d3d10imports.hpp"') |
| print(r'#include "d3d10size.hpp"') |
| print(r'#include "d3d10state.hpp"') |
| print(r'#include "d3d11imports.hpp"') |
| print(r'#include "d3d11size.hpp"') |
| print(r'#include "dcompimports.hpp"') |
| print(r'#include "d3dstate.hpp"') |
| print(r'#include "d3d9imports.hpp" // D3DERR_WASSTILLDRAWING') |
| print() |
| print('''static d3dretrace::D3DDumper<IDXGISwapChain> dxgiDumper;''') |
| print('''static d3dretrace::D3DDumper<ID3D10Device> d3d10Dumper;''') |
| print('''static d3dretrace::D3DDumper<ID3D11DeviceContext> d3d11Dumper;''') |
| print() |
| |
| api = API() |
| api.addModule(dxgi) |
| api.addModule(d3d10) |
| api.addModule(d3d10_1) |
| api.addModule(d3d11) |
| api.addModule(dcomp) |
| |
| retracer = D3DRetracer() |
| retracer.retraceApi(api) |
| |
| |
| if __name__ == '__main__': |
| main() |