Skip to content

Commit

Permalink
Use VulkanSpec with its shiny new API
Browse files Browse the repository at this point in the history
  • Loading branch information
serenity4 committed Oct 4, 2023
1 parent 463b066 commit ede3089
Show file tree
Hide file tree
Showing 34 changed files with 260 additions and 265 deletions.
5 changes: 1 addition & 4 deletions generator/scripts/externsync.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
using Pkg
Pkg.activate(dirname(@__DIR__))
include("../src/spec/VulkanSpec.jl")

using .VulkanSpec

# List all function parameters which require external synchronization.
for f in spec_funcs
for f in api.functions
if any(f.params.is_externsync)
print("Function: ")
printstyled(f.name, '\n'; color = :cyan)
Expand Down
6 changes: 2 additions & 4 deletions generator/src/VulkanGen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ using Pkg: project
$(SIGNATURES)
"""

const VULKAN_API = Ref{VulkanAPI}()

__init__() = VULKAN_API[] = VulkanAPI(project().version)
const api = VulkanAPI(project().version)

include("types.jl")
include("exprs.jl")
Expand Down Expand Up @@ -106,6 +104,6 @@ export
Parent,
exports,

VULKAN_API
api

end # module VulkanGen
4 changes: 2 additions & 2 deletions generator/src/config.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ end
include_provisional_exts(config::WrapperConfig) = config.include_provisional_exts || PLATFORM_PROVISIONAL in config.include_platforms

function extensions(config::WrapperConfig)
exts = filter(x -> x.is_provisional && include_provisional_exts(config) || x.platform in config.include_platforms || x.platform == PLATFORM_NONE && config.wrap_core, spec_extensions_supported)
exts = filter(x -> x.is_provisional && include_provisional_exts(config) || x.platform in config.include_platforms || x.platform == PLATFORM_NONE && config.wrap_core, filter(x -> !x.is_disabled, api.extensions))
end

function _filter_specs(specs, extensions, wrap_core)
filter(specs) do spec
ext = extension(spec)
ext = get(api.extensions, spec, nothing)
isnothing(ext) && wrap_core || ext in extensions
end
end
Expand Down
2 changes: 1 addition & 1 deletion generator/src/dependency_resolution.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function dependencies(ex)
deps = raw_dependencies(ex)
filter!.(
[
!isalias,
x -> !isalias(x, api.aliases),
x -> !startswith(string(x), r"(?:Vk|VK_|StdVideo)"),
!is_vulkan_type,
!in(known_dependencies),
Expand Down
28 changes: 14 additions & 14 deletions generator/src/type_conversions.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
function hl_type(spec::Spec)
@match s = spec begin
if s.name == :pNext end => :Any
GuardBy(is_version) => :VersionNumber
if is_version(s, api.constants) end => :VersionNumber
GuardBy(is_arr) => begin
T = hl_type(ptr_type(s.type))
:(Vector{$T})
Expand All @@ -23,15 +23,15 @@ function hl_type(type)
end
:(NTuple{$_N,$(hl_type(T))})
end
GuardBy(in([spec_structs.name; spec_unions.name])) => struct_name(t, true)
GuardBy(in(spec_handles.name)) => remove_vk_prefix(t)
GuardBy(in([api.structs.name; api.unions.name])) => struct_name(t, true)
GuardBy(in(api.handles.name)) => remove_vk_prefix(t)
GuardBy(is_fn_ptr) => :FunctionPtr
:(Ptr{$T}) => hl_type(T)
GuardBy(is_flag_bitmask) => bitmask_flag_type(t)
GuardBy(in(spec_flags.name)) && if !isnothing(flag_by_name(t).bitmask)
end => bitmask_flag_type(flag_by_name(t).bitmask)
GuardBy(in(spec_constants.name)) => follow_constant(t)
GuardBy(in(spec_enums.name)) => enum_type(t)
GuardBy(in(api.flags.name)) && if !isnothing(api.flags[t].bitmask)
end => bitmask_flag_type(api.flags[t].bitmask)
GuardBy(in(api.constants.name)) => follow_constant(t, api.constants)
GuardBy(in(api.enums.name)) => enum_type(t)
GuardBy(is_vulkan_type) => remove_vk_prefix(t)
GuardBy(is_intermediate) => Symbol(string(t)[2:end])
_ => t
Expand All @@ -53,13 +53,13 @@ function idiomatic_julia_type(type)
:Cstring => :String
:VkBool32 => :Bool
:(Ptr{$pt}) => idiomatic_julia_type(pt)
GuardBy(in([spec_structs.name; spec_unions.name])) => struct_name(t)
GuardBy(in(spec_handles.name)) => remove_vk_prefix(t)
GuardBy(in(spec_enums.name)) => enum_type(t)
GuardBy(in([api.structs.name; api.unions.name])) => struct_name(t)
GuardBy(in(api.handles.name)) => remove_vk_prefix(t)
GuardBy(in(api.enums.name)) => enum_type(t)
GuardBy(is_flag_bitmask) => bitmask_flag_type(t)
GuardBy(in(spec_flags.name)) && if !isnothing(flag_by_name(t).bitmask)
end => bitmask_flag_type(flag_by_name(t).bitmask)
GuardBy(in(spec_constants.name)) => follow_constant(t)
GuardBy(in(api.flags.name)) && if !isnothing(api.flags[t].bitmask)
end => bitmask_flag_type(api.flags[t].bitmask)
GuardBy(in(api.constants.name)) => follow_constant(t, api.constants)
_ => t
end
end
Expand All @@ -69,7 +69,7 @@ Return a new type easier to deal with.
"""
function idiomatic_julia_type(spec::Spec)
@match s = spec begin
GuardBy(is_version) => :VersionNumber
if is_version(s, api.constants) end => :VersionNumber
GuardBy(is_arr) => :(Vector{$(idiomatic_julia_type(ptr_type(s.type)))})
GuardBy(is_data) => :(Ptr{Cvoid})
_ => idiomatic_julia_type(s.type)
Expand Down
2 changes: 1 addition & 1 deletion generator/src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ ntuple_type(ex) = @when :(NTuple{$N,$T}) = ex T

