fuzzgpu 0.1.1__tar.gz → 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/Cargo.lock +2 -2
  2. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/PKG-INFO +3 -3
  3. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/README.md +2 -2
  4. fuzzgpu-0.1.2/assets/banner.svg +66 -0
  5. fuzzgpu-0.1.2/assets/github-stats.svg +51 -0
  6. fuzzgpu-0.1.2/assets/top-languages.svg +62 -0
  7. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/crates/fuzzgpu-core/Cargo.toml +1 -1
  8. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/crates/fuzzgpu-core/src/damerau.rs +2 -1
  9. fuzzgpu-0.1.2/crates/fuzzgpu-core/src/gpu.rs +151 -0
  10. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/crates/fuzzgpu-core/src/jaro.rs +91 -46
  11. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/crates/fuzzgpu-core/src/levenshtein.rs +58 -31
  12. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/crates/fuzzgpu-core/src/needleman.rs +8 -8
  13. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/crates/fuzzgpu-python/Cargo.toml +2 -2
  14. fuzzgpu-0.1.2/crates/fuzzgpu-python/src/lib.rs +442 -0
  15. fuzzgpu-0.1.2/crates/fuzzgpu-wasm/Cargo.toml +19 -0
  16. fuzzgpu-0.1.2/crates/fuzzgpu-wasm/src/lib.rs +92 -0
  17. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/pyproject.toml +2 -2
  18. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/python/fuzzgpu/__init__.py +21 -11
  19. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/python/fuzzgpu/fuzz.py +13 -2
  20. fuzzgpu-0.1.2/tests/test_api_signatures.py +171 -0
  21. fuzzgpu-0.1.2/tests/test_basic.py +323 -0
  22. fuzzgpu-0.1.2/tests/test_concurrency.py +62 -0
  23. fuzzgpu-0.1.2/tests/test_edge_cases.py +338 -0
  24. fuzzgpu-0.1.2/tests/test_invariants.py +169 -0
  25. fuzzgpu-0.1.2/tests/test_stress.py +123 -0
  26. fuzzgpu-0.1.1/crates/fuzzgpu-core/src/gpu.rs +0 -96
  27. fuzzgpu-0.1.1/crates/fuzzgpu-python/src/lib.rs +0 -276
  28. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/Cargo.toml +0 -0
  29. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/LICENSE +0 -0
  30. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/assets/logo.png +0 -0
  31. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/assets/logo.svg +0 -0
  32. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/crates/fuzzgpu-core/src/fuzz.rs +0 -0
  33. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/crates/fuzzgpu-core/src/lib.rs +0 -0
  34. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/crates/fuzzgpu-core/src/shaders/jaro.wgsl +0 -0
  35. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/crates/fuzzgpu-core/src/shaders/jaro_matrix.wgsl +0 -0
  36. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/crates/fuzzgpu-core/src/shaders/levenshtein.wgsl +0 -0
  37. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/crates/fuzzgpu-core/src/shaders/levenshtein_matrix.wgsl +0 -0
  38. {fuzzgpu-0.1.1 → fuzzgpu-0.1.2}/crates/fuzzgpu-core/src/simd.rs +0 -0
