1use super::*;
4
5impl QTensorEngine {
6 pub(crate) fn elem_gpu_pipeline(&self, op: u32) -> Option<&wgpu::ComputePipeline> {
8 use super::gpu_params::{ELEM_OP_ADD_RESIDUAL, ELEM_OP_RMS_NORM};
9 match op {
10 ELEM_OP_RMS_NORM => Some(&self.elem_rms_norm_pipeline),
11 ELEM_OP_ADD_RESIDUAL => Some(&self.elem_add_residual_pipeline),
12 _ => None,
13 }
14 }
15 pub(crate) fn gpu_device(&self) -> &wgpu::Device {
16 #[cfg(target_arch = "wasm32")]
17 {
18 return &self.device;
19 }
20 #[cfg(not(target_arch = "wasm32"))]
21 {
22 &crate::gpu_context::shared_gpu().device
23 }
24 }
25
26 #[inline]
27 pub(crate) fn gpu_queue(&self) -> &wgpu::Queue {
28 #[cfg(target_arch = "wasm32")]
29 {
30 return &self.queue;
31 }
32 #[cfg(not(target_arch = "wasm32"))]
33 {
34 &crate::gpu_context::shared_gpu().queue
35 }
36 }
37
38 #[inline]
40 pub fn device(&self) -> &wgpu::Device {
41 self.gpu_device()
42 }
43
44 #[inline]
46 pub fn queue(&self) -> &wgpu::Queue {
47 self.gpu_queue()
48 }
49
50 pub async fn try_new() -> Result<Self, String> {
51 #[cfg(not(target_arch = "wasm32"))]
52 log::info!(
53 "LLM_LOAD|engine-init|0.10|Initializing native GGUF runtime (shared GpuContext)"
54 );
55 #[cfg(target_arch = "wasm32")]
56 log::info!("LLM_LOAD|engine-init|0.10|Initializing WASM GGUF runtime");
57
58 #[cfg(not(target_arch = "wasm32"))]
59 let shared = crate::gpu_context::shared_gpu();
60 #[cfg(not(target_arch = "wasm32"))]
61 let device = &shared.device;
62 #[cfg(not(target_arch = "wasm32"))]
63 let _queue = &shared.queue;
64 #[cfg(not(target_arch = "wasm32"))]
65 log::info!("LLM_LOAD|gpu-device|0.35|Reusing process-wide wgpu device");
66 #[cfg(all(not(target_arch = "wasm32"), feature = "cuda"))]
69 {
70 let _ = crate::warm_cuda_context();
71 }
72
73 #[cfg(target_arch = "wasm32")]
74 let (wasm_device, wasm_queue) = {
75 let instance = wgpu::Instance::default();
76 let adapter = match instance
79 .request_adapter(&wgpu::RequestAdapterOptions {
80 power_preference: wgpu::PowerPreference::HighPerformance,
81 ..Default::default()
82 })
83 .await
84 {
85 Ok(a) => a,
86 Err(high_err) => instance
87 .request_adapter(&wgpu::RequestAdapterOptions::default())
88 .await
89 .map_err(|e| {
90 format!(
91 "Failed to find wgpu adapter (high-performance: {high_err}; default: {e})"
92 )
93 })?,
94 };
95 let info = adapter.get_info();
96 log::info!(
97 "LLM_LOAD|webgpu-adapter|0.20|name={} backend={:?} device={:?} vendor={:?}",
98 info.name,
99 info.backend,
100 info.device,
101 info.vendor
102 );
103 let required_features =
107 crate::gpu_context::requested_native_llm_features(adapter.features());
108 let experimental_features =
109 if required_features.contains(wgpu::Features::EXPERIMENTAL_COOPERATIVE_MATRIX) {
110 unsafe { wgpu::ExperimentalFeatures::enabled() }
113 } else {
114 wgpu::ExperimentalFeatures::disabled()
115 };
116 let adapter_limits = adapter.limits();
120 let required_limits = wgpu::Limits {
121 max_buffer_size: adapter_limits.max_buffer_size,
122 max_storage_buffer_binding_size: adapter_limits.max_storage_buffer_binding_size,
123 ..wgpu::Limits::default()
124 };
125
126 crate::gguf_bridge::wasm_yield::phase(&format!(
127 "Adapter '{}' — creating WebGPU device…",
128 info.name
129 ))
130 .await;
131 adapter
132 .request_device(&wgpu::DeviceDescriptor {
133 label: Some("qualia-wasm-llm"),
134 required_features,
135 required_limits,
136 experimental_features,
137 ..Default::default()
138 })
139 .await
140 .map_err(|e| {
141 format!(
142 "WebGPU requestDevice failed on adapter '{}': {e}. \
143 On phones use SmolLM2-360M only, close other tabs, and ensure Chrome WebGPU is enabled.",
144 info.name
145 )
146 })?
147 };
148 #[cfg(target_arch = "wasm32")]
149 let device = &wasm_device;
150 #[cfg(target_arch = "wasm32")]
152 crate::gguf_bridge::wasm_yield::phase(
153 "Compiling compute pipelines (UI may pause 30–90s on phones — leave tab open)…",
154 )
155 .await;
156 #[cfg(not(target_arch = "wasm32"))]
157 let native_pipeline_cache = create_native_pipeline_cache(device);
158 #[cfg(target_arch = "wasm32")]
159 let native_pipeline_cache: Option<wgpu::PipelineCache> = None;
160
161 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
162 label: Some("Fused Transformer Shader"),
163 source: wgpu::ShaderSource::Wgsl(
164 #[cfg(target_arch = "wasm32")]
165 include_str!("../shaders/wasm/fused_transformer.wgsl").into(),
166 #[cfg(not(target_arch = "wasm32"))]
167 include_str!("../shaders/fused_transformer.wgsl").into(),
168 ),
169 });
170
171 #[cfg(not(target_arch = "wasm32"))]
175 let coop_gemv_residual_bind_layout =
176 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
177 label: Some("CoopGemvBGL"),
178 entries: &[
179 wgpu::BindGroupLayoutEntry {
180 binding: 0,
181 visibility: wgpu::ShaderStages::COMPUTE,
182 ty: wgpu::BindingType::Buffer {
183 ty: wgpu::BufferBindingType::Storage { read_only: true },
184 has_dynamic_offset: false,
185 min_binding_size: None,
186 },
187 count: None,
188 },
189 wgpu::BindGroupLayoutEntry {
190 binding: 1,
191 visibility: wgpu::ShaderStages::COMPUTE,
192 ty: wgpu::BindingType::Buffer {
193 ty: wgpu::BufferBindingType::Storage { read_only: true },
194 has_dynamic_offset: false,
195 min_binding_size: None,
196 },
197 count: None,
198 },
199 wgpu::BindGroupLayoutEntry {
200 binding: 2,
201 visibility: wgpu::ShaderStages::COMPUTE,
202 ty: wgpu::BindingType::Buffer {
203 ty: wgpu::BufferBindingType::Uniform,
204 has_dynamic_offset: false,
205 min_binding_size: None,
206 },
207 count: None,
208 },
209 wgpu::BindGroupLayoutEntry {
210 binding: 3,
211 visibility: wgpu::ShaderStages::COMPUTE,
212 ty: wgpu::BindingType::Buffer {
213 ty: wgpu::BufferBindingType::Storage { read_only: false },
214 has_dynamic_offset: false,
215 min_binding_size: None,
216 },
217 count: None,
218 },
219 wgpu::BindGroupLayoutEntry {
220 binding: 4,
221 visibility: wgpu::ShaderStages::COMPUTE,
222 ty: wgpu::BindingType::Buffer {
223 ty: wgpu::BufferBindingType::Storage { read_only: true },
224 has_dynamic_offset: false,
225 min_binding_size: None,
226 },
227 count: None,
228 },
229 ],
230 });
231 #[cfg(not(target_arch = "wasm32"))]
232 let coop_gemv_bind_layout = coop_gemv_residual_bind_layout.clone();
233 #[cfg(not(target_arch = "wasm32"))]
234 let coop_gemv_pipeline_layout =
235 device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
236 label: Some("CoopGemvPL"),
237 bind_group_layouts: &[Some(&coop_gemv_bind_layout)],
238 immediate_size: 0,
239 });
240 #[cfg(not(target_arch = "wasm32"))]
241 let coop_gemv_residual_pipeline_layout =
242 device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
243 label: Some("CoopGemvResidualPL"),
244 bind_group_layouts: &[Some(&coop_gemv_residual_bind_layout)],
245 immediate_size: 0,
246 });
247
248 #[cfg(target_arch = "wasm32")]
249 let mc8_gemm_bind_layout =
250 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
251 label: Some("MC8GemmBGL"),
252 entries: &[
253 wgpu::BindGroupLayoutEntry {
254 binding: 0,
255 visibility: wgpu::ShaderStages::COMPUTE,
256 ty: wgpu::BindingType::Buffer {
257 ty: wgpu::BufferBindingType::Storage { read_only: true },
258 has_dynamic_offset: false,
259 min_binding_size: None,
260 },
261 count: None,
262 },
263 wgpu::BindGroupLayoutEntry {
264 binding: 1,
265 visibility: wgpu::ShaderStages::COMPUTE,
266 ty: wgpu::BindingType::Buffer {
267 ty: wgpu::BufferBindingType::Storage { read_only: true },
268 has_dynamic_offset: false,
269 min_binding_size: None,
270 },
271 count: None,
272 },
273 wgpu::BindGroupLayoutEntry {
274 binding: 2,
275 visibility: wgpu::ShaderStages::COMPUTE,
276 ty: wgpu::BindingType::Buffer {
277 ty: wgpu::BufferBindingType::Uniform,
278 has_dynamic_offset: true,
279 min_binding_size: std::num::NonZeroU64::new(MC8_UNIFORM_ALIGN as u64),
280 },
281 count: None,
282 },
283 wgpu::BindGroupLayoutEntry {
284 binding: 3,
285 visibility: wgpu::ShaderStages::COMPUTE,
286 ty: wgpu::BindingType::Buffer {
287 ty: wgpu::BufferBindingType::Storage { read_only: false },
288 has_dynamic_offset: false,
289 min_binding_size: None,
290 },
291 count: None,
292 },
293 ],
294 });
295 #[cfg(target_arch = "wasm32")]
296 let mc8_gemm_pipeline_layout =
297 device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
298 label: Some("MC8GemmPL"),
299 bind_group_layouts: &[Some(&mc8_gemm_bind_layout)],
300 immediate_size: 0,
301 });
302
303 #[cfg(target_arch = "wasm32")]
304 let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
305 label: Some("Fused Transformer Pipeline (WASM)"),
306 layout: Some(&mc8_gemm_pipeline_layout),
307 module: &shader,
308 entry_point: Some("main"),
309 compilation_options: Default::default(),
310 cache: native_pipeline_cache.as_ref(),
311 });
312 #[cfg(target_arch = "wasm32")]
313 let mmv_q8_0_pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
314 label: Some("MulMatVec Q8_0 Pipeline (WASM)"),
315 layout: Some(&mc8_gemm_pipeline_layout),
316 module: &shader,
317 entry_point: Some("mul_mat_vec_q8_0"),
318 compilation_options: Default::default(),
319 cache: native_pipeline_cache.as_ref(),
320 });
321 #[cfg(not(target_arch = "wasm32"))]
322 let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
323 label: Some("Fused Transformer Pipeline"),
324 layout: None,
325 module: &shader,
326 entry_point: Some("main"),
327 compilation_options: Default::default(),
328 cache: native_pipeline_cache.as_ref(),
329 });
330 #[cfg(not(target_arch = "wasm32"))]
343 let (coop_gemv_pipeline, coop_gemv_residual_pipeline) =
344 if device.features().contains(wgpu::Features::SUBGROUP) {
345 let sg_src = format!(
347 "{}\n{}",
348 include_str!("../shaders/fused_transformer.wgsl"),
349 include_str!("../shaders/coop_gemv_subgroup.wgsl"),
350 );
351 let sg_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
352 label: Some("Coop GEMV Subgroup Shader"),
353 source: wgpu::ShaderSource::Wgsl(sg_src.into()),
354 });
355 let gemv = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
356 label: Some("Coop GEMV SG Pipeline"),
357 layout: Some(&coop_gemv_pipeline_layout),
358 module: &sg_module,
359 entry_point: Some("coop_gemv_sg"),
360 compilation_options: Default::default(),
361 cache: native_pipeline_cache.as_ref(),
362 });
363 let resid = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
364 label: Some("Coop GEMV Residual SG Pipeline"),
365 layout: Some(&coop_gemv_residual_pipeline_layout),
366 module: &sg_module,
367 entry_point: Some("coop_gemv_residual_sg"),
368 compilation_options: Default::default(),
369 cache: native_pipeline_cache.as_ref(),
370 });
371 (gemv, resid)
372 } else {
373 let gemv = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
374 label: Some("Coop GEMV Pipeline"),
375 layout: Some(&coop_gemv_pipeline_layout),
376 module: &shader,
377 entry_point: Some("coop_gemv"),
378 compilation_options: Default::default(),
379 cache: native_pipeline_cache.as_ref(),
380 });
381 let resid = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
382 label: Some("Coop GEMV Residual Pipeline"),
383 layout: Some(&coop_gemv_residual_pipeline_layout),
384 module: &shader,
385 entry_point: Some("coop_gemv_residual"),
386 compilation_options: Default::default(),
387 cache: native_pipeline_cache.as_ref(),
388 });
389 (gemv, resid)
390 };
391 #[cfg(not(target_arch = "wasm32"))]
392 let coop_gemv_mr_pipeline =
393 device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
394 label: Some("Coop GEMV Multi-Row Pipeline"),
395 layout: Some(&coop_gemv_pipeline_layout),
396 module: &shader,
397 entry_point: Some("coop_gemv_mr"),
398 compilation_options: Default::default(),
399 cache: native_pipeline_cache.as_ref(),
400 });
401 #[cfg(not(target_arch = "wasm32"))]
402 let coop_gemv_residual_mr_pipeline =
403 device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
404 label: Some("Coop GEMV Residual Multi-Row Pipeline"),
405 layout: Some(&coop_gemv_residual_pipeline_layout),
406 module: &shader,
407 entry_point: Some("coop_gemv_residual_mr"),
408 compilation_options: Default::default(),
409 cache: native_pipeline_cache.as_ref(),
410 });
411 #[cfg(not(target_arch = "wasm32"))]
412 let coop_gemv_warp_pipeline =
413 device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
414 label: Some("Coop GEMV Warp Pipeline"),
415 layout: Some(&coop_gemv_pipeline_layout),
416 module: &shader,
417 entry_point: Some("coop_gemv_warp"),
418 compilation_options: Default::default(),
419 cache: native_pipeline_cache.as_ref(),
420 });
421 #[cfg(not(target_arch = "wasm32"))]
422 let coop_gemv_residual_warp_pipeline =
423 device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
424 label: Some("Coop GEMV Residual Warp Pipeline"),
425 layout: Some(&coop_gemv_residual_pipeline_layout),
426 module: &shader,
427 entry_point: Some("coop_gemv_residual_warp"),
428 compilation_options: Default::default(),
429 cache: native_pipeline_cache.as_ref(),
430 });
431
432 #[cfg(not(target_arch = "wasm32"))]
433 let mock_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
434 label: Some("Mock Fused Contraction Shader"),
435 source: wgpu::ShaderSource::Wgsl(
436 include_str!("../shaders/fused_tensor_contraction.wgsl").into(),
437 ),
438 });
439 #[cfg(not(target_arch = "wasm32"))]
440 let mock_pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
441 label: Some("Mock Fused Contraction Pipeline"),
442 layout: None,
443 module: &mock_shader,
444 entry_point: Some("main"),
445 compilation_options: Default::default(),
446 cache: native_pipeline_cache.as_ref(),
447 });
448
449 let emb_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
450 label: Some("Quantized Embedding Shader"),
451 source: wgpu::ShaderSource::Wgsl(
452 include_str!("../shaders/quantized_embedding.wgsl").into(),
453 ),
454 });
455 let embedding_pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
456 label: Some("Quantized Embedding Pipeline"),
457 layout: None,
458 module: &emb_shader,
459 entry_point: Some("main"),
460 compilation_options: Default::default(),
461 cache: native_pipeline_cache.as_ref(),
462 });
463
464 let attn_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
465 label: Some("Fused Attention Shader"),
466 source: wgpu::ShaderSource::Wgsl(
467 include_str!("../shaders/fused_attention.wgsl").into(),
468 ),
469 });
470 #[cfg(target_arch = "wasm32")]
471 let mc8_attn_bind_layout =
472 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
473 label: Some("MC8AttnBGL"),
474 entries: &[
475 wgpu::BindGroupLayoutEntry {
476 binding: 0,
477 visibility: wgpu::ShaderStages::COMPUTE,
478 ty: wgpu::BindingType::Buffer {
479 ty: wgpu::BufferBindingType::Storage { read_only: true },
480 has_dynamic_offset: false,
481 min_binding_size: None,
482 },
483 count: None,
484 },
485 wgpu::BindGroupLayoutEntry {
486 binding: 1,
487 visibility: wgpu::ShaderStages::COMPUTE,
488 ty: wgpu::BindingType::Buffer {
489 ty: wgpu::BufferBindingType::Storage { read_only: true },
490 has_dynamic_offset: false,
491 min_binding_size: None,
492 },
493 count: None,
494 },
495 wgpu::BindGroupLayoutEntry {
496 binding: 2,
497 visibility: wgpu::ShaderStages::COMPUTE,
498 ty: wgpu::BindingType::Buffer {
499 ty: wgpu::BufferBindingType::Uniform,
500 has_dynamic_offset: true,
501 min_binding_size: std::num::NonZeroU64::new(MC8_UNIFORM_ALIGN as u64),
502 },
503 count: None,
504 },
505 wgpu::BindGroupLayoutEntry {
506 binding: 3,
507 visibility: wgpu::ShaderStages::COMPUTE,
508 ty: wgpu::BindingType::Buffer {
509 ty: wgpu::BufferBindingType::Storage { read_only: false },
510 has_dynamic_offset: false,
511 min_binding_size: None,
512 },
513 count: None,
514 },
515 wgpu::BindGroupLayoutEntry {
516 binding: 4,
517 visibility: wgpu::ShaderStages::COMPUTE,
518 ty: wgpu::BindingType::Buffer {
519 ty: wgpu::BufferBindingType::Storage { read_only: false },
520 has_dynamic_offset: false,
521 min_binding_size: None,
522 },
523 count: None,
524 },
525 wgpu::BindGroupLayoutEntry {
526 binding: 5,
527 visibility: wgpu::ShaderStages::COMPUTE,
528 ty: wgpu::BindingType::Buffer {
529 ty: wgpu::BufferBindingType::Storage { read_only: true },
530 has_dynamic_offset: false,
531 min_binding_size: None,
532 },
533 count: None,
534 },
535 ],
536 });
537 #[cfg(target_arch = "wasm32")]
538 let mc8_attn_pipeline_layout =
539 device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
540 label: Some("MC8AttnPL"),
541 bind_group_layouts: &[Some(&mc8_attn_bind_layout)],
542 immediate_size: 0,
543 });
544 #[cfg(target_arch = "wasm32")]
545 let attention_pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
546 label: Some("Fused Attention Pipeline"),
547 layout: Some(&mc8_attn_pipeline_layout),
548 module: &attn_shader,
549 entry_point: Some("main"),
550 compilation_options: Default::default(),
551 cache: native_pipeline_cache.as_ref(),
552 });
553 #[cfg(not(target_arch = "wasm32"))]
554 let attention_pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
555 label: Some("Fused Attention Pipeline"),
556 layout: None,
557 module: &attn_shader,
558 entry_point: Some("main"),
559 compilation_options: Default::default(),
560 cache: native_pipeline_cache.as_ref(),
561 });
562
563 let elem_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
564 label: Some("Wasm Elementwise Shader"),
565 source: wgpu::ShaderSource::Wgsl(
566 include_str!("../shaders/wasm_elementwise.wgsl").into(),
567 ),
568 });
569 #[cfg(target_arch = "wasm32")]
570 let mc8_elem_bind_layout =
571 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
572 label: Some("MC8ElemBGL"),
573 entries: &[
574 wgpu::BindGroupLayoutEntry {
575 binding: 0,
576 visibility: wgpu::ShaderStages::COMPUTE,
577 ty: wgpu::BindingType::Buffer {
578 ty: wgpu::BufferBindingType::Storage { read_only: true },
579 has_dynamic_offset: false,
580 min_binding_size: None,
581 },
582 count: None,
583 },
584 wgpu::BindGroupLayoutEntry {
585 binding: 1,
586 visibility: wgpu::ShaderStages::COMPUTE,
587 ty: wgpu::BindingType::Buffer {
588 ty: wgpu::BufferBindingType::Storage { read_only: true },
589 has_dynamic_offset: false,
590 min_binding_size: None,
591 },
592 count: None,
593 },
594 wgpu::BindGroupLayoutEntry {
595 binding: 2,
596 visibility: wgpu::ShaderStages::COMPUTE,
597 ty: wgpu::BindingType::Buffer {
598 ty: wgpu::BufferBindingType::Storage { read_only: false },
599 has_dynamic_offset: false,
600 min_binding_size: None,
601 },
602 count: None,
603 },
604 wgpu::BindGroupLayoutEntry {
605 binding: 3,
606 visibility: wgpu::ShaderStages::COMPUTE,
607 ty: wgpu::BindingType::Buffer {
608 ty: wgpu::BufferBindingType::Uniform,
609 has_dynamic_offset: true,
610 min_binding_size: std::num::NonZeroU64::new(MC8_UNIFORM_ALIGN as u64),
611 },
612 count: None,
613 },
614 ],
615 });
616 #[cfg(target_arch = "wasm32")]
617 let mc8_elem_pipeline_layout =
618 device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
619 label: Some("MC8ElemPL"),
620 bind_group_layouts: &[Some(&mc8_elem_bind_layout)],
621 immediate_size: 0,
622 });
623 #[cfg(target_arch = "wasm32")]
624 let elem_rms_norm_pipeline =
625 device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
626 label: Some("ElemRmsNorm"),
627 layout: Some(&mc8_elem_pipeline_layout),
628 module: &elem_shader,
629 entry_point: Some("rms_norm_batch"),
630 compilation_options: Default::default(),
631 cache: native_pipeline_cache.as_ref(),
632 });
633 #[cfg(target_arch = "wasm32")]
634 let elem_silu_mul_pipeline =
635 device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
636 label: Some("ElemSiluMul"),
637 layout: Some(&mc8_elem_pipeline_layout),
638 module: &elem_shader,
639 entry_point: Some("silu_mul_main"),
640 compilation_options: Default::default(),
641 cache: native_pipeline_cache.as_ref(),
642 });
643 #[cfg(target_arch = "wasm32")]
644 let elem_add_residual_pipeline =
645 device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
646 label: Some("ElemAddResidual"),
647 layout: Some(&mc8_elem_pipeline_layout),
648 module: &elem_shader,
649 entry_point: Some("add_residual_main"),
650 compilation_options: Default::default(),
651 cache: native_pipeline_cache.as_ref(),
652 });
653 #[cfg(not(target_arch = "wasm32"))]
654 let elem_rms_norm_pipeline =
655 device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
656 label: Some("ElemRmsNorm"),
657 layout: None,
658 module: &elem_shader,
659 entry_point: Some("rms_norm_batch"),
660 compilation_options: Default::default(),
661 cache: native_pipeline_cache.as_ref(),
662 });
663 #[cfg(not(target_arch = "wasm32"))]
664 let elem_silu_mul_pipeline =
665 device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
666 label: Some("ElemSiluMul"),
667 layout: None,
668 module: &elem_shader,
669 entry_point: Some("silu_mul_main"),
670 compilation_options: Default::default(),
671 cache: native_pipeline_cache.as_ref(),
672 });
673 #[cfg(not(target_arch = "wasm32"))]
674 let elem_add_residual_pipeline =
675 device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
676 label: Some("ElemAddResidual"),
677 layout: None,
678 module: &elem_shader,
679 entry_point: Some("add_residual_main"),
680 compilation_options: Default::default(),
681 cache: native_pipeline_cache.as_ref(),
682 });
683
684 #[cfg(target_arch = "wasm32")]
689 let mc8_ffn_fused_bind_layout =
690 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
691 label: Some("MC8FfnFusedBGL"),
692 entries: &[
693 wgpu::BindGroupLayoutEntry {
695 binding: 0,
696 visibility: wgpu::ShaderStages::COMPUTE,
697 ty: wgpu::BindingType::Buffer {
698 ty: wgpu::BufferBindingType::Storage { read_only: true },
699 has_dynamic_offset: false,
700 min_binding_size: None,
701 },
702 count: None,
703 },
704 wgpu::BindGroupLayoutEntry {
706 binding: 1,
707 visibility: wgpu::ShaderStages::COMPUTE,
708 ty: wgpu::BindingType::Buffer {
709 ty: wgpu::BufferBindingType::Storage { read_only: true },
710 has_dynamic_offset: false,
711 min_binding_size: None,
712 },
713 count: None,
714 },
715 wgpu::BindGroupLayoutEntry {
717 binding: 2,
718 visibility: wgpu::ShaderStages::COMPUTE,
719 ty: wgpu::BindingType::Buffer {
720 ty: wgpu::BufferBindingType::Storage { read_only: true },
721 has_dynamic_offset: false,
722 min_binding_size: None,
723 },
724 count: None,
725 },
726 wgpu::BindGroupLayoutEntry {
728 binding: 3,
729 visibility: wgpu::ShaderStages::COMPUTE,
730 ty: wgpu::BindingType::Buffer {
731 ty: wgpu::BufferBindingType::Uniform,
732 has_dynamic_offset: true,
733 min_binding_size: std::num::NonZeroU64::new(MC8_UNIFORM_ALIGN as u64),
734 },
735 count: None,
736 },
737 wgpu::BindGroupLayoutEntry {
739 binding: 4,
740 visibility: wgpu::ShaderStages::COMPUTE,
741 ty: wgpu::BindingType::Buffer {
742 ty: wgpu::BufferBindingType::Storage { read_only: false },
743 has_dynamic_offset: false,
744 min_binding_size: None,
745 },
746 count: None,
747 },
748 ],
749 });
750 #[cfg(target_arch = "wasm32")]
751 let mc8_ffn_fused_pipeline = {
752 let tpl = include_str!("../shaders/wasm/dequant_template.wgsl");
754 let gate_fns = tpl.replace("$W", "gate_words").replace("$S", "_gate");
755 let up_fns = tpl.replace("$W", "up_words").replace("$S", "_up");
756 let base = include_str!("../shaders/wasm/fused_ffn.wgsl");
757 let src = base.replace("// @@DEQUANT_FUNCTIONS@@", &format!("{gate_fns}\n{up_fns}"));
761 let module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
762 label: Some("FusedFFNExpansion"),
763 source: wgpu::ShaderSource::Wgsl(src.into()),
764 });
765 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
766 label: Some("MC8FfnFusedPL"),
767 bind_group_layouts: &[Some(&mc8_ffn_fused_bind_layout)],
768 immediate_size: 0,
769 });
770 device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
771 label: Some("FusedFFNExpansionPipeline"),
772 layout: Some(&layout),
773 module: &module,
774 entry_point: Some("fused_ffn_expansion"),
775 compilation_options: Default::default(),
776 cache: native_pipeline_cache.as_ref(),
777 })
778 };
779
780 #[cfg(not(target_arch = "wasm32"))]
783 let ffn_fused_bind_layout =
784 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
785 label: Some("NativeFfnFusedBGL"),
786 entries: &[
787 wgpu::BindGroupLayoutEntry {
788 binding: 0,
789 visibility: wgpu::ShaderStages::COMPUTE,
790 ty: wgpu::BindingType::Buffer {
791 ty: wgpu::BufferBindingType::Storage { read_only: true },
792 has_dynamic_offset: false,
793 min_binding_size: None,
794 },
795 count: None,
796 },
797 wgpu::BindGroupLayoutEntry {
798 binding: 1,
799 visibility: wgpu::ShaderStages::COMPUTE,
800 ty: wgpu::BindingType::Buffer {
801 ty: wgpu::BufferBindingType::Storage { read_only: true },
802 has_dynamic_offset: false,
803 min_binding_size: None,
804 },
805 count: None,
806 },
807 wgpu::BindGroupLayoutEntry {
808 binding: 2,
809 visibility: wgpu::ShaderStages::COMPUTE,
810 ty: wgpu::BindingType::Buffer {
811 ty: wgpu::BufferBindingType::Storage { read_only: true },
812 has_dynamic_offset: false,
813 min_binding_size: None,
814 },
815 count: None,
816 },
817 wgpu::BindGroupLayoutEntry {
818 binding: 3,
819 visibility: wgpu::ShaderStages::COMPUTE,
820 ty: wgpu::BindingType::Buffer {
821 ty: wgpu::BufferBindingType::Uniform,
822 has_dynamic_offset: false,
823 min_binding_size: std::num::NonZeroU64::new(std::mem::size_of::<
824 GemmGpuParams,
825 >(
826 )
827 as u64),
828 },
829 count: None,
830 },
831 wgpu::BindGroupLayoutEntry {
832 binding: 4,
833 visibility: wgpu::ShaderStages::COMPUTE,
834 ty: wgpu::BindingType::Buffer {
835 ty: wgpu::BufferBindingType::Storage { read_only: false },
836 has_dynamic_offset: false,
837 min_binding_size: None,
838 },
839 count: None,
840 },
841 ],
842 });
843 #[cfg(not(target_arch = "wasm32"))]
844 let (
845 ffn_fused_pipeline,
846 ffn_fused_coop_pipeline,
847 ffn_fused_mr_pipeline,
848 ffn_fused_warp_pipeline,
849 ) = {
850 let tpl = include_str!("../shaders/dequant_template.wgsl");
851 let gate_fns = tpl.replace("$W", "gate_words").replace("$S", "_gate");
852 let up_fns = tpl.replace("$W", "up_words").replace("$S", "_up");
853 let base = include_str!("../shaders/fused_ffn.wgsl");
854 let src = base.replace("// @@DEQUANT_FUNCTIONS@@", &format!("{gate_fns}\n{up_fns}"));
855 let module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
856 label: Some("NativeFusedFFNExpansion"),
857 source: wgpu::ShaderSource::Wgsl(src.into()),
858 });
859 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
860 label: Some("NativeFfnFusedPL"),
861 bind_group_layouts: &[Some(&ffn_fused_bind_layout)],
862 immediate_size: 0,
863 });
864 let naive = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
865 label: Some("NativeFusedFFNExpansionPipeline"),
866 layout: Some(&layout),
867 module: &module,
868 entry_point: Some("fused_ffn_expansion"),
869 compilation_options: Default::default(),
870 cache: native_pipeline_cache.as_ref(),
871 });
872 let coop_ep = if device.features().contains(wgpu::Features::SUBGROUP) {
874 "coop_fused_ffn_sg"
875 } else {
876 "coop_fused_ffn_expansion"
877 };
878 let coop = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
879 label: Some("NativeCoopFusedFFNExpansionPipeline"),
880 layout: Some(&layout),
881 module: &module,
882 entry_point: Some(coop_ep),
883 compilation_options: Default::default(),
884 cache: native_pipeline_cache.as_ref(),
885 });
886 let coop_mr = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
888 label: Some("NativeCoopFusedFFNMultiRowPipeline"),
889 layout: Some(&layout),
890 module: &module,
891 entry_point: Some("coop_fused_ffn_mr"),
892 compilation_options: Default::default(),
893 cache: native_pipeline_cache.as_ref(),
894 });
895 let coop_warp = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
897 label: Some("NativeCoopFusedFFNWarpPipeline"),
898 layout: Some(&layout),
899 module: &module,
900 entry_point: Some("coop_fused_ffn_warp"),
901 compilation_options: Default::default(),
902 cache: native_pipeline_cache.as_ref(),
903 });
904 log::info!(
905 "LLM_LOAD|fused_ffn|coop_entry={coop_ep}|mr=coop_fused_ffn_mr|warp=coop_fused_ffn_warp"
906 );
907 (naive, coop, coop_mr, coop_warp)
908 };
909
910 #[cfg(not(target_arch = "wasm32"))]
912 let dual_gemv_bind_layout =
913 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
914 label: Some("DualGemvBGL"),
915 entries: &[
916 wgpu::BindGroupLayoutEntry {
917 binding: 0,
918 visibility: wgpu::ShaderStages::COMPUTE,
919 ty: wgpu::BindingType::Buffer {
920 ty: wgpu::BufferBindingType::Storage { read_only: true },
921 has_dynamic_offset: false,
922 min_binding_size: None,
923 },
924 count: None,
925 },
926 wgpu::BindGroupLayoutEntry {
927 binding: 1,
928 visibility: wgpu::ShaderStages::COMPUTE,
929 ty: wgpu::BindingType::Buffer {
930 ty: wgpu::BufferBindingType::Storage { read_only: true },
931 has_dynamic_offset: false,
932 min_binding_size: None,
933 },
934 count: None,
935 },
936 wgpu::BindGroupLayoutEntry {
937 binding: 2,
938 visibility: wgpu::ShaderStages::COMPUTE,
939 ty: wgpu::BindingType::Buffer {
940 ty: wgpu::BufferBindingType::Uniform,
941 has_dynamic_offset: false,
942 min_binding_size: None,
943 },
944 count: None,
945 },
946 wgpu::BindGroupLayoutEntry {
947 binding: 3,
948 visibility: wgpu::ShaderStages::COMPUTE,
949 ty: wgpu::BindingType::Buffer {
950 ty: wgpu::BufferBindingType::Storage { read_only: false },
951 has_dynamic_offset: false,
952 min_binding_size: None,
953 },
954 count: None,
955 },
956 wgpu::BindGroupLayoutEntry {
957 binding: 4,
958 visibility: wgpu::ShaderStages::COMPUTE,
959 ty: wgpu::BindingType::Buffer {
960 ty: wgpu::BufferBindingType::Storage { read_only: true },
961 has_dynamic_offset: false,
962 min_binding_size: None,
963 },
964 count: None,
965 },
966 wgpu::BindGroupLayoutEntry {
967 binding: 5,
968 visibility: wgpu::ShaderStages::COMPUTE,
969 ty: wgpu::BindingType::Buffer {
970 ty: wgpu::BufferBindingType::Storage { read_only: false },
971 has_dynamic_offset: false,
972 min_binding_size: None,
973 },
974 count: None,
975 },
976 ],
977 });
978 #[cfg(not(target_arch = "wasm32"))]
979 let (dual_gemv_pipeline, dual_gemv_mr_pipeline) = {
980 let module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
981 label: Some("Dual GEMV Shader"),
982 source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/dual_gemv.wgsl").into()),
983 });
984 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
985 label: Some("DualGemvPL"),
986 bind_group_layouts: &[Some(&dual_gemv_bind_layout)],
987 immediate_size: 0,
988 });
989 let dual = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
990 label: Some("Dual GEMV Pipeline"),
991 layout: Some(&layout),
992 module: &module,
993 entry_point: Some("coop_gemv_dual"),
994 compilation_options: Default::default(),
995 cache: native_pipeline_cache.as_ref(),
996 });
997 let dual_mr = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
998 label: Some("Dual GEMV Multi-Row Pipeline"),
999 layout: Some(&layout),
1000 module: &module,
1001 entry_point: Some("coop_gemv_dual_mr"),
1002 compilation_options: Default::default(),
1003 cache: native_pipeline_cache.as_ref(),
1004 });
1005 (dual, dual_mr)
1006 };
1007
1008 #[cfg(not(target_arch = "wasm32"))]
1010 let triple_gemv_bind_layout =
1011 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
1012 label: Some("TripleGemvBGL"),
1013 entries: &[
1014 wgpu::BindGroupLayoutEntry {
1016 binding: 0,
1017 visibility: wgpu::ShaderStages::COMPUTE,
1018 ty: wgpu::BindingType::Buffer {
1019 ty: wgpu::BufferBindingType::Storage { read_only: true },
1020 has_dynamic_offset: false,
1021 min_binding_size: None,
1022 },
1023 count: None,
1024 },
1025 wgpu::BindGroupLayoutEntry {
1026 binding: 1,
1027 visibility: wgpu::ShaderStages::COMPUTE,
1028 ty: wgpu::BindingType::Buffer {
1029 ty: wgpu::BufferBindingType::Storage { read_only: true },
1030 has_dynamic_offset: false,
1031 min_binding_size: None,
1032 },
1033 count: None,
1034 },
1035 wgpu::BindGroupLayoutEntry {
1036 binding: 2,
1037 visibility: wgpu::ShaderStages::COMPUTE,
1038 ty: wgpu::BindingType::Buffer {
1039 ty: wgpu::BufferBindingType::Uniform,
1040 has_dynamic_offset: false,
1041 min_binding_size: None,
1042 },
1043 count: None,
1044 },
1045 wgpu::BindGroupLayoutEntry {
1046 binding: 3,
1047 visibility: wgpu::ShaderStages::COMPUTE,
1048 ty: wgpu::BindingType::Buffer {
1049 ty: wgpu::BufferBindingType::Storage { read_only: false },
1050 has_dynamic_offset: false,
1051 min_binding_size: None,
1052 },
1053 count: None,
1054 },
1055 wgpu::BindGroupLayoutEntry {
1056 binding: 4,
1057 visibility: wgpu::ShaderStages::COMPUTE,
1058 ty: wgpu::BindingType::Buffer {
1059 ty: wgpu::BufferBindingType::Storage { read_only: true },
1060 has_dynamic_offset: false,
1061 min_binding_size: None,
1062 },
1063 count: None,
1064 },
1065 wgpu::BindGroupLayoutEntry {
1066 binding: 5,
1067 visibility: wgpu::ShaderStages::COMPUTE,
1068 ty: wgpu::BindingType::Buffer {
1069 ty: wgpu::BufferBindingType::Storage { read_only: false },
1070 has_dynamic_offset: false,
1071 min_binding_size: None,
1072 },
1073 count: None,
1074 },
1075 wgpu::BindGroupLayoutEntry {
1076 binding: 6,
1077 visibility: wgpu::ShaderStages::COMPUTE,
1078 ty: wgpu::BindingType::Buffer {
1079 ty: wgpu::BufferBindingType::Storage { read_only: true },
1080 has_dynamic_offset: false,
1081 min_binding_size: None,
1082 },
1083 count: None,
1084 },
1085 wgpu::BindGroupLayoutEntry {
1086 binding: 7,
1087 visibility: wgpu::ShaderStages::COMPUTE,
1088 ty: wgpu::BindingType::Buffer {
1089 ty: wgpu::BufferBindingType::Storage { read_only: false },
1090 has_dynamic_offset: false,
1091 min_binding_size: None,
1092 },
1093 count: None,
1094 },
1095 ],
1096 });
1097 #[cfg(not(target_arch = "wasm32"))]
1098 let triple_gemv_pipeline = {
1099 let module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
1100 label: Some("Triple GEMV Shader"),
1101 source: wgpu::ShaderSource::Wgsl(
1102 include_str!("../shaders/triple_gemv.wgsl").into(),
1103 ),
1104 });
1105 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
1106 label: Some("TripleGemvPL"),
1107 bind_group_layouts: &[Some(&triple_gemv_bind_layout)],
1108 immediate_size: 0,
1109 });
1110 device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
1111 label: Some("Triple GEMV Pipeline"),
1112 layout: Some(&layout),
1113 module: &module,
1114 entry_point: Some("coop_gemv_triple"),
1115 compilation_options: Default::default(),
1116 cache: native_pipeline_cache.as_ref(),
1117 })
1118 };
1119
1120 #[cfg(target_os = "windows")]
1124 let dml_status = {
1125 let want = matches!(
1126 std::env::var("QUALIA_DIRECTML")
1127 .or_else(|_| std::env::var("QUALIA_LLM_DIRECTML"))
1128 .ok()
1129 .as_deref(),
1130 Some("1") | Some("true") | Some("on")
1131 );
1132 if !want {
1133 log::info!(
1134 "LLM_LOAD|gpu-backend|0.45|DirectML deferred (set QUALIA_DIRECTML=1 to enable second D3D12 device)"
1135 );
1136 None
1137 } else {
1138 match crate::directml_bridge::DmlDevice::new() {
1139 Ok(device) => {
1140 log::info!(
1141 "DirectML device initialization: Ok({})",
1142 device.adapter_desc
1143 );
1144 log::info!(
1145 "LLM_LOAD|gpu-backend|0.45|DirectML ready on {}",
1146 device.adapter_desc
1147 );
1148 log::info!(
1149 "LLM_LOAD|gpu-route|0.48|Streaming weights through DirectML with {:.1} GiB VRAM free",
1150 bytes_to_gib(
1151 device
1152 .local_budget_bytes
1153 .saturating_sub(device.local_usage_bytes)
1154 )
1155 );
1156 Some(device)
1157 }
1158 Err(err) => {
1159 log::warn!("DirectML device initialization failed: {:?}", err);
1160 log::info!(
1161 "LLM_LOAD|gpu-backend|0.45|DirectML unavailable; using wgpu fallback"
1162 );
1163 None
1164 }
1165 }
1166 }
1167 };
1168
1169 #[cfg(not(target_os = "windows"))]
1170 {
1171 log::info!("LLM_LOAD|gpu-backend|0.45|Using wgpu fallback backend for native compute");
1172 }
1173
1174 #[cfg(not(target_arch = "wasm32"))]
1175 let pipeline_bind_layout = pipeline.get_bind_group_layout(0);
1176 #[cfg(not(target_arch = "wasm32"))]
1179 let embedding_bind_layout = embedding_pipeline.get_bind_group_layout(0);
1180 #[cfg(not(target_arch = "wasm32"))]
1181 let attention_bind_layout = attention_pipeline.get_bind_group_layout(0);
1182 #[cfg(not(target_arch = "wasm32"))]
1183 let elem_silu_mul_bind_layout = elem_silu_mul_pipeline.get_bind_group_layout(0);
1184 #[cfg(not(target_arch = "wasm32"))]
1185 let attention_kv_gemm_params = device.create_buffer(&wgpu::BufferDescriptor {
1186 label: Some("AttentionKvGemmParams"),
1187 size: 256 * 2,
1188 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
1189 mapped_at_creation: false,
1190 });
1191 #[cfg(not(target_arch = "wasm32"))]
1192 let attention_kv_params = device.create_buffer(&wgpu::BufferDescriptor {
1193 label: Some("AttentionKvWriteParams"),
1194 size: 256 * 2,
1195 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
1196 mapped_at_creation: false,
1197 });
1198
1199 let engine = Self {
1200 #[cfg(target_arch = "wasm32")]
1201 device: wasm_device,
1202 #[cfg(target_arch = "wasm32")]
1203 queue: wasm_queue,
1204 pipeline,
1205 #[cfg(target_arch = "wasm32")]
1206 mmv_q8_0_pipeline,
1207 #[cfg(not(target_arch = "wasm32"))]
1208 native_pipeline_cache,
1209 #[cfg(not(target_arch = "wasm32"))]
1210 pipeline_bind_layout,
1211 #[cfg(not(target_arch = "wasm32"))]
1212 coop_gemv_pipeline,
1213 #[cfg(not(target_arch = "wasm32"))]
1214 coop_gemv_bind_layout,
1215 #[cfg(not(target_arch = "wasm32"))]
1216 coop_gemv_mr_pipeline,
1217 #[cfg(not(target_arch = "wasm32"))]
1218 coop_gemv_residual_pipeline,
1219 #[cfg(not(target_arch = "wasm32"))]
1220 coop_gemv_residual_bind_layout,
1221 #[cfg(not(target_arch = "wasm32"))]
1222 coop_gemv_residual_mr_pipeline,
1223 #[cfg(not(target_arch = "wasm32"))]
1224 coop_gemv_warp_pipeline,
1225 #[cfg(not(target_arch = "wasm32"))]
1226 coop_gemv_residual_warp_pipeline,
1227 #[cfg(not(target_arch = "wasm32"))]
1228 mock_pipeline,
1229 embedding_pipeline,
1230 #[cfg(not(target_arch = "wasm32"))]
1231 embedding_bind_layout,
1232 attention_pipeline,
1233 #[cfg(not(target_arch = "wasm32"))]
1234 attention_bind_layout,
1235 is_initialized: true,
1236 #[cfg(target_os = "windows")]
1237 dml: dml_status,
1238 gguf_mmap: None,
1239 #[cfg(target_arch = "wasm32")]
1240 cached_tokenizer: None,
1241 #[cfg(target_arch = "wasm32")]
1242 cached_tensor_index: None,
1243 #[cfg(target_arch = "wasm32")]
1244 cached_token_embd: None,
1245 #[cfg(target_arch = "wasm32")]
1246 p64_resident: None,
1247 #[cfg(not(target_arch = "wasm32"))]
1248 p64_index: None,
1249 #[cfg(not(target_arch = "wasm32"))]
1250 tensor_index_cache: None,
1251 tensor_data_offset: 0,
1252 hyperparams: crate::gguf_sharder::GgufHyperparams::default(),
1253 max_tensor_bytes: 0,
1254 gemm_input_buf: None,
1255 gemm_weight_buf: None,
1256 #[cfg(target_arch = "wasm32")]
1257 mc8_weight_arena: None,
1258 #[cfg(target_arch = "wasm32")]
1259 mc8_weights_resident: false,
1260 #[cfg(target_arch = "wasm32")]
1261 mc8_weight_role_stride: [0u64; 7],
1262 #[cfg(target_arch = "wasm32")]
1263 gemm_weight_buf_b: None,
1264 gemm_output_buf: None,
1265 gemm_params_buf: None,
1266 gemm_output_staging: None,
1267 output_topk_pipeline: None,
1268 output_topk_bind_layout: None,
1269 topk_cand_val_buf: None,
1270 topk_cand_idx_buf: None,
1271 topk_cand_staging: None,
1272 topk_params_buf: None,
1273 gemm_aux_buf: None,
1274 gemm_ffn_buf: None,
1275 #[cfg(target_arch = "wasm32")]
1276 prefill_scratch_buf: None,
1277 #[cfg(target_arch = "wasm32")]
1278 prefill_work_buf_a: None,
1279 #[cfg(target_arch = "wasm32")]
1280 prefill_work_buf_b: None,
1281 #[cfg(target_arch = "wasm32")]
1282 mc8_q_proj_buf: None,
1283 #[cfg(target_arch = "wasm32")]
1284 mc8_k_proj_buf: None,
1285 #[cfg(target_arch = "wasm32")]
1286 mc8_v_proj_buf: None,
1287 gemm_max_out_dim: MAX_STACK_GEMM_OUT as u32,
1288 gemm_max_input_floats: 0,
1289 kv_layout: None,
1290 kv_cache_gpu: None,
1291 kv_cache_cpu: None,
1292 attention_params_buf: None,
1293 attention_mask_buf: None,
1294 elem_rms_norm_pipeline,
1295 elem_silu_mul_pipeline,
1296 #[cfg(not(target_arch = "wasm32"))]
1297 elem_silu_mul_bind_layout,
1298 elem_add_residual_pipeline,
1299 elem_params_buf: None,
1300 norm_weight_buf: None,
1301 #[cfg(target_arch = "wasm32")]
1302 mc8_gemm_bind_layout,
1303 #[cfg(target_arch = "wasm32")]
1304 mc8_elem_bind_layout,
1305 #[cfg(target_arch = "wasm32")]
1306 mc8_attn_bind_layout,
1307 #[cfg(target_arch = "wasm32")]
1308 mc8_ffn_fused_bind_layout,
1309 #[cfg(target_arch = "wasm32")]
1310 mc8_ffn_fused_pipeline,
1311 #[cfg(not(target_arch = "wasm32"))]
1312 ffn_fused_bind_layout,
1313 #[cfg(not(target_arch = "wasm32"))]
1314 ffn_fused_pipeline,
1315 #[cfg(not(target_arch = "wasm32"))]
1316 ffn_fused_coop_pipeline,
1317 #[cfg(not(target_arch = "wasm32"))]
1318 ffn_fused_mr_pipeline,
1319 #[cfg(not(target_arch = "wasm32"))]
1320 ffn_fused_warp_pipeline,
1321 #[cfg(not(target_arch = "wasm32"))]
1322 dual_gemv_pipeline,
1323 #[cfg(not(target_arch = "wasm32"))]
1324 dual_gemv_mr_pipeline,
1325 #[cfg(not(target_arch = "wasm32"))]
1326 dual_gemv_bind_layout,
1327 #[cfg(not(target_arch = "wasm32"))]
1328 triple_gemv_pipeline,
1329 #[cfg(not(target_arch = "wasm32"))]
1330 triple_gemv_bind_layout,
1331 mc8_logits_resident_buf: None,
1332 mc8_logits_row_bytes: 0,
1333 #[cfg(not(target_arch = "wasm32"))]
1334 ternary_ffn: None,
1335 #[cfg(not(target_arch = "wasm32"))]
1336 resident_decode: super::resident_decode::ResidentDecodeState::Unbuilt,
1337 #[cfg(all(not(target_arch = "wasm32"), feature = "cuda"))]
1338 cuda_decode_plan: super::cuda_decode_plan::CudaDecodePlanState::Unbuilt,
1339 #[cfg(not(target_arch = "wasm32"))]
1340 prefill_arena: super::prefill_arena::PrefillArenaState::Unbuilt,
1341 #[cfg(not(target_arch = "wasm32"))]
1342 verify_arena: super::verify_arena::VerifyArenaState::Unbuilt,
1343 #[cfg(not(target_arch = "wasm32"))]
1344 gemm_resident_weights: std::sync::Mutex::new(std::collections::HashMap::new()),
1345 #[cfg(not(target_arch = "wasm32"))]
1346 ffn_fused_params: None,
1347 #[cfg(not(target_arch = "wasm32"))]
1348 attention_kv_gemm_params: Some(attention_kv_gemm_params),
1349 #[cfg(not(target_arch = "wasm32"))]
1350 attention_kv_params: Some(attention_kv_params),
1351 #[cfg(target_arch = "wasm32")]
1352 mc8_norm_resident_buf: None,
1353 #[cfg(target_arch = "wasm32")]
1354 mc8_norm_stride: 0,
1355 #[cfg(target_arch = "wasm32")]
1356 mc8_bg_cache: std::sync::Mutex::new(std::collections::HashMap::new()),
1357 };
1358 let mut relu_probe = [-1.0f32, 2.0];
1361 let _ =
1362 super::cpu_ops::apply_cpu_elem_op(super::gpu_params::ELEM_OP_RELU, &mut relu_probe, 2);
1363 let _ = super::gpu_params::elem_op_label(super::gpu_params::ELEM_OP_RMS_NORM);
1364 let _ = engine.elem_gpu_pipeline(super::gpu_params::ELEM_OP_RMS_NORM);
1365 let _ = engine.elem_gpu_pipeline(super::gpu_params::ELEM_OP_ADD_RESIDUAL);
1366 Ok(engine)
1367 }
1368
1369 #[cfg(not(target_arch = "wasm32"))]
1370 pub fn new() -> Self {
1371 let handle = tokio::runtime::Handle::try_current().unwrap_or_else(|_| {
1372 let rt = Box::leak(Box::new(tokio::runtime::Runtime::new().unwrap()));
1373 rt.handle().clone()
1374 });
1375 tokio::task::block_in_place(|| {
1376 handle
1377 .block_on(Self::try_new())
1378 .expect("Failed to initialize native GGUF engine")
1379 })
1380 }
1381
1382 pub(crate) fn ensure_kv_cache(&mut self, h: &crate::gguf_sharder::GgufHyperparams) {
1383 let layout = match KvCacheLayout::from_hyperparams(h) {
1384 Some(l) => l,
1385 None => {
1386 #[cfg(target_arch = "wasm32")]
1387 wlog(
1388 "[kv_cache] FAILED from_hyperparams (zero dims or exceeds KV_CACHE_MAX_BYTES)",
1389 );
1390 return;
1391 }
1392 };
1393 let bytes = (layout.total_f32_elems * std::mem::size_of::<f32>()) as wgpu::BufferAddress;
1394 #[cfg(not(target_arch = "wasm32"))]
1397 {
1398 let ledger = crate::gpu_context::global_vram_ledger();
1399 let orch = crate::gpu_context::universe_orchestrator();
1400 if !ledger.can_allocate_in_universe(
1401 &orch,
1402 crate::gpu_context::ComputeUniverse::LlmInference,
1403 bytes,
1404 ) {
1405 log::warn!(
1406 "LLM_LOAD|kv-cache|denied|U0 budget {:.1} MiB used, need {:.1} MiB (mode {:?})",
1407 ledger.universe_used_bytes(crate::gpu_context::ComputeUniverse::LlmInference)
1408 as f64
1409 / (1024.0 * 1024.0),
1410 bytes as f64 / (1024.0 * 1024.0),
1411 orch.active_mode,
1412 );
1413 return;
1414 }
1415 }
1416 let gpu = self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1417 label: Some("StaticKvCacheArena"),
1418 size: bytes.max(4),
1419 usage: wgpu::BufferUsages::STORAGE
1421 | wgpu::BufferUsages::COPY_DST
1422 | wgpu::BufferUsages::COPY_SRC,
1423 mapped_at_creation: false,
1424 });
1425 let cpu = vec![0f32; layout.total_f32_elems].into_boxed_slice();
1426 let attn_params_bytes = {
1427 #[cfg(target_arch = "wasm32")]
1428 {
1429 (MC8_MAX_ATTN_UNIFORM_CHUNK_SLOTS * MC8_UNIFORM_ALIGN) as wgpu::BufferAddress
1430 }
1431 #[cfg(not(target_arch = "wasm32"))]
1432 {
1433 std::mem::size_of::<AttentionGpuParams>() as wgpu::BufferAddress
1434 }
1435 };
1436 self.attention_params_buf =
1437 Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1438 label: Some("AttentionParams"),
1439 size: attn_params_bytes.max(4),
1440 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
1441 mapped_at_creation: false,
1442 }));
1443 let mask_bytes = (MAX_ATTN_MASK_UPLOAD_WORDS * std::mem::size_of::<u32>()).max(4);
1444 self.attention_mask_buf = Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1445 label: Some("AttentionKvMaskBatch"),
1446 size: mask_bytes as wgpu::BufferAddress,
1447 usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
1448 mapped_at_creation: false,
1449 }));
1450 self.kv_layout = Some(layout);
1451 self.kv_cache_gpu = Some(gpu);
1452 self.kv_cache_cpu = Some(cpu);
1453 #[cfg(not(target_arch = "wasm32"))]
1455 self.upload_dict_atoms();
1456 #[cfg(not(target_arch = "wasm32"))]
1457 {
1458 let ledger = crate::gpu_context::global_vram_ledger();
1459 ledger.record_kv_cache(bytes);
1460 }
1461 log::info!(
1462 "LLM_LOAD|kv-cache|0.86|Reserved {:.1} MiB KV cache (GPU + CPU mirror, context {})",
1463 bytes as f64 / (1024.0 * 1024.0),
1464 layout.max_context,
1465 );
1466 #[cfg(not(target_arch = "wasm32"))]
1467 eprintln!(
1468 "[gguf_bridge] KV arena {} slots ({:.1} MiB, {}), context={}",
1469 layout.total_f32_elems,
1470 bytes as f64 / (1024.0 * 1024.0),
1471 if layout.dict_k > 0 {
1472 "dict-coded"
1473 } else if layout.int8 {
1474 "int8+scale"
1475 } else {
1476 "f32"
1477 },
1478 layout.max_context,
1479 );
1480 }
1481
1482 pub fn reset_kv_cache(&mut self) {
1484 let Some(layout) = self.kv_layout.as_ref() else {
1485 return;
1486 };
1487 let n = layout.total_f32_elems;
1488 if let Some(cpu) = self.kv_cache_cpu.as_mut() {
1489 for v in cpu.iter_mut().take(n) {
1490 unsafe { core::ptr::write_volatile(v, 0.0) };
1491 }
1492 }
1493 if let (Some(cpu), Some(gpu)) = (self.kv_cache_cpu.as_ref(), self.kv_cache_gpu.as_ref()) {
1494 self.gpu_queue()
1495 .write_buffer(gpu, 0, bytemuck::cast_slice(&cpu[..n]));
1496 }
1497 #[cfg(not(target_arch = "wasm32"))]
1499 self.upload_dict_atoms();
1500 }
1501
1502 #[cfg(not(target_arch = "wasm32"))]
1505 pub(crate) fn upload_dict_atoms(&self) {
1506 let Some(layout) = self.kv_layout.as_ref() else {
1507 return;
1508 };
1509 if layout.dict_k == 0 {
1510 return;
1511 }
1512 let (Some(buf), Some((flat, na, hd))) = (
1513 self.kv_cache_gpu.as_ref(),
1514 crate::kv_dict_runtime::atoms_flat(),
1515 ) else {
1516 return;
1517 };
1518 let code_region = (layout.max_context * 2 * layout.n_kv_head * layout.dict_k) as usize;
1519 let per_layer_atoms = 2 * na * hd;
1520 let ls = layout.layer_stride as usize;
1521 for l in 0..layout.n_layer as usize {
1522 let s = l * per_layer_atoms;
1523 let e = ((l + 1) * per_layer_atoms).min(flat.len());
1524 if e <= s {
1525 break;
1526 }
1527 let dst_word = l * ls + code_region;
1528 self.gpu_queue().write_buffer(
1529 buf,
1530 (dst_word * 4) as u64,
1531 bytemuck::cast_slice(&flat[s..e]),
1532 );
1533 }
1534 }
1535
1536 pub fn get_kv_cache_cpu(&self) -> Option<&[f32]> {
1537 self.kv_cache_cpu.as_deref()
1538 }
1539
1540 pub fn set_kv_cache_cpu(&mut self, data: &[f32]) {
1541 let Some(layout) = self.kv_layout.as_ref() else {
1542 return;
1543 };
1544 let n = layout.total_f32_elems;
1545 if data.len() < n {
1546 return;
1547 }
1548 if let Some(cpu) = self.kv_cache_cpu.as_mut() {
1549 cpu[..n].copy_from_slice(&data[..n]);
1550 }
1551 if let (Some(cpu), Some(gpu)) = (self.kv_cache_cpu.as_ref(), self.kv_cache_gpu.as_ref()) {
1552 self.gpu_queue()
1553 .write_buffer(gpu, 0, bytemuck::cast_slice(&cpu[..n]));
1554 }
1555 }
1556
1557 #[cfg(not(target_arch = "wasm32"))]
1562 pub fn read_kv_cache_gpu(&self) -> Option<Vec<f32>> {
1563 let gpu = self.kv_cache_gpu.as_ref()?;
1564 let layout = self.kv_layout.as_ref()?;
1565 if layout.int8 {
1566 return None;
1567 }
1568 let n = layout.total_f32_elems;
1569 let size = (n * std::mem::size_of::<f32>()) as wgpu::BufferAddress;
1570 let staging = self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1571 label: Some("KvCacheReadback"),
1572 size: size.max(4),
1573 usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
1574 mapped_at_creation: false,
1575 });
1576 let mut encoder =
1577 self.gpu_device()
1578 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
1579 label: Some("KvReadback"),
1580 });
1581 encoder.copy_buffer_to_buffer(gpu, 0, &staging, 0, size);
1582 self.gpu_queue().submit(Some(encoder.finish()));
1583
1584 let slice = staging.slice(..);
1585 let (tx, rx) = futures_channel::oneshot::channel();
1586 slice.map_async(wgpu::MapMode::Read, move |v| {
1587 let _ = tx.send(v);
1588 });
1589 self.poll_wait();
1590 let handle = tokio::runtime::Handle::try_current().unwrap_or_else(|_| {
1591 let rt = Box::leak(Box::new(tokio::runtime::Runtime::new().unwrap()));
1592 rt.handle().clone()
1593 });
1594 if handle.block_on(rx).ok()?.is_err() {
1595 return None;
1596 }
1597 let data = slice
1598 .get_mapped_range()
1599 .expect("wgpu buffer map_range failed");
1600 let out: Vec<f32> = bytemuck::cast_slice(&data).to_vec();
1601 drop(data);
1602 staging.unmap();
1603 Some(out)
1604 }
1605
1606 #[cfg(not(target_arch = "wasm32"))]
1611 pub fn capture_kv_f32(
1612 &self,
1613 n_tokens: u32,
1614 max_per_layer: usize,
1615 ) -> Option<crate::kv_capture::KvCapture> {
1616 let layout = *self.kv_layout.as_ref()?;
1617 let flat = self.read_kv_cache_gpu()?;
1618 let n_layer = layout.n_layer as usize;
1619 let n_kv = layout.n_kv_head as usize;
1620 let head_dim = layout.head_dim as usize;
1621 if head_dim == 0 || n_kv == 0 || n_layer == 0 {
1622 return None;
1623 }
1624 let take = (n_tokens as usize).min(layout.max_context as usize);
1625 let mut k = vec![Vec::new(); n_layer];
1626 let mut v = vec![Vec::new(); n_layer];
1627 let read_vec = |base_of: &dyn Fn(u32) -> usize| -> Option<Vec<f32>> {
1628 let mut out = Vec::with_capacity(head_dim);
1629 for d in 0..head_dim {
1630 let idx = base_of(d as u32);
1631 if idx >= flat.len() {
1632 return None;
1633 }
1634 out.push(flat[idx]);
1635 }
1636 Some(out)
1637 };
1638 for l in 0..n_layer {
1639 for pos in 0..take {
1640 let slot = layout.ring_slot(pos as u32);
1641 for hkv in 0..n_kv {
1642 if k[l].len() < max_per_layer {
1643 if let Some(vec_k) =
1644 read_vec(&|d| layout.k_index(l as u32, slot, hkv as u32, d))
1645 {
1646 k[l].push(vec_k);
1647 }
1648 }
1649 if v[l].len() < max_per_layer {
1650 if let Some(vec_v) =
1651 read_vec(&|d| layout.v_index(l as u32, slot, hkv as u32, d))
1652 {
1653 v[l].push(vec_v);
1654 }
1655 }
1656 }
1657 }
1658 }
1659 Some(crate::kv_capture::KvCapture { head_dim, k, v })
1660 }
1661
1662 pub(crate) fn ensure_gemm_buffers(&mut self, max_weight_bytes: usize, max_out_dim: u32) {
1663 if self.output_topk_pipeline.is_none() {
1666 self.init_output_topk();
1667 }
1668 let need_input = MAX_STACK_GEMM_IN.max(MAX_PREFILL_BATCH_FLOATS);
1669 let prefill_bufs_ready = {
1670 #[cfg(target_arch = "wasm32")]
1671 {
1672 self.prefill_scratch_buf.is_some()
1673 && self.prefill_work_buf_a.is_some()
1674 && self.prefill_work_buf_b.is_some()
1675 }
1676 #[cfg(not(target_arch = "wasm32"))]
1677 {
1678 true
1679 }
1680 };
1681 #[cfg(target_arch = "wasm32")]
1682 let weight_arena_ready = self.mc8_weight_arena.is_some();
1683 #[cfg(not(target_arch = "wasm32"))]
1684 let weight_arena_ready = true;
1685 if self.gemm_weight_buf.is_some()
1686 && max_weight_bytes <= self.max_tensor_bytes
1687 && self.gemm_max_input_floats >= need_input
1688 && prefill_bufs_ready
1689 && weight_arena_ready
1690 {
1691 return;
1692 }
1693 let w_bytes = max_weight_bytes.max(4) as wgpu::BufferAddress;
1694 let in_bytes = (need_input * 4) as wgpu::BufferAddress;
1695 let out_bytes = (max_out_dim as usize * 4).max(4) as wgpu::BufferAddress;
1696 self.gemm_input_buf = Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1697 label: Some("LayerGemmInput"),
1698 size: in_bytes,
1699 usage: wgpu::BufferUsages::STORAGE
1700 | wgpu::BufferUsages::COPY_DST
1701 | wgpu::BufferUsages::COPY_SRC,
1702 mapped_at_creation: false,
1703 }));
1704 self.gemm_weight_buf = Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1705 label: Some("LayerGemmWeight"),
1706 size: w_bytes,
1707 usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
1708 mapped_at_creation: false,
1709 }));
1710 #[cfg(target_arch = "wasm32")]
1711 {
1712 let weight_usage = wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST;
1713 let arena_min = 4u64;
1718 let mk_arena = |label: &str| {
1719 self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1720 label: Some(label),
1721 size: arena_min,
1722 usage: weight_usage,
1723 mapped_at_creation: false,
1724 })
1725 };
1726 let qkv_k = mk_arena("MC8WeightAttnK");
1727 let qkv_v = mk_arena("MC8WeightAttnV");
1728 let qkv_q = mk_arena("MC8WeightAttnQ");
1729 let o_proj = mk_arena("MC8WeightOProj");
1730 let gate = mk_arena("MC8WeightGate");
1731 let up = mk_arena("MC8WeightUp");
1732 let down = mk_arena("MC8WeightDown");
1733 self.mc8_weight_arena = Some(Mc8WeightArenaBufs {
1734 qkv_k,
1735 qkv_v,
1736 qkv_q,
1737 o_proj,
1738 gate,
1739 up,
1740 down,
1741 });
1742 self.gemm_weight_buf_b =
1745 Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1746 label: Some("LayerGemmWeightB"),
1747 size: arena_min,
1748 usage: weight_usage,
1749 mapped_at_creation: false,
1750 }));
1751 }
1752 self.gemm_output_buf = Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1753 label: Some("LayerGemmOutput"),
1754 size: out_bytes,
1755 usage: wgpu::BufferUsages::STORAGE
1756 | wgpu::BufferUsages::COPY_SRC
1757 | wgpu::BufferUsages::COPY_DST,
1758 mapped_at_creation: false,
1759 }));
1760 let gemm_params_bytes = {
1761 #[cfg(target_arch = "wasm32")]
1762 {
1763 (MC8_MAX_GEMM_UNIFORM_CHUNK_SLOTS * MC8_UNIFORM_ALIGN) as wgpu::BufferAddress
1764 }
1765 #[cfg(not(target_arch = "wasm32"))]
1766 {
1767 std::mem::size_of::<GemmGpuParams>() as wgpu::BufferAddress
1768 }
1769 };
1770 self.gemm_params_buf = Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1771 label: Some("LayerGemmParams"),
1772 size: gemm_params_bytes.max(4),
1773 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
1774 mapped_at_creation: false,
1775 }));
1776 #[cfg(target_arch = "wasm32")]
1777 let staging_bytes = out_bytes.max((65536 * 4) as wgpu::BufferAddress);
1778 #[cfg(not(target_arch = "wasm32"))]
1779 let staging_bytes = out_bytes;
1780 self.gemm_output_staging = Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1781 label: Some("LayerGemmStaging"),
1782 size: staging_bytes,
1783 usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
1784 mapped_at_creation: false,
1785 }));
1786 self.gemm_aux_buf = Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1787 label: Some("LayerGemmAux"),
1788 size: out_bytes,
1789 usage: wgpu::BufferUsages::STORAGE
1790 | wgpu::BufferUsages::COPY_DST
1791 | wgpu::BufferUsages::COPY_SRC,
1792 mapped_at_creation: false,
1793 }));
1794 self.gemm_ffn_buf = Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1795 label: Some("LayerGemmFfnUp"),
1796 size: out_bytes,
1797 usage: wgpu::BufferUsages::STORAGE
1798 | wgpu::BufferUsages::COPY_DST
1799 | wgpu::BufferUsages::COPY_SRC,
1800 mapped_at_creation: false,
1801 }));
1802 #[cfg(target_arch = "wasm32")]
1803 {
1804 self.prefill_scratch_buf =
1805 Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1806 label: Some("PrefillBatchScratch"),
1807 size: in_bytes,
1808 usage: wgpu::BufferUsages::STORAGE
1809 | wgpu::BufferUsages::COPY_DST
1810 | wgpu::BufferUsages::COPY_SRC,
1811 mapped_at_creation: false,
1812 }));
1813 let work_row_floats =
1815 (MAX_HIDDEN_DIM + 2 * max_out_dim as usize + MAX_HIDDEN_DIM).max(4);
1816 let work_bytes =
1817 (PREFILL_CHUNK_SIZE * work_row_floats * 4).max(4) as wgpu::BufferAddress;
1818 let work_usage = wgpu::BufferUsages::STORAGE
1819 | wgpu::BufferUsages::COPY_DST
1820 | wgpu::BufferUsages::COPY_SRC;
1821 self.prefill_work_buf_a =
1822 Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1823 label: Some("PrefillBatchWorkA"),
1824 size: work_bytes,
1825 usage: work_usage,
1826 mapped_at_creation: false,
1827 }));
1828 self.prefill_work_buf_b =
1829 Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1830 label: Some("PrefillBatchWorkB"),
1831 size: work_bytes,
1832 usage: work_usage,
1833 mapped_at_creation: false,
1834 }));
1835 self.mc8_q_proj_buf = Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1837 label: Some("MC8QProj"),
1838 size: work_bytes,
1839 usage: work_usage,
1840 mapped_at_creation: false,
1841 }));
1842 self.mc8_k_proj_buf = Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1843 label: Some("MC8KProj"),
1844 size: work_bytes,
1845 usage: work_usage,
1846 mapped_at_creation: false,
1847 }));
1848 self.mc8_v_proj_buf = Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1849 label: Some("MC8VProj"),
1850 size: work_bytes,
1851 usage: work_usage,
1852 mapped_at_creation: false,
1853 }));
1854 }
1855 let elem_params_bytes = {
1856 #[cfg(target_arch = "wasm32")]
1857 {
1858 (MC8_MAX_ELEM_UNIFORM_CHUNK_SLOTS * MC8_UNIFORM_ALIGN) as wgpu::BufferAddress
1859 }
1860 #[cfg(not(target_arch = "wasm32"))]
1861 {
1862 std::mem::size_of::<ElemGpuParams>() as wgpu::BufferAddress
1863 }
1864 };
1865 self.elem_params_buf = Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1866 label: Some("ElemParams"),
1867 size: elem_params_bytes.max(4),
1868 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
1869 mapped_at_creation: false,
1870 }));
1871 let norm_bytes = (MAX_HIDDEN_DIM * 4) as wgpu::BufferAddress;
1872 self.norm_weight_buf = Some(self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
1873 label: Some("NormWeights"),
1874 size: norm_bytes.max(4),
1875 usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
1876 mapped_at_creation: false,
1877 }));
1878 self.gemm_max_out_dim = max_out_dim;
1879 self.gemm_max_input_floats = need_input;
1880 self.max_tensor_bytes = max_weight_bytes;
1881 }
1882}