is_ntuple(ex) = !isnothing(ntuple_type(ex))

is_vulkan_type(name) = name [spec_handles.name; spec_structs.name; spec_unions.name]
is_vulkan_type(name) = name [api.handles.name; api.structs.name; api.unions.name]

inner_type(ex) = @when :($T{$(args...)}) = ex map(args) do arg
@match arg begin
Expand Down
56 changes: 27 additions & 29 deletions generator/src/wrap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ struct Parent <: MethodDefinition
p::Dict
end

VulkanSpec.has_parent(def::HandleDefinition) = has_parent(def.spec)

struct StructureType <: MethodDefinition
spec::SpecStruct
ex::Expr
Expand Down Expand Up @@ -153,19 +151,19 @@ include("wrap/docs.jl")
function VulkanWrapper(config::WrapperConfig)
f = filter_specs(config)

constants = ConstantDefinition.(filter(include_constant, f(spec_constants)))
enums = EnumDefinition.(f(spec_enums))
bitmasks = BitmaskDefinition.(f(spec_bitmasks))
handles = HandleDefinition.(f(spec_handles))
constants = ConstantDefinition.(filter(include_constant, f(api.constants)))
enums = EnumDefinition.(f(api.enums))
bitmasks = BitmaskDefinition.(f(api.bitmasks))
handles = HandleDefinition.(f(api.handles))

# Structures.
structs = StructDefinition{false}.(f(spec_structs))
structs = StructDefinition{false}.(f(api.structs))
structs_hl = StructDefinition{true}.(structs)

struct_constructors = Constructor.(structs)
struct_constructors_from_hl = [Constructor(T, x) for (T, x) in zip(structs, structs_hl)]
struct_constructors_from_ll = [Constructor(T, x) for (T, x) in zip(structs_hl, structs)]
struct_constructors_from_core = [Constructor(T, x) for (T, x) in zip(structs_hl, f(spec_structs))]
struct_constructors_from_core = [Constructor(T, x) for (T, x) in zip(structs_hl, f(api.structs))]
struct_constructors_hl = Constructor.(structs_hl)

## Do not overwrite the default constructor (leads to infinite recursion).
Expand All @@ -174,7 +172,7 @@ function VulkanWrapper(config::WrapperConfig)
end

