/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrMesh_DEFINED
#define GrMesh_DEFINED
#include "GrBuffer.h"
#include "GrGpuResourceRef.h"
class GrPrimitiveProcessor;
/**
* Used to communicate index and vertex buffers, counts, and offsets for a draw from GrOp to
* GrGpu. It also holds the primitive type for the draw. TODO: Consider moving ownership of this
* and draw-issuing responsibility to GrPrimitiveProcessor. The rest of the vertex info lives there
* already (stride, attribute mappings).
*/
class GrMesh {
public:
GrMesh(GrPrimitiveType primitiveType)
: fPrimitiveType(primitiveType)
, fBaseVertex(0) {
SkDEBUGCODE(fNonIndexNonInstanceData.fVertexCount = -1;)
}
GrPrimitiveType primitiveType() const { return fPrimitiveType; }
bool isIndexed() const { return SkToBool(fIndexBuffer.get()); }
bool isInstanced() const { return SkToBool(fInstanceBuffer.get()); }
bool hasVertexData() const { return SkToBool(fVertexBuffer.get()); }
void setNonIndexedNonInstanced(int vertexCount);
void setIndexed(const GrBuffer* indexBuffer, int indexCount, int baseIndex,
uint16_t minIndexValue, uint16_t maxIndexValue);
void setIndexedPatterned(const GrBuffer* indexBuffer, int indexCount, int vertexCount,
int patternRepeatCount, int maxPatternRepetitionsInIndexBuffer);
void setInstanced(const GrBuffer* instanceBuffer, int instanceCount, int baseInstance,
int vertexCount);
void setIndexedInstanced(const GrBuffer* indexBuffer, int indexCount,
const GrBuffer* instanceBuffer, int instanceCount, int baseInstance=0);
void setVertexData(const GrBuffer* vertexBuffer, int baseVertex = 0);
class SendToGpuImpl {
public:
virtual void sendMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
const GrBuffer* vertexBuffer, int vertexCount,
int baseVertex) = 0;
virtual void sendIndexedMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
const GrBuffer* indexBuffer, int indexCount,
int baseIndex, uint16_t minIndexValue,
uint16_t maxIndexValue, const GrBuffer* vertexBuffer,
int baseVertex) = 0;
virtual void sendInstancedMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
const GrBuffer* vertexBuffer, int vertexCount,
int baseVertex, const GrBuffer* instanceBuffer,
int instanceCount, int baseInstance) = 0;
virtual void sendIndexedInstancedMeshToGpu(const GrPrimitiveProcessor&, GrPrimitiveType,
const GrBuffer* indexBuffer, int indexCount,
int baseIndex, const GrBuffer* vertexBuffer,
int baseVertex, const GrBuffer* instanceBuffer,
int instanceCount, int baseInstance) = 0;
virtual ~SendToGpuImpl() {}
};
void sendToGpu(const GrPrimitiveProcessor&, SendToGpuImpl*) const;
struct PatternBatch;
private:
using PendingBuffer = GrPendingIOResource<const GrBuffer, kRead_GrIOType>;
GrPrimitiveType fPrimitiveType;
PendingBuffer fIndexBuffer;
PendingBuffer fInstanceBuffer;
PendingBuffer fVertexBuffer;
int fBaseVertex;
union {
struct { // When fIndexBuffer == nullptr and fInstanceBuffer == nullptr.
int fVertexCount;
} fNonIndexNonInstanceData;
struct { // When fIndexBuffer != nullptr and fInstanceBuffer == nullptr.
struct {
int fIndexCount;
int fPatternRepeatCount;
} fIndexData;
union {
struct { // When fPatternRepeatCount == 0.
int fBaseIndex;
uint16_t fMinIndexValue;
uint16_t fMaxIndexValue;
} fNonPatternIndexData;
struct { // When fPatternRepeatCount != 0.
int fVertexCount;
int fMaxPatternRepetitionsInIndexBuffer;
} fPatternData;
};
};
struct { // When fInstanceBuffer != nullptr.
struct {
int fInstanceCount;
int fBaseInstance;
} fInstanceData;
union { // When fIndexBuffer == nullptr.
struct {
int fVertexCount;
} fInstanceNonIndexData;
struct { // When fIndexBuffer != nullptr.
int fIndexCount;
} fInstanceIndexData;
};
};
};
};
inline void GrMesh::setNonIndexedNonInstanced(int vertexCount) {
fIndexBuffer.reset(nullptr);
fInstanceBuffer.reset(nullptr);
fNonIndexNonInstanceData.fVertexCount = vertexCount;
}
inline void GrMesh::setIndexed(const GrBuffer* indexBuffer, int indexCount, int baseIndex,
uint16_t minIndexValue, uint16_t maxIndexValue) {
SkASSERT(indexBuffer);
SkASSERT(indexCount >= 1);
SkASSERT(baseIndex >= 0);
SkASSERT(maxIndexValue >= minIndexValue);
fIndexBuffer.reset(indexBuffer);
fInstanceBuffer.reset(nullptr);
fIndexData.fIndexCount = indexCount;
fIndexData.fPatternRepeatCount = 0;
fNonPatternIndexData.fBaseIndex = baseIndex;
fNonPatternIndexData.fMinIndexValue = minIndexValue;
fNonPatternIndexData.fMaxIndexValue = maxIndexValue;
}
inline void GrMesh::setIndexedPatterned(const GrBuffer* indexBuffer, int indexCount,
int vertexCount, int patternRepeatCount,
int maxPatternRepetitionsInIndexBuffer) {
SkASSERT(indexBuffer);
SkASSERT(indexCount >= 1);
SkASSERT(vertexCount >= 1);
SkASSERT(patternRepeatCount >= 1);
SkASSERT(maxPatternRepetitionsInIndexBuffer >= 1);
fIndexBuffer.reset(indexBuffer);
fInstanceBuffer.reset(nullptr);
fIndexData.fIndexCount = indexCount;
fIndexData.fPatternRepeatCount = patternRepeatCount;
fPatternData.fVertexCount = vertexCount;
fPatternData.fMaxPatternRepetitionsInIndexBuffer = maxPatternRepetitionsInIndexBuffer;
}
inline void GrMesh::setInstanced(const GrBuffer* instanceBuffer, int instanceCount,
int baseInstance, int vertexCount) {
SkASSERT(instanceBuffer);
SkASSERT(instanceCount >= 1);
SkASSERT(baseInstance >= 0);
fIndexBuffer.reset(nullptr);
fInstanceBuffer.reset(instanceBuffer);
fInstanceData.fInstanceCount = instanceCount;
fInstanceData.fBaseInstance = baseInstance;
fInstanceNonIndexData.fVertexCount = vertexCount;
}
inline void GrMesh::setIndexedInstanced(const GrBuffer* indexBuffer, int indexCount,
const GrBuffer* instanceBuffer, int instanceCount,
int baseInstance) {
SkASSERT(indexBuffer);
SkASSERT(indexCount >= 1);
SkASSERT(instanceBuffer);
SkASSERT(instanceCount >= 1);
SkASSERT(baseInstance >= 0);
fIndexBuffer.reset(indexBuffer);
fInstanceBuffer.reset(instanceBuffer);
fInstanceData.fInstanceCount = instanceCount;
fInstanceData.fBaseInstance = baseInstance;
fInstanceIndexData.fIndexCount = indexCount;
}
inline void GrMesh::setVertexData(const GrBuffer* vertexBuffer, int baseVertex) {
SkASSERT(baseVertex >= 0);
fVertexBuffer.reset(vertexBuffer);
fBaseVertex = baseVertex;
}
inline void GrMesh::sendToGpu(const GrPrimitiveProcessor& primProc, SendToGpuImpl* impl) const {
if (this->isInstanced()) {
if (!this->isIndexed()) {
impl->sendInstancedMeshToGpu(primProc, fPrimitiveType, fVertexBuffer.get(),
fInstanceNonIndexData.fVertexCount, fBaseVertex,
fInstanceBuffer.get(), fInstanceData.fInstanceCount,
fInstanceData.fBaseInstance);
} else {
impl->sendIndexedInstancedMeshToGpu(primProc, fPrimitiveType, fIndexBuffer.get(),
fInstanceIndexData.fIndexCount, 0,
fVertexBuffer.get(), fBaseVertex,
fInstanceBuffer.get(), fInstanceData.fInstanceCount,
fInstanceData.fBaseInstance);
}
return;
}
if (!this->isIndexed()) {
SkASSERT(fNonIndexNonInstanceData.fVertexCount > 0);
impl->sendMeshToGpu(primProc, fPrimitiveType, fVertexBuffer.get(),
fNonIndexNonInstanceData.fVertexCount, fBaseVertex);
return;
}
if (0 == fIndexData.fPatternRepeatCount) {
impl->sendIndexedMeshToGpu(primProc, fPrimitiveType, fIndexBuffer.get(),
fIndexData.fIndexCount, fNonPatternIndexData.fBaseIndex,
fNonPatternIndexData.fMinIndexValue,
fNonPatternIndexData.fMaxIndexValue, fVertexBuffer.get(),
fBaseVertex);
return;
}
SkASSERT(fIndexData.fPatternRepeatCount > 0);
int baseRepetition = 0;
do {
int repeatCount = SkTMin(fPatternData.fMaxPatternRepetitionsInIndexBuffer,
fIndexData.fPatternRepeatCount - baseRepetition);
// A patterned index buffer must contain indices in the range [0..vertexCount].
int minIndexValue = 0;
int maxIndexValue = fPatternData.fVertexCount * repeatCount - 1;
impl->sendIndexedMeshToGpu(primProc, fPrimitiveType, fIndexBuffer.get(),
fIndexData.fIndexCount * repeatCount, 0, minIndexValue,
maxIndexValue, fVertexBuffer.get(),
fBaseVertex + fPatternData.fVertexCount * baseRepetition);
baseRepetition += repeatCount;
} while (baseRepetition < fIndexData.fPatternRepeatCount);
}
#endif