-
Notifications
You must be signed in to change notification settings - Fork 0
/
end_of_replay.go
79 lines (70 loc) · 3.15 KB
/
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
// Copyright (C) 2017 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 replay
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/builder"
"github.com/google/gapid/gapis/replay/value"
)
// 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 []Result
}
// AddResult adds the given replay result listener to this transform.
func (t *EndOfReplay) AddResult(r Result) {
t.res = append(t.res, r)
}
func (t *EndOfReplay) Transform(ctx context.Context, id api.CmdID, cmd api.Cmd, out transform.Writer) error {
return out.MutateAndWrite(ctx, id, cmd)
}
func (t *EndOfReplay) Flush(ctx context.Context, out transform.Writer) error {
t.AddNotifyInstruction(ctx, out, func() interface{} { return nil })
return nil
}
func (t *EndOfReplay) PreLoop(ctx context.Context, out transform.Writer) {}
func (t *EndOfReplay) PostLoop(ctx context.Context, out transform.Writer) {}
func (t *EndOfReplay) BuffersCommands() bool { return false }
// AddNotifyInstruction adds the 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 a transform Flush.
func (t *EndOfReplay) AddNotifyInstruction(ctx context.Context, out transform.Writer, result func() interface{}) {
out.MutateAndWrite(ctx, api.CmdNoID, 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.
code := uint32(0x6060fa51)
b.Push(value.U32(code))
b.Post(b.Buffer(1), 4, func(r binary.Reader, err error) {
for _, res := range t.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() != code {
return nil, log.Err(ctx, nil, "Flush did not get expected EOS code")
}
return result(), nil
})
}
})
return nil
}})
}