| {{/* |
| * 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. |
| ElementSize(ϟs *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}}) ElementSize(ϟs *gfxapi.State) uint64 { |
| {{if $el_is_ptr}} |
| if p.Pointer.Pool == memory.ApplicationPool { |
| return uint64(ϟs.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}}) Read(ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$el_ty}} { |
| return p.Slice(0, 1, ϟs).Read(ϟa, ϟ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}}) OnRead(ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$ptr_ty}} { |
| p.Slice(0, 1, ϟs).OnRead(ϟa, ϟ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}}) OnWrite(ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$ptr_ty}} { |
| p.Slice(0, 1, ϟs).OnWrite(ϟa, ϟs, ϟd, ϟl, ϟb) |
| return p |
| } |
| |
| func (p {{$ptr_ty}}) MapMemory(ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$ptr_ty}} { |
| p.Slice(0, 1, ϟs).MapMemory(ϟa, ϟ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}}) StringSlice(ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger) Charˢ { |
| i, d := uint64(0), ϟs.MemoryDecoder(ϟs.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.ElementSize(ϟs), 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}}) Clone(ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$slice_ty}} { |
| s.OnRead(ϟa, ϟs, ϟd, ϟl, ϟb) |
| pool := &memory.Pool{} |
| pool.Write(0, ϟs.Memory[s.Root.Pool].Slice(s.Range(ϟs))) |
| 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}}) ElementSize(ϟs *gfxapi.State) uint64 { |
| {{if $el_is_ptr}} |
| if s.Root.Pool == memory.ApplicationPool { |
| return uint64(ϟs.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}}) Range(ϟs *gfxapi.State) memory.Range { |
| return memory.Range{ Base: s.Base, Size: s.Count * s.ElementSize(ϟs) } |
| } |
| |
| // ResourceID returns an identifier to a resource representing the data of |
| // this slice. |
| func (s {{$slice_ty}}) ResourceID(ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger) binary.ID { |
| id, err := ϟs.Memory[s.Root.Pool].Slice(s.Range(ϟs)).ResourceID(ϟd, ϟl) |
| if err != nil { |
| panic(err) |
| } |
| return id |
| } |
| |
| // Decoder returns a memory decoder for the slice. |
| func (s {{$slice_ty}}) Decoder(ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger) binary.Decoder { |
| return ϟs.MemoryDecoder(ϟs.Memory[s.Root.Pool].Slice(s.Range(ϟs)), ϟd, ϟl) |
| } |
| |
| // Encoder returns a memory encoder for the slice. |
| func (s {{$slice_ty}}) Encoder(ϟs *gfxapi.State) binary.Encoder { |
| return ϟs.MemoryEncoder(ϟs.Memory[s.Root.Pool], s.Range(ϟs)) |
| } |
| |
| {{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.ElementSize(ϟs)) / out.ElementSize(ϟs) |
| return out |
| } |
| |
| // Read reads and returns all the {{$el_ty}} elements in this {{$slice_ty}}. |
| func (s {{$slice_ty}}) Read(ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) []{{$el_ty}} { |
| d, res := s.Decoder(ϟs, ϟd, ϟl), make([]{{$el_ty}}, s.Count) |
| s.OnRead(ϟa, ϟ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.Encoder(ϟs) |
| 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.OnWrite(ϟa, ϟ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.Read(ϟa, ϟs, ϟd, ϟl, ϟb), ϟa, ϟs, ϟd, ϟl, ϟb) // Element-wise copy so we can convert u64 <-> {{$ptr_ty}} |
| } else { |
| {{end}} |
| src.OnRead(ϟa, ϟs, ϟd, ϟl, ϟb) |
| ϟs.Memory[dst.Root.Pool].Write(dst.Base, ϟs.Memory[src.Root.Pool].Slice(src.Range(ϟs))) |
| dst.OnWrite(ϟa, ϟ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}}) OnRead(ϟa 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.Range(ϟs)) |
| } |
| if ϟb != nil && s.Root.Pool == memory.ApplicationPool { |
| s.MapMemory(ϟa, ϟ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.ElementSize(ϟs)), s.Decoder(ϟs, ϟ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.remap(ϟa, ϟs); remap { |
| loadRemap(ϟb, 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.ElementSize(ϟs)), s.Decoder(ϟs, ϟ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.Range(ϟs), s.ResourceID(ϟs, ϟ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}}) OnWrite(ϟa 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.Range(ϟs)) |
| } |
| if ϟb != nil && s.Root.Pool == memory.ApplicationPool { |
| ϟb.MapMemory(s.Root.Range(uint64(s.Range(ϟs).End() - s.Root.Address))) |
| {{if (GetAnnotation $s.To "replay_remap")}} |
| {{/* Element type has explicitly stated it needs custom remapping */}} |
| size := s.ElementSize(ϟs) |
| ptr, step, d := value.RemappedPointer(s.Base), value.RemappedPointer(size), s.Decoder(ϟs, ϟ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.remap(ϟa, ϟ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}}) MapMemory(ϟa 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.Range(ϟs) |
| ϟ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.ElementSize(ϟs), 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.ElementSize(ϟs), 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}} |