Consolidate stroke-rect ops and use GrFillRectOp instead of GrNonAA/AARectOp
Bug: skia:
Change-Id: Iee57bc970a026de2ad5a0758153e9cbb20753fa1
Reviewed-on: https://skia-review.googlesource.com/c/173105
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/ops/GrAAFillRectOp.cpp b/src/gpu/ops/GrAAFillRectOp.cpp
deleted file mode 100644
index 3aa05bb..0000000
--- a/src/gpu/ops/GrAAFillRectOp.cpp
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * 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 "GrColor.h"
-#include "GrDefaultGeoProcFactory.h"
-#include "GrMeshDrawOp.h"
-#include "GrOpFlushState.h"
-#include "GrRectOpFactory.h"
-#include "GrResourceKey.h"
-#include "GrResourceProvider.h"
-#include "GrTypes.h"
-#include "SkMatrix.h"
-#include "SkMatrixPriv.h"
-#include "SkRect.h"
-#include "SkPointPriv.h"
-#include "ops/GrSimpleMeshDrawOpHelper.h"
-#include <new>
-
-GR_DECLARE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
-
-static inline bool view_matrix_ok_for_aa_fill_rect(const SkMatrix& viewMatrix) {
- return viewMatrix.preservesRightAngles();
-}
-
-static inline void set_inset_fan(SkPoint* pts, size_t stride, const SkRect& r, SkScalar dx,
- SkScalar dy) {
- SkPointPriv::SetRectFan(pts, r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
-}
-
-static const int kNumAAFillRectsInIndexBuffer = 256;
-static const int kVertsPerAAFillRect = 8;
-static const int kIndicesPerAAFillRect = 30;
-
-static sk_sp<const GrBuffer> get_index_buffer(GrResourceProvider* resourceProvider) {
- GR_DEFINE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
-
- // clang-format off
- static const uint16_t gFillAARectIdx[] = {
- 0, 1, 5, 5, 4, 0,
- 1, 2, 6, 6, 5, 1,
- 2, 3, 7, 7, 6, 2,
- 3, 0, 4, 4, 7, 3,
- 4, 5, 6, 6, 7, 4,
- };
- // clang-format on
-
- GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFillAARectIdx) == kIndicesPerAAFillRect);
- return resourceProvider->findOrCreatePatternedIndexBuffer(
- gFillAARectIdx, kIndicesPerAAFillRect, kNumAAFillRectsInIndexBuffer,
- kVertsPerAAFillRect, gAAFillRectIndexBufferKey);
-}
-
-static void generate_aa_fill_rect_geometry(intptr_t verts,
- size_t vertexStride,
- GrColor color,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkRect& devRect,
- bool tweakAlphaForCoverage,
- const SkMatrix* localMatrix) {
- SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
- SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
-
- SkScalar inset;
-
- if (viewMatrix.rectStaysRect()) {
- inset = SkMinScalar(devRect.width(), SK_Scalar1);
- inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
-
- set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
- set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
- } else {
- // compute transformed (1, 0) and (0, 1) vectors
- SkVector vec[2] = {{viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY]},
- {viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY]}};
-
- SkScalar len1 = SkPoint::Normalize(&vec[0]);
- vec[0].scale(SK_ScalarHalf);
- SkScalar len2 = SkPoint::Normalize(&vec[1]);
- vec[1].scale(SK_ScalarHalf);
-
- inset = SkMinScalar(len1 * rect.width(), SK_Scalar1);
- inset = SK_ScalarHalf * SkMinScalar(inset, len2 * rect.height());
-
- // create the rotated rect
- SkPointPriv::SetRectFan(fan0Pos, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- vertexStride);
- SkMatrixPriv::MapPointsWithStride(viewMatrix, fan0Pos, vertexStride, 4);
-
- // Now create the inset points and then outset the original
- // rotated points
-
- // TL
- *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
- *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
- *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
- // BL
- *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
- *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
- *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
- // BR
- *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
- *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
- *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
- // TR
- *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
- *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
- *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
- }
-
- if (localMatrix) {
- SkMatrix invViewMatrix;
- if (!viewMatrix.invert(&invViewMatrix)) {
- SkDebugf("View matrix is non-invertible, local coords will be wrong.");
- invViewMatrix = SkMatrix::I();
- }
- SkMatrix localCoordMatrix;
- localCoordMatrix.setConcat(*localMatrix, invViewMatrix);
- SkPoint* fan0Loc = reinterpret_cast<SkPoint*>(verts + sizeof(SkPoint) + sizeof(GrColor));
- SkMatrixPriv::MapPointsWithStride(localCoordMatrix, fan0Loc, vertexStride, fan0Pos,
- vertexStride, 8);
- }
-
- // Make verts point to vertex color and then set all the color and coverage vertex attrs
- // values.
- verts += sizeof(SkPoint);
-
- // The coverage offset is always the last vertex attribute
- intptr_t coverageOffset = vertexStride - sizeof(GrColor) - sizeof(SkPoint);
- for (int i = 0; i < 4; ++i) {
- if (tweakAlphaForCoverage) {
- *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
- } else {
- *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
- *reinterpret_cast<float*>(verts + i * vertexStride + coverageOffset) = 0;
- }
- }
-
- int scale;
- if (inset < SK_ScalarHalf) {
- scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
- SkASSERT(scale >= 0 && scale <= 255);
- } else {
- scale = 0xff;
- }
-
- verts += 4 * vertexStride;
-
- float innerCoverage = GrNormalizeByteToFloat(scale);
- GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
-
- for (int i = 0; i < 4; ++i) {
- if (tweakAlphaForCoverage) {
- *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
- } else {
- *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
- *reinterpret_cast<float*>(verts + i * vertexStride + coverageOffset) = innerCoverage;
- }
- }
-}
-
-namespace {
-
-class AAFillRectOp final : public GrMeshDrawOp {
-private:
- using Helper = GrSimpleMeshDrawOpHelperWithStencil;
-
-public:
- DEFINE_OP_CLASS_ID
-
- static std::unique_ptr<GrDrawOp> Make(GrContext* context,
- GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkRect& devRect,
- const SkMatrix* localMatrix,
- const GrUserStencilSettings* stencil) {
- SkASSERT(view_matrix_ok_for_aa_fill_rect(viewMatrix));
- return Helper::FactoryHelper<AAFillRectOp>(context, std::move(paint), viewMatrix, rect,
- devRect, localMatrix, stencil);
- }
-
- AAFillRectOp(const Helper::MakeArgs& helperArgs,
- const SkPMColor4f& color,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkRect& devRect,
- const SkMatrix* localMatrix,
- const GrUserStencilSettings* stencil)
- : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage, stencil) {
- if (localMatrix) {
- void* mem = fRectData.push_back_n(sizeof(RectWithLocalMatrixInfo));
- new (mem) RectWithLocalMatrixInfo(color, viewMatrix, rect, devRect, *localMatrix);
- } else {
- void* mem = fRectData.push_back_n(sizeof(RectInfo));
- new (mem) RectInfo(color, viewMatrix, rect, devRect);
- }
- IsZeroArea zeroArea =
- (!rect.width() || !rect.height()) ? IsZeroArea::kYes : IsZeroArea::kNo;
- this->setBounds(devRect, HasAABloat::kYes, zeroArea);
- fRectCnt = 1;
- }
-
- const char* name() const override { return "AAFillRectOp"; }
-
- void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
- fHelper.visitProxies(func);
- }
-
-#ifdef SK_DEBUG
- SkString dumpInfo() const override {
- SkString str;
- str.append(INHERITED::dumpInfo());
- str.appendf("# combined: %d\n", fRectCnt);
- const RectInfo* info = this->first();
- for (int i = 0; i < fRectCnt; ++i) {
- const SkRect& rect = info->rect();
- str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
- info->color().toBytes_RGBA(), rect.fLeft, rect.fTop, rect.fRight,
- rect.fBottom);
- info = this->next(info);
- }
- str += fHelper.dumpInfo();
- str += INHERITED::dumpInfo();
- return str;
- }
-#endif
-
- FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
-
- RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
- SkPMColor4f color = this->first()->color();
- auto result = fHelper.xpRequiresDstTexture(
- caps, clip, GrProcessorAnalysisCoverage::kSingleChannel, &color);
- this->first()->setColor(color);
- return result;
- }
-
-private:
- void onPrepareDraws(Target* target) override {
- using namespace GrDefaultGeoProcFactory;
-
- Color color(Color::kPremulGrColorAttribute_Type);
- Coverage::Type coverageType = Coverage::kSolid_Type;
- if (!fHelper.compatibleWithAlphaAsCoverage()) {
- coverageType = Coverage::kAttribute_Type;
- }
- LocalCoords lc = LocalCoords::kUnused_Type;
- if (fHelper.usesLocalCoords()) {
- lc = LocalCoords::kHasExplicit_Type;
- }
-
- sk_sp<GrGeometryProcessor> gp =
- GrDefaultGeoProcFactory::Make(target->caps().shaderCaps(), color, coverageType,
- lc, SkMatrix::I());
- if (!gp) {
- SkDebugf("Couldn't create GrGeometryProcessor\n");
- return;
- }
-
- size_t vertexStride = gp->vertexStride();
-
- sk_sp<const GrBuffer> indexBuffer = get_index_buffer(target->resourceProvider());
- PatternHelper helper(target, GrPrimitiveType::kTriangles, vertexStride, indexBuffer.get(),
- kVertsPerAAFillRect, kIndicesPerAAFillRect, fRectCnt);
- void* vertices = helper.vertices();
- if (!vertices || !indexBuffer) {
- SkDebugf("Could not allocate vertices\n");
- return;
- }
-
- const RectInfo* info = this->first();
- const SkMatrix* localMatrix = nullptr;
- for (int i = 0; i < fRectCnt; i++) {
- intptr_t verts =
- reinterpret_cast<intptr_t>(vertices) + i * kVertsPerAAFillRect * vertexStride;
- if (fHelper.usesLocalCoords()) {
- if (info->hasLocalMatrix()) {
- localMatrix = &static_cast<const RectWithLocalMatrixInfo*>(info)->localMatrix();
- } else {
- localMatrix = &SkMatrix::I();
- }
- }
- // TODO4F: Preserve float colors
- generate_aa_fill_rect_geometry(verts, vertexStride, info->color().toBytes_RGBA(),
- info->viewMatrix(), info->rect(), info->devRect(),
- fHelper.compatibleWithAlphaAsCoverage(), localMatrix);
- info = this->next(info);
- }
- auto pipe = fHelper.makePipeline(target);
- helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
- }
-
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
- AAFillRectOp* that = t->cast<AAFillRectOp>();
- if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
- }
-
- fRectData.push_back_n(that->fRectData.count(), that->fRectData.begin());
- fRectCnt += that->fRectCnt;
- return CombineResult::kMerged;
- }
-
- struct RectInfo {
- public:
- RectInfo(const SkPMColor4f& color, const SkMatrix& viewMatrix, const SkRect& rect,
- const SkRect& devRect)
- : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kNo) {}
- bool hasLocalMatrix() const { return HasLocalMatrix::kYes == fHasLocalMatrix; }
- const SkPMColor4f& color() const { return fColor; }
- const SkMatrix& viewMatrix() const { return fViewMatrix; }
- const SkRect& rect() const { return fRect; }
- const SkRect& devRect() const { return fDevRect; }
-
- void setColor(const SkPMColor4f& color) { fColor = color; }
-
- protected:
- enum class HasLocalMatrix : uint32_t { kNo, kYes };
-
- RectInfo(const SkPMColor4f& color, const SkMatrix& viewMatrix, const SkRect& rect,
- const SkRect& devRect, HasLocalMatrix hasLM)
- : fHasLocalMatrix(hasLM)
- , fColor(color)
- , fViewMatrix(viewMatrix)
- , fRect(rect)
- , fDevRect(devRect) {}
-
- HasLocalMatrix fHasLocalMatrix;
- SkPMColor4f fColor;
- SkMatrix fViewMatrix;
- SkRect fRect;
- SkRect fDevRect;
- };
-
- struct RectWithLocalMatrixInfo : public RectInfo {
- public:
- RectWithLocalMatrixInfo(const SkPMColor4f& color, const SkMatrix& viewMatrix,
- const SkRect& rect, const SkRect& devRect,
- const SkMatrix& localMatrix)
- : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kYes)
- , fLocalMatrix(localMatrix) {}
- const SkMatrix& localMatrix() const { return fLocalMatrix; }
-
- private:
- SkMatrix fLocalMatrix;
- };
-
- RectInfo* first() { return reinterpret_cast<RectInfo*>(fRectData.begin()); }
- const RectInfo* first() const { return reinterpret_cast<const RectInfo*>(fRectData.begin()); }
- const RectInfo* next(const RectInfo* prev) const {
- intptr_t next =
- reinterpret_cast<intptr_t>(prev) +
- (prev->hasLocalMatrix() ? sizeof(RectWithLocalMatrixInfo) : sizeof(RectInfo));
- return reinterpret_cast<const RectInfo*>(next);
- }
-
- SkSTArray<4 * sizeof(RectWithLocalMatrixInfo), uint8_t, true> fRectData;
- Helper fHelper;
- int fRectCnt;
-
- typedef GrMeshDrawOp INHERITED;
-};
-
-} // anonymous namespace
-
-namespace GrRectOpFactory {
-
-std::unique_ptr<GrDrawOp> MakeAAFill(GrContext* context,
- GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const GrUserStencilSettings* stencil) {
- if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
- return nullptr;
- }
- SkRect devRect;
- viewMatrix.mapRect(&devRect, rect);
- return AAFillRectOp::Make(context, std::move(paint), viewMatrix, rect, devRect,
- nullptr, stencil);
-}
-
-std::unique_ptr<GrDrawOp> MakeAAFillWithLocalMatrix(GrContext* context,
- GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkMatrix& localMatrix,
- const SkRect& rect) {
- if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
- return nullptr;
- }
- SkRect devRect;
- viewMatrix.mapRect(&devRect, rect);
- return AAFillRectOp::Make(context, std::move(paint), viewMatrix, rect, devRect,
- &localMatrix, nullptr);
-}
-
-std::unique_ptr<GrDrawOp> MakeAAFillWithLocalRect(GrContext* context,
- GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkRect& localRect) {
- if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
- return nullptr;
- }
- SkRect devRect;
- viewMatrix.mapRect(&devRect, rect);
- SkMatrix localMatrix;
- if (!localMatrix.setRectToRect(rect, localRect, SkMatrix::kFill_ScaleToFit)) {
- return nullptr;
- }
- return AAFillRectOp::Make(context, std::move(paint), viewMatrix, rect, devRect,
- &localMatrix, nullptr);
-}
-
-} // namespace GrRectOpFactory
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-#if GR_TEST_UTILS
-
-#include "GrDrawOpTest.h"
-
-GR_DRAW_OP_TEST_DEFINE(AAFillRectOp) {
- SkMatrix viewMatrix;
- do {
- viewMatrix = GrTest::TestMatrixInvertible(random);
- } while (!view_matrix_ok_for_aa_fill_rect(viewMatrix));
- SkRect rect = GrTest::TestRect(random);
- SkRect devRect;
- viewMatrix.mapRect(&devRect, rect);
- const SkMatrix* localMatrix = nullptr;
- SkMatrix m;
- if (random->nextBool()) {
- m = GrTest::TestMatrix(random);
- }
- const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
- : GrGetRandomStencil(random, context);
- return AAFillRectOp::Make(context, std::move(paint), viewMatrix, rect,
- devRect, localMatrix, stencil);
-}
-
-#endif
diff --git a/src/gpu/ops/GrDefaultPathRenderer.cpp b/src/gpu/ops/GrDefaultPathRenderer.cpp
index a30fe3b..1cb2d14 100644
--- a/src/gpu/ops/GrDefaultPathRenderer.cpp
+++ b/src/gpu/ops/GrDefaultPathRenderer.cpp
@@ -9,6 +9,7 @@
#include "GrContext.h"
#include "GrDefaultGeoProcFactory.h"
#include "GrDrawOpTest.h"
+#include "GrFillRectOp.h"
#include "GrFixedClip.h"
#include "GrMesh.h"
#include "GrOpFlushState.h"
@@ -23,7 +24,6 @@
#include "SkTLazy.h"
#include "SkTraceEvent.h"
#include "ops/GrMeshDrawOp.h"
-#include "ops/GrRectOpFactory.h"
GrDefaultPathRenderer::GrDefaultPathRenderer() {
}
@@ -611,11 +611,11 @@
}
const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
viewMatrix;
+ // This is a non-coverage aa rect op since we assert aaType != kCoverage at the start
renderTargetContext->addDrawOp(
clip,
- GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
- context, std::move(paint), viewM, localMatrix,
- bounds, aaType, passes[p]));
+ GrFillRectOp::MakeWithLocalMatrix(context, std::move(paint), aaType, viewM,
+ localMatrix, bounds, passes[p]));
} else {
bool stencilPass = stencilOnly || passCount > 1;
std::unique_ptr<GrDrawOp> op;
diff --git a/src/gpu/ops/GrFillRectOp.cpp b/src/gpu/ops/GrFillRectOp.cpp
index 15baf8c..5e4d8933 100644
--- a/src/gpu/ops/GrFillRectOp.cpp
+++ b/src/gpu/ops/GrFillRectOp.cpp
@@ -174,8 +174,13 @@
break;
}
}
- auto result = fHelper.xpRequiresDstTexture(
- caps, clip, GrProcessorAnalysisCoverage::kSingleChannel, &quadColors);
+
+ // If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA
+ // then the coverage is always 1.0, so specify kNone for more optimal blending.
+ GrProcessorAnalysisCoverage coverage = fHelper.aaType() == GrAAType::kCoverage ?
+ GrProcessorAnalysisCoverage::kSingleChannel :
+ GrProcessorAnalysisCoverage::kNone;
+ auto result = fHelper.xpRequiresDstTexture(caps, clip, coverage, &quadColors);
// If there is a constant color after analysis, that means all of the quads should be set
// to the same color (even if they started out with different colors).
SkPMColor4f colorOverride;
@@ -352,40 +357,40 @@
namespace GrFillRectOp {
-std::unique_ptr<GrDrawOp> Make(GrContext* context,
- GrPaint&& paint,
- GrAAType aaType,
- GrQuadAAFlags edgeAA,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const GrUserStencilSettings* stencilSettings) {
+std::unique_ptr<GrDrawOp> MakePerEdge(GrContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ GrQuadAAFlags edgeAA,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const GrUserStencilSettings* stencilSettings) {
return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
GrPerspQuad(rect, SkMatrix::I()), GrQuadType::kRect);
}
-std::unique_ptr<GrDrawOp> MakeWithLocalMatrix(GrContext* context,
- GrPaint&& paint,
- GrAAType aaType,
- GrQuadAAFlags edgeAA,
- const SkMatrix& viewMatrix,
- const SkMatrix& localMatrix,
- const SkRect& rect,
- const GrUserStencilSettings* stencilSettings) {
+std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalMatrix(GrContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ GrQuadAAFlags edgeAA,
+ const SkMatrix& viewMatrix,
+ const SkMatrix& localMatrix,
+ const SkRect& rect,
+ const GrUserStencilSettings* stencilSettings) {
GrQuadType localQuadType = GrQuadTypeForTransformedRect(localMatrix);
return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
GrPerspQuad(rect, localMatrix), localQuadType);
}
-std::unique_ptr<GrDrawOp> MakeWithLocalRect(GrContext* context,
- GrPaint&& paint,
- GrAAType aaType,
- GrQuadAAFlags edgeAA,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkRect& localRect,
- const GrUserStencilSettings* stencilSettings) {
+std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalRect(GrContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ GrQuadAAFlags edgeAA,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkRect& localRect,
+ const GrUserStencilSettings* stencilSettings) {
return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
GrPerspQuad(localRect, SkMatrix::I()), GrQuadType::kRect);
@@ -426,6 +431,41 @@
return op;
}
+std::unique_ptr<GrDrawOp> Make(GrContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const GrUserStencilSettings* stencil) {
+ return MakePerEdge(context, std::move(paint), aaType,
+ aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
+ viewMatrix, rect, stencil);
+}
+
+std::unique_ptr<GrDrawOp> MakeWithLocalMatrix(GrContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ const SkMatrix& viewMatrix,
+ const SkMatrix& localMatrix,
+ const SkRect& rect,
+ const GrUserStencilSettings* stencil) {
+ return MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
+ aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
+ viewMatrix, localMatrix, rect, stencil);
+}
+
+std::unique_ptr<GrDrawOp> MakeWithLocalRect(GrContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkRect& localRect,
+ const GrUserStencilSettings* stencil) {
+ return MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
+ aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
+ viewMatrix, rect, localRect, stencil);
+}
+
} // namespace GrFillRectOp
#if GR_TEST_UTILS
@@ -477,19 +517,21 @@
} else {
// Single local matrix
SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
- return GrFillRectOp::MakeWithLocalMatrix(context, std::move(paint), aaType, aaFlags,
- viewMatrix, localMatrix, rect, stencil);
+ return GrFillRectOp::MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
+ aaFlags, viewMatrix, localMatrix,
+ rect, stencil);
}
} else {
// Pass local rect directly
SkRect localRect = GrTest::TestRect(random);
- return GrFillRectOp::MakeWithLocalRect(context, std::move(paint), aaType, aaFlags,
- viewMatrix, rect, localRect, stencil);
+ return GrFillRectOp::MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
+ aaFlags, viewMatrix, rect, localRect,
+ stencil);
}
} else {
// The simplest constructor
- return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags, viewMatrix, rect,
- stencil);
+ return GrFillRectOp::MakePerEdge(context, std::move(paint), aaType, aaFlags, viewMatrix,
+ rect, stencil);
}
}
diff --git a/src/gpu/ops/GrFillRectOp.h b/src/gpu/ops/GrFillRectOp.h
index 8d287bb..175c9f3 100644
--- a/src/gpu/ops/GrFillRectOp.h
+++ b/src/gpu/ops/GrFillRectOp.h
@@ -17,12 +17,55 @@
class SkMatrix;
struct SkRect;
+/**
+ * A set of factory functions for drawing filled rectangles either coverage-antialiased, or
+ * non-antialiased. The non-antialiased ops can be used with MSAA. As with other GrDrawOp factories,
+ * the GrPaint is only consumed by these methods if a valid op is returned. If null is returned then
+ * the paint is unmodified and may still be used.
+ */
namespace GrFillRectOp {
+// General purpose factory functions that handle per-edge anti-aliasing
+std::unique_ptr<GrDrawOp> MakePerEdge(GrContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ GrQuadAAFlags edgeAA,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const GrUserStencilSettings* stencil = nullptr);
+
+std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalMatrix(GrContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ GrQuadAAFlags edgeAA,
+ const SkMatrix& viewMatrix,
+ const SkMatrix& localMatrix,
+ const SkRect& rect,
+ const GrUserStencilSettings* stl = nullptr);
+
+std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalRect(GrContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ GrQuadAAFlags edgeAA,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkRect& localRect,
+ const GrUserStencilSettings* stencil = nullptr);
+
+// Bulk API for drawing quads with a single op
+std::unique_ptr<GrDrawOp> MakeSet(GrContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ const SkMatrix& viewMatrix,
+ const GrRenderTargetContext::QuadSetEntry quads[],
+ int quadCount,
+ const GrUserStencilSettings* stencil = nullptr);
+
+// Specializations where all edges are treated the same. If the aa type is coverage, then the
+// edges will be anti-aliased, otherwise per-edge AA will be disabled.
std::unique_ptr<GrDrawOp> Make(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
- GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkRect& rect,
const GrUserStencilSettings* stencil = nullptr);
@@ -30,7 +73,6 @@
std::unique_ptr<GrDrawOp> MakeWithLocalMatrix(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
- GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
const SkRect& rect,
@@ -39,19 +81,11 @@
std::unique_ptr<GrDrawOp> MakeWithLocalRect(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
- GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkRect& localRect,
const GrUserStencilSettings* stencil = nullptr);
-std::unique_ptr<GrDrawOp> MakeSet(GrContext* context,
- GrPaint&& paint,
- GrAAType aaType,
- const SkMatrix& viewMatrix,
- const GrRenderTargetContext::QuadSetEntry quads[],
- int quadCount,
- const GrUserStencilSettings* stencil = nullptr);
-}
+} // namespace GrFillRectOp
#endif // GrFillRectOp_DEFINED
diff --git a/src/gpu/ops/GrNonAAFillRectOp.cpp b/src/gpu/ops/GrNonAAFillRectOp.cpp
deleted file mode 100644
index ae0c9b7..0000000
--- a/src/gpu/ops/GrNonAAFillRectOp.cpp
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrAppliedClip.h"
-#include "GrColor.h"
-#include "GrDefaultGeoProcFactory.h"
-#include "GrDrawOpTest.h"
-#include "GrMeshDrawOp.h"
-#include "GrOpFlushState.h"
-#include "GrPrimitiveProcessor.h"
-#include "GrQuad.h"
-#include "GrRectOpFactory.h"
-#include "GrResourceProvider.h"
-#include "GrSimpleMeshDrawOpHelper.h"
-#include "SkMatrixPriv.h"
-
-static const int kVertsPerRect = 4;
-static const int kIndicesPerRect = 6;
-
-/** We always use per-vertex colors so that rects can be combined across color changes. Sometimes
- we have explicit local coords and sometimes not. We *could* always provide explicit local
- coords and just duplicate the positions when the caller hasn't provided a local coord rect,
- but we haven't seen a use case which frequently switches between local rect and no local
- rect draws.
-
- The vertex attrib order is always pos, color, [local coords].
- */
-static sk_sp<GrGeometryProcessor> make_gp(const GrShaderCaps* shaderCaps) {
- using namespace GrDefaultGeoProcFactory;
- return GrDefaultGeoProcFactory::Make(shaderCaps,
- Color::kPremulGrColorAttribute_Type,
- Coverage::kSolid_Type,
- LocalCoords::kHasExplicit_Type,
- SkMatrix::I());
-}
-
-static sk_sp<GrGeometryProcessor> make_perspective_gp(const GrShaderCaps* shaderCaps,
- const SkMatrix& viewMatrix,
- bool hasExplicitLocalCoords,
- const SkMatrix* localMatrix) {
- SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
-
- using namespace GrDefaultGeoProcFactory;
-
- // If we have perspective on the viewMatrix then we won't map on the CPU, nor will we map
- // the local rect on the cpu (in case the localMatrix also has perspective).
- // Otherwise, if we have a local rect, then we apply the localMatrix directly to the localRect
- // to generate vertex local coords
- if (viewMatrix.hasPerspective()) {
- LocalCoords localCoords(hasExplicitLocalCoords ? LocalCoords::kHasExplicit_Type
- : LocalCoords::kUsePosition_Type,
- localMatrix);
- return GrDefaultGeoProcFactory::Make(shaderCaps, Color::kPremulGrColorAttribute_Type,
- Coverage::kSolid_Type, localCoords, viewMatrix);
- } else if (hasExplicitLocalCoords) {
- LocalCoords localCoords(LocalCoords::kHasExplicit_Type, localMatrix);
- return GrDefaultGeoProcFactory::Make(shaderCaps, Color::kPremulGrColorAttribute_Type,
- Coverage::kSolid_Type, localCoords, SkMatrix::I());
- } else {
- LocalCoords localCoords(LocalCoords::kUsePosition_Type, localMatrix);
- return GrDefaultGeoProcFactory::MakeForDeviceSpace(shaderCaps,
- Color::kPremulGrColorAttribute_Type,
- Coverage::kSolid_Type, localCoords,
- viewMatrix);
- }
-}
-
-static void tesselate(intptr_t vertices,
- size_t vertexStride,
- GrColor color,
- const SkMatrix* viewMatrix,
- const SkRect& rect,
- const GrQuad* localQuad) {
- SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
-
- SkPointPriv::SetRectTriStrip(positions, rect, vertexStride);
-
- if (viewMatrix) {
- SkMatrixPriv::MapPointsWithStride(*viewMatrix, positions, vertexStride, kVertsPerRect);
- }
-
- // Setup local coords
- // TODO we should only do this if local coords are being read
- if (localQuad) {
- static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
- for (int i = 0; i < kVertsPerRect; i++) {
- SkPoint* coords =
- reinterpret_cast<SkPoint*>(vertices + kLocalOffset + i * vertexStride);
- *coords = localQuad->point(i);
- }
- }
-
- static const int kColorOffset = sizeof(SkPoint);
- GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset);
- for (int j = 0; j < 4; ++j) {
- *vertColor = color;
- vertColor = (GrColor*)((intptr_t)vertColor + vertexStride);
- }
-}
-
-namespace {
-
-class NonAAFillRectOp final : public GrMeshDrawOp {
-private:
- using Helper = GrSimpleMeshDrawOpHelperWithStencil;
-
-public:
- static std::unique_ptr<GrDrawOp> Make(GrContext* context,
- GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkRect* localRect,
- const SkMatrix* localMatrix,
- GrAAType aaType,
- const GrUserStencilSettings* stencilSettings) {
- SkASSERT(GrAAType::kCoverage != aaType);
- return Helper::FactoryHelper<NonAAFillRectOp>(context, std::move(paint), viewMatrix, rect,
- localRect, localMatrix, aaType,
- stencilSettings);
- }
-
- NonAAFillRectOp() = delete;
-
- NonAAFillRectOp(const Helper::MakeArgs& args, const SkPMColor4f& color,
- const SkMatrix& viewMatrix, const SkRect& rect, const SkRect* localRect,
- const SkMatrix* localMatrix, GrAAType aaType,
- const GrUserStencilSettings* stencilSettings)
- : INHERITED(ClassID()), fHelper(args, aaType, stencilSettings) {
-
- SkASSERT(!viewMatrix.hasPerspective() && (!localMatrix || !localMatrix->hasPerspective()));
- RectInfo& info = fRects.push_back();
- info.fColor = color;
- info.fViewMatrix = viewMatrix;
- info.fRect = rect;
- if (localRect && localMatrix) {
- info.fLocalQuad = GrQuad(*localRect, *localMatrix);
- } else if (localRect) {
- info.fLocalQuad = GrQuad(*localRect);
- } else if (localMatrix) {
- info.fLocalQuad = GrQuad(rect, *localMatrix);
- } else {
- info.fLocalQuad = GrQuad(rect);
- }
- this->setTransformedBounds(fRects[0].fRect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
- }
-
- const char* name() const override { return "NonAAFillRectOp"; }
-
- void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
- fHelper.visitProxies(func);
- }
-
-#ifdef SK_DEBUG
- SkString dumpInfo() const override {
- SkString str;
- str.append(GrMeshDrawOp::dumpInfo());
- str.appendf("# combined: %d\n", fRects.count());
- for (int i = 0; i < fRects.count(); ++i) {
- const RectInfo& info = fRects[i];
- str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
- info.fColor.toBytes_RGBA(), info.fRect.fLeft, info.fRect.fTop,
- info.fRect.fRight, info.fRect.fBottom);
- }
- str += fHelper.dumpInfo();
- str += INHERITED::dumpInfo();
- return str;
- }
-#endif
-
- RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
- SkPMColor4f* color = &fRects.front().fColor;
- return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
- }
-
- FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
-
- DEFINE_OP_CLASS_ID
-
-private:
- void onPrepareDraws(Target* target) override {
- sk_sp<GrGeometryProcessor> gp = make_gp(target->caps().shaderCaps());
- if (!gp) {
- SkDebugf("Couldn't create GrGeometryProcessor\n");
- return;
- }
-
- size_t kVertexStride = gp->vertexStride();
- int rectCount = fRects.count();
-
- sk_sp<const GrBuffer> indexBuffer = target->resourceProvider()->refQuadIndexBuffer();
- PatternHelper helper(target, GrPrimitiveType::kTriangles, kVertexStride, indexBuffer.get(),
- kVertsPerRect, kIndicesPerRect, rectCount);
- void* vertices = helper.vertices();
- if (!vertices || !indexBuffer) {
- SkDebugf("Could not allocate vertices\n");
- return;
- }
-
- for (int i = 0; i < rectCount; i++) {
- intptr_t verts =
- reinterpret_cast<intptr_t>(vertices) + i * kVertsPerRect * kVertexStride;
- // TODO4F: Preserve float colors
- tesselate(verts, kVertexStride, fRects[i].fColor.toBytes_RGBA(), &fRects[i].fViewMatrix,
- fRects[i].fRect, &fRects[i].fLocalQuad);
- }
- auto pipe = fHelper.makePipeline(target);
- helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
- }
-
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
- NonAAFillRectOp* that = t->cast<NonAAFillRectOp>();
- if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
- }
- fRects.push_back_n(that->fRects.count(), that->fRects.begin());
- return CombineResult::kMerged;
- }
-
- struct RectInfo {
- SkPMColor4f fColor;
- SkMatrix fViewMatrix;
- SkRect fRect;
- GrQuad fLocalQuad;
- };
-
- Helper fHelper;
- SkSTArray<1, RectInfo, true> fRects;
- typedef GrMeshDrawOp INHERITED;
-};
-
-// We handle perspective in the local matrix or viewmatrix with special ops.
-class NonAAFillRectPerspectiveOp final : public GrMeshDrawOp {
-private:
- using Helper = GrSimpleMeshDrawOpHelperWithStencil;
-
-public:
- static std::unique_ptr<GrDrawOp> Make(GrContext* context,
- GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkRect* localRect,
- const SkMatrix* localMatrix,
- GrAAType aaType,
- const GrUserStencilSettings* stencilSettings) {
- SkASSERT(GrAAType::kCoverage != aaType);
- return Helper::FactoryHelper<NonAAFillRectPerspectiveOp>(context, std::move(paint),
- viewMatrix, rect,
- localRect, localMatrix, aaType,
- stencilSettings);
- }
-
- NonAAFillRectPerspectiveOp() = delete;
-
- NonAAFillRectPerspectiveOp(const Helper::MakeArgs& args, const SkPMColor4f& color,
- const SkMatrix& viewMatrix, const SkRect& rect,
- const SkRect* localRect, const SkMatrix* localMatrix,
- GrAAType aaType, const GrUserStencilSettings* stencilSettings)
- : INHERITED(ClassID())
- , fHelper(args, aaType, stencilSettings)
- , fViewMatrix(viewMatrix) {
- SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
- RectInfo& info = fRects.push_back();
- info.fColor = color;
- info.fRect = rect;
- fHasLocalRect = SkToBool(localRect);
- fHasLocalMatrix = SkToBool(localMatrix);
- if (fHasLocalMatrix) {
- fLocalMatrix = *localMatrix;
- }
- if (fHasLocalRect) {
- info.fLocalRect = *localRect;
- }
- this->setTransformedBounds(rect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
- }
-
- const char* name() const override { return "NonAAFillRectPerspectiveOp"; }
-
- void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
- fHelper.visitProxies(func);
- }
-
-#ifdef SK_DEBUG
- SkString dumpInfo() const override {
- SkString str;
- str.appendf("# combined: %d\n", fRects.count());
- for (int i = 0; i < fRects.count(); ++i) {
- const RectInfo& geo = fRects[i];
- str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
- geo.fColor.toBytes_RGBA(), geo.fRect.fLeft, geo.fRect.fTop,
- geo.fRect.fRight, geo.fRect.fBottom);
- }
- str += fHelper.dumpInfo();
- str += INHERITED::dumpInfo();
- return str;
- }
-#endif
-
- RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
- SkPMColor4f* color = &fRects.front().fColor;
- return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
- }
-
- FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
-
- DEFINE_OP_CLASS_ID
-
-private:
- void onPrepareDraws(Target* target) override {
- sk_sp<GrGeometryProcessor> gp = make_perspective_gp(
- target->caps().shaderCaps(),
- fViewMatrix,
- fHasLocalRect,
- fHasLocalMatrix ? &fLocalMatrix : nullptr);
- if (!gp) {
- SkDebugf("Couldn't create GrGeometryProcessor\n");
- return;
- }
- size_t vertexStride = gp->vertexStride();
- int rectCount = fRects.count();
-
- sk_sp<const GrBuffer> indexBuffer = target->resourceProvider()->refQuadIndexBuffer();
- PatternHelper helper(target, GrPrimitiveType::kTriangles, vertexStride, indexBuffer.get(),
- kVertsPerRect, kIndicesPerRect, rectCount);
- void* vertices = helper.vertices();
- if (!vertices || !indexBuffer) {
- SkDebugf("Could not allocate vertices\n");
- return;
- }
-
- for (int i = 0; i < rectCount; i++) {
- const RectInfo& info = fRects[i];
- // TODO4F: Preserve float colors
- GrColor color = info.fColor.toBytes_RGBA();
- intptr_t verts =
- reinterpret_cast<intptr_t>(vertices) + i * kVertsPerRect * vertexStride;
- if (fHasLocalRect) {
- GrQuad quad(info.fLocalRect);
- tesselate(verts, vertexStride, color, nullptr, info.fRect, &quad);
- } else {
- tesselate(verts, vertexStride, color, nullptr, info.fRect, nullptr);
- }
- }
- auto pipe = fHelper.makePipeline(target);
- helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
- }
-
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
- NonAAFillRectPerspectiveOp* that = t->cast<NonAAFillRectPerspectiveOp>();
- if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
- }
-
- // We could combine across perspective vm changes if we really wanted to.
- if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
- return CombineResult::kCannotCombine;
- }
- if (fHasLocalRect != that->fHasLocalRect) {
- return CombineResult::kCannotCombine;
- }
- if (fHasLocalMatrix && !fLocalMatrix.cheapEqualTo(that->fLocalMatrix)) {
- return CombineResult::kCannotCombine;
- }
-
- fRects.push_back_n(that->fRects.count(), that->fRects.begin());
- return CombineResult::kMerged;
- }
-
- struct RectInfo {
- SkRect fRect;
- SkPMColor4f fColor;
- SkRect fLocalRect;
- };
-
- SkSTArray<1, RectInfo, true> fRects;
- Helper fHelper;
- bool fHasLocalMatrix;
- bool fHasLocalRect;
- SkMatrix fLocalMatrix;
- SkMatrix fViewMatrix;
-
- typedef GrMeshDrawOp INHERITED;
-};
-
-} // anonymous namespace
-
-namespace GrRectOpFactory {
-
-std::unique_ptr<GrDrawOp> MakeNonAAFill(GrContext* context,
- GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- GrAAType aaType,
- const GrUserStencilSettings* stencilSettings) {
- if (viewMatrix.hasPerspective()) {
- return NonAAFillRectPerspectiveOp::Make(context, std::move(paint), viewMatrix, rect,
- nullptr, nullptr, aaType, stencilSettings);
- } else {
- return NonAAFillRectOp::Make(context, std::move(paint), viewMatrix, rect, nullptr, nullptr,
- aaType, stencilSettings);
- }
-}
-
-std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalMatrix(
- GrContext* context,
- GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkMatrix& localMatrix,
- const SkRect& rect,
- GrAAType aaType,
- const GrUserStencilSettings* stencilSettings) {
- if (viewMatrix.hasPerspective() || localMatrix.hasPerspective()) {
- return NonAAFillRectPerspectiveOp::Make(context, std::move(paint), viewMatrix, rect,
- nullptr, &localMatrix, aaType, stencilSettings);
- } else {
- return NonAAFillRectOp::Make(context, std::move(paint), viewMatrix, rect, nullptr,
- &localMatrix, aaType, stencilSettings);
- }
-}
-
-std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalRect(GrContext* context,
- GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkRect& localRect,
- GrAAType aaType) {
- if (viewMatrix.hasPerspective()) {
- return NonAAFillRectPerspectiveOp::Make(context, std::move(paint), viewMatrix, rect,
- &localRect, nullptr, aaType, nullptr);
- } else {
- return NonAAFillRectOp::Make(context, std::move(paint), viewMatrix, rect, &localRect,
- nullptr, aaType, nullptr);
- }
-}
-
-} // namespace GrRectOpFactory
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-#if GR_TEST_UTILS
-
-GR_DRAW_OP_TEST_DEFINE(NonAAFillRectOp) {
- SkRect rect = GrTest::TestRect(random);
- SkRect localRect = GrTest::TestRect(random);
- SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
- SkMatrix localMatrix = GrTest::TestMatrix(random);
- const GrUserStencilSettings* stencil = GrGetRandomStencil(random, context);
- GrAAType aaType = GrAAType::kNone;
- if (fsaaType == GrFSAAType::kUnifiedMSAA) {
- aaType = random->nextBool() ? GrAAType::kMSAA : GrAAType::kNone;
- }
- const SkRect* lr = random->nextBool() ? &localRect : nullptr;
- const SkMatrix* lm = random->nextBool() ? &localMatrix : nullptr;
- if (viewMatrix.hasPerspective() || (lm && lm->hasPerspective())) {
- return NonAAFillRectPerspectiveOp::Make(context, std::move(paint), viewMatrix, rect,
- lr, lm, aaType, stencil);
- } else {
- return NonAAFillRectOp::Make(context, std::move(paint), viewMatrix, rect,
- lr, lm, aaType, stencil);
- }
-}
-
-#endif
diff --git a/src/gpu/ops/GrNonAAStrokeRectOp.cpp b/src/gpu/ops/GrNonAAStrokeRectOp.cpp
deleted file mode 100644
index c2786ef..0000000
--- a/src/gpu/ops/GrNonAAStrokeRectOp.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * 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 "GrColor.h"
-#include "GrDefaultGeoProcFactory.h"
-#include "GrDrawOpTest.h"
-#include "GrMeshDrawOp.h"
-#include "GrOpFlushState.h"
-#include "GrRectOpFactory.h"
-#include "GrSimpleMeshDrawOpHelper.h"
-#include "SkRandom.h"
-#include "SkStrokeRec.h"
-
-/* create a triangle strip that strokes the specified rect. There are 8
- unique vertices, but we repeat the last 2 to close up. Alternatively we
- could use an indices array, and then only send 8 verts, but not sure that
- would be faster.
- */
-static void init_stroke_rect_strip(SkPoint verts[10], const SkRect& rect, SkScalar width) {
- const SkScalar rad = SkScalarHalf(width);
-
- verts[0].set(rect.fLeft + rad, rect.fTop + rad);
- verts[1].set(rect.fLeft - rad, rect.fTop - rad);
- verts[2].set(rect.fRight - rad, rect.fTop + rad);
- verts[3].set(rect.fRight + rad, rect.fTop - rad);
- verts[4].set(rect.fRight - rad, rect.fBottom - rad);
- verts[5].set(rect.fRight + rad, rect.fBottom + rad);
- verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
- verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
- verts[8] = verts[0];
- verts[9] = verts[1];
-
- // TODO: we should be catching this higher up the call stack and just draw a single
- // non-AA rect
- if (2*rad >= rect.width()) {
- verts[0].fX = verts[2].fX = verts[4].fX = verts[6].fX = verts[8].fX = rect.centerX();
- }
- if (2*rad >= rect.height()) {
- verts[0].fY = verts[2].fY = verts[4].fY = verts[6].fY = verts[8].fY = rect.centerY();
- }
-}
-
-// Allow all hairlines and all miters, so long as the miter limit doesn't produce beveled corners.
-inline static bool allowed_stroke(const SkStrokeRec& stroke) {
- SkASSERT(stroke.getStyle() == SkStrokeRec::kStroke_Style ||
- stroke.getStyle() == SkStrokeRec::kHairline_Style);
- return !stroke.getWidth() ||
- (stroke.getJoin() == SkPaint::kMiter_Join && stroke.getMiter() > SK_ScalarSqrt2);
-}
-
-namespace {
-
-class NonAAStrokeRectOp final : public GrMeshDrawOp {
-private:
- using Helper = GrSimpleMeshDrawOpHelper;
-
-public:
- DEFINE_OP_CLASS_ID
-
- const char* name() const override { return "NonAAStrokeRectOp"; }
-
- void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
- fHelper.visitProxies(func);
- }
-
-#ifdef SK_DEBUG
- SkString dumpInfo() const override {
- SkString string;
- string.appendf(
- "Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
- "StrokeWidth: %.2f\n",
- fColor.toBytes_RGBA(), fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
- fStrokeWidth);
- string += fHelper.dumpInfo();
- string += INHERITED::dumpInfo();
- return string;
- }
-#endif
-
- static std::unique_ptr<GrDrawOp> Make(GrContext* context,
- GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkStrokeRec& stroke,
- GrAAType aaType) {
- if (!allowed_stroke(stroke)) {
- return nullptr;
- }
- Helper::Flags flags = Helper::Flags::kNone;
- // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
- // hairline rects. We jam all the vertices to pixel centers to avoid this, but not
- // when MSAA is enabled because it can cause ugly artifacts.
- if (stroke.getStyle() == SkStrokeRec::kHairline_Style && aaType != GrAAType::kMSAA) {
- flags |= Helper::Flags::kSnapVerticesToPixelCenters;
- }
- return Helper::FactoryHelper<NonAAStrokeRectOp>(context, std::move(paint), flags,
- viewMatrix, rect,
- stroke, aaType);
- }
-
- NonAAStrokeRectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color,
- Helper::Flags flags, const SkMatrix& viewMatrix, const SkRect& rect,
- const SkStrokeRec& stroke, GrAAType aaType)
- : INHERITED(ClassID()), fHelper(helperArgs, aaType, flags) {
- fColor = color;
- fViewMatrix = viewMatrix;
- fRect = rect;
- // Sort the rect for hairlines
- fRect.sort();
- fStrokeWidth = stroke.getWidth();
-
- SkScalar rad = SkScalarHalf(fStrokeWidth);
- SkRect bounds = rect;
- bounds.outset(rad, rad);
-
- // If our caller snaps to pixel centers then we have to round out the bounds
- if (flags & Helper::Flags::kSnapVerticesToPixelCenters) {
- viewMatrix.mapRect(&bounds);
- // We want to be consistent with how we snap non-aa lines. To match what we do in
- // GrGLSLVertexShaderBuilder, we first floor all the vertex values and then add half a
- // pixel to force us to pixel centers.
- bounds.set(SkScalarFloorToScalar(bounds.fLeft),
- SkScalarFloorToScalar(bounds.fTop),
- SkScalarFloorToScalar(bounds.fRight),
- SkScalarFloorToScalar(bounds.fBottom));
- bounds.offset(0.5f, 0.5f);
- this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
- } else {
- this->setTransformedBounds(bounds, fViewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
- }
- }
-
- FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
-
- RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
- return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone,
- &fColor);
- }
-
-private:
- void onPrepareDraws(Target* target) override {
- sk_sp<GrGeometryProcessor> gp;
- {
- using namespace GrDefaultGeoProcFactory;
- Color color(fColor);
- LocalCoords::Type localCoordsType = fHelper.usesLocalCoords()
- ? LocalCoords::kUsePosition_Type
- : LocalCoords::kUnused_Type;
- gp = GrDefaultGeoProcFactory::Make(target->caps().shaderCaps(), color,
- Coverage::kSolid_Type, localCoordsType,
- fViewMatrix);
- }
-
- size_t kVertexStride = gp->vertexStride();
- int vertexCount = kVertsPerHairlineRect;
- if (fStrokeWidth > 0) {
- vertexCount = kVertsPerStrokeRect;
- }
-
- const GrBuffer* vertexBuffer;
- int firstVertex;
-
- void* verts =
- target->makeVertexSpace(kVertexStride, vertexCount, &vertexBuffer, &firstVertex);
-
- if (!verts) {
- SkDebugf("Could not allocate vertices\n");
- return;
- }
-
- SkPoint* vertex = reinterpret_cast<SkPoint*>(verts);
-
- GrPrimitiveType primType;
- if (fStrokeWidth > 0) {
- primType = GrPrimitiveType::kTriangleStrip;
- init_stroke_rect_strip(vertex, fRect, fStrokeWidth);
- } else {
- // hairline
- primType = GrPrimitiveType::kLineStrip;
- vertex[0].set(fRect.fLeft, fRect.fTop);
- vertex[1].set(fRect.fRight, fRect.fTop);
- vertex[2].set(fRect.fRight, fRect.fBottom);
- vertex[3].set(fRect.fLeft, fRect.fBottom);
- vertex[4].set(fRect.fLeft, fRect.fTop);
- }
-
- GrMesh* mesh = target->allocMesh(primType);
- mesh->setNonIndexedNonInstanced(vertexCount);
- mesh->setVertexData(vertexBuffer, firstVertex);
- auto pipe = fHelper.makePipeline(target);
- target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
- }
-
- // TODO: override onCombineIfPossible
-
- Helper fHelper;
- SkPMColor4f fColor;
- SkMatrix fViewMatrix;
- SkRect fRect;
- SkScalar fStrokeWidth;
-
- const static int kVertsPerHairlineRect = 5;
- const static int kVertsPerStrokeRect = 10;
-
- typedef GrMeshDrawOp INHERITED;
-};
-
-} // anonymous namespace
-
-namespace GrRectOpFactory {
-std::unique_ptr<GrDrawOp> MakeNonAAStroke(GrContext* context,
- GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkStrokeRec& stroke,
- GrAAType aaType) {
- return NonAAStrokeRectOp::Make(context, std::move(paint), viewMatrix, rect, stroke, aaType);
-}
-} // namespace GrRectOpFactory
-
-#if GR_TEST_UTILS
-
-GR_DRAW_OP_TEST_DEFINE(NonAAStrokeRectOp) {
- SkMatrix viewMatrix = GrTest::TestMatrix(random);
- SkRect rect = GrTest::TestRect(random);
- SkScalar strokeWidth = random->nextBool() ? 0.0f : 2.0f;
- SkPaint strokePaint;
- strokePaint.setStrokeWidth(strokeWidth);
- strokePaint.setStyle(SkPaint::kStroke_Style);
- strokePaint.setStrokeJoin(SkPaint::kMiter_Join);
- SkStrokeRec strokeRec(strokePaint);
- GrAAType aaType = GrAAType::kNone;
- if (fsaaType == GrFSAAType::kUnifiedMSAA) {
- aaType = random->nextBool() ? GrAAType::kMSAA : GrAAType::kNone;
- }
- return NonAAStrokeRectOp::Make(context, std::move(paint), viewMatrix, rect, strokeRec, aaType);
-}
-
-#endif
diff --git a/src/gpu/ops/GrRectOpFactory.h b/src/gpu/ops/GrRectOpFactory.h
deleted file mode 100644
index 29ac10e..0000000
--- a/src/gpu/ops/GrRectOpFactory.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrRectOpFactory_DEFINED
-#define GrRectOpFactory_DEFINED
-
-#include <memory>
-#include "GrTypes.h"
-
-enum class GrAAType : unsigned;
-class GrDrawOp;
-class GrPaint;
-struct GrUserStencilSettings;
-class SkMatrix;
-struct SkRect;
-class SkStrokeRec;
-
-/**
- * A set of factory functions for drawing rectangles including fills, strokes, coverage-antialiased,
- * and non-antialiased. The non-antialiased ops can be used with MSAA. As with other GrDrawOp
- * factories, the GrPaint is only consumed by these methods if a valid op is returned. If null is
- * returned then the paint is unmodified and may still be used.
- */
-namespace GrRectOpFactory {
-/** AA Fill */
-
-std::unique_ptr<GrDrawOp> MakeAAFill(GrContext*,
- GrPaint&&,
- const SkMatrix&,
- const SkRect&,
- const GrUserStencilSettings* = nullptr);
-
-std::unique_ptr<GrDrawOp> MakeAAFillWithLocalMatrix(GrContext*,
- GrPaint&&,
- const SkMatrix& viewMatrix,
- const SkMatrix& localMatrix,
- const SkRect&);
-
-std::unique_ptr<GrDrawOp> MakeAAFillWithLocalRect(GrContext*,
- GrPaint&&,
- const SkMatrix&,
- const SkRect& rect,
- const SkRect& localRect);
-
-/** Non-AA Fill - GrAAType must be either kNone or kMSAA. */
-
-std::unique_ptr<GrDrawOp> MakeNonAAFill(GrContext*,
- GrPaint&&,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- GrAAType,
- const GrUserStencilSettings* = nullptr);
-
-std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalMatrix(GrContext*,
- GrPaint&&,
- const SkMatrix& viewMatrix,
- const SkMatrix& localMatrix,
- const SkRect&,
- GrAAType,
- const GrUserStencilSettings* = nullptr);
-
-std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalRect(GrContext*,
- GrPaint&&,
- const SkMatrix&,
- const SkRect& rect,
- const SkRect& localRect,
- GrAAType);
-
-/** AA Stroke */
-
-std::unique_ptr<GrDrawOp> MakeAAStroke(GrContext*,
- GrPaint&&,
- const SkMatrix&,
- const SkRect&,
- const SkStrokeRec&);
-
-// rects[0] == outer rectangle, rects[1] == inner rectangle. Null return means there is nothing to
-// draw rather than failure.
-std::unique_ptr<GrDrawOp> MakeAAFillNestedRects(GrContext*,
- GrPaint&&,
- const SkMatrix&,
- const SkRect rects[2]);
-
-/** Non-AA Stroke - GrAAType must be either kNone or kMSAA. */
-
-std::unique_ptr<GrDrawOp> MakeNonAAStroke(GrContext*,
- GrPaint&&,
- const SkMatrix&,
- const SkRect&,
- const SkStrokeRec&,
- GrAAType);
-
-} // namespace GrRectOpFactory
-
-#endif
diff --git a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
index a0ef219..9a54dfe 100644
--- a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
@@ -18,7 +18,7 @@
#include "GrStencilClip.h"
#include "GrStencilPathOp.h"
#include "GrStyle.h"
-#include "ops/GrRectOpFactory.h"
+#include "ops/GrFillRectOp.h"
GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
const GrCaps& caps) {
@@ -156,10 +156,12 @@
if (GrAAType::kMixedSamples == coverAAType) {
coverAAType = GrAAType::kNone;
}
- std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
+ // This is a non-coverage aa rect operation
+ SkASSERT(coverAAType == GrAAType::kNone || coverAAType == GrAAType::kMSAA);
+ std::unique_ptr<GrDrawOp> op = GrFillRectOp::MakeWithLocalMatrix(
args.fContext, std::move(args.fPaint),
- coverMatrix, localMatrix, coverBounds,
- coverAAType, &kInvertedCoverPass);
+ coverAAType, coverMatrix, localMatrix,
+ coverBounds, &kInvertedCoverPass);
args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
}
diff --git a/src/gpu/ops/GrAAStrokeRectOp.cpp b/src/gpu/ops/GrStrokeRectOp.cpp
similarity index 65%
rename from src/gpu/ops/GrAAStrokeRectOp.cpp
rename to src/gpu/ops/GrStrokeRectOp.cpp
index d6c4d97..98b3b67 100644
--- a/src/gpu/ops/GrAAStrokeRectOp.cpp
+++ b/src/gpu/ops/GrStrokeRectOp.cpp
@@ -1,25 +1,31 @@
/*
- * Copyright 2015 Google Inc.
+ * Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
+#include "GrStrokeRectOp.h"
+
+#include "GrColor.h"
#include "GrDefaultGeoProcFactory.h"
+#include "GrDrawOpTest.h"
+#include "GrMeshDrawOp.h"
#include "GrOpFlushState.h"
-#include "GrRectOpFactory.h"
#include "GrResourceKey.h"
#include "GrResourceProvider.h"
#include "GrSimpleMeshDrawOpHelper.h"
#include "GrVertexWriter.h"
+#include "ops/GrFillRectOp.h"
+#include "SkRandom.h"
#include "SkStrokeRec.h"
-GR_DECLARE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey);
-GR_DECLARE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey);
+namespace {
// We support all hairlines, bevels, and miters, but not round joins. Also, check whether the miter
-// limit makes a miter join effectively beveled.
-inline static bool allowed_stroke(const SkStrokeRec& stroke, bool* isMiter) {
+// limit makes a miter join effectively beveled. If the miter is effectively beveled, it is only
+// supported when using an AA stroke.
+inline static bool allowed_stroke(const SkStrokeRec& stroke, GrAA aa, bool* isMiter) {
SkASSERT(stroke.getStyle() == SkStrokeRec::kStroke_Style ||
stroke.getStyle() == SkStrokeRec::kHairline_Style);
// For hairlines, make bevel and round joins appear the same as mitered ones.
@@ -29,18 +35,216 @@
}
if (stroke.getJoin() == SkPaint::kBevel_Join) {
*isMiter = false;
- return true;
+ return aa == GrAA::kYes; // bevel only supported with AA
}
if (stroke.getJoin() == SkPaint::kMiter_Join) {
*isMiter = stroke.getMiter() >= SK_ScalarSqrt2;
- return true;
+ // Supported under non-AA only if it remains mitered
+ return aa == GrAA::kYes || *isMiter;
}
return false;
}
-static void compute_rects(SkRect* devOutside, SkRect* devOutsideAssist, SkRect* devInside,
- bool* isDegenerate, const SkMatrix& viewMatrix, const SkRect& rect,
- SkScalar strokeWidth, bool miterStroke) {
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Non-AA Stroking
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+/* create a triangle strip that strokes the specified rect. There are 8
+ unique vertices, but we repeat the last 2 to close up. Alternatively we
+ could use an indices array, and then only send 8 verts, but not sure that
+ would be faster.
+ */
+static void init_nonaa_stroke_rect_strip(SkPoint verts[10], const SkRect& rect, SkScalar width) {
+ const SkScalar rad = SkScalarHalf(width);
+
+ verts[0].set(rect.fLeft + rad, rect.fTop + rad);
+ verts[1].set(rect.fLeft - rad, rect.fTop - rad);
+ verts[2].set(rect.fRight - rad, rect.fTop + rad);
+ verts[3].set(rect.fRight + rad, rect.fTop - rad);
+ verts[4].set(rect.fRight - rad, rect.fBottom - rad);
+ verts[5].set(rect.fRight + rad, rect.fBottom + rad);
+ verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
+ verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
+ verts[8] = verts[0];
+ verts[9] = verts[1];
+
+ // TODO: we should be catching this higher up the call stack and just draw a single
+ // non-AA rect
+ if (2*rad >= rect.width()) {
+ verts[0].fX = verts[2].fX = verts[4].fX = verts[6].fX = verts[8].fX = rect.centerX();
+ }
+ if (2*rad >= rect.height()) {
+ verts[0].fY = verts[2].fY = verts[4].fY = verts[6].fY = verts[8].fY = rect.centerY();
+ }
+}
+
+class NonAAStrokeRectOp final : public GrMeshDrawOp {
+private:
+ using Helper = GrSimpleMeshDrawOpHelper;
+
+public:
+ DEFINE_OP_CLASS_ID
+
+ const char* name() const override { return "NonAAStrokeRectOp"; }
+
+ void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
+ fHelper.visitProxies(func);
+ }
+
+#ifdef SK_DEBUG
+ SkString dumpInfo() const override {
+ SkString string;
+ string.appendf(
+ "Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
+ "StrokeWidth: %.2f\n",
+ fColor.toBytes_RGBA(), fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
+ fStrokeWidth);
+ string += fHelper.dumpInfo();
+ string += INHERITED::dumpInfo();
+ return string;
+ }
+#endif
+
+ static std::unique_ptr<GrDrawOp> Make(GrContext* context,
+ GrPaint&& paint,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkStrokeRec& stroke,
+ GrAAType aaType) {
+ bool isMiter;
+ if (!allowed_stroke(stroke, GrAA::kNo, &isMiter)) {
+ return nullptr;
+ }
+ Helper::Flags flags = Helper::Flags::kNone;
+ // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
+ // hairline rects. We jam all the vertices to pixel centers to avoid this, but not
+ // when MSAA is enabled because it can cause ugly artifacts.
+ if (stroke.getStyle() == SkStrokeRec::kHairline_Style && aaType != GrAAType::kMSAA) {
+ flags |= Helper::Flags::kSnapVerticesToPixelCenters;
+ }
+ return Helper::FactoryHelper<NonAAStrokeRectOp>(context, std::move(paint), flags,
+ viewMatrix, rect,
+ stroke, aaType);
+ }
+
+ NonAAStrokeRectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color,
+ Helper::Flags flags, const SkMatrix& viewMatrix, const SkRect& rect,
+ const SkStrokeRec& stroke, GrAAType aaType)
+ : INHERITED(ClassID()), fHelper(helperArgs, aaType, flags) {
+ fColor = color;
+ fViewMatrix = viewMatrix;
+ fRect = rect;
+ // Sort the rect for hairlines
+ fRect.sort();
+ fStrokeWidth = stroke.getWidth();
+
+ SkScalar rad = SkScalarHalf(fStrokeWidth);
+ SkRect bounds = rect;
+ bounds.outset(rad, rad);
+
+ // If our caller snaps to pixel centers then we have to round out the bounds
+ if (flags & Helper::Flags::kSnapVerticesToPixelCenters) {
+ viewMatrix.mapRect(&bounds);
+ // We want to be consistent with how we snap non-aa lines. To match what we do in
+ // GrGLSLVertexShaderBuilder, we first floor all the vertex values and then add half a
+ // pixel to force us to pixel centers.
+ bounds.set(SkScalarFloorToScalar(bounds.fLeft),
+ SkScalarFloorToScalar(bounds.fTop),
+ SkScalarFloorToScalar(bounds.fRight),
+ SkScalarFloorToScalar(bounds.fBottom));
+ bounds.offset(0.5f, 0.5f);
+ this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
+ } else {
+ this->setTransformedBounds(bounds, fViewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
+ }
+ }
+
+ FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
+
+ RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
+ return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone,
+ &fColor);
+ }
+
+private:
+ void onPrepareDraws(Target* target) override {
+ sk_sp<GrGeometryProcessor> gp;
+ {
+ using namespace GrDefaultGeoProcFactory;
+ Color color(fColor);
+ LocalCoords::Type localCoordsType = fHelper.usesLocalCoords()
+ ? LocalCoords::kUsePosition_Type
+ : LocalCoords::kUnused_Type;
+ gp = GrDefaultGeoProcFactory::Make(target->caps().shaderCaps(), color,
+ Coverage::kSolid_Type, localCoordsType,
+ fViewMatrix);
+ }
+
+ size_t kVertexStride = gp->vertexStride();
+ int vertexCount = kVertsPerHairlineRect;
+ if (fStrokeWidth > 0) {
+ vertexCount = kVertsPerStrokeRect;
+ }
+
+ const GrBuffer* vertexBuffer;
+ int firstVertex;
+
+ void* verts =
+ target->makeVertexSpace(kVertexStride, vertexCount, &vertexBuffer, &firstVertex);
+
+ if (!verts) {
+ SkDebugf("Could not allocate vertices\n");
+ return;
+ }
+
+ SkPoint* vertex = reinterpret_cast<SkPoint*>(verts);
+
+ GrPrimitiveType primType;
+ if (fStrokeWidth > 0) {
+ primType = GrPrimitiveType::kTriangleStrip;
+ init_nonaa_stroke_rect_strip(vertex, fRect, fStrokeWidth);
+ } else {
+ // hairline
+ primType = GrPrimitiveType::kLineStrip;
+ vertex[0].set(fRect.fLeft, fRect.fTop);
+ vertex[1].set(fRect.fRight, fRect.fTop);
+ vertex[2].set(fRect.fRight, fRect.fBottom);
+ vertex[3].set(fRect.fLeft, fRect.fBottom);
+ vertex[4].set(fRect.fLeft, fRect.fTop);
+ }
+
+ GrMesh* mesh = target->allocMesh(primType);
+ mesh->setNonIndexedNonInstanced(vertexCount);
+ mesh->setVertexData(vertexBuffer, firstVertex);
+ auto pipe = fHelper.makePipeline(target);
+ target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
+ }
+
+ // TODO: override onCombineIfPossible
+
+ Helper fHelper;
+ SkPMColor4f fColor;
+ SkMatrix fViewMatrix;
+ SkRect fRect;
+ SkScalar fStrokeWidth;
+
+ const static int kVertsPerHairlineRect = 5;
+ const static int kVertsPerStrokeRect = 10;
+
+ typedef GrMeshDrawOp INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// AA Stroking
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+GR_DECLARE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey);
+GR_DECLARE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey);
+
+static void compute_aa_rects(SkRect* devOutside, SkRect* devOutsideAssist, SkRect* devInside,
+ bool* isDegenerate, const SkMatrix& viewMatrix, const SkRect& rect,
+ SkScalar strokeWidth, bool miterStroke) {
SkRect devRect;
viewMatrix.mapRect(&devRect, rect);
@@ -90,10 +294,10 @@
}
}
-static sk_sp<GrGeometryProcessor> create_stroke_rect_gp(const GrShaderCaps* shaderCaps,
- bool tweakAlphaForCoverage,
- const SkMatrix& viewMatrix,
- bool usesLocalCoords) {
+static sk_sp<GrGeometryProcessor> create_aa_stroke_rect_gp(const GrShaderCaps* shaderCaps,
+ bool tweakAlphaForCoverage,
+ const SkMatrix& viewMatrix,
+ bool usesLocalCoords) {
using namespace GrDefaultGeoProcFactory;
Coverage::Type coverageType;
@@ -111,8 +315,6 @@
viewMatrix);
}
-namespace {
-
class AAStrokeRectOp final : public GrMeshDrawOp {
private:
using Helper = GrSimpleMeshDrawOpHelper;
@@ -148,7 +350,7 @@
const SkRect& rect,
const SkStrokeRec& stroke) {
bool isMiter;
- if (!allowed_stroke(stroke, &isMiter)) {
+ if (!allowed_stroke(stroke, GrAA::kYes, &isMiter)) {
return nullptr;
}
return Helper::FactoryHelper<AAStrokeRectOp>(context, std::move(paint), viewMatrix, rect,
@@ -163,8 +365,8 @@
, fViewMatrix(viewMatrix) {
fMiterStroke = isMiter;
RectInfo& info = fRects.push_back();
- compute_rects(&info.fDevOutside, &info.fDevOutsideAssist, &info.fDevInside,
- &info.fDegenerate, viewMatrix, rect, stroke.getWidth(), isMiter);
+ compute_aa_rects(&info.fDevOutside, &info.fDevOutsideAssist, &info.fDevInside,
+ &info.fDegenerate, viewMatrix, rect, stroke.getWidth(), isMiter);
info.fColor = color;
if (isMiter) {
this->setBounds(info.fDevOutside, HasAABloat::kYes, IsZeroArea::kNo);
@@ -254,13 +456,11 @@
typedef GrMeshDrawOp INHERITED;
};
-} // anonymous namespace
-
void AAStrokeRectOp::onPrepareDraws(Target* target) {
- sk_sp<GrGeometryProcessor> gp(create_stroke_rect_gp(target->caps().shaderCaps(),
- fHelper.compatibleWithAlphaAsCoverage(),
- this->viewMatrix(),
- fHelper.usesLocalCoords()));
+ sk_sp<GrGeometryProcessor> gp(create_aa_stroke_rect_gp(target->caps().shaderCaps(),
+ fHelper.compatibleWithAlphaAsCoverage(),
+ this->viewMatrix(),
+ fHelper.usesLocalCoords()));
if (!gp) {
SkDebugf("Couldn't create GrGeometryProcessor\n");
return;
@@ -520,12 +720,31 @@
}
}
-namespace GrRectOpFactory {
+} // anonymous namespace
-std::unique_ptr<GrDrawOp> MakeAAFillNestedRects(GrContext* context,
- GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkRect rects[2]) {
+namespace GrStrokeRectOp {
+
+std::unique_ptr<GrDrawOp> Make(GrContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkStrokeRec& stroke) {
+ if (aaType == GrAAType::kCoverage) {
+ // The AA op only supports axis-aligned rectangles
+ if (!viewMatrix.rectStaysRect()) {
+ return nullptr;
+ }
+ return AAStrokeRectOp::Make(context, std::move(paint), viewMatrix, rect, stroke);
+ } else {
+ return NonAAStrokeRectOp::Make(context, std::move(paint), viewMatrix, rect, stroke, aaType);
+ }
+}
+
+std::unique_ptr<GrDrawOp> MakeNested(GrContext* context,
+ GrPaint&& paint,
+ const SkMatrix& viewMatrix,
+ const SkRect rects[2]) {
SkASSERT(viewMatrix.rectStaysRect());
SkASSERT(!rects[0].isEmpty() && !rects[1].isEmpty());
@@ -536,28 +755,35 @@
if (devOutside.isEmpty()) {
return nullptr;
}
- return MakeAAFill(context, std::move(paint), viewMatrix, rects[0]);
+ return GrFillRectOp::Make(context, std::move(paint), GrAAType::kCoverage, viewMatrix,
+ rects[0]);
}
return AAStrokeRectOp::Make(context, std::move(paint), viewMatrix, devOutside, devInside);
}
-std::unique_ptr<GrDrawOp> MakeAAStroke(GrContext* context,
- GrPaint&& paint,
- const SkMatrix& viewMatrix,
- const SkRect& rect,
- const SkStrokeRec& stroke) {
- return AAStrokeRectOp::Make(context, std::move(paint), viewMatrix, rect, stroke);
-}
-
-} // namespace GrRectOpFactory
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
+} // namespace GrStrokeRectOp
#if GR_TEST_UTILS
#include "GrDrawOpTest.h"
+GR_DRAW_OP_TEST_DEFINE(NonAAStrokeRectOp) {
+ SkMatrix viewMatrix = GrTest::TestMatrix(random);
+ SkRect rect = GrTest::TestRect(random);
+ SkScalar strokeWidth = random->nextBool() ? 0.0f : 2.0f;
+ SkPaint strokePaint;
+ strokePaint.setStrokeWidth(strokeWidth);
+ strokePaint.setStyle(SkPaint::kStroke_Style);
+ strokePaint.setStrokeJoin(SkPaint::kMiter_Join);
+ SkStrokeRec strokeRec(strokePaint);
+ GrAAType aaType = GrAAType::kNone;
+ if (fsaaType == GrFSAAType::kUnifiedMSAA) {
+ aaType = random->nextBool() ? GrAAType::kMSAA : GrAAType::kNone;
+ }
+ return NonAAStrokeRectOp::Make(context, std::move(paint), viewMatrix, rect, strokeRec, aaType);
+}
+
GR_DRAW_OP_TEST_DEFINE(AAStrokeRectOp) {
bool miterStroke = random->nextBool();
@@ -572,7 +798,7 @@
rec.setStrokeParams(SkPaint::kButt_Cap,
miterStroke ? SkPaint::kMiter_Join : SkPaint::kBevel_Join, 1.f);
SkMatrix matrix = GrTest::TestMatrixRectStaysRect(random);
- return GrRectOpFactory::MakeAAStroke(context, std::move(paint), matrix, rect, rec);
+ return AAStrokeRectOp::Make(context, std::move(paint), matrix, rect, rec);
}
#endif
diff --git a/src/gpu/ops/GrStrokeRectOp.h b/src/gpu/ops/GrStrokeRectOp.h
new file mode 100644
index 0000000..97ea865a
--- /dev/null
+++ b/src/gpu/ops/GrStrokeRectOp.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrStrokeRectOp_DEFINED
+#define GrStrokeRectOp_DEFINED
+
+#include "GrTypesPriv.h"
+
+class GrDrawOp;
+class GrPaint;
+class SkMatrix;
+struct SkRect;
+class SkStrokeRec;
+
+/**
+ * A set of factory functions for drawing stroked rectangles either coverage-antialiased, or
+ * non-antialiased. The non-antialiased ops can be used with MSAA. As with other GrDrawOp factories,
+ * the GrPaint is only consumed by these methods if a valid op is returned. If null is returned then
+ * the paint is unmodified and may still be used.
+ */
+namespace GrStrokeRectOp {
+
+std::unique_ptr<GrDrawOp> Make(GrContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkStrokeRec& stroke);
+
+// rects[0] == outer rectangle, rects[1] == inner rectangle. Null return means there is nothing to
+// draw rather than failure. The area between the rectangles will be filled by the paint, and it
+// will be anti-aliased with coverage AA. viewMatrix.rectStaysRect() must be true.
+std::unique_ptr<GrDrawOp> MakeNested(GrContext* context,
+ GrPaint&& paint,
+ const SkMatrix& viewMatrix,
+ const SkRect rects[2]);
+
+} // namespace GrStrokeRectOp
+
+#endif // GrStrokeRectOp_DEFINED