@@ -248,7 +248,7 @@ dependencies = [
248
248
 
249
249
  [[package]]
250
250
  name = "fuzzgpu-core"
251
- version = "0.1.1"
251
+ version = "0.1.2"
252
252
  dependencies = [
253
253
  "bytemuck",
254
254
  "log",
@@ -260,7 +260,7 @@ dependencies = [
260
260
 
261
261
  [[package]]
262
262
  name = "fuzzgpu-python"
263
- version = "0.1.1"
263
+ version = "0.1.2"
264
264
  dependencies = [
265
265
  "fuzzgpu-core",
266
266
  "pollster",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fuzzgpu
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -35,7 +35,7 @@ Project-URL: Repository, https://github.com/kuntal-devrat/fuzzgpu
35
35
 
36
36
  *Cross-platform GPU compute via WebGPU (`wgpu`) & Multi-Core CPU parallelism with Rayon. Zero CUDA dependencies.*
37
37
 
38
- [![PyPI Version](https://img.shields.io/badge/pypi-v0.1.1-blue.svg?style=flat-square)](https://pypi.org/project/fuzzgpu/)
38
+ [![PyPI Version](https://img.shields.io/badge/pypi-v0.1.2-blue.svg?style=flat-square)](https://pypi.org/project/fuzzgpu/)
39
39
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?style=flat-square)](https://opensource.org/licenses/MIT)
40
40
  [![Rust](https://img.shields.io/badge/rust-1.75+-orange.svg?style=flat-square)](https://www.rust-lang.org)
41
41
  [![Cross Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux%20%7C%20WASM-lightgrey.svg?style=flat-square)](https://github.com/kuntal-devrat/fuzzgpu)
@@ -100,7 +100,7 @@ pip install fuzzgpu
100
100
  ### Rust (Cargo.toml)
101
101
  ```toml
102
102
  [dependencies]
103
- fuzzgpu-core = "0.1.1"
103
+ fuzzgpu-core = "0.1.2"
104
104
  ```
105
105
 
106
106
  ---
@@ -8,7 +8,7 @@
8
8
 
9
9
  *Cross-platform GPU compute via WebGPU (`wgpu`) & Multi-Core CPU parallelism with Rayon. Zero CUDA dependencies.*
10
10
 
11
- [![PyPI Version](https://img.shields.io/badge/pypi-v0.1.1-blue.svg?style=flat-square)](https://pypi.org/project/fuzzgpu/)
11
+ [![PyPI Version](https://img.shields.io/badge/pypi-v0.1.2-blue.svg?style=flat-square)](https://pypi.org/project/fuzzgpu/)
12
12
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?style=flat-square)](https://opensource.org/licenses/MIT)
13
13
  [![Rust](https://img.shields.io/badge/rust-1.75+-orange.svg?style=flat-square)](https://www.rust-lang.org)
14
14
  [![Cross Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux%20%7C%20WASM-lightgrey.svg?style=flat-square)](https://github.com/kuntal-devrat/fuzzgpu)
@@ -73,7 +73,7 @@ pip install fuzzgpu
73
73
  ### Rust (Cargo.toml)
74
74
  ```toml
75
75
  [dependencies]
76
- fuzzgpu-core = "0.1.1"
76
+ fuzzgpu-core = "0.1.2"
77
77
  ```
78
78
 
79
79
  ---
@@ -0,0 +1,66 @@
1
+ <svg width="850" height="200" viewBox="0 0 850 200" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <linearGradient id="bg_grad" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" stop-color="#0B0F19" />
5
+ <stop offset="50%" stop-color="#111827" />
6
+ <stop offset="100%" stop-color="#0D1117" />
7
+ </linearGradient>
8
+ <linearGradient id="accent_grad" x1="0%" y1="0%" x2="100%" y2="0%">
9
+ <stop offset="0%" stop-color="#38BDF8" />
10
+ <stop offset="50%" stop-color="#818CF8" />
11
+ <stop offset="100%" stop-color="#C084FC" />
12
+ </linearGradient>
13
+ <linearGradient id="wave1" x1="0%" y1="0%" x2="100%" y2="0%">
14
+ <stop offset="0%" stop-color="#007ec6" stop-opacity="0.3" />
15
+ <stop offset="50%" stop-color="#8B5CF6" stop-opacity="0.4" />
16
+ <stop offset="100%" stop-color="#EC4899" stop-opacity="0.2" />
17
+ </linearGradient>
18
+ <linearGradient id="wave2" x1="0%" y1="0%" x2="100%" y2="0%">
19
+ <stop offset="0%" stop-color="#38BDF8" stop-opacity="0.15" />
20
+ <stop offset="100%" stop-color="#818CF8" stop-opacity="0.2" />
21
+ </linearGradient>
22
+ <filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
23
+ <feGaussianBlur stdDeviation="6" result="blur" />
24
+ <feComposite in="SourceGraphic" in2="blur" operator="over" />
25
+ </filter>
26
+ </defs>
27
+
28
+ <!-- Background Card -->
29
+ <rect width="850" height="200" rx="16" fill="url(#bg_grad)" stroke="#30363D" stroke-width="1.5" />
30
+
31
+ <!-- Ambient Wave Layer -->
32
+ <path d="M0 130 C 200 90, 350 170, 550 120 C 700 80, 780 140, 850 110 L 850 200 L 0 200 Z" fill="url(#wave1)" />
33
+ <path d="M0 150 C 180 120, 380 180, 580 140 C 720 110, 800 160, 850 140 L 850 200 L 0 200 Z" fill="url(#wave2)" />
34
+
35
+ <!-- Neon Accent Line Top -->
36
+ <rect x="0" y="0" width="850" height="3" rx="1.5" fill="url(#accent_grad)" />
37
+
38
+ <!-- Title Text -->
39
+ <text x="425" y="78" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Inter', sans-serif" font-size="38" font-weight="800" fill="#F0F6FC" letter-spacing="1">
40
+ Devrat Kuntal
41
+ </text>
42
+
43
+ <!-- Subtitle / Tagline -->
44
+ <text x="425" y="112" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Inter', sans-serif" font-size="15" font-weight="600" fill="#38BDF8" letter-spacing="0.5">
45
+ ⚡ AI ARCHITECT | HIGH-PERFORMANCE SYSTEMS &amp; GPU COMPUTE ENGINEER
46
+ </text>
47
+
48
+ <!-- Tech tags pill badges -->
49
+ <g transform="translate(195, 140)">
50
+ <!-- Pill 1: WebGPU / WGSL -->
51
+ <rect x="0" y="0" width="105" height="24" rx="12" fill="#1F2937" stroke="#38BDF8" stroke-width="1" />
52
+ <text x="52.5" y="16" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="11" font-weight="600" fill="#E0F2FE">⚡ WebGPU/WGSL</text>
53
+
54
+ <!-- Pill 2: Rust SIMD -->
55
+ <rect x="115" y="0" width="95" height="24" rx="12" fill="#1F2937" stroke="#DEA584" stroke-width="1" />
56
+ <text x="162.5" y="16" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="11" font-weight="600" fill="#FFEDD5">🦀 Rust SIMD</text>
57
+
58
+ <!-- Pill 3: PyO3 ABI3 -->
59
+ <rect x="220" y="0" width="95" height="24" rx="12" fill="#1F2937" stroke="#818CF8" stroke-width="1" />
60
+ <text x="267.5" y="16" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="11" font-weight="600" fill="#E0E7FF">🐍 PyO3 ABI3</text>
61
+
62
+ <!-- Pill 4: AI Agent Runtimes -->
63
+ <rect x="325" y="0" width="135" height="24" rx="12" fill="#1F2937" stroke="#EC4899" stroke-width="1" />
64
+ <text x="392.5" y="16" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="11" font-weight="600" fill="#FCE7F3">🤖 AI Agent Runtimes</text>
65
+ </g>
66
+ </svg>
@@ -0,0 +1,51 @@
1
+ <svg width="415" height="195" viewBox="0 0 415 195" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <linearGradient id="card_bg" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" stop-color="#0D1117" />
5
+ <stop offset="100%" stop-color="#161B22" />
6
+ </linearGradient>
7
+ <linearGradient id="icon_grad" x1="0%" y1="0%" x2="100%" y2="100%">
8
+ <stop offset="0%" stop-color="#38BDF8" />
9
+ <stop offset="100%" stop-color="#8B5CF6" />
10
+ </linearGradient>
11
+ </defs>
12
+
13
+ <rect width="415" height="195" rx="12" fill="url(#card_bg)" stroke="#30363D" stroke-width="1" />
14
+
15
+ <!-- Header -->
16
+ <text x="25" y="35" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif" font-size="18" font-weight="700" fill="#38BDF8">
17
+ GitHub Analytics
18
+ </text>
19
+
20
+ <!-- Metric 1: Total Stars -->
21
+ <g transform="translate(25, 60)">
22
+ <circle cx="10" cy="10" r="10" fill="#1F2937" />
23
+ <text x="10" y="14" text-anchor="middle" font-size="11">⭐</text>
24
+ <text x="30" y="15" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="500" fill="#94A3B8">Total Stars Earned:</text>
25
+ <text x="365" y="15" text-anchor="end" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="14" font-weight="700" fill="#F0F6FC">4</text>
26
+ </g>
27
+
28
+ <!-- Metric 2: Total Commits (2025/2026) -->
29
+ <g transform="translate(25, 90)">
30
+ <circle cx="10" cy="10" r="10" fill="#1F2937" />
31
+ <text x="10" y="14" text-anchor="middle" font-size="11">⚡</text>
32
+ <text x="30" y="15" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="500" fill="#94A3B8">Total Commits (Recent):</text>
33
+ <text x="365" y="15" text-anchor="end" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="14" font-weight="700" fill="#F0F6FC">335+</text>
34
+ </g>
35
+
36
+ <!-- Metric 3: Total PRs -->
37
+ <g transform="translate(25, 120)">
38
+ <circle cx="10" cy="10" r="10" fill="#1F2937" />
39
+ <text x="10" y="14" text-anchor="middle" font-size="11">🔀</text>
40
+ <text x="30" y="15" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="500" fill="#94A3B8">Pull Requests:</text>
41
+ <text x="365" y="15" text-anchor="end" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="14" font-weight="700" fill="#F0F6FC">12</text>
42
+ </g>
43
+
44
+ <!-- Metric 4: Total Repositories -->
45
+ <g transform="translate(25, 150)">
46
+ <circle cx="10" cy="10" r="10" fill="#1F2937" />
47
+ <text x="10" y="14" text-anchor="middle" font-size="11">📦</text>
48
+ <text x="30" y="15" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="500" fill="#94A3B8">Active Repositories:</text>
49
+ <text x="365" y="15" text-anchor="end" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="14" font-weight="700" fill="#F0F6FC">26</text>
50
+ </g>
51
+ </svg>
@@ -0,0 +1,62 @@
1
+ <svg width="415" height="195" viewBox="0 0 415 195" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <linearGradient id="lang_bg" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" stop-color="#0D1117" />
5
+ <stop offset="100%" stop-color="#161B22" />
6
+ </linearGradient>
7
+ <clipPath id="bar_clip">
8
+ <rect x="25" y="55" width="365" height="9" rx="4.5" />
9
+ </clipPath>
10
+ </defs>
11
+
12
+ <rect width="415" height="195" rx="12" fill="url(#lang_bg)" stroke="#30363D" stroke-width="1" />
13
+
14
+ <!-- Header -->
15
+ <text x="25" y="35" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif" font-size="18" font-weight="700" fill="#38BDF8">
16
+ Most Used Languages
17
+ </text>
18
+
19
+ <!-- Stacked Bar -->
20
+ <g clip-path="url(#bar_clip)">
21
+ <rect x="25.0" y="55" width="169.3" height="9" fill="#3178c6" />
22
+ <rect x="194.3" y="55" width="75.4" height="9" fill="#f1e05a" />
23
+ <rect x="269.7" y="55" width="37.0" height="9" fill="#3572A5" />
24
+ <rect x="306.7" y="55" width="28.1" height="9" fill="#dea584" />
25
+ <rect x="334.8" y="55" width="25.4" height="9" fill="#663399" />
26
+ <rect x="360.2" y="55" width="7.9" height="9" fill="#A97BFF" />
27
+
28
+ </g>
29
+
30
+ <!-- Language List -->
31
+
32
+ <g transform="translate(25, 90)">
33
+ <circle cx="6" cy="6" r="5" fill="#3178c6" />
34
+ <text x="20" y="10" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="500" fill="#94A3B8">TypeScript</text>
35
+ <text x="160" y="10" text-anchor="end" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="600" fill="#F0F6FC">46.4%</text>
36
+ </g>
37
+ <g transform="translate(25, 118)">
38
+ <circle cx="6" cy="6" r="5" fill="#f1e05a" />
39
+ <text x="20" y="10" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="500" fill="#94A3B8">JavaScript</text>
40
+ <text x="160" y="10" text-anchor="end" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="600" fill="#F0F6FC">20.7%</text>
41
+ </g>
42
+ <g transform="translate(25, 146)">
43
+ <circle cx="6" cy="6" r="5" fill="#3572A5" />
44
+ <text x="20" y="10" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="500" fill="#94A3B8">Python</text>
45
+ <text x="160" y="10" text-anchor="end" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="600" fill="#F0F6FC">10.1%</text>
46
+ </g>
47
+ <g transform="translate(215, 90)">
48
+ <circle cx="6" cy="6" r="5" fill="#dea584" />
49
+ <text x="20" y="10" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="500" fill="#94A3B8">Rust</text>
50
+ <text x="160" y="10" text-anchor="end" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="600" fill="#F0F6FC">7.7%</text>
51
+ </g>
52
+ <g transform="translate(215, 118)">
53
+ <circle cx="6" cy="6" r="5" fill="#663399" />
54
+ <text x="20" y="10" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="500" fill="#94A3B8">CSS</text>
55
+ <text x="160" y="10" text-anchor="end" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="600" fill="#F0F6FC">7.0%</text>
56
+ </g>
57
+ <g transform="translate(215, 146)">
58
+ <circle cx="6" cy="6" r="5" fill="#A97BFF" />
59
+ <text x="20" y="10" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="500" fill="#94A3B8">Kotlin</text>
60
+ <text x="160" y="10" text-anchor="end" font-family="-apple-system, BlinkMacSystemFont, sans-serif" font-size="13" font-weight="600" fill="#F0F6FC">2.2%</text>
61
+ </g>
62
+ </svg>
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "fuzzgpu-core"
3
- version = "0.1.1"
3
+ version = "0.1.2"
4
4
  edition = "2021"
5
5
  description = "GPU-accelerated fuzzy string matching engine"
6
6
  license = "MIT"
@@ -152,7 +152,8 @@ pub fn damerau_levenshtein_cdist(list_a: &[&str], list_b: &[&str]) -> Vec<Vec<u3
152
152
  }).collect()
153
153
  }
154
154
 
155
- /// Damerau-Levenshtein normalized ratio (0.0 to 100.0) based on Sørensen-Dice formula.
155
+ /// Damerau-Levenshtein normalized ratio (0.0 to 100.0) based on standard edit distance similarity formula:
156
+ /// `((total_len - dist) / total_len) * 100.0`.
156
157
  pub fn damerau_ratio(s1: &str, s2: &str) -> f64 {
157
158
  let len_a = if s1.is_ascii() { s1.len() } else { s1.chars().count() };
158
159
  let len_b = if s2.is_ascii() { s2.len() } else { s2.chars().count() };
@@ -0,0 +1,151 @@
1
+ use std::sync::atomic::{AtomicBool, Ordering};
2
+ use std::sync::{Arc, OnceLock};
3
+ use thiserror::Error;
4
+
5
+ #[derive(Error, Debug)]
6
+ pub enum FuzzGpuError {
7
+ #[error("GPU not available: {0}")]
8
+ NoDevice(String),
9
+ #[error("Shader compilation failed: {0}")]
10
+ ShaderError(String),
11
+ #[error("Buffer error: {0}")]
12
+ BufferError(String),
13
+ #[error("GPU operation timed out: {0}")]
14
+ Timeout(String),
15
+ #[error("Invalid input or parameters: {0}")]
16
+ InvalidInput(String),
17
+ }
18
+
19
+ pub type Result<T> = std::result::Result<T, FuzzGpuError>;
20
+
21
+ pub struct GpuEngine {
22
+ pub device: wgpu::Device,
23
+ pub queue: wgpu::Queue,
24
+ pub info: GpuInfo,
25
+ pub max_buffer_size: u64,
26
+ pub max_storage_buffer_binding_size: u32,
27
+ }
28
+
29
+ static GLOBAL_ENGINE: OnceLock<Arc<GpuEngine>> = OnceLock::new();
30
+ static CPU_ONLY_FLAG: AtomicBool = AtomicBool::new(false);
31
+
32
+ #[derive(Debug, Clone)]
33
+ pub struct GpuInfo {
34
+ pub name: String,
35
+ pub backend: String,
36
+ }
37
+
38
+ impl GpuEngine {
39
+ /// Enable or disable CPU-only fallback globally.
40
+ pub fn set_cpu_only(cpu_only: bool) {
41
+ CPU_ONLY_FLAG.store(cpu_only, Ordering::SeqCst);
42
+ }
43
+
44
+ /// Check whether CPU-only mode is active.
45
+ pub fn is_cpu_only() -> bool {
46
+ if CPU_ONLY_FLAG.load(Ordering::Relaxed) {
47
+ return true;
48
+ }
49
+ if let Ok(v) = std::env::var("FUZZGPU_USE_CPU") {
50
+ if v == "1" || v.eq_ignore_ascii_case("true") || v.eq_ignore_ascii_case("yes") {
51
+ return true;
52
+ }
53
+ }
54
+ false
55
+ }
56
+
57
+ /// Returns whether a GPU device is available and ready for compute.
58
+ pub fn is_available() -> bool {
59
+ if Self::is_cpu_only() {
60
+ return false;
61
+ }
62
+ Self::get().is_ok()
63
+ }
64
+
65
+ /// Get or lazily initialize the singleton GPU engine.
66
+ pub fn get() -> Result<Arc<Self>> {
67
+ if Self::is_cpu_only() {
68
+ return Err(FuzzGpuError::NoDevice("CPU-only mode is forced (FUZZGPU_USE_CPU)".into()));
69
+ }
70
+
71
+ if let Some(engine) = GLOBAL_ENGINE.get() {
72
+ return Ok(Arc::clone(engine));
73
+ }
74
+
75
+ let engine = pollster::block_on(Self::new_inner())?;
76
+ let _ = GLOBAL_ENGINE.set(Arc::clone(&engine));
77
+ Ok(engine)
78
+ }
79
+
80
+ async fn new_inner() -> Result<Arc<Self>> {
81
+ let instance = wgpu::Instance::default();
82
+
83
+ let adapter = match instance
84
+ .request_adapter(&wgpu::RequestAdapterOptions {
85
+ power_preference: wgpu::PowerPreference::HighPerformance,
86
+ compatible_surface: None,
87
+ force_fallback_adapter: false,
88
+ })
89
+ .await
90
+ {
91
+ Some(a) => a,
92
+ None => instance
93
+ .request_adapter(&wgpu::RequestAdapterOptions {
94
+ power_preference: wgpu::PowerPreference::None,
95
+ compatible_surface: None,
96
+ force_fallback_adapter: true,
97
+ })
98
+ .await
99
+ .ok_or_else(|| FuzzGpuError::NoDevice("No GPU adapter found".into()))?,
100
+ };
101
+
102
+ let adapter_info = adapter.get_info();
103
+ let info = GpuInfo {
104
+ name: adapter_info.name.clone(),
105
+ backend: format!("{:?}", adapter_info.backend),
106
+ };
107
+
108
+ // Query adapter limits dynamically rather than blindly hardcoding 128MB
109
+ let adapter_limits = adapter.limits();
110
+ let target_storage_size = (128 * 1024 * 1024).min(adapter_limits.max_storage_buffer_binding_size);
111
+ let target_buffer_size = (128 * 1024 * 1024).min(adapter_limits.max_buffer_size);
112
+
113
+ let required_limits = wgpu::Limits {
114
+ max_storage_buffer_binding_size: target_storage_size,
115
+ max_buffer_size: target_buffer_size,
116
+ max_compute_workgroup_storage_size: 16 * 1024.min(adapter_limits.max_compute_workgroup_storage_size),
117
+ max_compute_invocations_per_workgroup: 256.min(adapter_limits.max_compute_invocations_per_workgroup),
118
+ ..Default::default()
119
+ };
120
+
121
+ let (device, queue) = adapter
122
+ .request_device(
123
+ &wgpu::DeviceDescriptor {
124
+ label: Some("fuzzgpu"),
125
+ required_features: wgpu::Features::empty(),
126
+ required_limits,
127
+ memory_hints: wgpu::MemoryHints::Performance,
128
+ },
129
+ None,
130
+ )
131
+ .await
132
+ .map_err(|e| FuzzGpuError::NoDevice(format!("Failed to create GPU device: {}", e)))?;
133
+
134
+ if std::env::var("FUZZGPU_DEBUG").is_ok() {
135
+ eprintln!(
136
+ "fuzzgpu: Initialized {} ({}) with max buffer size {} MB",
137
+ info.name,
138
+ info.backend,
139
+ target_buffer_size / (1024 * 1024)
140
+ );
141
+ }
142
+
143
+ Ok(Arc::new(Self {
144
+ device,
145
+ queue,
146
+ info,
147
+ max_buffer_size: target_buffer_size,
148
+ max_storage_buffer_binding_size: target_storage_size,
149
+ }))
150
+ }
151
+ }