~eliasnaur/gio#131: 
gpu: display artifacts when using a large atlas size

Paths rasterized to the atlas with a texture coordinate beyond 8192 pixels in either dimension degrades the output in various ways. For example, some paths are clipped significantly, entirely invisible, or rendered as a mashup of multiple adjacent paths in the atlas. This is particularly easy to trigger when drawing many moderately sized paths that fill a window on a high-resolution display. An example program demonstrates the issue:

package main

import (
        "image/color"
        "log"

        "gioui.org/app"
        "gioui.org/f32"
        "gioui.org/io/system"
        "gioui.org/op"
        "gioui.org/op/clip"
        "gioui.org/op/paint"
        "gioui.org/unit"
)

const tiles = 4096
const stride = 64
const width = 32

func main() {
        go func() {
                w := app.NewWindow(
                        app.Size(unit.Dp(640), unit.Dp(480)),
                )
                ops := new(op.Ops)
                for {   
                        e := <-w.Events()
                        switch e := e.(type) {
                        case system.DestroyEvent:
                                log.Fatal(e.Err)
                        case system.FrameEvent:
                                ops.Reset()
                                for i := 0; i < tiles; i++ {
                                        stack := op.Push(ops)
                                        pt := f32.Pt(float32(i%stride)*width, float32(i/stride)*width)
                                        rect := f32.Rectangle{Min: pt, Max: pt.Add(f32.Pt(width, width))}
                                        clip.Rect{Rect: rect, SE: width / 4, SW: width / 4, NW: width / 4, NE: width / 4}.Add(ops)
                                        paint.ColorOp{Color: color.RGBA{R: 0xFF, A: 0xFF}}.Add(ops)
                                        paint.PaintOp{Rect: rect}.Add(ops)
                                        stack.Pop()
                                }
                                e.Frame(ops)
                        }
                }
        }()
        app.Main()
}

At first I thought this was a symptom #127 but it appears to be unrelated, as it can be reproduced with much fewer draw calls than are necessary to exhaust the z-buffer.

My current hypothesis is that some precision is getting lost somewhere during stenciling, but I haven't yet been able to narrow it down further. I'm still trying to understand the shaders themselves, as well as how the GL profile chooses precision, in conjunction with glslcc's SPIR-V compilation. The stencil shader inputs and outputs appear to be correct, when analyzed in RenderDoc, despite the results on the atlas appearing incorrect, but I did not perform an exhaustive analysis.

I am running a Gio application on Linux/X11 with the OpenGL 3.0 ES profile (with a Radeon RX 5700 XT), which reports a MAX_TEXTURE_SIZE of 16384.

A workaround is to artificially cap the max texture size to something reasonable, like 4k or 8k, which resolves the issue entirely.

I would probably have not encountered this/noticed except for:

  • The atlas grows for each shape drawn, despite every shape being the same.
  • The atlas packing algorithm prefers to grow in one direction until reaching the buffer bounds.

Example incorrect output (the entire screen should be full of red squares): https://user-images.githubusercontent.com/639066/84194562-3247a480-aa6b-11ea-841a-2ed7985608ec.png

The same program/output as above, but with a wider window: https://user-images.githubusercontent.com/639066/84194585-3c69a300-aa6b-11ea-8e0e-0f2b0b298d82.png

Atlas extracted from RenderDoc (notice the large gap): https://user-images.githubusercontent.com/639066/84194599-4095c080-aa6b-11ea-82ee-c445093c70b9.png

Status
REPORTED
Submitter
~lrewega
Assigned to
No-one
Submitted
29 days ago
Updated
27 days ago
Labels
No labels applied.

~eliasnaur 29 days ago

Nice analysis, thank you. This may be solvable by tweaking with the shader float precision, but capping the texture size is probably best. Can I persuade you to send a patch that fixes your problem, along with a test in app/headless?

~lrewega 29 days ago

Yes, patch submitted: https://lists.sr.ht/~eliasnaur/gio-patches/patches/10968

I will add a test and update the series.

~lrewega 29 days ago

FWIW I tried abusing glslcc to use highp everywhere in addition to manually adding highp everywhere possible to the input shaders, and saw no discernible improvement. I have begun to suspect either the loss of precision is not happening in the shader, or it is innate to the profile being used.

~lrewega 29 days ago

So, funny story: I can't actually reproduce this in headless mode. The issue doesn't seem to happen there.

~eliasnaur closed duplicate ticket #133 28 days ago

~tainted-bit closed duplicate ticket #133 27 days ago

~lrewega 27 days ago

I can't actually reproduce this in headless mode.

I lied, math is hard. I updated the patch series, though the test doesn't feel great, it will at least likely catch regressions.

Register here or Log in to comment, or comment via email.