Skip to content

Commit

Permalink
Move shared object exported entry points to tag dispatch (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
solidpixel authored Dec 11, 2024
1 parent 4e477fe commit 543afec
Show file tree
Hide file tree
Showing 22 changed files with 931 additions and 658 deletions.
135 changes: 74 additions & 61 deletions generator/generate_vulkan_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,30 +32,48 @@
import sys
import xml.etree.ElementTree as ET

# These functions are manually created as fully exported entry points in the
# layer library, and are not part of the dynamic dispatch behavior
MANUAL_FUNCTIONS = {
# Exposed by loader so not handled by the layer
# These functions are not part of the layer implementation
EXCLUDED_FUNCTIONS = {
# Functions exposed by loader not the implementation
'vkEnumerateInstanceVersion',
# Exposed as symbols managed by the loader so not handled by the layer
'vkGetInstanceProcAddr',
}

# These functions are excluded from generated intercept and dispatch tables
NO_INTERCEPT_OR_DISPATCH_FUNCTIONS = {
# Functions resolved by the loaded not the implementation
'vkGetDeviceProcAddr',
# Exposed by layer as explicit entry points
'vkGetInstanceProcAddr',
}

# These functions are excluded from generated intercept tables
NO_INTERCEPT_FUNCTIONS = {
# Functions exported as shared object exports and resolved by loader
'vkEnumerateDeviceExtensionProperties',
'vkEnumerateDeviceLayerProperties',
'vkEnumerateInstanceExtensionProperties',
'vkEnumerateInstanceLayerProperties',
}

# These functions are manually exported, but we can use driver forwarding
FORWARD_WITHOUT_INTERCEPT = {
'vkEnumerateDeviceExtensionProperties',
'vkEnumerateInstanceExtensionProperties',
# These functions are excluded from generated dispatch tables
NO_DISPATCH_FUNCTIONS = {
# Functions resolved by the loaded not the implementation
'vkCreateDevice',
'vkCreateInstance',
}

# These functions are found via the loader-injected chain info
INTERCEPT_WITHOUT_FORWARD = {
# These functions are excluded from generated declarations
CUSTOM_FUNCTIONS = {
'vkCreateDevice',
'vkCreateInstance',
'vkDestroyDevice',
'vkDestroyInstance',
'vkGetDeviceProcAddr',
'vkGetInstanceProcAddr',
'vkEnumerateDeviceExtensionProperties',
'vkEnumerateDeviceLayerProperties',
'vkEnumerateInstanceExtensionProperties',
'vkEnumerateInstanceLayerProperties',
'vkGetDeviceImageMemoryRequirementsKHR',
}

# Filter out extensions from these vendors by default
Expand Down Expand Up @@ -284,7 +302,7 @@ def __init__(self, mapping, root):
self.params.append((ptype, text, tail))

# Filter out functions that are not dynamically dispatched
if self.name in MANUAL_FUNCTIONS:
if self.name in EXCLUDED_FUNCTIONS:
raise NotImplementedError

# Filter out functions that are not in our supported mapping
Expand All @@ -299,7 +317,10 @@ def __init__(self, mapping, root):
elif dispatch_type in DEVICE_FUNCTION_PARAM_TYPE:
self.dispatch_type = 'device'
else:
assert False, f'Unknown dispatch: {dispatch_type} {self.name}'
if self.name.startswith('vkEnumerateInstance'):
self.dispatch_type = 'instance'
else:
assert False, f'Unknown dispatch: {dispatch_type} {self.name}'


def load_template(path):
Expand Down Expand Up @@ -346,19 +367,23 @@ def generate_layer_instance_dispatch_table(file, mapping, commands):
if command.dispatch_type != 'instance':
continue

tname = command.name
if tname in NO_INTERCEPT_OR_DISPATCH_FUNCTIONS:
continue

plat_define = mapping.get_platform_define(command.name)

ttype = f'PFN_{command.name}'
tname = command.name
if tname not in FORWARD_WITHOUT_INTERCEPT:

if tname not in NO_INTERCEPT_FUNCTIONS:
if plat_define:
itable_members.append(f'#if defined({plat_define})')

itable_members.append(f' ENTRY({tname}),')
if plat_define:
itable_members.append('#endif')

if tname not in INTERCEPT_WITHOUT_FORWARD:
if tname not in NO_DISPATCH_FUNCTIONS:
if plat_define:
dispatch_table_members.append(f'#if defined({plat_define})')
dispatch_table_inits.append(f'#if defined({plat_define})')
Expand Down Expand Up @@ -457,7 +482,7 @@ def generate_layer_instance_layer_decls(file, mapping, commands):
file.write('\n')


def generate_layer_instance_layer_defs(file, mapping, commands, manual_commands):
def generate_layer_instance_layer_defs(file, mapping, commands):

# Write the copyright header to the file
write_copyright_header(file)
Expand All @@ -470,6 +495,13 @@ def generate_layer_instance_layer_defs(file, mapping, commands, manual_commands)
if command.dispatch_type != 'instance':
continue

tname = command.name
if tname in NO_INTERCEPT_FUNCTIONS:
continue

if tname in CUSTOM_FUNCTIONS:
continue

plat_define = mapping.get_platform_define(command.name)
if plat_define:
lines.append(f'#if defined({plat_define})\n')
Expand All @@ -492,16 +524,13 @@ def generate_layer_instance_layer_defs(file, mapping, commands, manual_commands)
lines.append(') {')
lines.append(' LAYER_TRACE(__func__);\n')

if command.name in manual_commands:
lines.append(manual_commands[command.name])
else:
lines.append(' // Hold the lock to access layer-wide global store')
lines.append(' std::unique_lock<std::mutex> lock { g_vulkanLock };')
lines.append(f' auto* layer = Instance::retrieve({dispatch});\n')
lines.append(' // Hold the lock to access layer-wide global store')
lines.append(' std::unique_lock<std::mutex> lock { g_vulkanLock };')
lines.append(f' auto* layer = Instance::retrieve({dispatch});\n')

lines.append(' // Release the lock to call into the driver')
lines.append(' lock.unlock();')
lines.append(f' {retfwd}layer->driver.{command.name}({parmfwd});')
lines.append(' // Release the lock to call into the driver')
lines.append(' lock.unlock();')
lines.append(f' {retfwd}layer->driver.{command.name}({parmfwd});')

lines.append('}\n')

Expand All @@ -527,9 +556,12 @@ def generate_layer_device_dispatch_table(file, mapping, commands):
if command.dispatch_type != 'device':
continue

tname = command.name
if tname in NO_INTERCEPT_OR_DISPATCH_FUNCTIONS:
continue

plat_define = mapping.get_platform_define(command.name)
ttype = f'PFN_{command.name}'
tname = command.name

if plat_define:
itable_members.append(f'#if defined({plat_define})')
Expand Down Expand Up @@ -613,7 +645,7 @@ def generate_layer_device_layer_decls(file, mapping, commands):
file.write('\n')


def generate_layer_device_layer_defs(file, mapping, commands, manual_commands):
def generate_layer_device_layer_defs(file, mapping, commands):

# Write the copyright header to the file
write_copyright_header(file)
Expand All @@ -626,6 +658,10 @@ def generate_layer_device_layer_defs(file, mapping, commands, manual_commands):
if command.dispatch_type != 'device':
continue

tname = command.name
if tname in CUSTOM_FUNCTIONS:
continue

plat_define = mapping.get_platform_define(command.name)
if plat_define:
lines.append(f'#if defined({plat_define})\n')
Expand All @@ -649,16 +685,13 @@ def generate_layer_device_layer_defs(file, mapping, commands, manual_commands):
lines.append(') {')
lines.append(' LAYER_TRACE(__func__);\n')

if command.name in manual_commands:
lines.append(manual_commands[command.name])
else:
lines.append(' // Hold the lock to access layer-wide global store')
lines.append(' std::unique_lock<std::mutex> lock { g_vulkanLock };')
lines.append(f' auto* layer = Device::retrieve({dispatch});\n')
lines.append(' // Hold the lock to access layer-wide global store')
lines.append(' std::unique_lock<std::mutex> lock { g_vulkanLock };')
lines.append(f' auto* layer = Device::retrieve({dispatch});\n')

lines.append(' // Release the lock to call into the driver')
lines.append(' lock.unlock();')
lines.append(f' {retfwd}layer->driver.{command.name}({parmfwd});')
lines.append(' // Release the lock to call into the driver')
lines.append(' lock.unlock();')
lines.append(f' {retfwd}layer->driver.{command.name}({parmfwd});')

lines.append('}\n')

Expand All @@ -669,23 +702,6 @@ def generate_layer_device_layer_defs(file, mapping, commands, manual_commands):
file.write(data)


def load_handwritten_commands():
'''
Load the small number of hand-written functions from template files.
'''
script_dir = os.path.dirname(__file__)
template_dir = os.path.join(script_dir, 'vk_codegen')
pattern = re.compile(r'^function_(.*)\.txt$')

commands = {}
for path in os.listdir(template_dir):
match = pattern.match(path)
if match:
commands[match.group(1)] = load_template(path)

return commands


def copy_resource(src_dir, out_dir):
out_dir = os.path.abspath(out_dir)
os.makedirs(out_dir, exist_ok=True)
Expand Down Expand Up @@ -738,9 +754,6 @@ def main():
# Sort functions into alphabetical order
commands.sort(key=lambda x: x.name)

# Load hand written function bodies
manual_commands = load_handwritten_commands()

# Generate dynamic resources
outfile = os.path.join(outdir, 'instance_dispatch_table.hpp')
with open(outfile, 'w', encoding='utf-8', newline='\n') as handle:
Expand All @@ -756,15 +769,15 @@ def main():

outfile = os.path.join(outdir, 'instance_functions.cpp')
with open(outfile, 'w', encoding='utf-8', newline='\n') as handle:
generate_layer_instance_layer_defs(handle, mapping, commands, manual_commands)
generate_layer_instance_layer_defs(handle, mapping, commands)

outfile = os.path.join(outdir, 'device_functions.hpp')
with open(outfile, 'w', encoding='utf-8', newline='\n') as handle:
generate_layer_device_layer_decls(handle, mapping, commands)

outfile = os.path.join(outdir, 'device_functions.cpp')
with open(outfile, 'w', encoding='utf-8', newline='\n') as handle:
generate_layer_device_layer_defs(handle, mapping, commands, manual_commands)
generate_layer_device_layer_defs(handle, mapping, commands)

return 0

Expand Down
30 changes: 0 additions & 30 deletions generator/vk_codegen/function_vkCreateDevice.txt

This file was deleted.

56 changes: 0 additions & 56 deletions generator/vk_codegen/function_vkCreateInstance.txt

This file was deleted.

11 changes: 0 additions & 11 deletions generator/vk_codegen/function_vkDestroyDevice.txt

This file was deleted.

11 changes: 0 additions & 11 deletions generator/vk_codegen/function_vkDestroyInstance.txt

This file was deleted.

Loading

0 comments on commit 543afec

Please sign in to comment.