blob: c6942eacfddc1cf7bd82319804db658d81cc00ec [file] [log] [blame]
José Fonsecae0e61402010-11-25 15:03:23 +00001##########################################################################
2#
3# Copyright 2010 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é Fonseca4a826ed2010-11-30 16:58:22 +000027"""Generic retracing code generator."""
28
José Fonseca0a37edf2011-10-09 09:45:22 +010029
José Fonseca9d27a542012-04-14 17:22:57 +010030# Adjust path
31import os.path
José Fonseca0a37edf2011-10-09 09:45:22 +010032import sys
José Fonseca9d27a542012-04-14 17:22:57 +010033sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
34
José Fonseca0a37edf2011-10-09 09:45:22 +010035
José Fonsecabd86a222011-09-27 09:21:38 +010036import specs.stdapi as stdapi
José Fonsecae0e61402010-11-25 15:03:23 +000037
38
José Fonseca2672a7d2012-04-14 15:17:12 +010039class UnsupportedType(Exception):
40 pass
41
42
Cass Everitt3b595cb2013-06-19 19:30:32 -050043def lookupHandle(handle, value, lval=False):
José Fonseca8a844ae2010-12-06 18:50:52 +000044 if handle.key is None:
José Fonseca632a78d2012-04-19 07:18:59 +010045 return "_%s_map[%s]" % (handle.name, value)
José Fonseca8a844ae2010-12-06 18:50:52 +000046 else:
47 key_name, key_type = handle.key
Cass Everitt3b595cb2013-06-19 19:30:32 -050048 if handle.name == "location" and lval == False:
49 return "_location_map[%s].lookupUniformLocation(%s)" % (key_name, value)
50 else:
51 return "_%s_map[%s][%s]" % (handle.name, key_name, value)
José Fonseca8a844ae2010-12-06 18:50:52 +000052
53
José Fonseca4a2c57b2012-04-07 10:50:53 +010054class ValueAllocator(stdapi.Visitor):
55
56 def visitLiteral(self, literal, lvalue, rvalue):
57 pass
58
59 def visitConst(self, const, lvalue, rvalue):
60 self.visit(const.type, lvalue, rvalue)
61
62 def visitAlias(self, alias, lvalue, rvalue):
63 self.visit(alias.type, lvalue, rvalue)
64
65 def visitEnum(self, enum, lvalue, rvalue):
66 pass
67
68 def visitBitmask(self, bitmask, lvalue, rvalue):
69 pass
70
71 def visitArray(self, array, lvalue, rvalue):
José Fonseca915d4da2014-09-05 11:55:17 +010072 print ' %s = _allocator.allocArray<%s>(&%s);' % (lvalue, array.type, rvalue)
José Fonseca4a2c57b2012-04-07 10:50:53 +010073
74 def visitPointer(self, pointer, lvalue, rvalue):
José Fonseca915d4da2014-09-05 11:55:17 +010075 print ' %s = _allocator.allocArray<%s>(&%s);' % (lvalue, pointer.type, rvalue)
José Fonseca4a2c57b2012-04-07 10:50:53 +010076
77 def visitIntPointer(self, pointer, lvalue, rvalue):
78 pass
79
80 def visitObjPointer(self, pointer, lvalue, rvalue):
81 pass
82
83 def visitLinearPointer(self, pointer, lvalue, rvalue):
84 pass
85
86 def visitReference(self, reference, lvalue, rvalue):
87 self.visit(reference.type, lvalue, rvalue);
88
89 def visitHandle(self, handle, lvalue, rvalue):
90 pass
91
92 def visitBlob(self, blob, lvalue, rvalue):
93 pass
94
95 def visitString(self, string, lvalue, rvalue):
96 pass
97
98 def visitStruct(self, struct, lvalue, rvalue):
99 pass
100
101 def visitPolymorphic(self, polymorphic, lvalue, rvalue):
José Fonsecadbf714b2012-11-20 17:03:43 +0000102 assert polymorphic.defaultType is not None
José Fonseca4a2c57b2012-04-07 10:50:53 +0100103 self.visit(polymorphic.defaultType, lvalue, rvalue)
104
José Fonseca2672a7d2012-04-14 15:17:12 +0100105 def visitOpaque(self, opaque, lvalue, rvalue):
106 pass
107
José Fonseca4a2c57b2012-04-07 10:50:53 +0100108
José Fonsecadbf714b2012-11-20 17:03:43 +0000109class ValueDeserializer(stdapi.Visitor, stdapi.ExpanderMixin):
José Fonsecae0e61402010-11-25 15:03:23 +0000110
José Fonseca54f304a2012-01-14 19:33:08 +0000111 def visitLiteral(self, literal, lvalue, rvalue):
José Fonseca2f2ea482011-10-15 15:10:06 +0100112 print ' %s = (%s).to%s();' % (lvalue, rvalue, literal.kind)
José Fonsecae0e61402010-11-25 15:03:23 +0000113
José Fonseca54f304a2012-01-14 19:33:08 +0000114 def visitConst(self, const, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000115 self.visit(const.type, lvalue, rvalue)
116
José Fonseca54f304a2012-01-14 19:33:08 +0000117 def visitAlias(self, alias, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000118 self.visit(alias.type, lvalue, rvalue)
119
José Fonseca54f304a2012-01-14 19:33:08 +0000120 def visitEnum(self, enum, lvalue, rvalue):
José Fonseca96ce6002012-04-02 08:10:48 +0200121 print ' %s = static_cast<%s>((%s).toSInt());' % (lvalue, enum, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000122
José Fonseca54f304a2012-01-14 19:33:08 +0000123 def visitBitmask(self, bitmask, lvalue, rvalue):
Jose Fonsecab29a5802016-05-20 23:40:35 +0100124 print ' %s = static_cast<%s>((%s).toUInt());' % (lvalue, bitmask, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000125
José Fonseca54f304a2012-01-14 19:33:08 +0000126 def visitArray(self, array, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100127 tmp = '_a_' + array.tag + '_' + str(self.seq)
José Fonseca68013c92012-04-05 19:58:38 +0100128 self.seq += 1
129
Jose Fonsecaf48264d2015-07-17 17:00:23 +0100130 print ' const trace::Array *%s = (%s).toArray();' % (tmp, rvalue)
131 print ' if (%s) {' % (tmp,)
Jose Fonseca41efd942015-06-10 22:54:18 +0100132
Jose Fonsecaf48264d2015-07-17 17:00:23 +0100133 length = '%s->values.size()' % (tmp,)
Jose Fonseca41efd942015-06-10 22:54:18 +0100134 if self.insideStruct:
135 if isinstance(array.length, int):
136 # Member is an array
137 print r' static_assert( std::is_array< std::remove_reference< decltype( %s ) >::type >::value , "lvalue must be an array" );' % lvalue
138 print r' static_assert( std::extent< std::remove_reference< decltype( %s ) >::type >::value == %s, "array size mismatch" );' % (lvalue, array.length)
Jose Fonsecaf48264d2015-07-17 17:00:23 +0100139 print r' assert( %s );' % (tmp,)
140 print r' assert( %s->size() == %s );' % (tmp, array.length)
141 length = str(array.length)
Jose Fonseca41efd942015-06-10 22:54:18 +0100142 else:
143 # Member is a pointer to an array, hence must be allocated
144 print r' static_assert( std::is_pointer< std::remove_reference< decltype( %s ) >::type >::value , "lvalue must be a pointer" );' % lvalue
145 print r' %s = _allocator.allocArray<%s>(&%s);' % (lvalue, array.type, rvalue)
146
José Fonseca632a78d2012-04-19 07:18:59 +0100147 index = '_j' + array.tag
José Fonsecadbaae492011-04-21 09:28:10 +0100148 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
José Fonsecae0e61402010-11-25 15:03:23 +0000149 try:
José Fonseca68013c92012-04-05 19:58:38 +0100150 self.visit(array.type, '%s[%s]' % (lvalue, index), '*%s->values[%s]' % (tmp, index))
José Fonsecae0e61402010-11-25 15:03:23 +0000151 finally:
152 print ' }'
José Fonsecae0e61402010-11-25 15:03:23 +0000153 print ' }'
154
José Fonseca54f304a2012-01-14 19:33:08 +0000155 def visitPointer(self, pointer, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100156 tmp = '_a_' + pointer.tag + '_' + str(self.seq)
José Fonseca68013c92012-04-05 19:58:38 +0100157 self.seq += 1
158
Jose Fonseca2e295882016-05-16 14:20:39 +0100159 if self.insideStruct:
160 # Member is a pointer to an object, hence must be allocated
161 print r' static_assert( std::is_pointer< std::remove_reference< decltype( %s ) >::type >::value , "lvalue must be a pointer" );' % lvalue
162 print r' %s = _allocator.allocArray<%s>(&%s);' % (lvalue, pointer.type, rvalue)
163
José Fonseca4a2c57b2012-04-07 10:50:53 +0100164 print ' if (%s) {' % (lvalue,)
Nigel Stewartabaef292013-07-10 09:01:01 -0500165 print ' const trace::Array *%s = (%s).toArray();' % (tmp, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000166 try:
José Fonseca68013c92012-04-05 19:58:38 +0100167 self.visit(pointer.type, '%s[0]' % (lvalue,), '*%s->values[0]' % (tmp,))
José Fonsecae0e61402010-11-25 15:03:23 +0000168 finally:
José Fonsecae0e61402010-11-25 15:03:23 +0000169 print ' }'
170
José Fonseca59ee88e2012-01-15 14:24:10 +0000171 def visitIntPointer(self, pointer, lvalue, rvalue):
172 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, pointer, rvalue)
173
José Fonsecafbcf6832012-04-05 07:10:30 +0100174 def visitObjPointer(self, pointer, lvalue, rvalue):
José Fonseca915d4da2014-09-05 11:55:17 +0100175 print ' %s = retrace::asObjPointer<%s>(call, %s);' % (lvalue, pointer.type, rvalue)
José Fonsecafbcf6832012-04-05 07:10:30 +0100176
José Fonseca59ee88e2012-01-15 14:24:10 +0000177 def visitLinearPointer(self, pointer, lvalue, rvalue):
178 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, pointer, rvalue)
179
José Fonsecab89c5932012-04-01 22:47:11 +0200180 def visitReference(self, reference, lvalue, rvalue):
181 self.visit(reference.type, lvalue, rvalue);
182
José Fonseca54f304a2012-01-14 19:33:08 +0000183 def visitHandle(self, handle, lvalue, rvalue):
José Fonseca59ee88e2012-01-15 14:24:10 +0000184 #OpaqueValueDeserializer().visit(handle.type, lvalue, rvalue);
185 self.visit(handle.type, lvalue, rvalue);
José Fonseca54f304a2012-01-14 19:33:08 +0000186 new_lvalue = lookupHandle(handle, lvalue)
Jose Fonseca28e29ee2017-07-30 14:21:48 +0100187 shaderObject = new_lvalue.startswith('_program_map') or new_lvalue.startswith('_shader_map')
188 if shaderObject:
189 print 'if (glretrace::supportsARBShaderObjects) {'
190 print ' if (retrace::verbosity >= 2) {'
191 print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(_handleARB_map[%s]) << "\\n";' % (handle.name, lvalue, lvalue)
192 print ' }'
193 print ' %s = _handleARB_map[%s];' % (lvalue, lvalue)
194 print '} else {'
José Fonseca031b7382011-05-10 20:36:40 +0100195 print ' if (retrace::verbosity >= 2) {'
José Fonsecaa10af892011-04-11 09:10:55 +0100196 print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
José Fonseca031b7382011-05-10 20:36:40 +0100197 print ' }'
Jose Fonseca28e29ee2017-07-30 14:21:48 +0100198 print ' %s = %s;' % (lvalue, new_lvalue)
199 if shaderObject:
Carl Worth37007772012-08-28 11:45:52 -0700200 print '}'
José Fonsecae0e61402010-11-25 15:03:23 +0000201
José Fonseca54f304a2012-01-14 19:33:08 +0000202 def visitBlob(self, blob, lvalue, rvalue):
José Fonseca7ebb9e22011-05-06 09:58:45 +0100203 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000204
José Fonseca54f304a2012-01-14 19:33:08 +0000205 def visitString(self, string, lvalue, rvalue):
José Fonseca7ebb9e22011-05-06 09:58:45 +0100206 print ' %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000207
José Fonsecaa65a23a2012-04-02 08:10:06 +0200208 seq = 0
209
Jose Fonseca41efd942015-06-10 22:54:18 +0100210 insideStruct = 0
211
José Fonsecaa65a23a2012-04-02 08:10:06 +0200212 def visitStruct(self, struct, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100213 tmp = '_s_' + struct.tag + '_' + str(self.seq)
José Fonsecaa65a23a2012-04-02 08:10:06 +0200214 self.seq += 1
215
Jose Fonseca41efd942015-06-10 22:54:18 +0100216 self.insideStruct += 1
217
Nigel Stewartabaef292013-07-10 09:01:01 -0500218 print ' const trace::Struct *%s = (%s).toStruct();' % (tmp, rvalue)
José Fonsecaa65a23a2012-04-02 08:10:06 +0200219 print ' assert(%s);' % (tmp)
José Fonsecaa65a23a2012-04-02 08:10:06 +0200220 for i in range(len(struct.members)):
José Fonsecadbf714b2012-11-20 17:03:43 +0000221 member = struct.members[i]
222 self.visitMember(member, lvalue, '*%s->members[%s]' % (tmp, i))
José Fonsecaa65a23a2012-04-02 08:10:06 +0200223
Jose Fonseca41efd942015-06-10 22:54:18 +0100224 self.insideStruct -= 1
225
José Fonseca4a2c57b2012-04-07 10:50:53 +0100226 def visitPolymorphic(self, polymorphic, lvalue, rvalue):
José Fonsecaeb216e62012-11-20 11:08:08 +0000227 if polymorphic.defaultType is None:
José Fonsecadbf714b2012-11-20 17:03:43 +0000228 switchExpr = self.expand(polymorphic.switchExpr)
229 print r' switch (%s) {' % switchExpr
230 for cases, type in polymorphic.iterSwitch():
231 for case in cases:
232 print r' %s:' % case
233 caseLvalue = lvalue
234 if type.expr is not None:
235 caseLvalue = 'static_cast<%s>(%s)' % (type, caseLvalue)
236 print r' {'
237 try:
238 self.visit(type, caseLvalue, rvalue)
239 finally:
240 print r' }'
241 print r' break;'
242 if polymorphic.defaultType is None:
243 print r' default:'
244 print r' retrace::warning(call) << "unexpected polymorphic case" << %s << "\n";' % (switchExpr,)
245 print r' break;'
246 print r' }'
247 else:
248 self.visit(polymorphic.defaultType, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100249
250 def visitOpaque(self, opaque, lvalue, rvalue):
251 raise UnsupportedType
José Fonseca4a2c57b2012-04-07 10:50:53 +0100252
José Fonsecae0e61402010-11-25 15:03:23 +0000253
José Fonseca54f304a2012-01-14 19:33:08 +0000254class OpaqueValueDeserializer(ValueDeserializer):
José Fonsecaa10af892011-04-11 09:10:55 +0100255 '''Value extractor that also understands opaque values.
256
257 Normally opaque values can't be retraced, unless they are being extracted
258 in the context of handles.'''
259
José Fonseca54f304a2012-01-14 19:33:08 +0000260 def visitOpaque(self, opaque, lvalue, rvalue):
José Fonseca46a48392011-10-14 11:34:27 +0100261 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, opaque, rvalue)
José Fonsecaa10af892011-04-11 09:10:55 +0100262
José Fonsecae0e61402010-11-25 15:03:23 +0000263
José Fonsecadbf714b2012-11-20 17:03:43 +0000264class SwizzledValueRegistrator(stdapi.Visitor, stdapi.ExpanderMixin):
José Fonseca54f304a2012-01-14 19:33:08 +0000265 '''Type visitor which will register (un)swizzled value pairs, to later be
266 swizzled.'''
José Fonsecae0e61402010-11-25 15:03:23 +0000267
José Fonseca54f304a2012-01-14 19:33:08 +0000268 def visitLiteral(self, literal, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000269 pass
270
José Fonseca54f304a2012-01-14 19:33:08 +0000271 def visitAlias(self, alias, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000272 self.visit(alias.type, lvalue, rvalue)
273
José Fonseca54f304a2012-01-14 19:33:08 +0000274 def visitEnum(self, enum, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000275 pass
276
José Fonseca54f304a2012-01-14 19:33:08 +0000277 def visitBitmask(self, bitmask, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000278 pass
279
José Fonseca54f304a2012-01-14 19:33:08 +0000280 def visitArray(self, array, lvalue, rvalue):
Nigel Stewartabaef292013-07-10 09:01:01 -0500281 print ' const trace::Array *_a%s = (%s).toArray();' % (array.tag, rvalue)
José Fonseca632a78d2012-04-19 07:18:59 +0100282 print ' if (_a%s) {' % (array.tag)
283 length = '_a%s->values.size()' % array.tag
284 index = '_j' + array.tag
José Fonsecadbaae492011-04-21 09:28:10 +0100285 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
José Fonsecae0e61402010-11-25 15:03:23 +0000286 try:
José Fonseca632a78d2012-04-19 07:18:59 +0100287 self.visit(array.type, '%s[%s]' % (lvalue, index), '*_a%s->values[%s]' % (array.tag, index))
José Fonsecae0e61402010-11-25 15:03:23 +0000288 finally:
289 print ' }'
290 print ' }'
291
José Fonseca54f304a2012-01-14 19:33:08 +0000292 def visitPointer(self, pointer, lvalue, rvalue):
Nigel Stewartabaef292013-07-10 09:01:01 -0500293 print ' const trace::Array *_a%s = (%s).toArray();' % (pointer.tag, rvalue)
José Fonseca632a78d2012-04-19 07:18:59 +0100294 print ' if (_a%s) {' % (pointer.tag)
José Fonsecae0e61402010-11-25 15:03:23 +0000295 try:
José Fonseca632a78d2012-04-19 07:18:59 +0100296 self.visit(pointer.type, '%s[0]' % (lvalue,), '*_a%s->values[0]' % (pointer.tag,))
José Fonsecae0e61402010-11-25 15:03:23 +0000297 finally:
298 print ' }'
299
José Fonseca59ee88e2012-01-15 14:24:10 +0000300 def visitIntPointer(self, pointer, lvalue, rvalue):
301 pass
302
José Fonsecafbcf6832012-04-05 07:10:30 +0100303 def visitObjPointer(self, pointer, lvalue, rvalue):
José Fonsecad8068b32012-11-13 21:37:42 +0000304 print r' retrace::addObj(call, %s, %s);' % (rvalue, lvalue)
José Fonsecafbcf6832012-04-05 07:10:30 +0100305
José Fonseca59ee88e2012-01-15 14:24:10 +0000306 def visitLinearPointer(self, pointer, lvalue, rvalue):
307 assert pointer.size is not None
308 if pointer.size is not None:
Jose Fonsecae05718d2015-05-20 10:22:56 +0100309 print r' retrace::addRegion(call, (%s).toUIntPtr(), %s, %s);' % (rvalue, lvalue, pointer.size)
José Fonseca59ee88e2012-01-15 14:24:10 +0000310
José Fonsecab89c5932012-04-01 22:47:11 +0200311 def visitReference(self, reference, lvalue, rvalue):
312 pass
313
José Fonseca54f304a2012-01-14 19:33:08 +0000314 def visitHandle(self, handle, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100315 print ' %s _origResult;' % handle.type
316 OpaqueValueDeserializer().visit(handle.type, '_origResult', rvalue);
José Fonsecad922e1d2010-11-25 17:14:02 +0000317 if handle.range is None:
José Fonseca632a78d2012-04-19 07:18:59 +0100318 rvalue = "_origResult"
Cass Everitt3b595cb2013-06-19 19:30:32 -0500319 entry = lookupHandle(handle, rvalue, True)
Carl Worth37007772012-08-28 11:45:52 -0700320 if (entry.startswith('_program_map') or entry.startswith('_shader_map')):
321 print 'if (glretrace::supportsARBShaderObjects) {'
322 print ' _handleARB_map[%s] = %s;' % (rvalue, lvalue)
323 print '} else {'
324 print ' %s = %s;' % (entry, lvalue)
325 print '}'
326 else:
327 print " %s = %s;" % (entry, lvalue)
Ilia Mirkin8db03b72017-11-26 14:23:35 -0500328 if entry.startswith('_textureHandle_map') or entry.startswith('_imageHandle_map'):
329 print ' if (%s != %s) {' % (rvalue, lvalue)
330 print ' std::cout << "Bindless handle doesn\'t match, GPU failures ahead.\\n";'
331 print ' }'
332
José Fonseca031b7382011-05-10 20:36:40 +0100333 print ' if (retrace::verbosity >= 2) {'
José Fonseca8a844ae2010-12-06 18:50:52 +0000334 print ' std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
José Fonseca031b7382011-05-10 20:36:40 +0100335 print ' }'
José Fonsecad922e1d2010-11-25 17:14:02 +0000336 else:
José Fonseca632a78d2012-04-19 07:18:59 +0100337 i = '_h' + handle.tag
José Fonseca8a844ae2010-12-06 18:50:52 +0000338 lvalue = "%s + %s" % (lvalue, i)
José Fonseca632a78d2012-04-19 07:18:59 +0100339 rvalue = "_origResult + %s" % (i,)
José Fonseca54f304a2012-01-14 19:33:08 +0000340 entry = lookupHandle(handle, rvalue)
José Fonsecadbaae492011-04-21 09:28:10 +0100341 print ' for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
José Fonseca8a844ae2010-12-06 18:50:52 +0000342 print ' {entry} = {lvalue};'.format(**locals())
José Fonseca031b7382011-05-10 20:36:40 +0100343 print ' if (retrace::verbosity >= 2) {'
José Fonseca8a844ae2010-12-06 18:50:52 +0000344 print ' std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
José Fonseca031b7382011-05-10 20:36:40 +0100345 print ' }'
José Fonsecad922e1d2010-11-25 17:14:02 +0000346 print ' }'
José Fonsecae0e61402010-11-25 15:03:23 +0000347
José Fonseca54f304a2012-01-14 19:33:08 +0000348 def visitBlob(self, blob, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000349 pass
350
José Fonseca54f304a2012-01-14 19:33:08 +0000351 def visitString(self, string, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000352 pass
353
José Fonseca4a2c57b2012-04-07 10:50:53 +0100354 seq = 0
355
356 def visitStruct(self, struct, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100357 tmp = '_s_' + struct.tag + '_' + str(self.seq)
José Fonseca4a2c57b2012-04-07 10:50:53 +0100358 self.seq += 1
359
Nigel Stewartabaef292013-07-10 09:01:01 -0500360 print ' const trace::Struct *%s = (%s).toStruct();' % (tmp, rvalue)
José Fonseca4a2c57b2012-04-07 10:50:53 +0100361 print ' assert(%s);' % (tmp,)
362 print ' (void)%s;' % (tmp,)
363 for i in range(len(struct.members)):
José Fonsecadbf714b2012-11-20 17:03:43 +0000364 member = struct.members[i]
365 self.visitMember(member, lvalue, '*%s->members[%s]' % (tmp, i))
José Fonseca4a2c57b2012-04-07 10:50:53 +0100366
367 def visitPolymorphic(self, polymorphic, lvalue, rvalue):
José Fonsecadbf714b2012-11-20 17:03:43 +0000368 assert polymorphic.defaultType is not None
José Fonseca4a2c57b2012-04-07 10:50:53 +0100369 self.visit(polymorphic.defaultType, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100370
371 def visitOpaque(self, opaque, lvalue, rvalue):
372 pass
José Fonseca4a2c57b2012-04-07 10:50:53 +0100373
José Fonsecae0e61402010-11-25 15:03:23 +0000374
José Fonsecae0e61402010-11-25 15:03:23 +0000375class Retracer:
376
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000377 def makeFunctionId(self, function):
378 name = function.name
379 if function.overloaded:
380 # TODO: Use a sequence number
381 name += '__%08x' % (hash(function) & 0xffffffff)
382 return name
383
José Fonseca54f304a2012-01-14 19:33:08 +0000384 def retraceFunction(self, function):
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000385 print 'static void retrace_%s(trace::Call &call) {' % self.makeFunctionId(function)
José Fonseca54f304a2012-01-14 19:33:08 +0000386 self.retraceFunctionBody(function)
José Fonseca62212972011-03-23 13:22:55 +0000387 print '}'
388 print
389
José Fonseca8e3c2c02012-01-23 00:30:35 +0000390 def retraceInterfaceMethod(self, interface, method):
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000391 print 'static void retrace_%s__%s(trace::Call &call) {' % (interface.name, self.makeFunctionId(method))
José Fonseca8e3c2c02012-01-23 00:30:35 +0000392 self.retraceInterfaceMethodBody(interface, method)
393 print '}'
394 print
395
José Fonseca54f304a2012-01-14 19:33:08 +0000396 def retraceFunctionBody(self, function):
José Fonsecadd27f9f2012-04-13 13:57:23 +0100397 assert function.sideeffects
José Fonseca4d7f1fe2011-05-09 20:54:31 +0100398
José Fonseca7c7c9062012-04-27 13:02:08 +0100399 if function.type is not stdapi.Void:
400 self.checkOrigResult(function)
401
José Fonseca8e3c2c02012-01-23 00:30:35 +0000402 self.deserializeArgs(function)
403
José Fonseca3db3b2f2012-05-11 14:55:50 +0100404 self.declareRet(function)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000405 self.invokeFunction(function)
406
407 self.swizzleValues(function)
408
409 def retraceInterfaceMethodBody(self, interface, method):
José Fonseca1da480d2012-04-13 17:36:19 +0100410 assert method.sideeffects
José Fonseca8e3c2c02012-01-23 00:30:35 +0000411
José Fonseca7c7c9062012-04-27 13:02:08 +0100412 if method.type is not stdapi.Void:
413 self.checkOrigResult(method)
414
José Fonseca8e3c2c02012-01-23 00:30:35 +0000415 self.deserializeThisPointer(interface)
416
417 self.deserializeArgs(method)
418
José Fonseca3db3b2f2012-05-11 14:55:50 +0100419 self.declareRet(method)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000420 self.invokeInterfaceMethod(interface, method)
421
422 self.swizzleValues(method)
423
José Fonseca7c7c9062012-04-27 13:02:08 +0100424 def checkOrigResult(self, function):
425 '''Hook for checking the original result, to prevent succeeding now
426 where the original did not, which would cause diversion and potentially
427 unpredictable results.'''
428
429 assert function.type is not stdapi.Void
430
431 if str(function.type) == 'HRESULT':
432 print r' if (call.ret && FAILED(call.ret->toSInt())) {'
433 print r' return;'
434 print r' }'
435
José Fonseca8e3c2c02012-01-23 00:30:35 +0000436 def deserializeThisPointer(self, interface):
José Fonsecadc279372012-04-05 19:58:20 +0100437 print r' %s *_this;' % (interface.name,)
José Fonseca915d4da2014-09-05 11:55:17 +0100438 print r' _this = retrace::asObjPointer<%s>(call, call.arg(0));' % (interface.name,)
José Fonsecadc279372012-04-05 19:58:20 +0100439 print r' if (!_this) {'
José Fonsecadc279372012-04-05 19:58:20 +0100440 print r' return;'
441 print r' }'
José Fonseca8e3c2c02012-01-23 00:30:35 +0000442
443 def deserializeArgs(self, function):
José Fonsecad994cf02011-11-03 19:35:53 +0000444 print ' retrace::ScopedAllocator _allocator;'
445 print ' (void)_allocator;'
José Fonsecae0e61402010-11-25 15:03:23 +0000446 success = True
447 for arg in function.args:
José Fonseca0075f152012-04-14 20:25:52 +0100448 arg_type = arg.type.mutable()
José Fonsecae0e61402010-11-25 15:03:23 +0000449 print ' %s %s;' % (arg_type, arg.name)
450 rvalue = 'call.arg(%u)' % (arg.index,)
451 lvalue = arg.name
452 try:
José Fonseca54f304a2012-01-14 19:33:08 +0000453 self.extractArg(function, arg, arg_type, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100454 except UnsupportedType:
José Fonseca8e3c2c02012-01-23 00:30:35 +0000455 success = False
José Fonseca2d216ae2012-04-01 22:48:24 +0200456 print ' memset(&%s, 0, sizeof %s); // FIXME' % (arg.name, arg.name)
José Fonseca4a2c57b2012-04-07 10:50:53 +0100457 print
José Fonseca8e3c2c02012-01-23 00:30:35 +0000458
José Fonsecae0e61402010-11-25 15:03:23 +0000459 if not success:
José Fonseca9109c3a2011-05-24 19:31:26 +0100460 print ' if (1) {'
José Fonseca54f304a2012-01-14 19:33:08 +0000461 self.failFunction(function)
José Fonsecaeb216e62012-11-20 11:08:08 +0000462 sys.stderr.write('warning: unsupported %s call\n' % function.name)
José Fonseca9109c3a2011-05-24 19:31:26 +0100463 print ' }'
José Fonseca8e3c2c02012-01-23 00:30:35 +0000464
465 def swizzleValues(self, function):
José Fonsecae0e61402010-11-25 15:03:23 +0000466 for arg in function.args:
467 if arg.output:
José Fonseca0075f152012-04-14 20:25:52 +0100468 arg_type = arg.type.mutable()
José Fonsecae0e61402010-11-25 15:03:23 +0000469 rvalue = 'call.arg(%u)' % (arg.index,)
470 lvalue = arg.name
471 try:
José Fonseca54f304a2012-01-14 19:33:08 +0000472 self.regiterSwizzledValue(arg_type, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100473 except UnsupportedType:
José Fonseca0a37edf2011-10-09 09:45:22 +0100474 print ' // XXX: %s' % arg.name
José Fonsecae0e61402010-11-25 15:03:23 +0000475 if function.type is not stdapi.Void:
476 rvalue = '*call.ret'
José Fonseca632a78d2012-04-19 07:18:59 +0100477 lvalue = '_result'
José Fonsecae0e61402010-11-25 15:03:23 +0000478 try:
José Fonseca54f304a2012-01-14 19:33:08 +0000479 self.regiterSwizzledValue(function.type, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100480 except UnsupportedType:
José Fonsecafbcf6832012-04-05 07:10:30 +0100481 raise
José Fonseca46a48392011-10-14 11:34:27 +0100482 print ' // XXX: result'
José Fonsecae0e61402010-11-25 15:03:23 +0000483
José Fonseca54f304a2012-01-14 19:33:08 +0000484 def failFunction(self, function):
José Fonsecab1bb3c22011-10-08 20:23:18 +0100485 print ' if (retrace::verbosity >= 0) {'
José Fonsecaf5cda412011-10-09 17:27:23 +0100486 print ' retrace::unsupported(call);'
José Fonsecab1bb3c22011-10-08 20:23:18 +0100487 print ' }'
José Fonsecafa15d332010-11-25 20:22:39 +0000488 print ' return;'
489
José Fonseca54f304a2012-01-14 19:33:08 +0000490 def extractArg(self, function, arg, arg_type, lvalue, rvalue):
José Fonseca4a2c57b2012-04-07 10:50:53 +0100491 ValueAllocator().visit(arg_type, lvalue, rvalue)
492 if arg.input:
493 ValueDeserializer().visit(arg_type, lvalue, rvalue)
José Fonsecafd34e4e2011-06-03 19:34:29 +0100494
José Fonseca54f304a2012-01-14 19:33:08 +0000495 def extractOpaqueArg(self, function, arg, arg_type, lvalue, rvalue):
José Fonseca4a2c57b2012-04-07 10:50:53 +0100496 try:
497 ValueAllocator().visit(arg_type, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100498 except UnsupportedType:
José Fonseca4a2c57b2012-04-07 10:50:53 +0100499 pass
José Fonseca54f304a2012-01-14 19:33:08 +0000500 OpaqueValueDeserializer().visit(arg_type, lvalue, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000501
José Fonseca54f304a2012-01-14 19:33:08 +0000502 def regiterSwizzledValue(self, type, lvalue, rvalue):
503 visitor = SwizzledValueRegistrator()
504 visitor.visit(type, lvalue, rvalue)
505
José Fonseca3db3b2f2012-05-11 14:55:50 +0100506 def declareRet(self, function):
507 if function.type is not stdapi.Void:
508 print ' %s _result;' % (function.type)
509
José Fonseca54f304a2012-01-14 19:33:08 +0000510 def invokeFunction(self, function):
Jose Fonsecaf39fd602017-08-23 15:13:39 +0100511 # Same as invokeFunction, but without error checking
512 #
513 # XXX: Find a better name
514 self.doInvokeFunction(function)
515 if function.type is not stdapi.Void:
516 self.checkResult(None, function)
517
518 def doInvokeFunction(self, function):
José Fonseca59ee88e2012-01-15 14:24:10 +0000519 arg_names = ", ".join(function.argNames())
José Fonsecafa15d332010-11-25 20:22:39 +0000520 if function.type is not stdapi.Void:
José Fonseca632a78d2012-04-19 07:18:59 +0100521 print ' _result = %s(%s);' % (function.name, arg_names)
José Fonsecafa15d332010-11-25 20:22:39 +0000522 else:
523 print ' %s(%s);' % (function.name, arg_names)
524
Jose Fonsecad9ff09f2016-05-16 14:04:36 +0100525 def doInvokeInterfaceMethod(self, interface, method):
526 # Same as invokeInterfaceMethod, but without error checking
527 #
528 # XXX: Find a better name
529
José Fonseca8e3c2c02012-01-23 00:30:35 +0000530 arg_names = ", ".join(method.argNames())
531 if method.type is not stdapi.Void:
José Fonseca632a78d2012-04-19 07:18:59 +0100532 print ' _result = _this->%s(%s);' % (method.name, arg_names)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000533 else:
534 print ' _this->%s(%s);' % (method.name, arg_names)
535
José Fonsecada777082015-02-09 11:18:36 +0000536 # Adjust reference count when QueryInterface fails. This is
537 # particularly useful when replaying traces on older Direct3D runtimes
538 # which might miss newer versions of interfaces, yet none of those
539 # methods are actually used.
540 #
541 # TODO: Generalize to other methods that return interfaces
542 if method.name == 'QueryInterface':
543 print r' if (FAILED(_result)) {'
544 print r' IUnknown *pObj = retrace::asObjPointer<IUnknown>(call, *call.arg(2).toArray()->values[0]);'
545 print r' if (pObj) {'
546 print r' pObj->AddRef();'
547 print r' }'
548 print r' }'
549
José Fonseca8a4462e2014-09-23 14:39:01 +0100550 # Debug COM reference counting. Disabled by default as reported
551 # reference counts depend on internal implementation details.
552 if method.name in ('AddRef', 'Release'):
553 print r' if (0) retrace::checkMismatch(call, "cRef", call.ret, _result);'
554
555 # On release our reference when we reach Release() == 0 call in the
556 # trace.
557 if method.name == 'Release':
558 print r' ULONG _orig_result = call.ret->toUInt();'
559 print r' if (_orig_result == 0 || _result == 0) {'
560 print r' if (_orig_result != 0) {'
561 print r' retrace::warning(call) << "unexpected object destruction\n";'
562 print r' }'
Jose Fonsecaf56b86d2016-06-28 22:26:45 +0100563 print r' // NOTE: Must not delete the object mapping here. See'
564 print r' // https://github.com/apitrace/apitrace/issues/462'
José Fonseca8a4462e2014-09-23 14:39:01 +0100565 print r' }'
566
Jose Fonsecad9ff09f2016-05-16 14:04:36 +0100567 def invokeInterfaceMethod(self, interface, method):
568 self.doInvokeInterfaceMethod(interface, method)
569
570 if method.type is not stdapi.Void:
571 self.checkResult(interface, method)
572
Jose Fonseca5c487ec2015-06-02 22:16:52 +0100573 def checkResult(self, interface, methodOrFunction):
574 assert methodOrFunction.type is not stdapi.Void
575 if str(methodOrFunction.type) == 'HRESULT':
José Fonseca4f49d212012-11-14 14:02:35 +0000576 print r' if (FAILED(_result)) {'
José Fonseca64add5f2014-09-05 11:53:11 +0100577 print r' retrace::failed(call, _result);'
Jose Fonsecad0094a22017-05-30 12:31:37 +0100578 self.handleFailure(interface, methodOrFunction)
José Fonseca4f49d212012-11-14 14:02:35 +0000579 print r' }'
José Fonseca31983872015-02-09 11:16:20 +0000580 else:
581 print r' (void)_result;'
José Fonseca4f49d212012-11-14 14:02:35 +0000582
Jose Fonsecad0094a22017-05-30 12:31:37 +0100583 def handleFailure(self, interface, methodOrFunction):
584 print r' return;'
585
José Fonsecafacdb352014-09-05 13:22:01 +0100586 def checkPitchMismatch(self, method):
José Fonseca9a3abc72014-09-23 14:39:18 +0100587 # Warn for mismatches in 2D/3D mappings.
588 # FIXME: We should try to swizzle them. It's a bit of work, but possible.
589 for outArg in method.args:
590 if outArg.output \
591 and isinstance(outArg.type, stdapi.Pointer) \
592 and isinstance(outArg.type.type, stdapi.Struct):
593 print r' const trace::Array *_%s = call.arg(%u).toArray();' % (outArg.name, outArg.index)
594 print r' if (%s) {' % outArg.name
595 print r' const trace::Struct *_struct = _%s->values[0]->toStruct();' % (outArg.name)
596 print r' if (_struct) {'
597 struct = outArg.type.type
598 for memberIndex in range(len(struct.members)):
599 memberType, memberName = struct.members[memberIndex]
600 if memberName.endswith('Pitch'):
Jose Fonseca1e3c0f72015-07-20 21:50:42 +0100601 print r' if (%s->%s) {' % (outArg.name, memberName)
602 print r' retrace::checkMismatch(call, "%s", _struct->members[%u], %s->%s);' % (memberName, memberIndex, outArg.name, memberName)
603 print r' }'
José Fonseca9a3abc72014-09-23 14:39:18 +0100604 print r' }'
605 print r' }'
José Fonsecafacdb352014-09-05 13:22:01 +0100606
José Fonseca54f304a2012-01-14 19:33:08 +0000607 def filterFunction(self, function):
José Fonseca4441baf2010-11-25 19:55:27 +0000608 return True
609
José Fonseca2741ed82011-10-07 23:36:39 +0100610 table_name = 'retrace::callbacks'
611
José Fonseca54f304a2012-01-14 19:33:08 +0000612 def retraceApi(self, api):
José Fonsecae0e61402010-11-25 15:03:23 +0000613
José Fonseca412149c2012-04-01 22:47:30 +0200614 print '#include "os_time.hpp"'
José Fonsecae0e61402010-11-25 15:03:23 +0000615 print '#include "trace_parser.hpp"'
José Fonseca91343f52011-04-01 08:37:06 +0100616 print '#include "retrace.hpp"'
José Fonsecaab8142f2012-05-13 10:04:19 +0100617 print '#include "retrace_swizzle.hpp"'
José Fonsecae0e61402010-11-25 15:03:23 +0000618 print
619
José Fonseca44703822012-01-31 10:48:58 +0000620 types = api.getAllTypes()
José Fonsecae0e61402010-11-25 15:03:23 +0000621 handles = [type for type in types if isinstance(type, stdapi.Handle)]
José Fonsecad922e1d2010-11-25 17:14:02 +0000622 handle_names = set()
José Fonsecae0e61402010-11-25 15:03:23 +0000623 for handle in handles:
José Fonsecad922e1d2010-11-25 17:14:02 +0000624 if handle.name not in handle_names:
José Fonseca8a844ae2010-12-06 18:50:52 +0000625 if handle.key is None:
José Fonseca632a78d2012-04-19 07:18:59 +0100626 print 'static retrace::map<%s> _%s_map;' % (handle.type, handle.name)
José Fonseca8a844ae2010-12-06 18:50:52 +0000627 else:
628 key_name, key_type = handle.key
José Fonseca632a78d2012-04-19 07:18:59 +0100629 print 'static std::map<%s, retrace::map<%s> > _%s_map;' % (key_type, handle.type, handle.name)
José Fonsecad922e1d2010-11-25 17:14:02 +0000630 handle_names.add(handle.name)
José Fonsecae0e61402010-11-25 15:03:23 +0000631 print
632
José Fonseca81301932012-11-11 00:10:20 +0000633 functions = filter(self.filterFunction, api.getAllFunctions())
José Fonseca8e3c2c02012-01-23 00:30:35 +0000634 for function in functions:
José Fonseca84cea3b2012-05-09 21:12:30 +0100635 if function.sideeffects and not function.internal:
José Fonseca1da480d2012-04-13 17:36:19 +0100636 self.retraceFunction(function)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000637 interfaces = api.getAllInterfaces()
638 for interface in interfaces:
José Fonseca14aa1712014-08-22 15:36:55 +0100639 for method in interface.methods:
José Fonseca84cea3b2012-05-09 21:12:30 +0100640 if method.sideeffects and not method.internal:
José Fonseca1da480d2012-04-13 17:36:19 +0100641 self.retraceInterfaceMethod(interface, method)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000642
643 print 'const retrace::Entry %s[] = {' % self.table_name
644 for function in functions:
José Fonseca84cea3b2012-05-09 21:12:30 +0100645 if not function.internal:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000646 sigName = function.sigName()
José Fonseca84cea3b2012-05-09 21:12:30 +0100647 if function.sideeffects:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000648 print ' {"%s", &retrace_%s},' % (sigName, self.makeFunctionId(function))
José Fonseca84cea3b2012-05-09 21:12:30 +0100649 else:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000650 print ' {"%s", &retrace::ignore},' % (sigName,)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000651 for interface in interfaces:
José Fonseca14aa1712014-08-22 15:36:55 +0100652 for base, method in interface.iterBaseMethods():
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000653 sigName = method.sigName()
José Fonseca1da480d2012-04-13 17:36:19 +0100654 if method.sideeffects:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000655 print ' {"%s::%s", &retrace_%s__%s},' % (interface.name, sigName, base.name, self.makeFunctionId(method))
José Fonseca1da480d2012-04-13 17:36:19 +0100656 else:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000657 print ' {"%s::%s", &retrace::ignore},' % (interface.name, sigName)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000658 print ' {NULL, NULL}'
659 print '};'
660 print
José Fonsecae0e61402010-11-25 15:03:23 +0000661