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
package shaderkit
import "core:log"
import "core:os"
import gpu ".."
import shader "../shader"
Options :: struct {
entry: string,
opt_level: shader.Opt_Level,
debug: bool,
include_dirs: []string,
file_reader: shader.File_Reader,
}
compile_target :: proc() -> shader.Target {
when gpu.REQUIRED_SHADER_FORMAT == .SPIRV {
return .SPIR_V
} else when gpu.REQUIRED_SHADER_FORMAT == .HLSL {
return .HLSL_SM6
} else when gpu.REQUIRED_SHADER_FORMAT == .GLSL {
return .GLSL_450_OPENGL
} else {
#assert(false, "unsupported REQUIRED_SHADER_FORMAT")
}
}
compile_options :: proc(stage: gpu.Shader_Stage, options: Options) -> shader.Compile_Options {
return {
target = compile_target(),
opt_level = options.opt_level,
stage = shader_stage(stage),
entry = options.entry,
debug = options.debug,
include_dirs = options.include_dirs,
file_reader = options.file_reader,
hlsl_cbuffer_push_constants = true,
hlsl_push_constant_slot = 13,
hlsl_omit_register_spaces = true,
}
}
compile_shader_source :: proc(name: string, stage: gpu.Shader_Stage, source: string, options: Options = {}, allocator := context.allocator) -> shader.Compile_Result {
return shader.compile(source, compile_options(stage, options), name, allocator)
}
create_shader_from_source :: proc(name: string, stage: gpu.Shader_Stage, source: string, options: Options = {}) -> (gpu.Shader_Handle, bool) {
result := compile_shader_source(name, stage, source, options)
defer shader.destroy_compile_result(&result)
if !result.success {
log_compile_diagnostics(name, source, result.diagnostics)
return {}, false
}
entry := options.entry
if entry == "" do entry = "main"
handle, ok := gpu.create_shader_module({
stage = stage,
format = gpu.REQUIRED_SHADER_FORMAT,
name = name,
entry = entry,
data = result.output,
})
if !ok {
log.errorf("gpu/shaderkit: failed to create shader module %s", name)
return {}, false
}
return handle, true
}
create_shader_from_file :: proc(path: string, stage: gpu.Shader_Stage, options: Options = {}) -> (gpu.Shader_Handle, bool) {
source, err := os.read_entire_file(path, context.allocator)
if err != nil {
log.errorf("gpu/shaderkit: failed to read shader source %s", path)
return {}, false
}
defer delete(source)
return create_shader_from_source(path, stage, string(source), options)
}
load_compute_shader_from_source :: proc(name: string, source: string, num_buffers: u32 = 4, push_constant_size: u32 = 0, options: Options = {}) -> gpu.Compute_Shader {
result := compile_shader_source(name, .Compute, source, options)
defer shader.destroy_compile_result(&result)
if !result.success {
log_compile_diagnostics(name, source, result.diagnostics)
return {}
}
return gpu.load_compute_shader_from_bytes(
name,
result.output,
gpu.REQUIRED_SHADER_FORMAT,
num_buffers,
push_constant_size,
)
}
log_compile_diagnostics :: proc(name, source: string, diagnostics: []shader.Diagnostic) {
for d in diagnostics {
msg := shader.format_diagnostic_with_source(d, source)
log.errorf("gpu/shaderkit: %s: %s", name, msg)
delete(msg)
}
}
shader_stage :: proc(stage: gpu.Shader_Stage) -> shader.Shader_Stage {
switch stage {
case .Vertex: return .Vertex
case .Fragment: return .Fragment
case .Compute: return .Compute
}
return .None
}