blob: 62d53665739d4de9758a74f34108474278243379 [file] [log] [blame]
José Fonsecaff0b1ee2012-10-25 12:17:39 +01001##########################################################################
2#
3# Copyright 2008-2009 VMware, Inc.
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
José Fonseca20aa9352012-11-23 14:34:29 +000027import sys
José Fonsecaff0b1ee2012-10-25 12:17:39 +010028from dlltrace import DllTracer
José Fonseca5abf5602013-05-30 14:00:44 +010029from trace import getWrapperInterfaceName
José Fonsecaff0b1ee2012-10-25 12:17:39 +010030from specs import stdapi
José Fonseca20aa9352012-11-23 14:34:29 +000031from specs.stdapi import API
José Fonseca5abf5602013-05-30 14:00:44 +010032from specs import dxgi
33from specs import d3d10
José Fonseca5abf5602013-05-30 14:00:44 +010034from specs import d3d11
Jose Fonsecabab19212016-01-31 23:58:30 +000035from specs import dcomp
José Fonsecae354d8d2015-02-06 10:30:01 +000036from specs import d3d9
José Fonsecaff0b1ee2012-10-25 12:17:39 +010037
38
39class D3DCommonTracer(DllTracer):
40
41 def serializeArgValue(self, function, arg):
42 # Dump shaders as strings
43 if isinstance(arg.type, stdapi.Blob) and arg.name.startswith('pShaderBytecode'):
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +010044 print(' DumpShader(trace::localWriter, %s, %s);' % (arg.name, arg.type.size))
José Fonsecaff0b1ee2012-10-25 12:17:39 +010045 return
46
Jose Fonseca3dccc202018-12-04 12:29:00 +000047 # Serialize the swap-chain dimensions
48 if function.name.startswith('CreateSwapChain') and arg.name == 'pDesc' \
José Fonseca2b6d24e2013-02-22 15:00:26 +000049 or arg.name == 'pSwapChainDesc':
Jose Fonseca3dccc202018-12-04 12:29:00 +000050 assert isinstance(arg.type, stdapi.Pointer)
51 descType = arg.type.type.mutable()
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +010052 print(r' %s *_pSwapChainDesc = nullptr;' % descType)
53 print(r' %s _SwapChainDesc;' % descType)
54 print(r' if (%s) {' % arg.name)
55 print(r' _SwapChainDesc = *%s;' % arg.name)
Jose Fonseca3dccc202018-12-04 12:29:00 +000056 if self.interface is not None and self.interface.name.endswith('DWM'):
57 # Obtain size from the output
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +010058 print(r' assert(pOutput);')
59 print(r' DXGI_OUTPUT_DESC _OutputDesc;')
60 print(r' if (SUCCEEDED(pOutput->GetDesc(&_OutputDesc))) {')
61 print(r' _SwapChainDesc.BufferDesc.Width = _OutputDesc.DesktopCoordinates.right - _OutputDesc.DesktopCoordinates.left;')
62 print(r' _SwapChainDesc.BufferDesc.Height = _OutputDesc.DesktopCoordinates.bottom - _OutputDesc.DesktopCoordinates.top;')
63 print(r' }')
Jose Fonseca3dccc202018-12-04 12:29:00 +000064 elif function.name == 'CreateSwapChainForHwnd':
65 # Obtain size from the window
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +010066 print(r' RECT _rect;')
67 print(r' if (GetClientRect(hWnd, &_rect)) {')
68 print(r' if (%s->Width == 0) {' % arg.name)
69 print(r' _SwapChainDesc.Width = _rect.right - _rect.left;')
70 print(r' }')
71 print(r' if (%s->Height == 0) {' % arg.name)
72 print(r' _SwapChainDesc.Height = _rect.bottom - _rect.top;')
73 print(r' }')
74 print(r' }')
Jose Fonseca3dccc202018-12-04 12:29:00 +000075 elif function.name.startswith('CreateSwapChainFor'):
76 # TODO
77 pass
78 else:
José Fonseca419d7682013-02-22 10:24:31 +000079 # Obtain size from the window
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +010080 print(r' RECT _rect;')
81 print(r' if (GetClientRect(%s->OutputWindow, &_rect)) {' % arg.name)
82 print(r' if (%s->BufferDesc.Width == 0) {' % arg.name)
83 print(r' _SwapChainDesc.BufferDesc.Width = _rect.right - _rect.left;')
84 print(r' }')
85 print(r' if (%s->BufferDesc.Height == 0) {' % arg.name)
86 print(r' _SwapChainDesc.BufferDesc.Height = _rect.bottom - _rect.top;')
87 print(r' }')
88 print(r' }')
89 print(r' _pSwapChainDesc = &_SwapChainDesc;')
90 print(r' }')
José Fonseca2b6d24e2013-02-22 15:00:26 +000091 self.serializeValue(arg.type, '_pSwapChainDesc')
José Fonseca419d7682013-02-22 10:24:31 +000092 return
93
José Fonseca04ffbed2014-07-23 13:57:14 +010094 # Serialize object names
José Fonseca04ffbed2014-07-23 13:57:14 +010095 if function.name == 'SetPrivateData' and arg.name == 'pData':
96 iid = function.args[0].name
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +010097 print(r' if (%s == WKPDID_D3DDebugObjectName) {' % iid)
98 print(r' trace::localWriter.writeString(static_cast<const char *>(pData), DataSize);')
99 print(r' } else {')
José Fonseca04ffbed2014-07-23 13:57:14 +0100100 DllTracer.serializeArgValue(self, function, arg)
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100101 print(r' }')
José Fonseca04ffbed2014-07-23 13:57:14 +0100102 return
103
José Fonsecaff0b1ee2012-10-25 12:17:39 +0100104 DllTracer.serializeArgValue(self, function, arg)
José Fonseca5abf5602013-05-30 14:00:44 +0100105
106 # Interfaces that need book-keeping for maps
107 mapInterfaces = (
108 dxgi.IDXGISurface,
109 d3d10.ID3D10Resource,
José Fonseca5abf5602013-05-30 14:00:44 +0100110 )
José Fonseca0168b512012-11-03 18:44:36 +0000111
112 def enumWrapperInterfaceVariables(self, interface):
113 variables = DllTracer.enumWrapperInterfaceVariables(self, interface)
114
115 # Add additional members to track maps
José Fonseca5abf5602013-05-30 14:00:44 +0100116 if interface.hasBase(*self.mapInterfaces):
José Fonseca0168b512012-11-03 18:44:36 +0000117 variables += [
José Fonseca6a940052014-10-07 21:39:06 +0100118 ('_MAP_DESC', 'm_MapDesc', None),
Jose Fonseca5057d102016-05-05 17:01:12 +0100119 ('MemoryShadow', 'm_MapShadow', None),
José Fonseca6a940052014-10-07 21:39:06 +0100120 ]
121 if interface.hasBase(d3d11.ID3D11DeviceContext):
122 variables += [
123 ('std::map< std::pair<ID3D11Resource *, UINT>, _MAP_DESC >', 'm_MapDescs', None),
Jose Fonseca5057d102016-05-05 17:01:12 +0100124 ('std::map< std::pair<ID3D11Resource *, UINT>, MemoryShadow >', 'm_MapShadows', None),
José Fonseca0168b512012-11-03 18:44:36 +0000125 ]
Jose Fonseca91403b62016-05-19 15:10:03 +0100126 if interface.hasBase(d3d11.ID3D11VideoContext):
127 variables += [
128 ('std::map<UINT, std::pair<void *, UINT> >', 'm_MapDesc', None),
129 ]
José Fonseca0168b512012-11-03 18:44:36 +0000130
131 return variables
132
133 def implementWrapperInterfaceMethodBody(self, interface, base, method):
Jose Fonseca4713c3b2015-08-12 11:06:34 +0100134 if method.getArgByName('pInitialData'):
135 pDesc1 = method.getArgByName('pDesc1')
136 if pDesc1 is not None:
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100137 print(r' %s pDesc = pDesc1;' % (pDesc1.type,))
Jose Fonseca4713c3b2015-08-12 11:06:34 +0100138
José Fonseca5abf5602013-05-30 14:00:44 +0100139 if method.name in ('Map', 'Unmap'):
140 # On D3D11 Map/Unmap is not a resource method, but a context method instead.
141 resourceArg = method.getArgByName('pResource')
142 if resourceArg is None:
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100143 print(' _MAP_DESC & _MapDesc = m_MapDesc;')
144 print(' MemoryShadow & _MapShadow = m_MapShadow;')
145 print(' %s *pResourceInstance = m_pInstance;' % interface.name)
José Fonseca5abf5602013-05-30 14:00:44 +0100146 else:
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100147 print(r' static bool _warned = false;')
148 print(r' if (_this->GetType() == D3D11_DEVICE_CONTEXT_DEFERRED && !_warned) {')
149 print(r' os::log("apitrace: warning: map with deferred context may not be realiably traced\n");')
150 print(r' _warned = true;')
151 print(r' }')
152 print(' _MAP_DESC & _MapDesc = m_MapDescs[std::pair<%s, UINT>(pResource, Subresource)];' % resourceArg.type)
153 print(' MemoryShadow & _MapShadow = m_MapShadows[std::pair<%s, UINT>(pResource, Subresource)];' % resourceArg.type)
154 print(' Wrap%spResourceInstance = static_cast<Wrap%s>(%s);' % (resourceArg.type, resourceArg.type, resourceArg.name))
José Fonseca5abf5602013-05-30 14:00:44 +0100155
José Fonseca0168b512012-11-03 18:44:36 +0000156 if method.name == 'Unmap':
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100157 print(' if (_MapDesc.Size && _MapDesc.pData) {')
158 print(' if (_shouldShadowMap(pResourceInstance)) {')
159 print(' _MapShadow.update(trace::fakeMemcpy);')
160 print(' } else {')
José Fonseca6f0e3032014-06-25 01:00:35 +0100161 self.emit_memcpy('_MapDesc.pData', '_MapDesc.Size')
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100162 print(' }')
163 print(' }')
José Fonseca0168b512012-11-03 18:44:36 +0000164
Jose Fonseca91403b62016-05-19 15:10:03 +0100165 if interface.hasBase(d3d11.ID3D11VideoContext) and \
166 method.name == 'ReleaseDecoderBuffer':
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100167 print(' std::map<UINT, std::pair<void *, UINT> >::iterator it = m_MapDesc.find(Type);')
168 print(' if (it != m_MapDesc.end()) {')
Jose Fonseca91403b62016-05-19 15:10:03 +0100169 self.emit_memcpy('it->second.first', 'it->second.second')
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100170 print(' m_MapDesc.erase(it);')
171 print(' }')
Jose Fonseca91403b62016-05-19 15:10:03 +0100172
José Fonseca0168b512012-11-03 18:44:36 +0000173 DllTracer.implementWrapperInterfaceMethodBody(self, interface, base, method)
174
175 if method.name == 'Map':
176 # NOTE: recursive locks are explicitely forbidden
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100177 print(' if (SUCCEEDED(_result)) {')
178 print(' _getMapDesc(_this, %s, _MapDesc);' % ', '.join(method.argNames()))
179 print(' if (_MapDesc.pData && _shouldShadowMap(pResourceInstance)) {')
Jose Fonseca5057d102016-05-05 17:01:12 +0100180 if interface.name.startswith('IDXGI'):
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100181 print(' (void)_MapShadow;')
Jose Fonseca5057d102016-05-05 17:01:12 +0100182 else:
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100183 print(' bool _discard = MapType == 4 /* D3D1[01]_MAP_WRITE_DISCARD */;')
184 print(' _MapShadow.cover(_MapDesc.pData, _MapDesc.Size, _discard);')
185 print(' }')
186 print(' } else {')
187 print(' _MapDesc.pData = NULL;')
188 print(' _MapDesc.Size = 0;')
189 print(' }')
José Fonseca0168b512012-11-03 18:44:36 +0000190
Jose Fonseca91403b62016-05-19 15:10:03 +0100191 if interface.hasBase(d3d11.ID3D11VideoContext) and \
192 method.name == 'GetDecoderBuffer':
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100193 print(' if (SUCCEEDED(_result)) {')
194 print(' m_MapDesc[Type] = std::make_pair(*ppBuffer, *pBufferSize);')
195 print(' } else {')
196 print(' m_MapDesc[Type] = std::make_pair(nullptr, 0);')
197 print(' }')
Jose Fonseca91403b62016-05-19 15:10:03 +0100198
Jose Fonseca982fa6b2016-04-09 14:09:57 +0100199 def invokeMethod(self, interface, base, method):
Andrii Simiklit3793ce32019-05-24 17:31:09 +0300200 if method.name == 'CreateBuffer':
201 if interface.name.startswith('ID3D11'):
202 print(r' D3D11_SUBRESOURCE_DATA initialData;')
203 else:
204 print(r' D3D10_SUBRESOURCE_DATA initialData;')
205 print(r' if (!pInitialData) {')
206 print(r' pInitialData = &initialData;')
207 print(r' _initialBufferAlloc(pDesc, &initialData);')
208 print(r' }')
209
Jose Fonseca982fa6b2016-04-09 14:09:57 +0100210 DllTracer.invokeMethod(self, interface, base, method)
211
212 # When D2D is used on top of WARP software rasterizer it seems to do
213 # most of its rendering via the undocumented and opaque IWarpPrivateAPI
214 # interface. Althought hiding this interface will affect behavior,
215 # there's little point in traces that use it, as they lack enough
216 # information to replay correctly.
217 #
218 # Returning E_NOINTERFACE when for IID_IWarpPrivateAPI matches what
219 # happens when D2D is used with drivers other than WARP.
220 if method.name == 'QueryInterface':
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100221 print(r' if (_result == S_OK && riid == IID_IWarpPrivateAPI && ppvObj && *ppvObj) {')
222 print(r' static_cast<IUnknown *>(*ppvObj)->Release();')
223 print(r' *ppvObj = nullptr;')
224 print(r' _result = E_NOINTERFACE;')
225 print(r' os::log("apitrace: warning: hiding IWarpPrivateAPI interface\n");')
226 print(r' }')
Jose Fonseca982fa6b2016-04-09 14:09:57 +0100227
Jose Fonsecaaaf4bb62020-05-08 09:23:24 +0100228 if interface.name.startswith('ID3D11Device') and method.name == 'CheckFeatureSupport':
229 print(r' if (FORCE_D3D_FEATURE_LEVEL_11_0 &&')
230 print(r' _result == S_OK &&')
231 print(r' Feature >= D3D11_FEATURE_D3D11_OPTIONS) {')
232 print(r' ZeroMemory(pFeatureSupportData, FeatureSupportDataSize);')
233 print(r' }')
234
235 if method.name == 'CheckMultisampleQualityLevels':
236 print(r' if (FORCE_D3D_FEATURE_LEVEL_11_0 &&')
237 print(r' _result == S_OK &&')
238 print(r' pNumQualityLevels && *pNumQualityLevels > 1) {')
239 print(r' *pNumQualityLevels = 1;')
240 print(r' }')
241
Jose Fonseca5057d102016-05-05 17:01:12 +0100242 # Ensure buffers are initialized, otherwise we can fail to detect
243 # changes when unititialized data matches what the app wrote.
244 if method.name == 'CreateBuffer':
Andrii Simiklit3793ce32019-05-24 17:31:09 +0300245 print(r' if (pInitialData == &initialData) {')
246 print(r' _initialBufferFree(&initialData);')
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100247 print(r' }')
Jose Fonseca5057d102016-05-05 17:01:12 +0100248
José Fonseca0168b512012-11-03 18:44:36 +0000249
José Fonseca20aa9352012-11-23 14:34:29 +0000250if __name__ == '__main__':
Piotr Podsiadły0b8b0192019-01-03 20:39:55 +0100251 print(r'#include "guids_defs.hpp"')
252 print()
253 print(r'#include "trace_writer_local.hpp"')
254 print(r'#include "os.hpp"')
255 print()
256 print(r'#include "dxgitrace.hpp"')
257 print()
José Fonseca20aa9352012-11-23 14:34:29 +0000258
Jose Fonsecaaaf4bb62020-05-08 09:23:24 +0100259 # TODO: Expose this via a runtime option
260 print('#define FORCE_D3D_FEATURE_LEVEL_11_0 0')
261
José Fonseca20aa9352012-11-23 14:34:29 +0000262 api = API()
José Fonsecafc58d052014-06-13 12:47:19 +0100263 api.addModule(dxgi.dxgi)
264 api.addModule(d3d10.d3d10)
Jose Fonsecaa92e0c42015-03-14 10:49:23 +0000265 api.addModule(d3d10.d3d10_1)
José Fonsecafc58d052014-06-13 12:47:19 +0100266 api.addModule(d3d11.d3d11)
Jose Fonsecabab19212016-01-31 23:58:30 +0000267 api.addModule(dcomp.dcomp)
José Fonsecae354d8d2015-02-06 10:30:01 +0000268 api.addModule(d3d9.d3dperf)
José Fonseca20aa9352012-11-23 14:34:29 +0000269
270 tracer = D3DCommonTracer()
271 tracer.traceApi(api)