2016-11-12 11:23:34 +00:00
|
|
|
#!/usr/bin/python3 -i
|
|
|
|
#
|
|
|
|
# Copyright (c) 2013-2016 The Khronos Group Inc.
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
import os,re,sys
|
|
|
|
from generator import *
|
|
|
|
|
|
|
|
doc = """
|
|
|
|
/*
|
|
|
|
** This is a simple extension loader which provides the implementations for the
|
|
|
|
** extension prototypes declared in vulkan header. It supports loading extensions either
|
|
|
|
** for a single instance or a single device. Multiple instances are not yet supported.
|
|
|
|
**
|
|
|
|
** To use the loader add vulkan_ext.c to your solution and include <vulkan/vulkan_ext.h>.
|
|
|
|
**
|
|
|
|
** If your application is using a single instance, but multiple devices callParam
|
|
|
|
**
|
|
|
|
** vkExtInitInstance(instance);
|
|
|
|
**
|
|
|
|
** after initializing the instance. This way the extension loader will use the loaders
|
|
|
|
** trampoline functions to call the correct driver for each call. This method is safe
|
|
|
|
** if your application might use more than one device at the cost of one additional
|
|
|
|
** indirection, the dispatch table of each dispatchable object.
|
|
|
|
**
|
|
|
|
** If your application uses only a single device it's better to use
|
|
|
|
**
|
|
|
|
** vkExtInitDevice(device);
|
|
|
|
**
|
|
|
|
** once the device has been initialized. This will resolve the function pointers
|
|
|
|
** upfront and thus removes one indirection for each call into the driver. This *can*
|
|
|
|
** result in slightly more performance for calling overhead limited cases.
|
|
|
|
*/
|
|
|
|
"""
|
|
|
|
|
|
|
|
# StubExtGeneratorOptions - subclass of GeneratorOptions.
|
|
|
|
#
|
|
|
|
# Adds options used by COutputGenerator objects during C language header
|
|
|
|
# generation.
|
|
|
|
#
|
|
|
|
# Additional members
|
|
|
|
# prefixText - list of strings to prefix generated header with
|
|
|
|
# (usually a copyright statement + calling convention macros).
|
|
|
|
# alignFuncParam - if nonzero and parameters are being put on a
|
|
|
|
# separate line, align parameter names at the specified column
|
|
|
|
class StubExtGeneratorOptions(GeneratorOptions):
|
|
|
|
"""Represents options during C interface generation for headers"""
|
|
|
|
def __init__(self,
|
|
|
|
filename = None,
|
|
|
|
directory = '.',
|
|
|
|
apiname = None,
|
|
|
|
profile = None,
|
|
|
|
versions = '.*',
|
|
|
|
emitversions = '.*',
|
|
|
|
defaultExtensions = None,
|
|
|
|
addExtensions = None,
|
|
|
|
removeExtensions = None,
|
|
|
|
sortProcedure = regSortFeatures,
|
|
|
|
prefixText = "",
|
|
|
|
alignFuncParam = 0):
|
|
|
|
GeneratorOptions.__init__(self, filename, directory, apiname, profile,
|
|
|
|
versions, emitversions, defaultExtensions,
|
|
|
|
addExtensions, removeExtensions, sortProcedure)
|
|
|
|
self.prefixText = prefixText
|
|
|
|
self.alignFuncParam = alignFuncParam
|
|
|
|
|
|
|
|
# ExtensionStubSourceOutputGenerator - subclass of OutputGenerator.
|
|
|
|
# Generates C-language extension wrapper interface sources.
|
|
|
|
#
|
|
|
|
# ---- methods ----
|
|
|
|
# ExtensionStubSourceOutputGenerator(errFile, warnFile, diagFile) - args as for
|
|
|
|
# OutputGenerator. Defines additional internal state.
|
|
|
|
# ---- methods overriding base class ----
|
|
|
|
# beginFile(genOpts)
|
|
|
|
# endFile()
|
|
|
|
# beginFeature(interface, emit)
|
|
|
|
# endFeature()
|
|
|
|
# genType(typeinfo,name)
|
|
|
|
# genStruct(typeinfo,name)
|
|
|
|
# genGroup(groupinfo,name)
|
|
|
|
# genEnum(enuminfo, name)
|
|
|
|
# genCmd(cmdinfo)
|
|
|
|
class ExtensionStubSourceOutputGenerator(OutputGenerator):
|
|
|
|
"""Generate specified API interfaces in a specific style, such as a C header"""
|
|
|
|
# This is an ordered list of sections in the header file.
|
|
|
|
TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum',
|
|
|
|
'group', 'bitmask', 'funcpointer', 'struct']
|
|
|
|
ALL_SECTIONS = TYPE_SECTIONS + ['commandPointer', 'command']
|
|
|
|
def __init__(self,
|
|
|
|
errFile = sys.stderr,
|
|
|
|
warnFile = sys.stderr,
|
|
|
|
diagFile = sys.stdout):
|
|
|
|
OutputGenerator.__init__(self, errFile, warnFile, diagFile)
|
|
|
|
#
|
|
|
|
def beginFile(self, genOpts):
|
|
|
|
OutputGenerator.beginFile(self, genOpts)
|
|
|
|
# C-specific
|
|
|
|
#
|
|
|
|
# Multiple inclusion protection & C++ wrappers.
|
|
|
|
|
Change log for November 25, 2016 Vulkan 1.0.35 spec update:
* Bump API patch number and header version number to 35 for this update.
Github Issues:
* Document in the <<memory-device-hostaccess,Host Access>> section that
mapping and unmapping does not invalidate or flush the mapped memory
(public issues 27, 126).
* Redefine the entire <<synchronization>> chapter in terms of consistent
and well defined terminology, that's called out at the start of the
chapter. This terminology is applied equally to all synchronization
types, including subpass dependencies, submissions, and much of the
implicit ordering stuff dotted around the spec. Key terms are laid out
in the <<synchronization-dependencies,Execution and Memory
Dependencies>> section at the top of the rewritten chapter (public
issues 128, 131, 132, 217, 299, 300, 302, 306, 322, 346, 347, 371, 407).
* Specify order of submission for batches in the
<<vkQueueSubmit,vkQueueSubmit>> and
<<vkQueueBindSparse,vkQueueBindSparse>> commands (public issue 371).
* Add valid usage statements to each of the WSI extension sections
indicating that the WSI-specific structure parameters must be valid, and
remove automatically generated valid usage statements now covered by the
manual sections (public issue 383).
* Clarify render pass compatibility for flink:vkCmdExecuteCommands (public
issue 390).
Internal Issues:
* Update +vk.xml+ to make previously explicit valid usage statements for
<<vkDebugReportMessageEXT,vkDebugReportMessageEXT>> implicit instead
(internal issue 553).
* Add valid usage statement for slink:VkCreateImageInfo preventing
creation of 1D sparse images (internal issue 573).
* Fix Python scripts to always read/write files in utf-8 encoding, and a
logic error in reflib.py which could cause a fatal error for
malstructured asciidoc (internal issues 578, 586).
2016-11-26 10:33:44 +00:00
|
|
|
# Internal state - accumulators for function pointers and function
|
|
|
|
# pointer initializatoin
|
2016-11-12 11:23:34 +00:00
|
|
|
self.pointers = [];
|
|
|
|
self.pointerInitializersInstance = [];
|
|
|
|
self.pointerInitializersDevice = [];
|
|
|
|
|
|
|
|
#
|
|
|
|
# Write header protection
|
Change log for November 25, 2016 Vulkan 1.0.35 spec update:
* Bump API patch number and header version number to 35 for this update.
Github Issues:
* Document in the <<memory-device-hostaccess,Host Access>> section that
mapping and unmapping does not invalidate or flush the mapped memory
(public issues 27, 126).
* Redefine the entire <<synchronization>> chapter in terms of consistent
and well defined terminology, that's called out at the start of the
chapter. This terminology is applied equally to all synchronization
types, including subpass dependencies, submissions, and much of the
implicit ordering stuff dotted around the spec. Key terms are laid out
in the <<synchronization-dependencies,Execution and Memory
Dependencies>> section at the top of the rewritten chapter (public
issues 128, 131, 132, 217, 299, 300, 302, 306, 322, 346, 347, 371, 407).
* Specify order of submission for batches in the
<<vkQueueSubmit,vkQueueSubmit>> and
<<vkQueueBindSparse,vkQueueBindSparse>> commands (public issue 371).
* Add valid usage statements to each of the WSI extension sections
indicating that the WSI-specific structure parameters must be valid, and
remove automatically generated valid usage statements now covered by the
manual sections (public issue 383).
* Clarify render pass compatibility for flink:vkCmdExecuteCommands (public
issue 390).
Internal Issues:
* Update +vk.xml+ to make previously explicit valid usage statements for
<<vkDebugReportMessageEXT,vkDebugReportMessageEXT>> implicit instead
(internal issue 553).
* Add valid usage statement for slink:VkCreateImageInfo preventing
creation of 1D sparse images (internal issue 573).
* Fix Python scripts to always read/write files in utf-8 encoding, and a
logic error in reflib.py which could cause a fatal error for
malstructured asciidoc (internal issues 578, 586).
2016-11-26 10:33:44 +00:00
|
|
|
filename = self.genOpts.directory + '/' + 'vulkan_ext.h'
|
|
|
|
self.outFileHeader = open(filename, 'w', encoding='utf-8')
|
2016-11-12 11:23:34 +00:00
|
|
|
|
|
|
|
write('#ifndef VULKAN_EXT_H', file=self.outFileHeader)
|
|
|
|
write('#define VULKAN_EXT_H', file=self.outFileHeader)
|
|
|
|
write('', file=self.outFileHeader)
|
|
|
|
write('#ifdef __cplusplus', file=self.outFileHeader)
|
|
|
|
write('extern "C" {', file=self.outFileHeader)
|
|
|
|
write('#endif', file=self.outFileHeader)
|
|
|
|
|
|
|
|
#
|
|
|
|
# User-supplied prefix text, if any (list of strings)
|
|
|
|
if (genOpts.prefixText):
|
|
|
|
for s in genOpts.prefixText:
|
|
|
|
write(s, file=self.outFile)
|
|
|
|
write(s, file=self.outFileHeader)
|
|
|
|
|
|
|
|
write(doc, file=self.outFileHeader)
|
|
|
|
|
|
|
|
write('#include <vulkan/vulkan.h>', file=self.outFile)
|
|
|
|
self.newline()
|
|
|
|
|
|
|
|
write('#include <vulkan/vulkan.h>', file=self.outFileHeader)
|
|
|
|
write('', file=self.outFileHeader)
|
|
|
|
|
|
|
|
write('void vkExtInitInstance(VkInstance instance);', file=self.outFileHeader)
|
|
|
|
write('void vkExtInitDevice(VkDevice device);', file=self.outFileHeader)
|
|
|
|
write('', file=self.outFileHeader)
|
|
|
|
|
|
|
|
def endFile(self):
|
|
|
|
for pointer in self.pointers:
|
|
|
|
write(pointer, file=self.outFile)
|
|
|
|
|
|
|
|
self.newline()
|
|
|
|
|
|
|
|
write('void vkExtInitInstance(VkInstance instance)\n{', file=self.outFile)
|
|
|
|
for pointerInitializer in self.pointerInitializersInstance:
|
|
|
|
write(pointerInitializer, file=self.outFile)
|
|
|
|
write('}', file=self.outFile)
|
|
|
|
|
|
|
|
self.newline()
|
|
|
|
|
|
|
|
write('void vkExtInitDevice(VkDevice device)\n{', file=self.outFile)
|
|
|
|
for pointerInitializer in self.pointerInitializersDevice:
|
|
|
|
write(pointerInitializer, file=self.outFile)
|
|
|
|
write('}', file=self.outFile)
|
|
|
|
|
|
|
|
self.newline()
|
|
|
|
|
|
|
|
#Finish header file
|
|
|
|
write('#ifdef __cplusplus', file=self.outFileHeader)
|
|
|
|
write('}', file=self.outFileHeader)
|
|
|
|
write('#endif', file=self.outFileHeader)
|
|
|
|
write('', file=self.outFileHeader)
|
|
|
|
write('#endif', file=self.outFileHeader)
|
|
|
|
self.outFileHeader.close()
|
|
|
|
|
|
|
|
# Finish processing in superclass
|
|
|
|
OutputGenerator.endFile(self)
|
|
|
|
|
|
|
|
def beginFeature(self, interface, emit):
|
|
|
|
# Start processing in superclass
|
|
|
|
OutputGenerator.beginFeature(self, interface, emit)
|
|
|
|
|
|
|
|
# Accumulate function pointers and function pointer initialization
|
|
|
|
self.featurePointers = []
|
|
|
|
self.featurePointerInitializersInstance = []
|
|
|
|
self.featurePointerInitializersDevice = []
|
|
|
|
|
|
|
|
def endFeature(self):
|
|
|
|
# Add feature to global list with protectFeature
|
|
|
|
if (self.emit and self.featurePointers):
|
|
|
|
if (self.genOpts.protectFeature):
|
|
|
|
self.pointers.append('#ifdef ' + self.featureName)
|
|
|
|
self.pointerInitializersInstance.append('#ifdef ' + self.featureName)
|
|
|
|
self.pointerInitializersDevice.append('#ifdef ' + self.featureName)
|
|
|
|
|
|
|
|
if (self.featureExtraProtect != None):
|
|
|
|
self.pointers.append('#ifdef ' + self.featureExtraProtect)
|
|
|
|
self.pointerInitializersInstance.append('#ifndef ' + self.featureName)
|
|
|
|
self.pointerInitializersDevice.append('#ifndef ' + self.featureName)
|
|
|
|
|
|
|
|
self.pointers += self.featurePointers;
|
|
|
|
self.pointerInitializersInstance += self.featurePointerInitializersInstance;
|
|
|
|
self.pointerInitializersDevice += self.featurePointerInitializersDevice;
|
|
|
|
|
|
|
|
if (self.featureExtraProtect != None):
|
|
|
|
self.pointers.append('#endif /* ' + self.featureExtraProtect + ' */')
|
|
|
|
self.pointerInitializersInstance.append('#endif /* ' + self.featureExtraProtect + ' */')
|
|
|
|
self.pointerInitializersDevice.append('#endif /* ' + self.featureExtraProtect + ' */')
|
|
|
|
if (self.genOpts.protectFeature):
|
|
|
|
self.pointers.append('#endif /* ' + self.featureName + ' */')
|
|
|
|
self.pointerInitializersInstance.append('#endif /* ' + self.featureName + ' */')
|
|
|
|
self.pointerInitializersDevice.append('#endif /* ' + self.featureName + ' */')
|
|
|
|
|
|
|
|
# Finish processing in superclass
|
|
|
|
OutputGenerator.endFeature(self)
|
|
|
|
#
|
|
|
|
# Type generation
|
|
|
|
def genType(self, typeinfo, name):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def genStruct(self, typeinfo, typeName):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def genGroup(self, groupinfo, groupName):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def genEnum(self, enuminfo, name):
|
|
|
|
pass
|
|
|
|
|
|
|
|
#
|
|
|
|
# Command generation
|
|
|
|
def genCmd(self, cmdinfo, name):
|
|
|
|
OutputGenerator.genCmd(self, cmdinfo, name)
|
|
|
|
|
|
|
|
#
|
|
|
|
decls = self.makeStub(cmdinfo.elem)
|
|
|
|
self.featurePointerInitializersInstance.append(decls[0])
|
|
|
|
self.featurePointerInitializersDevice.append(decls[1])
|
|
|
|
self.featurePointers.append(decls[2])
|
|
|
|
|
|
|
|
#
|
|
|
|
# makeStub - return static declaration for function pointer and initialization of function pointer
|
|
|
|
# as a two-element list of strings.
|
|
|
|
# cmd - Element containing a <command> tag
|
|
|
|
def makeStub(self, cmd):
|
|
|
|
"""Generate a stub function pointer <command> Element"""
|
|
|
|
proto = cmd.find('proto')
|
|
|
|
params = cmd.findall('param')
|
|
|
|
name = cmd.find('name')
|
|
|
|
|
|
|
|
# Begin accumulating prototype and typedef strings
|
|
|
|
pfnDecl = 'static '
|
|
|
|
pfnDecl += noneStr(proto.text)
|
|
|
|
|
|
|
|
# Find the name tag and generate the function pointer and function pointer initialization code
|
|
|
|
nameTag = proto.find('name')
|
|
|
|
tail = noneStr(nameTag.tail)
|
|
|
|
returnType = noneStr(proto.find('type').text)
|
|
|
|
|
|
|
|
type = self.makeFunctionPointerType(nameTag.text, tail)
|
|
|
|
|
|
|
|
# For each child element, if it's a <name> wrap in appropriate
|
|
|
|
# declaration. Otherwise append its contents and tail con#tents.
|
|
|
|
stubDecl = ''
|
|
|
|
for elem in proto:
|
|
|
|
text = noneStr(elem.text)
|
|
|
|
tail = noneStr(elem.tail)
|
|
|
|
if (elem.tag == 'name'):
|
|
|
|
name = self.makeProtoName(text, tail)
|
|
|
|
stubDecl += name
|
|
|
|
else:
|
|
|
|
stubDecl += text + tail
|
|
|
|
|
|
|
|
pfnName = self.makeFunctionPointerName(nameTag.text, noneStr(tail));
|
|
|
|
pfnDecl += type + ' ' + pfnName + ';'
|
|
|
|
|
|
|
|
# Now generate the stub function
|
|
|
|
pfnDecl += '\n'
|
|
|
|
|
|
|
|
# Now add the parameter declaration list, which is identical
|
|
|
|
# for prototypes and typedefs. Concatenate all the text from
|
|
|
|
# a <param> node without the tags. No tree walking required
|
|
|
|
# since all tags are ignored.
|
|
|
|
n = len(params)
|
|
|
|
paramdecl = '(\n'
|
|
|
|
|
|
|
|
pfnCall = '\n{\n ' + ('return ', '')[returnType == 'void'] + pfnName + '(\n'
|
|
|
|
# Indented parameters
|
|
|
|
if n > 0:
|
|
|
|
indentCallParam = '(\n'
|
|
|
|
indentdecl = '(\n'
|
|
|
|
for i in range(0,n):
|
|
|
|
callParam = ''
|
|
|
|
|
|
|
|
paramdecl += self.makeCParamDecl(params[i], self.genOpts.alignFuncParam)
|
|
|
|
pfnCall += self.makeCCallParam(params[i], self.genOpts.alignFuncParam)
|
|
|
|
if (i < n - 1):
|
|
|
|
paramdecl += ',\n'
|
|
|
|
pfnCall += ',\n'
|
|
|
|
else:
|
|
|
|
paramdecl += ')'
|
|
|
|
pfnCall += '\n );\n'
|
|
|
|
indentdecl += paramdecl
|
|
|
|
indentCallParam += pfnCall
|
|
|
|
else:
|
|
|
|
indentdecl = '(void);'
|
|
|
|
|
|
|
|
pfnCall += '}\n'
|
|
|
|
|
|
|
|
featureInstance = ' ' + pfnName + ' = ('+type+')vkGetInstanceProcAddr(instance, "' + name + '");'
|
|
|
|
featureDevice = ' ' + pfnName + ' = ('+type+')vkGetDeviceProcAddr(device, "' + name + '");'
|
|
|
|
return [featureInstance, featureDevice , pfnDecl + stubDecl + paramdecl + pfnCall]
|
|
|
|
|
|
|
|
# Return function pointer type for given function
|
|
|
|
def makeFunctionPointerType(self, name, tail):
|
|
|
|
return 'PFN_' + name + tail
|
|
|
|
|
|
|
|
# Return name of static variable which stores the function pointer for the given function
|
|
|
|
def makeFunctionPointerName(self, name, tail):
|
|
|
|
return 'pfn_' + name + tail
|
|
|
|
|
|
|
|
#
|
|
|
|
# makeCParamDecl - return a string which is an indented, formatted
|
|
|
|
# declaration for a <param> or <member> block (e.g. function parameter
|
|
|
|
# or structure/union member).
|
|
|
|
# param - Element (<param> or <member>) to format
|
|
|
|
# aligncol - if non-zero, attempt to align the nested <name> element
|
|
|
|
# at this column
|
|
|
|
def makeCCallParam(self, param, aligncol):
|
|
|
|
return ' ' + param.find('name').text
|
|
|
|
|