Commit Graph

79 Commits

Author SHA1 Message Date
Elias Naur 0ba984c19c gpu: [compute] don't change vertex buffers during render passes
Vulkan doesn't support it, so move vertex buffer updates outside render
passes. Splitting render passes is another approach, but not as
efficient.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-09-21 17:53:05 +02:00
Elias Naur 21ca9d13a8 gpu: switch from uniform buffers to combined push buffers
Vulkan doesn't support changing uniforms during a render pass. However,
push constants *can* be changed. The gio-shader repository was changed
to use push constants instead of uniforms, this change implements the
corresponding driver and renderer change.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-09-21 17:53:02 +02:00
Elias Naur 3d1e9b0856 gpu: rename DrawMode to Topology and move it to pipeline descriptors
Vulkan needs the topology stated in its pipeline descriptor, not at
draw time.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-09-20 15:13:00 +02:00
Elias Naur 41e812d5e8 gpu: [compute] always bind valid materials texture
Currently, we run kernel4.comp with whatever texture was
bound (or none) when there are no materials in the set of layers.

However, Vulkan require every image binding to a compute shader to be
non-null and valid. This change works around that limitation by binding
a small dummy texture when no materials are needed.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-09-20 15:13:00 +02:00
Elias Naur cc2edbaa51 gpu: introduce render passes
Modern GPU API such as Metal and Vulkan use explicit render passes
and command buffers for recording rendering commands. They don't have
global state; each render pass starts with a clean set of bound
textures, pipeline etc.

Change our GPU abstraction to better match newer API and modify our two
renderers to explicitly describe their render passes.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-09-20 15:13:00 +02:00
Elias Naur 173f14be78 gpu: [compute] don't leak driver.Device instance
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-09-09 12:39:02 +02:00
Elias Naur f3f4bacb1c gpu: don't leak GPU buffer from sizedBuffer.Release
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-09-07 16:31:49 +02:00
Elias Naur 2749eb91f3 gpu: [compute] clip image materials to their rendered size
Before this change, transformed images would take up as much atlas
texture space to fit them. However, we can easily run out of space for
large images or images with large scaling applied.

This change limits transformed images to their rendered bounds which is
the window size in the worst case.

Updates gio#219 (fixes the chat kitchen example)

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-27 12:59:01 +02:00
Elias Naur 9e9cb17a5d gpu: [compute] clip transformed images to their bounds
A follow-up change will cause some transformed images to render outside
their allocated atlas bounds. This change uses the GPU viewport to clip
them so they won't overwrite other atlas content.

Updates gio#219

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-27 12:59:01 +02:00
Elias Naur 6818af9390 gpu: [compute] get rid of material regions
The atlas allocations contains enough information to replace regions.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-27 12:59:01 +02:00
Elias Naur 7f6e376424 gpu,gpu/internal: support variable strides in ReadPixels
It saves a roundtrip to scratch memory when the CPU fallback renderer
downloads rendered materials.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-27 12:59:01 +02:00
Elias Naur 06ffa42d16 gpu: [compute] support unlimited number of materials and images
This change extends the atlas allocation machinery to images and
materials.

Updates gio#219

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-27 12:59:01 +02:00
Elias Naur 1d7ed55c29 gpu: support rectangular atlas packers
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-27 07:48:26 +02:00
Elias Naur 414be0a0b3 gpu: Merge GPU.Collect and GPU.Frame
There's no meaningful reason to have them separate. The intention was to
enable rendering concurrent with other processing, but that's gaining
framerate at the expense of input latency and complicating ImageOp
semantics.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-24 08:30:52 +02:00
Elias Naur 64ccb1c06d gpu: [compute] add missing error handling
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-21 16:48:50 +02:00
Elias Naur 86e474688b gpu: [compute] don't round atlas dimensions to power-of-twos
There is no clear benefit and the rounding tends to waste texture
memory.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-21 16:40:21 +02:00
Elias Naur c9970cb8e3 gpu,gpu/internal,internal/gl: replace BlitFramebuffer with CopyTexture
OpenGL ES 2.0 doesn't support glBlitFramebuffer, but does support
glCopyTexSubImage2D. Fortunately, we don't need the extra features of
glBlitFramebuffer anyway.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-21 11:16:28 +02:00
Elias Naur a7f08eedf3 gpu,gpu/internal: split shader storage usage into read and write
Metal has texture write usage flags for read and write.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-21 08:31:46 +02:00
Elias Naur 07fdc1a2de gpu,gpu/internal: drop implied transformation from BlitFramebuffer
The Metal (and presumably the D3D11) backend doesn't support transformed
framebuffer blits. The only caller doesn't need it either, so drop that
capability from the driver abstraction.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-21 08:31:46 +02:00
Elias Naur 58cc817e5f gpu,gpu/internal: move vertex buffer stride to pipeline state
Metal needs the vertex stride at pipeline creation.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-21 08:31:46 +02:00
Elias Naur 1af910959b gpu: fold buffer clearing into framebuffer bind
In Metal, clearing a framebuffer is most efficiently done during bind.
Modify our driver accordingly.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-21 08:31:46 +02:00
Elias Naur d38c78d7ac gpu,gpu/internal: move InputDesc back from gioui.org/shader module
It was moved to gioui.org/shader by mistake.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-21 08:31:46 +02:00
Elias Naur afaa31eca8 gpu: introduce pipeline abstraction
Modern API such as Metal and Vulkan want clients to compile expensive
state changes into pipeline objects. Change our GPU driver abstraction
to match, thereby paving the way for future drivers.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-21 08:31:46 +02:00
Elias Naur 13b93b27d8 gpu: update gioui.org/shader for portable materials.vert shader
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-21 08:31:46 +02:00
Elias Naur 8140e39c20 go.*,gpu: use gioui.org/cpu.Supported to determine CPU fallback support
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-17 09:44:17 +02:00
Elias Naur 6aee543234 all: switch to external shaders in the gioui.org/shaders module
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-08 13:47:41 +01:00
Elias Naur 18b4442393 all: remove Z buffer support
It is no longer needed by any rendering backend.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-08 13:47:37 +01:00
Elias Naur 7d84e419c9 gpu,gpu/headless,app/internal/wm: add explicit RenderTarget API
Both the OpenGL and the Direct3D API are stateful and gpu.GPU renders to
the render target current when Frame is called.

