Skip to content

Commit

Permalink
Add gvr extension to group reproduction contexts sensibly.
Browse files Browse the repository at this point in the history
  • Loading branch information
ben-clayton committed Sep 14, 2017
1 parent b06ba8d commit 9a53ca7
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 3 deletions.
1 change: 1 addition & 0 deletions gapis/api/gvr/CMakeFiles.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ set(files
constant_sets.go
convert.go
enum.go
extension.go
framebindings.go
gvr.api
gvr.go
Expand Down
185 changes: 185 additions & 0 deletions gapis/api/gvr/extension.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// 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 gvr

import (
"context"
"reflect"

"github.com/google/gapid/gapis/api"
"github.com/google/gapid/gapis/api/gles"
"github.com/google/gapid/gapis/extensions"
"github.com/google/gapid/gapis/resolve"
"github.com/google/gapid/gapis/resolve/cmdgrouper"
"github.com/google/gapid/gapis/service"
"github.com/google/gapid/gapis/service/path"
)

func init() {
extensions.Register(extensions.Extension{
Name: "GVR",
AdjustContexts: adjustContexts,
CmdGroupers: newReprojectionGroupers,
Events: newReprojectionEvents,
})
}

type contextUsage int

const (
rendererCtx = contextUsage(iota)
reprojectionCtx
)

func adjustContexts(ctx context.Context, ctxs []*api.ContextInfo) {
// Look for the renderer context.
tyGvrFrameSubmit := reflect.TypeOf(&Gvr_frame_submit{})
if c := findContextByCommand(ctxs, tyGvrFrameSubmit); c != nil {
c.UserData[rendererCtx] = true
c.Name = "Main context (" + c.Name + ")"
}

// Look for the reprojection context.
tyGlFlush := reflect.TypeOf(&gles.GlFlush{})
if c := findContextByCommand(ctxs, tyGlFlush); c != nil {
c.UserData[reprojectionCtx] = true
c.Name = "Reprojection context"
}
}

func findContextByCommand(ctxs []*api.ContextInfo, ty reflect.Type) *api.ContextInfo {
highest, best := 0, (*api.ContextInfo)(nil)
for _, c := range ctxs {
if count := c.NumCommandsByType[ty]; count > highest {
highest, best = count, c
}
}
return best
}

func isReprojectionContext(ctx context.Context, p *path.Context) bool {
// Only group if we're looking at the reprojection thread.
if p == nil {
return false
}
c, err := resolve.Context(ctx, p)
if c == nil || err != nil {
return false
}
_, ok := c.UserData[reprojectionCtx]
return ok
}

func newReprojectionGroupers(ctx context.Context, p *path.CommandTree) []cmdgrouper.Grouper {
if !isReprojectionContext(ctx, p.Capture.Context(p.GetFilter().GetContext().ID())) {
return nil
}
glFenceSync := func(cond gles.GLenum) func(cmd, prev api.Cmd) bool {
return func(cmd, prev api.Cmd) bool {
c, ok := cmd.(*gles.GlFenceSync)
return ok && c.Condition == cond
}
}
glEndTilingQCOM := func(cond gles.GLbitfield) func(cmd, prev api.Cmd) bool {
return func(cmd, prev api.Cmd) bool {
c, ok := cmd.(*gles.GlEndTilingQCOM)
return ok && c.PreserveMask == cond
}
}
eglDestroySyncKHR := func() func(cmd, prev api.Cmd) bool {
return func(cmd, prev api.Cmd) bool {
_, ok := cmd.(*gles.EglDestroySyncKHR)
return ok
}
}
glClientWaitSync := func() func(cmd, prev api.Cmd) bool {
return func(cmd, prev api.Cmd) bool {
_, ok := cmd.(*gles.GlClientWaitSync)
return ok
}
}
glDeleteSync := func() func(cmd, prev api.Cmd) bool {
return func(cmd, prev api.Cmd) bool {
_, ok := cmd.(*gles.GlDeleteSync)
return ok
}
}
glDrawElements := func() func(cmd, prev api.Cmd) bool {
return func(cmd, prev api.Cmd) bool {
_, ok := cmd.(*gles.GlDrawElements)
return ok
}
}
notGlDrawElements := func() func(cmd, prev api.Cmd) bool {
return func(cmd, prev api.Cmd) bool {
_, ok := cmd.(*gles.GlDrawElements)
return !ok
}
}
notGlFlush := func() func(cmd, prev api.Cmd) bool {
return func(cmd, prev api.Cmd) bool {
_, ok := cmd.(*gles.GlFlush)
return !ok
}
}
return []cmdgrouper.Grouper{
cmdgrouper.Sequence("Left eye",
cmdgrouper.Rule{Pred: eglDestroySyncKHR()},
cmdgrouper.Rule{Pred: glClientWaitSync()},
cmdgrouper.Rule{Pred: glDeleteSync()},
cmdgrouper.Rule{Pred: notGlDrawElements(), Repeats: true},
cmdgrouper.Rule{Pred: glDrawElements()},
),
cmdgrouper.Sequence("Right eye",
cmdgrouper.Rule{Pred: glFenceSync(gles.GLenum_GL_SYNC_GPU_COMMANDS_COMPLETE)},
cmdgrouper.Rule{Pred: glEndTilingQCOM(1), Optional: true},
cmdgrouper.Rule{Pred: glClientWaitSync()},
cmdgrouper.Rule{Pred: glDeleteSync()},
cmdgrouper.Rule{Pred: notGlDrawElements(), Repeats: true},
cmdgrouper.Rule{Pred: glDrawElements()},
cmdgrouper.Rule{Pred: notGlFlush(), Repeats: true},
),
}
}

func newReprojectionEvents(ctx context.Context, p *path.Events) extensions.EventProvider {
if !isReprojectionContext(ctx, p.Capture.Context(p.GetFilter().GetContext().ID())) {
return nil
}

var pending []service.EventKind
return func(ctx context.Context, id api.CmdID, cmd api.Cmd, s *api.GlobalState) []*service.Event {
events := []*service.Event{}
for _, kind := range pending {
events = append(events, &service.Event{
Kind: kind,
Command: p.Capture.Command(uint64(id)),
})
}
pending = nil
if _, ok := cmd.(*gles.GlFlush); ok {
if p.LastInFrame {
events = append(events, &service.Event{
Kind: service.EventKind_LastInFrame,
Command: p.Capture.Command(uint64(id)),
})
}
if p.FirstInFrame {
pending = append(pending, service.EventKind_FirstInFrame)
}
}
return events
}
}
15 changes: 14 additions & 1 deletion gapis/extensions/extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,36 @@
package extensions

import (
"context"
"sync"

"github.com/google/gapid/gapis/api"
"github.com/google/gapid/gapis/resolve/cmdgrouper"
"github.com/google/gapid/gapis/service"
"github.com/google/gapid/gapis/service/path"
)

var (
extensions []Extension
mutex sync.Mutex
)

// EventProvider is a function that produces events for the given command and
// state.
type EventProvider func(ctx context.Context, id api.CmdID, cmd api.Cmd, s *api.GlobalState) []*service.Event

// Extension is a GAPIS extension.
// It should be registered at application initialization with Register.
type Extension struct {
// Name of the extension.
Name string
// AdjustContexts lets the extension rename or reprioritize the list of
// contexts.
AdjustContexts func(context.Context, []*api.ContextInfo)
// Custom command groupers.
CmdGroupers func() []cmdgrouper.Grouper
CmdGroupers func(ctx context.Context, p *path.CommandTree) []cmdgrouper.Grouper
// Custom events provider.
Events func(ctx context.Context, p *path.Events) EventProvider
}

// Register registers the extension e.
Expand Down
5 changes: 4 additions & 1 deletion gapis/extensions/unity/unity.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@
package unity

import (
"context"

"github.com/google/gapid/gapis/extensions"
"github.com/google/gapid/gapis/resolve/cmdgrouper"
"github.com/google/gapid/gapis/service/path"
)

func init() {
extensions.Register(extensions.Extension{
Name: "Unity",
CmdGroupers: func() []cmdgrouper.Grouper {
CmdGroupers: func(ctx context.Context, p *path.CommandTree) []cmdgrouper.Grouper {
return []cmdgrouper.Grouper{
newStateResetGrouper(),
}
Expand Down
2 changes: 1 addition & 1 deletion gapis/resolve/command_tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ func (r *CommandTreeResolvable) Resolve(ctx context.Context) (interface{}, error

// Add any extension groupers
for _, e := range extensions.Get() {
groupers = append(groupers, e.CmdGroupers()...)
groupers = append(groupers, e.CmdGroupers(ctx, p)...)
}

// Walk the list of unfiltered commands to build the groups.
Expand Down
7 changes: 7 additions & 0 deletions gapis/resolve/contexts.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/google/gapid/gapis/api"
"github.com/google/gapid/gapis/capture"
"github.com/google/gapid/gapis/database"
"github.com/google/gapid/gapis/extensions"
"github.com/google/gapid/gapis/messages"
"github.com/google/gapid/gapis/service"
"github.com/google/gapid/gapis/service/path"
Expand Down Expand Up @@ -156,5 +157,11 @@ func (r *ContextListResolvable) Resolve(ctx context.Context) (interface{}, error
}
}

for _, e := range extensions.Get() {
if e.AdjustContexts != nil {
e.AdjustContexts(ctx, out)
}
}

return out, nil
}
15 changes: 15 additions & 0 deletions gapis/resolve/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/google/gapid/gapis/api"
"github.com/google/gapid/gapis/capture"
"github.com/google/gapid/gapis/extensions"
"github.com/google/gapid/gapis/service"
"github.com/google/gapid/gapis/service/path"
)
Expand All @@ -40,6 +41,16 @@ func Events(ctx context.Context, p *path.Events) (*service.Events, error) {
return nil, err
}

// Add any extension events
eps := []extensions.EventProvider{}
for _, e := range extensions.Get() {
if e.Events != nil {
if ep := e.Events(ctx, p); ep != nil {
eps = append(eps, ep)
}
}
}

events := []*service.Event{}

s := c.NewState()
Expand Down Expand Up @@ -138,6 +149,10 @@ func Events(ctx context.Context, p *path.Events) (*service.Events, error) {
})
}

for _, ep := range eps {
events = append(events, ep(ctx, id, cmd, s)...)
}

lastCmd = id
return nil
})
Expand Down

0 comments on commit 9a53ca7

Please sign in to comment.