The OpenGL (ES) implementations on Apple platforms are deprecated and
don't support GPU compute programs. This change adds support for the
replacement, the Metal GPU API.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
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>
The default renderer tracks opaque rectangle draw operations and render
them front-to-back with a z-buffer to omit overdraw. However,
- Overlapping opaque rectangles are rare in a GUI, and the most common
instance, a solid window background, is already optimized to a glClear.
- A z-buffer is memory heavy.
- We conservatively assume a 16-bit depth buffer, which limits the
number of drawing operations to 64k (#127).
- Depth buffer support makes GPU ports more complex, especially for
upcoming ports (Metal, Vulkan).
- The compute renderer doesn't use z-buffers.
This change removes the optimization; a follow-up removes GPU backend
support.
Fixes gio#127
Signed-off-by: Elias Naur <mail@eliasnaur.com>
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>
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>
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>
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>
The transformation information in ops.Key is a layer violation.
Introduce a key type specific to package gpu and use that instead.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
To ease the integration with foreign OpenGL contexts, carefully save the
context state before rendering a frame and restore it afterwards. Gio
rendering can then be mixed with OpenGL code that expects exclusive
control over context state.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
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>
The current renderer transforms and processes paths before sending them
to the GPU. It can compute bounds during processing.
The new renderer passes paths verbatim to the GPU, but needs the bounds
for constructing clip bounds.
This change computes the bounds during construction, so it is available
at use. As a bonus for storing the bounds with the path, path caches
(such as for storing text fragments) automatically reuse the bounds
calculations as well.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
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>
To avoid an import cycle in a future change, internal/stroke can no
longer import op/clip. Move required op/clip functionality to
internal/stroke and duplicate the remaining types.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Complex strokes are not yet supported in either of the current renderers,
so they are converted to filled outlines in package gpu.
We're about to move that complexity up to the op/clip package, so we're
going to need the converter available from outside package gpu. This
change extracts the conversion code and related types to the separate,
internal package stroke.
No functional changes; a follow-up moves the stroke conversion.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
In the old renderer, all strokes are converted to filled paths. The new
renderer can draw simple strokes natively. Do that, and avoid the costly
conversions.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The fill mode is now controlled by a SetFillMode command, not by flags
on each path segment and fill command.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Since clip.Path now encodes paths in the format expected by
elements.comp, use that data directly instead of a roundtrip through
drawOps.buildVerts.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
We're about to let clip.Path use more of the compute renderer features
(lines, cubic béziers). This change prepares the gpu package for reading
one of several commands types, not just the quadratic béziers of before.
The old Quad type is still the basis for the stroking algorithms, but
this change moves it into package gpu which is the only user.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The check for path segments in gpu is redundant; clip.Op.Add doesn't add
the Path op if there were no segments.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
All functions left in the old package unsafe were provided byte slice
views of other types. Rename the package accordingly and avoid a name
clash with the standard library package unsafe.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Outline represents a clipping operations that clips all drawing outside
a closed path. Before this change, paths not closed we're patched up by
adding an implicit line from the endpoint to the beginning.
These fixups are inefficient for a rare case, but acceptable because the
old renderer post-processes all paths anyway. However, the new compute
renderer don't need post-processing in most cases, making fixups too
expensive.
Given that clipping to an open path is fundamentally undefined and that
implicit fixup with a closing line segment is merely a way to force the
clip to be well-defined, this change adds a panic to Outline for Paths
that are not closed.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
It is no longer necessary for outside users of package gpu to explicitly
initialize a specific driver. The Direct3D driver is already internal,
this moves the OpenGL driver internally as well. The rename to opengl is
to avoid the name clash with the low-level "gioui.org/internal/glimpl"
package that we're about to rename.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
There are no longer any importers of package backend outside of
gioui.org/gpu. Move it internally, and rename it to the slightly more
specific "driver" while we're at it.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The package app/internal/d3d11 now contains only the GPU backend on
Direct3D. Move it below package gpu to reflect that.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
NewDevice creates a Device given an API, which is the necessary GPU
resources for a backend.
Convert gpu.New to take an API instead of a backend.Device directly.
In turn, this frees us to later unexport the backend package along with
the backend implementations (for now just gioui.org/gpu/gl for OpenGL).
It also allows programs that embed Gio (such as gioui.org/example/glfw)
to freely choose a backend, not just OpenGL.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
We'd like to allow Gio to share a Direct3D context with an embedding
program like the GLFW example does for OpenGL. To do that, d3d11.Device
needs to carry only the minimal information needed (ID3D11Device).
This change moves the caches of ID3D11DepthStencilState and
ID3D11BlendState from from d3d11.Device to d3d11.Backend. It also adds a
Release method for freeing them.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Return the output framebuffer from BeginFrame, to make it clear that
it may change between frames. Delete CurrentFramebuffer which is no
longer needed.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Gio UI may be overlaid on top of custom graphics such as in the glfw example.
That will only work if Gio doesn't clear the screen (to white).
Signed-off-by: Elias Naur <mail@eliasnaur.com>
It turns out restoring all operation state from the moment Defer
is executed is too much; for example, a right-click pop-up needs
the transformation, but not the current clip.
Change Defer to only restore the transformation, and reset all
other state.
Other combinations may be needed in future; we'll deal with them then,
possibly by exposing the load state mask.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Push/Pop only allows saving and restoring operation state in a
stack-like manner. We're going to need restoring arbitrary state
for implementing deferred operations.
Generalize state save/restore and implement Push and Pop on top of
that.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The new compute renderer is much less tolerant of discontinuous paths.
In particular, it requires that clip outlines form a closed loop.
Fixes TestPaintArc when GIORENDERER=forcecompute.
Signed-off-by: Elias Naur <mail@eliasnaur.com>