celestialsim/gpu/
device.rs1use std::sync::Arc;
8
9use godot::classes::rendering_device::{
10 DataFormat, ShaderLanguage, ShaderStage, TextureUsageBits, UniformType,
11};
12use godot::classes::{
13 RdShaderSource, RdShaderSpirv, RdTextureFormat, RdTextureView, RdUniform, RenderingDevice,
14};
15use godot::prelude::*;
16
17use super::owned::{Owned, RdBuffer, RdPipeline, RdShader, RdTexture, RidSink};
18
19pub fn compute_pipeline(
24 rd: &mut Gd<RenderingDevice>,
25 sink: &Arc<dyn RidSink>,
26 spirv: &[u8],
27 name: &str,
28) -> Option<(RdShader, RdPipeline)> {
29 if spirv.is_empty() {
30 godot_error!("[celestial] {name}: empty SPIR-V — was slangc installed at build time?");
31 return None;
32 }
33 let mut sp = RdShaderSpirv::new_gd();
34 sp.set_stage_bytecode(ShaderStage::COMPUTE, &PackedByteArray::from(spirv));
35 let shader_rid = rd.shader_create_from_spirv(&sp);
36 if !shader_rid.is_valid() {
37 godot_error!("[celestial] {name}: shader_create_from_spirv failed");
38 return None;
39 }
40 let shader: RdShader = Owned::new(shader_rid, sink.clone());
41 let pipeline_rid = rd.compute_pipeline_create(shader.rid());
42 if !pipeline_rid.is_valid() {
43 godot_error!("[celestial] {name}: compute_pipeline_create failed");
44 return None; }
46 Some((shader, Owned::new(pipeline_rid, sink.clone())))
47}
48
49pub fn compute_pipeline_from_glsl(
55 rd: &mut Gd<RenderingDevice>,
56 sink: &Arc<dyn RidSink>,
57 glsl: &str,
58 name: &str,
59) -> Option<(RdShader, RdPipeline)> {
60 let mut src = RdShaderSource::new_gd();
61 src.set_language(ShaderLanguage::GLSL);
62 src.set_stage_source(ShaderStage::COMPUTE, glsl);
63 let Some(spirv) = rd.shader_compile_spirv_from_source_ex(&src).allow_cache(true).done() else {
64 godot_error!("[celestial] {name}: shader_compile_spirv_from_source returned null");
65 return None;
66 };
67 let err = spirv.get_stage_compile_error(ShaderStage::COMPUTE);
68 if !err.is_empty() {
69 godot_error!("[celestial] {name}: GLSL compile error:\n{err}");
70 return None;
71 }
72 let shader_rid = rd.shader_create_from_spirv(&spirv);
73 if !shader_rid.is_valid() {
74 godot_error!("[celestial] {name}: shader_create_from_spirv failed");
75 return None;
76 }
77 let shader: RdShader = Owned::new(shader_rid, sink.clone());
78 let pipeline_rid = rd.compute_pipeline_create(shader.rid());
79 if !pipeline_rid.is_valid() {
80 godot_error!("[celestial] {name}: compute_pipeline_create failed");
81 return None; }
83 Some((shader, Owned::new(pipeline_rid, sink.clone())))
84}
85
86pub fn storage_buffer_empty(
88 rd: &mut Gd<RenderingDevice>,
89 sink: &Arc<dyn RidSink>,
90 size: u64,
91) -> RdBuffer {
92 Owned::new(rd.storage_buffer_create_ex(size as u32).done(), sink.clone())
93}
94
95pub fn storage_buffer(
97 rd: &mut Gd<RenderingDevice>,
98 sink: &Arc<dyn RidSink>,
99 bytes: &[u8],
100) -> RdBuffer {
101 let rid = rd
102 .storage_buffer_create_ex(bytes.len() as u32)
103 .data(&PackedByteArray::from(bytes))
104 .done();
105 Owned::new(rid, sink.clone())
106}
107
108pub fn attribute_texture(
110 rd: &mut Gd<RenderingDevice>,
111 sink: &Arc<dyn RidSink>,
112 width: u32,
113 height: u32,
114) -> RdTexture {
115 let mut fmt = RdTextureFormat::new_gd();
116 fmt.set_format(DataFormat::R16G16B16A16_SFLOAT);
117 fmt.set_width(width);
118 fmt.set_height(height);
119 fmt.set_usage_bits(
120 TextureUsageBits::STORAGE_BIT | TextureUsageBits::SAMPLING_BIT,
121 );
122 Owned::new(rd.texture_create(&fmt, &RdTextureView::new_gd()), sink.clone())
123}
124
125pub fn position_texture(
129 rd: &mut Gd<RenderingDevice>,
130 sink: &Arc<dyn RidSink>,
131 width: u32,
132 height: u32,
133) -> RdTexture {
134 let mut fmt = RdTextureFormat::new_gd();
135 fmt.set_format(DataFormat::R32G32B32A32_SFLOAT);
136 fmt.set_width(width);
137 fmt.set_height(height);
138 fmt.set_usage_bits(
140 TextureUsageBits::STORAGE_BIT
141 | TextureUsageBits::SAMPLING_BIT
142 | TextureUsageBits::CAN_COPY_FROM_BIT,
143 );
144 Owned::new(rd.texture_create(&fmt, &RdTextureView::new_gd()), sink.clone())
145}
146
147pub fn atlas_texture(
152 rd: &mut Gd<RenderingDevice>,
153 sink: &Arc<dyn RidSink>,
154 width: u32,
155 height: u32,
156) -> RdTexture {
157 let mut fmt = RdTextureFormat::new_gd();
158 fmt.set_format(DataFormat::R8G8B8A8_UNORM);
159 fmt.set_width(width);
160 fmt.set_height(height);
161 fmt.set_usage_bits(
163 TextureUsageBits::STORAGE_BIT
164 | TextureUsageBits::SAMPLING_BIT
165 | TextureUsageBits::CAN_COPY_FROM_BIT,
166 );
167 Owned::new(rd.texture_create(&fmt, &RdTextureView::new_gd()), sink.clone())
168}
169
170pub fn uniform(utype: UniformType, binding: i32, rid: Rid) -> Gd<RdUniform> {
171 let mut u = RdUniform::new_gd();
172 u.set_uniform_type(utype);
173 u.set_binding(binding);
174 u.add_id(rid);
175 u
176}