Skip to content

Commit 99ddac1

Browse files
committed
Query specializations using C++ concepts
1 parent 8bb89ab commit 99ddac1

16 files changed

+15793
-5990
lines changed

generator/generate_vulkan_common.py

Lines changed: 179 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -508,40 +508,104 @@ def generate_instance_decls(
508508
if plat_define:
509509
lines.append(f'#if defined({plat_define})\n')
510510

511-
# Declare the default implementation
511+
# Explicitly delete the generic primary template
512512
lines.append('/* See Vulkan API for documentation. */')
513-
lines.append('/* Default common code pass-through implementation. */')
514-
decl = f'VKAPI_ATTR {command.rtype} ' \
515-
f'VKAPI_CALL layer_{command.name}_default('
513+
lines.append('/* Delete the generic match-all */')
514+
decl = f'template <typename T>\n' \
515+
f'VKAPI_ATTR {command.rtype} ' \
516+
f'VKAPI_CALL layer_{command.name}('
516517
lines.append(decl)
517518

518519
for i, (ptype, pname, array) in enumerate(command.params):
519520
ending = ','
520521
if i == len(command.params) - 1:
521-
ending = ');'
522+
ending = ') = delete;'
522523
parl = f' {ptype} {pname}{array}{ending}'
523524
lines.append(parl)
524525
lines.append('')
525526

526-
# Define the default tag dispatch handler
527-
lines.append('/* Match-all template to use default implementation. */')
528-
decl = 'template <typename T>'
529-
lines.append(decl)
530-
decl = f'VKAPI_ATTR {command.rtype} VKAPI_CALL layer_{command.name}('
527+
# Define the default_tag template
528+
lines.append('/* Default common code implementation. */')
529+
decl = f'template <>\n' \
530+
f'VKAPI_ATTR {command.rtype} ' \
531+
f'VKAPI_CALL layer_{command.name}<default_tag>('
531532
lines.append(decl)
532533

533534
for i, (ptype, pname, array) in enumerate(command.params):
534535
ending = ','
535536
if i == len(command.params) - 1:
536-
ending = ''
537+
ending = ');'
537538
parl = f' {ptype} {pname}{array}{ending}'
538539
lines.append(parl)
540+
lines.append('')
539541

540-
parmfwd = ', '.join([x[1] for x in command.params])
541-
retfwd = 'return ' if command.rtype != 'void' else ''
542-
lines.append(') {')
543-
lines.append(f' {retfwd}layer_{command.name}_default({parmfwd});')
544-
lines.append('}\n')
542+
if plat_define:
543+
lines.append('#endif\n')
544+
545+
file.write('\n'.join(lines))
546+
file.write('\n')
547+
548+
file.write('// clang-format on\n')
549+
550+
551+
def generate_instance_queries(
552+
file: TextIO, mapping: VersionInfo, commands: list[Command]) -> None:
553+
'''
554+
Generate the instance intercept declarations header.
555+
556+
Args:
557+
file: The file to write.
558+
mapping: The version mapping information for the commands.
559+
commands: The list of commands read from the spec.
560+
'''
561+
# Write the copyright header to the file
562+
write_copyright_header(file)
563+
564+
file.write('#pragma once\n')
565+
file.write('\n')
566+
567+
file.write('// clang-format off\n')
568+
file.write('\n')
569+
570+
file.write('#include <vulkan/vulkan.h>\n')
571+
file.write('\n')
572+
573+
# Create a listing of API versions and API extensions
574+
for command in commands:
575+
if command.dispatch_type != 'instance':
576+
continue
577+
578+
lines = []
579+
assert command.name
580+
581+
plat_define = mapping.get_platform_define(command.name)
582+
if plat_define:
583+
lines.append(f'#if defined({plat_define})\n')
584+
585+
# Define the concept to test if user_tag specialization exists
586+
lines.append('/* Test for user_tag availability. */')
587+
decl = f'template <typename T>\n' \
588+
f'concept hasLayerPtr_{command.name} = ' \
589+
f'requires {{ layer_{command.name}<user_tag>; }};'
590+
lines.append(decl)
591+
lines.append('')
592+
593+
# Define the function pointer resolution
594+
lines.append('/* Function pointer resolution. */')
595+
decl = f'constexpr PFN_{command.name} getLayerPtr_{command.name}()\n' \
596+
f'{{\n' \
597+
f' return [] <typename T>\n' \
598+
f' {{\n' \
599+
f' if constexpr(hasLayerPtr_{command.name}<T>)\n' \
600+
f' {{\n' \
601+
f' return layer_{command.name}<T>;\n' \
602+
f' }}\n' \
603+
f'\n' \
604+
f' return layer_{command.name}<default_tag>;\n' \
605+
f' }}.operator()<user_tag>();\n' \
606+
f'}}'
607+
lines.append(decl)
608+
lines.append('')
545609

546610
if plat_define:
547611
lines.append('#endif\n')
@@ -582,8 +646,9 @@ def generate_instance_defs(
582646
lines.append(f'#if defined({plat_define})\n')
583647

584648
lines.append('/* See Vulkan API for documentation. */')
585-
decl = f'VKAPI_ATTR {command.rtype} ' \
586-
f'VKAPI_CALL layer_{command.name}_default('
649+
decl = f'template <>\n' \
650+
f'VKAPI_ATTR {command.rtype} ' \
651+
f'VKAPI_CALL layer_{command.name}<default_tag>('
587652
lines.append(decl)
588653

589654
for i, (ptype, pname, array) in enumerate(command.params):
@@ -691,7 +756,8 @@ def generate_device_decls(
691756
file.write('// clang-format off\n')
692757
file.write('\n')
693758

694-
file.write('#include <vulkan/vulkan.h>\n')
759+
file.write('#include <vulkan/vulkan.h>\n\n')
760+
file.write('#include "framework/utils.hpp"\n')
695761
file.write('\n')
696762

697763
# Create a listing of API versions and API extensions
@@ -706,39 +772,36 @@ def generate_device_decls(
706772
if plat_define:
707773
lines.append(f'#if defined({plat_define})\n')
708774

775+
# Explicitly delete the generic primary template
709776
lines.append('/* See Vulkan API for documentation. */')
710-
lines.append('/* Default common code pass-through implementation. */')
711-
decl = f'VKAPI_ATTR {command.rtype} ' \
712-
f'VKAPI_CALL layer_{command.name}_default('
777+
lines.append('/* Delete the generic match-all */')
778+
decl = f'template <typename T>\n' \
779+
f'VKAPI_ATTR {command.rtype} ' \
780+
f'VKAPI_CALL layer_{command.name}('
713781
lines.append(decl)
714782

715783
for i, (ptype, pname, array) in enumerate(command.params):
716784
ending = ','
717785
if i == len(command.params) - 1:
718-
ending = ');'
786+
ending = ') = delete;'
719787
parl = f' {ptype} {pname}{array}{ending}'
720788
lines.append(parl)
721789
lines.append('')
722790

723-
# Define the default tag dispatch handler
724-
lines.append('/* Match-all template to use default implementation. */')
725-
decl = 'template <typename T>'
726-
lines.append(decl)
727-
decl = f'VKAPI_ATTR {command.rtype} VKAPI_CALL layer_{command.name}('
791+
# Define the default_tag template
792+
lines.append('/* Default common code implementation. */')
793+
decl = f'template <>\n' \
794+
f'VKAPI_ATTR {command.rtype} ' \
795+
f'VKAPI_CALL layer_{command.name}<default_tag>('
728796
lines.append(decl)
729797

730798
for i, (ptype, pname, array) in enumerate(command.params):
731799
ending = ','
732800
if i == len(command.params) - 1:
733-
ending = ''
801+
ending = ');'
734802
parl = f' {ptype} {pname}{array}{ending}'
735803
lines.append(parl)
736-
737-
parmfwd = ', '.join([x[1] for x in command.params])
738-
retfwd = 'return ' if command.rtype != 'void' else ''
739-
lines.append(') {')
740-
lines.append(f' {retfwd}layer_{command.name}_default({parmfwd});')
741-
lines.append('}\n')
804+
lines.append('')
742805

743806
if plat_define:
744807
lines.append('#endif\n')
@@ -779,9 +842,9 @@ def generate_device_defs(
779842
lines.append(f'#if defined({plat_define})\n')
780843

781844
lines.append('/* See Vulkan API for documentation. */')
782-
783-
decl = f'VKAPI_ATTR {command.rtype} ' \
784-
f'VKAPI_CALL layer_{command.name}_default('
845+
decl = f'template <>\n' \
846+
f'VKAPI_ATTR {command.rtype} ' \
847+
f'VKAPI_CALL layer_{command.name}<default_tag>('
785848
lines.append(decl)
786849

787850
for i, (ptype, pname, array) in enumerate(command.params):
@@ -815,6 +878,76 @@ def generate_device_defs(
815878
file.write(data)
816879

817880

881+
def generate_device_queries(
882+
file: TextIO, mapping: VersionInfo, commands: list[Command]) -> None:
883+
'''
884+
Generate the device intercept queries header.
885+
886+
Args:
887+
file: The file to write.
888+
mapping: The version mapping information for the commands.
889+
commands: The list of commands read from the spec.
890+
'''
891+
892+
# Write the copyright header to the file
893+
write_copyright_header(file)
894+
895+
file.write('#pragma once\n')
896+
file.write('\n')
897+
898+
file.write('// clang-format off\n')
899+
file.write('\n')
900+
901+
file.write('#include <vulkan/vulkan.h>\n\n')
902+
file.write('#include "framework/utils.hpp"\n')
903+
file.write('\n')
904+
905+
# Create a listing of API versions and API extensions
906+
for command in commands:
907+
if command.dispatch_type != 'device':
908+
continue
909+
910+
assert command.name
911+
912+
lines = []
913+
plat_define = mapping.get_platform_define(command.name)
914+
if plat_define:
915+
lines.append(f'#if defined({plat_define})\n')
916+
917+
# Define the concept to test if user_tag specialization exists
918+
lines.append('/* Test for user_tag availability. */')
919+
decl = f'template <typename T>\n' \
920+
f'concept hasLayerPtr_{command.name} = ' \
921+
f'requires {{ layer_{command.name}<user_tag>; }};'
922+
lines.append(decl)
923+
lines.append('')
924+
925+
# Define the function pointer resolution
926+
lines.append('/* Function pointer resolution. */')
927+
decl = f'constexpr PFN_{command.name} getLayerPtr_{command.name}()\n' \
928+
f'{{\n' \
929+
f' return [] <typename T>\n' \
930+
f' {{\n' \
931+
f' if constexpr(hasLayerPtr_{command.name}<T>)\n' \
932+
f' {{\n' \
933+
f' return layer_{command.name}<T>;\n' \
934+
f' }}\n' \
935+
f'\n' \
936+
f' return layer_{command.name}<default_tag>;\n' \
937+
f' }}.operator()<user_tag>();\n' \
938+
f'}}'
939+
lines.append(decl)
940+
lines.append('')
941+
942+
if plat_define:
943+
lines.append('#endif\n')
944+
945+
file.write('\n'.join(lines))
946+
file.write('\n')
947+
948+
file.write('// clang-format on\n')
949+
950+
818951
def main() -> int:
819952
'''
820953
Tool main function.
@@ -867,6 +1000,10 @@ def main() -> int:
8671000
with open(outfile, 'w', encoding='utf-8', newline='\n') as handle:
8681001
generate_instance_decls(handle, mapping, commands)
8691002

1003+
outfile = os.path.join(outdir, 'instance_functions_query.hpp')
1004+
with open(outfile, 'w', encoding='utf-8', newline='\n') as handle:
1005+
generate_instance_queries(handle, mapping, commands)
1006+
8701007
outfile = os.path.join(outdir, 'instance_functions.cpp')
8711008
with open(outfile, 'w', encoding='utf-8', newline='\n') as handle:
8721009
generate_instance_defs(handle, mapping, commands)
@@ -879,6 +1016,10 @@ def main() -> int:
8791016
with open(outfile, 'w', encoding='utf-8', newline='\n') as handle:
8801017
generate_device_decls(handle, mapping, commands)
8811018

1019+
outfile = os.path.join(outdir, 'device_functions_query.hpp')
1020+
with open(outfile, 'w', encoding='utf-8', newline='\n') as handle:
1021+
generate_device_queries(handle, mapping, commands)
1022+
8821023
outfile = os.path.join(outdir, 'device_functions.cpp')
8831024
with open(outfile, 'w', encoding='utf-8', newline='\n') as handle:
8841025
generate_device_defs(handle, mapping, commands)

generator/vk_codegen/device_dispatch_table.txt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
#include "layer_device_functions.hpp"
1313
#endif
1414

15+
// These must be after the layer_*_functions.hpp includes
16+
#include "framework/device_functions_query.hpp"
17+
1518
/**
1619
* @brief Interception table lookup entry.
1720
*/
@@ -28,12 +31,12 @@ struct DeviceInterceptTableEntry
2831
PFN_vkVoidFunction function;
2932

3033
/**
31-
* @brief The layer default function pointer.
34+
* @brief Did the layer provide a specialization?
3235
*/
33-
PFN_vkVoidFunction defaultFunction;
36+
bool hasLayerSpecialization;
3437
};
3538

36-
#define ENTRY(fnc) { STR(fnc), reinterpret_cast<PFN_vkVoidFunction>(layer_##fnc<user_tag>), reinterpret_cast<PFN_vkVoidFunction>(layer_##fnc<default_tag>) }
39+
#define ENTRY(fnc) { STR(fnc), reinterpret_cast<PFN_vkVoidFunction>(getLayerPtr_##fnc()), hasLayerPtr_##fnc<user_tag> }
3740

3841
/**
3942
* @brief The device dispatch table used to call the driver.

generator/vk_codegen/instance_dispatch_table.txt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
#include "layer_instance_functions.hpp"
1414
#endif
1515

16+
// These must be after the layer_*_functions.hpp includes
17+
#include "framework/device_functions_query.hpp"
18+
#include "framework/instance_functions_query.hpp"
19+
1620
/**
1721
* @brief Interception table lookup entry.
1822
*/
@@ -29,12 +33,12 @@ struct InstanceInterceptTableEntry
2933
PFN_vkVoidFunction function;
3034

3135
/**
32-
* @brief The layer default function pointer.
36+
* @brief Did the layer provide a specialization?
3337
*/
34-
PFN_vkVoidFunction defaultFunction;
38+
bool hasLayerSpecialization;
3539
};
3640

37-
#define ENTRY(fnc) { STR(fnc), reinterpret_cast<PFN_vkVoidFunction>(layer_##fnc<user_tag>), reinterpret_cast<PFN_vkVoidFunction>(layer_##fnc<default_tag>) }
41+
#define ENTRY(fnc) { STR(fnc), reinterpret_cast<PFN_vkVoidFunction>(getLayerPtr_##fnc()), hasLayerPtr_##fnc<user_tag> }
3842

3943
/**
4044
* @brief The instance dispatch table used to call the driver.

layer_gpu_timeline/manifest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"file_format_version": "1.0.0",
33
"layer": {
4-
"name": "VK_LAYER_LGL_gpu_timeline",
4+
"name": "VK_LAYER_LGL_gpu_timeline2",
55
"type": "INSTANCE",
6-
"library_path": "libVkLayerGPUTimeline.so",
6+
"library_path": "libVkLayerGPUTimeline2.so",
77
"api_version": "1.0.0",
88
"implementation_version": "1",
99
"description": "Layer for generating API correlated semantic metadata"

layer_gpu_timeline/source/CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@
2323

2424
# Set output file names
2525
if (CMAKE_BUILD_TYPE STREQUAL "Release")
26-
set(VK_LAYER VkLayerGPUTimeline_sym)
27-
set(VK_LAYER_STRIP libVkLayerGPUTimeline.so)
26+
set(VK_LAYER VkLayerGPUTimeline2_sym)
27+
set(VK_LAYER_STRIP libVkLayerGPUTimeline2.so)
2828
else()
2929
set(VK_LAYER VkLayerGPUTimeline)
3030
endif()
3131

3232
# Set strings used by configure
33-
set(LGL_LAYER_NAME_STR "VK_LAYER_LGL_gpu_timeline")
34-
set(LGL_LAYER_DESC_STR "VkLayerGPUTimeline by LGL")
33+
set(LGL_LAYER_NAME_STR "VK_LAYER_LGL_gpu_timeline2")
34+
set(LGL_LAYER_DESC_STR "VkLayerGPUTimeline2 by LGL")
3535

3636
# Vulkan layer library
3737
configure_file(

0 commit comments

Comments
 (0)