Skip to content

Commit

Permalink
Display the state of currently selected API & context.
Browse files Browse the repository at this point in the history
  • Loading branch information
ben-clayton committed Sep 14, 2017
1 parent ad73e6b commit 94d0e90
Show file tree
Hide file tree
Showing 15 changed files with 148 additions and 76 deletions.
14 changes: 14 additions & 0 deletions gapic/src/main/com/google/gapid/models/ApiContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,20 @@ public int getPriority() {
return context != null ? context.getPriority() : 0;
}

public Path.State.Builder state(Path.State.Builder path) {
if (id != null) {
path.getContextBuilder().setData(id.getData());
}
return path;
}

public Path.StateTree.Builder stateTree(Path.StateTree.Builder path) {
if (id != null) {
path.getStateBuilder().getContextBuilder().setData(id.getData());
}
return path;
}

public Path.Events.Builder events(Path.Events.Builder path) {
path.getFilterBuilder().setContext(id);
return path;
Expand Down
4 changes: 2 additions & 2 deletions gapic/src/main/com/google/gapid/models/ApiState.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ public class ApiState
private final ObjectStore<Path.Any> selection = ObjectStore.create();

public ApiState(
Shell shell, Client client, Follower follower, AtomStream atoms, ConstantSets constants) {
Shell shell, Client client, Follower follower, AtomStream atoms, ApiContext contexts, ConstantSets constants) {
super(LOG, shell, client, Listener.class);
this.constants = constants;

atoms.addListener(new AtomStream.Listener() {
@Override
public void onAtomsSelected(AtomIndex index) {
load(stateTree(index), false);
load(stateTree(index, contexts.getSelectedContext()), false);
}
});
follower.addListener(new Follower.Listener() {
Expand Down
2 changes: 1 addition & 1 deletion gapic/src/main/com/google/gapid/models/Models.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public static Models create(Shell shell, Settings settings, Client client) {
Timeline timeline = new Timeline(shell, client, capture, contexts);
AtomStream atoms = new AtomStream(shell, client, capture, contexts, constants);
Resources resources = new Resources(shell, client, capture);
ApiState state = new ApiState(shell, client, follower, atoms, constants);
ApiState state = new ApiState(shell, client, follower, atoms, contexts, constants);
Reports reports = new Reports(shell, client, capture, devices, contexts);
Thumbnails thumbs = new Thumbnails(client, devices, capture);
return new Models(settings, follower, capture, devices, atoms, contexts, timeline, resources,
Expand Down
10 changes: 5 additions & 5 deletions gapic/src/main/com/google/gapid/util/Paths.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,16 @@ public static Path.State stateAfter(Path.Command command) {
return Path.State.newBuilder().setAfter(command).build();
}

public static Path.Any stateTree(AtomIndex atom) {
public static Path.Any stateTree(AtomIndex atom, FilteringContext context) {
if (atom == null) {
return null;
}
return Path.Any.newBuilder()
.setStateTree(
Path.StateTree.newBuilder()
.setState(stateAfter(atom.getCommand()))
.setArrayGroupSize(2000))
.build();
context.stateTree(
Path.StateTree.newBuilder()
.setState(stateAfter(atom.getCommand()))
.setArrayGroupSize(2000))).build();
}

public static Path.Any stateTree(Path.ID tree, Path.Any statePath) {
Expand Down
28 changes: 28 additions & 0 deletions gapis/api/gles/gles.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/google/gapid/core/log"
"github.com/google/gapid/gapis/api"
"github.com/google/gapid/gapis/messages"
"github.com/google/gapid/gapis/resolve"
"github.com/google/gapid/gapis/resolve/dependencygraph"
"github.com/google/gapid/gapis/service/path"
)
Expand All @@ -37,6 +38,33 @@ func (s *State) GetContext(thread uint64) *Context {
return s.Contexts[thread]
}

// Root returns the path to the root of the state to display. It can vary based
// on filtering mode. Returning nil, nil indicates there is no state to show at
// this point in the capture.
func (s *State) Root(ctx context.Context, p *path.State) (path.Node, error) {
if p.Context == nil || !p.Context.IsValid() {
return p, nil
}
c, err := resolve.Context(ctx, p.After.Capture.Context(p.Context))
if err != nil {
return nil, err
}
for thread, context := range s.Contexts {
if c.ID() == context.ID() {
return s.contextRoot(p.After, thread), nil
}
}
return nil, nil
}

func (s *State) contextRoot(p *path.Command, thread uint64) *path.MapIndex {
return path.NewField("Contexts", resolve.APIStateAfter(p, ID)).MapIndex(thread)
}

func (s *State) objectsRoot(p *path.Command, thread uint64) *path.Field {
return s.contextRoot(p, thread).Field("Objects")
}

func (c *State) preMutate(ctx context.Context, s *api.GlobalState, cmd api.Cmd) error {
c.CurrentContext = c.GetContext(cmd.Thread())
// TODO: Find better way to separate GL and EGL commands.
Expand Down
11 changes: 2 additions & 9 deletions gapis/api/gles/links.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,7 @@ func objects(ctx context.Context, p path.Node) (*path.Field, *Context, error) {
if !ok {
return nil, nil, nil
}
return cmdPath.StateAfter().
Field("Contexts").
MapIndex(thread).
Field("Objects"), context, nil
return state.objectsRoot(cmdPath, thread), context, nil
}
return nil, nil, nil
}
Expand All @@ -67,11 +64,7 @@ func sharedObjects(ctx context.Context, p path.Node) (*path.Field, *Context, err
if !ok {
return nil, nil, nil
}
return cmdPath.StateAfter().
Field("Contexts").
MapIndex(thread).
Field("Objects").
Field("Shared"), context, nil
return state.objectsRoot(cmdPath, thread).Field("Shared"), context, nil
}
return nil, nil, nil
}
Expand Down
7 changes: 7 additions & 0 deletions gapis/api/gvr/gvr.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ import (

var _ = replay.QueryFramebufferAttachment(API{})

// Root returns the path to the root of the state to display. It can vary based
// on filtering mode. Returning nil, nil indicates there is no state to show at
// this point in the capture.
func (s *State) Root(ctx context.Context, p *path.State) (path.Node, error) {
return nil, nil
}

func (c *State) preMutate(ctx context.Context, s *api.GlobalState, cmd api.Cmd) error {
return nil
}
Expand Down
5 changes: 5 additions & 0 deletions gapis/api/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/google/gapid/gapis/database"
"github.com/google/gapid/gapis/memory"
"github.com/google/gapid/gapis/replay/value"
"github.com/google/gapid/gapis/service/path"
"github.com/google/gapid/gapis/stringtable"
)

Expand Down Expand Up @@ -64,6 +65,10 @@ type GlobalState struct {

// State represents the graphics state for a single context.
type State interface {
// Root returns the path to the root of the state to display. It can vary
// based on filtering mode. Returning nil, nil indicates there is no state
// to show at this point in the capture.
Root(ctx context.Context, p *path.State) (path.Node, error)
}

// NewStateWithEmptyAllocator returns a new, default-initialized State object,
Expand Down
8 changes: 8 additions & 0 deletions gapis/api/test/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/google/gapid/core/image"
"github.com/google/gapid/gapis/api"
"github.com/google/gapid/gapis/service/path"
)

type CustomState struct{}
Expand All @@ -29,6 +30,13 @@ func (API) GetFramebufferAttachmentInfo(*api.GlobalState, uint64, api.Framebuffe

func (API) Context(*api.GlobalState, uint64) api.Context { return nil }

// Root returns the path to the root of the state to display. It can vary based
// on filtering mode. Returning nil, nil indicates there is no state to show at
// this point in the capture.
func (s *State) Root(ctx context.Context, p *path.State) (path.Node, error) {
return nil, nil
}

func (c *State) preMutate(ctx context.Context, s *api.GlobalState, cmd api.Cmd) error {
return nil
}
Expand Down
7 changes: 7 additions & 0 deletions gapis/api/vulkan/vulkan.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ func (API) Context(s *api.GlobalState, thread uint64) api.Context {
return VulkanContext{}
}

// Root returns the path to the root of the state to display. It can vary based
// on filtering mode. Returning nil, nil indicates there is no state to show at
// this point in the capture.
func (*State) Root(ctx context.Context, p *path.State) (path.Node, error) {
return p, nil
}

func (c *State) preMutate(ctx context.Context, s *api.GlobalState, cmd api.Cmd) error {
return nil
}
Expand Down
80 changes: 45 additions & 35 deletions gapis/resolve/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package resolve

import (
"context"
"fmt"

"github.com/google/gapid/gapis/api"
"github.com/google/gapid/gapis/api/sync"
Expand All @@ -38,12 +37,8 @@ func GlobalState(ctx context.Context, p *path.GlobalState) (*api.GlobalState, er
}

// State resolves the specific API state at a requested point in a capture.
func State(ctx context.Context, p *path.State) (api.State, error) {
obj, err := database.Build(ctx, &StateResolvable{p})
if err != nil {
return nil, err
}
return obj.(api.State), nil
func State(ctx context.Context, p *path.State) (interface{}, error) {
return database.Build(ctx, &StateResolvable{p})
}

// Resolve implements the database.Resolver interface.
Expand Down Expand Up @@ -82,45 +77,60 @@ func (r *GlobalStateResolvable) Resolve(ctx context.Context) (interface{}, error
// Resolve implements the database.Resolver interface.
func (r *StateResolvable) Resolve(ctx context.Context) (interface{}, error) {
ctx = capture.Put(ctx, r.Path.After.Capture)
cmdIdx := r.Path.After.Indices[0]
if len(r.Path.After.Indices) > 1 {
return nil, fmt.Errorf("Subcommands currently not supported for api state") // TODO: Subcommands
}
cmds, err := NCmds(ctx, r.Path.After.Capture, cmdIdx+1)
obj, _, _, err := state(ctx, r.Path)
return obj, err
}

func state(ctx context.Context, p *path.State) (interface{}, path.Node, api.ID, error) {
cmd, err := Cmd(ctx, p.After)
if err != nil {
return nil, err
return nil, nil, api.ID{}, err
}
return apiState(ctx, cmds, r.Path)
}

func apiState(ctx context.Context, cmds []api.Cmd, p *path.State) (api.State, error) {
cmdIdx := p.After.Indices[0]
if len(p.After.Indices) > 1 {
return nil, fmt.Errorf("Subcommands currently not supported for api state") // TODO: Subcommands
a := cmd.API()
if a == nil {
return nil, nil, api.ID{}, &service.ErrDataUnavailable{Reason: messages.ErrStateUnavailable()}
}
if count := uint64(len(cmds)); cmdIdx >= count {
return nil, errPathOOB(cmdIdx, "Index", 0, count-1, p)

g, err := GlobalState(ctx, p.After.GlobalStateAfter())
if err != nil {
return nil, nil, api.ID{}, err
}
a := cmds[cmdIdx].API()
if a == nil {
return nil, &service.ErrDataUnavailable{Reason: messages.ErrStateUnavailable()}

state := g.APIs[a.ID()]
if state == nil {
return nil, nil, api.ID{}, &service.ErrDataUnavailable{Reason: messages.ErrStateUnavailable()}
}
s, err := capture.NewState(ctx)

root, err := state.Root(ctx, p)
if err != nil {
return nil, err
return nil, nil, api.ID{}, err
}
if root == nil {
return nil, nil, api.ID{}, &service.ErrDataUnavailable{Reason: messages.ErrStateUnavailable()}
}

err = api.ForeachCmd(ctx, cmds[:cmdIdx+1], func(ctx context.Context, id api.CmdID, cmd api.Cmd) error {
cmd.Mutate(ctx, id, s, nil)
return nil
// Transform the State path node to a GlobalState node to prevent the
// object load recursing back into this function.
abs := path.Transform(root, func(n path.Node) path.Node {
switch n := n.(type) {
case *path.State:
return APIStateAfter(p.After, a.ID())
default:
return n
}
})

obj, err := Get(ctx, abs.Path())
if err != nil {
return nil, err
return nil, nil, api.ID{}, err
}

res, found := s.APIs[a.ID()]
if !found {
return nil, &service.ErrDataUnavailable{Reason: messages.ErrStateUnavailable()}
}
return res, nil
return obj, abs, a.ID(), nil
}

// APIStateAfter returns an absolute path to the API state after c.
func APIStateAfter(c *path.Command, a api.ID) path.Node {
p := &path.GlobalState{After: c}
return p.Field("APIs").MapIndex(a)
}
36 changes: 16 additions & 20 deletions gapis/resolve/state_tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"github.com/google/gapid/core/data/slice"
"github.com/google/gapid/core/math/u64"
"github.com/google/gapid/gapis/api"
"github.com/google/gapid/gapis/capture"
"github.com/google/gapid/gapis/database"
"github.com/google/gapid/gapis/memory"
"github.com/google/gapid/gapis/service"
Expand All @@ -45,10 +44,11 @@ func StateTree(ctx context.Context, c *path.StateTree) (*service.StateTree, erro
}

type stateTree struct {
state *api.GlobalState
root *stn
api *path.API
groupLimit uint64
globalState *api.GlobalState
state interface{}
root *stn
api *path.API
groupLimit uint64
}

// needsSubgrouping returns true if the child count exceeds the group limit and
Expand Down Expand Up @@ -211,16 +211,16 @@ func (n *stn) buildChildren(ctx context.Context, tree *stateTree) {
s, e := subgroupRange(tree.groupLimit, size, i)
children = append(children, &stn{
name: fmt.Sprintf("[%d - %d]", n.subgroupOffset+s, n.subgroupOffset+e-1),
value: reflect.ValueOf(slice.ISlice(s, e, tree.state.MemoryLayout)),
value: reflect.ValueOf(slice.ISlice(s, e, tree.globalState.MemoryLayout)),
path: path.NewSlice(s, e-1, n.path),
isSubgroup: true,
subgroupOffset: n.subgroupOffset + s,
})
}
} else {
for i, c := uint64(0), slice.Count(); i < c; i++ {
ptr := slice.IIndex(i, tree.state.MemoryLayout)
el, err := memory.LoadPointer(ctx, ptr, tree.state.Memory, tree.state.MemoryLayout)
ptr := slice.IIndex(i, tree.globalState.MemoryLayout)
el, err := memory.LoadPointer(ctx, ptr, tree.globalState.Memory, tree.globalState.MemoryLayout)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -347,26 +347,22 @@ func stateValuePreview(v reflect.Value) (*box.Value, bool) {
// Resolve builds and returns a *StateTree for the path.StateTreeNode.
// Resolve implements the database.Resolver interface.
func (r *StateTreeResolvable) Resolve(ctx context.Context) (interface{}, error) {
state, err := GlobalState(ctx, r.Path.After.GlobalStateAfter())
globalState, err := GlobalState(ctx, r.Path.After.GlobalStateAfter())
if err != nil {
return nil, err
}
c, err := capture.ResolveFromPath(ctx, r.Path.After.Capture)

rootObj, rootPath, apiID, err := state(ctx, r.Path)
if err != nil {
return nil, err
}
cmdIdx := r.Path.After.Indices[0]

api := c.Commands[cmdIdx].API()
if api == nil {
return nil, fmt.Errorf("Command has no API")
}
apiState := state.APIs[api.ID()]
apiPath := &path.API{Id: path.NewID(id.ID(api.ID()))}
apiPath := &path.API{Id: path.NewID(id.ID(apiID))}

root := &stn{
name: "root",
value: deref(reflect.ValueOf(apiState)),
path: r.Path,
value: deref(reflect.ValueOf(rootObj)),
path: rootPath,
}
return &stateTree{state, root, apiPath, uint64(r.ArrayGroupSize)}, nil
return &stateTree{globalState, rootObj, root, apiPath, uint64(r.ArrayGroupSize)}, nil
}
Loading

0 comments on commit 94d0e90

Please sign in to comment.