# Unions.
unions = StructDefinition{false}.(f(spec_unions))
unions = StructDefinition{false}.(f(api.unions))
unions_hl = StructDefinition{true}.(unions)

union_constructors = [constructors.(unions)...;]
Expand All @@ -185,13 +183,13 @@ function VulkanWrapper(config::WrapperConfig)

enum_converts_to_integer = [Convert(enum, enum_val_type(enum)) for enum in enums]
enum_converts_to_enum = [Convert(enum_val_type(enum), enum) for enum in enums]
enum_converts_from_spec = [Convert(enum, spec_enum.name) for (enum, spec_enum) in zip(enums, f(spec_enums))]
enum_converts_to_spec = [Convert(spec_enum.name, enum) for (enum, spec_enum) in zip(enums, f(spec_enums))]
enum_converts_from_spec = [Convert(enum, spec_enum.name) for (enum, spec_enum) in zip(enums, f(api.enums))]
enum_converts_to_spec = [Convert(spec_enum.name, enum) for (enum, spec_enum) in zip(enums, f(api.enums))]
struct_converts_to_ll = [Convert(T, x) for (T, x) in zip(structs, structs_hl)]
union_converts_to_ll = [Convert(T, x) for (T, x) in zip(unions, unions_hl)]

funcs = APIFunction.(f(spec_funcs), false)
funcs_fptr = APIFunction.(f(spec_funcs), true)
funcs = APIFunction.(f(api.functions), false)
funcs_fptr = APIFunction.(f(api.functions), true)
funcs_hl = promote_hl.(funcs)
funcs_hl_fptr = promote_hl.(funcs_fptr)

Expand All @@ -209,7 +207,7 @@ function VulkanWrapper(config::WrapperConfig)
handle_constructors_api_hl_fptr = Constructor{HandleDefinition,APIFunction{APIFunction{SpecFunc}}}[]

for handle in handles
cs = f(filter(x -> x.handle == handle.spec && !x.batch, spec_create_funcs))
cs = f(filter(x -> x.handle == handle.spec && !x.batch, api.constructors))
for api_constructor in cs
(; func) = api_constructor
f1 = APIFunction(func, false)
Expand Down Expand Up @@ -246,16 +244,16 @@ function VulkanWrapper(config::WrapperConfig)

parent_overloads = Parent.(filter(has_parent, handles))

stypes = StructureType.(filter(x -> haskey(structure_types, x.name), f(spec_structs)))
hl_type_mappings = [HLTypeMapping.(f(spec_structs)); HLTypeMapping.(f(spec_unions))]
core_type_mappings = [CoreTypeMapping.(f(spec_structs)); CoreTypeMapping.(f(spec_unions))]
intermediate_type_mappings = IntermediateTypeMapping.(filter(has_intermediate_type, f(spec_structs)))
stypes = StructureType.(filter(x -> haskey(api.structure_types, x.name), f(api.structs)))
hl_type_mappings = [HLTypeMapping.(f(api.structs)); HLTypeMapping.(f(api.unions))]
core_type_mappings = [CoreTypeMapping.(f(api.structs)); CoreTypeMapping.(f(api.unions))]
intermediate_type_mappings = IntermediateTypeMapping.(filter(has_intermediate_type, f(api.structs)))

# For SPIR-V, there is no platform-dependent behavior, so no need to call `f`.
spirv_exts = spec_spirv_extensions
spirv_caps = map(spec_spirv_capabilities) do spec
spirv_exts = api.extensions_spirv
spirv_caps = map(api.capabilities_spirv) do spec
feats = map(spec.enabling_features) do feat
FeatureCondition(struct_name(follow_alias(feat.type), true), nc_convert(SnakeCaseLower, feat.member), feat.core_version, feat.extension)
FeatureCondition(struct_name(follow_alias(feat.type, api.aliases), true), nc_convert(SnakeCaseLower, feat.member), feat.core_version, feat.extension)
end
props = map(spec.enabling_properties) do prop
bit = isnothing(prop.bit) ? nothing : remove_vk_prefix(prop.bit)
Expand All @@ -269,25 +267,25 @@ function VulkanWrapper(config::WrapperConfig)
]

