iris: a one-layer glyph atlas is a GL_TEXTURE_2D, so every glyph drew as a box
The emulator was blamed for two days for what is iris's own defect on any GL adapter. `GpuTextures::new` created the atlas `texture_2d_array` with one layer; wgpu-hal picks the GL target from the descriptor alone (`gles::Texture::get_info_from_desc`, `(false, 1) => TEXTURE_2D`), so the shader's `sampler2DArray` was handed a `GL_TEXTURE_2D`, the unit was incomplete, every `textureSample` returned (0,0,0,1), and `draw_glyph`'s `color.a *= texel.a` painted the whole glyph quad. `MIN_ARRAY_LAYERS = 2`, with the account at `create_array_texture` and a `debug_assert!` there. Vulkan -- the phone's build and the desktop's default backend -- was never affected. `force-gles` now switches the desktop backend too, so the GLES path is reproducible on a machine with a real GPU in seconds rather than only through an APK: that is how this was found, with two shader probes showing the sample was exactly (0,0,0,1).
This commit is contained in:
1 parent
69525bd131
commit
3cb18ac5c2
5 files changed
+108
-14
No files matched your search
@@ -5,6 +5,10 @@ use crate::{PatchRect, TextureKind, TextureUpdate, Textures};
|
||||
|
||||
use super::atlas::PAGE;
|
||||
|
||||
/// The fewest layers the glyph atlas array is ever created with. Two, not
|
||||
/// one, for the GLES reason written on `create_array_texture`.
|
||||
const MIN_ARRAY_LAYERS: u32 = 2;
|
||||
|
||||
/// What one texture slot is, GPU-side. Parallel to `Textures`' own slot
|
||||
/// numbering (`TextureKind`'s `Image`/`Page`), so a slot's index means the
|
||||
/// same thing on both sides without a second map to keep in sync.
|
||||
@@ -360,7 +364,26 @@ impl GpuTextures {
|
||||
})
|
||||
}
|
||||
|
||||
/// The atlas is sampled as a `texture_2d_array`, and **a one-layer
|
||||
/// array is not one on the GLES backend**: wgpu-hal picks the GL
|
||||
/// texture target from the descriptor alone
|
||||
/// (`gles::Texture::get_info_from_desc`, `(false, 1) => TEXTURE_2D`),
|
||||
/// so a capacity of 1 creates a `GL_TEXTURE_2D` and binds it to the
|
||||
/// shader's `sampler2DArray`. GL then treats that unit as incomplete
|
||||
/// and every `textureSample` returns (0, 0, 0, 1) -- which, through
|
||||
/// `draw_glyph`'s `color.a *= texel.a`, draws every glyph as a solid
|
||||
/// filled box. That was iris's appearance on the emulator's GLES for
|
||||
/// two days (RUST.md, "the emulator cannot draw iris's glyphs"), and
|
||||
/// it is a real defect on any device whose adapter is GL rather than
|
||||
/// Vulkan, not an emulator artifact. So the array never has fewer than
|
||||
/// `MIN_ARRAY_LAYERS` layers; the second layer costs one page of
|
||||
/// texture memory and is used by the next atlas page anyway.
|
||||
fn create_array_texture(device: &Device, capacity: u32) -> Texture {
|
||||
debug_assert!(
|
||||
capacity >= MIN_ARRAY_LAYERS,
|
||||
"glyph atlas array asked for {capacity} layers; fewer than {MIN_ARRAY_LAYERS} is a \
|
||||
GL_TEXTURE_2D on the GLES backend and draws every glyph as a box"
|
||||
);
|
||||
device.create_texture(&TextureDescriptor {
|
||||
label: Some("glyph atlas array"),
|
||||
size: Extent3d {
|
||||
@@ -382,7 +405,7 @@ impl GpuTextures {
|
||||
pub fn new(device: &Device, queue: &Queue) -> Self {
|
||||
let sampler = default_sampler(device);
|
||||
let null_view = null_texture_view(device);
|
||||
let array_capacity = 1;
|
||||
let array_capacity = MIN_ARRAY_LAYERS;
|
||||
let array_texture = Self::create_array_texture(device, array_capacity);
|
||||
let array_view = array_texture.create_view(&TextureViewDescriptor {
|
||||
dimension: Some(TextureViewDimension::D2Array),
|
||||
|
||||
Reference in new issue
Block a user