-
Notifications
You must be signed in to change notification settings - Fork 134
/
transform_end_of_replay.go
108 lines (92 loc) · 3.83 KB
/
transform_end_of_replay.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Copyright (C) 2020 Google Inc.
//
// 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.
package vulkan
import (
"context"
"github.com/google/gapid/core/data/binary"
"github.com/google/gapid/core/log"
"github.com/google/gapid/gapis/api"
"github.com/google/gapid/gapis/api/transform"
"github.com/google/gapid/gapis/replay"
"github.com/google/gapid/gapis/replay/builder"
"github.com/google/gapid/gapis/replay/value"
)
var _ transform.Transform = &endOfReplay{}
// endOfReplay is a transform that causes a post back at the end of the replay. It can be used to
// ensure that GAPIS waits for a replay to finish, if there are no postbacks, or no pending
// postbacks in the replay.
type endOfReplay struct {
res []replay.Result
}
func newEndOfReplay() *endOfReplay {
return &endOfReplay{
res: []replay.Result{},
}
}
// AddResult adds the given replay result listener to this transform.
func (endTransform *endOfReplay) AddResult(r replay.Result) {
endTransform.res = append(endTransform.res, r)
}
func (endTransform *endOfReplay) RequiresAccurateState() bool {
return false
}
func (endTransform *endOfReplay) RequiresInnerStateMutation() bool {
return false
}
func (endTransform *endOfReplay) SetInnerStateMutationFunction(mutator transform.StateMutator) {
// This transform do not require inner state mutation
}
func (endTransform *endOfReplay) BeginTransform(ctx context.Context, inputState *api.GlobalState) error {
return nil
}
func (endTransform *endOfReplay) ClearTransformResources(ctx context.Context) {
// No resource allocated
}
func (endTransform *endOfReplay) EndTransform(ctx context.Context, inputState *api.GlobalState) ([]api.Cmd, error) {
return []api.Cmd{endTransform.CreateNotifyInstruction(ctx, defaultNotifyFunction)}, nil
}
func (endTransform *endOfReplay) TransformCommand(ctx context.Context, id transform.CommandID, inputCommands []api.Cmd, inputState *api.GlobalState) ([]api.Cmd, error) {
return inputCommands, nil
}
func defaultNotifyFunction() interface{} {
return nil
}
// CreateNotifyInstruction creates a command that adds an instruction to the replay stream
// that will notify GAPIS that the replay has finished.
// It should be the end (or very near the end) of the replay stream and thus
// be called from an EndTransform.
func (endTransform *endOfReplay) CreateNotifyInstruction(ctx context.Context, result func() interface{}) api.Cmd {
return replay.Custom{T: 0, F: func(ctx context.Context, s *api.GlobalState, b *builder.Builder) error {
// Since the PostBack function is called before the replay target has actually arrived at the post command,
// we need to actually write some data here. r.Uint32() is what actually waits for the replay target to have
// posted the data in question. If we did not do this, we would shut-down the replay as soon as the second-to-last
// Post had occurred, which may not be anywhere near the end of the stream.
kEosCode := uint32(0x6060fa51)
b.Push(value.U32(kEosCode))
b.Post(b.Buffer(1), 4, func(r binary.Reader, err error) {
for _, res := range endTransform.res {
res.Do(func() (interface{}, error) {
if err != nil {
return nil, log.Err(ctx, err, "Flush did not get expected EOS code: '%v'")
}
if r.Uint32() != kEosCode {
return nil, log.Err(ctx, nil, "Flush did not get expected EOS code")
}
return result(), nil
})
}
})
return nil
}}
}