added skeletal animation support to GPU backend
Pulled from reverted CL: https://skia-review.googlesource.com/c/skia/+/139282 Bug: skia: Change-Id: Iad8e834aa5bbd085b2dee679cb343c5736c57907 Reviewed-on: https://skia-review.googlesource.com/140383 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Ruiqi Mao <ruiqimao@google.com>
This commit is contained in:
parent
2229b76258
commit
4ec72f7cc7
@ -874,7 +874,8 @@ bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context,
|
||||
}
|
||||
|
||||
paint.addCoverageFragmentProcessor(std::move(fp));
|
||||
renderTargetContext->drawVertices(clip, std::move(paint), viewMatrix, std::move(vertices));
|
||||
renderTargetContext->drawVertices(clip, std::move(paint), viewMatrix, std::move(vertices),
|
||||
nullptr, 0);
|
||||
} else {
|
||||
SkMatrix inverse;
|
||||
if (!viewMatrix.invert(&inverse)) {
|
||||
|
@ -27,8 +27,12 @@ enum GPFlag {
|
||||
kColorAttributeIsSkColor_GPFlag = 0x2,
|
||||
kLocalCoordAttribute_GPFlag = 0x4,
|
||||
kCoverageAttribute_GPFlag = 0x8,
|
||||
kBonesAttribute_GPFlag = 0x10,
|
||||
};
|
||||
|
||||
static constexpr int kMaxBones = 100; // Due to GPU memory limitations, only up to 100 bone
|
||||
// matrices are accepted.
|
||||
|
||||
class DefaultGeoProc : public GrGeometryProcessor {
|
||||
public:
|
||||
static sk_sp<GrGeometryProcessor> Make(uint32_t gpTypeFlags,
|
||||
@ -37,10 +41,12 @@ public:
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkMatrix& localMatrix,
|
||||
bool localCoordsWillBeRead,
|
||||
uint8_t coverage) {
|
||||
uint8_t coverage,
|
||||
const float* bones,
|
||||
int boneCount) {
|
||||
return sk_sp<GrGeometryProcessor>(new DefaultGeoProc(
|
||||
gpTypeFlags, color, std::move(colorSpaceXform), viewMatrix, localMatrix, coverage,
|
||||
localCoordsWillBeRead));
|
||||
localCoordsWillBeRead, bones, boneCount));
|
||||
}
|
||||
|
||||
const char* name() const override { return "DefaultGeometryProcessor"; }
|
||||
@ -52,6 +58,9 @@ public:
|
||||
bool localCoordsWillBeRead() const { return fLocalCoordsWillBeRead; }
|
||||
uint8_t coverage() const { return fCoverage; }
|
||||
bool hasVertexCoverage() const { return fInCoverage.isInitialized(); }
|
||||
const float* bones() const { return fBones; }
|
||||
int boneCount() const { return fBoneCount; }
|
||||
bool hasBones() const { return SkToBool(fBones); }
|
||||
|
||||
class GLSLProcessor : public GrGLSLGeometryProcessor {
|
||||
public:
|
||||
@ -99,11 +108,37 @@ public:
|
||||
&fColorUniform);
|
||||
}
|
||||
|
||||
// Setup bone transforms
|
||||
const char* transformedPositionName = gp.fInPosition.name();
|
||||
if (gp.hasBones()) {
|
||||
const char* vertBonesUniformName;
|
||||
fBonesUniform = uniformHandler->addUniformArray(kVertex_GrShaderFlag,
|
||||
kFloat3x3_GrSLType,
|
||||
"Bones",
|
||||
kMaxBones,
|
||||
&vertBonesUniformName);
|
||||
vertBuilder->codeAppendf(
|
||||
"float2 transformedPosition = (%s[0] * float3(%s, 1)).xy;"
|
||||
"float3x3 influence = float3x3(0);"
|
||||
"for (int i = 0; i < 4; i++) {"
|
||||
" int index = %s[i];"
|
||||
" float weight = %s[i];"
|
||||
" influence += %s[index] * weight;"
|
||||
"}"
|
||||
"transformedPosition = (influence * float3(transformedPosition, 1)).xy;",
|
||||
vertBonesUniformName,
|
||||
gp.fInPosition.name(),
|
||||
gp.fInBoneIndices.name(),
|
||||
gp.fInBoneWeights.name(),
|
||||
vertBonesUniformName);
|
||||
transformedPositionName = "transformedPosition";
|
||||
}
|
||||
|
||||
// Setup position
|
||||
this->writeOutputPosition(vertBuilder,
|
||||
uniformHandler,
|
||||
gpArgs,
|
||||
gp.fInPosition.name(),
|
||||
transformedPositionName,
|
||||
gp.viewMatrix(),
|
||||
&fViewMatrixUniform);
|
||||
|
||||
@ -147,8 +182,8 @@ public:
|
||||
GrProcessorKeyBuilder* b) {
|
||||
const DefaultGeoProc& def = gp.cast<DefaultGeoProc>();
|
||||
uint32_t key = def.fFlags;
|
||||
key |= (def.coverage() == 0xff) ? 0x10 : 0;
|
||||
key |= (def.localCoordsWillBeRead() && def.localMatrix().hasPerspective()) ? 0x20 : 0x0;
|
||||
key |= (def.coverage() == 0xff) ? 0x20 : 0;
|
||||
key |= (def.localCoordsWillBeRead() && def.localMatrix().hasPerspective()) ? 0x40 : 0x0;
|
||||
key |= ComputePosKey(def.viewMatrix()) << 20;
|
||||
b->add32(key);
|
||||
b->add32(GrColorSpaceXform::XformKey(def.fColorSpaceXform.get()));
|
||||
@ -180,6 +215,10 @@ public:
|
||||
this->setTransformDataHelper(dgp.fLocalMatrix, pdman, &transformIter);
|
||||
|
||||
fColorSpaceHelper.setData(pdman, dgp.fColorSpaceXform.get());
|
||||
|
||||
if (dgp.hasBones()) {
|
||||
pdman.setMatrix3fv(fBonesUniform, dgp.boneCount(), dgp.bones());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
@ -189,6 +228,7 @@ public:
|
||||
UniformHandle fViewMatrixUniform;
|
||||
UniformHandle fColorUniform;
|
||||
UniformHandle fCoverageUniform;
|
||||
UniformHandle fBonesUniform;
|
||||
GrGLSLColorSpaceXformHelper fColorSpaceHelper;
|
||||
|
||||
typedef GrGLSLGeometryProcessor INHERITED;
|
||||
@ -209,7 +249,9 @@ private:
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkMatrix& localMatrix,
|
||||
uint8_t coverage,
|
||||
bool localCoordsWillBeRead)
|
||||
bool localCoordsWillBeRead,
|
||||
const float* bones,
|
||||
int boneCount)
|
||||
: INHERITED(kDefaultGeoProc_ClassID)
|
||||
, fColor(color)
|
||||
, fViewMatrix(viewMatrix)
|
||||
@ -217,7 +259,9 @@ private:
|
||||
, fCoverage(coverage)
|
||||
, fFlags(gpTypeFlags)
|
||||
, fLocalCoordsWillBeRead(localCoordsWillBeRead)
|
||||
, fColorSpaceXform(std::move(colorSpaceXform)) {
|
||||
, fColorSpaceXform(std::move(colorSpaceXform))
|
||||
, fBones(bones)
|
||||
, fBoneCount(boneCount) {
|
||||
fInPosition = {"inPosition", kFloat2_GrVertexAttribType};
|
||||
int cnt = 1;
|
||||
if (fFlags & kColorAttribute_GPFlag) {
|
||||
@ -232,17 +276,32 @@ private:
|
||||
fInCoverage = {"inCoverage", kHalf_GrVertexAttribType};
|
||||
++cnt;
|
||||
}
|
||||
if (fFlags & kBonesAttribute_GPFlag) {
|
||||
SkASSERT(bones && (boneCount > 0));
|
||||
fInBoneIndices = {"inBoneIndices", kInt4_GrVertexAttribType};
|
||||
++cnt;
|
||||
fInBoneWeights = {"inBoneWeights", kFloat4_GrVertexAttribType};
|
||||
++cnt;
|
||||
}
|
||||
this->setVertexAttributeCnt(cnt);
|
||||
}
|
||||
|
||||
const Attribute& onVertexAttribute(int i) const override {
|
||||
return IthInitializedAttribute(i, fInPosition, fInColor, fInLocalCoords, fInCoverage);
|
||||
return IthInitializedAttribute(i,
|
||||
fInPosition,
|
||||
fInColor,
|
||||
fInLocalCoords,
|
||||
fInCoverage,
|
||||
fInBoneIndices,
|
||||
fInBoneWeights);
|
||||
}
|
||||
|
||||
Attribute fInPosition;
|
||||
Attribute fInColor;
|
||||
Attribute fInLocalCoords;
|
||||
Attribute fInCoverage;
|
||||
Attribute fInBoneIndices;
|
||||
Attribute fInBoneWeights;
|
||||
GrColor fColor;
|
||||
SkMatrix fViewMatrix;
|
||||
SkMatrix fLocalMatrix;
|
||||
@ -250,6 +309,8 @@ private:
|
||||
uint32_t fFlags;
|
||||
bool fLocalCoordsWillBeRead;
|
||||
sk_sp<GrColorSpaceXform> fColorSpaceXform;
|
||||
const float* fBones;
|
||||
int fBoneCount;
|
||||
|
||||
GR_DECLARE_GEOMETRY_PROCESSOR_TEST
|
||||
|
||||
@ -259,6 +320,15 @@ private:
|
||||
GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc);
|
||||
|
||||
#if GR_TEST_UTILS
|
||||
static constexpr int kNumFloatsPerSkMatrix = 9;
|
||||
static constexpr int kTestBoneCount = 4;
|
||||
static constexpr float kTestBones[kTestBoneCount * kNumFloatsPerSkMatrix] = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||
};
|
||||
|
||||
sk_sp<GrGeometryProcessor> DefaultGeoProc::TestCreate(GrProcessorTestData* d) {
|
||||
uint32_t flags = 0;
|
||||
if (d->fRandom->nextBool()) {
|
||||
@ -273,6 +343,9 @@ sk_sp<GrGeometryProcessor> DefaultGeoProc::TestCreate(GrProcessorTestData* d) {
|
||||
if (d->fRandom->nextBool()) {
|
||||
flags |= kLocalCoordAttribute_GPFlag;
|
||||
}
|
||||
if (d->fRandom->nextBool()) {
|
||||
flags |= kBonesAttribute_GPFlag;
|
||||
}
|
||||
|
||||
return DefaultGeoProc::Make(flags,
|
||||
GrRandomColor(d->fRandom),
|
||||
@ -280,7 +353,9 @@ sk_sp<GrGeometryProcessor> DefaultGeoProc::TestCreate(GrProcessorTestData* d) {
|
||||
GrTest::TestMatrix(d->fRandom),
|
||||
GrTest::TestMatrix(d->fRandom),
|
||||
d->fRandom->nextBool(),
|
||||
GrRandomCoverage(d->fRandom));
|
||||
GrRandomCoverage(d->fRandom),
|
||||
kTestBones,
|
||||
kTestBoneCount);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -307,7 +382,9 @@ sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::Make(const Color& color,
|
||||
viewMatrix,
|
||||
localCoords.fMatrix ? *localCoords.fMatrix : SkMatrix::I(),
|
||||
localCoordsWillBeRead,
|
||||
inCoverage);
|
||||
inCoverage,
|
||||
nullptr,
|
||||
0);
|
||||
}
|
||||
|
||||
sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::MakeForDeviceSpace(
|
||||
@ -330,3 +407,33 @@ sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::MakeForDeviceSpace(
|
||||
LocalCoords inverted(LocalCoords::kUsePosition_Type, &invert);
|
||||
return Make(color, coverage, inverted, SkMatrix::I());
|
||||
}
|
||||
|
||||
sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::MakeWithBones(const Color& color,
|
||||
const Coverage& coverage,
|
||||
const LocalCoords& localCoords,
|
||||
const Bones& bones,
|
||||
const SkMatrix& viewMatrix) {
|
||||
uint32_t flags = 0;
|
||||
if (Color::kPremulGrColorAttribute_Type == color.fType) {
|
||||
flags |= kColorAttribute_GPFlag;
|
||||
} else if (Color::kUnpremulSkColorAttribute_Type == color.fType) {
|
||||
flags |= kColorAttribute_GPFlag | kColorAttributeIsSkColor_GPFlag;
|
||||
}
|
||||
flags |= coverage.fType == Coverage::kAttribute_Type ? kCoverageAttribute_GPFlag : 0;
|
||||
flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoordAttribute_GPFlag : 0;
|
||||
flags |= kBonesAttribute_GPFlag;
|
||||
|
||||
uint8_t inCoverage = coverage.fCoverage;
|
||||
bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type;
|
||||
|
||||
GrColor inColor = color.fColor;
|
||||
return DefaultGeoProc::Make(flags,
|
||||
inColor,
|
||||
color.fColorSpaceXform,
|
||||
viewMatrix,
|
||||
localCoords.fMatrix ? *localCoords.fMatrix : SkMatrix::I(),
|
||||
localCoordsWillBeRead,
|
||||
inCoverage,
|
||||
bones.fBones,
|
||||
bones.fBoneCount);
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ namespace GrDefaultGeoProcFactory {
|
||||
SkPoint fLocalCoord;
|
||||
};
|
||||
|
||||
struct PositionColorLocalCoordCoverage {
|
||||
struct PositionColorLocalCoordCoverageAttr {
|
||||
SkPoint fPosition;
|
||||
GrColor fColor;
|
||||
SkPoint fLocalCoord;
|
||||
@ -118,6 +118,15 @@ namespace GrDefaultGeoProcFactory {
|
||||
const SkMatrix* fMatrix;
|
||||
};
|
||||
|
||||
struct Bones {
|
||||
Bones(const float bones[], int boneCount)
|
||||
: fBones(bones)
|
||||
, fBoneCount(boneCount) {}
|
||||
|
||||
const float* fBones;
|
||||
int fBoneCount;
|
||||
};
|
||||
|
||||
sk_sp<GrGeometryProcessor> Make(const Color&,
|
||||
const Coverage&,
|
||||
const LocalCoords&,
|
||||
@ -132,6 +141,17 @@ namespace GrDefaultGeoProcFactory {
|
||||
const Coverage&,
|
||||
const LocalCoords&,
|
||||
const SkMatrix& viewMatrix);
|
||||
|
||||
/*
|
||||
* Use this factory to create a GrGeometryProcessor that supports skeletal animation through
|
||||
* deformation of vertices using matrices that are passed in. This should only be called from
|
||||
* GrDrawVerticesOp.
|
||||
*/
|
||||
sk_sp<GrGeometryProcessor> MakeWithBones(const Color&,
|
||||
const Coverage&,
|
||||
const LocalCoords&,
|
||||
const Bones&,
|
||||
const SkMatrix& viewMatrix);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -846,6 +846,8 @@ void GrRenderTargetContext::drawVertices(const GrClip& clip,
|
||||
GrPaint&& paint,
|
||||
const SkMatrix& viewMatrix,
|
||||
sk_sp<SkVertices> vertices,
|
||||
const SkMatrix bones[],
|
||||
int boneCount,
|
||||
GrPrimitiveType* overridePrimType) {
|
||||
ASSERT_SINGLE_OWNER
|
||||
RETURN_IF_ABANDONED
|
||||
@ -857,7 +859,7 @@ void GrRenderTargetContext::drawVertices(const GrClip& clip,
|
||||
SkASSERT(vertices);
|
||||
GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo);
|
||||
std::unique_ptr<GrDrawOp> op = GrDrawVerticesOp::Make(
|
||||
fContext, std::move(paint), std::move(vertices), viewMatrix, aaType,
|
||||
fContext, std::move(paint), std::move(vertices), bones, boneCount, viewMatrix, aaType,
|
||||
this->colorSpaceInfo().refColorSpaceXformFromSRGB(), overridePrimType);
|
||||
this->addDrawOp(clip, std::move(op));
|
||||
}
|
||||
|
@ -218,12 +218,16 @@ public:
|
||||
* @param paint describes how to color pixels.
|
||||
* @param viewMatrix transformation matrix
|
||||
* @param vertices specifies the mesh to draw.
|
||||
* @param bones bone deformation matrices.
|
||||
* @param boneCount number of bone matrices.
|
||||
* @param overridePrimType primitive type to draw. If NULL, derive prim type from vertices.
|
||||
*/
|
||||
void drawVertices(const GrClip&,
|
||||
GrPaint&& paint,
|
||||
const SkMatrix& viewMatrix,
|
||||
sk_sp<SkVertices> vertices,
|
||||
const SkMatrix bones[],
|
||||
int boneCount,
|
||||
GrPrimitiveType* overridePrimType = nullptr);
|
||||
|
||||
/**
|
||||
|
@ -369,7 +369,7 @@ void SkGpuDevice::drawPoints(SkCanvas::PointMode mode,
|
||||
nullptr);
|
||||
|
||||
fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), *viewMatrix,
|
||||
std::move(vertices), &primitiveType);
|
||||
std::move(vertices), nullptr, 0, &primitiveType);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -1486,7 +1486,9 @@ static bool init_vertices_paint(GrContext* context, const GrColorSpaceInfo& colo
|
||||
}
|
||||
|
||||
void SkGpuDevice::wireframeVertices(SkVertices::VertexMode vmode, int vertexCount,
|
||||
const SkPoint vertices[], SkBlendMode bmode,
|
||||
const SkPoint vertices[],
|
||||
const SkMatrix bones[], int boneCount,
|
||||
SkBlendMode bmode,
|
||||
const uint16_t indices[], int indexCount,
|
||||
const SkPaint& paint) {
|
||||
ASSERT_SINGLE_OWNER
|
||||
@ -1544,12 +1546,13 @@ void SkGpuDevice::wireframeVertices(SkVertices::VertexMode vmode, int vertexCoun
|
||||
std::move(grPaint),
|
||||
this->ctm(),
|
||||
builder.detach(),
|
||||
bones,
|
||||
boneCount,
|
||||
&primitiveType);
|
||||
}
|
||||
|
||||
void SkGpuDevice::drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
|
||||
void SkGpuDevice::drawVertices(const SkVertices* vertices, const SkMatrix bones[], int boneCount,
|
||||
SkBlendMode mode, const SkPaint& paint) {
|
||||
// TODO: GPU ANIMATION
|
||||
ASSERT_SINGLE_OWNER
|
||||
GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext.get());
|
||||
|
||||
@ -1560,7 +1563,8 @@ void SkGpuDevice::drawVertices(const SkVertices* vertices, const SkMatrix* bones
|
||||
if ((!hasTexs || !paint.getShader()) && !hasColors) {
|
||||
// The dreaded wireframe mode. Fallback to drawVertices and go so slooooooow.
|
||||
this->wireframeVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(),
|
||||
mode, vertices->indices(), vertices->indexCount(), paint);
|
||||
bones, boneCount, mode, vertices->indices(), vertices->indexCount(),
|
||||
paint);
|
||||
return;
|
||||
}
|
||||
if (!init_vertices_paint(fContext.get(), fRenderTargetContext->colorSpaceInfo(), paint,
|
||||
@ -1568,7 +1572,8 @@ void SkGpuDevice::drawVertices(const SkVertices* vertices, const SkMatrix* bones
|
||||
return;
|
||||
}
|
||||
fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), this->ctm(),
|
||||
sk_ref_sp(const_cast<SkVertices*>(vertices)));
|
||||
sk_ref_sp(const_cast<SkVertices*>(vertices)),
|
||||
bones, boneCount);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -91,7 +91,7 @@ public:
|
||||
int scalarsPerPos, const SkPoint& offset, const SkPaint&) override;
|
||||
void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y,
|
||||
const SkPaint& paint, SkDrawFilter* drawFilter) override;
|
||||
void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
|
||||
void drawVertices(const SkVertices*, const SkMatrix bones[], int boneCount, SkBlendMode,
|
||||
const SkPaint&) override;
|
||||
void drawShadow(const SkPath&, const SkDrawShadowRec&) override;
|
||||
void drawAtlas(const SkImage* atlas, const SkRSXform[], const SkRect[],
|
||||
@ -248,7 +248,8 @@ private:
|
||||
void drawStrokedLine(const SkPoint pts[2], const SkPaint&);
|
||||
|
||||
void wireframeVertices(SkVertices::VertexMode, int vertexCount, const SkPoint verts[],
|
||||
SkBlendMode, const uint16_t indices[], int indexCount, const SkPaint&);
|
||||
const SkMatrix bones[], int boneCount, SkBlendMode,
|
||||
const uint16_t indices[], int indexCount, const SkPaint&);
|
||||
|
||||
static sk_sp<GrRenderTargetContext> MakeRenderTargetContext(GrContext*,
|
||||
SkBudgeted,
|
||||
|
@ -12,9 +12,13 @@
|
||||
#include "SkGr.h"
|
||||
#include "SkRectPriv.h"
|
||||
|
||||
static constexpr int kNumFloatsPerSkMatrix = 9;
|
||||
|
||||
std::unique_ptr<GrDrawOp> GrDrawVerticesOp::Make(GrContext* context,
|
||||
GrPaint&& paint,
|
||||
sk_sp<SkVertices> vertices,
|
||||
const SkMatrix bones[],
|
||||
int boneCount,
|
||||
const SkMatrix& viewMatrix,
|
||||
GrAAType aaType,
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
@ -23,13 +27,14 @@ std::unique_ptr<GrDrawOp> GrDrawVerticesOp::Make(GrContext* context,
|
||||
GrPrimitiveType primType = overridePrimType ? *overridePrimType
|
||||
: SkVertexModeToGrPrimitiveType(vertices->mode());
|
||||
return Helper::FactoryHelper<GrDrawVerticesOp>(context, std::move(paint), std::move(vertices),
|
||||
primType, aaType, std::move(colorSpaceXform),
|
||||
viewMatrix);
|
||||
bones, boneCount, primType, aaType,
|
||||
std::move(colorSpaceXform), viewMatrix);
|
||||
}
|
||||
|
||||
GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor color,
|
||||
sk_sp<SkVertices> vertices, GrPrimitiveType primitiveType,
|
||||
GrAAType aaType, sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
sk_sp<SkVertices> vertices, const SkMatrix bones[],
|
||||
int boneCount, GrPrimitiveType primitiveType, GrAAType aaType,
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
const SkMatrix& viewMatrix)
|
||||
: INHERITED(ClassID())
|
||||
, fHelper(helperArgs, aaType)
|
||||
@ -46,8 +51,25 @@ GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor c
|
||||
mesh.fColor = color;
|
||||
mesh.fViewMatrix = viewMatrix;
|
||||
mesh.fVertices = std::move(vertices);
|
||||
if (bones) {
|
||||
// Copy the bone data over in the format that the GPU would upload.
|
||||
mesh.fBones.reserve(boneCount * kNumFloatsPerSkMatrix);
|
||||
for (int i = 0; i < boneCount; i ++) {
|
||||
const SkMatrix& matrix = bones[i];
|
||||
mesh.fBones.push_back(matrix.get(SkMatrix::kMScaleX));
|
||||
mesh.fBones.push_back(matrix.get(SkMatrix::kMSkewY));
|
||||
mesh.fBones.push_back(matrix.get(SkMatrix::kMPersp0));
|
||||
mesh.fBones.push_back(matrix.get(SkMatrix::kMSkewX));
|
||||
mesh.fBones.push_back(matrix.get(SkMatrix::kMScaleY));
|
||||
mesh.fBones.push_back(matrix.get(SkMatrix::kMPersp1));
|
||||
mesh.fBones.push_back(matrix.get(SkMatrix::kMTransX));
|
||||
mesh.fBones.push_back(matrix.get(SkMatrix::kMTransY));
|
||||
mesh.fBones.push_back(matrix.get(SkMatrix::kMPersp2));
|
||||
}
|
||||
}
|
||||
mesh.fIgnoreTexCoords = false;
|
||||
mesh.fIgnoreColors = false;
|
||||
mesh.fIgnoreBones = false;
|
||||
|
||||
fFlags = 0;
|
||||
if (mesh.hasPerVertexColors()) {
|
||||
@ -56,6 +78,15 @@ GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor c
|
||||
if (mesh.hasExplicitLocalCoords()) {
|
||||
fFlags |= kAnyMeshHasExplicitLocalCoords_Flag;
|
||||
}
|
||||
if (mesh.hasBones()) {
|
||||
fFlags |= kHasBones_Flag;
|
||||
}
|
||||
|
||||
// Special case for meshes with a world transform but no bone weights.
|
||||
// These will be considered normal vertices draws without bones.
|
||||
if (!mesh.fVertices->hasBones() && boneCount == 1) {
|
||||
mesh.fViewMatrix.preConcat(bones[0]);
|
||||
}
|
||||
|
||||
IsZeroArea zeroArea;
|
||||
if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
|
||||
@ -64,10 +95,26 @@ GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor c
|
||||
zeroArea = IsZeroArea::kNo;
|
||||
}
|
||||
|
||||
this->setTransformedBounds(mesh.fVertices->bounds(),
|
||||
mesh.fViewMatrix,
|
||||
HasAABloat::kNo,
|
||||
zeroArea);
|
||||
if (this->hasBones()) {
|
||||
// We don't know the bounds if there are deformations involved, so attempt to calculate
|
||||
// the maximum possible.
|
||||
SkRect bounds;
|
||||
const SkRect originalBounds = bones[0].mapRect(mesh.fVertices->bounds());
|
||||
for (int i = 1; i < boneCount; i++) {
|
||||
const SkMatrix& matrix = bones[i];
|
||||
bounds.join(matrix.mapRect(originalBounds));
|
||||
}
|
||||
|
||||
this->setTransformedBounds(bounds,
|
||||
mesh.fViewMatrix,
|
||||
HasAABloat::kNo,
|
||||
zeroArea);
|
||||
} else {
|
||||
this->setTransformedBounds(mesh.fVertices->bounds(),
|
||||
mesh.fViewMatrix,
|
||||
HasAABloat::kNo,
|
||||
zeroArea);
|
||||
}
|
||||
}
|
||||
|
||||
SkString GrDrawVerticesOp::dumpInfo() const {
|
||||
@ -107,7 +154,8 @@ GrDrawOp::RequiresDstTexture GrDrawVerticesOp::finalize(const GrCaps& caps,
|
||||
}
|
||||
|
||||
sk_sp<GrGeometryProcessor> GrDrawVerticesOp::makeGP(bool* hasColorAttribute,
|
||||
bool* hasLocalCoordAttribute) const {
|
||||
bool* hasLocalCoordAttribute,
|
||||
bool* hasBoneAttribute) const {
|
||||
using namespace GrDefaultGeoProcFactory;
|
||||
LocalCoords::Type localCoordsType;
|
||||
if (fHelper.usesLocalCoords()) {
|
||||
@ -140,10 +188,21 @@ sk_sp<GrGeometryProcessor> GrDrawVerticesOp::makeGP(bool* hasColorAttribute,
|
||||
|
||||
const SkMatrix& vm = this->hasMultipleViewMatrices() ? SkMatrix::I() : fMeshes[0].fViewMatrix;
|
||||
|
||||
return GrDefaultGeoProcFactory::Make(color,
|
||||
Coverage::kSolid_Type,
|
||||
localCoordsType,
|
||||
vm);
|
||||
Bones bones(fMeshes[0].fBones.data(), fMeshes[0].fBones.size() / kNumFloatsPerSkMatrix);
|
||||
*hasBoneAttribute = this->hasBones();
|
||||
|
||||
if (this->hasBones()) {
|
||||
return GrDefaultGeoProcFactory::MakeWithBones(color,
|
||||
Coverage::kSolid_Type,
|
||||
localCoordsType,
|
||||
bones,
|
||||
vm);
|
||||
} else {
|
||||
return GrDefaultGeoProcFactory::Make(color,
|
||||
Coverage::kSolid_Type,
|
||||
localCoordsType,
|
||||
vm);
|
||||
}
|
||||
}
|
||||
|
||||
void GrDrawVerticesOp::onPrepareDraws(Target* target) {
|
||||
@ -157,13 +216,16 @@ void GrDrawVerticesOp::onPrepareDraws(Target* target) {
|
||||
void GrDrawVerticesOp::drawVolatile(Target* target) {
|
||||
bool hasColorAttribute;
|
||||
bool hasLocalCoordsAttribute;
|
||||
bool hasBoneAttribute;
|
||||
sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute,
|
||||
&hasLocalCoordsAttribute);
|
||||
&hasLocalCoordsAttribute,
|
||||
&hasBoneAttribute);
|
||||
|
||||
// Calculate the stride.
|
||||
size_t vertexStride = sizeof(SkPoint) +
|
||||
(hasColorAttribute ? sizeof(uint32_t) : 0) +
|
||||
(hasLocalCoordsAttribute ? sizeof(SkPoint) : 0);
|
||||
(hasLocalCoordsAttribute ? sizeof(SkPoint) : 0) +
|
||||
(hasBoneAttribute ? 4 * (sizeof(uint32_t) + sizeof(float)) : 0);
|
||||
SkASSERT(vertexStride == gp->debugOnly_vertexStride());
|
||||
|
||||
// Allocate buffers.
|
||||
@ -189,6 +251,7 @@ void GrDrawVerticesOp::drawVolatile(Target* target) {
|
||||
// Fill the buffers.
|
||||
this->fillBuffers(hasColorAttribute,
|
||||
hasLocalCoordsAttribute,
|
||||
hasBoneAttribute,
|
||||
vertexStride,
|
||||
verts,
|
||||
indices);
|
||||
@ -202,8 +265,10 @@ void GrDrawVerticesOp::drawNonVolatile(Target* target) {
|
||||
|
||||
bool hasColorAttribute;
|
||||
bool hasLocalCoordsAttribute;
|
||||
bool hasBoneAttribute;
|
||||
sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute,
|
||||
&hasLocalCoordsAttribute);
|
||||
&hasLocalCoordsAttribute,
|
||||
&hasBoneAttribute);
|
||||
|
||||
SkASSERT(fMeshes.count() == 1); // Non-volatile meshes should never combine.
|
||||
|
||||
@ -235,7 +300,8 @@ void GrDrawVerticesOp::drawNonVolatile(Target* target) {
|
||||
// Calculate the stride.
|
||||
size_t vertexStride = sizeof(SkPoint) +
|
||||
(hasColorAttribute ? sizeof(uint32_t) : 0) +
|
||||
(hasLocalCoordsAttribute ? sizeof(SkPoint) : 0);
|
||||
(hasLocalCoordsAttribute ? sizeof(SkPoint) : 0) +
|
||||
(hasBoneAttribute ? 4 * (sizeof(uint32_t) + sizeof(float)) : 0);
|
||||
SkASSERT(vertexStride == gp->debugOnly_vertexStride());
|
||||
|
||||
// Allocate vertex buffer.
|
||||
@ -266,6 +332,7 @@ void GrDrawVerticesOp::drawNonVolatile(Target* target) {
|
||||
// Fill the buffers.
|
||||
this->fillBuffers(hasColorAttribute,
|
||||
hasLocalCoordsAttribute,
|
||||
hasBoneAttribute,
|
||||
vertexStride,
|
||||
verts,
|
||||
indices);
|
||||
@ -286,6 +353,7 @@ void GrDrawVerticesOp::drawNonVolatile(Target* target) {
|
||||
|
||||
void GrDrawVerticesOp::fillBuffers(bool hasColorAttribute,
|
||||
bool hasLocalCoordsAttribute,
|
||||
bool hasBoneAttribute,
|
||||
size_t vertexStride,
|
||||
void* verts,
|
||||
uint16_t* indices) const {
|
||||
@ -296,7 +364,7 @@ void GrDrawVerticesOp::fillBuffers(bool hasColorAttribute,
|
||||
// We have a fast case below for uploading the vertex data when the matrix is translate
|
||||
// only and there are colors but not local coords. Fast case does not apply when there are bone
|
||||
// transformations.
|
||||
bool fastAttrs = hasColorAttribute && !hasLocalCoordsAttribute;
|
||||
bool fastAttrs = hasColorAttribute && !hasLocalCoordsAttribute && !hasBoneAttribute;
|
||||
for (int i = 0; i < instanceCount; i++) {
|
||||
// Get each mesh.
|
||||
const Mesh& mesh = fMeshes[i];
|
||||
@ -314,6 +382,8 @@ void GrDrawVerticesOp::fillBuffers(bool hasColorAttribute,
|
||||
const SkPoint* positions = mesh.fVertices->positions();
|
||||
const SkColor* colors = mesh.fVertices->colors();
|
||||
const SkPoint* localCoords = mesh.fVertices->texCoords();
|
||||
const SkVertices::BoneIndices* boneIndices = mesh.fVertices->boneIndices();
|
||||
const SkVertices::BoneWeights* boneWeights = mesh.fVertices->boneWeights();
|
||||
bool fastMesh = (!this->hasMultipleViewMatrices() ||
|
||||
mesh.fViewMatrix.getType() <= SkMatrix::kTranslate_Mask) &&
|
||||
mesh.hasPerVertexColors();
|
||||
@ -343,6 +413,14 @@ void GrDrawVerticesOp::fillBuffers(bool hasColorAttribute,
|
||||
offset += sizeof(uint32_t);
|
||||
}
|
||||
size_t localCoordOffset = offset;
|
||||
if (hasLocalCoordsAttribute) {
|
||||
offset += sizeof(SkPoint);
|
||||
}
|
||||
size_t boneIndexOffset = offset;
|
||||
if (hasBoneAttribute) {
|
||||
offset += 4 * sizeof(uint32_t);
|
||||
}
|
||||
size_t boneWeightOffset = offset;
|
||||
|
||||
for (int j = 0; j < vertexCount; ++j) {
|
||||
if (this->hasMultipleViewMatrices()) {
|
||||
@ -364,6 +442,16 @@ void GrDrawVerticesOp::fillBuffers(bool hasColorAttribute,
|
||||
*(SkPoint*)((intptr_t)verts + localCoordOffset) = positions[j];
|
||||
}
|
||||
}
|
||||
if (hasBoneAttribute) {
|
||||
const SkVertices::BoneIndices& indices = boneIndices[j];
|
||||
const SkVertices::BoneWeights& weights = boneWeights[j];
|
||||
for (int k = 0; k < 4; k++) {
|
||||
size_t indexOffset = boneIndexOffset + sizeof(uint32_t) * k;
|
||||
size_t weightOffset = boneWeightOffset + sizeof(float) * k;
|
||||
*(uint32_t*)((intptr_t)verts + indexOffset) = indices.indices[k];
|
||||
*(float*)((intptr_t)verts + weightOffset) = weights.weights[k];
|
||||
}
|
||||
}
|
||||
verts = (void*)((intptr_t)verts + vertexStride);
|
||||
}
|
||||
}
|
||||
@ -397,6 +485,13 @@ bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Meshes with bones cannot be combined because different meshes use different bones, so to
|
||||
// combine them, the matrices would have to be combined, and the bone indices on each vertex
|
||||
// would change, thus making the vertices uncacheable.
|
||||
if (this->hasBones() || that->hasBones()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Non-volatile meshes cannot batch, because if a non-volatile mesh batches with another mesh,
|
||||
// then on the next frame, if that non-volatile mesh is drawn, it will draw the other mesh
|
||||
// that was saved in its vertex buffer, which is not necessarily there anymore.
|
||||
@ -558,7 +653,7 @@ GR_DRAW_OP_TEST_DEFINE(GrDrawVerticesOp) {
|
||||
if (GrFSAAType::kUnifiedMSAA == fsaaType && random->nextBool()) {
|
||||
aaType = GrAAType::kMSAA;
|
||||
}
|
||||
return GrDrawVerticesOp::Make(context, std::move(paint), std::move(vertices),
|
||||
return GrDrawVerticesOp::Make(context, std::move(paint), std::move(vertices), nullptr, 0,
|
||||
viewMatrix, aaType, std::move(colorSpaceXform), &type);
|
||||
}
|
||||
|
||||
|
@ -38,13 +38,16 @@ public:
|
||||
static std::unique_ptr<GrDrawOp> Make(GrContext* context,
|
||||
GrPaint&&,
|
||||
sk_sp<SkVertices>,
|
||||
const SkMatrix bones[],
|
||||
int boneCount,
|
||||
const SkMatrix& viewMatrix,
|
||||
GrAAType,
|
||||
sk_sp<GrColorSpaceXform>,
|
||||
GrPrimitiveType* overridePrimType = nullptr);
|
||||
|
||||
GrDrawVerticesOp(const Helper::MakeArgs&, GrColor, sk_sp<SkVertices>, GrPrimitiveType, GrAAType,
|
||||
sk_sp<GrColorSpaceXform>, const SkMatrix& viewMatrix);
|
||||
GrDrawVerticesOp(const Helper::MakeArgs&, GrColor, sk_sp<SkVertices>, const SkMatrix bones[],
|
||||
int boneCount, GrPrimitiveType, GrAAType, sk_sp<GrColorSpaceXform>,
|
||||
const SkMatrix& viewMatrix);
|
||||
|
||||
const char* name() const override { return "DrawVerticesOp"; }
|
||||
|
||||
@ -72,6 +75,7 @@ private:
|
||||
|
||||
void fillBuffers(bool hasColorAttribute,
|
||||
bool hasLocalCoordsAttribute,
|
||||
bool hasBoneAttribute,
|
||||
size_t vertexStride,
|
||||
void* verts,
|
||||
uint16_t* indices) const;
|
||||
@ -84,7 +88,8 @@ private:
|
||||
int firstIndex);
|
||||
|
||||
sk_sp<GrGeometryProcessor> makeGP(bool* hasColorAttribute,
|
||||
bool* hasLocalCoordAttribute) const;
|
||||
bool* hasLocalCoordAttribute,
|
||||
bool* hasBoneAttribute) const;
|
||||
|
||||
GrPrimitiveType primitiveType() const { return fPrimitiveType; }
|
||||
bool combinablePrimitive() const {
|
||||
@ -98,9 +103,11 @@ private:
|
||||
struct Mesh {
|
||||
GrColor fColor; // Used if this->hasPerVertexColors() is false.
|
||||
sk_sp<SkVertices> fVertices;
|
||||
std::vector<float> fBones; // Transformation matrices stored in GPU format.
|
||||
SkMatrix fViewMatrix;
|
||||
bool fIgnoreTexCoords;
|
||||
bool fIgnoreColors;
|
||||
bool fIgnoreBones;
|
||||
|
||||
bool hasExplicitLocalCoords() const {
|
||||
return fVertices->hasTexCoords() && !fIgnoreTexCoords;
|
||||
@ -109,6 +116,10 @@ private:
|
||||
bool hasPerVertexColors() const {
|
||||
return fVertices->hasColors() && !fIgnoreColors;
|
||||
}
|
||||
|
||||
bool hasBones() const {
|
||||
return fVertices->hasBones() && fBones.size() && !fIgnoreBones;
|
||||
}
|
||||
};
|
||||
|
||||
bool isIndexed() const {
|
||||
@ -128,10 +139,15 @@ private:
|
||||
return SkToBool(kHasMultipleViewMatrices_Flag & fFlags);
|
||||
}
|
||||
|
||||
bool hasBones() const {
|
||||
return SkToBool(kHasBones_Flag & fFlags);
|
||||
}
|
||||
|
||||
enum Flags {
|
||||
kRequiresPerVertexColors_Flag = 0x1,
|
||||
kAnyMeshHasExplicitLocalCoords_Flag = 0x2,
|
||||
kHasMultipleViewMatrices_Flag = 0x4,
|
||||
kHasBones_Flag = 0x8,
|
||||
};
|
||||
|
||||
Helper fHelper;
|
||||
|
Loading…
Reference in New Issue
Block a user