| // 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. |
| |
| package client |
| |
| import ( |
| "fmt" |
| "sync" |
| |
| "android.googlesource.com/platform/tools/gpu/atom" |
| "android.googlesource.com/platform/tools/gpu/binary/registry" |
| "android.googlesource.com/platform/tools/gpu/binary/schema" |
| "android.googlesource.com/platform/tools/gpu/log" |
| "android.googlesource.com/platform/tools/gpu/service" |
| "android.googlesource.com/platform/tools/gpu/service/path" |
| ) |
| |
| type rpc struct { |
| logger log.Logger |
| client service.Client |
| ready <-chan struct{} |
| } |
| |
| func (r *rpc) init(logger log.Logger, client service.Client, constants map[string]schema.ConstantSet) { |
| ready := make(chan struct{}) |
| |
| r.logger = logger |
| r.ready = ready |
| |
| go func() { |
| // make the decoder namespace try the global namespace before the schema one |
| schemaNamespace := registry.NewNamespace() |
| namespace := registry.NewNamespace(registry.Global, schemaNamespace) |
| |
| s, err := client.GetSchema(r.logger) |
| if err != nil { |
| log.Errorf(r.logger, "Error resolving schema: %v", err) |
| return |
| } |
| log.Infof(r.logger, "Schema with %d classes, %d constant sets", len(s.Classes), len(s.Constants)) |
| atoms := 0 |
| for _, class := range s.Classes { |
| // Find the atom metadata, if present |
| if meta := atom.FindMetadata(class); meta != nil { |
| atoms++ |
| schemaNamespace.Add(NewAtomClass(class, meta)) |
| } else { |
| schemaNamespace.Add(class) |
| } |
| } |
| log.Infof(r.logger, "Schema with %d atoms", atoms) |
| for _, s := range s.Constants { |
| constants[s.Type.String()] = s |
| } |
| // Replace the current RPC |
| r.client = service.NewClient(client.Multiplexer(), namespace) |
| close(ready) |
| }() |
| } |
| |
| func (r *rpc) beginRPC(name string) log.Logger { |
| <-r.ready |
| return log.Enter(log.Fork(r.logger), name) |
| } |
| |
| func (r *rpc) GetCaptures() ([]capture, error) { |
| l := r.beginRPC("GetCaptures") |
| ids, err := r.client.GetCaptures(l) |
| if err != nil { |
| return nil, err |
| } |
| |
| wg := sync.WaitGroup{} |
| wg.Add(len(ids)) |
| captures := make([]capture, len(ids)) |
| for i := range ids { |
| i := i |
| go func() { |
| defer wg.Done() |
| captures[i].path = ids[i] |
| if c, err := service.GetCapture(captures[i].path, r.client, l); err == nil { |
| captures[i].info = c |
| } else { |
| log.E(l, "Failed to resolve capture %v: %v", ids[i], err) |
| } |
| }() |
| } |
| wg.Wait() |
| return captures, nil |
| } |
| |
| func (r *rpc) GetDevices() ([]device, error) { |
| l := r.beginRPC("GetDevices") |
| ids, err := r.client.GetDevices(l) |
| if err != nil { |
| return nil, err |
| } |
| |
| wg := sync.WaitGroup{} |
| wg.Add(len(ids)) |
| devices := make([]device, len(ids)) |
| for i := range ids { |
| i := i |
| go func() { |
| defer wg.Done() |
| devices[i].path = ids[i] |
| if d, err := service.GetDevice(devices[i].path, r.client, l); err == nil { |
| devices[i].info = d |
| } else { |
| log.E(l, "Failed to resolve device %v: %v", devices[i].path, err) |
| } |
| }() |
| } |
| wg.Wait() |
| return devices, nil |
| } |
| |
| func (r *rpc) Import(name string, data []byte) (*path.Capture, error) { |
| l := r.beginRPC("Import") |
| |
| id, err := r.client.Import(name, data, l) |
| if err != nil { |
| log.E(l, "Error importing capture: %v", err) |
| } |
| |
| return id, err |
| } |
| |
| func (r *rpc) LoadCapture(p *path.Capture) (service.Capture, error) { |
| l := r.beginRPC("LoadCapture") |
| |
| if capture, err := service.GetCapture(p, r.client, l); err == nil { |
| log.E(l, "Error getting capture: %v", err) |
| return service.Capture{}, err |
| } else { |
| return *capture, nil |
| } |
| } |
| |
| func (r *rpc) LoadAtoms(p *path.Atoms) ([]atom.Atom, error) { |
| l := r.beginRPC("LoadAtoms") |
| |
| stream, err := r.client.Get(p, l) |
| if err != nil { |
| log.E(l, "Error getting atom stream: %v", err) |
| return nil, err |
| } |
| |
| return stream.(*atom.List).Atoms, nil |
| } |
| |
| func (r *rpc) LoadHierarchy(p *path.Hierarchy) (atom.Group, error) { |
| l := r.beginRPC("LoadHierarchy") |
| |
| root, err := r.client.Get(p, l) |
| if err != nil { |
| log.E(l, "Error getting hierarchy: %v", err) |
| return atom.Group{}, err |
| } |
| |
| return *root.(*atom.Group), nil |
| } |
| |
| func (r *rpc) LoadTiming(device *path.Device, capture *path.Capture, flags service.TimingFlags) (service.TimingInfo, error) { |
| l := r.beginRPC("LoadTiming") |
| |
| p, err := r.client.GetTimingInfo(device, capture, flags, l) |
| if err != nil { |
| return service.TimingInfo{}, err |
| } |
| |
| timingInfo, err := service.GetTimingInfo(p, r.client, l) |
| if err != nil { |
| return service.TimingInfo{}, err |
| } |
| |
| return *timingInfo, nil |
| } |
| |
| func (r *rpc) LoadReport(capture *path.Capture) (service.Report, error) { |
| l := r.beginRPC("LoadReport") |
| |
| report, err := r.client.Get(capture.Report(), l) |
| if err != nil { |
| log.E(l, "Error loading report: %v", err) |
| return service.Report{}, nil |
| } |
| |
| return *report.(*service.Report), nil |
| } |
| |
| func (r *rpc) LoadState(state *path.State) (*schema.Object, error) { |
| l := r.beginRPC("LoadState") |
| |
| object, err := r.client.Get(state, l) |
| if err != nil { |
| log.E(l, "Error loading state: %v", err) |
| return nil, err |
| } |
| |
| return object.(*schema.Object), nil |
| } |
| |
| func (r *rpc) LoadMemory(rng *path.MemoryRange) (service.MemoryInfo, error) { |
| l := r.beginRPC("LoadMemory") |
| |
| object, err := r.client.Get(rng, l) |
| if err != nil { |
| log.E(l, "Error loading memory: %v", err) |
| return service.MemoryInfo{}, err |
| } |
| |
| return *object.(*service.MemoryInfo), nil |
| } |
| |
| func (r *rpc) RequestColorBuffer(device *path.Device, after *path.Atom, settings service.RenderSettings) (w, h int, d []byte, e error) { |
| l := r.beginRPC("RequestColorBuffer") |
| |
| imageID, err := r.client.GetFramebufferColor(device, after, settings, l) |
| if err != nil { |
| return 0, 0, nil, err |
| } |
| |
| imageInfo, err := service.GetImageInfo(imageID, r.client, l) |
| if err != nil { |
| return 0, 0, nil, err |
| } |
| |
| data, err := service.GetBlob(imageInfo.Data, r.client, l) |
| if err != nil { |
| return 0, 0, nil, err |
| } |
| |
| if imageInfo.Width <= 0 || imageInfo.Height <= 0 { |
| return 0, 0, nil, fmt.Errorf("Invalid image dimensions %dx%d", imageInfo.Width, imageInfo.Height) |
| } |
| return int(imageInfo.Width), int(imageInfo.Height), data, nil |
| } |
| |
| func (r *rpc) RequestDepthBuffer(device *path.Device, after *path.Atom) (w, h int, d []byte, e error) { |
| l := r.beginRPC("RequestDepthBuffer") |
| |
| imageID, err := r.client.GetFramebufferDepth(device, after, l) |
| if err != nil { |
| return 0, 0, nil, err |
| } |
| |
| imageInfo, err := service.GetImageInfo(imageID, r.client, l) |
| if err != nil { |
| return 0, 0, nil, err |
| } |
| |
| data, err := service.GetBlob(imageInfo.Data, r.client, l) |
| if err != nil { |
| return 0, 0, nil, err |
| } |
| |
| if imageInfo.Width <= 0 || imageInfo.Height <= 0 { |
| return 0, 0, nil, fmt.Errorf("Invalid image dimensions %dx%d", imageInfo.Width, imageInfo.Height) |
| } |
| return int(imageInfo.Width), int(imageInfo.Height), data, nil |
| } |
| |
| func (r *rpc) Change(p path.Path, v interface{}) (path.Path, error) { |
| l := r.beginRPC("Change") |
| log.I(l, "%v -> %v", p, v) |
| p, err := r.client.Set(p, v, l) |
| if err != nil { |
| return nil, err |
| } |
| return p, nil |
| } |
| |
| func (r *rpc) Follow(p path.Path) (path.Path, error) { |
| l := r.beginRPC("Follow") |
| p, err := r.client.Follow(p, l) |
| if err != nil { |
| log.E(l, "%v", err) |
| return nil, err |
| } |
| return p, nil |
| } |