mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-05 01:15:35 +00:00
internal/scene: extract compute shader encoding to a separate package
We're about to encode clip.Paths with the format compatible with the compute renderer. This change extracts the encoding to a re-usable package. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+21
-95
@@ -17,6 +17,7 @@ import (
|
|||||||
"gioui.org/gpu/internal/driver"
|
"gioui.org/gpu/internal/driver"
|
||||||
"gioui.org/internal/byteslice"
|
"gioui.org/internal/byteslice"
|
||||||
"gioui.org/internal/f32color"
|
"gioui.org/internal/f32color"
|
||||||
|
"gioui.org/internal/scene"
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/op"
|
"gioui.org/op"
|
||||||
)
|
)
|
||||||
@@ -121,7 +122,7 @@ type textureOp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type encoder struct {
|
type encoder struct {
|
||||||
scene []sceneElem
|
scene []scene.Command
|
||||||
npath int
|
npath int
|
||||||
npathseg int
|
npathseg int
|
||||||
}
|
}
|
||||||
@@ -149,8 +150,6 @@ type config struct {
|
|||||||
anno_alloc memAlloc
|
anno_alloc memAlloc
|
||||||
}
|
}
|
||||||
|
|
||||||
type sceneElem [sceneElemSize / 4]uint32
|
|
||||||
|
|
||||||
// memAlloc matches Alloc in mem.h
|
// memAlloc matches Alloc in mem.h
|
||||||
type memAlloc struct {
|
type memAlloc struct {
|
||||||
offset uint32
|
offset uint32
|
||||||
@@ -171,31 +170,12 @@ const (
|
|||||||
kernel4OutputUnit = 2
|
kernel4OutputUnit = 2
|
||||||
kernel4AtlasUnit = 3
|
kernel4AtlasUnit = 3
|
||||||
|
|
||||||
pathSize = 12
|
pathSize = 12
|
||||||
binSize = 8
|
binSize = 8
|
||||||
pathsegSize = 44
|
pathsegSize = 44
|
||||||
annoSize = 28
|
annoSize = 28
|
||||||
stateSize = 60
|
stateSize = 60
|
||||||
stateStride = 4 + 2*stateSize
|
stateStride = 4 + 2*stateSize
|
||||||
sceneElemSize = 36
|
|
||||||
)
|
|
||||||
|
|
||||||
// GPU commands from scene.h
|
|
||||||
const (
|
|
||||||
elemNop = iota
|
|
||||||
elemStrokeLine
|
|
||||||
elemFillLine
|
|
||||||
elemStrokeQuad
|
|
||||||
elemFillQuad
|
|
||||||
elemStrokeCubic
|
|
||||||
elemFillCubic
|
|
||||||
elemStroke
|
|
||||||
elemFill
|
|
||||||
elemLineWidth
|
|
||||||
elemTransform
|
|
||||||
elemBeginClip
|
|
||||||
elemEndClip
|
|
||||||
elemFillImage
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -747,17 +727,18 @@ func (g *compute) render(tileDims image.Point) error {
|
|||||||
|
|
||||||
// Pad scene with zeroes to avoid reading garbage in elements.comp.
|
// Pad scene with zeroes to avoid reading garbage in elements.comp.
|
||||||
scenePadding := partitionSize - len(g.enc.scene)%partitionSize
|
scenePadding := partitionSize - len(g.enc.scene)%partitionSize
|
||||||
g.enc.scene = append(g.enc.scene, make([]sceneElem, scenePadding)...)
|
g.enc.scene = append(g.enc.scene, make([]scene.Command, scenePadding)...)
|
||||||
|
|
||||||
realloced := false
|
realloced := false
|
||||||
if s := len(g.enc.scene) * sceneElemSize; s > g.buffers.scene.size {
|
scene := byteslice.Slice(g.enc.scene)
|
||||||
|
if s := len(scene); s > g.buffers.scene.size {
|
||||||
realloced = true
|
realloced = true
|
||||||
paddedCap := s * 11 / 10
|
paddedCap := s * 11 / 10
|
||||||
if err := g.buffers.scene.ensureCapacity(g.ctx, paddedCap); err != nil {
|
if err := g.buffers.scene.ensureCapacity(g.ctx, paddedCap); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.buffers.scene.buffer.Upload(byteslice.Slice(g.enc.scene))
|
g.buffers.scene.buffer.Upload(scene)
|
||||||
|
|
||||||
w, h := tileDims.X*tileWidthPx, tileDims.Y*tileHeightPx
|
w, h := tileDims.X*tileWidthPx, tileDims.Y*tileHeightPx
|
||||||
if g.output.size.X != w || g.output.size.Y != h {
|
if g.output.size.X != w || g.output.size.Y != h {
|
||||||
@@ -1029,52 +1010,25 @@ func (e *encoder) append(e2 encoder) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *encoder) transform(m f32.Affine2D) {
|
func (e *encoder) transform(m f32.Affine2D) {
|
||||||
sx, hx, ox, hy, sy, oy := m.Elems()
|
e.scene = append(e.scene, scene.Transform(m))
|
||||||
e.scene = append(e.scene, sceneElem{
|
|
||||||
0: elemTransform,
|
|
||||||
1: math.Float32bits(sx),
|
|
||||||
2: math.Float32bits(hy),
|
|
||||||
3: math.Float32bits(hx),
|
|
||||||
4: math.Float32bits(sy),
|
|
||||||
5: math.Float32bits(ox),
|
|
||||||
6: math.Float32bits(oy),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *encoder) lineWidth(width float32) {
|
func (e *encoder) lineWidth(width float32) {
|
||||||
e.scene = append(e.scene, sceneElem{
|
e.scene = append(e.scene, scene.LineWidth(width))
|
||||||
0: elemLineWidth,
|
|
||||||
1: math.Float32bits(width),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *encoder) stroke(col color.RGBA) {
|
func (e *encoder) stroke(col color.RGBA) {
|
||||||
e.scene = append(e.scene, sceneElem{
|
e.scene = append(e.scene, scene.Stroke(col))
|
||||||
0: elemStroke,
|
|
||||||
1: uint32(col.R)<<24 | uint32(col.G)<<16 | uint32(col.B)<<8 | uint32(col.A),
|
|
||||||
})
|
|
||||||
e.npath++
|
e.npath++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *encoder) beginClip(bbox f32.Rectangle) {
|
func (e *encoder) beginClip(bbox f32.Rectangle) {
|
||||||
e.scene = append(e.scene, sceneElem{
|
e.scene = append(e.scene, scene.BeginClip(bbox))
|
||||||
0: elemBeginClip,
|
|
||||||
1: math.Float32bits(bbox.Min.X),
|
|
||||||
2: math.Float32bits(bbox.Min.Y),
|
|
||||||
3: math.Float32bits(bbox.Max.X),
|
|
||||||
4: math.Float32bits(bbox.Max.Y),
|
|
||||||
})
|
|
||||||
e.npath++
|
e.npath++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *encoder) endClip(bbox f32.Rectangle) {
|
func (e *encoder) endClip(bbox f32.Rectangle) {
|
||||||
e.scene = append(e.scene, sceneElem{
|
e.scene = append(e.scene, scene.EndClip(bbox))
|
||||||
0: elemEndClip,
|
|
||||||
1: math.Float32bits(bbox.Min.X),
|
|
||||||
2: math.Float32bits(bbox.Min.Y),
|
|
||||||
3: math.Float32bits(bbox.Max.X),
|
|
||||||
4: math.Float32bits(bbox.Max.Y),
|
|
||||||
})
|
|
||||||
e.npath++
|
e.npath++
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1088,10 +1042,7 @@ func (e *encoder) rect(r f32.Rectangle, stroke bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *encoder) fill(col color.RGBA) {
|
func (e *encoder) fill(col color.RGBA) {
|
||||||
e.scene = append(e.scene, sceneElem{
|
e.scene = append(e.scene, scene.Fill(col))
|
||||||
0: elemFill,
|
|
||||||
1: uint32(col.R)<<24 | uint32(col.G)<<16 | uint32(col.B)<<8 | uint32(col.A),
|
|
||||||
})
|
|
||||||
e.npath++
|
e.npath++
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1102,41 +1053,16 @@ func (e *encoder) setFillImageOffset(index int, offset image.Point) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *encoder) fillImage(index int) {
|
func (e *encoder) fillImage(index int) {
|
||||||
e.scene = append(e.scene, sceneElem{
|
e.scene = append(e.scene, scene.FillImage(index))
|
||||||
0: elemFillImage,
|
|
||||||
1: uint32(index),
|
|
||||||
})
|
|
||||||
e.npath++
|
e.npath++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *encoder) line(start, end f32.Point, stroke bool, flags uint32) {
|
func (e *encoder) line(start, end f32.Point, stroke bool, flags uint32) {
|
||||||
tag := uint32(elemFillLine)
|
e.scene = append(e.scene, scene.Line(start, end, stroke, flags))
|
||||||
if stroke {
|
|
||||||
tag = elemStrokeLine
|
|
||||||
}
|
|
||||||
e.scene = append(e.scene, sceneElem{
|
|
||||||
0: flags<<16 | tag,
|
|
||||||
1: math.Float32bits(start.X),
|
|
||||||
2: math.Float32bits(start.Y),
|
|
||||||
3: math.Float32bits(end.X),
|
|
||||||
4: math.Float32bits(end.Y),
|
|
||||||
})
|
|
||||||
e.npathseg++
|
e.npathseg++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *encoder) quad(start, ctrl, end f32.Point, stroke bool) {
|
func (e *encoder) quad(start, ctrl, end f32.Point, stroke bool) {
|
||||||
tag := uint32(elemFillQuad)
|
e.scene = append(e.scene, scene.Quad(start, ctrl, end, stroke))
|
||||||
if stroke {
|
|
||||||
tag = elemStrokeQuad
|
|
||||||
}
|
|
||||||
e.scene = append(e.scene, sceneElem{
|
|
||||||
0: tag,
|
|
||||||
1: math.Float32bits(start.X),
|
|
||||||
2: math.Float32bits(start.Y),
|
|
||||||
3: math.Float32bits(ctrl.X),
|
|
||||||
4: math.Float32bits(ctrl.Y),
|
|
||||||
5: math.Float32bits(end.X),
|
|
||||||
6: math.Float32bits(end.Y),
|
|
||||||
})
|
|
||||||
e.npathseg++
|
e.npathseg++
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
// SPDX-License-Identifier: Unlicense OR MIT
|
||||||
|
|
||||||
|
// Package scene encodes and decodes graphics commands in the format used by the
|
||||||
|
// compute renderer.
|
||||||
|
package scene
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image/color"
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"gioui.org/f32"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Command [sceneElemSize / 4]uint32
|
||||||
|
|
||||||
|
const sceneElemSize = 36
|
||||||
|
|
||||||
|
// GPU commands from scene.h
|
||||||
|
const (
|
||||||
|
elemNop = iota
|
||||||
|
elemStrokeLine
|
||||||
|
elemFillLine
|
||||||
|
elemStrokeQuad
|
||||||
|
elemFillQuad
|
||||||
|
elemStrokeCubic
|
||||||
|
elemFillCubic
|
||||||
|
elemStroke
|
||||||
|
elemFill
|
||||||
|
elemLineWidth
|
||||||
|
elemTransform
|
||||||
|
elemBeginClip
|
||||||
|
elemEndClip
|
||||||
|
elemFillImage
|
||||||
|
)
|
||||||
|
|
||||||
|
func Line(start, end f32.Point, stroke bool, flags uint32) Command {
|
||||||
|
tag := uint32(elemFillLine)
|
||||||
|
if stroke {
|
||||||
|
tag = elemStrokeLine
|
||||||
|
}
|
||||||
|
return Command{
|
||||||
|
0: flags<<16 | tag,
|
||||||
|
1: math.Float32bits(start.X),
|
||||||
|
2: math.Float32bits(start.Y),
|
||||||
|
3: math.Float32bits(end.X),
|
||||||
|
4: math.Float32bits(end.Y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Quad(start, ctrl, end f32.Point, stroke bool) Command {
|
||||||
|
tag := uint32(elemFillQuad)
|
||||||
|
if stroke {
|
||||||
|
tag = elemStrokeQuad
|
||||||
|
}
|
||||||
|
return Command{
|
||||||
|
0: tag,
|
||||||
|
1: math.Float32bits(start.X),
|
||||||
|
2: math.Float32bits(start.Y),
|
||||||
|
3: math.Float32bits(ctrl.X),
|
||||||
|
4: math.Float32bits(ctrl.Y),
|
||||||
|
5: math.Float32bits(end.X),
|
||||||
|
6: math.Float32bits(end.Y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Transform(m f32.Affine2D) Command {
|
||||||
|
sx, hx, ox, hy, sy, oy := m.Elems()
|
||||||
|
return Command{
|
||||||
|
0: elemTransform,
|
||||||
|
1: math.Float32bits(sx),
|
||||||
|
2: math.Float32bits(hy),
|
||||||
|
3: math.Float32bits(hx),
|
||||||
|
4: math.Float32bits(sy),
|
||||||
|
5: math.Float32bits(ox),
|
||||||
|
6: math.Float32bits(oy),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func LineWidth(width float32) Command {
|
||||||
|
return Command{
|
||||||
|
0: elemLineWidth,
|
||||||
|
1: math.Float32bits(width),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Stroke(col color.RGBA) Command {
|
||||||
|
return Command{
|
||||||
|
0: elemStroke,
|
||||||
|
1: uint32(col.R)<<24 | uint32(col.G)<<16 | uint32(col.B)<<8 | uint32(col.A),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BeginClip(bbox f32.Rectangle) Command {
|
||||||
|
return Command{
|
||||||
|
0: elemBeginClip,
|
||||||
|
1: math.Float32bits(bbox.Min.X),
|
||||||
|
2: math.Float32bits(bbox.Min.Y),
|
||||||
|
3: math.Float32bits(bbox.Max.X),
|
||||||
|
4: math.Float32bits(bbox.Max.Y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func EndClip(bbox f32.Rectangle) Command {
|
||||||
|
return Command{
|
||||||
|
0: elemEndClip,
|
||||||
|
1: math.Float32bits(bbox.Min.X),
|
||||||
|
2: math.Float32bits(bbox.Min.Y),
|
||||||
|
3: math.Float32bits(bbox.Max.X),
|
||||||
|
4: math.Float32bits(bbox.Max.Y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fill(col color.RGBA) Command {
|
||||||
|
return Command{
|
||||||
|
0: elemFill,
|
||||||
|
1: uint32(col.R)<<24 | uint32(col.G)<<16 | uint32(col.B)<<8 | uint32(col.A),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FillImage(index int) Command {
|
||||||
|
return Command{
|
||||||
|
0: elemFillImage,
|
||||||
|
1: uint32(index),
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user