gpu-probe: say whether each adapter has compute, not just the preferred one

Compute is a downlevel capability rather than a feature -- unconditional
on any Vulkan 1.0 device, GLES 3.1 and up -- so the question shadows and
blur raise is what the *weakest* adapter iris can fall back to offers.
Both here answer yes: Venus and virgl each report COMPUTE_SHADERS, 1024
invocations per workgroup and 64 KB of workgroup storage, virgl because
it is ES 3.2. The only no-compute machine in this project is the
emulator's SwiftShader software GL at ES 3.0.

RUST.md gains that table, why DRM native context is unrelated to it, and
what each of shadows/blur/paths actually needs -- only vello proper turns
the compute question on.
This commit is contained in:
iris committed 2026-09-08 12:55:47 -04:00
1 parent b9924e7617
commit db0a41a7cd
2 files changed
+81

No files matched your search

+66
View File
@@ -7534,6 +7534,72 @@ healthy one.
screenshot is being taken to judge. **Check it before trusting a screenshot is being taken to judge. **Check it before trusting a
layer-2 screenshot or any frame number from that window.** layer-2 screenshot or any frame number from that window.**
### Is compute available? Asked of every adapter, not reasoned about (2026-09-08)
Iris asked whether shadows, blur and path rendering mean turning compute
back on. `rigs/gpu-probe` now prints `DownlevelFlags::COMPUTE_SHADERS`
and the compute limits **for every adapter it enumerates**, because that
is the question -- compute is a downlevel capability rather than a
feature, granted unconditionally by any Vulkan 1.0 device and by GLES
only from ES 3.1, so what matters is the weakest adapter iris might fall
back to, not the preferred one. Measured here:
| adapter | compute | invocations/workgroup | workgroup storage |
|---|---|---|---|
| `Vulkan` Virtio-GPU Venus (RX 7900 XT) | yes | 1024 | 64 KB |
| `Gl` virgl (RX 7900 XT, radeonsi) | yes | 1024 | 64 KB |
So **the GL fallback on this VM already has compute** (virgl reports ES
3.2). The only no-compute machine in this project is the Android
emulator's **SwiftShader software GL** at `EMU_GPU=software`, which
reports ES 3.0 -- a software rasteriser used for one test configuration,
not a device anything ships to. The phone has Vulkan.
**DRM native context would not change any of this**, which is the answer
to "would enabling drm without full passthrough get us to 3.1": it is
about *how* Vulkan reaches the host GPU from this VM (RADV in the guest
against a passed-through DRM context, instead of Venus proxying every
call), not about what API level anything reports, and both paths here are
already above 3.1. It is worth wanting for other reasons -- fewer
Venus-specific faults and closer-to-real frame behaviour on the desktop
path -- and it costs host-side work (virglrenderer with its amdgpu DRM
renderer, a qemu exposing `context_types=drm`, `vulkan-radeon` in the
guest). The host keeps its GPU either way; that is what makes it
different from VFIO passthrough. Not on the critical path for any of the
three features below.
**So the gate is design, not hardware.** What each of the three actually
needs:
- **Drop shadows: fragment, analytically.** A blurred rounded rect has a
closed form (an erf approximation of the gaussian), so a shadow is one
more primitive that *references the shape it belongs to* -- the same
move LAYOUT.md's masks make -- rather than a blur pass over a captured
texture. No extra target, no second pass, nothing to invalidate. This
is where most of the visual value is and it needs nothing new from the
device.
- **Backdrop blur: fragment, dual Kawase.** Downsample, a few cheap
taps, upsample. A compute version with shared-memory tiles is perhaps
1.5x faster and costs the fallback path a second implementation; on a
phone the bandwidth saving from downsampling dominates either way.
Revisit if it measures badly on the phone, with a number.
- **Paths: the one genuine decision.** Three options, in ascending cost:
CPU tessellation (`lyon`) into the existing triangle pipeline;
`vello_hybrid` (CPU coarse, fragment fine, built for no-compute
targets); `vello` proper, which *does* need compute. Only this last one
turns on the compute question, and it brings a large dependency with
it. Decide it against the actual path workload (icons and charts are
not the same problem as arbitrary SVG), not in advance.
**If compute is turned on later, the shape to use.** Keep
`iris_core::device_limits()` zeroing the six `max_compute_*` fields as
the default, and have the compute-needing feature ask the adapter --
`DownlevelFlags::COMPUTE_SHADERS` plus the limits it needs -- and switch
itself off when the answer is no. One capability check that a feature
consults, not a compute branch spread through the renderer, and not an
unconditional request that aborts `request_device` on a device that
cannot serve it (which is exactly the 2026-09-05 crash).
### "wgpu crashes on drop" was the Vulkan loader unloading Mesa (2026-09-08) ### "wgpu crashes on drop" was the Vulkan loader unloading Mesa (2026-09-08)
`iris/tests/mask_sdf.rs` `SIGSEGV`d **after** printing `test result: ok`, `iris/tests/mask_sdf.rs` `SIGSEGV`d **after** printing `test result: ok`,
+15
View File
@@ -79,6 +79,21 @@ fn main() {
" {:?} {} ({:?})", " {:?} {} ({:?})",
info.backend, info.name, info.device_type info.backend, info.name, info.device_type
); );
// Compute is a *downlevel* capability, not a feature: Vulkan
// grants it to any 1.0 device, and GLES only from ES 3.1. So
// "can iris use a compute pass here" is this flag on every
// adapter iris might fall back to, not just the preferred one.
let down = adapter.get_downlevel_capabilities();
let limits = adapter.limits();
println!(
" compute shaders: {} (shader model {:?})",
down.flags.contains(DownlevelFlags::COMPUTE_SHADERS),
down.shader_model
);
println!(
" max compute invocations/workgroup: {}, workgroup storage: {} bytes",
limits.max_compute_invocations_per_workgroup, limits.max_compute_workgroup_storage_size
);
} }
let Some(adapter) = pollster::block_on(instance.request_adapter(&RequestAdapterOptions { let Some(adapter) = pollster::block_on(instance.request_adapter(&RequestAdapterOptions {