blob: a45b5981660b0ba23bff1508c9ecf4807708bf9c [file] [log] [blame]
{{/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/}}
{{Global "module" ""}}
{{Include "go_common.tmpl"}}
{{$ | Macro "api.go" | GoFmt | Write "api.go"}}
{{define "api.go"}}
{{template "Go.GeneratedHeader" (Global "OutputDir")}}
import (
"fmt"
"android.googlesource.com/platform/tools/gpu/atom"
"android.googlesource.com/platform/tools/gpu/binary"
"android.googlesource.com/platform/tools/gpu/gfxapi"
"android.googlesource.com/platform/tools/gpu/log"
"android.googlesource.com/platform/tools/gpu/memory"
"android.googlesource.com/platform/tools/gpu/replay/builder"
"android.googlesource.com/platform/tools/gpu/service"
)
{{range $p := $.Pseudonyms}}
{{template "Pseudonym" $p}}
{{end}}
{{range $p := $.Pointers}}
{{template "Pointer" $p}}
{{end}}
{{range $s := $.StaticArrays}}
{{template "Array" $s}}
{{end}}
{{range $s := $.Slices}}
{{template "Slice" $s}}
{{end}}
{{range $m := $.Maps}}
{{template "Map" $m}}
{{end}}
{{range $i, $c := AllCommands $}}
{{Template "CommandEntry" "Command" $c "Index" $i}}
{{end}}
{{range $c := $.Classes}}
{{template "Class" $c}}
{{end}}
{{range $e := $.Enums}}
{{template "Enum" $e}}
{{end}}
{{template "State" $}}
{{template "NewAtoms" $}}
{{template "API" $}}
func init() {
gfxapi.Register(API())
}
func min(a, b uint64) uint64 {
if a < b {
return a
} else {
return b
}
}
// SliceInfo is the common data between all slice types.
type SliceInfo struct {
binary.Generate
Root memory.Pointer // Original pointer this slice derives from.
Base uint64 // Address of first element.
Count uint64 // Number of elements in the slice.
}
// Info returns the SliceInfo. It is used to conform to the Slice interface.
func (s SliceInfo) Info() SliceInfo { return s }
// Slice is the interface implemented by all slice types
type Slice interface {
// Info returns the SliceInfo of this slice.
Info() SliceInfo
// ElementSize returns the size in bytes of a single element in the slice.
ElementSizes *gfxapi.State) uint64
}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a type declaration for the specified pseudonym.
-------------------------------------------------------------------------------
*/}}
{{define "Pseudonym"}}
{{AssertType $ "Pseudonym"}}
{{$u := $ | Underlying}}
{{ if IsPointer $u}}{{Template "Pointer" $}}
{{else if IsSlice $u}}{{Template "Slice" $}}
{{else if IsVoid $u}}
{{else }}type {{$.Name}} {{Template "Go.Type" $.To}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a type declaration for the static-array type.
-------------------------------------------------------------------------------
*/}}
{{define "Array"}}
{{AssertType $ "StaticArray"}}
type {{Template "Go.Type" $}} struct {
binary.Generate
Elements [{{$.Size}}]{{Template "Go.Type" $.ValueType}}
}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a type declaration and implementation for the Pointer type or indirect
type (Pseudonym) to Pointer.
-------------------------------------------------------------------------------
*/}}
{{define "Pointer"}}
{{AssertType $ "Pointer" "Pseudonym"}}
{{$p := $ | Underlying | Unpack }}
{{$slice_ty := Macro "Go.Type" $p.Slice }}
{{$ptr_ty := Macro "Go.Type" $ }}
{{$el_ty := Macro "Go.Type" $p.To }}
{{$el_is_void := IsVoid ($p.To | Underlying | Unpack) }}
{{$el_is_char := IsChar ($p.To | Underlying | Unpack) }}
{{$el_is_ptr := IsPointer ($p.To | Underlying | Unpack) }}
// {{$ptr_ty}} is a pointer to a {{$el_ty}} element.
{{if $el_is_ptr}}
// Note: Pointers are stored differently between the application pool and internal pools.
// * The application pool stores pointers as an address of an architecture-dependant size.
// * Internal pools store pointers as an 64-bit unsigned address and a 32-bit unsigned
// pool identifier.
{{end}}
type {{$ptr_ty}} struct {
binary.Generate
memory.Pointer
}
// New{{$ptr_ty}} returns a {{$ptr_ty}} that points to addr in the application pool.
func New{{$ptr_ty}}(addr uint64) {{$ptr_ty}} {
return {{$ptr_ty}}{ Pointer: memory.Pointer{ Address: addr, Pool: memory.ApplicationPool } }
}
// ElementSize returns the size in bytes of an element that {{$ptr_ty}} points to.
func (p {{$ptr_ty}}) ElementSizes *gfxapi.State) uint64 {
{{if $el_is_ptr}}
if p.Pointer.Pool == memory.ApplicationPool {
return uint64s.Architecture.PointerSize)
} else {
return 12
}
{{else}}
return {{Template "Go.SizeOf" $p.To}}
{{end}}
}
{{if not $el_is_void}}
// Read reads and returns the {{$el_ty}} element at the pointer.
func (p {{$ptr_ty}}) Reada atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$el_ty}} {
return p.Slice(0, 1, ϟs).Reada, ϟs, ϟd, ϟl, ϟb)[0]
}
// Write writes value to the {{$el_ty}} element at the pointer.
func (p {{$ptr_ty}}) Write(value {{$el_ty}}, ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {
p.Slice(0, 1, ϟs).Write([]{{$el_ty}}{value}, ϟa, ϟs, ϟd, ϟl, ϟb)
}
{{end}}
// OnRead calls the backing pool's OnRead callback. p is returned so calls can be chained.
func (p {{$ptr_ty}}) OnReada atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$ptr_ty}} {
p.Slice(0, 1, ϟs).OnReada, ϟs, ϟd, ϟl, ϟb)
return p
}
// OnWrite calls the backing pool's OnWrite callback. p is returned so calls can be chained.
func (p {{$ptr_ty}}) OnWritea atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$ptr_ty}} {
p.Slice(0, 1, ϟs).OnWritea, ϟs, ϟd, ϟl, ϟb)
return p
}
func (p {{$ptr_ty}}) MapMemorya atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$ptr_ty}} {
p.Slice(0, 1, ϟs).MapMemorya, ϟs, ϟd, ϟl, ϟb)
return p
}
{{if $el_is_char}}
// StringSlice returns a slice starting at p and ending at the first 0 byte null-terminator.
func (p {{$ptr_ty}}) StringSlices *gfxapi.State, ϟd database.Database, ϟl log.Logger) Charˢ {
i, d := uint64(0), ϟs.MemoryDecoders.Memory[p.Pointer.Pool].At(p.Address), ϟd, ϟl)
for {
i++
if b, _ := d.Uint8(); b == 0 {
return Charˢ(p.Slice(0, i, ϟs))
}
}
}
{{end}}
// Slice returns a new {{$slice_ty}} from the pointer using start and end indices.
func (p {{$ptr_ty}}) Slice(start, end uint64, ϟs *gfxapi.State) {{$slice_ty}} {
if start > end {
panic(fmt.Errorf("Slice start (%d) is greater than the end (%d)", start, end))
}
return {{$slice_ty}}{SliceInfo: SliceInfo{Root: p.Pointer, Base: p.Address + start * p.ElementSizes), Count: end-start}}
}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a type declaration and implementation for the Slice type or indirect
type (Pseudonym) to Slice.
-------------------------------------------------------------------------------
*/}}
{{define "Slice"}}
{{AssertType $ "Slice" "Pseudonym"}}
{{$s := $ | Underlying | Unpack }}
{{$slice_ty := Macro "Go.Type" $ }}
{{$ptr_ty := Macro "Go.Type" $s.Pointer }}
{{$el_ty := Macro "Go.Type" $s.To }}
{{$el_size := Macro "Go.SizeOf" $s.To }}
{{$el_is_char := IsChar ($s.To | Underlying | Unpack) }}
{{$el_is_void := IsVoid ($s.To | Underlying | Unpack) }}
{{$el_is_ptr := IsPointer ($s.To | Underlying | Unpack) }}
// {{$slice_ty}} is a slice of {{$el_ty}}.
type {{$slice_ty}} struct {
binary.Generate
SliceInfo
}
{{if $el_is_char}}
// Make{{$slice_ty}}FromString returns a {{$slice_ty}} backed by a new
// memory pool containing a copy of str.
func Make{{$slice_ty}}FromString(str string, ϟs *gfxapi.State) {{$slice_ty}} {
pool := &memory.Pool{}
pool.Write(0, memory.Blob([]byte(str)))
id := ϟs.NextPoolID
ϟs.Memory[id] = pool
ϟs.NextPoolID++
return {{$slice_ty}}{ SliceInfo: SliceInfo{ Count: uint64(len(str)), Root: memory.Pointer{ Pool: id } } }
}
{{end}}
// Make{{$slice_ty}} returns a {{$slice_ty}} backed by a new memory pool.
func Make{{$slice_ty}}(count uint64, ϟs *gfxapi.State) {{$slice_ty}} {
id := ϟs.NextPoolID
ϟs.Memory[id] = &memory.Pool{}
ϟs.NextPoolID++
return {{$slice_ty}}{ SliceInfo: SliceInfo{ Count: count, Root: memory.Pointer{ Pool: id } } }
}
// Clone returns a copy of the {{$slice_ty}} in a new memory pool.
func (s {{$slice_ty}}) Clonea atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$slice_ty}} {
s.OnReada, ϟs, ϟd, ϟl, ϟb)
pool := &memory.Pool{}
pool.Write(0, ϟs.Memory[s.Root.Pool].Slice(s.Ranges)))
id := ϟs.NextPoolID
ϟs.Memory[id] = pool
ϟs.NextPoolID++
dst := {{$slice_ty}}{ SliceInfo: SliceInfo{ Count: s.Count, Root: memory.Pointer{ Pool: id } } }
return dst
}
// ElementSize returns the size in bytes of an element that {{$slice_ty}} points to.
func (s {{$slice_ty}}) ElementSizes *gfxapi.State) uint64 {
{{if $el_is_ptr}}
if s.Root.Pool == memory.ApplicationPool {
return uint64s.Architecture.PointerSize)
} else {
return 12
}
{{else}}
return {{Template "Go.SizeOf" $s.To}}
{{end}}
}
// Range returns the memory range this slice represents in the underlying pool.
func (s {{$slice_ty}}) Ranges *gfxapi.State) memory.Range {
return memory.Range{ Base: s.Base, Size: s.Count * s.ElementSizes) }
}
// ResourceID returns an identifier to a resource representing the data of
// this slice.
func (s {{$slice_ty}}) ResourceIDs *gfxapi.State, ϟd database.Database, ϟl log.Logger) binary.ID {
id, err := ϟs.Memory[s.Root.Pool].Slice(s.Ranges)).ResourceIDd, ϟl)
if err != nil {
panic(err)
}
return id
}
// Decoder returns a memory decoder for the slice.
func (s {{$slice_ty}}) Decoders *gfxapi.State, ϟd database.Database, ϟl log.Logger) binary.Decoder {
return ϟs.MemoryDecoders.Memory[s.Root.Pool].Slice(s.Ranges)), ϟd, ϟl)
}
// Encoder returns a memory encoder for the slice.
func (s {{$slice_ty}}) Encoders *gfxapi.State) binary.Encoder {
return ϟs.MemoryEncoders.Memory[s.Root.Pool], s.Ranges))
}
{{if not $el_is_void}}
// As{{$slice_ty}} returns s cast to a {{$slice_ty}}.
// The returned slice length will be calculated so that the returned slice is
// no longer (in bytes) than s.
func As{{$slice_ty}}(s Slice, ϟs *gfxapi.State) {{$slice_ty}} {
out := {{$slice_ty}}{ SliceInfo: s.Info() }
out.Count = (out.Count * s.ElementSizes)) / out.ElementSizes)
return out
}
// Read reads and returns all the {{$el_ty}} elements in this {{$slice_ty}}.
func (s {{$slice_ty}}) Reada atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) []{{$el_ty}} {
d, res := s.Decoders, ϟd, ϟl), make([]{{$el_ty}}, s.Count)
s.OnReada, ϟs, ϟd, ϟl, ϟb)
for i := range res {
{{if $el_is_ptr}}
if s.Root.Pool == memory.ApplicationPool {
ptr, err := binary.ReadUint(d, ϟs.Architecture.PointerSize*8)
if err != nil {
panic(err)
}
res[i] = New{{$el_ty}}(ptr)
} else {
{{end}}
{{Template "Go.Decode" "Name" "res[i]" "Type" $s.To "ErrHandler" "panic(err)"}}
{{if $el_is_ptr}} } {{end}}
}
return res
}
// Write copies elements from src to this slice. The number of elements copied is returned
// which is the minimum of s.Count and len(src).
func (s {{$slice_ty}}) Write(src []{{$el_ty}}, ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) uint64 {
count := min(s.Count, uint64(len(src)))
s = s.Slice(0, count, ϟs)
e := s.Encoders)
for i := uint64(0); i < count; i++ {
{{if $el_is_ptr}}
if s.Root.Pool == memory.ApplicationPool {
if err := binary.WriteUint(e, ϟs.Architecture.PointerSize*8, src[i].Address); err != nil {
panic(err)
}
} else {
{{end}}
{{Template "Go.Encode" "Name" "src[i]" "Type" $s.To "ErrHandler" "panic(err)"}}
{{if $el_is_ptr}} } {{end}}
}
s.OnWritea, ϟs, ϟd, ϟl, ϟb)
return count
}
// Copy copies elements from src to this slice.
// The number of elements copied is the minimum of dst.Count and src.Count.
// The slices of this and dst to the copied elements is returned.
func (dst {{$slice_ty}}) Copy(src {{$slice_ty}}, ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) (d, s {{$slice_ty}}) {
count := min(dst.Count, src.Count)
dst, src = dst.Slice(0, count, ϟs), src.Slice(0, count, ϟs)
{{if $el_is_ptr}}
if (dst.Root.Pool == memory.ApplicationPool) != (src.Root.Pool == memory.ApplicationPool) {
dst.Write(src.Reada, ϟs, ϟd, ϟl, ϟb), ϟa, ϟs, ϟd, ϟl, ϟb) // Element-wise copy so we can convert u64 <-> {{$ptr_ty}}
} else {
{{end}}
src.OnReada, ϟs, ϟd, ϟl, ϟb)
ϟs.Memory[dst.Root.Pool].Write(dst.Base, ϟs.Memory[src.Root.Pool].Slice(src.Ranges)))
dst.OnWritea, ϟs, ϟd, ϟl, ϟb)
{{if $el_is_ptr}} } {{end}}
return dst, src
}
{{end}}
// OnRead calls the backing pool's OnRead callback. s is returned so calls can be chained.
func (s {{$slice_ty}}) OnReada atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$slice_ty}} {
if f := ϟs.Memory[s.Root.Pool].OnRead; f != nil {
f(s.Ranges))
}
if ϟb != nil && s.Root.Pool == memory.ApplicationPool {
s.MapMemorya, ϟs, ϟd, ϟl, ϟb)
{{if (GetAnnotation $s.To "replay_remap")}}
{{/* Element type has explicitly stated it needs custom remapping */}}
ptr, step, d := value.RemappedPointer(s.Base), value.RemappedPointer(s.ElementSizes)), s.Decoders, ϟd, ϟl)
for i := uint64(0); i < s.Count; i++ {
var v {{$el_ty}}
{{Template "Go.Decode" "Name" "v" "Type" $s.To "ErrHandler" "panic(err)"}}
if key, remap := v.remapa, ϟs); remap {
loadRemapb, key, {{Template "Go.Replay.Type" $s.To}}, {{Template "Go.Replay.Value" "Type" $s.To "Name" "v"}})
} else {
ϟb.Push({{Template "Go.Replay.Value" "Type" $s.To "Name" "v"}})
}
ϟb.Store(ptr)
ptr += step
}
{{else if IsPointer ($s.To | Underlying)}}
{{/* Pointers need remapping to replay addresses */}}
ptr, step, d := value.RemappedPointer(s.Base), value.RemappedPointer(s.ElementSizes)), s.Decoders, ϟd, ϟl)
for i := uint64(0); i < s.Count; i++ {
v, err := binary.ReadUint(d, ϟs.Architecture.PointerSize*8)
if err != nil { panic(err) }
ϟb.Push({{Template "Go.Replay.Value" "Type" $s.To "Name" (printf "New%s(v)" $el_ty)}})
ϟb.Store(ptr)
ptr += step
}
{{else}}
ϟb.Write(s.Ranges), s.ResourceIDs, ϟd, ϟl))
{{end}}
}
return s
}
// OnWrite calls the backing pool's OnWrite callback. s is returned so calls can be chained.
func (s {{$slice_ty}}) OnWritea atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$slice_ty}} {
if f := ϟs.Memory[s.Root.Pool].OnWrite; f != nil {
f(s.Ranges))
}
if ϟb != nil && s.Root.Pool == memory.ApplicationPool {
ϟb.MapMemory(s.Root.Range(uint64(s.Ranges).End() - s.Root.Address)))
{{if (GetAnnotation $s.To "replay_remap")}}
{{/* Element type has explicitly stated it needs custom remapping */}}
size := s.ElementSizes)
ptr, step, d := value.RemappedPointer(s.Base), value.RemappedPointer(size), s.Decoders, ϟd, ϟl)
for i := uint64(0); i < s.Count; i++ {
var v {{$el_ty}}
{{Template "Go.Decode" "Name" "v" "Type" $s.To "ErrHandler" "panic(err)"}}
if key, remap := v.remapa, ϟs); remap {
dst, found := ϟb.Remappings[key]
if !found {
dst = ϟb.AllocateMemory(size)
ϟb.Remappings[key] = dst
}
ϟb.Load({{Template "Go.Replay.Type" $s.To}}, ptr)
ϟb.Store(dst)
}
ptr += step
}
{{end}}
}
return s
}
func (s {{$slice_ty}}) MapMemorya atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$slice_ty}} {
if ϟb != nil && s.Root.Pool == memory.ApplicationPool {
rng := s.Ranges)
ϟb.MapMemory(s.Root.Range(uint64(rng.End() - s.Root.Address)))
}
return s
}
// Index returns a {{$ptr_ty}} to the i'th element in this {{$slice_ty}}.
func (s {{$slice_ty}}) Index(i uint64, ϟs *gfxapi.State) {{$ptr_ty}} {
return {{$ptr_ty}}{ Pointer: memory.Pointer{ Address: s.Base + i * s.ElementSizes), Pool: s.Root.Pool } }
}
// Slice returns a sub-slice from the {{$slice_ty}} using start and end indices.
func (s {{$slice_ty}}) Slice(start, end uint64, ϟs *gfxapi.State) {{$slice_ty}} {
if start >= end {
panic(fmt.Errorf("%v.Slice(%d, %d) - start must be less than end", s, start, end))
}
if end > s.Count {
panic(fmt.Errorf("%v.Slice(%d, %d) - out of bounds", s, start, end))
}
return {{$slice_ty}}{SliceInfo: SliceInfo{Root: s.Root, Base: s.Base + start * s.ElementSizes), Count: end-start}}
}
// String returns a string description of the {{$slice_ty}} slice.
func (s {{$slice_ty}}) String() string {
return fmt.Sprintf("{{$el_ty}}(%v@%v)[%d]", s.Base, s.Root.Pool, s.Count)
}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a type declaration and implementation for the specified static array.
-------------------------------------------------------------------------------
*/}}
{{define "StaticArray"}}
{{AssertType $ "StaticArray"}}
type {{$.Name}} [{{$.Size}}]{{Template "Go.Type" $.ValueType}}
func (s {{$.Name}}) Len() int { return {{$.Size}} }
func (s {{$.Name}}) Range() [{{$.Size}}]{{Template "Go.Type" $.ValueType}} { return s}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a type declaration and implementation for the specified map.
-------------------------------------------------------------------------------
*/}}
{{define "Map"}}
{{AssertType $ "Map"}}
{{$name := $.Name}}
{{$key := Macro "Go.Type" $.KeyType}}
{{$value := Macro "Go.Type" $.ValueType}}
type {{$name}} map[{{$key}}]{{$value}}
func (m {{$name}}) Get(key {{$key}}) {{$value}} {
{{$init := Macro "Init" "Name" "v" "Type" $.ValueType}}
{{if $init}}
v, ok := m[key]
if !ok {
{{$init}}
}
return v
{{else}}
return m[key]
{{end}}
}
func (m {{$name}}) Contains(key {{$key}}) bool {
_, ok := m[key]
return ok
}
func (m {{$name}}) Delete(key {{$key}}) {
delete(m, key)
}
func (m {{$name}}) Range() []{{$value}} {
values := make([]{{$value}}, 0, len(m))
for _, value := range m {
values = append(values, value)
}
return values
}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits initialization code for the specified type.
-------------------------------------------------------------------------------
*/}}
{{define "Init"}}
{{AssertType $.Type "Type"}}
{{AssertType $.Name "string"}}
{{ if IsMap $.Type}}{{$.Name}} = make({{Template "Go.Type" $.Type}})
{{else if IsClass $.Type}}{{$.Name}}.Init()
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a type declaration and implementation for the specified command.
-------------------------------------------------------------------------------
*/}}
{{define "CommandEntry"}}
{{AssertType $.Command "Function"}}
{{$name := Macro "Go.CmdName" $.Command}}
{{$ret := not (IsVoid $.Command.Return.Type)}}
{{template "Go.CommentHeader" $name}}
type {{$name}} struct {
binary.Generate
observations atom.Observations
{{range $p := $.Command.FullParameters}}
{{Template "Go.Public" $p.Name}} {{Template "Go.Type" $p}}
{{end}}
}
func (a *{{$name}}) String() string {
return fmt.Sprintf("{{Template "CmdName" $.Command}}(§
{{range $i, $p := $.Command.CallParameters}}
{{if $i}}, §{{end}}
{{$p.Name}}: %v§
{{end}}
){{if $ret}} → %v{{end}}"
{{range $i, $p := $.Command.CallParameters}}
a.{{Template "Go.Parameter" $p}}, §
{{end}}
{{if $ret}}a.Result§{{end}}
)
}
// AddRead appends a new read observation to the atom of the range rng with
// the data id.
// The {{$name}} pointer is returned so that calls can be chained.
func (a *{{$name}}) AddRead(rng memory.Range, id binary.ID) *{{$name}} {
a.observations.Reads = append(a.observations.Reads, atom.Observation{Range: rng, ID: id})
return a
}
// AddWrite appends a new write observation to the atom of the range rng with
// the data id.
// The {{$name}} pointer is returned so that calls can be chained.
func (a *{{$name}}) AddWrite(rng memory.Range, id binary.ID) *{{$name}} {
a.observations.Writes = append(a.observations.Writes, atom.Observation{Range: rng, ID: id})
return a
}
func (c *{{$name}}) API() gfxapi.ID { return api{}.ID() }
func (c *{{$name}}) Flags() atom.Flags { return 0 §
{{if GetAnnotation $.Command "DrawCall"}} | atom.DrawCall §{{end}}
{{if GetAnnotation $.Command "EndOfFrame"}} | atom.EndOfFrame §{{end}}
}
func (a *{{$name}}) Observations() *atom.Observations { return &a.observations }
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a type declaration and implementation for the specified class.
-------------------------------------------------------------------------------
*/}}
{{define "Class"}}
{{AssertType $ "Class"}}
{{template "Go.CommentHeader" print "class " $.Name }}
{{if GetAnnotation $ "Interface"}}
type {{$.Name}} interface {
{{Template "ClassInterface" $}}
}
{{else}}
type {{$.Name}} struct {
binary.Generate
{{Template "ClassFields" $}}
}
func (c *{{$.Name}}) Init() {
{{Template "FieldsInit" "Type" $ "Name" "c"}}
}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits an interface declaration for the specified @interface class.
-------------------------------------------------------------------------------
*/}}
{{define "ClassInterface"}}
{{AssertType $ "Class"}}
{{range $v := $.Fields}}
{{$type := TypeOf $v}}
Get{{Title $v.Name}}() {{Template "Go.Type" $type}}
Set{{Title $v.Name}}({{Template "Go.Type" $type}})
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a list of fields of the specified class.
-------------------------------------------------------------------------------
*/}}
{{define "ClassFields"}}
{{AssertType $ "Class"}}
{{range $v := $.Fields}}
{{Title $v.Name}} {{Template "Go.Type" $v}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits initialization code for all fields of the specified class.
-------------------------------------------------------------------------------
*/}}
{{define "FieldsInit"}}
{{AssertType $.Type "Class" "API"}}
{{AssertType $.Name "string"}}
{{range $v := $.Type.Fields}}
{{Template "FieldInit" "Field" $v "Name" (print $.Name "." $v.Name)}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits initialization code for the specified class field.
-------------------------------------------------------------------------------
*/}}
{{define "FieldInit"}}
{{AssertType $.Field "Field" "Global"}}
{{AssertType $.Name "string"}}
{{if $.Field.Default}}{{$.Name}} = {{Template "Default" $.Field.Default}}
{{else }}{{Template "Init" "Type" (TypeOf $.Field) "Name" $.Name}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the default value for the specified type.
-------------------------------------------------------------------------------
*/}}
{{define "Default"}}
{{ if IsBoolValue $}}{{$}}
{{else if IsNumericValue $}}{{$}}
{{else if IsStringValue $}}{{$}}
{{else if IsEnumEntry $}}{{$.Owner.Name}}_{{$.Name}}
{{else if IsCast $}}{{Template "Default" $.Object}}
{{else}}{{Error "macro Default called with unsupported type: %T" $}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the implementation code for the specified class.
-------------------------------------------------------------------------------
*/}}
{{define "ClassImpl"}}
{{AssertType $.Class "Class"}}
{{AssertType $.Impl "string"}}
{{range $v := $.Class.Fields}}
{{$type := TypeOf $v}}
{{$FType := Macro "Go.Type" $type}}
func (i *{{$.Impl}}) Get{{$v.Name}}() {{$FType}} { return i.{{$v.Name}} }
func (i *{{$.Impl}}) Set{{$v.Name}}(v {{$FType}}) { i.{{$v.Name}} = v }
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a type declaration and implementation for the specified enum.
-------------------------------------------------------------------------------
*/}}
{{define "Enum"}}
{{AssertType $ "Enum"}}
{{template "Go.CommentHeader" print "enum " $.Name }}
type {{$.Name}} uint32
{{Template "EnumConstants" "Enum" $ "Name" $.Name}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a list of entries for the specified enum.
-------------------------------------------------------------------------------
*/}}
{{define "EnumConstants"}}
{{AssertType $.Enum "Enum"}}
{{AssertType $.Name "string"}}
const (
{{range $e := $.Enum.Entries}}
{{$.Name}}_{{$e.Name}} = {{$.Name}}({{$e.Value}})
{{end}}
)
{{range $e := $.Enum.Extends}}
// {{$e.Name}}
{{Template "EnumConstants" "Enum" $e "Name" $.Name}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits cases matching a string representation for each entry of the specified enum.
-------------------------------------------------------------------------------
*/}}
{{define "EnumStringCases"}}
{{AssertType $ "Enum"}}
{{range $e := $.Entries}}
case {{$e.Value}}: return "{{$e.Name}}"
{{end}}
{{range $e := $.Extends}}
// {{$e.Name}}
{{Template "EnumStringCases" $e}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a type declaration for holding the state.
-------------------------------------------------------------------------------
*/}}
{{define "State"}}
{{template "Go.CommentHeader" "State"}}
type State struct {
binary.Generate
{{range $g := $.Globals}}
{{Title $g.Name}} {{Template "Go.Type" $g}}
{{end}}
}
func (g *State) Init() {
{{range $g := $.Globals}}
{{Template "FieldInit" "Field" $g "Name" (print "g." $g.Name)}}
{{end}}
}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a top-level type declaration for the specified API.
-------------------------------------------------------------------------------
*/}}
{{define "API"}}
{{template "Go.CommentHeader" "API"}}
var apiID = gfxapi.ID(binary.NewID([]byte("{{Global "API"}}")))
type api struct {}
func (api) Name() string {
return "{{Global "API"}}"
}
func (api) ID() gfxapi.ID {
return apiID
}
func (api) GetFramebufferAttachmentSize(state *gfxapi.State, attachment gfxapi.FramebufferAttachment) (width uint32, height uint32, err error) {
return getState(state).getFramebufferAttachmentSize(attachment)
}
func API() gfxapi.API {
return api{}
}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the boolean expression testing for equality between LHS and RHS.
-------------------------------------------------------------------------------
*/}}
{{define "Equal"}}
{{AssertType $.Type "Type"}}
{{Template "BinaryOp" "Type" $.Type "LHS" $.LHS "RHS" $.RHS "Operator" "==" "Name" "Equal"}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the boolean expression that is true if LHS < RHS, otherwise false.
-------------------------------------------------------------------------------
*/}}
{{define "Less"}}
{{AssertType $.Type "Type"}}
{{if IsBool $.Type}}false
{{else }}{{Template "BinaryOp" "Type" $.Type "LHS" $.LHS "RHS" $.RHS "Operator" "<" "Name" "Less"}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the binary expression for the given LHS and RHS types.
-------------------------------------------------------------------------------
*/}}
{{define "BinaryOp"}}
{{AssertType $.Name "string"}}
{{AssertType $.Operator "string"}}
{{AssertType $.Type "Type"}}
{{ if IsS8 $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else if IsU8 $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else if IsU16 $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else if IsS16 $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else if IsF32 $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else if IsU32 $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else if IsS32 $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else if IsF64 $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else if IsU64 $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else if IsS64 $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else if IsInt $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else if IsUint $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else if IsString $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else if IsEnum $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else if IsPointer $.Type}}{{$.LHS}} {{$.Operator}} {{$.RHS}}
{{else }}{{$.LHS}}.{{$.Name}}({{$.RHS}})
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits an Atom constructor for each command.
-------------------------------------------------------------------------------
*/}}
{{define "NewAtoms"}}
{{AssertType $ "API"}}
{{range $c := AllCommands $}}
{{$name := Macro "Go.CmdName" $c}}
func New{{$name}}(§
{{range $p := $c.FullParameters}}
{{if $p | TypeOf | Underlying | IsPointer}}
{{Title $p.Name}} memory.Pointer
{{else}}
{{Title $p.Name}} {{Template "Go.Type" $p}},§
{{end}}
{{end}}
) *{{$name}} {
return &{{$name}}
{{range $p := $c.FullParameters}}
{{if $p | TypeOf | Underlying | IsPointer}}
{{Template "Go.Public" $p.Name}}: {{Template "Go.Type" $p}}{ Pointer: {{Title $p.Name}} },§
{{else}}
{{Template "Go.Public" $p.Name}}: {{Title $p.Name}},§
{{end}}
{{end}}
}
}
{{end}}
{{end}}