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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
package vk_backend
import bk ".."
import vk "vendor:vulkan"
// --- Format conversion ---
@(private)
to_vk_format :: proc(fmt: bk.Format) -> vk.Format {
switch fmt {
case .Undefined:
return .UNDEFINED
case .R8G8B8A8_SRGB:
return .R8G8B8A8_SRGB
case .R8G8B8A8_UNORM:
return .R8G8B8A8_UNORM
case .B8G8R8A8_SRGB:
return .B8G8R8A8_SRGB
case .D32_SFLOAT:
return .D32_SFLOAT
case .D32_SFLOAT_S8_UINT:
return .D32_SFLOAT_S8_UINT
case .D24_UNORM_S8_UINT:
return .D24_UNORM_S8_UINT
}
return .UNDEFINED
}
@(private)
from_vk_format :: proc(fmt: vk.Format) -> bk.Format {
#partial switch fmt {
case .R8G8B8A8_SRGB:
return .R8G8B8A8_SRGB
case .R8G8B8A8_UNORM:
return .R8G8B8A8_UNORM
case .B8G8R8A8_SRGB:
return .B8G8R8A8_SRGB
case .D32_SFLOAT:
return .D32_SFLOAT
case .D32_SFLOAT_S8_UINT:
return .D32_SFLOAT_S8_UINT
case .D24_UNORM_S8_UINT:
return .D24_UNORM_S8_UINT
case:
return .Undefined
}
}
// --- Buffer/memory conversion ---
@(private)
to_vk_buffer_usage :: proc(flags: bk.Buffer_Usage_Flags) -> vk.BufferUsageFlags {
result: vk.BufferUsageFlags
if .Vertex in flags {result += {.VERTEX_BUFFER}}
if .Index in flags {result += {.INDEX_BUFFER}}
if .Uniform in flags {result += {.UNIFORM_BUFFER}}
if .Storage in flags {result += {.STORAGE_BUFFER}}
if .Indirect_Argument in flags {result += {.INDIRECT_BUFFER}}
if .Transfer_Src in flags {result += {.TRANSFER_SRC}}
if .Transfer_Dst in flags {result += {.TRANSFER_DST}}
return result
}
@(private)
to_vk_memory_properties :: proc(flags: bk.Memory_Property_Flags) -> vk.MemoryPropertyFlags {
result: vk.MemoryPropertyFlags
if .Device_Local in flags {result += {.DEVICE_LOCAL}}
if .Host_Visible in flags {result += {.HOST_VISIBLE}}
if .Host_Coherent in flags {result += {.HOST_COHERENT}}
return result
}
// --- Pipeline state conversion ---
@(private)
to_vk_topology :: proc(t: bk.Topology) -> vk.PrimitiveTopology {
switch t {
case .Triangle_List:
return .TRIANGLE_LIST
case .Triangle_Strip:
return .TRIANGLE_STRIP
case .Line_List:
return .LINE_LIST
case .Point_List:
return .POINT_LIST
}
return .TRIANGLE_LIST
}
@(private)
to_vk_cull_mode :: proc(c: bk.Cull_Mode) -> vk.CullModeFlags {
switch c {
case .None:
return {}
case .Front:
return {.FRONT}
case .Back:
return {.BACK}
case .Front_And_Back:
return {.FRONT, .BACK}
}
return {}
}
@(private)
to_vk_front_face :: proc(f: bk.Front_Face) -> vk.FrontFace {
switch f {
case .Counter_Clockwise:
return .COUNTER_CLOCKWISE
case .Clockwise:
return .CLOCKWISE
}
return .COUNTER_CLOCKWISE
}
@(private)
to_vk_shader_stages :: proc(flags: bk.Shader_Stage_Flags) -> vk.ShaderStageFlags {
result: vk.ShaderStageFlags
if .Vertex in flags {result += {.VERTEX}}
if .Fragment in flags {result += {.FRAGMENT}}
if .Compute in flags {result += {.COMPUTE}}
return result
}
// --- Image conversion ---
@(private)
to_vk_image_usage :: proc(flags: bk.Image_Usage_Flags) -> vk.ImageUsageFlags {
result: vk.ImageUsageFlags
if .Sampled in flags {result += {.SAMPLED}}
if .Color_Attachment in flags {result += {.COLOR_ATTACHMENT}}
if .Depth_Stencil_Attachment in flags {result += {.DEPTH_STENCIL_ATTACHMENT}}
if .Transfer_Dst in flags {result += {.TRANSFER_DST}}
if .Transfer_Src in flags {result += {.TRANSFER_SRC}}
return result
}
@(private)
to_vk_image_aspect :: proc(flags: bk.Image_Aspect_Flags) -> vk.ImageAspectFlags {
result: vk.ImageAspectFlags
if .Color in flags {result += {.COLOR}}
if .Depth in flags {result += {.DEPTH}}
if .Stencil in flags {result += {.STENCIL}}
return result
}
@(private)
to_vk_image_layout :: proc(l: bk.Image_Layout) -> vk.ImageLayout {
switch l {
case .Undefined:
return .UNDEFINED
case .Color_Attachment:
return .COLOR_ATTACHMENT_OPTIMAL
case .Depth_Stencil_Attachment:
return .DEPTH_STENCIL_ATTACHMENT_OPTIMAL
case .Shader_Read_Only:
return .SHADER_READ_ONLY_OPTIMAL
case .Depth_Stencil_Read_Only:
return .DEPTH_STENCIL_READ_ONLY_OPTIMAL
case .Transfer_Dst:
return .TRANSFER_DST_OPTIMAL
case .Present_Src:
return .PRESENT_SRC_KHR
}
return .UNDEFINED
}
@(private)
to_vk_attachment_load_op :: proc(op: bk.Attachment_Load_Op) -> vk.AttachmentLoadOp {
switch op {
case .Load:
return .LOAD
case .Clear:
return .CLEAR
case .Dont_Care:
return .DONT_CARE
}
return .LOAD
}
@(private)
to_vk_attachment_store_op :: proc(op: bk.Attachment_Store_Op) -> vk.AttachmentStoreOp {
switch op {
case .Store:
return .STORE
case .Dont_Care:
return .DONT_CARE
}
return .STORE
}
// --- Sampler conversion ---
@(private)
to_vk_filter :: proc(f: bk.Filter) -> vk.Filter {
switch f {
case .Nearest:
return .NEAREST
case .Linear:
return .LINEAR
}
return .LINEAR
}
@(private)
to_vk_address_mode :: proc(m: bk.Address_Mode) -> vk.SamplerAddressMode {
switch m {
case .Repeat:
return .REPEAT
case .Clamp_To_Edge:
return .CLAMP_TO_EDGE
case .Clamp_To_Border:
return .CLAMP_TO_BORDER
}
return .REPEAT
}
@(private)
to_vk_compare_op :: proc(op: bk.Compare_Op) -> vk.CompareOp {
switch op {
case .Never:
return .NEVER
case .Less:
return .LESS
case .Less_Or_Equal:
return .LESS_OR_EQUAL
case .Equal:
return .EQUAL
case .Greater_Or_Equal:
return .GREATER_OR_EQUAL
case .Greater:
return .GREATER
case .Not_Equal:
return .NOT_EQUAL
case .Always:
return .ALWAYS
}
return .ALWAYS
}
@(private)
to_vk_stencil_op :: proc(op: bk.Stencil_Op) -> vk.StencilOp {
switch op {
case .Keep:
return .KEEP
case .Zero:
return .ZERO
case .Replace:
return .REPLACE
case .Increment_Clamp:
return .INCREMENT_AND_CLAMP
case .Decrement_Clamp:
return .DECREMENT_AND_CLAMP
case .Invert:
return .INVERT
}
return .KEEP
}
@(private)
to_vk_stencil_face :: proc(face: bk.Stencil_Face_State, state: bk.Stencil_State) -> vk.StencilOpState {
return {
failOp = to_vk_stencil_op(face.fail_op),
passOp = to_vk_stencil_op(face.pass_op),
depthFailOp = to_vk_stencil_op(face.depth_fail_op),
compareOp = to_vk_compare_op(face.compare_op),
compareMask = u32(state.read_mask),
writeMask = u32(state.write_mask),
reference = u32(state.reference),
}
}
// --- Descriptor conversion ---
@(private)
to_vk_descriptor_type :: proc(t: bk.Descriptor_Type) -> vk.DescriptorType {
switch t {
case .Combined_Image_Sampler:
return .COMBINED_IMAGE_SAMPLER
case .Uniform_Buffer:
return .UNIFORM_BUFFER
case .Storage_Buffer:
return .STORAGE_BUFFER
}
return .COMBINED_IMAGE_SAMPLER
}
// --- Vertex format conversion ---
@(private)
to_vk_vertex_format :: proc(fmt: bk.Vertex_Format) -> vk.Format {
switch fmt {
case .Float2:
return .R32G32_SFLOAT
case .Float3:
return .R32G32B32_SFLOAT
case .Float4:
return .R32G32B32A32_SFLOAT
}
return .UNDEFINED
}
// --- Helpers ---
@(private)
format_pixel_size :: proc(fmt: bk.Format) -> u32 {
switch fmt {
case .R8G8B8A8_SRGB, .R8G8B8A8_UNORM, .B8G8R8A8_SRGB:
return 4
case .D32_SFLOAT:
return 4
case .D32_SFLOAT_S8_UINT:
return 8
case .D24_UNORM_S8_UINT:
return 4
case .Undefined:
return 0
}
return 0
}