diff options
Diffstat (limited to 'src/gpu/ops/GrDrawPathOp.cpp')
-rw-r--r-- | src/gpu/ops/GrDrawPathOp.cpp | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/src/gpu/ops/GrDrawPathOp.cpp b/src/gpu/ops/GrDrawPathOp.cpp new file mode 100644 index 0000000000..43e1c38b88 --- /dev/null +++ b/src/gpu/ops/GrDrawPathOp.cpp @@ -0,0 +1,218 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrDrawPathOp.h" + +#include "GrRenderTargetPriv.h" + +static void pre_translate_transform_values(const float* xforms, + GrPathRendering::PathTransformType type, int count, + SkScalar x, SkScalar y, float* dst); + +void GrDrawPathOpBase::onPrepare(GrOpFlushState*) { + const GrRenderTargetPriv& rtPriv = this->pipeline()->getRenderTarget()->renderTargetPriv(); + fStencilPassSettings.reset(GrPathRendering::GetStencilPassSettings(fFillType), + this->pipeline()->hasStencilClip(), rtPriv.numStencilBits()); +} + +SkString GrDrawPathOp::dumpInfo() const { + SkString string; + string.printf("PATH: 0x%p", fPath.get()); + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; +} + +void GrDrawPathOp::onDraw(GrOpFlushState* state, const SkRect& bounds) { + GrProgramDesc desc; + + sk_sp<GrPathProcessor> pathProc( + GrPathProcessor::Create(this->color(), this->overrides(), this->viewMatrix())); + state->gpu()->pathRendering()->drawPath(*this->pipeline(), *pathProc, + this->stencilPassSettings(), fPath.get()); +} + +SkString GrDrawPathRangeOp::dumpInfo() const { + SkString string; + string.printf("RANGE: 0x%p COUNTS: [", fPathRange.get()); + for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) { + string.appendf("%d, ", iter.get()->fInstanceData->count()); + } + string.remove(string.size() - 2, 2); + string.append("]"); + string.append(DumpPipelineInfo(*this->pipeline())); + string.append(INHERITED::dumpInfo()); + return string; +} + +GrDrawPathRangeOp::GrDrawPathRangeOp(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x, + SkScalar y, GrColor color, GrPathRendering::FillType fill, + GrPathRange* range, const InstanceData* instanceData, + const SkRect& bounds) + : INHERITED(ClassID(), viewMatrix, color, fill) + , fPathRange(range) + , fTotalPathCount(instanceData->count()) + , fScale(scale) { + fDraws.addToHead()->set(instanceData, x, y); + this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); +} + +bool GrDrawPathRangeOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { + GrDrawPathRangeOp* that = t->cast<GrDrawPathRangeOp>(); + if (this->fPathRange.get() != that->fPathRange.get() || + this->transformType() != that->transformType() || this->fScale != that->fScale || + this->color() != that->color() || !this->viewMatrix().cheapEqualTo(that->viewMatrix())) { + return false; + } + if (!GrPipeline::AreEqual(*this->pipeline(), *that->pipeline())) { + return false; + } + switch (fDraws.head()->fInstanceData->transformType()) { + case GrPathRendering::kNone_PathTransformType: + if (this->fDraws.head()->fX != that->fDraws.head()->fX || + this->fDraws.head()->fY != that->fDraws.head()->fY) { + return false; + } + break; + case GrPathRendering::kTranslateX_PathTransformType: + if (this->fDraws.head()->fY != that->fDraws.head()->fY) { + return false; + } + break; + case GrPathRendering::kTranslateY_PathTransformType: + if (this->fDraws.head()->fX != that->fDraws.head()->fX) { + return false; + } + break; + default: + break; + } + // TODO: Check some other things here. (winding, opaque, pathProc color, vm, ...) + // Try to combine this call with the previous DrawPaths. We do this by stenciling all the + // paths together and then covering them in a single pass. This is not equivalent to two + // separate draw calls, so we can only do it if there is no blending (no overlap would also + // work). Note that it's also possible for overlapping paths to cancel each other's winding + // numbers, and we only partially account for this by not allowing even/odd paths to be + // combined. (Glyphs in the same font tend to wind the same direction so it works out OK.) + if (GrPathRendering::kWinding_FillType != this->fillType() || + GrPathRendering::kWinding_FillType != that->fillType() || + this->overrides().willColorBlendWithDst()) { + return false; + } + SkASSERT(!that->overrides().willColorBlendWithDst()); + fTotalPathCount += that->fTotalPathCount; + while (Draw* head = that->fDraws.head()) { + Draw* draw = fDraws.addToTail(); + draw->fInstanceData.reset(head->fInstanceData.release()); + draw->fX = head->fX; + draw->fY = head->fY; + that->fDraws.popHead(); + } + this->joinBounds(*that); + return true; +} + +void GrDrawPathRangeOp::onDraw(GrOpFlushState* state, const SkRect& bounds) { + const Draw& head = *fDraws.head(); + + SkMatrix drawMatrix(this->viewMatrix()); + drawMatrix.preScale(fScale, fScale); + drawMatrix.preTranslate(head.fX, head.fY); + + SkMatrix localMatrix; + localMatrix.setScale(fScale, fScale); + localMatrix.preTranslate(head.fX, head.fY); + + sk_sp<GrPathProcessor> pathProc( + GrPathProcessor::Create(this->color(), this->overrides(), drawMatrix, localMatrix)); + + if (fDraws.count() == 1) { + const InstanceData& instances = *head.fInstanceData; + state->gpu()->pathRendering()->drawPaths(*this->pipeline(), + *pathProc, + this->stencilPassSettings(), + fPathRange.get(), + instances.indices(), + GrPathRange::kU16_PathIndexType, + instances.transformValues(), + instances.transformType(), + instances.count()); + } else { + int floatsPerTransform = GrPathRendering::PathTransformSize(this->transformType()); + SkAutoSTMalloc<4096, float> transformStorage(floatsPerTransform * fTotalPathCount); + SkAutoSTMalloc<2048, uint16_t> indexStorage(fTotalPathCount); + int idx = 0; + for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) { + const Draw& draw = *iter.get(); + const InstanceData& instances = *draw.fInstanceData; + memcpy(&indexStorage[idx], instances.indices(), instances.count() * sizeof(uint16_t)); + pre_translate_transform_values(instances.transformValues(), this->transformType(), + instances.count(), draw.fX - head.fX, draw.fY - head.fY, + &transformStorage[floatsPerTransform * idx]); + idx += instances.count(); + + // TODO: Support mismatched transform types if we start using more types other than 2D. + SkASSERT(instances.transformType() == this->transformType()); + } + SkASSERT(idx == fTotalPathCount); + + state->gpu()->pathRendering()->drawPaths(*this->pipeline(), + *pathProc, + this->stencilPassSettings(), + fPathRange.get(), + indexStorage, + GrPathRange::kU16_PathIndexType, + transformStorage, + this->transformType(), + fTotalPathCount); + } +} + +inline void pre_translate_transform_values(const float* xforms, + GrPathRendering::PathTransformType type, int count, + SkScalar x, SkScalar y, float* dst) { + if (0 == x && 0 == y) { + memcpy(dst, xforms, count * GrPathRendering::PathTransformSize(type) * sizeof(float)); + return; + } + switch (type) { + case GrPathRendering::kNone_PathTransformType: + SkFAIL("Cannot pre-translate kNone_PathTransformType."); + break; + case GrPathRendering::kTranslateX_PathTransformType: + SkASSERT(0 == y); + for (int i = 0; i < count; i++) { + dst[i] = xforms[i] + x; + } + break; + case GrPathRendering::kTranslateY_PathTransformType: + SkASSERT(0 == x); + for (int i = 0; i < count; i++) { + dst[i] = xforms[i] + y; + } + break; + case GrPathRendering::kTranslate_PathTransformType: + for (int i = 0; i < 2 * count; i += 2) { + dst[i] = xforms[i] + x; + dst[i + 1] = xforms[i + 1] + y; + } + break; + case GrPathRendering::kAffine_PathTransformType: + for (int i = 0; i < 6 * count; i += 6) { + dst[i] = xforms[i]; + dst[i + 1] = xforms[i + 1]; + dst[i + 2] = xforms[i] * x + xforms[i + 1] * y + xforms[i + 2]; + dst[i + 3] = xforms[i + 3]; + dst[i + 4] = xforms[i + 4]; + dst[i + 5] = xforms[i + 3] * x + xforms[i + 4] * y + xforms[i + 5]; + } + break; + default: + SkFAIL("Unknown transform type."); + break; + } +} |