blob: ae80b91accdb255e329de2af90da7bfcb28a13df [file] [log] [blame]
Mark Lobodzinskiff910992016-10-11 14:29:52 -06001#!/usr/bin/python3 -i
2#
3# Copyright (c) 2015-2016 The Khronos Group Inc.
4# Copyright (c) 2015-2016 Valve Corporation
5# Copyright (c) 2015-2016 LunarG, Inc.
6# Copyright (c) 2015-2016 Google Inc.
7#
8# Licensed under the Apache License, Version 2.0 (the "License");
9# you may not use this file except in compliance with the License.
10# You may obtain a copy of the License at
11#
12# http://www.apache.org/licenses/LICENSE-2.0
13#
14# Unless required by applicable law or agreed to in writing, software
15# distributed under the License is distributed on an "AS IS" BASIS,
16# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17# See the License for the specific language governing permissions and
18# limitations under the License.
19#
20# Author: Mike Stroyan <stroyan@google.com>
Mark Lobodzinskid3b439e2017-06-07 13:08:41 -060021# Author: Mark Lobodzinski <mark@lunarg.com>
Mark Lobodzinskiff910992016-10-11 14:29:52 -060022
23import os,re,sys
24from generator import *
Mark Lobodzinski62f71562017-10-24 13:41:18 -060025from common_codegen import *
Mark Lobodzinskiff910992016-10-11 14:29:52 -060026
27# ThreadGeneratorOptions - subclass of GeneratorOptions.
28#
29# Adds options used by ThreadOutputGenerator objects during threading
30# layer generation.
31#
32# Additional members
33# prefixText - list of strings to prefix generated header with
34# (usually a copyright statement + calling convention macros).
35# protectFile - True if multiple inclusion protection should be
36# generated (based on the filename) around the entire header.
37# protectFeature - True if #ifndef..#endif protection should be
38# generated around a feature interface in the header file.
39# genFuncPointers - True if function pointer typedefs should be
40# generated
41# protectProto - If conditional protection should be generated
42# around prototype declarations, set to either '#ifdef'
43# to require opt-in (#ifdef protectProtoStr) or '#ifndef'
44# to require opt-out (#ifndef protectProtoStr). Otherwise
45# set to None.
46# protectProtoStr - #ifdef/#ifndef symbol to use around prototype
47# declarations, if protectProto is set
48# apicall - string to use for the function declaration prefix,
49# such as APICALL on Windows.
50# apientry - string to use for the calling convention macro,
51# in typedefs, such as APIENTRY.
52# apientryp - string to use for the calling convention macro
53# in function pointer typedefs, such as APIENTRYP.
54# indentFuncProto - True if prototype declarations should put each
55# parameter on a separate line
56# indentFuncPointer - True if typedefed function pointers should put each
57# parameter on a separate line
58# alignFuncParam - if nonzero and parameters are being put on a
59# separate line, align parameter names at the specified column
60class ThreadGeneratorOptions(GeneratorOptions):
61 def __init__(self,
62 filename = None,
63 directory = '.',
64 apiname = None,
65 profile = None,
66 versions = '.*',
67 emitversions = '.*',
68 defaultExtensions = None,
69 addExtensions = None,
70 removeExtensions = None,
Mark Lobodzinski62f71562017-10-24 13:41:18 -060071 emitExtensions = None,
Mark Lobodzinskiff910992016-10-11 14:29:52 -060072 sortProcedure = regSortFeatures,
73 prefixText = "",
74 genFuncPointers = True,
75 protectFile = True,
76 protectFeature = True,
Mark Lobodzinskiff910992016-10-11 14:29:52 -060077 apicall = '',
78 apientry = '',
79 apientryp = '',
80 indentFuncProto = True,
81 indentFuncPointer = False,
Mark Lobodzinski62f71562017-10-24 13:41:18 -060082 alignFuncParam = 0,
83 expandEnumerants = True):
Mark Lobodzinskiff910992016-10-11 14:29:52 -060084 GeneratorOptions.__init__(self, filename, directory, apiname, profile,
85 versions, emitversions, defaultExtensions,
Mark Lobodzinski62f71562017-10-24 13:41:18 -060086 addExtensions, removeExtensions, emitExtensions, sortProcedure)
Mark Lobodzinskiff910992016-10-11 14:29:52 -060087 self.prefixText = prefixText
88 self.genFuncPointers = genFuncPointers
89 self.protectFile = protectFile
90 self.protectFeature = protectFeature
Mark Lobodzinskiff910992016-10-11 14:29:52 -060091 self.apicall = apicall
92 self.apientry = apientry
93 self.apientryp = apientryp
94 self.indentFuncProto = indentFuncProto
95 self.indentFuncPointer = indentFuncPointer
96 self.alignFuncParam = alignFuncParam
Mark Lobodzinski62f71562017-10-24 13:41:18 -060097 self.expandEnumerants = expandEnumerants
98
Mark Lobodzinskiff910992016-10-11 14:29:52 -060099
100# ThreadOutputGenerator - subclass of OutputGenerator.
101# Generates Thread checking framework
102#
103# ---- methods ----
104# ThreadOutputGenerator(errFile, warnFile, diagFile) - args as for
105# OutputGenerator. Defines additional internal state.
106# ---- methods overriding base class ----
107# beginFile(genOpts)
108# endFile()
109# beginFeature(interface, emit)
110# endFeature()
111# genType(typeinfo,name)
112# genStruct(typeinfo,name)
113# genGroup(groupinfo,name)
114# genEnum(enuminfo, name)
115# genCmd(cmdinfo)
116class ThreadOutputGenerator(OutputGenerator):
117 """Generate specified API interfaces in a specific style, such as a C header"""
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700118
119 inline_copyright_message = """
120// This file is ***GENERATED***. Do Not Edit.
121// See layer_chassis_dispatch_generator.py for modifications.
122
123/* Copyright (c) 2015-2018 The Khronos Group Inc.
124 * Copyright (c) 2015-2018 Valve Corporation
125 * Copyright (c) 2015-2018 LunarG, Inc.
126 * Copyright (c) 2015-2018 Google Inc.
127 *
128 * Licensed under the Apache License, Version 2.0 (the "License");
129 * you may not use this file except in compliance with the License.
130 * You may obtain a copy of the License at
131 *
132 * http://www.apache.org/licenses/LICENSE-2.0
133 *
134 * Unless required by applicable law or agreed to in writing, software
135 * distributed under the License is distributed on an "AS IS" BASIS,
136 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137 * See the License for the specific language governing permissions and
138 * limitations under the License.
139 *
140 * Author: Mark Lobodzinski <mark@lunarg.com>
141 */"""
142
143 inline_custom_source_preamble = """
144void ThreadSafety::PreCallRecordAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo,
145 VkCommandBuffer *pCommandBuffers) {
146 StartReadObject(device);
147 StartWriteObject(pAllocateInfo->commandPool);
148}
149
150void ThreadSafety::PostCallRecordAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo,
151 VkCommandBuffer *pCommandBuffers) {
152 FinishReadObject(device);
153 FinishWriteObject(pAllocateInfo->commandPool);
154
155 // Record mapping from command buffer to command pool
156 for (uint32_t index = 0; index < pAllocateInfo->commandBufferCount; index++) {
157 std::lock_guard<std::mutex> lock(command_pool_lock);
158 command_pool_map[pCommandBuffers[index]] = pAllocateInfo->commandPool;
159 }
160}
161
162void ThreadSafety::PreCallRecordAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
163 VkDescriptorSet *pDescriptorSets) {
164 StartReadObject(device);
165 StartWriteObject(pAllocateInfo->descriptorPool);
166 // Host access to pAllocateInfo::descriptorPool must be externally synchronized
167}
168
169void ThreadSafety::PostCallRecordAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
170 VkDescriptorSet *pDescriptorSets) {
171 FinishReadObject(device);
172 FinishWriteObject(pAllocateInfo->descriptorPool);
173 // Host access to pAllocateInfo::descriptorPool must be externally synchronized
174}
175
176void ThreadSafety::PreCallRecordFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
177 const VkCommandBuffer *pCommandBuffers) {
178 const bool lockCommandPool = false; // pool is already directly locked
179 StartReadObject(device);
180 StartWriteObject(commandPool);
181 for (uint32_t index = 0; index < commandBufferCount; index++) {
182 StartWriteObject(pCommandBuffers[index], lockCommandPool);
183 }
184 // The driver may immediately reuse command buffers in another thread.
185 // These updates need to be done before calling down to the driver.
186 for (uint32_t index = 0; index < commandBufferCount; index++) {
187 FinishWriteObject(pCommandBuffers[index], lockCommandPool);
188 std::lock_guard<std::mutex> lock(command_pool_lock);
189 command_pool_map.erase(pCommandBuffers[index]);
190 }
191}
192
193void ThreadSafety::PostCallRecordFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
194 const VkCommandBuffer *pCommandBuffers) {
195 FinishReadObject(device);
196 FinishWriteObject(commandPool);
197}
198
199void ThreadSafety::PreCallRecordResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
200 StartReadObject(device);
201 StartWriteObject(commandPool);
202 // Check for any uses of non-externally sync'd command buffers (for example from vkCmdExecuteCommands)
203 c_VkCommandPoolContents.StartWrite(commandPool);
204 // Host access to commandPool must be externally synchronized
205}
206
207void ThreadSafety::PostCallRecordResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
208 FinishReadObject(device);
209 FinishWriteObject(commandPool);
210 c_VkCommandPoolContents.FinishWrite(commandPool);
211 // Host access to commandPool must be externally synchronized
212}
213
214void ThreadSafety::PreCallRecordDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
215 StartReadObject(device);
216 StartWriteObject(commandPool);
217 // Check for any uses of non-externally sync'd command buffers (for example from vkCmdExecuteCommands)
218 c_VkCommandPoolContents.StartWrite(commandPool);
219 // Host access to commandPool must be externally synchronized
220}
221
222void ThreadSafety::PostCallRecordDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
223 FinishReadObject(device);
224 FinishWriteObject(commandPool);
225 c_VkCommandPoolContents.FinishWrite(commandPool);
226}
227
228"""
229
230
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600231 # This is an ordered list of sections in the header file.
232 TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum',
233 'group', 'bitmask', 'funcpointer', 'struct']
234 ALL_SECTIONS = TYPE_SECTIONS + ['command']
235 def __init__(self,
236 errFile = sys.stderr,
237 warnFile = sys.stderr,
238 diagFile = sys.stdout):
239 OutputGenerator.__init__(self, errFile, warnFile, diagFile)
240 # Internal state - accumulators for different inner block text
241 self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600242
243 # Check if the parameter passed in is a pointer to an array
244 def paramIsArray(self, param):
245 return param.attrib.get('len') is not None
246
247 # Check if the parameter passed in is a pointer
248 def paramIsPointer(self, param):
249 ispointer = False
250 for elem in param:
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600251 if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail:
252 ispointer = True
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600253 return ispointer
Mark Lobodzinski60b77b32017-02-14 09:16:56 -0700254
255 # Check if an object is a non-dispatchable handle
256 def isHandleTypeNonDispatchable(self, handletype):
257 handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
258 if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
259 return True
260 else:
261 return False
262
263 # Check if an object is a dispatchable handle
264 def isHandleTypeDispatchable(self, handletype):
265 handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
266 if handle is not None and handle.find('type').text == 'VK_DEFINE_HANDLE':
267 return True
268 else:
269 return False
270
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600271 def makeThreadUseBlock(self, cmd, functionprefix):
272 """Generate C function pointer typedef for <command> Element"""
273 paramdecl = ''
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600274 # Find and add any parameters that are thread unsafe
275 params = cmd.findall('param')
276 for param in params:
277 paramname = param.find('name')
278 if False: # self.paramIsPointer(param):
279 paramdecl += ' // not watching use of pointer ' + paramname.text + '\n'
280 else:
281 externsync = param.attrib.get('externsync')
282 if externsync == 'true':
283 if self.paramIsArray(param):
Mark Lobodzinski716a4f92018-11-16 08:54:20 -0700284 paramdecl += 'for (uint32_t index=0;index<' + param.attrib.get('len') + ';index++) {\n'
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700285 paramdecl += ' ' + functionprefix + 'WriteObject(' + paramname.text + '[index]);\n'
Mark Lobodzinski716a4f92018-11-16 08:54:20 -0700286 paramdecl += '}\n'
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600287 else:
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700288 paramdecl += functionprefix + 'WriteObject(' + paramname.text + ');\n'
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600289 elif (param.attrib.get('externsync')):
290 if self.paramIsArray(param):
291 # Externsync can list pointers to arrays of members to synchronize
Mark Lobodzinski716a4f92018-11-16 08:54:20 -0700292 paramdecl += 'for (uint32_t index=0;index<' + param.attrib.get('len') + ';index++) {\n'
293 second_indent = ''
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600294 for member in externsync.split(","):
295 # Replace first empty [] in member name with index
296 element = member.replace('[]','[index]',1)
297 if '[]' in element:
298 # Replace any second empty [] in element name with
299 # inner array index based on mapping array names like
300 # "pSomeThings[]" to "someThingCount" array size.
301 # This could be more robust by mapping a param member
302 # name to a struct type and "len" attribute.
303 limit = element[0:element.find('s[]')] + 'Count'
304 dotp = limit.rfind('.p')
305 limit = limit[0:dotp+1] + limit[dotp+2:dotp+3].lower() + limit[dotp+3:]
Mark Lobodzinski716a4f92018-11-16 08:54:20 -0700306 paramdecl += ' for(uint32_t index2=0;index2<'+limit+';index2++)\n'
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600307 element = element.replace('[]','[index2]')
Mark Lobodzinski716a4f92018-11-16 08:54:20 -0700308 second_indent = ' '
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700309 paramdecl += ' ' + second_indent + functionprefix + 'WriteObject(' + element + ');\n'
Mark Lobodzinski716a4f92018-11-16 08:54:20 -0700310 paramdecl += '}\n'
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600311 else:
312 # externsync can list members to synchronize
313 for member in externsync.split(","):
314 member = str(member).replace("::", "->")
Mark Lobodzinski9c147802017-02-10 08:34:54 -0700315 member = str(member).replace(".", "->")
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700316 paramdecl += ' ' + functionprefix + 'WriteObject(' + member + ');\n'
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600317 else:
318 paramtype = param.find('type')
319 if paramtype is not None:
320 paramtype = paramtype.text
321 else:
322 paramtype = 'None'
Mark Lobodzinski60b77b32017-02-14 09:16:56 -0700323 if (self.isHandleTypeDispatchable(paramtype) or self.isHandleTypeNonDispatchable(paramtype)) and paramtype != 'VkPhysicalDevice':
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600324 if self.paramIsArray(param) and ('pPipelines' != paramname.text):
Mark Lobodzinski9c147802017-02-10 08:34:54 -0700325 # Add pointer dereference for array counts that are pointer values
326 dereference = ''
327 for candidate in params:
328 if param.attrib.get('len') == candidate.find('name').text:
329 if self.paramIsPointer(candidate):
330 dereference = '*'
Mark Lobodzinski60b77b32017-02-14 09:16:56 -0700331 param_len = str(param.attrib.get('len')).replace("::", "->")
Mark Lobodzinski716a4f92018-11-16 08:54:20 -0700332 paramdecl += 'for (uint32_t index = 0; index < ' + dereference + param_len + '; index++) {\n'
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700333 paramdecl += ' ' + functionprefix + 'ReadObject(' + paramname.text + '[index]);\n'
Mark Lobodzinski716a4f92018-11-16 08:54:20 -0700334 paramdecl += '}\n'
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600335 elif not self.paramIsPointer(param):
336 # Pointer params are often being created.
337 # They are not being read from.
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700338 paramdecl += functionprefix + 'ReadObject(' + paramname.text + ');\n'
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600339 explicitexternsyncparams = cmd.findall("param[@externsync]")
340 if (explicitexternsyncparams is not None):
341 for param in explicitexternsyncparams:
342 externsyncattrib = param.attrib.get('externsync')
343 paramname = param.find('name')
Mark Lobodzinski716a4f92018-11-16 08:54:20 -0700344 paramdecl += '// Host access to '
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600345 if externsyncattrib == 'true':
346 if self.paramIsArray(param):
347 paramdecl += 'each member of ' + paramname.text
348 elif self.paramIsPointer(param):
349 paramdecl += 'the object referenced by ' + paramname.text
350 else:
351 paramdecl += paramname.text
352 else:
353 paramdecl += externsyncattrib
354 paramdecl += ' must be externally synchronized\n'
355
356 # Find and add any "implicit" parameters that are thread unsafe
357 implicitexternsyncparams = cmd.find('implicitexternsyncparams')
358 if (implicitexternsyncparams is not None):
359 for elem in implicitexternsyncparams:
Mark Lobodzinski716a4f92018-11-16 08:54:20 -0700360 paramdecl += '// '
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600361 paramdecl += elem.text
362 paramdecl += ' must be externally synchronized between host accesses\n'
363
364 if (paramdecl == ''):
365 return None
366 else:
367 return paramdecl
368 def beginFile(self, genOpts):
369 OutputGenerator.beginFile(self, genOpts)
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600370 #
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700371 # TODO: LUGMAL -- remove this and add our copyright
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600372 # User-supplied prefix text, if any (list of strings)
373 if (genOpts.prefixText):
374 for s in genOpts.prefixText:
375 write(s, file=self.outFile)
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700376
377 self.header_file = (genOpts.filename == 'thread_safety.h')
378 self.source_file = (genOpts.filename == 'thread_safety.cpp')
379
380 if not self.header_file and not self.source_file:
381 print("Error: Output Filenames have changed, update generator source.\n")
382 sys.exit(1)
383
384 if self.source_file:
385 write('#include "chassis.h"', file=self.outFile)
386 write('#include "thread_safety_validation.h"', file=self.outFile)
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600387 self.newline()
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700388 write(self.inline_custom_source_preamble, file=self.outFile)
389
390 def endFile(self):
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600391 # Finish processing in superclass
392 OutputGenerator.endFile(self)
393 def beginFeature(self, interface, emit):
394 #write('// starting beginFeature', file=self.outFile)
395 # Start processing in superclass
396 OutputGenerator.beginFeature(self, interface, emit)
397 # C-specific
398 # Accumulate includes, defines, types, enums, function pointer typedefs,
399 # end function prototypes separately for this feature. They're only
400 # printed in endFeature().
Mark Lobodzinski62f71562017-10-24 13:41:18 -0600401 self.featureExtraProtect = GetFeatureProtect(interface)
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600402 self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
403 #write('// ending beginFeature', file=self.outFile)
404 def endFeature(self):
405 # C-specific
406 # Actually write the interface to the output file.
407 #write('// starting endFeature', file=self.outFile)
408 if (self.emit):
409 self.newline()
410 if (self.genOpts.protectFeature):
411 write('#ifndef', self.featureName, file=self.outFile)
412 # If type declarations are needed by other features based on
413 # this one, it may be necessary to suppress the ExtraProtect,
414 # or move it below the 'for section...' loop.
415 #write('// endFeature looking at self.featureExtraProtect', file=self.outFile)
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100416 if (self.featureExtraProtect is not None):
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600417 write('#ifdef', self.featureExtraProtect, file=self.outFile)
418 #write('#define', self.featureName, '1', file=self.outFile)
419 for section in self.TYPE_SECTIONS:
420 #write('// endFeature writing section'+section, file=self.outFile)
421 contents = self.sections[section]
422 if contents:
423 write('\n'.join(contents), file=self.outFile)
424 self.newline()
425 #write('// endFeature looking at self.sections[command]', file=self.outFile)
426 if (self.sections['command']):
Jamie Madill24aa9742016-12-13 17:02:57 -0500427 write('\n'.join(self.sections['command']), end=u'', file=self.outFile)
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600428 self.newline()
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100429 if (self.featureExtraProtect is not None):
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600430 write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile)
431 if (self.genOpts.protectFeature):
432 write('#endif /*', self.featureName, '*/', file=self.outFile)
433 # Finish processing in superclass
434 OutputGenerator.endFeature(self)
435 #write('// ending endFeature', file=self.outFile)
436 #
437 # Append a definition to the specified section
438 def appendSection(self, section, text):
439 # self.sections[section].append('SECTION: ' + section + '\n')
440 self.sections[section].append(text)
441 #
442 # Type generation
Mike Schuchardtf375c7c2017-12-28 11:23:48 -0700443 def genType(self, typeinfo, name, alias):
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600444 pass
445 #
446 # Struct (e.g. C "struct" type) generation.
447 # This is a special case of the <type> tag where the contents are
448 # interpreted as a set of <member> tags instead of freeform C
449 # C type declarations. The <member> tags are just like <param>
450 # tags - they are a declaration of a struct or union member.
451 # Only simple member declarations are supported (no nested
452 # structs etc.)
Mike Schuchardtf375c7c2017-12-28 11:23:48 -0700453 def genStruct(self, typeinfo, typeName, alias):
454 OutputGenerator.genStruct(self, typeinfo, typeName, alias)
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600455 body = 'typedef ' + typeinfo.elem.get('category') + ' ' + typeName + ' {\n'
456 # paramdecl = self.makeCParamDecl(typeinfo.elem, self.genOpts.alignFuncParam)
457 for member in typeinfo.elem.findall('.//member'):
458 body += self.makeCParamDecl(member, self.genOpts.alignFuncParam)
459 body += ';\n'
460 body += '} ' + typeName + ';\n'
461 self.appendSection('struct', body)
462 #
463 # Group (e.g. C "enum" type) generation.
464 # These are concatenated together with other types.
Mike Schuchardtf375c7c2017-12-28 11:23:48 -0700465 def genGroup(self, groupinfo, groupName, alias):
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600466 pass
467 # Enumerant generation
468 # <enum> tags may specify their values in several ways, but are usually
469 # just integers.
Mike Schuchardtf375c7c2017-12-28 11:23:48 -0700470 def genEnum(self, enuminfo, name, alias):
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600471 pass
472 #
473 # Command generation
Mike Schuchardtf375c7c2017-12-28 11:23:48 -0700474 def genCmd(self, cmdinfo, name, alias):
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600475 # Commands shadowed by interface functions and are not implemented
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700476 # TODO: Many of these no longer need to be manually written routines. Winnow list.
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600477 special_functions = [
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600478 'vkCreateDevice',
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600479 'vkCreateInstance',
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600480 'vkAllocateCommandBuffers',
481 'vkFreeCommandBuffers',
John Zulaufe28aa342018-10-24 12:18:39 -0600482 'vkResetCommandPool',
483 'vkDestroyCommandPool',
Mark Lobodzinski3bd82ad2017-02-16 11:45:27 -0700484 'vkAllocateDescriptorSets',
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700485 'vkQueuePresentKHR',
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600486 ]
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700487 if name == 'vkQueuePresentKHR' or (name in special_functions and self.source_file):
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600488 return
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700489
490 if (("DebugMarker" in name or "DebugUtilsObject" in name) and "EXT" in name):
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600491 self.appendSection('command', '// TODO - not wrapping EXT function ' + name)
492 return
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700493
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600494 # Determine first if this function needs to be intercepted
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700495 startthreadsafety = self.makeThreadUseBlock(cmdinfo.elem, 'Start')
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600496 if startthreadsafety is None:
497 return
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700498 finishthreadsafety = self.makeThreadUseBlock(cmdinfo.elem, 'Finish')
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600499
Mike Schuchardtf375c7c2017-12-28 11:23:48 -0700500 OutputGenerator.genCmd(self, cmdinfo, name, alias)
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700501
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600502 # setup common to call wrappers
503 # first parameter is always dispatchable
504 dispatchable_type = cmdinfo.elem.find('param/type').text
505 dispatchable_name = cmdinfo.elem.find('param/name').text
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700506
507 decls = self.makeCDecls(cmdinfo.elem)
508
509 if self.source_file:
510 pre_decl = decls[0][:-1]
511 pre_decl = pre_decl.split("VKAPI_CALL ")[1]
512 pre_decl = 'void ThreadSafety::PreCallRecord' + pre_decl + ' {'
513
514 # PreCallRecord
515 self.appendSection('command', '')
516 self.appendSection('command', pre_decl)
517 self.appendSection('command', " " + "\n ".join(str(startthreadsafety).rstrip().split("\n")))
518 self.appendSection('command', '}')
519
520 post_decl = pre_decl.replace('PreCallRecord', 'PostCallRecord')
521
522 # PostCallRecord
523 self.appendSection('command', '')
524 self.appendSection('command', post_decl)
525 self.appendSection('command', " " + "\n ".join(str(finishthreadsafety).rstrip().split("\n")))
526 self.appendSection('command', '}')
527
528 if self.header_file:
529 pre_decl = decls[0][:-1]
530 pre_decl = pre_decl.split("VKAPI_CALL ")[1]
531 pre_decl = 'void PreCallRecord' + pre_decl + ';'
532
533 # PreCallRecord
534 self.appendSection('command', '')
535 self.appendSection('command', pre_decl)
536
537 post_decl = pre_decl.replace('PreCallRecord', 'PostCallRecord')
538
539 # PostCallRecord
540 self.appendSection('command', '')
541 self.appendSection('command', post_decl)
542
Mark Lobodzinskiff910992016-10-11 14:29:52 -0600543 #
544 # override makeProtoName to drop the "vk" prefix
545 def makeProtoName(self, name, tail):
546 return self.genOpts.apientry + name[2:] + tail