1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use std::mem;
use syn::Ident;
use proc_macro2::{Span, TokenStream};
use crate::enums::Decoration;
use crate::parse::{Instruction, Spirv};
use crate::spirv_search;
use crate::structs;
pub fn has_specialization_constants(doc: &Spirv) -> bool {
for instruction in doc.instructions.iter() {
match instruction {
&Instruction::SpecConstantTrue { .. } => return true,
&Instruction::SpecConstantFalse { .. } => return true,
&Instruction::SpecConstant { .. } => return true,
&Instruction::SpecConstantComposite { .. } => return true,
_ => (),
}
}
false
}
pub fn write_specialization_constants(doc: &Spirv) -> TokenStream {
struct SpecConst {
name: String,
constant_id: u32,
rust_ty: TokenStream,
rust_size: usize,
rust_alignment: u32,
default_value: TokenStream,
}
let mut spec_consts = Vec::new();
for instruction in doc.instructions.iter() {
let (type_id, result_id, default_value) = match instruction {
&Instruction::SpecConstantTrue { result_type_id, result_id } =>
(result_type_id, result_id, quote!{1u32}),
&Instruction::SpecConstantFalse { result_type_id, result_id } =>
(result_type_id, result_id, quote!{0u32}),
&Instruction::SpecConstant { result_type_id, result_id, ref data } => {
let def_val = quote!{
unsafe {{ ::std::mem::transmute([ #( #data ),* ]) }}
};
(result_type_id, result_id, def_val)
}
&Instruction::SpecConstantComposite { result_type_id, result_id, ref data } => {
let def_val = quote!{
unsafe {{ ::std::mem::transmute([ #( #data ),* ]) }}
};
(result_type_id, result_id, def_val)
}
_ => continue,
};
let (rust_ty, rust_size, rust_alignment) = spec_const_type_from_id(doc, type_id);
let rust_size = rust_size.expect("Found runtime-sized specialization constant");
let constant_id = doc.get_decoration_params(result_id, Decoration::DecorationSpecId)
.unwrap()[0];
spec_consts.push(SpecConst {
name: spirv_search::name_from_id(doc, result_id),
constant_id,
rust_ty,
rust_size,
rust_alignment: rust_alignment as u32,
default_value,
});
}
let map_entries = {
let mut map_entries = Vec::new();
let mut curr_offset = 0;
for spec_const in &spec_consts {
let constant_id = spec_const.constant_id;
let rust_size = spec_const.rust_size;
map_entries.push(quote!{
SpecializationMapEntry {
constant_id: #constant_id,
offset: #curr_offset,
size: #rust_size,
}
});
assert_ne!(spec_const.rust_size, 0);
curr_offset += spec_const.rust_size as u32;
curr_offset = spec_const.rust_alignment * (1 + (curr_offset - 1) / spec_const.rust_alignment);
}
map_entries
};
let num_map_entries = map_entries.len();
let mut struct_members = vec!();
let mut struct_member_defaults = vec!();
for spec_const in spec_consts {
let name = Ident::new(&spec_const.name, Span::call_site());
let rust_ty = spec_const.rust_ty;
let default_value = spec_const.default_value;
struct_members.push(quote!{ pub #name: #rust_ty });
struct_member_defaults.push(quote!{ #name: #default_value });
}
quote!{
#[derive(Debug, Copy, Clone)]
#[allow(non_snake_case)]
#[repr(C)]
pub struct SpecializationConstants {
#( #struct_members ),*
}
impl Default for SpecializationConstants {
fn default() -> SpecializationConstants {
SpecializationConstants {
#( #struct_member_defaults ),*
}
}
}
unsafe impl SpecConstsTrait for SpecializationConstants {
fn descriptors() -> &'static [SpecializationMapEntry] {
static DESCRIPTORS: [SpecializationMapEntry; #num_map_entries] = [
#( #map_entries ),*
];
&DESCRIPTORS
}
}
}
}
fn spec_const_type_from_id(doc: &Spirv, searched: u32) -> (TokenStream, Option<usize>, usize) {
for instruction in doc.instructions.iter() {
match instruction {
&Instruction::TypeBool { result_id } if result_id == searched => {
return (quote!{u32}, Some(mem::size_of::<u32>()), mem::align_of::<u32>());
},
_ => (),
}
}
structs::type_from_id(doc, searched)
}