#ifndef _gpuCacheSample_h_
#define _gpuCacheSample_h_
#include <maya/MBoundingBox.h>
#include <maya/MMatrix.h>
#include <maya/MHWGeometry.h>
#include <Alembic/Util/Digest.h>
#include <mutex>
#include <vector>
#include <memory>
#include "gpuCacheConfig.h"
namespace GPUCache {
class ArrayBase
{
public:
typedef Alembic::Util::Digest Digest;
struct Key
{
Key(const size_t bytes,
const Digest& digest
) : fBytes(bytes),
fDigest(digest)
{}
const size_t fBytes;
const Digest fDigest;
};
struct KeyHash
: std::unary_function<Key, std::size_t>
{
std::size_t operator()(Key const& key) const
{
std::size_t seed = 0;
GPUCache::hash_combine(seed, key.fBytes);
GPUCache::hash_combine(seed, key.fDigest.words[0]);
GPUCache::hash_combine(seed, key.fDigest.words[1]);
return seed;
}
};
struct KeyEqualTo
: std::binary_function<Key, Key, bool>
{
bool operator()(Key const& x,
Key const& y) const
{
return (x.fBytes == y.fBytes &&
x.fDigest == y.fDigest);
}
};
typedef void (*Callback)(const Key& array);
static void registerCreationCallback(Callback callback);
static void unregisterCreationCallback(Callback callback);
static void registerDestructionCallback(Callback callback);
static void unregisterDestructionCallback(Callback callback);
virtual ~ArrayBase();
size_t bytes() const { return fKey.fBytes; }
Digest digest() const { return fKey.fDigest; }
const Key& key() const { return fKey; }
bool isReadable() const { return fIsReadable; }
protected:
ArrayBase(size_t bytes, const Digest& digest, bool isReadable);
private:
ArrayBase(const ArrayBase&);
const ArrayBase& operator= (const ArrayBase&);
const Key fKey;
const bool fIsReadable;
};
template<typename T>
class ArrayReadInterface
{
public:
virtual const T* get() const = 0;
virtual ~ArrayReadInterface() {}
};
template <class T> class ReadableArray;
template <class T>
class Array : public ArrayBase
{
public:
~Array() override;
virtual std::shared_ptr<const ArrayReadInterface<T> > getReadable() const = 0;
virtual std::shared_ptr<ReadableArray<T> > getReadableArray() const = 0;
size_t size() const { return bytes() / sizeof(T); }
protected:
Array(size_t size, const Digest& digest, bool isReadable)
: ArrayBase(size * sizeof(T), digest, isReadable)
{}
};
template <typename T>
class ReadableArray : public Array<T>, public ArrayReadInterface<T>, public std::enable_shared_from_this<ReadableArray<T> >
{
public:
typedef typename Array<T>::Digest Digest;
~ReadableArray() override {}
std::shared_ptr<const ArrayReadInterface<T> > getReadable() const override
{
return this->shared_from_this();
}
std::shared_ptr<ReadableArray<T> > getReadableArray() const override
{
return const_cast<ReadableArray<T> *>(this)->shared_from_this();
}
protected:
ReadableArray(size_t size, const Digest& digest)
: Array<T>(size, digest, true)
{}
};
template <typename T>
class ArrayRegistry
{
public:
typedef Alembic::Util::Digest Digest;
static std::mutex& mutex();
static std::shared_ptr<Array<T> > lookup(
const Digest& digest,
size_t size
);
static std::shared_ptr<Array<T> > lookupNonReadable(
const Digest& digest,
size_t size
);
static std::shared_ptr<ReadableArray<T> > lookupReadable(
const Digest& digest,
size_t size
);
static void insert(std::shared_ptr<Array<T> > array);
};
template <class T>
class SharedArray : public ReadableArray<T>
{
public:
typedef typename Array<T>::Digest Digest;
static std::shared_ptr<ReadableArray<T> > create(
const GPUCache::shared_array<T>& data, size_t size);
static std::shared_ptr<ReadableArray<T> > create(
const GPUCache::shared_array<T>& data, Digest digest, size_t size);
~SharedArray() override;
const T* get() const override;
private:
struct MakeSharedEnabler;
SharedArray(
const GPUCache::shared_array<T>& data,
size_t size,
const Digest& digest
) : ReadableArray<T>(size, digest),
fData(data)
{}
const GPUCache::shared_array<T> fData;
};
class IndexBuffer
{
public:
typedef Alembic::Util::Digest Digest;
typedef unsigned int index_t;
typedef std::shared_ptr<const ReadableArray<index_t> > ReadableArrayPtr;
typedef std::shared_ptr<const ArrayReadInterface<index_t> > ReadInterfacePtr;
struct Key
{
Key(
const std::shared_ptr<Array<index_t> >& array,
const size_t beginIdx,
const size_t endIdx
) : fArrayKey(array->key()),
fBeginIdx(beginIdx),
fEndIdx(endIdx)
{}
const ArrayBase::Key fArrayKey;
const size_t fBeginIdx;
const size_t fEndIdx;
};
struct KeyHash
: std::unary_function<Key, std::size_t>
{
std::size_t operator()(Key const& key) const
{
std::size_t seed = 0;
GPUCache::hash_combine(seed, ArrayBase::KeyHash()(key.fArrayKey));
GPUCache::hash_combine(seed, key.fBeginIdx);
GPUCache::hash_combine(seed, key.fEndIdx);
return seed;
}
};
struct KeyEqualTo
: std::binary_function<Key, Key, bool>
{
bool operator()(Key const& x,
Key const& y) const
{
return (ArrayBase::KeyEqualTo()(x.fArrayKey, y.fArrayKey) &&
x.fBeginIdx == y.fBeginIdx &&
x.fEndIdx == y.fEndIdx);
}
};
static std::shared_ptr<IndexBuffer> create(
const std::shared_ptr<Array<index_t> >& array
)
{ return create( array, 0, array->size() ); }
static std::shared_ptr<IndexBuffer> create(
const std::shared_ptr<Array<index_t> >& array,
const size_t beginIdx,
const size_t endIdx
);
static size_t nbAllocated();
static size_t nbAllocatedBytes();
~IndexBuffer();
ReadInterfacePtr readableInterface() const { return fArray->getReadable(); }
size_t numIndices() const { return fEndIdx - fBeginIdx; }
size_t bytes() const { return numIndices() * sizeof(index_t); }
const std::shared_ptr<Array<index_t> >& array() const
{ return fArray; }
const size_t beginIdx() const
{ return fBeginIdx; }
const size_t endIdx() const
{ return fEndIdx; }
void ReplaceArrayInstance(std::shared_ptr<Array<index_t> >& newArray) const;
private:
struct MakeSharedEnabler;
IndexBuffer(
const std::shared_ptr<Array<index_t> >& array,
const size_t beginIdx,
const size_t endIdx
) : fArray(array),
fBeginIdx(beginIdx),
fEndIdx(endIdx)
{}
const std::shared_ptr<Array<index_t> > fArray;
const size_t fBeginIdx;
const size_t fEndIdx;
};
class VertexBuffer
{
public:
typedef Alembic::Util::Digest Digest;
typedef std::shared_ptr<const ReadableArray<float> > ReadableArrayPtr;
typedef std::shared_ptr<const ArrayReadInterface<float> > ReadInterfacePtr;
struct Key
{
Key(
const std::shared_ptr<Array<float> >& array,
) : fArrayKey(array->key()),
{}
const ArrayBase::Key fArrayKey;
std::string fName;
int fDimension;
int fOffset;
int fStride;
};
struct KeyHash
: std::unary_function<Key, std::size_t>
{
std::size_t operator()(Key const& key) const
{
std::size_t seed = 0;
GPUCache::hash_combine(seed, ArrayBase::KeyHash()(key.fArrayKey));
GPUCache::hash_combine(seed, key.fName);
GPUCache::hash_combine(seed, key.fSemantic);
GPUCache::hash_combine(seed, key.fDataType);
GPUCache::hash_combine(seed, key.fDimension);
GPUCache::hash_combine(seed, key.fOffset);
GPUCache::hash_combine(seed, key.fStride);
return seed;
}
};
struct KeyEqualTo
: std::binary_function<Key, Key, bool>
{
bool operator()(Key const& x,
Key const& y) const
{
return (ArrayBase::KeyEqualTo()(x.fArrayKey, y.fArrayKey) &&
x.fName == y.fName &&
x.fSemantic == y.fSemantic &&
x.fDataType == y.fDataType &&
x.fDimension == y.fDimension &&
x.fOffset == y.fOffset &&
x.fStride == y.fStride);
}
};
static std::shared_ptr<VertexBuffer> createPositions(
const std::shared_ptr<Array<float> >& array);
static std::shared_ptr<VertexBuffer> createNormals(
const std::shared_ptr<Array<float> >& array);
static std::shared_ptr<VertexBuffer> createUVs(
const std::shared_ptr<Array<float> >& array);
static size_t nbAllocated();
static size_t nbAllocatedBytes();
~VertexBuffer();
ReadInterfacePtr readableInterface() const { return fArray->getReadable(); }
size_t numVerts() const
{ return fArray->size() / fDescriptor.dimension(); }
size_t bytes() const
{ return fArray->bytes(); }
const std::shared_ptr<Array<float> >& array() const
{ return fArray; }
{ return fDescriptor; }
void ReplaceArrayInstance(std::shared_ptr<Array<float> >& newArray) const;
private:
struct MakeSharedEnabler;
static std::shared_ptr<VertexBuffer> create(
const std::shared_ptr<Array<float> >& array,
);
VertexBuffer(
const std::shared_ptr<Array<float> >& array,
)
: fArray(array),
fDescriptor(desc)
{}
const std::shared_ptr<Array<float> > fArray;
};
class ShapeSample
{
public:
static std::shared_ptr<ShapeSample> create(
double timeInSeconds,
size_t numWires,
size_t numVerts,
const std::shared_ptr<IndexBuffer>& wireVertIndices,
const std::shared_ptr<IndexBuffer>& triangleVertIndices,
const std::shared_ptr<VertexBuffer>& positions,
bool visibility);
static std::shared_ptr<ShapeSample> create(
double timeInSeconds,
size_t numWires,
size_t numVerts,
const std::shared_ptr<IndexBuffer>& wireVertIndices,
const std::vector<std::shared_ptr<IndexBuffer> >& triangleVertIndices,
const std::shared_ptr<VertexBuffer>& positions,
bool visibility);
static std::shared_ptr<ShapeSample> createEmptySample(
double timeInSeconds)
{
return ShapeSample::create(
timeInSeconds,
0,
0,
std::shared_ptr<IndexBuffer>(),
std::shared_ptr<IndexBuffer>(),
std::shared_ptr<VertexBuffer>(),
GPUCache::Config::kDefaultGrayColor,
false);
}
static std::shared_ptr<ShapeSample> createBoundingBoxPlaceHolderSample(
double timeInSeconds,
const MBoundingBox& bbox,
bool visibility)
{
std::shared_ptr<ShapeSample> sample = ShapeSample::create(
timeInSeconds,
0,
0,
std::shared_ptr<IndexBuffer>(),
std::shared_ptr<IndexBuffer>(),
std::shared_ptr<VertexBuffer>(),
bbox,
GPUCache::Config::kDefaultGrayColor,
visibility);
sample->setBoundingBoxPlaceHolder();
return sample;
}
~ShapeSample();
void setNormals(const std::shared_ptr<VertexBuffer>& normals);
void setUVs(const std::shared_ptr<VertexBuffer>& uvs);
double timeInSeconds() const { return fTimeInSeconds; }
bool visibility() const { return fVisibility; }
size_t numWires() const { return fNumWires; }
size_t numTriangles(size_t groupId) const
{ return fTriangleVertIndices[groupId] ? fTriangleVertIndices[groupId]->numIndices()/3 : 0; }
size_t numTriangles() const;
size_t numVerts() const { return fNumVerts; }
const std::shared_ptr<IndexBuffer>& wireVertIndices() const
{ return fWireVertIndices; }
const std::shared_ptr<IndexBuffer>& triangleVertIndices(size_t groupId) const
{ return fTriangleVertIndices[groupId]; }
const std::vector<std::shared_ptr<IndexBuffer> >& triangleVertexIndexGroups() const
{ return fTriangleVertIndices; }
size_t numIndexGroups() const
{ return fTriangleVertIndices.size(); }
const std::shared_ptr<VertexBuffer>& positions() const
{ return fPositions; }
{ return fBoundingBox; }
const MColor& diffuseColor()
const
{ return fDiffuseColor; }
const std::shared_ptr<VertexBuffer>& normals() const
{ return fNormals; }
const std::shared_ptr<VertexBuffer>& uvs() const
{ return fUVs; }
bool isBoundingBoxPlaceHolder() const
{ return fBoundingBoxPlaceHolder; }
void setBoundingBoxPlaceHolder()
{ fBoundingBoxPlaceHolder = true; }
private:
struct MakeSharedEnabler;
ShapeSample(
double timeInSeconds,
size_t numWires,
size_t numVerts,
const std::shared_ptr<IndexBuffer>& wireVertIndices,
const std::shared_ptr<IndexBuffer>& triangleVertIndices,
const std::shared_ptr<VertexBuffer>& positions,
bool visibility
);
ShapeSample(
double timeInSeconds,
size_t numWires,
size_t numVerts,
const std::shared_ptr<IndexBuffer>& wireVertIndices,
const std::vector<std::shared_ptr<IndexBuffer> >& triangleVertIndices,
const std::shared_ptr<VertexBuffer>& positions,
bool visibility
);
const double fTimeInSeconds;
const size_t fNumWires;
const size_t fNumVerts;
const std::shared_ptr<IndexBuffer> fWireVertIndices;
const std::vector<std::shared_ptr<IndexBuffer> > fTriangleVertIndices;
const std::shared_ptr<VertexBuffer> fPositions;
const bool fVisibility;
std::shared_ptr<VertexBuffer> fNormals;
std::shared_ptr<VertexBuffer> fUVs;
bool fBoundingBoxPlaceHolder;
};
class XformSample
{
public:
static std::shared_ptr<XformSample> create(
double timeInSeconds,
bool visibility);
~XformSample() {}
double timeInSeconds() const { return fTimeInSeconds; }
const MMatrix& xform()
const {
return fXform; }
bool isReflection() const { return fIsReflection; }
const MBoundingBox& boundingBox()
const {
return fBoundingBox; }
bool visibility() const { return fVisibility; }
private:
struct MakeSharedEnabler;
XformSample(double timeInSeconds,
bool visibility)
: fTimeInSeconds(timeInSeconds),
fXform(xform),
fIsReflection(xform.
det3x3() < 0.0f),
fBoundingBox(boundingBox),
fVisibility(visibility)
{}
const double fTimeInSeconds;
const bool fIsReflection;
const bool fVisibility;
};
}
#endif