1use crate::ontology::*;
9use crate::types::*;
10use std::sync::atomic::{AtomicU64, Ordering};
11
12static NEXT_RESOURCE_ID: AtomicU64 = AtomicU64::new(1);
14
15fn next_id() -> u64 {
16 NEXT_RESOURCE_ID.fetch_add(1, Ordering::Relaxed)
17}
18
19pub struct GpuBuffer {
23 inner: wgpu::Buffer,
24 id: u64,
25 label: Option<String>,
26 size: u64,
27 usage: BufferUsages,
28}
29
30impl GpuBuffer {
31 pub(crate) fn from_raw(inner: wgpu::Buffer, desc: &GpuBufferDescriptor) -> Self {
32 Self {
33 inner,
34 id: next_id(),
35 label: desc.label.clone(),
36 size: desc.size,
37 usage: desc.usage,
38 }
39 }
40
41 pub fn id(&self) -> u64 {
43 self.id
44 }
45 pub fn label(&self) -> Option<&str> {
47 self.label.as_deref()
48 }
49 pub fn size(&self) -> u64 {
51 self.size
52 }
53 pub fn usage(&self) -> BufferUsages {
55 self.usage
56 }
57 pub fn raw(&self) -> &wgpu::Buffer {
59 &self.inner
60 }
61
62 pub fn slice(
64 &self,
65 bounds: impl std::ops::RangeBounds<BufferAddress>,
66 ) -> wgpu::BufferSlice<'_> {
67 self.inner.slice(bounds)
68 }
69
70 pub fn as_entire_binding(&self) -> wgpu::BindingResource<'_> {
72 self.inner.as_entire_binding()
73 }
74}
75
76pub struct GpuTexture {
80 inner: wgpu::Texture,
81 id: u64,
82 label: Option<String>,
83 size: Extent3d,
84 format: TextureFormat,
85 dimension: TextureDimension,
86 mip_level_count: u32,
87 sample_count: u32,
88 usage: TextureUsages,
89}
90
91impl GpuTexture {
92 pub(crate) fn from_raw(inner: wgpu::Texture, desc: &GpuTextureDescriptor) -> Self {
93 Self {
94 inner,
95 id: next_id(),
96 label: desc.label.clone(),
97 size: desc.size,
98 format: desc.format,
99 dimension: desc.dimension,
100 mip_level_count: desc.mip_level_count,
101 sample_count: desc.sample_count,
102 usage: desc.usage,
103 }
104 }
105
106 pub fn id(&self) -> u64 {
107 self.id
108 }
109 pub fn label(&self) -> Option<&str> {
110 self.label.as_deref()
111 }
112 pub fn size(&self) -> Extent3d {
113 self.size
114 }
115 pub fn format(&self) -> TextureFormat {
116 self.format
117 }
118 pub fn dimension(&self) -> TextureDimension {
119 self.dimension
120 }
121 pub fn mip_level_count(&self) -> u32 {
122 self.mip_level_count
123 }
124 pub fn sample_count(&self) -> u32 {
125 self.sample_count
126 }
127 pub fn usage(&self) -> TextureUsages {
128 self.usage
129 }
130 pub fn raw(&self) -> &wgpu::Texture {
131 &self.inner
132 }
133
134 pub fn create_view_default(&self) -> GpuTextureView {
136 let view = self
137 .inner
138 .create_view(&wgpu::TextureViewDescriptor::default());
139 GpuTextureView {
140 inner: view,
141 id: next_id(),
142 label: self.label.clone().map(|l| format!("{l}_view")),
143 format: self.format,
144 }
145 }
146
147 pub fn create_view(&self, desc: &wgpu::TextureViewDescriptor<'_>) -> GpuTextureView {
149 let view = self.inner.create_view(desc);
150 GpuTextureView {
151 inner: view,
152 id: next_id(),
153 label: desc.label.map(String::from),
154 format: desc.format.unwrap_or(self.format),
155 }
156 }
157}
158
159impl Discoverable for GpuTexture {
160 fn schema(&self) -> WidgetSchema {
161 let mut s = WidgetSchema::new(
162 "GpuTexture",
163 "GPU texture — image data stored on the GPU for sampling or rendering",
164 SemanticRole::System,
165 );
166 s.tags = vec!["gpu".into(), "texture".into(), "image".into()];
167 s
168 }
169
170 fn capabilities(&self) -> Vec<AgentCapability> {
171 vec![AgentCapability::Custom("gpu_texture".into())]
172 }
173
174 fn actions(&self) -> Vec<AgentAction> {
175 vec![AgentAction::simple(
176 "get_info",
177 "Query texture dimensions, format, and usage",
178 false,
179 )]
180 }
181
182 fn semantic_role(&self) -> SemanticRole {
183 SemanticRole::System
184 }
185
186 fn agent_state(&self) -> serde_json::Value {
187 serde_json::json!({
188 "id": self.id,
189 "label": self.label,
190 "width": self.size.width,
191 "height": self.size.height,
192 "depth_or_layers": self.size.depth_or_array_layers,
193 "format": format!("{:?}", self.format),
194 "dimension": format!("{:?}", self.dimension),
195 "mip_levels": self.mip_level_count,
196 "sample_count": self.sample_count,
197 "usage": format!("{:?}", self.usage),
198 })
199 }
200
201 fn execute_action(
202 &mut self,
203 action: &str,
204 _params: &serde_json::Value,
205 ) -> Result<serde_json::Value, String> {
206 match action {
207 "get_info" => Ok(self.agent_state()),
208 _ => Err(format!("Unknown action: {action}")),
209 }
210 }
211
212 fn agent_id(&self) -> Option<&str> {
213 None
214 }
215}
216
217pub struct GpuTextureView {
221 inner: wgpu::TextureView,
222 id: u64,
223 label: Option<String>,
224 format: TextureFormat,
225}
226
227impl GpuTextureView {
228 pub(crate) fn from_surface(inner: wgpu::TextureView, format: TextureFormat) -> Self {
229 Self {
230 inner,
231 id: next_id(),
232 label: Some("surface_view".into()),
233 format,
234 }
235 }
236
237 pub fn id(&self) -> u64 {
238 self.id
239 }
240 pub fn label(&self) -> Option<&str> {
241 self.label.as_deref()
242 }
243 pub fn format(&self) -> TextureFormat {
244 self.format
245 }
246 pub fn raw(&self) -> &wgpu::TextureView {
247 &self.inner
248 }
249}
250
251pub struct GpuSampler {
255 inner: wgpu::Sampler,
256 id: u64,
257 label: Option<String>,
258}
259
260impl GpuSampler {
261 pub(crate) fn from_raw(inner: wgpu::Sampler, label: Option<String>) -> Self {
262 Self {
263 inner,
264 id: next_id(),
265 label,
266 }
267 }
268
269 pub fn id(&self) -> u64 {
270 self.id
271 }
272 pub fn label(&self) -> Option<&str> {
273 self.label.as_deref()
274 }
275 pub fn raw(&self) -> &wgpu::Sampler {
276 &self.inner
277 }
278}
279
280pub struct GpuShaderModule {
284 inner: wgpu::ShaderModule,
285 id: u64,
286 label: Option<String>,
287 source_kind: ShaderSourceKind,
288}
289
290#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
292pub enum ShaderSourceKind {
293 Wgsl,
294 SpirV,
295 Naga,
296}
297
298impl GpuShaderModule {
299 pub(crate) fn from_raw(
300 inner: wgpu::ShaderModule,
301 label: Option<String>,
302 source_kind: ShaderSourceKind,
303 ) -> Self {
304 Self {
305 inner,
306 id: next_id(),
307 label,
308 source_kind,
309 }
310 }
311
312 pub fn id(&self) -> u64 {
313 self.id
314 }
315 pub fn label(&self) -> Option<&str> {
316 self.label.as_deref()
317 }
318 pub fn source_kind(&self) -> ShaderSourceKind {
319 self.source_kind
320 }
321 pub fn raw(&self) -> &wgpu::ShaderModule {
322 &self.inner
323 }
324}
325
326pub struct GpuBindGroupLayout {
330 inner: wgpu::BindGroupLayout,
331 id: u64,
332 label: Option<String>,
333}
334
335impl GpuBindGroupLayout {
336 pub(crate) fn from_raw(inner: wgpu::BindGroupLayout, label: Option<String>) -> Self {
337 Self {
338 inner,
339 id: next_id(),
340 label,
341 }
342 }
343
344 pub fn id(&self) -> u64 {
345 self.id
346 }
347 pub fn label(&self) -> Option<&str> {
348 self.label.as_deref()
349 }
350 pub fn raw(&self) -> &wgpu::BindGroupLayout {
351 &self.inner
352 }
353}
354
355pub struct GpuBindGroup {
359 inner: wgpu::BindGroup,
360 id: u64,
361 label: Option<String>,
362}
363
364impl GpuBindGroup {
365 pub(crate) fn from_raw(inner: wgpu::BindGroup, label: Option<String>) -> Self {
366 Self {
367 inner,
368 id: next_id(),
369 label,
370 }
371 }
372
373 pub fn id(&self) -> u64 {
374 self.id
375 }
376 pub fn label(&self) -> Option<&str> {
377 self.label.as_deref()
378 }
379 pub fn raw(&self) -> &wgpu::BindGroup {
380 &self.inner
381 }
382}
383
384pub struct GpuPipelineLayout {
388 inner: wgpu::PipelineLayout,
389 id: u64,
390 label: Option<String>,
391}
392
393impl GpuPipelineLayout {
394 pub(crate) fn from_raw(inner: wgpu::PipelineLayout, label: Option<String>) -> Self {
395 Self {
396 inner,
397 id: next_id(),
398 label,
399 }
400 }
401
402 pub fn id(&self) -> u64 {
403 self.id
404 }
405 pub fn label(&self) -> Option<&str> {
406 self.label.as_deref()
407 }
408 pub fn raw(&self) -> &wgpu::PipelineLayout {
409 &self.inner
410 }
411}
412
413pub struct GpuRenderPipeline {
418 inner: wgpu::RenderPipeline,
419 id: u64,
420 label: Option<String>,
421}
422
423impl GpuRenderPipeline {
424 pub(crate) fn from_raw(inner: wgpu::RenderPipeline, label: Option<String>) -> Self {
425 Self {
426 inner,
427 id: next_id(),
428 label,
429 }
430 }
431
432 pub fn id(&self) -> u64 {
433 self.id
434 }
435 pub fn label(&self) -> Option<&str> {
436 self.label.as_deref()
437 }
438 pub fn raw(&self) -> &wgpu::RenderPipeline {
439 &self.inner
440 }
441}
442
443impl Discoverable for GpuRenderPipeline {
444 fn schema(&self) -> WidgetSchema {
445 let mut s = WidgetSchema::new(
446 "GpuRenderPipeline",
447 "GPU render pipeline — compiled vertex/fragment shader program",
448 SemanticRole::System,
449 );
450 s.tags = vec![
451 "gpu".into(),
452 "pipeline".into(),
453 "render".into(),
454 "shader".into(),
455 ];
456 s
457 }
458
459 fn capabilities(&self) -> Vec<AgentCapability> {
460 vec![AgentCapability::Custom("gpu_render_pipeline".into())]
461 }
462
463 fn actions(&self) -> Vec<AgentAction> {
464 vec![AgentAction::simple(
465 "get_info",
466 "Query pipeline metadata",
467 false,
468 )]
469 }
470
471 fn semantic_role(&self) -> SemanticRole {
472 SemanticRole::System
473 }
474
475 fn agent_state(&self) -> serde_json::Value {
476 serde_json::json!({
477 "id": self.id,
478 "label": self.label,
479 "kind": "RenderPipeline",
480 })
481 }
482
483 fn execute_action(
484 &mut self,
485 action: &str,
486 _params: &serde_json::Value,
487 ) -> Result<serde_json::Value, String> {
488 match action {
489 "get_info" => Ok(self.agent_state()),
490 _ => Err(format!("Unknown action: {action}")),
491 }
492 }
493
494 fn agent_id(&self) -> Option<&str> {
495 None
496 }
497}
498
499pub struct GpuComputePipeline {
503 inner: wgpu::ComputePipeline,
504 id: u64,
505 label: Option<String>,
506}
507
508impl GpuComputePipeline {
509 pub(crate) fn from_raw(inner: wgpu::ComputePipeline, label: Option<String>) -> Self {
510 Self {
511 inner,
512 id: next_id(),
513 label,
514 }
515 }
516
517 pub fn id(&self) -> u64 {
518 self.id
519 }
520 pub fn label(&self) -> Option<&str> {
521 self.label.as_deref()
522 }
523 pub fn raw(&self) -> &wgpu::ComputePipeline {
524 &self.inner
525 }
526}
527
528impl Discoverable for GpuComputePipeline {
529 fn schema(&self) -> WidgetSchema {
530 let mut s = WidgetSchema::new(
531 "GpuComputePipeline",
532 "GPU compute pipeline — compiled compute shader program for GPGPU workloads",
533 SemanticRole::System,
534 );
535 s.tags = vec![
536 "gpu".into(),
537 "pipeline".into(),
538 "compute".into(),
539 "shader".into(),
540 ];
541 s
542 }
543
544 fn capabilities(&self) -> Vec<AgentCapability> {
545 vec![AgentCapability::Custom("gpu_compute_pipeline".into())]
546 }
547
548 fn actions(&self) -> Vec<AgentAction> {
549 vec![AgentAction::simple(
550 "get_info",
551 "Query compute pipeline metadata",
552 false,
553 )]
554 }
555
556 fn semantic_role(&self) -> SemanticRole {
557 SemanticRole::System
558 }
559
560 fn agent_state(&self) -> serde_json::Value {
561 serde_json::json!({
562 "id": self.id,
563 "label": self.label,
564 "kind": "ComputePipeline",
565 })
566 }
567
568 fn execute_action(
569 &mut self,
570 action: &str,
571 _params: &serde_json::Value,
572 ) -> Result<serde_json::Value, String> {
573 match action {
574 "get_info" => Ok(self.agent_state()),
575 _ => Err(format!("Unknown action: {action}")),
576 }
577 }
578
579 fn agent_id(&self) -> Option<&str> {
580 None
581 }
582}
583
584pub struct GpuQuerySet {
588 inner: wgpu::QuerySet,
589 id: u64,
590 label: Option<String>,
591 count: u32,
592}
593
594impl GpuQuerySet {
595 pub(crate) fn from_raw(inner: wgpu::QuerySet, label: Option<String>, count: u32) -> Self {
596 Self {
597 inner,
598 id: next_id(),
599 label,
600 count,
601 }
602 }
603
604 pub fn id(&self) -> u64 {
605 self.id
606 }
607 pub fn label(&self) -> Option<&str> {
608 self.label.as_deref()
609 }
610 pub fn count(&self) -> u32 {
611 self.count
612 }
613 pub fn raw(&self) -> &wgpu::QuerySet {
614 &self.inner
615 }
616}