aliases = AliasDeclaration[]
for (source, target) in collect(alias_dict)
for (source, target) in collect(api.aliases.dict)
startswith(string(target), "vk") && continue
al = AliasDeclaration(source => target)
al.target in exported_symbols && push!(aliases, al)
end
function_aliases = Expr[]
_spec_funcs = f(spec_funcs)
for (source, target) in collect(alias_dict)
functions = f(api.functions)
for (source, target) in collect(api.aliases.dict)
al = AliasDeclaration(source => target)
startswith(string(source), "vk") || continue
f = func_by_name(target)
f = api.functions[target]
handle = dispatch_handle(f)
param = @match handle begin
:(device($x)) || :(instance($x)) || x::Symbol => x
nothing => nothing
end
args = Any[:(args...)]
!isnothing(param) && pushfirst!(args, param)
if f in _spec_funcs
if f in functions
push!(function_aliases,
# :($source(args..., fptr::FunctionPtr; kwargs...) = $target(args..., fptr; kwargs...)),
:($(al.source)($(args...); kwargs...) = @dispatch $source $handle $(al.target)($(args...); kwargs...))
Expand Down Expand Up @@ -348,9 +346,9 @@ function VulkanWrapper(config::WrapperConfig)

:(const SPIRV_EXTENSIONS = [$(spirv_exts...)]);
:(const SPIRV_CAPABILITIES = [$(spirv_caps...)]);
:(const CORE_FUNCTIONS = $core_functions);
:(const INSTANCE_FUNCTIONS = $instance_functions);
:(const DEVICE_FUNCTIONS = $device_functions);
:(const CORE_FUNCTIONS = $(api.core_functions));
:(const INSTANCE_FUNCTIONS = $(api.instance_functions));
:(const DEVICE_FUNCTIONS = $(api.device_functions));
],
exported_symbols,
)
Expand Down
28 changes: 14 additions & 14 deletions generator/src/wrap/call.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ end

function len_expr(x::Spec, identifier)
@assert !isnothing(x.len)
params = children(parent_spec(x))
params = children(x.parent)
postwalk(x.len) do ex
ex == :/ && return :÷
ex isa Symbol && ex in params.name && return :($identifier.$ex)
Expand All @@ -27,11 +27,11 @@ end
function from_vk_call(prop, t, jtype = hl_type(t))
@match t begin
:Cstring => :(unsafe_string($prop))
GuardBy(in(spec_flags.name)) || GuardBy(in(spec_enums.name)) => prop
GuardBy(in(getproperty.(filter(!isnothing, spec_flags.bitmask), :name))) => :($jtype(UInt32($prop)))
GuardBy(in(spec_handles.name)) => :($(remove_vk_prefix(t))($prop))
GuardBy(in(api.flags.name)) || GuardBy(in(api.enums.name)) => prop
GuardBy(in(getproperty.(filter(!isnothing, api.flags.bitmask), :name))) => :($jtype(UInt32($prop)))
GuardBy(in(api.handles.name)) => :($(remove_vk_prefix(t))($prop))
:(NTuple{$_,$T}) && if jtype :String end => broadcast_ex(from_vk_call(prop, ntuple_type(t)))
if follow_constant(t) == jtype
if follow_constant(t, api.constants) == jtype
end => prop
if is_hl(jtype) end => :($jtype($prop))
_ => :(from_vk($jtype, $prop))
Expand All @@ -42,8 +42,8 @@ function vk_call(x::Spec)
var = wrap_identifier(x.name)
jtype = idiomatic_julia_type(x)
@match x begin
::SpecStructMember && if x.type == :VkStructureType && parent(x) keys(structure_types)
end => :(structure_type($(parent(x))))
::SpecStructMember && if x.type == :VkStructureType && x.parent.name keys(api.structure_types)
end => :(structure_type($(x.parent.name)))
::SpecStructMember && if is_semantic_ptr(x.type)
end => :(unsafe_convert($(x.type), $var))
if is_fn_ptr(x.type)
Expand All @@ -59,30 +59,30 @@ function vk_call(x::Spec)
end
end
GuardBy(is_pointer_start) => 0 # always set first* variables to 0, and the user should provide a (sub)array of the desired length
if x.type spec_handles.name
if x.type api.handles.name
end => var # handled by unsafe_convert in ccall

