aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Ruiqi Mao <ruiqimao@google.com>2018-07-10 13:08:32 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-07-10 20:25:55 +0000
commitd275ef501c8e6ea6444912e22c29e2d13a3dfb53 (patch)
tree8171fef3aef275e20e87963d85f50ec8711b683d
parentc69c4410be7def8fa129496de994d83c497f06db (diff)
added skeletal animation support to GPU backend
Pulled from reverted CL: https://skia-review.googlesource.com/c/skia/+/138596 Bug: skia: Change-Id: Ie07f1c76bae65c219ebe93d071bb19f1a30100c2 Reviewed-on: https://skia-review.googlesource.com/139282 Reviewed-by: Brian Osman <brianosman@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com> Commit-Queue: Ruiqi Mao <ruiqimao@google.com>
-rw-r--r--src/core/SkBlurMF.cpp3
-rw-r--r--src/gpu/GrDefaultGeoProcFactory.cpp127
-rw-r--r--src/gpu/GrDefaultGeoProcFactory.h22
-rw-r--r--src/gpu/GrRenderTargetContext.cpp4
-rw-r--r--src/gpu/GrRenderTargetContext.h4
-rw-r--r--src/gpu/SkGpuDevice.cpp17
-rw-r--r--src/gpu/SkGpuDevice.h5
-rw-r--r--src/gpu/ops/GrDrawVerticesOp.cpp133
-rw-r--r--src/gpu/ops/GrDrawVerticesOp.h22
9 files changed, 294 insertions, 43 deletions
diff --git a/src/core/SkBlurMF.cpp b/src/core/SkBlurMF.cpp
index 23cca83655..f3d71230e7 100644
--- a/src/core/SkBlurMF.cpp
+++ b/src/core/SkBlurMF.cpp
@@ -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)) {
diff --git a/src/gpu/GrDefaultGeoProcFactory.cpp b/src/gpu/GrDefaultGeoProcFactory.cpp
index e2bf87b277..788833ed8c 100644
--- a/src/gpu/GrDefaultGeoProcFactory.cpp
+++ b/src/gpu/GrDefaultGeoProcFactory.cpp
@@ -27,8 +27,13 @@ enum GPFlag {
kColorAttributeIsSkColor_GPFlag = 0x2,
kLocalCoordAttribute_GPFlag = 0x4,
kCoverageAttribute_GPFlag = 0x8,
+ kBonesAttribute_GPFlag = 0x10,
};
+static constexpr int kNumFloatsPerSkMatrix = 9;
+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 +42,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 +59,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 +109,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 +183,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 +216,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 +229,7 @@ public:
UniformHandle fViewMatrixUniform;
UniformHandle fColorUniform;
UniformHandle fCoverageUniform;
+ UniformHandle fBonesUniform;
GrGLSLColorSpaceXformHelper fColorSpaceHelper;
typedef GrGLSLGeometryProcessor INHERITED;
@@ -209,7 +250,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 +260,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 +277,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 +310,8 @@ private:
uint32_t fFlags;
bool fLocalCoordsWillBeRead;
sk_sp<GrColorSpaceXform> fColorSpaceXform;
+ const float* fBones;
+ int fBoneCount;
GR_DECLARE_GEOMETRY_PROCESSOR_TEST
@@ -259,6 +321,14 @@ private:
GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc);
#if GR_TEST_UTILS
+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);
+}
diff --git a/src/gpu/GrDefaultGeoProcFactory.h b/src/gpu/GrDefaultGeoProcFactory.h
index 314c1bb963..52db807ca4 100644
--- a/src/gpu/GrDefaultGeoProcFactory.h
+++ b/src/gpu/GrDefaultGeoProcFactory.h
@@ -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
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 497518f46f..51c9a85f02 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -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));
}
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index 783b351b06..ee0d183981 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -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);
/**
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index f031e5edf1..c9cda0de7d 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -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);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index 48ba8ac8a1..c31e6245b3 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -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,
diff --git a/src/gpu/ops/GrDrawVerticesOp.cpp b/src/gpu/ops/GrDrawVerticesOp.cpp
index 7cfb3a2efa..bb5b7a5ef2 100644
--- a/src/gpu/ops/GrDrawVerticesOp.cpp
+++ b/src/gpu/ops/GrDrawVerticesOp.cpp
@@ -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);
}
diff --git a/src/gpu/ops/GrDrawVerticesOp.h b/src/gpu/ops/GrDrawVerticesOp.h
index 3a6eca0a0d..d15e620ff5 100644
--- a/src/gpu/ops/GrDrawVerticesOp.h
+++ b/src/gpu/ops/GrDrawVerticesOp.h
@@ -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;