Modern GPU API such as Metal don't have a concept of a current render
target, and the target even changes each frame.

Add RenderTarget and add an explicit target argument to GPU.Frame as
well as the underlying driver.Device.BeginFrame.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-08 13:45:23 +01:00
Elias Naur 8cec7e04eb gpu,gpu/shaders: [compute] decode sRGB texels in shader when EXT_sRGB is missing
This change avoids the hard dependency on GPU support for sRGB encoded
textures in the compute renderer.

With this change and the previously added CPU fallback, Gio no longer
rely on any GPU functionality outside the OpenGL ES 2.0 level.

Fixes gio#49
Fixes gio#154
Fixes gio#97
Fixes gio#36
Fixes gio#172

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-29 09:05:55 +02:00
Elias Naur b3a8c24334 gpu/internal/driver: rename TextureFormatSRGB to TextureFormatSRGBA
The format implies an alpha channel; name it accordingly.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-29 08:37:18 +02:00
Elias Naur ea38195e2e gpu: [compute] add CPU fallback
This change adds a CPU fallback for devices that don't support the old
renderer nor have GPU support for compute programs.

Most of the hard work is implemented in the gioui.org/cpu module. It
uses the SwiftShader project with light modification to output
statically compiled CPU .o files for each compute program.

The CPU fallback only covers Linux and Android on arm, arm64, amd64
architectures. There is no fundamental reason support can't be extended
to other platforms:

- macOS and iOS are probably easy, but it's likely that virtually every
  device has GPU support for compute shaders.
