Revert "Revert "Add a new non-AA rect op that does not inherit from GrLegacyMeshDrawOp.""
This reverts commit 0f353327968530506dd3dd15fca79ef59fe013f1.
Bug: skia:
Change-Id: I8def56fa55bfc70de4386bf0b7a7867f6e91c173
Reviewed-on: https://skia-review.googlesource.com/15251
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/ops/GrMeshDrawOp.cpp b/src/gpu/ops/GrMeshDrawOp.cpp
index 92571d6..ee7c0a5 100644
--- a/src/gpu/ops/GrMeshDrawOp.cpp
+++ b/src/gpu/ops/GrMeshDrawOp.cpp
@@ -67,8 +67,6 @@
}
void GrMeshDrawOp::onExecute(GrOpFlushState* state) {
- SkASSERT(!state->drawOpArgs().fAppliedClip);
- SkASSERT(!state->drawOpArgs().fDstTexture.texture());
int currUploadIdx = 0;
int currMeshIdx = 0;
diff --git a/src/gpu/ops/GrNewNonAAFillRectOp.cpp b/src/gpu/ops/GrNewNonAAFillRectOp.cpp
new file mode 100644
index 0000000..15e025a
--- /dev/null
+++ b/src/gpu/ops/GrNewNonAAFillRectOp.cpp
@@ -0,0 +1,198 @@
+/*
+ * 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 "GrNewNonAAFillRectOp.h"
+#include "GrAppliedClip.h"
+#include "GrColor.h"
+#include "GrDefaultGeoProcFactory.h"
+#include "GrMeshDrawOp.h"
+#include "GrOpFlushState.h"
+#include "GrPrimitiveProcessor.h"
+#include "GrQuad.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() {
+ using namespace GrDefaultGeoProcFactory;
+ return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, Coverage::kSolid_Type,
+ LocalCoords::kHasExplicit_Type, SkMatrix::I());
+}
+
+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);
+
+ positions->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, 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);
+ }
+}
+
+class NewNonAAFillRectOp final : public GrMeshDrawOp {
+private:
+ using Helper = GrSimpleMeshDrawOpHelperWithStencil;
+
+public:
+ DEFINE_OP_CLASS_ID
+ NewNonAAFillRectOp() = delete;
+
+ static std::unique_ptr<GrDrawOp> Make(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<NewNonAAFillRectOp>(std::move(paint), viewMatrix, rect,
+ localRect, localMatrix, aaType,
+ stencilSettings);
+ }
+
+ const char* name() const override { return "NonAAFillRectOp"; }
+
+ 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, info.fRect.fLeft, info.fRect.fTop, info.fRect.fRight,
+ info.fRect.fBottom);
+ }
+ return str;
+ }
+
+ bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) override {
+ GrColor* color = &fRects.front().fColor;
+ return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
+ }
+
+ FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
+
+ NewNonAAFillRectOp(const Helper::MakeArgs& args, GrColor 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.setFromMappedRect(*localRect, *localMatrix);
+ } else if (localRect) {
+ info.fLocalQuad.set(*localRect);
+ } else if (localMatrix) {
+ info.fLocalQuad.setFromMappedRect(rect, *localMatrix);
+ } else {
+ info.fLocalQuad.set(rect);
+ }
+ this->setTransformedBounds(fRects[0].fRect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
+ }
+
+private:
+ void onPrepareDraws(Target* target) const override {
+ sk_sp<GrGeometryProcessor> gp = make_gp();
+ if (!gp) {
+ SkDebugf("Couldn't create GrGeometryProcessor\n");
+ return;
+ }
+ SkASSERT(gp->getVertexStride() ==
+ sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr));
+
+ size_t vertexStride = gp->getVertexStride();
+ int rectCount = fRects.count();
+
+ sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer());
+ PatternHelper helper;
+ void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride,
+ indexBuffer.get(), kVertsPerRect, kIndicesPerRect, rectCount);
+ 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 * vertexStride;
+ tesselate(verts, vertexStride, fRects[i].fColor, &fRects[i].fViewMatrix,
+ fRects[i].fRect, &fRects[i].fLocalQuad);
+ }
+ helper.recordDraw(target, gp.get(), fHelper.makePipeline(target));
+ }
+
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ NewNonAAFillRectOp* that = t->cast<NewNonAAFillRectOp>();
+ if (!fHelper.isCompatible(that->fHelper)) {
+ return false;
+ }
+ fRects.push_back_n(that->fRects.count(), that->fRects.begin());
+ this->joinBounds(*that);
+ return true;
+ }
+
+ struct RectInfo {
+ GrColor fColor;
+ SkMatrix fViewMatrix;
+ SkRect fRect;
+ GrQuad fLocalQuad;
+ };
+
+ Helper fHelper;
+ SkSTArray<1, RectInfo, true> fRects;
+ typedef GrMeshDrawOp INHERITED;
+};
+
+namespace GrNewNonAAFillRectOp {
+
+std::unique_ptr<GrDrawOp> Make(GrPaint&& paint,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkRect* localRect,
+ const SkMatrix* localMatrix,
+ GrAAType aaType,
+ const GrUserStencilSettings* stencilSettings) {
+ return NewNonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, localRect, localMatrix,
+ aaType, stencilSettings);
+}
+}; // namespace GrNewNonAAFillRectOp
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/ops/GrNewNonAAFillRectOp.h b/src/gpu/ops/GrNewNonAAFillRectOp.h
new file mode 100644
index 0000000..8f78707
--- /dev/null
+++ b/src/gpu/ops/GrNewNonAAFillRectOp.h
@@ -0,0 +1,31 @@
+/*
+ * 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 GrNewNonAAFillRectOp_DEFINED
+#define GrNewNonAAFillRectOp_DEFINED
+
+#include <memory>
+#include "GrColor.h"
+
+class GrDrawOp;
+class GrPaint;
+class SkMatrix;
+struct SkRect;
+struct GrUserStencilSettings;
+enum class GrAAType : unsigned;
+
+namespace GrNewNonAAFillRectOp {
+std::unique_ptr<GrDrawOp> Make(GrPaint&&,
+ const SkMatrix& viewMatrix,
+ const SkRect& rect,
+ const SkRect* localRect,
+ const SkMatrix* localMatrix,
+ GrAAType,
+ const GrUserStencilSettings* = nullptr);
+};
+
+#endif
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
new file mode 100644
index 0000000..f64f9ec
--- /dev/null
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
@@ -0,0 +1,194 @@
+/*
+ * 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 GrSimpleMeshDrawOpHelper_DEFINED
+#define GrSimpleMeshDrawOpHelper_DEFINED
+
+#include "GrAppliedClip.h"
+#include "GrOpFlushState.h"
+#include "GrPipeline.h"
+#include "GrProcessorSet.h"
+#include "GrUserStencilSettings.h"
+
+/**
+ * This class can be used to help implement simple mesh draw ops. It reduces the amount of
+ * boilerplate code to type and also provides a mechanism for optionally allocating space for a
+ * GrProcessorSet based on a GrPaint. It is intended to be used by ops that construct a single
+ * GrPipeline for a uniform primitive color and a GrPaint.
+ */
+class GrSimpleMeshDrawOpHelper {
+public:
+ struct MakeArgs;
+
+ /**
+ * This can be used by a Op class to perform allocation and initialization such that a
+ * GrProcessorSet (if required) is allocated at the same time as the Op instance. It requires
+ * that Op implements a constructor of the form:
+ * Op(MakeArgs, GrColor, OpArgs...)
+ * which is public or made accessible via 'friend'.
+ */
+ template <typename Op, typename... OpArgs>
+ static std::unique_ptr<GrDrawOp> FactoryHelper(GrPaint&& paint, OpArgs... opArgs);
+
+ GrSimpleMeshDrawOpHelper(const MakeArgs& args, GrAAType aaType,
+ GrUserStencilSettings* stencilSettings = nullptr)
+ : fProcessors(args.fProcessorSet)
+ , fPipelineFlags(args.fSRGBFlags)
+ , fAAType((int)aaType) {
+ SkASSERT(!stencilSettings);
+ if (GrAATypeIsHW(aaType)) {
+ fPipelineFlags |= GrPipeline::kHWAntialias_Flag;
+ }
+ }
+
+ ~GrSimpleMeshDrawOpHelper() {
+ if (fProcessors) {
+ fProcessors->~GrProcessorSet();
+ }
+ }
+
+ GrSimpleMeshDrawOpHelper() = delete;
+ GrSimpleMeshDrawOpHelper(const GrSimpleMeshDrawOpHelper&) = delete;
+ GrSimpleMeshDrawOpHelper& operator=(const GrSimpleMeshDrawOpHelper&) = delete;
+
+ GrDrawOp::FixedFunctionFlags fixedFunctionFlags() const {
+ return GrAATypeIsHW((this->aaType())) ? GrDrawOp::FixedFunctionFlags::kUsesHWAA
+ : GrDrawOp::FixedFunctionFlags::kNone;
+ }
+
+ bool isCompatible(const GrSimpleMeshDrawOpHelper& that) const {
+ if (SkToBool(fProcessors) != SkToBool(that.fProcessors)) {
+ return false;
+ }
+ if (SkToBool(fProcessors) && *fProcessors != *that.fProcessors) {
+ return false;
+ }
+ return fPipelineFlags == that.fPipelineFlags && fAAType == that.fAAType;
+ }
+
+ bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip,
+ GrProcessorAnalysisCoverage geometryCoverage, GrColor* color) {
+ if (fProcessors) {
+ GrProcessorAnalysisCoverage coverage = geometryCoverage;
+ if (GrProcessorAnalysisCoverage::kNone == coverage) {
+ coverage = clip->clipCoverageFragmentProcessor()
+ ? GrProcessorAnalysisCoverage::kSingleChannel
+ : GrProcessorAnalysisCoverage::kNone;
+ }
+ bool isMixedSamples = this->aaType() == GrAAType::kMixedSamples;
+ GrProcessorSet::Analysis analysis =
+ fProcessors->finalize(*color, coverage, clip, isMixedSamples, caps, color);
+ return analysis.requiresDstTexture();
+ } else {
+ return GrProcessorSet::EmptySetAnalysis().requiresDstTexture();
+ }
+ }
+
+ GrPipeline* makePipeline(GrMeshDrawOp::Target* target) const {
+ return target->allocPipeline(this->pipelineInitArgs(target));
+ }
+
+ struct MakeArgs {
+ private:
+ MakeArgs() = default;
+
+ GrProcessorSet* fProcessorSet;
+ uint32_t fSRGBFlags;
+
+ friend class GrSimpleMeshDrawOpHelper;
+ };
+
+protected:
+ GrAAType aaType() const { return static_cast<GrAAType>(fAAType); }
+ uint32_t pipelineFlags() const { return fPipelineFlags; }
+ const GrProcessorSet& processors() const {
+ return fProcessors ? *fProcessors : GrProcessorSet::EmptySet();
+ }
+
+ GrPipeline::InitArgs pipelineInitArgs(GrMeshDrawOp::Target* target) const {
+ GrPipeline::InitArgs args;
+ args.fFlags = this->pipelineFlags();
+ args.fProcessors = &this->processors();
+ args.fRenderTarget = target->renderTarget();
+ args.fAppliedClip = target->clip();
+ args.fDstTexture = target->dstTexture();
+ args.fCaps = &target->caps();
+ return args;
+ }
+
+private:
+ GrProcessorSet* fProcessors;
+ unsigned fPipelineFlags : 8;
+ unsigned fAAType : 2;
+};
+
+/**
+ * This class extends GrSimpleMeshDrawOpHelper to support an optional GrUserStencilSettings. This
+ * uses private inheritance because it non-virtually overrides methods in the base class and should
+ * never be used with a GrSimpleMeshDrawOpHelper pointer or reference.
+ */
+class GrSimpleMeshDrawOpHelperWithStencil : private GrSimpleMeshDrawOpHelper {
+public:
+ using MakeArgs = GrSimpleMeshDrawOpHelper::MakeArgs;
+
+ // using declarations can't be templated, so this is a pass through function instead.
+ template <typename Op, typename... OpArgs>
+ static std::unique_ptr<GrDrawOp> FactoryHelper(GrPaint&& paint, OpArgs... opArgs) {
+ return GrSimpleMeshDrawOpHelper::FactoryHelper<Op, OpArgs...>(
+ std::move(paint), std::forward<OpArgs>(opArgs)...);
+ }
+
+ GrSimpleMeshDrawOpHelperWithStencil(const MakeArgs& args, GrAAType aaType,
+ const GrUserStencilSettings* stencilSettings)
+ : INHERITED(args, aaType)
+ , fStencilSettings(stencilSettings ? stencilSettings
+ : &GrUserStencilSettings::kUnused) {}
+
+ GrDrawOp::FixedFunctionFlags fixedFunctionFlags() const {
+ GrDrawOp::FixedFunctionFlags flags = INHERITED::fixedFunctionFlags();
+ if (fStencilSettings != &GrUserStencilSettings::kUnused) {
+ flags |= GrDrawOp::FixedFunctionFlags::kUsesStencil;
+ }
+ return flags;
+ }
+
+ using GrSimpleMeshDrawOpHelper::xpRequiresDstTexture;
+
+ bool isCompatible(const GrSimpleMeshDrawOpHelperWithStencil& that) const {
+ return INHERITED::isCompatible(that) && fStencilSettings == that.fStencilSettings;
+ }
+
+ GrPipeline* makePipeline(GrMeshDrawOp::Target* target) const {
+ auto args = INHERITED::pipelineInitArgs(target);
+ args.fUserStencil = fStencilSettings;
+ return target->allocPipeline(args);
+ }
+
+private:
+ const GrUserStencilSettings* fStencilSettings;
+ typedef GrSimpleMeshDrawOpHelper INHERITED;
+};
+
+template <typename Op, typename... OpArgs>
+std::unique_ptr<GrDrawOp> GrSimpleMeshDrawOpHelper::FactoryHelper(GrPaint&& paint,
+ OpArgs... opArgs) {
+ MakeArgs makeArgs;
+ makeArgs.fSRGBFlags = GrPipeline::SRGBFlagsFromPaint(paint);
+ GrColor color = paint.getColor();
+ if (paint.isTrivial()) {
+ makeArgs.fProcessorSet = nullptr;
+ return std::unique_ptr<GrDrawOp>(new Op(makeArgs, color, std::forward<OpArgs>(opArgs)...));
+ } else {
+ char* mem = (char*)GrOp::operator new(sizeof(Op) + sizeof(GrProcessorSet));
+ char* setMem = mem + sizeof(Op);
+ makeArgs.fProcessorSet = new (setMem) GrProcessorSet(std::move(paint));
+ return std::unique_ptr<GrDrawOp>(
+ new (mem) Op(makeArgs, color, std::forward<OpArgs>(opArgs)...));
+ }
+}
+
+#endif