blob: 887883fb9d08e39dd9391ceae05b54e6f6e606ca [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
import (
"fmt"
"strings"
"android.googlesource.com/platform/tools/gpu/binary"
"android.googlesource.com/platform/tools/gpu/database"
"android.googlesource.com/platform/tools/gpu/database/store"
"android.googlesource.com/platform/tools/gpu/interval"
"android.googlesource.com/platform/tools/gpu/log"
)
// Pool represents an unbounded and isolated memory space. Pool can be used
// to represent the application address space, or hidden GPU Pool.
//
// Pool can be sliced into smaller regions which can be read or written to.
// All writes to Pool or its slices do not actually perform binary data
// copies, but instead all writes are stored as lightweight records. Only when a
// Pool slice has Get called will any resolving, loading or copying of binary
// data occur.
type Pool struct {
binary.Generate `disable:"true"`
writes []write
}
// PoolID is an indentifier of a Pool.
type PoolID uint32
// ApplicationPool is the PoolID of Pool representing the application's memory
// address space.
const ApplicationPool PoolID = 0
// Slice returns a Slice referencing the subset of the Pool range.
func (m *Pool) Slice(rng Range) Slice {
for i := len(m.writes) - 1; i >= 0; i-- {
w := m.writes[i]
if w.dst.Overlaps(rng) {
if w.dst == rng {
return w.src
} else {
return poolSlice{m, rng, len(m.writes)}
}
}
}
return nullSlice(rng.Size)
}
// At returns an unbounded Slice starting at p.
func (m *Pool) At(p Pointer) Slice {
return m.Slice(Range{Base: p, Size: ^uint64(0) - uint64(p)})
}
// Write copies the slice src to dst.
func (m *Pool) Write(dst Pointer, src Slice) {
rng := Range{Base: dst, Size: src.Size()}
m.writes = append(m.writes, write{rng, src})
}
// String returns the full history of writes performed to this pool.
func (m *Pool) String() string {
l := make([]string, len(m.writes)+1)
l[0] = fmt.Sprintf("Pool(%p):", m)
for i, w := range m.writes {
l[i+1] = fmt.Sprintf("(%d) %v <- %v", i, w.dst, w.src)
}
return strings.Join(l, "\n")
}
type write struct {
dst Range
src Slice
}
type poolSlice struct {
pool *Pool // The pool that this slice belongs to.
rng Range // The memory range of the slice.
at int // The index in the pool's writes slice when the slice was created.
}
func (m poolSlice) Get(d database.Database, l log.Logger) ([]byte, error) {
buffer := make([]byte, m.rng.Size)
remaining := RangeList{m.rng}
for i := m.at - 1; i >= 0; i-- {
w := m.pool.writes[i]
if s, c := interval.Intersect(&remaining, w.dst.Span()); c > 0 {
src, err := w.src.Get(d, l)
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 poolSlice) ResourceID(d database.Database, l log.Logger) (binary.ID, error) {
bytes, err := m.Get(d, l)
if err != nil {
return binary.ID{}, err
}
return d.Store(&store.Blob{Data: bytes}, l)
}
func (m poolSlice) Slice(rng Range) Slice {
if uint64(rng.Last()) > m.rng.Size {
panic(fmt.Errorf("%v.Slice(%v) - out of bounds", m.String(), rng))
}
rng.Base += m.rng.Base
return poolSlice{m.pool, rng, len(m.pool.writes)}
}
func (m poolSlice) Size() uint64 {
return m.rng.Size
}
func (m poolSlice) String() string {
return fmt.Sprintf("Pool(%p)@%d%v", m.pool, m.at, m.rng)
}