Repository navigation
optimization(vulkan): accelerate Android Gaussian blur - #126
Merged
chuzcjoe merged 1 commit intoOct 26, 2026
Merged
Conversation
chuzcjoe
force-pushed
the
daily/optimization-vulkan-android-gaussian-blur-20261024
branch
from
October 25, 2026 21:38
88dd293 to
433779f
Compare
chuzcjoe
marked this pull request as ready for review
October 26, 2026 20:47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The existing Vulkan
ComputeGaussianBlurworkload intests/vulkan/runs a fixed 3x3 Gaussian filter on a 4000x3000 float image. Its Slang shader reads invariant weights through a storage buffer, and every pipeline owns that buffer, its device-memory allocation and descriptor. The original Android GPU dispatch takes about 10.248 ms on the connected Adreno 740.This PR optimizes that existing Android compute path. It does not claim to accelerate the public Vulkan library, application rendering, another graphics backend or unmeasured devices. Baseline: freshly fetched
03119ea9bb65bb8ec24d9c694e268959b5404931; reviewed merged #124/#125 and recent closed proposals, with no open issue/PR overlap or earlier Oct 24 PR.Solution
preciseaccumulation. Remove its weight buffer, device-memory allocation, initialization map/copy and storage descriptor: storage descriptors 3 -> 2, total bindings 4 -> 3. The logical removed payload is 36 bytes; driver allocation size/RSS was not measured./13inputs validate the original GPU against the CPU within 2e-6 before comparing new/original GPU bytes. Source contents stay unchanged. Shapes include 1x1, single rows/columns, 2-pixel borders and partial 16x16 groups.Existing
ComputeGaussianBlurcallers opt in automatically when built for Android. Run the existingComputeGaussianBlur.testthrough the normal test script; runvulkan_gaussian_benchmarkseparately for measurements. This helper remains under tests; there is no new public API or independent shared-module/dependency change.Candidate/alternative evaluation: shared-memory tiles reduced redundant loads but regressed Android by about 46% on the large input, so were rejected. Applying GLSL on macOS regressed medium inputs by about 2.5-2.8x and large inputs by about 20%, so the platform selection is deliberate. Constant Slang weights changed last-bit results on fractional inputs; the installed Slang emitted no NoContraction decoration for the attempted precise mode. A related upstream Slang precision report describes this class of limitation. The final GLSL emits NoContraction and passes original-GPU byte comparisons on Android. Timing improvements below compare the complete old Slang path with the complete new GLSL path; compiler and constant-weight effects are not isolated.
Other candidates were pitched/partial texture uploads (no concrete streaming consumer yet) and exclusive Vulkan resource ownership (requires a separate compatibility/lifetime design). Neither was expanded into this PR.
Validation
Final commit:
88dd29347ab5127017f4427281c8672432b145c8; tested source treedeee98f6223f49a6d8af30c9f37f0bad26db9e24matches the commit. Full diff reviewed,git diff --checkpassed. All locked submodules initialized in this fresh Orca worktree; builds/tests stayed here. No installs, new dependencies, licenses, shell profiles, APKs or device settings were changed. An existing ignored PNG fixture was copied from the main checkout and SHA256-checked without modifying the source.Both core builds use C++20,
-O3 -DNDEBUG,-Wall -Wextra -Wpedantic -Werror; run.sh requests Debug but the top-level project supplies these actual flags. CMake 4.4.4, Vulkan SDK 1.4.350.0, glslc shaderc 2026.2, Slang 2026.8, xxd; explicit shell-local PATH resolves CMake/adb/glslc/slangc/xxd.macOS native, Apple M6 / MoltenVK 1.4.1, macOS 27.0.1, SDK 27.0, Apple Clang 21.0.0:
source /Users/joechu/VulkanSDK/1.4.350.0/setup-env.sh ./scripts/run.sh -t macos -r tests ./build/macos/tests/vulkan/vulkan_gaussian_benchmarkAndroid arm64-v8a, sole authorized physical USB model 2210132C / nuwa, Adreno 740, Android 13 / API 33; existing NDK 28.2.13676358 (r28c), Android Clang 19.0.1, target API 34, JDK 17.0.20.1, adb 37.0.1:
adb devices -l export ANDROID_NDK_ROOT=/Users/joechu/Library/Android/sdk/ndk/28.2.13676358 ./scripts/run.sh -t arm64-v8a -r tests adb push build/arm64-v8a/tests/vulkan/vulkan_gaussian_benchmark /data/local/tmp/core/vulkan_gaussian_benchmark adb shell /data/local/tmp/core/vulkan_gaussian_benchmarkspirv-val --target-env vulkan1.1and contains NoContraction decorations. Its C-formatted words were converted to binary for validation/disassembly.Controlled benchmark
Per invocation/case/path: 5 warmups + 31 timed samples; three complete invocations per platform, 93 samples/path/case total. Alternating order reverses each pair. Same device, toolchain/core configuration, input and buffers within comparisons; no builds ran concurrently with the final measurements. GPU timestamps bracket pipeline binding/dispatch, checked query/fence results and valid timestamp bits. Allocation, compilation/cache loading, CPU recording, submission/wait, data fill/oracle/checks and final host-read barrier are outside the GPU interval. Every output element is checked after the first warmup and last sample for both paths; input immutability is checked afterward.
Second-invocation GPU medians, microseconds:
For 4000x3000, Adreno p10/median/p90 in the second invocation: original [10246.979, 10248.385, 10259.427] us; final [5133.281, 5133.750, 5134.167] us. Three invocation medians: 10248.698 -> 5133.542, 10248.385 -> 5133.750, 10248.385 -> 5133.750 us: approximately 2.0x GPU dispatch speedup / 49.9% shorter interval for this workload.
M6 large-input medians: 871.042 -> 875.083, 781.667 -> 781.416, 765.292 -> 764.667 us, consistent with the unchanged GPU path and measurement noise. Medium/small-case variation is retained in the logs; Android 1024x1024 final medians range 540-719 us. Power, thermal state and frequency were not controlled. No general GPU, macOS, FPS, CPU time, upload, pipeline-compilation or RSS benefit is claimed. Benefits have only been measured on this Android GPU/configuration and these finite-input workloads.
Initial unmodified full suites passed 42 macOS / 44 Android tests. A preliminary fractional-input exact CPU comparison and the rejected constant Slang variant failed before the final design; those logs and rejected tile/macOS-GLSL measurements are retained. Final full runs above are the accepted validation. Logs, raw sample CSV rows, p10/median/p90 summaries, device/environment snapshots and verifier are in this worktree's ignored
build/daily-gaussian-20261024/; macOS tmp outputs were preserved before Android recreated tmp/.Changes
Relative to current origin/master: 9 files, +477 / -15 = 492 changed lines, below 1000.
tests/vulkan/CMakeLists.txttests/vulkan/ComputeGaussianBlur/ComputeGaussianBlur.comptests/vulkan/ComputeGaussianBlur/ComputeGaussianBlur.cpptests/vulkan/ComputeGaussianBlur/ComputeGaussianBlur.htests/vulkan/ComputeGaussianBlur/GaussianBlurReference.htests/vulkan/GaussianBlurShaderTest.cpptests/vulkan/benchmarks/GaussianBlurBaseline.htests/vulkan/benchmarks/GaussianBlurBaseline.slangtests/vulkan/benchmarks/GaussianBlurBenchmark.cppImplementation/shader/helper: +40/-15; regression tests, CPU oracle, baseline and benchmark/build: +437/-0; documentation: 0. No project Markdown/README edits, generated binaries/assets or added code comments.
Risk
The measured optimization is Android-specific; other Android drivers may schedule/compiler-optimize this shader differently. Fractional finite inputs are checked against the original GPU bytes on both tested devices, not an exhaustive IEEE/NaN/subnormal proof. GLSL's precise accumulation is deliberate; the old Slang kernel remains the baseline and non-Android implementation. The private test helper's platform-specific layout requires rebuilding its callers; public Vulkan headers and function signatures are unchanged. This does not add configurable kernels, in-place blur, new dimension validation, asynchronous ownership or a rendering integration; existing positive-dimension, distinct-buffer assumptions remain. Full default suites pass on both required targets; graphical windows were built but not visually exercised.