Prune commentary and stale Rust port notes

This commit is contained in:
iris committed 2026-09-10 00:44:13 -04:00
1 parent 5428cd75c9
commit 25370731d0
193 files changed
+693 -16219

No files matched your search

+3 -8
View File
@@ -3,16 +3,11 @@ name = "gpu-probe"
version = "0.1.0"
edition = "2024"
# Deliberately its own crate rather than a member of iris's workspace: the
# vendored `iris/` tree is meant to stay reconcilable with the iris/iris
# repository, and this is a rig belonging to ai-app.
# Standalone so this app-specific rig does not alter iris's workspace.
[dependencies]
# Pinned to what iris asks for, so the answer is about iris rather than
# about a different wgpu.
# Match iris's wgpu version.
wgpu = "30.0.1"
pollster = "1.0.1"
# Queried directly, because wgpu and `cmd gpu vkjson` disagreed about
# descriptor indexing in the emulator and only the raw call says which is
# right.
# Raw Vulkan queries settle capabilities on which wgpu and `cmd gpu vkjson` disagree.
ash = "0.38"
@@ -1,33 +1,3 @@
//! Why a GPU test segfaults *after* it has passed, and what stops it.
//!
//! Measured here 2026-09-08, on this VM's Venus adapter. Destroying the
//! last `VkInstance` makes the Vulkan loader `dlclose` the ICD; Mesa's
//! ICD (`/usr/lib/libvulkan_virtio.so`) registers a `pthread_key_create`
//! destructor pointing into its own text and is not linked `-z nodelete`,
//! so glibc calls that destructor through unmapped memory when the thread
//! that used Vulkan exits. libtest runs every `#[test]` on a spawned
//! thread, which is why it looked like "wgpu crashes on drop": the drop
//! itself completes, and the crash lands as the thread unwinds.
//!
//! The four modes are the experiment, and each is one variable:
//!
//! | mode | what it does | 2026-09-08 |
//! |---|---|---|
//! | `main` | wgpu instance + device on the main thread, dropped | exits 0 |
//! | `thread` | the same on a spawned thread | **SIGSEGV** |
//! | `keep` | the same, but the instance is never dropped | exits 0 |
//! | `raw` | raw Vulkan (`ash`), instance + device, spawned thread | **SIGSEGV** |
//!
//! `raw` is the one that says whose bug it is: no wgpu is involved, so
//! there is nothing for wgpu or a caller to fix in its drop order. `keep`
//! is the fix -- hold one `wgpu::Instance` for the process, which is what
//! wgpu asks for anyway. `iris/tests/mask_sdf.rs` does exactly that.
//!
//! `VK_LOADER_DISABLE_DYNAMIC_LIBRARY_UNLOADING=1` also makes every mode
//! exit cleanly, which is the confirmation that the unload is the
//! mechanism -- but it is an environment variable every caller would have
//! to remember, so it belongs in this comment rather than in a script.
use ash::vk;
use pollster::block_on;
use wgpu::*;
@@ -42,12 +12,9 @@ fn main() {
other => panic!("unknown mode {other:?}: main | thread | keep | raw"),
};
std::thread::spawn(body).join().expect("the spawned thread");
// Not reached when the thread's exit takes the process with it.
eprintln!("thread joined");
}
/// A wgpu instance and device, opened and closed. `keep_instance` is the
/// fix under test: everything else still drops normally.
fn wgpu_open_and_close(keep_instance: bool) {
let instance = Instance::default();
let adapter =
@@ -71,8 +38,6 @@ fn wgpu_open_and_close(keep_instance: bool) {
eprintln!("wgpu closed");
}
/// The same shape with no wgpu in it at all, which is what makes this a
/// loader/driver bug rather than a wgpu one.
fn raw_vulkan_open_and_close() {
unsafe {
let entry = ash::Entry::load().expect("vulkan loader");
-51
View File
@@ -1,55 +1,13 @@
//! Ask a device whether it can give iris the GPU it asks for.
//!
//! Until 2026-09-04 iris's renderer bound every texture it had drawn as one
//! binding array and indexed it non-uniformly from the shader, which needed
//! descriptor indexing and a very large per-stage binding-array limit
//! (101,000 elements: 100,000 textures and 1,000 samplers,
//! `UiLimits::default`). That was ordinary on a desktop and, per
//! TEXTURES.md's "iris's binding array does not survive real Android
//! hardware", not available on a real share of Android GPUs -- and it failed
//! outright on this emulator's software Vulkan, which is what this rig
//! caught first. iris now asks for nothing beyond wgpu's own defaults (see
//! `iris/src/default/render.rs`): the glyph atlas is one `texture_2d_array`
//! and a standalone image is its own ordinary bind group, and neither needs
//! descriptor indexing. This rig still asks `request_device` for exactly
//! what iris asks for, so it keeps being the answer to "does iris's actual
//! device request succeed here" rather than a guess from reading the code.
//!
//! It runs as a plain executable with no window and no APK, because
//! `request_adapter` needs no surface -- so it can be pushed to a device with
//! `adb push` and run from `/data/local/tmp`, which is far cheaper than an
//! app. What it therefore cannot answer is anything about presenting to a
//! surface; that is the Android backend's own problem.
mod vk;
use wgpu::*;
/// What `iris/src/default/render.rs` asks `request_device` for, now that the
/// binding array is gone: nothing beyond wgpu's own default feature set.
fn iris_features() -> Features {
Features::empty()
}
/// The one non-default limit iris asks for -- unrelated to the binding array,
/// kept for the big storage buffers behind rects/glyphs.
const IRIS_MAX_BUFFER_SIZE: u64 = 1 << 30;
/// Mirrors `iris_core::device_limits()` (`iris/core/src/render/mod.rs`) --
/// cannot call it directly, since this rig is deliberately its own crate,
/// not a workspace member (this file's own Cargo.toml comment). Keep the
/// two in sync by hand when one changes; this rig's whole purpose is "does
/// the device iris actually builds come back," so a stale copy here would
/// silently stop answering that question. Zeroed rather than left at
/// `Limits::default()`'s desktop-tier values because nothing in iris
/// creates a `ComputePipeline` or a `@compute` shader stage -- found by
/// grepping the whole `iris`/`iris-core` tree before this rig's comment was
/// written -- and the unconditional default request is what crashed
/// `request_device` on the Android emulator's software GL path
/// (`EMU_GPU=software`, `force-gles`: SwiftShader's GL reports itself as
/// OpenGL ES 3.0, which has no compute shaders at all, so the adapter's
/// real limit is 0). The same would happen on a real GLES-3.0-only Android
/// device.
fn iris_limits() -> Limits {
Limits {
max_buffer_size: IRIS_MAX_BUFFER_SIZE,
@@ -79,10 +37,6 @@ fn main() {
" {:?} {} ({:?})",
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!(
@@ -143,11 +97,6 @@ fn main() {
}
);
// The question that actually matters: does the device iris builds come
// back, or does wgpu refuse it? With no features and no binding-array
// limits requested, this is expected to succeed everywhere -- this rig
// is what turned that from an assumption into a measurement, first on
// this emulator's software Vulkan.
let wanted = iris_limits();
match pollster::block_on(adapter.request_device(&DeviceDescriptor {
required_features: iris_features(),
-11
View File
@@ -1,11 +1,3 @@
//! The raw Vulkan half of the probe.
//!
//! wgpu reports a feature only after a chain of its own decisions -- which
//! physical device, which API version, which extension list -- so "wgpu says
//! no" and "the driver says no" are different claims. This asks
//! `vkGetPhysicalDeviceFeatures2` itself and prints the inputs to that chain,
//! so a disagreement can be attributed rather than guessed at.
use ash::{Entry, vk};
use std::ffi::CStr;
@@ -29,9 +21,6 @@ pub fn report() {
println!("\nraw vulkan:");
println!(" loader instance version: {}", ver(instance_version));
// Ask for the highest instance version the loader admits to: wgpu clamps
// the device version by the instance's, so an instance created at 1.0
// makes a 1.3 device look like 1.0.
let app_info = vk::ApplicationInfo::default().api_version(instance_version);
let create = vk::InstanceCreateInfo::default().application_info(&app_info);
let instance = match unsafe { entry.create_instance(&create, None) } {