minigpu 1.7.0
minigpu: ^1.7.0 copied to clipboard
A library that brings multiplatform GPU compute to Dart and Flutter, using WebGPU directly with a Dawn backend.
minigpu #
1.7.0 #
-
Compiled shaders are now cached on disk, so WGSL compilation is a once-per-machine cost instead of a once-per-process one. On by default — no code change is needed to get it. Turning WGSL into a backend shader is the most expensive thing a process does at startup: on Windows/D3D11 it runs through FXC, whose optimiser cost grows superlinearly with kernel size, so a large compute kernel can spend tens of seconds there on every launch. Measured on a 3-kernel probe: total time in compute pipeline creation 34 ms cold → 1 ms warm, with byte-identical outputs.
New API, all optional:
Minigpu.configureShaderCache(enabled:, directory:, maxBytes:, extraKey:),Minigpu.shaderCacheStats,Minigpu.shaderCacheDirectory,Minigpu.clearShaderCache(), and theShaderCacheStatsvalue type. Configuration is PRE-INIT and process-global, the same contract aspreferDisplayAdapter.MGPU_SHADER_CACHE=0disables it andMGPU_SHADER_CACHE_DIR=<path>redirects it, both outranking the programmatic settings — so "is the cache the problem?" is answerable on a build you cannot edit.Stored under the OS cache convention (
%LOCALAPPDATA%/~/Library/Caches/$XDG_CACHE_HOME), capped at 256 MB with LRU eviction. Android has no default — an app-private cache directory cannot be discovered from C++, so caching stays off there until a host passes one toconfigureShaderCache. Web is a no-op: no Dawn, no FXC, nothing to cache.Every failure mode is a cache miss, never a failed device: an unwritable or missing directory, a full disk, a corrupt or truncated entry, a lock, or a race with another process all degrade to "compile it" and continue. A cache that could break startup would be worse than no cache.
Stale entries are prevented rather than tolerated. The key covers the Dawn version, adapter, driver version and compile options, so a driver update or a GPU swap MISSES instead of loading a blob built by different software. Each entry also stores its own full key and is verified on read — a filename hash collision costs a recompile rather than silently binding the wrong pipeline, which matters because the blob-level hash Dawn validates proves a blob is intact, not that it belongs to the key that was asked for.
No Dart-authored cache providers, by construction: Dawn's load callback is synchronous and can arrive on a Dawn-internal thread, and a Dart isolate can only be entered asynchronously from a foreign thread (
NativeCallable.listener), which cannot return a blob to a blocked native caller. -
Buffer.writeRawBytesis now copy-free on the way to the GPU, on BOTH native and web. No API change; the payload is simply no longer duplicated into an intermediate list/scratch before it is handed to the driver. On a streaming path (one whole frame per call) that duplicate was a whole-frame host copy per frame — at 4K, half of the entire upload cost. Measured on a 4K 240-frame encode:upload3.71 → 1.84 ms/frame. See minigpu_ffi and minigpu_web for the platform details; the web fix also removes a whole-frame ALLOCATION per frame, which was a garbage source as well as a copy. -
Read staging no longer churns a GPU buffer per call. A read whose length differs from the previous read used to destroy and recreate the staging buffer; capacity now only grows. This is invisible to a caller reading a fixed-size tensor and worth 33 ms per 723 reads at 4K to one reading a variable-length payload.
-
Minigpu.drainWorkQueue()— blocks until every GPU task already queued has run. Dispatches, readbacks and shared-texture blits execute on a native worker thread, so destroying a buffer or texture can free a resource a queued task is about to touch; draining first makes teardown ordered instead of hopeful. SYNCHRONOUS on purpose: the caller that needs it most is one that cannot await — Flutter'sState.reassemble, the only hook you get on hot reload before the framework rebuilds on top of your GPU resources. Use it asstop producing → drainWorkQueue() → release, never per frame. No-op on web. -
Picks up the minigpu_ffi completion-delivery fix. Async GPU work (
ComputeShader.dispatch,Buffer.read, the shared-texture present, context init) used to signal Dart through a per-callNativeCallablethat was closed when the operation finished. A completion arriving after that close aborted the whole process withCallback invoked after it has been deleted— and isolate teardown deleted the callbacks too, so hot restart and any worker isolate exiting with GPU work in flight were fatal as well. Completions now arrive on a Dart native port, which is silently inert once its isolate is gone. No API change; existing code gets the fix by upgrading. Flutter hot reload was the reliable trigger, because it pauses the isolate at a safepoint for hundreds of milliseconds while the GPU worker thread keeps completing work.
1.6.1 #
- released 08/13/26 - MR
1.6.0 #
- Picks up minigpu_ffi 1.6.0: the process-global native context is now serialized and reference-counted, so several isolates initializing the GPU concurrently share one device instead of racing to free each other's. No API change in this package.
1.5.9 #
ComputeShader.setBufferandsetBufferAtSlotare now always ORDERED — the bind joins the WebGPU-thread FIFO, so it is correct againstdispatchFireas well asdispatch. This removes a silent-corruption trap rather than documenting it: the binds used to run inline on the caller's thread whiledispatchFireenqueued, so rebinds raced ahead and every fired dispatch saw the LAST binding. Measured on a 3-iteration bind→fire→rebind→fire loop, the old inline binds produced[[0,0], [0,0], [31,31]]— two destinations never written, no error raised — where the ordered binds produce[[11,11], [21,21], [31,31]]. Nothing prevented the bad pairing but choosing the right one of four bind methods.ComputeShader.setBufferFireis deprecated — it is now an alias forsetBuffer.setBufferAtSlotFire(added and never released during 1.5.9 development) is removed; usesetBufferAtSlot.- A compute shader is no longer destroyed inline.
mgpuDestroyComputeShaderqueues the delete on the same FIFO, so it lands after any bind or dispatch already queued against that shader. Ordered binds capture the shader pointer to mutate its binding tables when they run, so an inline delete would free it under a pending bind — the hazardsetBufferFire's docs previously pushed onto callers ("do not destroy the shader until a read has been awaited"). That constraint is now gone. (Buffers never had it: a queued bind captures only the raw WGPU handle by value, which is whymgpuDestroyBuffercan still delete immediately.) - New test
test/minigpu_fire_bind_test.dart: fire-then-read synchronization, rebind-between-fires ordering, equivalence with the fully awaited chain, and the 65535 cap ondispatchFire.
1.5.8 #
- Breaking-ish fix:
Minigpu()is now a per-isolate SINGLETON and the context is destroyed only by explicitdestroy()/destroySync(). Each construction used to attach aFinalizercallingdestroyContext(), but there is only ONE process-global native context — so any temporary wrapper (e.g.Minigpu().isInitializedin a testsetUp) destroyed the device, whenever the GC ran, out from under every live buffer and shader. Resources created before the loss were invalid on the auto-reinitialized device and their dispatches were silently dropped: zero outputs, no Dart-visible error. Minigpu.init()is now idempotent and concurrency-safe — returns immediately when already initialized, awaits the in-flight init when raced, and no longer throwsMinigpuAlreadyInitError. Update any code relying on that throw.ComputeShader.dispatch/dispatchFirenow throwArgumentErroraboveComputeShader.maxWorkgroupsPerDim(65535). Exceeding WebGPU's per-dimension cap invalidated the whole CommandBuffer, and since validation errors are STICKY, every later submit on the device failed too — one oversized dispatch silently poisoned unrelated work. The error names the offending dims and gives the canonical fold (gx = min(n, 65535); gy = (n + gx - 1) ~/ gx, flat index rebuilt in the shader asgid.x + gid.y * (num_workgroups.x * workgroup_size_x)).- New
ComputeShader.dispatchFire(x, y, z)— fire-and-forget dispatch with no per-dispatch completer round trip. Call order is still honoured, so awaiting any later buffer read synchronizes every fired dispatch. Bindings are snapshotted when the dispatch RUNS, not when it is fired: do notsetBufferon a shader with an unsynchronized fired dispatch outstanding. UsesetBufferFire(the bind joins the same FIFO) or a shader instance per call site. - New
Minigpu.forAdapter(String adapterFilter)— an INDEPENDENT context on the adapter whose name containsadapterFilter(case-insensitive substring), with its own device, queue and task FIFO. Not the singleton:init()before use,destroy()when done, and never mix two instances' resources in one dispatch. ThrowsUnsupportedErroron web. Instance getteradapterNamereports which adapter THIS context bound. - New
Minigpu.listAdapters()— hardware adapters with dedicated-VRAM total and usage (DXGI on Windows; empty elsewhere). ReturnsGpuAdapterInfofrompackage:minigpu_platform_interface/minigpu_platform_interface.dart. - New
Buffer.writeRawBytes(bytes, {dstByteOffset = 0})— raw 4-byte-aligned upload streamed in 32 MB chunks, so neither host scratch nor driver staging holds the whole payload. For LARGE transfers where a singlewritewould spike or pin host RAM. - New
Minigpu.drainSpinBudgetMs— the event-drain spin budget the LOADED native binary implements;nullon web, or on a binary predating the export, which for a native build means the drain fix below is NOT in it. Latency-sensitive callers should assert> 0at startup, since loading a stale native artifact is silent. - Native (
minigpu_ffi1.5.8), reaching consumers of this package through the shared context — seeminigpu_ffi/CHANGELOG.mdfor the contracts:- The Dawn event drain no longer costs a Windows timer quantum (~15.6 ms)
per GPU wait: present p50 15.69 → 2.57 ms at 1280x720 and 15.69 →
10.07 ms at 3840x2160 on an RTX 4090. Strictly better — waits can only
return sooner.
MGPU_DRAIN_SPIN_MS=<0..1000>tunes it (default 8). - Additive batched staging upload and readback scopes: N scattered host writes
become one queue write plus N recorded copies, and N per-buffer
mgpuReadSync*calls become one submit, one fence and one map (8 reads of 2.72 MB: 1.098 → 0.465 ms of API time). No Dart API on this package yet — reachable through theminigpu_ffibindings. - Multi-adapter context handles and
mgpuEnumAdapters, backingMinigpu.forAdapterandMinigpu.listAdaptersabove. - Three build fixes worth knowing if you have ever fought the Dawn step:
MINIGPU_DAWN_DIRis now honoured when building through Flutter / dart pub (it previously only moved the prebuilt-library search, not the Dawn root given to cmake); a Windows Dawn root no longer breaks a from-source Dawn build withInvalid character escape '\d'; and the Emscripten build's emdawnwebgpu port file is detected rather than hardcoded. Seeminigpu_ffi/README.md→ Troubleshooting.
- The Dawn event drain no longer costs a Windows timer quantum (~15.6 ms)
per GPU wait: present p50 15.69 → 2.57 ms at 1280x720 and 15.69 →
10.07 ms at 3840x2160 on an RTX 4090. Strictly better — waits can only
return sooner.
1.5.7 #
- Release cut of the adapter-selection and Tier B/Tier C work documented under 1.5.6; no additional API change in this package.
1.5.6 #
- New statics
Minigpu.preferDisplayAdapter([enable])andMinigpu.selectedAdapterName: pre-init hint that binds Dawn to the adapter driving the PRIMARY display (Windows) so screen capture, GPU processing and HW encode share one GPU (same-adapter zero-copy) on hybrid systems, and a query for which adapter Dawn actually selected. Call the hint before any minigpu use;MGPU_ADAPTER_NAMEstill overrides.
1.5.5 #
1.5.4 #
- fix release version pins
1.5.3 #
- Add async shared-output-texture copy:
SharedOutputTexture.copyFromBufferAsyncandVideoTexture.bgraToRgbaSharedOutputAsync. These run the GPU copy and the cross-device present sync on minigpu's WebGPU worker thread and complete aFuturewhen finished, instead of busy-polling the present-wait on the calling isolate — removing the dominant per-frame blocking cost on the shared-output (zero-copy encode) path. The synchronouscopyFromBuffer/bgraToRgbaSharedOutputare unchanged.
1.5.2 #
- Add
Minigpu.copyBuffer(src, dst, {required int elementCount}): GPU-side buffer-to-buffer copy using a WGSL compute shader — no CPU round-trip. The copy shader (64-element workgroup,array<u32>storage bindings) is created once perMinigpuinstance on first call and reused for all subsequent calls. Non-multiple-of-64 element counts are handled correctly via anarrayLengthguard in the shader. Minigpu.onShaderDestroyednow nulls the cached copy-shader reference when that shader is destroyed, preventing a double-destroy ifdestroyAllTrackedShaders()is called beforedestroy().Minigpu.destroy()explicitly tears down the cached copy shader before releasing the Dawn context.- New test suite
test/minigpu_copy_buffer_test.dart: 14 tests covering correctness (u32, f32, bit-pattern sentinel), partial copy, workgroup boundary alignment, shader reuse, andliveShaderCount/liveBufferCountstability.
1.5.1 #
- fix frame wait and timeouts
1.5.0 #
- Fix handle issue, release 1.5.0
1.4.15 #
- fix fallback paths
1.4.14 #
- fix Tier C
1.4.12 #
- fix texture path
1.4.11 #
- fixing build hook
1.4.9 #
- tryfix central dawn location
1.4.8 #
- fixes texture path on windows, fixes texture view on web
1.4.7 #
- Fixes logger characters
1.4.6 #
- fix garbled adapter name in logs: WGPUStringView.data is not null-terminated, copy to std::string before passing to snprintf
- fix garbled adapter name in logs: WGPUStringView.data is not null-terminated, copy to std::string before passing to snprintf
1.4.5 #
- fix Dawn built inside pub-cache instead of system dir: pass DAWN_DIR from Dart hook as cmake -D define so cmake subprocess inherits the correct path regardless of env; fix FETCHCONTENT_BASE_DIR pointing to pub-cache (now uses cmake binary dir)
- add Minigpu.setLogCallback / setLogLevel: routes native Dawn/GPU log lines through a Dart callback (NativeCallable.listener); mgpuSetLogCallback + mgpuSetLogLevel exported from C layer; all stderr calls in minigpu_external.cpp replaced with structured LOG_ERROR/INFO/WARN/DEBUG macros
1.4.4 #
- fix FormatException on non-UTF-8 bytes in setLogCallback: use Utf8Decoder(allowMalformed: true) instead of toDartString()
1.4.3 #
- improve adapter selection to prefer discrete GPU using dawn native EnumerateAdapters; fixes incorrect adapter picked on Optimus laptops
1.4.2 #
- fixes dawn library not being found
1.4.1 #
- added bindings observer
1.4.0 #
- adds minigpu_view, gpu_pipeline libraries
- adds
Minigpu.destroySync()for use in synchronous hot-reload teardown hooks (e.g.MinigpuBindingfromminigpu_flutter)
1.3.0 #
- Adds Texture Sharing
1.2.4-WIP #
- working on texture imports
1.2.3 #
- adds VRAM API
- fixes memleaks and broken tests
1.2.2 #
- fixes memleaks and broken tests
1.2.1 #
- Fix: fresh builds need dawn find off
- Change: 1.2.0 migrates minigpu to direct webgpu usage
- Breaking: Changed setData and references to .write
- Fix: broken compute shader and buffer finalizers
1.2.0 #
1.1.9 #
- fix pubspec version issue
1.1.8 #
- fixed concurrent buffer op crash
1.1.6 #
- fixed problem with audio input capture providing raw data
1.1.5 #
- Refactored example
- Various fixes
- Updated native assets to code assets
- Memory problems fixed on web and ffi
1.1.3 #
- breaking: import package instead of buffer and shader separately
- fix: pubspec repository url
- adds: tensor package protoype
- fix: issue with reading buffer segments fixed
1.1.2 #
- fix: create dawn dir to prevent first run error.
1.1.1 #
- fix: split download command for quiet fail on remote add
1.1.0 #
- fix: dawn git not running properly
1.0.9 #
- fix: prevent using project root on ffi since pub wont see the file
1.0.8 #
- fix: pub.dev still missing project root file
1.0.7 #
- fix: project root file missing
1.0.6 #
- fix: minigpu_ffi must also use flutter in pubspec or pub.dev analysis fails
- fix: issue with project root finding as package
1.0.5 #
- fix: must have flutter in pubspec or pub.dev analysis fails
1.0.4 #
- fix: updates to readme
1.0.3 #
- fix: remove flutter from package pubspec.yaml
- fix: updates to readme
1.0.2 #
- new: explicity set supported platforms in pubspec.yaml for pub.dev
1.0.1 #
- breaking: Uses dart native assets see updated readme.
- implements platform stub for native assets to coexist with flutter plugins.
- uses native_toolchain_cmake 0.0.4
1.0.0 #
- Initial version.