forked from joejulian/gio
op,internal/ops: support CallOps without macros
A recorded macro is prefixed with an internal macro op that stores
the end of the macro. The end is used to efficiently skip the macro
when not calling it. The call a macro, the CallOp stores the start
position of the macro.
To support seamless wrapping of Ops lists, this change removes the
dependency on the macro op prefix from CallOp. Internal code can
now call an Ops like this:
var ops op.Ops
var wrapper op.Ops
ops.AddCall(&wrapper.Internal, &ops.Internal, ops.PC{}, ops.PCFor(&ops.Internal))
References: https://todo.sr.ht/~eliasnaur/gio/318
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+4
-2
@@ -119,7 +119,7 @@ const (
|
||||
|
||||
const (
|
||||
TypeMacroLen = 1 + 4 + 4
|
||||
TypeCallLen = 1 + 4 + 4
|
||||
TypeCallLen = 1 + 4 + 4 + 4 + 4
|
||||
TypeDeferLen = 1
|
||||
TypePushTransformLen = 1 + 4*6
|
||||
TypeTransformLen = 1 + 1 + 4*6
|
||||
@@ -240,12 +240,14 @@ func FillMacro(o *Ops, startPC PC) {
|
||||
bo.PutUint32(data[5:], uint32(pc.refs))
|
||||
}
|
||||
|
||||
func AddCall(o *Ops, callOps *Ops, pc PC) {
|
||||
func AddCall(o *Ops, callOps *Ops, pc PC, end PC) {
|
||||
data := Write1(o, TypeCallLen, callOps)
|
||||
data[0] = byte(TypeCall)
|
||||
bo := binary.LittleEndian
|
||||
bo.PutUint32(data[1:], uint32(pc.data))
|
||||
bo.PutUint32(data[5:], uint32(pc.refs))
|
||||
bo.PutUint32(data[9:], uint32(end.data))
|
||||
bo.PutUint32(data[13:], uint32(end.refs))
|
||||
}
|
||||
|
||||
func PushOp(o *Ops, kind StackKind) (StackID, int) {
|
||||
|
||||
+21
-19
@@ -32,8 +32,9 @@ type Key struct {
|
||||
|
||||
// Shadow of op.MacroOp.
|
||||
type macroOp struct {
|
||||
ops *Ops
|
||||
pc PC
|
||||
ops *Ops
|
||||
start PC
|
||||
end PC
|
||||
}
|
||||
|
||||
// PC is an instruction counter for an operation list.
|
||||
@@ -52,6 +53,13 @@ type opMacroDef struct {
|
||||
endpc PC
|
||||
}
|
||||
|
||||
func (pc PC) Add(op OpType) PC {
|
||||
return PC{
|
||||
data: pc.data + op.Size(),
|
||||
refs: pc.refs + op.NumRefs(),
|
||||
}
|
||||
}
|
||||
|
||||
// Reset start reading from the beginning of ops.
|
||||
func (r *Reader) Reset(ops *Ops) {
|
||||
r.ResetAt(ops, PC{})
|
||||
@@ -128,24 +136,16 @@ func (r *Reader) Decode() (EncodedOp, bool) {
|
||||
}
|
||||
var op macroOp
|
||||
op.decode(data, refs)
|
||||
macroData := op.ops.data[op.pc.data:]
|
||||
if OpType(macroData[0]) != TypeMacro {
|
||||
panic("invalid macro reference")
|
||||
}
|
||||
var opDef opMacroDef
|
||||
opDef.decode(macroData[:TypeMacro.Size()])
|
||||
retPC := r.pc
|
||||
retPC.data += n
|
||||
retPC.refs += nrefs
|
||||
r.stack = append(r.stack, macro{
|
||||
ops: r.ops,
|
||||
retPC: retPC,
|
||||
endPC: opDef.endpc,
|
||||
endPC: op.end,
|
||||
})
|
||||
r.ops = op.ops
|
||||
r.pc = op.pc
|
||||
r.pc.data += TypeMacro.Size()
|
||||
r.pc.refs += TypeMacro.NumRefs()
|
||||
r.pc = op.start
|
||||
continue
|
||||
case TypeMacro:
|
||||
var op opMacroDef
|
||||
@@ -164,7 +164,7 @@ func (op *opMacroDef) decode(data []byte) {
|
||||
panic("invalid op")
|
||||
}
|
||||
bo := binary.LittleEndian
|
||||
data = data[:9]
|
||||
data = data[:TypeMacroLen]
|
||||
dataIdx := int(int32(bo.Uint32(data[1:])))
|
||||
refsIdx := int(int32(bo.Uint32(data[5:])))
|
||||
*op = opMacroDef{
|
||||
@@ -179,15 +179,17 @@ func (m *macroOp) decode(data []byte, refs []interface{}) {
|
||||
if OpType(data[0]) != TypeCall {
|
||||
panic("invalid op")
|
||||
}
|
||||
data = data[:9]
|
||||
data = data[:TypeCallLen]
|
||||
bo := binary.LittleEndian
|
||||
dataIdx := int(int32(bo.Uint32(data[1:])))
|
||||
refsIdx := int(int32(bo.Uint32(data[5:])))
|
||||
*m = macroOp{
|
||||
ops: refs[0].(*Ops),
|
||||
pc: PC{
|
||||
data: dataIdx,
|
||||
refs: refsIdx,
|
||||
start: PC{
|
||||
data: int(int32(bo.Uint32(data[1:]))),
|
||||
refs: int(int32(bo.Uint32(data[5:]))),
|
||||
},
|
||||
end: PC{
|
||||
data: int(int32(bo.Uint32(data[9:]))),
|
||||
refs: int(int32(bo.Uint32(data[13:]))),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,8 +92,9 @@ type MacroOp struct {
|
||||
// CallOp invokes the operations recorded by Record.
|
||||
type CallOp struct {
|
||||
// Ops is the list of operations to invoke.
|
||||
ops *ops.Ops
|
||||
pc ops.PC
|
||||
ops *ops.Ops
|
||||
start ops.PC
|
||||
end ops.PC
|
||||
}
|
||||
|
||||
// InvalidateOp requests a redraw at the given time. Use
|
||||
@@ -165,7 +166,9 @@ func (m MacroOp) Stop() CallOp {
|
||||
ops.FillMacro(m.ops, m.pc)
|
||||
return CallOp{
|
||||
ops: m.ops,
|
||||
pc: m.pc,
|
||||
// Skip macro header.
|
||||
start: m.pc.Add(ops.TypeMacro),
|
||||
end: ops.PCFor(m.ops),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +179,7 @@ func (c CallOp) Add(o *Ops) {
|
||||
if c.ops == nil {
|
||||
return
|
||||
}
|
||||
ops.AddCall(&o.Internal, c.ops, c.pc)
|
||||
ops.AddCall(&o.Internal, c.ops, c.start, c.end)
|
||||
}
|
||||
|
||||
func (r InvalidateOp) Add(o *Ops) {
|
||||
|
||||
Reference in New Issue
Block a user