diff options
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrDefaultGeoProcFactory.cpp | 142 | ||||
-rw-r--r-- | src/gpu/GrDefaultGeoProcFactory.h | 22 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetContext.cpp | 4 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetContext.h | 4 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 17 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.h | 5 | ||||
-rw-r--r-- | src/gpu/ops/GrDrawVerticesOp.cpp | 289 | ||||
-rw-r--r-- | src/gpu/ops/GrDrawVerticesOp.h | 47 |
8 files changed, 471 insertions, 59 deletions
diff --git a/src/gpu/GrDefaultGeoProcFactory.cpp b/src/gpu/GrDefaultGeoProcFactory.cpp index e2bf87b277..c9108e3d96 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 SkMatrix 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.data(); } + int boneCount() const { return fBones.size() / kNumFloatsPerSkMatrix; } + bool hasBones() const { return fBones.size() > 0; } 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 SkMatrix* bones, + int boneCount) : INHERITED(kDefaultGeoProc_ClassID) , fColor(color) , fViewMatrix(viewMatrix) @@ -217,7 +260,8 @@ private: , fCoverage(coverage) , fFlags(gpTypeFlags) , fLocalCoordsWillBeRead(localCoordsWillBeRead) - , fColorSpaceXform(std::move(colorSpaceXform)) { + , fColorSpaceXform(std::move(colorSpaceXform)) + , fBones() { fInPosition = {"inPosition", kFloat2_GrVertexAttribType}; int cnt = 1; if (fFlags & kColorAttribute_GPFlag) { @@ -232,17 +276,49 @@ 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); + + // Set bone data + if (bones) { + fBones.reserve(boneCount * kNumFloatsPerSkMatrix); + for (int i = 0; i < boneCount; i ++) { + const SkMatrix& matrix = bones[i]; + fBones.push_back(matrix.get(SkMatrix::kMScaleX)); + fBones.push_back(matrix.get(SkMatrix::kMSkewY)); + fBones.push_back(matrix.get(SkMatrix::kMPersp0)); + fBones.push_back(matrix.get(SkMatrix::kMSkewX)); + fBones.push_back(matrix.get(SkMatrix::kMScaleY)); + fBones.push_back(matrix.get(SkMatrix::kMPersp1)); + fBones.push_back(matrix.get(SkMatrix::kMTransX)); + fBones.push_back(matrix.get(SkMatrix::kMTransY)); + fBones.push_back(matrix.get(SkMatrix::kMPersp2)); + } + } } 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 +326,7 @@ private: uint32_t fFlags; bool fLocalCoordsWillBeRead; sk_sp<GrColorSpaceXform> fColorSpaceXform; + std::vector<float> fBones; GR_DECLARE_GEOMETRY_PROCESSOR_TEST @@ -273,6 +350,17 @@ sk_sp<GrGeometryProcessor> DefaultGeoProc::TestCreate(GrProcessorTestData* d) { if (d->fRandom->nextBool()) { flags |= kLocalCoordAttribute_GPFlag; } + if (d->fRandom->nextBool()) { + flags |= kBonesAttribute_GPFlag; + } + + int numBones = d->fRandom->nextRangeU(0, kMaxBones); + std::vector<SkMatrix> bones(numBones); + for (int i = 0; i < numBones; i++) { + for (int j = 0; j < kNumFloatsPerSkMatrix; j++) { + bones[i][j] = d->fRandom->nextF(); + } + } return DefaultGeoProc::Make(flags, GrRandomColor(d->fRandom), @@ -280,7 +368,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), + bones.data(), + numBones); } #endif @@ -307,7 +397,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 +422,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..c22cefbd73 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 SkMatrix bones[], int boneCount) + : fBones(bones) + , fBoneCount(boneCount) {} + + const SkMatrix* 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 05b3c2475a..40303668d8 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -844,6 +844,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 @@ -855,7 +857,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 a665517d4f..f1e527036b 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -365,7 +365,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); } /////////////////////////////////////////////////////////////////////////////// @@ -1480,7 +1480,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 @@ -1538,12 +1540,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()); @@ -1554,7 +1557,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, @@ -1562,7 +1566,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 ad5aba2b2c..6abca9d3e8 100644 --- a/src/gpu/ops/GrDrawVerticesOp.cpp +++ b/src/gpu/ops/GrDrawVerticesOp.cpp @@ -10,10 +10,13 @@ #include "GrDefaultGeoProcFactory.h" #include "GrOpFlushState.h" #include "SkGr.h" +#include "SkRectPriv.h" 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, @@ -22,13 +25,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) @@ -45,15 +49,28 @@ GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor c mesh.fColor = color; mesh.fViewMatrix = viewMatrix; mesh.fVertices = std::move(vertices); + if (bones) { + mesh.fBones.assign(bones, bones + boneCount); + } mesh.fIgnoreTexCoords = false; mesh.fIgnoreColors = false; + mesh.fIgnoreBones = false; fFlags = 0; if (mesh.hasPerVertexColors()) { fFlags |= kRequiresPerVertexColors_Flag; } if (mesh.hasExplicitLocalCoords()) { - fFlags |= kAnyMeshHasExplicitLocalCoords; + 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; @@ -62,7 +79,27 @@ GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor c } else { zeroArea = IsZeroArea::kNo; } - this->setTransformedBounds(mesh.fVertices->bounds(), viewMatrix, 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 { @@ -96,13 +133,14 @@ GrDrawOp::RequiresDstTexture GrDrawVerticesOp::finalize(const GrCaps& caps, } if (!fHelper.usesLocalCoords()) { fMeshes[0].fIgnoreTexCoords = true; - fFlags &= ~kAnyMeshHasExplicitLocalCoords; + fFlags &= ~kAnyMeshHasExplicitLocalCoords_Flag; } return result; } sk_sp<GrGeometryProcessor> GrDrawVerticesOp::makeGP(bool* hasColorAttribute, - bool* hasLocalCoordAttribute) const { + bool* hasLocalCoordAttribute, + bool* hasBoneAttribute) const { using namespace GrDefaultGeoProcFactory; LocalCoords::Type localCoordsType; if (fHelper.usesLocalCoords()) { @@ -132,26 +170,53 @@ sk_sp<GrGeometryProcessor> GrDrawVerticesOp::makeGP(bool* hasColorAttribute, } else { *hasColorAttribute = false; }; + 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()); + *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) { + if (fMeshes[0].fVertices->isVolatile()) { + this->drawVolatile(target); + } else { + this->drawNonVolatile(target); + } +} + +void GrDrawVerticesOp::drawVolatile(Target* target) { bool hasColorAttribute; bool hasLocalCoordsAttribute; - sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute, &hasLocalCoordsAttribute); - - size_t vertexStride = sizeof(SkPoint) + (hasColorAttribute ? sizeof(uint32_t) : 0) + - (hasLocalCoordsAttribute ? sizeof(SkPoint) : 0); + bool hasBoneAttribute; + sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute, + &hasLocalCoordsAttribute, + &hasBoneAttribute); + + // Calculate the stride. + size_t vertexStride = sizeof(SkPoint) + + (hasColorAttribute ? sizeof(uint32_t) : 0) + + (hasLocalCoordsAttribute ? sizeof(SkPoint) : 0) + + (hasBoneAttribute ? 4 * (sizeof(uint32_t) + sizeof(float)) : 0); SkASSERT(vertexStride == gp->debugOnly_vertexStride()); - int instanceCount = fMeshes.count(); - - const GrBuffer* vertexBuffer; - int firstVertex; - + // Allocate buffers. + const GrBuffer* vertexBuffer = nullptr; + int firstVertex = 0; void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex); - if (!verts) { SkDebugf("Could not allocate vertices\n"); return; @@ -159,37 +224,157 @@ void GrDrawVerticesOp::onPrepareDraws(Target* target) { const GrBuffer* indexBuffer = nullptr; int firstIndex = 0; - uint16_t* indices = nullptr; if (this->isIndexed()) { indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex); + if (!indices) { + SkDebugf("Could not allocate indices\n"); + return; + } + } + + // Fill the buffers. + this->fillBuffers(hasColorAttribute, + hasLocalCoordsAttribute, + hasBoneAttribute, + vertexStride, + verts, + indices); + + // Draw the vertices. + this->drawVertices(target, gp.get(), vertexBuffer, firstVertex, indexBuffer, firstIndex); +} + +void GrDrawVerticesOp::drawNonVolatile(Target* target) { + static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); + + bool hasColorAttribute; + bool hasLocalCoordsAttribute; + bool hasBoneAttribute; + sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute, + &hasLocalCoordsAttribute, + &hasBoneAttribute); + + int instanceCount = fMeshes.count(); + SkASSERT(instanceCount == 1); // Non-volatile meshes should never combine. + + // Get the resource provider. + GrResourceProvider* rp = target->resourceProvider(); + // Generate keys for the buffers. + GrUniqueKey vertexKey, indexKey; + GrUniqueKey::Builder vertexKeyBuilder(&vertexKey, kDomain, instanceCount + 1); + GrUniqueKey::Builder indexKeyBuilder(&indexKey, kDomain, instanceCount + 1); + for (int i = 0; i < instanceCount; i ++) { + vertexKeyBuilder[i] = indexKeyBuilder[i] = fMeshes[i].fVertices->uniqueID(); + } + vertexKeyBuilder[instanceCount] = 0; + indexKeyBuilder[instanceCount] = 1; + vertexKeyBuilder.finish(); + indexKeyBuilder.finish(); + + // Try to grab data from the cache. + sk_sp<GrBuffer> vertexBuffer = rp->findByUniqueKey<GrBuffer>(vertexKey); + sk_sp<GrBuffer> indexBuffer = rp->findByUniqueKey<GrBuffer>(indexKey); + + // Draw using the cached buffers if possible. + if (vertexBuffer) { + this->drawVertices(target, gp.get(), vertexBuffer.get(), 0, indexBuffer.get(), 0); + return; + } + + // Calculate the stride. + size_t vertexStride = sizeof(SkPoint) + + (hasColorAttribute ? sizeof(uint32_t) : 0) + + (hasLocalCoordsAttribute ? sizeof(SkPoint) : 0) + + (hasBoneAttribute ? 4 * (sizeof(uint32_t) + sizeof(float)) : 0); + SkASSERT(vertexStride == gp->debugOnly_vertexStride()); + + // Allocate vertex buffer. + vertexBuffer.reset(rp->createBuffer(fVertexCount * vertexStride, + kVertex_GrBufferType, + kStatic_GrAccessPattern, + 0)); + void* verts = vertexBuffer ? vertexBuffer->map() : nullptr; + if (!verts) { + SkDebugf("Could not allocate vertices\n"); + return; + } + + // Allocate index buffer. + uint16_t* indices = nullptr; + if (this->isIndexed()) { + indexBuffer.reset(rp->createBuffer(fIndexCount * sizeof(uint16_t), + kIndex_GrBufferType, + kStatic_GrAccessPattern, + 0)); + indices = indexBuffer ? static_cast<uint16_t*>(indexBuffer->map()) : nullptr; if (!indices) { SkDebugf("Could not allocate indices\n"); return; } } + // Fill the buffers. + this->fillBuffers(hasColorAttribute, + hasLocalCoordsAttribute, + hasBoneAttribute, + vertexStride, + verts, + indices); + + // Unmap the buffers. + vertexBuffer->unmap(); + if (indexBuffer) { + indexBuffer->unmap(); + } + + // Cache the buffers. + rp->assignUniqueKeyToResource(vertexKey, vertexBuffer.get()); + rp->assignUniqueKeyToResource(indexKey, indexBuffer.get()); + + // Draw the vertices. + this->drawVertices(target, gp.get(), vertexBuffer.get(), 0, indexBuffer.get(), 0); +} + +void GrDrawVerticesOp::fillBuffers(bool hasColorAttribute, + bool hasLocalCoordsAttribute, + bool hasBoneAttribute, + size_t vertexStride, + void* verts, + uint16_t* indices) const { + int instanceCount = fMeshes.count(); + + // Copy data into the buffers. int vertexOffset = 0; // 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. - bool fastAttrs = hasColorAttribute && !hasLocalCoordsAttribute; + // only and there are colors but not local coords. Fast case does not apply when there are bone + // transformations. + bool fastAttrs = hasColorAttribute && !hasLocalCoordsAttribute && !hasBoneAttribute; for (int i = 0; i < instanceCount; i++) { + // Get each mesh. const Mesh& mesh = fMeshes[i]; + + // Copy data into the index buffer. if (indices) { int indexCount = mesh.fVertices->indexCount(); for (int j = 0; j < indexCount; ++j) { *indices++ = mesh.fVertices->indices()[j] + vertexOffset; } } + + // Copy data into the vertex buffer. int vertexCount = mesh.fVertices->vertexCount(); 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(); if (fastAttrs && fastMesh) { + // Fast case. struct V { SkPoint fPos; uint32_t fColor; @@ -207,9 +392,19 @@ void GrDrawVerticesOp::onPrepareDraws(Target* target) { } verts = v + vertexCount; } else { + // Normal case. static constexpr size_t kColorOffset = sizeof(SkPoint); - size_t localCoordOffset = - hasColorAttribute ? kColorOffset + sizeof(uint32_t) : kColorOffset; + size_t offset = kColorOffset; + if (hasColorAttribute) { + offset += sizeof(uint32_t); + } + size_t localCoordOffset = offset; + if (hasLocalCoordsAttribute) { + offset += sizeof(SkPoint); + } + size_t boneIndexOffset = offset; + offset += 4 * sizeof(uint32_t); + size_t boneWeightOffset = offset; for (int j = 0; j < vertexCount; ++j) { if (this->hasMultipleViewMatrices()) { @@ -231,22 +426,40 @@ void GrDrawVerticesOp::onPrepareDraws(Target* target) { *(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); } } vertexOffset += vertexCount; } +} +void GrDrawVerticesOp::drawVertices(Target* target, + GrGeometryProcessor* gp, + const GrBuffer* vertexBuffer, + int firstVertex, + const GrBuffer* indexBuffer, + int firstIndex) { GrMesh mesh(this->primitiveType()); - if (!indices) { - mesh.setNonIndexedNonInstanced(fVertexCount); - } else { - mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertexCount - 1, + if (this->isIndexed()) { + mesh.setIndexed(indexBuffer, fIndexCount, + firstIndex, 0, fVertexCount - 1, GrPrimitiveRestart::kNo); + } else { + mesh.setNonIndexedNonInstanced(fVertexCount); } mesh.setVertexData(vertexBuffer, firstVertex); auto pipe = fHelper.makePipeline(target); - target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh); + target->draw(gp, pipe.fPipeline, pipe.fFixedDynamicState, mesh); } bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { @@ -256,6 +469,20 @@ 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. + if (!this->fMeshes[0].fVertices->isVolatile() || !that->fMeshes[0].fVertices->isVolatile()) { + return false; + } + if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) { return false; } @@ -410,8 +637,8 @@ 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), viewMatrix, - aaType, std::move(colorSpaceXform), &type); + return GrDrawVerticesOp::Make(context, std::move(paint), std::move(vertices), nullptr, 0, + viewMatrix, aaType, std::move(colorSpaceXform), &type); } #endif diff --git a/src/gpu/ops/GrDrawVerticesOp.h b/src/gpu/ops/GrDrawVerticesOp.h index 6d35c0d0e9..2e10fefe94 100644 --- a/src/gpu/ops/GrDrawVerticesOp.h +++ b/src/gpu/ops/GrDrawVerticesOp.h @@ -38,13 +38,15 @@ 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& helperArgs, GrColor, sk_sp<SkVertices>, - GrPrimitiveType, GrAAType, sk_sp<GrColorSpaceXform>, + 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"; } @@ -68,7 +70,26 @@ private: void onPrepareDraws(Target*) override; - sk_sp<GrGeometryProcessor> makeGP(bool* hasColorAttribute, bool* hasLocalCoordAttribute) const; + void drawVolatile(Target*); + void drawNonVolatile(Target*); + + void fillBuffers(bool hasColorAttribute, + bool hasLocalCoordsAttribute, + bool hasBoneAttribute, + size_t vertexStride, + void* verts, + uint16_t* indices) const; + + void drawVertices(Target*, + GrGeometryProcessor*, + const GrBuffer* vertexBuffer, + int firstVertex, + const GrBuffer* indexBuffer, + int firstIndex); + + sk_sp<GrGeometryProcessor> makeGP(bool* hasColorAttribute, + bool* hasLocalCoordAttribute, + bool* hasBoneAttribute) const; GrPrimitiveType primitiveType() const { return fPrimitiveType; } bool combinablePrimitive() const { @@ -82,9 +103,11 @@ private: struct Mesh { GrColor fColor; // Used if this->hasPerVertexColors() is false. sk_sp<SkVertices> fVertices; + std::vector<SkMatrix> fBones; SkMatrix fViewMatrix; bool fIgnoreTexCoords; bool fIgnoreColors; + bool fIgnoreBones; bool hasExplicitLocalCoords() const { return fVertices->hasTexCoords() && !fIgnoreTexCoords; @@ -93,6 +116,10 @@ private: bool hasPerVertexColors() const { return fVertices->hasColors() && !fIgnoreColors; } + + bool hasBones() const { + return fVertices->hasBones() && fBones.size() && !fIgnoreBones; + } }; bool isIndexed() const { @@ -105,18 +132,22 @@ private: } bool anyMeshHasExplicitLocalCoords() const { - return SkToBool(kAnyMeshHasExplicitLocalCoords & fFlags); + return SkToBool(kAnyMeshHasExplicitLocalCoords_Flag & fFlags); } bool hasMultipleViewMatrices() const { return SkToBool(kHasMultipleViewMatrices_Flag & fFlags); } - enum Flags { - kRequiresPerVertexColors_Flag = 0x1, - kAnyMeshHasExplicitLocalCoords = 0x2, - kHasMultipleViewMatrices_Flag = 0x4 + bool hasBones() const { + return SkToBool(kHasBones_Flag & fFlags); + } + enum Flags { + kRequiresPerVertexColors_Flag = 0x1, + kAnyMeshHasExplicitLocalCoords_Flag = 0x2, + kHasMultipleViewMatrices_Flag = 0x4, + kHasBones_Flag = 0x8, }; Helper fHelper; |