# constant pointer to a unique object
if is_ptr(x.type) &&
!is_arr(x) &&
(x.is_constant || (func = func_by_name(x.func); func.type == FTYPE_QUERY && x last(children(func))))
(x.is_constant || (func = api.functions[x.func]; func.type == FTYPE_QUERY && x last(children(func))))
end => @match x begin
if ptr_type(x.type) [spec_structs.name; spec_unions.name]
if ptr_type(x.type) [api.structs.name; api.unions.name]
end => var # handled by cconvert and unsafe_convert in ccall
if x.requirement == OPTIONAL
end => :($var == $(default(x)) ? $(default(x)) : Ref($var)) # allow optional pointers to be passed as C_NULL instead of a pointer to a 0-valued integer
_ => :(Ref($var))
end
if x.type [spec_flags.name; spec_enums.name]
if x.type [api.flags.name; api.enums.name]
end => var
if x.type getproperty.(filter(!isnothing, spec_flags.bitmask), :name)
if x.type getproperty.(filter(!isnothing, api.flags.bitmask), :name)
end => :($(x.type)($var.val))
if x.type extension_types
end => var
_ => @match jtype begin
:String || :Bool || :(Vector{$et}) || if jtype == follow_constant(x.type)
:String || :Bool || :(Vector{$et}) || if jtype == follow_constant(x.type, api.constants)
end => var # conversions are already defined
if x.type in [spec_structs.name; spec_unions.name] && jtype == struct_name(x.type)
if x.type in [api.structs.name; api.unions.name] && jtype == struct_name(x.type)
end => :($var.vks)
:(NTuple{Int($_N),$_T}) => var
_ => :(to_vk($(x.type), $var)) # fall back to the to_vk function for conversion
Expand Down
21 changes: 14 additions & 7 deletions generator/src/wrap/classification.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ is_optional(param::SpecFuncParam) = param.requirement ∈ [OPTIONAL, POINTER_OPT
"""
Represent an integer that gives the start of a C pointer.
"""
function is_pointer_start(spec::Spec)
params = children(parent_spec(spec))
any(params) do param
function is_pointer_start(spec::Union{SpecStructMember, SpecFuncParam})
any(spec.parent) do param
!isempty(param.arglen) &&
spec.type == :UInt32 &&
string(spec.name) == string("first", uppercasefirst(replace(string(param.name), r"Count$" => "")))
Expand All @@ -21,6 +20,14 @@ is_data_with_retrievable_size(spec::SpecFuncParam) = is_data(spec) && len(spec).
is_opaque_data(spec) = is_data(spec) && len(spec).requirement POINTER_REQUIRED
is_opaque_pointer(type) = is_ptr(type) && is_void(ptr_type(type))
is_opaque_pointer(spec::Spec) = is_opaque_pointer(spec.type)
is_void(t) = t == :Cvoid || t in [
:xcb_connection_t,
:_XDisplay,
:Display,
:wl_surface,
:wl_display,
:CAMetalLayer,
]
is_opaque(spec) = is_opaque_data(spec) || is_opaque_pointer(spec)
is_implicit_return(spec::SpecFuncParam) =
!is_opaque_data(spec) &&
Expand All @@ -30,15 +37,15 @@ is_implicit_return(spec::SpecFuncParam) =
spec.type extension_types &&
ptr_type(spec.type) extension_types
has_implicit_return_parameters(spec::SpecFunc) = any(is_implicit_return, children(spec))
is_flag(type) = type in spec_flags.name
is_flag(spec::Union{SpecFuncParam,SpecStructMember}) = spec.type in spec_flags.name
is_flag_bitmask(type) = type getproperty.(filter(!isnothing, spec_flags.bitmask), :name)
is_flag(type) = type in api.flags.name
is_flag(spec::Union{SpecFuncParam,SpecStructMember}) = spec.type in api.flags.name
is_flag_bitmask(type) = type getproperty.(filter(!isnothing, api.flags.bitmask), :name)
is_fn_ptr(type) = startswith(string(type), "PFN_")
is_fn_ptr(spec::Spec) = is_fn_ptr(spec.type)

function is_hl(type)
vktype = Symbol(:Vk, type)
vktype in [spec_structs.name; spec_unions.name]
vktype in [api.structs.name; api.unions.name]
end

is_intermediate(type) = startswith(string(type), '_')
Expand Down
Loading

0 comments on commit ede3089

Please sign in to comment.