- Windows needs a Cgo-less port, or a build constraint to require a C
  compiler (Gio core doesn't).
- FreeBSD and OpenBSD are probably also easy to do because they're so
  similar to Linux.
- The 386 binaries didn't work properly in my tests, so fixes to
  SwiftShader is probably needed. However, I expect virtually every
  Intel device can run amd64 binaries.

Updates gio#49
Fixes gio#228

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-27 14:56:50 +02:00
Elias Naur 5197f637a7 gpu: [compute] compute and store clipping path hashes during construction
The hash of the clipping paths that affect drawing operations are computed
and used to quickly determine that two operations are not equal, the
most likely outcome of a comparison.

However, for paths that are constructed once and cached computing the
hash at every frame is wasteful. This is especially true for text, which
is both cached and also among the largest paths in a frame.

This change moves the hashing to op/clip.Path construction time, and
stores the hash in the ops list so it won't be re-computed at every use.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-27 14:34:18 +02:00
Elias Naur 88fb798cca gpu: [compute] speed up path comparisons with op keys
To re-use previously cached layers, the compute renderer must know
whether two drawing operations are equal. In the case two operations are
not equal, a fast hash comparison will most likely fail. In the case two
equal operations with complicated clipping paths, the comparison of the
path data is expensive.

This change adds support for fast ops.Key comparisons, where two paths
are equal if their ops.Key are. This is an optimization that kicks in
for text rendering, where glyph clipping shapes are re-used across
frames.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-27 14:34:18 +02:00
Elias Naur 4ab872e36a gpu: [compute] re-use layers that differ only in integer offsets
To re-use drawing operations common to two layers, every operation must
exactly match, including their transformations. However, layers that
differ only by an integer offset can be re-used because rendering does
not depend on the absolute integer offset. This is important in the very
common case of scrolling otherwise static UI content.

This change separate the integer offset from drawing operations and
relaxes the layer cache to match layers that differ only in integer
offsets.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-27 14:34:18 +02:00
Elias Naur 318ddd0644 gpu: [compute] add function for separating integer offsets from transforms
Refactor only; separateTransform is needed in the following change.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-27 14:34:18 +02:00
Elias Naur e6c31a02fd gpu: [compute] cache and re-use drawing operations from the previous frame
The compute renderer is more expensive to run than the old renderer on
low-end GPUs, and even more so on CPUs. To ensure good performance
regardless of the end-user device, this change implements automatic
re-use of content rendered in the frame before the current.

The basic idea is that every drawing operation (PaintOp), along with its
transform and clipping, can be hashed and efficiently looked up. A naïve
caching approach is then to rasterize every operation to separate
sections of several large texture atlases, turning a cache hit into a
very cheap texture copy.

However, for scenes with lots of overlapping operations, the resulting
texture memory from separating the operations would be much larger than
the memory for just the window framebuffer.

So instead of caching individual operations, this change caches layers,
which are sequences of drawing operations. It starts by putting all
operations into a single layer. Then, if the subsequent frame re-uses a
sub-sequence of that larger layer, it is split.

For example, consider a UI similar to the kitchen sample:

Hello, Gio

<Editor>

<Line Editor>

<Button> <Button> <Button>

<ProgressBar>

<Checkbox> <Toggle>

In the first frame, all of the drawing operations comprising the UI will
be stored and cached in a single layer. In the second frame the
progress bar will have moved and the renderer splits the UI into three
layers: layer A for everything up to (but not including) the progress
bar, layer B with just the progress bar, and layer C for the rest. Note
that nothing has been re-used yet. In the third frame, the progress bar
moves again, and this time layer A and C can be copied from the cache
only the progress bar needs redrawing through the compute programs.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-27 14:34:18 +02:00
Elias Naur 938e51f111 gpu: [compute] clear viewport through glClear, not through compute
The performance difference is negligible, but is useful when the compute
pipeline can skip rendering to empty tiles.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-27 14:34:18 +02:00
Elias Naur 89ab5ebf4f gpu: [compute] unify resource cleanup
Rename all resource release methods to "Release", and release all
resources with a slice and loop.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-27 14:34:18 +02:00
Elias Naur b87cbc04f3 gpu: [compute] add compute renderer specific decoding of ops
Until now, the two renderers have shared structures and code for
decoding drawing ops and convert them to GPU-friendly structures.

However, the decoder is tailored to the old renderer and use
structures that poorly fits the new compute renderer.

This change copies the decoder and specializes the copy for the compute
renderer, avoiding a round-trip through the old renderer decoder.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-27 14:34:18 +02:00
Elias Naur 60a47e7de5 gpu/internal,internal/gl: add support for strided texture uploads
The CPU fallback of the compute renderer needs to upload subtextures
from a larger image.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-27 14:34:18 +02:00
Elias Naur 9188690e9e gpu: [compute] don't leak a texture if its framebuffer allocation fails
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-07-27 12:57:53 +02:00
Elias Naur d331f63d20 gpu: [compute] move material clip space transformation to the GPU
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-06-28 08:35:41 +02:00
Elias Naur 39775f555a gp/internal/opengl: support sRGB emulation for embedded content
Programs such as gio-example/glfw rely on Gio drawing blending with
the framebuffer background. This change makes it so when sRGB emulation
is active.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-05-16 18:17:00 +02:00
Elias Naur 21c319ace5 gpu/internal/opengl,internal: move sRGB emulation to OpenGL driver
There is only one driver but several backends (EGL, WebGL).

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-05-16 10:44:45 +02:00
Elias Naur 82fff0178b gpu: [compute] generalize sizedBuffer to cover vertex buffers
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-05-04 21:35:39 +02:00
Elias Naur f655027110 gpu: [compute] add materials and blit timers to profiling output
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-04-27 16:49:06 +02:00
Elias Naur 53aad36ac1 gpu: [compute] move encoding to Collect
Collect is for converting ops to GPU commands, Frame is for actual
rendering. There's little practical difference, but makes profiling
easier to distinguish between conversion and rendering.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-04-27 16:49:06 +02:00
Elias Naur 157430a3d2 gpu: [compute] move timer initialization from Collect to Frame
GPU operations logically belong in the Frame method, and it's probably
best to keep them inside BeginFrame/EndFrame as well.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-04-27 16:49:06 +02:00
Elias Naur bc2c3db43e op/clip,gpu: move approximation of complex strokes to op/clip.Op.Add
Before this change, the two renderers both had special case code for
approximating strokes they don't support natively. This change moves
that conversion to clip.Op.Add, for several reasons:

- The compute renderer no longer need fallback logic and caches for
  strokes it doesn't support.
- The approximation logic is slow. Moving it to clip.Op.Add will not
  speed it up, but will make the cost easier to spot in profiles. Until all
  strokes are supported natively, users can use macros to cache
  expensive strokes.
- Reduced garbage: Op.Add takes an op.Ops anyway, and can use that for
  storing the approximated stroke outline.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-23 19:37:45 +01:00
Elias Naur 0a4b6549da internal/stroke,gpu: move stroking of path data to package internal/strokg
Pure refactor, preparing for use in op/clip.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-23 15:42:43 +01:00