blob: 979ec0a84282c52fa0d828caa320cec0ea923521 [file] [log] [blame]
/*
* 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 "src/gpu/GrBuffer.h"
#include "src/gpu/GrGpuBuffer.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() {
SkDEBUGCODE(fNonIndexNonInstanceData.fVertexCount = -1;)
}
bool isIndexed() const { return SkToBool(fIndexBuffer.get()); }
const GrBuffer* indexBuffer() const {
SkASSERT(this->isIndexed());
return fIndexBuffer.get();
}
GrPrimitiveRestart primitiveRestart() const {
return GrPrimitiveRestart(fFlags & Flags::kUsePrimitiveRestart);
}
bool isInstanced() const { return fFlags & Flags::kIsInstanced; }
const GrBuffer* instanceBuffer() const {
SkASSERT(this->isInstanced() || !fInstanceBuffer);
return fInstanceBuffer.get();
}
const GrBuffer* vertexBuffer() const { return fVertexBuffer.get(); }
void setNonIndexedNonInstanced(int vertexCount);
void setIndexed(sk_sp<const GrBuffer> indexBuffer, int indexCount, int baseIndex,
uint16_t minIndexValue, uint16_t maxIndexValue, GrPrimitiveRestart);
void setIndexedPatterned(sk_sp<const GrBuffer> indexBuffer, int indexCount, int vertexCount,
int patternRepeatCount, int maxPatternRepetitionsInIndexBuffer);
void setInstanced(sk_sp<const GrBuffer> instanceBuffer, int instanceCount, int baseInstance,
int vertexCount);
void setIndexedInstanced(sk_sp<const GrBuffer> indexBuffer, int indexCount,
sk_sp<const GrBuffer> instanceBuffer, int instanceCount,
int baseInstance, GrPrimitiveRestart);
void setVertexData(sk_sp<const GrBuffer> vertexBuffer, int baseVertex = 0);
class SendToGpuImpl {
public:
virtual void sendArrayMeshToGpu(GrPrimitiveType, const GrMesh&, int vertexCount,
int baseVertex) = 0;
virtual void sendIndexedMeshToGpu(GrPrimitiveType, const GrMesh&, int indexCount,
int baseIndex, uint16_t minIndexValue,
uint16_t maxIndexValue, int baseVertex) = 0;
virtual void sendInstancedMeshToGpu(GrPrimitiveType, const GrMesh&, int vertexCount,
int baseVertex, int instanceCount,
int baseInstance) = 0;
virtual void sendIndexedInstancedMeshToGpu(GrPrimitiveType, const GrMesh&, int indexCount,
int baseIndex, int baseVertex, int instanceCount,
int baseInstance) = 0;
virtual ~SendToGpuImpl() {}
};
void sendToGpu(GrPrimitiveType, SendToGpuImpl*) const;
private:
enum class Flags : uint8_t {
kNone = 0,
kUsePrimitiveRestart = 1 << 0,
kIsInstanced = 1 << 1,
};
GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(Flags);
static_assert(Flags(GrPrimitiveRestart::kNo) == Flags::kNone);
static_assert(Flags(GrPrimitiveRestart::kYes) == Flags::kUsePrimitiveRestart);
sk_sp<const GrBuffer> fIndexBuffer;
sk_sp<const GrBuffer> fInstanceBuffer;
sk_sp<const GrBuffer> fVertexBuffer;
int fBaseVertex = 0;
Flags fFlags = Flags::kNone;
union {
struct { // When fIndexBuffer == nullptr and isInstanced() == false.
int fVertexCount;
} fNonIndexNonInstanceData;
struct { // When fIndexBuffer != nullptr and isInstanced() == false.
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 isInstanced() != false.
struct {
int fInstanceCount;
int fBaseInstance;
} fInstanceData;
union { // When fIndexBuffer == nullptr.
struct {
int fVertexCount;
} fInstanceNonIndexData;
struct { // When fIndexBuffer != nullptr.
int fIndexCount;
} fInstanceIndexData;
};
};
};
};
GR_MAKE_BITFIELD_CLASS_OPS(GrMesh::Flags);
inline void GrMesh::setNonIndexedNonInstanced(int vertexCount) {
fIndexBuffer.reset();
fInstanceBuffer.reset();
fNonIndexNonInstanceData.fVertexCount = vertexCount;
fFlags = Flags::kNone;
}
inline void GrMesh::setIndexed(sk_sp<const GrBuffer> indexBuffer, int indexCount, int baseIndex,
uint16_t minIndexValue, uint16_t maxIndexValue,
GrPrimitiveRestart primitiveRestart) {
SkASSERT(indexBuffer);
SkASSERT(indexCount >= 1);
SkASSERT(baseIndex >= 0);
SkASSERT(maxIndexValue >= minIndexValue);
fIndexBuffer = std::move(indexBuffer);
fInstanceBuffer.reset();
fIndexData.fIndexCount = indexCount;
fIndexData.fPatternRepeatCount = 0;
fNonPatternIndexData.fBaseIndex = baseIndex;
fNonPatternIndexData.fMinIndexValue = minIndexValue;
fNonPatternIndexData.fMaxIndexValue = maxIndexValue;
fFlags = Flags(primitiveRestart);
}
inline void GrMesh::setIndexedPatterned(sk_sp<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 = std::move(indexBuffer);
fInstanceBuffer.reset();
fIndexData.fIndexCount = indexCount;
fIndexData.fPatternRepeatCount = patternRepeatCount;
fPatternData.fVertexCount = vertexCount;
fPatternData.fMaxPatternRepetitionsInIndexBuffer = maxPatternRepetitionsInIndexBuffer;
fFlags = Flags::kNone;
}
inline void GrMesh::setInstanced(sk_sp<const GrBuffer> instanceBuffer, int instanceCount,
int baseInstance, int vertexCount) {
SkASSERT(instanceCount >= 1);
SkASSERT(baseInstance >= 0);
fIndexBuffer.reset();
fInstanceBuffer = std::move(instanceBuffer);
fInstanceData.fInstanceCount = instanceCount;
fInstanceData.fBaseInstance = baseInstance;
fInstanceNonIndexData.fVertexCount = vertexCount;
fFlags = Flags::kIsInstanced;
}
inline void GrMesh::setIndexedInstanced(sk_sp<const GrBuffer> indexBuffer, int indexCount,
sk_sp<const GrBuffer> instanceBuffer, int instanceCount,
int baseInstance, GrPrimitiveRestart primitiveRestart) {
SkASSERT(indexBuffer);
SkASSERT(indexCount >= 1);
SkASSERT(instanceCount >= 1);
SkASSERT(baseInstance >= 0);
fIndexBuffer = std::move(indexBuffer);
fInstanceBuffer = std::move(instanceBuffer);
fInstanceData.fInstanceCount = instanceCount;
fInstanceData.fBaseInstance = baseInstance;
fInstanceIndexData.fIndexCount = indexCount;
fFlags = Flags::kIsInstanced | Flags(primitiveRestart);
}
inline void GrMesh::setVertexData(sk_sp<const GrBuffer> vertexBuffer, int baseVertex) {
SkASSERT(baseVertex >= 0);
fVertexBuffer = std::move(vertexBuffer);
fBaseVertex = baseVertex;
}
inline void GrMesh::sendToGpu(GrPrimitiveType primitiveType, SendToGpuImpl* impl) const {
if (this->isInstanced()) {
if (!this->isIndexed()) {
impl->sendInstancedMeshToGpu(primitiveType, *this, fInstanceNonIndexData.fVertexCount,
fBaseVertex, fInstanceData.fInstanceCount,
fInstanceData.fBaseInstance);
} else {
impl->sendIndexedInstancedMeshToGpu(
primitiveType, *this, fInstanceIndexData.fIndexCount, 0, fBaseVertex,
fInstanceData.fInstanceCount, fInstanceData.fBaseInstance);
}
return;
}
if (!this->isIndexed()) {
SkASSERT(fNonIndexNonInstanceData.fVertexCount > 0);
impl->sendArrayMeshToGpu(primitiveType, *this, fNonIndexNonInstanceData.fVertexCount,
fBaseVertex);
return;
}
if (0 == fIndexData.fPatternRepeatCount) {
impl->sendIndexedMeshToGpu(primitiveType, *this, fIndexData.fIndexCount,
fNonPatternIndexData.fBaseIndex,
fNonPatternIndexData.fMinIndexValue,
fNonPatternIndexData.fMaxIndexValue, fBaseVertex);
return;
}
SkASSERT(fIndexData.fPatternRepeatCount > 0);
int baseRepetition = 0;
do {
int repeatCount = std::min(fPatternData.fMaxPatternRepetitionsInIndexBuffer,
fIndexData.fPatternRepeatCount - baseRepetition);
int indexCount = fIndexData.fIndexCount * repeatCount;
// A patterned index buffer must contain indices in the range [0..vertexCount].
int minIndexValue = 0;
int maxIndexValue = fPatternData.fVertexCount * repeatCount - 1;
SkASSERT(!(fFlags & Flags::kUsePrimitiveRestart));
impl->sendIndexedMeshToGpu(primitiveType, *this, indexCount, 0, minIndexValue,
maxIndexValue,
fBaseVertex + fPatternData.fVertexCount * baseRepetition);
baseRepetition += repeatCount;
} while (baseRepetition < fIndexData.fPatternRepeatCount);
}
#endif