1use super::ResourceSlot;
4
5#[derive(Debug, PartialEq, Eq)]
6pub enum VmError {
7 MissingMainFunction,
8 UnsupportedRawCode,
9 UnsupportedMainSignature {
10 message: String,
11 },
12 UnsupportedType {
13 type_name: String,
14 },
15 UnsupportedStatement {
16 message: String,
17 },
18 UnsupportedAssignmentTarget {
19 message: String,
20 },
21 UnsupportedExpression {
22 message: String,
23 },
24 UnsupportedBufferLayout {
25 message: String,
26 },
27 UnsupportedDescriptor {
28 slot: ResourceSlot,
29 message: String,
30 },
31 DescriptorAccessDenied {
32 slot: ResourceSlot,
33 access: &'static str,
34 },
35 DescriptorTypeMismatch {
36 slot: ResourceSlot,
37 expected: &'static str,
38 found: &'static str,
39 },
40 UnknownBufferMember {
41 member: String,
42 },
43 UnboundDescriptor {
44 slot: ResourceSlot,
45 },
46 MissingPushConstant,
47 MissingMeshOutputs,
48 MissingTaskOutputs,
49 MissingWorkgroupState,
50 UninitializedWorkgroupValue {
51 name: String,
52 },
53 MissingTaskPayload {
54 name: String,
55 },
56 TaskPayloadIndexOutOfBounds {
57 name: String,
58 index: usize,
59 count: usize,
60 },
61 TaskPayloadOutputIndexOutOfBounds {
62 name: String,
63 index: usize,
64 count: usize,
65 },
66 MeshOutputIndexOutOfBounds {
67 kind: &'static str,
68 index: usize,
69 count: usize,
70 },
71 MeshOutputCountLimitExceeded {
72 kind: &'static str,
73 requested: u32,
74 limit: u32,
75 },
76 TaskMeshOutputCountLimitExceeded {
77 requested: u32,
78 limit: u32,
79 },
80 DivergentWorkgroupBarrier {
81 lane: usize,
82 expected_instruction: usize,
83 found_instruction: Option<usize>,
84 },
85 MissingSpecialization {
86 name: String,
87 },
88 InstructionLimitExceeded {
89 limit: usize,
90 },
91 CallDepthLimitExceeded {
92 limit: usize,
93 },
94 CallArgumentMismatch {
95 expected: usize,
96 found: usize,
97 },
98 BufferAccessOutOfBounds {
99 offset: usize,
100 size: usize,
101 buffer_size: usize,
102 },
103 BufferArrayIndexOutOfBounds {
104 index: usize,
105 count: usize,
106 },
107 TextureAccessOutOfBounds {
108 x: u32,
109 y: u32,
110 z: u32,
111 width: u32,
112 height: u32,
113 depth: u32,
114 },
115 InvalidTextureDimensions {
116 width: u32,
117 height: u32,
118 depth: u32,
119 },
120 TextureTexelCountOverflow {
121 width: u32,
122 height: u32,
123 depth: u32,
124 },
125 TextureFormatMismatch {
126 expected: &'static str,
127 found: &'static str,
128 },
129 InvalidLiteral {
130 value: String,
131 value_type: String,
132 },
133 ArithmeticError {
134 message: String,
135 },
136 TypeMismatch {
137 expected: String,
138 found: String,
139 },
140 UninitializedRegister {
141 register: usize,
142 },
143 UninitializedLocal {
144 local: usize,
145 },
146}
147
148impl std::fmt::Display for VmError {
149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150 match self {
151 VmError::MissingMainFunction => {
152 write!(
153 f,
154 "Missing main function. The most likely cause is that the lexed BESL program does not define `main`."
155 )
156 }
157 VmError::UnsupportedRawCode => write!(
158 f,
159 "Raw code blocks are not supported. The most likely cause is that a reachable BESL function contains non-empty platform shader code with no portable VM semantics."
160 ),
161 VmError::UnsupportedMainSignature { message } => write!(
162 f,
163 "Unsupported main signature: {}. The most likely cause is that the VM only accepts `main: fn () -> void` right now.",
164 message
165 ),
166 VmError::UnsupportedType { type_name } => write!(
167 f,
168 "Unsupported type `{}`. The most likely cause is that the BESL type has no portable VM value or resource representation.",
169 type_name
170 ),
171 VmError::UnsupportedStatement { message } => write!(
172 f,
173 "Unsupported statement. {}. The most likely cause is that this statement form has not been lowered into VM control-flow or side-effect instructions.",
174 message
175 ),
176 VmError::UnsupportedAssignmentTarget { message } => write!(
177 f,
178 "Unsupported assignment target. {}. The most likely cause is that the target is not a writable local, buffer member, output, or image operation.",
179 message
180 ),
181 VmError::UnsupportedExpression { message } => write!(
182 f,
183 "Unsupported expression. {}. The most likely cause is that this BESL syntax or operand-type combination has no VM lowering yet.",
184 message
185 ),
186 VmError::UnsupportedBufferLayout { message } => write!(
187 f,
188 "Unsupported buffer layout. {}. The most likely cause is that a member cannot be represented in the VM's packed CPU buffer layout.",
189 message
190 ),
191 VmError::UnsupportedDescriptor { slot, message } => write!(
192 f,
193 "Unsupported resource at slot {}. {}. The most likely cause is a resource-kind mismatch, incompatible reused slot, or unsupported resource access.",
194 slot.slot(),
195 message
196 ),
197 VmError::DescriptorAccessDenied { slot, access } => write!(
198 f,
199 "Resource access denied at slot {}. The most likely cause is that the BESL resource was not declared with `{}` access.",
200 slot.slot(),
201 access
202 ),
203 VmError::DescriptorTypeMismatch { slot, expected, found } => write!(
204 f,
205 "Resource type mismatch at slot {}: expected `{}` but found `{}`. The most likely cause is that the host bound a different resource kind than the compiled BESL program requires.",
206 slot.slot(),
207 expected,
208 found
209 ),
210 VmError::UnknownBufferMember { member } => write!(
211 f,
212 "Unknown buffer member `{}`. The most likely cause is that the BESL accessor does not match the bound buffer layout.",
213 member
214 ),
215 VmError::UnboundDescriptor { slot } => write!(
216 f,
217 "Unbound resource at slot {}. The most likely cause is that no resource was bound into the slot before execution.",
218 slot.slot()
219 ),
220 VmError::MissingPushConstant => write!(
221 f,
222 "Missing push constant binding. The most likely cause is that the BESL program reads `push_constant` but the host did not bind any push constant data before execution."
223 ),
224 VmError::MissingMeshOutputs => write!(
225 f,
226 "Missing mesh output capture. The most likely cause is that the BESL mesh shader ran without binding `MeshOutputs`."
227 ),
228 VmError::MissingTaskOutputs => write!(
229 f,
230 "Missing task output capture. The most likely cause is that the BESL task shader ran without binding `TaskOutputs`."
231 ),
232 VmError::MissingWorkgroupState => write!(
233 f,
234 "Missing workgroup state. The most likely cause is that a BESL task shader accessed workgroup storage without binding `WorkgroupState`."
235 ),
236 VmError::UninitializedWorkgroupValue { name } => write!(
237 f,
238 "Uninitialized workgroup value `{name}`. The most likely cause is that the BESL shader loaded workgroup storage before one invocation initialized it."
239 ),
240 VmError::MissingTaskPayload { name } => write!(
241 f,
242 "Missing task payload `{name}`. The most likely cause is that the BESL mesh shader read a task-payload array that the host did not bind before execution."
243 ),
244 VmError::TaskPayloadIndexOutOfBounds { name, index, count } => write!(
245 f,
246 "Task payload `{name}` index {index} exceeds {count} bound elements. The most likely cause is that the host supplied fewer task-payload values than the mesh shader reads."
247 ),
248 VmError::TaskPayloadOutputIndexOutOfBounds { name, index, count } => write!(
249 f,
250 "Task payload output `{name}` index {index} exceeds {count} declared elements. The most likely cause is that the task shader wrote beyond its payload declaration."
251 ),
252 VmError::MeshOutputIndexOutOfBounds { kind, index, count } => write!(
253 f,
254 "Mesh {kind} output index {index} exceeds {count} declared outputs. The most likely cause is that the shader wrote beyond the counts supplied to `set_mesh_output_counts`."
255 ),
256 VmError::MeshOutputCountLimitExceeded {
257 kind,
258 requested,
259 limit,
260 } => write!(
261 f,
262 "Mesh {kind} output count {requested} exceeds the configured limit of {limit}. The most likely cause is that the shader requested more mesh output storage than the host allows."
263 ),
264 VmError::TaskMeshOutputCountLimitExceeded { requested, limit } => write!(
265 f,
266 "Task mesh output count {requested} exceeds the configured limit of {limit}. The most likely cause is that the shader requested more mesh workgroups than the host allows."
267 ),
268 VmError::DivergentWorkgroupBarrier {
269 lane,
270 expected_instruction,
271 found_instruction,
272 } => match found_instruction {
273 Some(found_instruction) => write!(
274 f,
275 "Divergent workgroup barrier in lane {lane}: expected instruction {expected_instruction} but found {found_instruction}. The most likely cause is that task invocations reached different barriers in the same synchronization phase."
276 ),
277 None => write!(
278 f,
279 "Divergent workgroup barrier in lane {lane}: expected instruction {expected_instruction} but the lane completed. The most likely cause is that task control flow skipped a barrier reached by peer invocations."
280 ),
281 },
282 VmError::MissingSpecialization { name } => write!(
283 f,
284 "Missing specialization `{}`. The most likely cause is that the host did not provide a value for a specialization used by the BESL program.",
285 name
286 ),
287 VmError::InstructionLimitExceeded { limit } => write!(
288 f,
289 "VM instruction limit {} exceeded. The most likely cause is that the BESL program contains an unbounded loop or needs a larger explicit execution budget.",
290 limit
291 ),
292 VmError::CallDepthLimitExceeded { limit } => write!(
293 f,
294 "VM call-depth limit {} exceeded. The most likely cause is that the BESL program recurses without reaching a base case.",
295 limit
296 ),
297 VmError::CallArgumentMismatch { expected, found } => write!(
298 f,
299 "Function call argument mismatch: expected {} arguments but found {}. The most likely cause is that the BESL function call does not match the declared parameter list.",
300 expected, found
301 ),
302 VmError::BufferAccessOutOfBounds {
303 offset,
304 size,
305 buffer_size,
306 } => write!(
307 f,
308 "Buffer access out of bounds at byte {} for {} bytes in a {} byte buffer. The most likely cause is that the bound buffer does not match the compiled BESL buffer layout.",
309 offset, size, buffer_size
310 ),
311 VmError::BufferArrayIndexOutOfBounds { index, count } => write!(
312 f,
313 "Buffer array index {} is out of bounds for {} elements. The most likely cause is that the BESL program indexed a buffer array member outside its declared length.",
314 index, count
315 ),
316 VmError::TextureAccessOutOfBounds {
317 x,
318 y,
319 z,
320 width,
321 height,
322 depth,
323 } => write!(
324 f,
325 "Texture access out of bounds at ({}, {}, {}) in a {}x{}x{} texture. The most likely cause is that the BESL program fetched a texel outside the bound texture dimensions.",
326 x, y, z, width, height, depth
327 ),
328 VmError::InvalidTextureDimensions { width, height, depth } => write!(
329 f,
330 "Invalid texture dimensions {}x{}x{}. The most likely cause is that the host created a texture with a zero dimension.",
331 width, height, depth
332 ),
333 VmError::TextureTexelCountOverflow { width, height, depth } => write!(
334 f,
335 "Texture dimensions {}x{}x{} are too large. The most likely cause is that their texel count exceeds addressable CPU memory.",
336 width, height, depth
337 ),
338 VmError::TextureFormatMismatch { expected, found } => write!(
339 f,
340 "Texture format mismatch: expected `{}` but found `{}`. The most likely cause is that the same CPU texture was used for incompatible float and integer shader operations.",
341 expected, found
342 ),
343 VmError::InvalidLiteral { value, value_type } => write!(
344 f,
345 "Invalid literal `{}` for `{}`. The most likely cause is that the literal cannot be parsed as the target BESL scalar type.",
346 value, value_type
347 ),
348 VmError::ArithmeticError { message } => write!(
349 f,
350 "Invalid arithmetic operation. {}. The most likely cause is that the BESL program evaluated an unsupported numeric operation such as division or modulo by zero.",
351 message
352 ),
353 VmError::TypeMismatch { expected, found } => write!(
354 f,
355 "Type mismatch: expected `{}` but found `{}`. The most likely cause is that the BESL assignment mixes incompatible scalar types.",
356 expected, found
357 ),
358 VmError::UninitializedRegister { register } => write!(
359 f,
360 "Uninitialized register {}. The most likely cause is that the VM tried to use a register before any instruction wrote a value into it.",
361 register
362 ),
363 VmError::UninitializedLocal { local } => write!(
364 f,
365 "Uninitialized local {}. The most likely cause is that the BESL program read a local variable before assigning a value to it.",
366 local
367 ),
368 }
369 }
370}
371
372impl std::error::Error for VmError {}