blob: a4557f0f214586801e32bf08e2143638fe7434a0 [file] [log] [blame]
// 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 memory contains types used for representing and simulating memory
// observed in the capture.
package memory
import (
"fmt"
"android.googlesource.com/platform/tools/gpu/binary"
"android.googlesource.com/platform/tools/gpu/database"
"android.googlesource.com/platform/tools/gpu/interval"
"android.googlesource.com/platform/tools/gpu/log"
)
// Data is the interface for a data source that can be resolved to a byte slice
// with Get.
//
// Size returns the number of bytes that would be returned by calling Get.
type Data interface {
Get(db database.Database, logger log.Logger) ([]byte, error)
Size() uint64
}
// DataSlicer extends the Data interface with aditional support for slicing.
//
// Slice returns a new DataSlicer referencing a subset range of the data.
// The range r is relative to the base of the DataSlicer. For example a slice of
// [0, 4] would return a DataSlicer referencing the first 5 bytes of this
// DataSlicer. Attempting to slice outside the range of this DataSlicer will
// result in a panic.
type DataSlicer interface {
Data
Slice(r Range) DataSlicer
}
// DataSliceWriter is similar to DataSlicer, but also has the Write method for
// modifying the data that the DataSliceWriter refers to.
//
// Write will replace the data in this DataSliceWriter with d.
// If d is shorter in length than the slice, then only the range [0, d.Size()-1]
// bytes will be replaced.
// A sliced DataSliceWriter shares the same data from which it was sliced - i.e.
// any mutations to a DataSliceWriter will also affect the Data it was sliced
// from.
type DataSliceWriter interface {
Data
Slice(r Range) DataSliceWriter
Write(d Data)
}
type dataSlice struct {
src Data
rng Range
}
func slice(src Data, rng Range) DataSlicer {
if rng.Base < 0 || uint64(rng.Last()) > src.Size() {
panic(fmt.Errorf("Slice range (%s) out of bounds (%s)", rng, Range{0, src.Size()}))
}
return dataSlice{src, rng}
}
func (s dataSlice) Get(db database.Database, logger log.Logger) ([]byte, error) {
if data, err := s.src.Get(db, logger); err == nil {
return data[s.rng.First() : s.rng.Last()+1], nil
} else {
return nil, err
}
}
func (s dataSlice) Slice(rng Range) DataSlicer { return slice(s.src, rng) }
func (s dataSlice) Size() uint64 { return s.rng.Size }
type memorySlice struct {
mem *Memory
rng Range
}
func (m memorySlice) Get(db database.Database, logger log.Logger) ([]byte, error) {
buffer := make([]byte, m.rng.Size)
remaining := RangeList{m.rng}
for i := len(m.mem.writes) - 1; i >= 0; i-- {
w := m.mem.writes[i]
if s, c := interval.Intersect(&remaining, w.dst.Span()); c > 0 {
src, err := w.src.Get(db, logger)
if err != nil {
return nil, err
}
for i := s; i < s+c; i++ {
intersect := w.dst.Intersect(remaining[i])
src := src[intersect.Base-w.dst.Base:][:intersect.Size]
dst := buffer[intersect.Base-m.rng.Base:][:intersect.Size]
copy(dst, src)
}
interval.Remove(&remaining, w.dst.Span())
if len(remaining) == 0 {
return buffer, nil
}
}
}
return buffer, nil
}
func (m memorySlice) Slice(rng Range) DataSliceWriter {
if rng.Base < 0 || uint64(rng.Last()) > m.rng.Size {
panic(fmt.Errorf("Slice range (%s) out of bounds (%s)", rng, Range{0, m.rng.Size}))
}
rng.Base += m.rng.Base
return memorySlice{m.mem, rng}
}
func (m memorySlice) Size() uint64 {
return m.rng.Size
}
func (m memorySlice) Write(src Data) {
m.mem.writes = append(m.mem.writes, memoryWrite{m.rng, src})
}
type memoryWrite struct {
dst Range
src Data
}
// Memory represents an unbounded and isolated memory space. Memory can be used
// to represent the application address space, or hidden GPU memory.
//
// Memory can be sliced into smaller regions which can be read or written to.
// All writes to Memory or its slices do not actually perform binary data
// copies, but instead all writes are stored as lightweight records. Only when a
// Memory slice has Get called will any resolving, loading or copying of binary
// data occur.
type Memory struct {
writes []memoryWrite
}
// Slice returns a DataSliceWriter referencing the subset of the Memory range.
func (m *Memory) Slice(rng Range) DataSliceWriter {
return memorySlice{m, rng}
}
// Write copies d to the Memory slice [0, d.Size()-1].
func (m *Memory) Write(d Data) {
m.writes = append(m.writes, memoryWrite{Range{0, d.Size()}, d})
}
func (m *Memory) Encode(e *binary.Encoder) error { return nil /* Currently not persisted */ }
func (m *Memory) Decode(d *binary.Decoder) error { return nil /* Currently not persisted */ }