| {{/* |
| * 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 "replay_writer.go" | GoFmt | Write "replay_writer.go"}} |
| |
| {{define "replay_writer.go"}} |
| {{template "Go.GeneratedHeader" (Global "OutputDir")}} |
| |
| import ( |
| "fmt" |
| "io" |
| "io/ioutil" |
| |
| "android.googlesource.com/platform/tools/gpu/atom" |
| "android.googlesource.com/platform/tools/gpu/binary" |
| "android.googlesource.com/platform/tools/gpu/database" |
| "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/replay/protocol" |
| "android.googlesource.com/platform/tools/gpu/replay/value" |
| ) |
| |
| {{Global "Go.Statement.Override" "Statement"}} |
| {{Global "Go.Read.Override" "Read"}} |
| |
| type postCall []func() |
| |
| func (p *postCall) add(f func()) { |
| *p = append(*p, f) |
| } |
| |
| func (p *postCall) exec() { |
| for _, f := range *p { |
| f() |
| } |
| } |
| |
| func loadRemap(ϟb *builder.Builder, key interface{}, val value.Value) { |
| if ptr, found := ϟb.Remappings[key]; found { |
| ϟb.Load(val.Type(), ptr) |
| } else { |
| ptr = ϟb.AllocateMemory(uint64(val.Type().Size(ϟb.Architecture().PointerSize))) |
| ϟb.Push(val) // We have an input to an unknown id, use the unmapped value. |
| ϟb.Clone(0) |
| ϟb.Store(ptr) |
| ϟb.Remappings[key] = ptr |
| } |
| } |
| |
| func storeRemap(ϟb *builder.Builder, key interface{}, val value.Pointer, ty protocol.Type) { |
| if ptr, found := ϟb.Remappings[key]; !found { |
| ptr = ϟb.AllocateMemory(uint64(ty.Size(ϟb.Architecture().PointerSize))) |
| ϟb.Load(ty, val) |
| ϟb.Store(ptr) |
| ϟb.Remappings[key] = ptr |
| } |
| } |
| |
| {{Macro "DeclareBuilderFunctionInfos" $}} |
| |
| {{ForEach $.Pseudonyms "DeclarePseudonymValue" | JoinWith "\n"}} |
| |
| {{ForEach (AllCommands $) "DeclareCommandReplay" | JoinWith "\n"}} |
| |
| {{ForEach $.Pointers "PointerReplayMethods" | JoinWith "\n"}} |
| {{ForEach $.Slices "SliceReplayMethods" | JoinWith "\n"}} |
| {{end}} |
| |
| |
| {{/* |
| ------------------------------------------------------------------------------- |
| Emits the replay function for the specified command |
| ------------------------------------------------------------------------------- |
| */}} |
| {{define "DeclareCommandReplay"}} |
| {{AssertType $ "Function"}} |
| |
| {{if not (GetAnnotation $ "no_replay")}} |
| |
| {{$name := Macro "Go.CmdName" $}} |
| var _ = replay.Replayer(&{{$name}}{}) // interface compliance check |
| func (ϟa *{{$name}}) {{if GetAnnotation $ "replay_custom"}}default{{end}}Replay(§ |
| ϟi atom.ID, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) { |
| ϟc := getState(ϟs) |
| ϟp := &postCall{} |
| _ = ϟc |
| |
| ϟa.observations.ApplyReads(ϟs.Memory[memory.ApplicationPool]) |
| |
| {{/* Simulate the call */}} |
| {{Macro "Go.Block" $.Block}} |
| |
| ϟa.observations.ApplyWrites(ϟs.Memory[memory.ApplicationPool]) |
| |
| {{/* Push all the parameters on the stack */}} |
| {{range $p := $.CallParameters}} |
| {{$type := TypeOf $p}} |
| {{$name := print "ϟa." (Macro "Go.Parameter" $p)}} |
| {{Macro "PushInput" "Type" $type "Name" $name}} |
| {{end}} |
| |
| {{/* Call the function */}} |
| ϟb.Call({{Macro "BuilderFunctionInfo" $}}) |
| |
| {{/* Perform post-call actions*/}} |
| ϟp.exec() |
| } |
| {{end}} |
| {{end}} |
| |
| |
| {{/* |
| ------------------------------------------------------------------------------- |
| Emits logic to push the specified input variable to the VM's stack. |
| ------------------------------------------------------------------------------- |
| */}} |
| {{define "PushInput"}} |
| {{AssertType $.Type "Type"}} |
| {{AssertType $.Name "string"}} |
| |
| {{if (GetAnnotation $.Type "replay_remap")}} |
| if key, remap := {{$.Name}}.remap(ϟa, ϟs); remap { |
| loadRemap(ϟb, key, {{Macro "Value" "Type" $.Type "Name" $.Name}}) |
| } else { |
| ϟb.Push({{Macro "Value" "Type" $.Type "Name" $.Name}}) |
| } |
| {{else}} |
| ϟb.Push({{Macro "Value" "Type" $.Type "Name" $.Name}}) |
| {{end}} |
| {{end}} |
| |
| |
| {{/* |
| ------------------------------------------------------------------------------- |
| Returns the builder.Value holding the specified variable. |
| ------------------------------------------------------------------------------- |
| */}} |
| {{define "Value"}} |
| {{AssertType $.Type "Type"}} |
| {{AssertType $.Name "string"}} |
| |
| {{if (GetAnnotation $.Type "replay_custom_value")}}{{$.Name}}.value(ϟb, ϟa, ϟs) |
| {{else if IsBool $.Type}}value.Bool({{$.Name}}) |
| {{else if IsS8 $.Type}}value.S8({{$.Name}}) |
| {{else if IsU8 $.Type}}value.U8({{$.Name}}) |
| {{else if IsS16 $.Type}}value.S16({{$.Name}}) |
| {{else if IsU16 $.Type}}value.U16({{$.Name}}) |
| {{else if IsF32 $.Type}}value.F32({{$.Name}}) |
| {{else if IsU32 $.Type}}value.U32({{$.Name}}) |
| {{else if IsS32 $.Type}}value.S32({{$.Name}}) |
| {{else if IsF64 $.Type}}value.F64({{$.Name}}) |
| {{else if IsU64 $.Type}}value.U64({{$.Name}}) |
| {{else if IsS64 $.Type}}value.S64({{$.Name}}) |
| {{else if IsInt $.Type}}value.S64({{$.Name}}) |
| {{else if IsUint $.Type}}value.U64({{$.Name}}) |
| {{else if IsString $.Type}}ϟb.String({{$.Name}}) |
| {{else if IsPointer $.Type}}{{$.Name}}.value() |
| {{else if IsEnum $.Type}}value.U32({{$.Name}}) |
| {{else if IsStaticArray $.Type}}{{$.Name}}.value(ϟb, ϟa, ϟs) |
| {{else if IsPseudonym $.Type}}{{$.Name}}.value(ϟb, ϟa, ϟs) |
| {{else if IsClass $.Type}}{{$.Name}}.value(ϟb, ϟa, ϟs) |
| {{else }}{{Error "macro Value '%v' called with unsupported type: %s" $.Name $.Type.Name}} |
| {{end}} |
| {{end}} |
| |
| |
| {{/* |
| ------------------------------------------------------------------------------- |
| Declares the value method for a given pseudonym type. |
| ------------------------------------------------------------------------------- |
| */}} |
| {{define "DeclarePseudonymValue"}} |
| {{AssertType $ "Pseudonym"}} |
| |
| {{if not (GetAnnotation $ "replay_custom_value")}} |
| {{$v := print (Macro "Go.Type" $.To) "(c)"}} |
| func (c {{$.Name}}) value(ϟb *builder.Builder, ϟa atom.Atom, ϟs *gfxapi.State) value.Value { return {{Macro "Value" "Type" $.To "Name" $v}} } |
| {{end}} |
| {{end}} |
| |
| |
| {{/* |
| ------------------------------------------------------------------------------- |
| Declares the value method for the given static array type. |
| ------------------------------------------------------------------------------- |
| */}} |
| {{define "DeclareArrayValue"}} |
| {{AssertType $ "Array" "StaticArray"}} |
| |
| {{if not (or (Macro "IsInternal" $.ValueType) (IsAny $.ValueType))}} |
| func (arr {{Macro "Go.Type" $}}) value(ϟb *builder.Builder, ϟa atom.Atom, ϟs *gfxapi.State) value.Pointer { |
| if len(arr) > 0 { |
| for _, e := range arr { |
| {{Macro "PushInput" "Type" $.ValueType "Name" "e"}} |
| } |
| return ϟb.Buffer(len(arr)) |
| } else { |
| return value.AbsolutePointer(0) |
| } |
| } |
| {{end}} |
| {{end}} |
| |
| |
| |
| {{/* |
| ------------------------------------------------------------------------------- |
| Emits a function info definition for each of the commands. |
| ------------------------------------------------------------------------------- |
| */}} |
| {{define "DeclareBuilderFunctionInfos"}} |
| {{AssertType $ "API"}} |
| |
| {{range $i, $c := AllCommands $}} |
| var {{Macro "BuilderFunctionInfo" $c}} = builder.FunctionInfo{§ |
| ID: {{$i}},§ |
| ReturnType: {{Macro "BuilderType" $c.Return.Type}},§ |
| Parameters: {{len $c.CallParameters}},§ |
| } |
| {{end}} |
| {{end}} |
| |
| |
| {{/* |
| ------------------------------------------------------------------------------- |
| Emits the name of the variable holding the specified command's function id. |
| ------------------------------------------------------------------------------- |
| */}} |
| {{define "BuilderFunctionInfo"}}{{AssertType $ "Function"}}funcInfo{{Macro "Go.CmdName" $}}{{end}} |
| |
| |
| {{/* |
| ------------------------------------------------------------------------------- |
| Emits the replay builder type for the given command return type. |
| ------------------------------------------------------------------------------- |
| */}} |
| {{define "BuilderType"}} |
| {{AssertType $ "Type"}} |
| |
| {{ if IsPseudonym $}}{{Macro "BuilderType" $.To}} |
| {{else if IsEnum $}}protocol.TypeUint32 |
| {{else if IsBool $}}protocol.TypeBool |
| {{else if IsInt $}}protocol.TypeInt64 |
| {{else if IsUint $}}protocol.TypeUint64 |
| {{else if IsS8 $}}protocol.TypeInt8 |
| {{else if IsU8 $}}protocol.TypeUint8 |
| {{else if IsS16 $}}protocol.TypeInt16 |
| {{else if IsU16 $}}protocol.TypeUint16 |
| {{else if IsS32 $}}protocol.TypeInt32 |
| {{else if IsU32 $}}protocol.TypeUint32 |
| {{else if IsF32 $}}protocol.TypeFloat |
| {{else if IsS64 $}}protocol.TypeInt64 |
| {{else if IsU64 $}}protocol.TypeUint64 |
| {{else if IsF64 $}}protocol.TypeDouble |
| {{else if IsVoid $}}protocol.TypeVoid |
| {{else if IsString $}}protocol.TypeVolatilePointer |
| {{else if IsPointer $}}protocol.TypeVolatilePointer {{/* TODO: Might be absolute... */}} |
| {{else}}{{Error "macro BuilderType called with unsupported type: %s" $.Name}} |
| {{end}} |
| {{end}} |
| |
| |
| {{/* |
| ------------------------------------------------------------------------------- |
| An override for the "Go.Statement" macro. |
| ------------------------------------------------------------------------------- |
| */}} |
| {{define "Statement"}} |
| {{if IsRead $}} |
| {{Macro "Go.Read" $.Slice}}.onReplayRead(ϟa, ϟs, ϟd, ϟl, ϟb) |
| {{else if IsWrite $}} |
| {{Macro "Go.Read" $.Slice}}.onReplayWrite(ϟa, ϟs, ϟd, ϟl, ϟb, ϟp) |
| {{else if IsCopy $}} |
| {{Macro "Go.Read" $.Dst}}.replayCopy({{Macro "Go.Read" $.Src}}, ϟa, ϟs, ϟd, ϟl, ϟb, ϟp) |
| {{else if IsSliceAssign $}} |
| {{if ne $.Operator "="}}{{Error "Compound assignments to pointers are not supported (%s)" $.Operator}}{{end}} |
| {{Macro "Go.Read" $.To.Slice}}.Index({{Macro "Go.Read" $.To.Index}}, ϟs).replayWrite({{Macro "Go.Read" $.Value}}, ϟa, ϟs, ϟd, ϟl, ϟb, ϟp) |
| {{else}} |
| {{Macro "Go.Statement.Default" $}} |
| {{end}} |
| {{end}} |
| |
| |
| {{/* |
| ------------------------------------------------------------------------------- |
| An override for the "Go.Read" macro. |
| ------------------------------------------------------------------------------- |
| */}} |
| {{define "Read"}} |
| {{if IsSliceIndex $}} |
| {{Macro "Go.Read" $.Slice}}.Index({{Macro "Go.Read" $.Index}}, ϟs).§ |
| {{if Global "Go.InferredExpression"}} |
| replayMap(ϟa, ϟs, ϟd, ϟl, ϟb) |
| {{else}} |
| replayRead(ϟa, ϟs, ϟd, ϟl, ϟb) |
| {{end}} |
| {{else}} |
| {{Macro "Go.Read.Default" $}} |
| {{end}} |
| {{end}} |
| |
| |
| {{/* |
| ------------------------------------------------------------------------------- |
| Emits additional methods used for replay generation for the Pointer type or |
| indirect type (Pseudonym) to Pointer. |
| ------------------------------------------------------------------------------- |
| */}} |
| {{define "PointerReplayMethods"}} |
| {{AssertType $ "Pointer" "Pseudonym"}} |
| |
| {{$p := $ | Underlying | Unpack }} |
| {{$ptr_ty := Macro "Go.Type" $ }} |
| {{$el_ty := Macro "Go.Type" $p.To }} |
| {{$el_is_void := IsVoid ($p.To | Underlying | Unpack)}} |
| |
| {{if not $el_is_void}} |
| func (p {{$ptr_ty}}) replayMap(ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$el_ty}} { |
| p.Slice(0, 1, ϟs).replayMap(ϟa, ϟs, ϟd, ϟl, ϟb) |
| return p.Read(ϟs, ϟd, ϟl) |
| } |
| |
| func (p {{$ptr_ty}}) replayRead(ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) {{$el_ty}} { |
| p.Slice(0, 1, ϟs).onReplayRead(ϟa, ϟs, ϟd, ϟl, ϟb) |
| return p.Read(ϟs, ϟd, ϟl) |
| } |
| |
| func (p {{$ptr_ty}}) replayWrite(value {{$el_ty}}, ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder, ϟp *postCall) { |
| p.Write(value, ϟs) |
| p.Slice(0, 1, ϟs).onReplayWrite(ϟa, ϟs, ϟd, ϟl, ϟb, ϟp) |
| } |
| {{end}} |
| |
| func (p {{$ptr_ty}}) value() value.Pointer { |
| if p.Address != 0 { |
| return value.VolatileCapturePointer(p.Address) |
| } else { |
| return value.AbsolutePointer(0) |
| } |
| } |
| {{end}} |
| |
| |
| {{/* |
| ------------------------------------------------------------------------------- |
| Emits additional methods used for replay generation for the Slice type or |
| indirect type (Pseudonym) to Slice. |
| ------------------------------------------------------------------------------- |
| */}} |
| {{define "SliceReplayMethods"}} |
| {{AssertType $ "Slice" "Pseudonym"}} |
| |
| {{$s := $ | Underlying | Unpack }} |
| {{$slice_ty := Macro "Go.Type" $ }} |
| {{$el_ty := Macro "Go.Type" $s.To }} |
| {{$el_is_void := IsVoid ($s.To | Underlying | Unpack)}} |
| |
| func (s {{$slice_ty}}) onReplayRead(ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) { |
| if s.Pool == memory.ApplicationPool { |
| s.replayMap(ϟa, ϟs, ϟd, ϟl, ϟb) |
| {{if (GetAnnotation $s.To "replay_remap")}} |
| ptr, step := value.VolatileCapturePointer(s.Base), value.VolatileCapturePointer(s.ElementSize(ϟs)) |
| for _, v := range s.Read(ϟs, ϟd, ϟl) { |
| if key, remap := v.remap(ϟa, ϟs); remap { |
| loadRemap(ϟb, key, {{Macro "Value" "Type" $s.To "Name" "v"}}) |
| } else { |
| ϟb.Push({{Macro "Value" "Type" $s.To "Name" "v"}}) |
| } |
| ϟb.Store(ptr) |
| ptr += step |
| } |
| {{else}} |
| ϟb.Write(s.Range(ϟs), s.ResourceID(ϟs, ϟd, ϟl)) |
| {{end}} |
| } |
| } |
| |
| func (s {{$slice_ty}}) onReplayWrite(ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder, ϟp *postCall) { |
| if s.Pool == memory.ApplicationPool { |
| ϟb.MapMemory(s.Root.Range(uint64(s.Range(ϟs).End() - s.Root))) |
| {{if (GetAnnotation $s.To "replay_remap")}} |
| ϟp.add(func() { |
| ptr, step := value.VolatileCapturePointer(s.Base), value.VolatileCapturePointer(s.ElementSize(ϟs)) |
| for _, v := range s.Read(ϟs, ϟd, ϟl) { |
| if key, remap := v.remap(ϟa, ϟs); remap { |
| storeRemap(ϟb, key, ptr, {{Macro "BuilderType" $s.To}}) |
| } |
| ptr += step |
| } |
| }) |
| {{end}} |
| } |
| } |
| |
| func (s {{$slice_ty}}) replayMap(ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) { |
| if s.Pool == memory.ApplicationPool { |
| rng := s.Range(ϟs) |
| ϟb.MapMemory(s.Root.Range(uint64(rng.End() - s.Root))) |
| } |
| } |
| |
| {{if not $el_is_void}} |
| func (s {{$slice_ty}}) replayRead(ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder) []{{$el_ty}} { |
| s.onReplayRead(ϟa, ϟs, ϟd, ϟl, ϟb) |
| return s.Read(ϟs, ϟd, ϟl) |
| } |
| |
| func (dst {{$slice_ty}}) replayCopy(src {{$slice_ty}}, ϟa atom.Atom, ϟs *gfxapi.State, ϟd database.Database, ϟl log.Logger, ϟb *builder.Builder, ϟp *postCall) { |
| dst, src = dst.Copy(src, ϟs, ϟd, ϟl) |
| src.onReplayRead(ϟa, ϟs, ϟd, ϟl, ϟb) |
| dst.onReplayWrite(ϟa, ϟs, ϟd, ϟl, ϟb, ϟp) |
| } |
| {{end}} |
| {{end}} |
| |