blob: c40aa71ec5bc1336c36718d88062a348ad4322fe [file] [log] [blame]
ethannicholas1a1b3ac2015-06-10 12:11:17 -07001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrAALinearizingConvexPathRenderer.h"
ethannicholas1a1b3ac2015-06-10 12:11:17 -07009#include "GrAAConvexTessellator.h"
ethannicholas1a1b3ac2015-06-10 12:11:17 -070010#include "GrContext.h"
11#include "GrDefaultGeoProcFactory.h"
Brian Salomon5ec9def2016-12-20 15:34:05 -050012#include "GrDrawOpTest.h"
ethannicholas1a1b3ac2015-06-10 12:11:17 -070013#include "GrGeometryProcessor.h"
Brian Salomon742e31d2016-12-07 17:06:19 -050014#include "GrOpFlushState.h"
ethannicholas1a1b3ac2015-06-10 12:11:17 -070015#include "GrPathUtils.h"
Brian Salomondad29232016-12-01 16:40:24 -050016#include "GrProcessor.h"
Brian Salomon653f42f2018-07-10 10:07:31 -040017#include "GrRenderTargetContext.h"
18#include "GrShape.h"
bsalomon6663acf2016-05-10 09:14:17 -070019#include "GrStyle.h"
ethannicholas1a1b3ac2015-06-10 12:11:17 -070020#include "SkGeometry.h"
Brian Salomondad29232016-12-01 16:40:24 -050021#include "SkPathPriv.h"
ethannicholas1a1b3ac2015-06-10 12:11:17 -070022#include "SkString.h"
23#include "SkTraceEvent.h"
egdaniele659a582015-11-13 09:55:43 -080024#include "glsl/GrGLSLGeometryProcessor.h"
Brian Salomon89527432016-12-16 09:52:16 -050025#include "ops/GrMeshDrawOp.h"
Brian Salomonb2955732017-07-13 16:42:55 -040026#include "ops/GrSimpleMeshDrawOpHelper.h"
ethannicholas1a1b3ac2015-06-10 12:11:17 -070027
fmalitabd5d7e72015-06-26 07:18:24 -070028static const int DEFAULT_BUFFER_SIZE = 100;
29
30// The thicker the stroke, the harder it is to produce high-quality results using tessellation. For
31// the time being, we simply drop back to software rendering above this stroke width.
32static const SkScalar kMaxStrokeWidth = 20.0;
ethannicholas1a1b3ac2015-06-10 12:11:17 -070033
34GrAALinearizingConvexPathRenderer::GrAALinearizingConvexPathRenderer() {
35}
36
37///////////////////////////////////////////////////////////////////////////////
38
Chris Dalton5ed44232017-09-07 13:22:46 -060039GrPathRenderer::CanDrawPath
40GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050041 if (GrAAType::kCoverage != args.fAAType) {
Chris Dalton5ed44232017-09-07 13:22:46 -060042 return CanDrawPath::kNo;
fmalitabd5d7e72015-06-26 07:18:24 -070043 }
bsalomon8acedde2016-06-24 10:42:16 -070044 if (!args.fShape->knownToBeConvex()) {
Chris Dalton5ed44232017-09-07 13:22:46 -060045 return CanDrawPath::kNo;
fmalitabd5d7e72015-06-26 07:18:24 -070046 }
bsalomon8acedde2016-06-24 10:42:16 -070047 if (args.fShape->style().pathEffect()) {
Chris Dalton5ed44232017-09-07 13:22:46 -060048 return CanDrawPath::kNo;
fmalitabd5d7e72015-06-26 07:18:24 -070049 }
bsalomon8acedde2016-06-24 10:42:16 -070050 if (args.fShape->inverseFilled()) {
Chris Dalton5ed44232017-09-07 13:22:46 -060051 return CanDrawPath::kNo;
bsalomon6663acf2016-05-10 09:14:17 -070052 }
Brian Osmana98e3992017-06-26 15:14:53 -040053 if (args.fShape->bounds().width() <= 0 && args.fShape->bounds().height() <= 0) {
54 // Stroked zero length lines should draw, but this PR doesn't handle that case
Chris Dalton5ed44232017-09-07 13:22:46 -060055 return CanDrawPath::kNo;
Brian Osmana98e3992017-06-26 15:14:53 -040056 }
bsalomon8acedde2016-06-24 10:42:16 -070057 const SkStrokeRec& stroke = args.fShape->style().strokeRec();
robertphillips8c170972016-09-22 12:42:30 -070058
59 if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
60 stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
ethannicholasfea77632015-08-19 12:09:12 -070061 if (!args.fViewMatrix->isSimilarity()) {
Chris Dalton5ed44232017-09-07 13:22:46 -060062 return CanDrawPath::kNo;
ethannicholasfea77632015-08-19 12:09:12 -070063 }
bsalomon6663acf2016-05-10 09:14:17 -070064 SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * stroke.getWidth();
robertphillips8c170972016-09-22 12:42:30 -070065 if (strokeWidth < 1.0f && stroke.getStyle() == SkStrokeRec::kStroke_Style) {
Chris Dalton5ed44232017-09-07 13:22:46 -060066 return CanDrawPath::kNo;
robertphillips8c170972016-09-22 12:42:30 -070067 }
Chris Dalton5ed44232017-09-07 13:22:46 -060068 if (strokeWidth > kMaxStrokeWidth ||
69 !args.fShape->knownToBeClosed() ||
70 stroke.getJoin() == SkPaint::Join::kRound_Join) {
71 return CanDrawPath::kNo;
72 }
73 return CanDrawPath::kYes;
fmalitabd5d7e72015-06-26 07:18:24 -070074 }
Chris Dalton5ed44232017-09-07 13:22:46 -060075 if (stroke.getStyle() != SkStrokeRec::kFill_Style) {
76 return CanDrawPath::kNo;
77 }
78 return CanDrawPath::kYes;
ethannicholas1a1b3ac2015-06-10 12:11:17 -070079}
80
81// extract the result vertices and indices from the GrAAConvexTessellator
82static void extract_verts(const GrAAConvexTessellator& tess,
83 void* vertices,
84 size_t vertexStride,
85 GrColor color,
86 uint16_t firstIndex,
87 uint16_t* idxs,
88 bool tweakAlphaForCoverage) {
89 intptr_t verts = reinterpret_cast<intptr_t>(vertices);
90
91 for (int i = 0; i < tess.numPts(); ++i) {
92 *((SkPoint*)((intptr_t)verts + i * vertexStride)) = tess.point(i);
93 }
94
95 // Make 'verts' point to the colors
96 verts += sizeof(SkPoint);
97 for (int i = 0; i < tess.numPts(); ++i) {
ethannicholas1a1b3ac2015-06-10 12:11:17 -070098 if (tweakAlphaForCoverage) {
fmalitabd5d7e72015-06-26 07:18:24 -070099 SkASSERT(SkScalarRoundToInt(255.0f * tess.coverage(i)) <= 255);
100 unsigned scale = SkScalarRoundToInt(255.0f * tess.coverage(i));
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700101 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
102 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
103 } else {
104 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
mtklein002c2ce2015-08-26 05:43:22 -0700105 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) =
fmalitabd5d7e72015-06-26 07:18:24 -0700106 tess.coverage(i);
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700107 }
108 }
109
110 for (int i = 0; i < tess.numIndices(); ++i) {
111 idxs[i] = tess.index(i) + firstIndex;
112 }
113}
114
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400115static sk_sp<GrGeometryProcessor> create_lines_only_gp(const GrShaderCaps* shaderCaps,
116 bool tweakAlphaForCoverage,
Brian Salomon60fb0b22017-06-15 17:09:36 -0400117 const SkMatrix& viewMatrix,
118 bool usesLocalCoords) {
joshualittdf0c5572015-08-03 11:35:28 -0700119 using namespace GrDefaultGeoProcFactory;
joshualitte494a582015-08-03 09:32:36 -0700120
joshualittdf0c5572015-08-03 11:35:28 -0700121 Coverage::Type coverageType;
Brian Salomon8c852be2017-01-04 10:44:42 -0500122 if (tweakAlphaForCoverage) {
joshualittdf0c5572015-08-03 11:35:28 -0700123 coverageType = Coverage::kSolid_Type;
124 } else {
125 coverageType = Coverage::kAttribute_Type;
126 }
Brian Salomon8c852be2017-01-04 10:44:42 -0500127 LocalCoords::Type localCoordsType =
128 usesLocalCoords ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type;
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400129 return MakeForDeviceSpace(shaderCaps,
130 Color::kPremulGrColorAttribute_Type,
131 coverageType,
132 localCoordsType,
Brian Salomon3de0aee2017-01-29 09:34:17 -0500133 viewMatrix);
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700134}
135
Brian Salomonb2955732017-07-13 16:42:55 -0400136namespace {
137
138class AAFlatteningConvexPathOp final : public GrMeshDrawOp {
139private:
140 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
141
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700142public:
Brian Salomon25a88092016-12-01 09:36:50 -0500143 DEFINE_OP_CLASS_ID
Robert Phillips7c525e62018-06-12 10:11:12 -0400144 static std::unique_ptr<GrDrawOp> Make(GrContext* context,
145 GrPaint&& paint,
Brian Salomonb2955732017-07-13 16:42:55 -0400146 const SkMatrix& viewMatrix,
147 const SkPath& path,
148 SkScalar strokeWidth,
149 SkStrokeRec::Style style,
150 SkPaint::Join join,
151 SkScalar miterLimit,
152 const GrUserStencilSettings* stencilSettings) {
Robert Phillips7c525e62018-06-12 10:11:12 -0400153 return Helper::FactoryHelper<AAFlatteningConvexPathOp>(context, std::move(paint),
154 viewMatrix, path,
Brian Salomonb2955732017-07-13 16:42:55 -0400155 strokeWidth, style, join, miterLimit,
156 stencilSettings);
Brian Salomon780dad12016-12-15 18:08:40 -0500157 }
158
Brian Salomonb2955732017-07-13 16:42:55 -0400159 AAFlatteningConvexPathOp(const Helper::MakeArgs& helperArgs,
160 GrColor color,
Brian Salomon780dad12016-12-15 18:08:40 -0500161 const SkMatrix& viewMatrix,
162 const SkPath& path,
163 SkScalar strokeWidth,
164 SkStrokeRec::Style style,
165 SkPaint::Join join,
Brian Salomonb2955732017-07-13 16:42:55 -0400166 SkScalar miterLimit,
167 const GrUserStencilSettings* stencilSettings)
168 : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage, stencilSettings) {
Brian Salomon780dad12016-12-15 18:08:40 -0500169 fPaths.emplace_back(
170 PathData{color, viewMatrix, path, strokeWidth, style, join, miterLimit});
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700171
bsalomon0432dd62016-06-30 07:19:27 -0700172 // compute bounds
bsalomon88cf17d2016-07-08 06:40:56 -0700173 SkRect bounds = path.getBounds();
bsalomon0432dd62016-06-30 07:19:27 -0700174 SkScalar w = strokeWidth;
175 if (w > 0) {
176 w /= 2;
177 // If the half stroke width is < 1 then we effectively fallback to bevel joins.
178 if (SkPaint::kMiter_Join == join && w > 1.f) {
179 w *= miterLimit;
180 }
bsalomon88cf17d2016-07-08 06:40:56 -0700181 bounds.outset(w, w);
bsalomon0432dd62016-06-30 07:19:27 -0700182 }
bsalomon88cf17d2016-07-08 06:40:56 -0700183 this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kYes, IsZeroArea::kNo);
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700184 }
185
Brian Salomonb2955732017-07-13 16:42:55 -0400186 const char* name() const override { return "AAFlatteningConvexPathOp"; }
187
Robert Phillipsf1748f52017-09-14 14:11:24 -0400188 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsb493eeb2017-09-13 13:10:52 -0400189 fHelper.visitProxies(func);
190 }
191
Brian Salomonb2955732017-07-13 16:42:55 -0400192 SkString dumpInfo() const override {
193 SkString string;
194 for (const auto& path : fPaths) {
195 string.appendf(
196 "Color: 0x%08x, StrokeWidth: %.2f, Style: %d, Join: %d, "
197 "MiterLimit: %.2f\n",
198 path.fColor, path.fStrokeWidth, path.fStyle, path.fJoin, path.fMiterLimit);
199 }
200 string += fHelper.dumpInfo();
201 string += INHERITED::dumpInfo();
202 return string;
Brian Salomon92aee3d2016-12-21 09:20:25 -0500203 }
204
Brian Salomonb2955732017-07-13 16:42:55 -0400205 FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
206
Brian Osman532b3f92018-07-11 10:02:07 -0400207 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
208 return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kSingleChannel,
Brian Salomonb2955732017-07-13 16:42:55 -0400209 &fPaths.back().fColor);
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700210 }
211
Brian Salomonb2955732017-07-13 16:42:55 -0400212private:
Brian Salomon7eae3e02018-08-07 14:02:38 +0000213 void draw(Target* target, sk_sp<const GrGeometryProcessor> gp, const GrPipeline* pipeline,
Brian Salomon49348902018-06-26 09:12:38 -0400214 const GrPipeline::FixedDynamicState* fixedDynamicState, int vertexCount,
215 size_t vertexStride, void* vertices, int indexCount, uint16_t* indices) const {
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700216 if (vertexCount == 0 || indexCount == 0) {
217 return;
218 }
Chris Daltonff926502017-05-03 14:36:54 -0400219 const GrBuffer* vertexBuffer;
Chris Daltonbca46e22017-05-15 11:03:26 -0600220 int firstVertex;
mtklein002c2ce2015-08-26 05:43:22 -0700221 void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer,
Chris Daltonbca46e22017-05-15 11:03:26 -0600222 &firstVertex);
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700223 if (!verts) {
224 SkDebugf("Could not allocate vertices\n");
225 return;
226 }
227 memcpy(verts, vertices, vertexCount * vertexStride);
228
cdalton397536c2016-03-25 12:15:03 -0700229 const GrBuffer* indexBuffer;
Chris Daltonbca46e22017-05-15 11:03:26 -0600230 int firstIndex;
231 uint16_t* idxs = target->makeIndexSpace(indexCount, &indexBuffer, &firstIndex);
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700232 if (!idxs) {
233 SkDebugf("Could not allocate indices\n");
234 return;
235 }
236 memcpy(idxs, indices, indexCount * sizeof(uint16_t));
Brian Salomon7eae3e02018-08-07 14:02:38 +0000237 GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
238 mesh->setIndexed(indexBuffer, indexCount, firstIndex, 0, vertexCount - 1,
239 GrPrimitiveRestart::kNo);
240 mesh->setVertexData(vertexBuffer, firstVertex);
241 target->draw(std::move(gp), pipeline, fixedDynamicState, mesh);
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700242 }
mtklein002c2ce2015-08-26 05:43:22 -0700243
Brian Salomon91326c32017-08-09 16:02:19 -0400244 void onPrepareDraws(Target* target) override {
Brian Salomon49348902018-06-26 09:12:38 -0400245 auto pipe = fHelper.makePipeline(target);
joshualittdf0c5572015-08-03 11:35:28 -0700246 // Setup GrGeometryProcessor
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400247 sk_sp<GrGeometryProcessor> gp(create_lines_only_gp(target->caps().shaderCaps(),
248 fHelper.compatibleWithAlphaAsCoverage(),
Brian Salomonb2955732017-07-13 16:42:55 -0400249 this->viewMatrix(),
250 fHelper.usesLocalCoords()));
joshualittdf0c5572015-08-03 11:35:28 -0700251 if (!gp) {
252 SkDebugf("Couldn't create a GrGeometryProcessor\n");
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700253 return;
254 }
255
Brian Salomon92be2f72018-06-19 14:33:47 -0400256 size_t vertexStride = fHelper.compatibleWithAlphaAsCoverage()
257 ? sizeof(GrDefaultGeoProcFactory::PositionColorAttr)
258 : sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr);
259 SkASSERT(vertexStride == gp->debugOnly_vertexStride());
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700260
Brian Salomon780dad12016-12-15 18:08:40 -0500261 int instanceCount = fPaths.count();
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700262
Greg Danield5b45932018-06-07 13:15:10 -0400263 int64_t vertexCount = 0;
264 int64_t indexCount = 0;
265 int64_t maxVertices = DEFAULT_BUFFER_SIZE;
266 int64_t maxIndices = DEFAULT_BUFFER_SIZE;
mtklein002c2ce2015-08-26 05:43:22 -0700267 uint8_t* vertices = (uint8_t*) sk_malloc_throw(maxVertices * vertexStride);
268 uint16_t* indices = (uint16_t*) sk_malloc_throw(maxIndices * sizeof(uint16_t));
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700269 for (int i = 0; i < instanceCount; i++) {
Brian Salomon780dad12016-12-15 18:08:40 -0500270 const PathData& args = fPaths[i];
robertphillips8c170972016-09-22 12:42:30 -0700271 GrAAConvexTessellator tess(args.fStyle, args.fStrokeWidth,
272 args.fJoin, args.fMiterLimit);
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700273
274 if (!tess.tessellate(args.fViewMatrix, args.fPath)) {
275 continue;
276 }
277
Greg Danield5b45932018-06-07 13:15:10 -0400278 int currentVertices = tess.numPts();
279 if (vertexCount + currentVertices > static_cast<int>(UINT16_MAX)) {
mtklein002c2ce2015-08-26 05:43:22 -0700280 // if we added the current instance, we would overflow the indices we can store in a
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700281 // uint16_t. Draw what we've got so far and reset.
Brian Salomon7eae3e02018-08-07 14:02:38 +0000282 this->draw(target, gp, pipe.fPipeline, pipe.fFixedDynamicState, vertexCount,
Brian Salomon49348902018-06-26 09:12:38 -0400283 vertexStride, vertices, indexCount, indices);
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700284 vertexCount = 0;
285 indexCount = 0;
286 }
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700287 if (vertexCount + currentVertices > maxVertices) {
288 maxVertices = SkTMax(vertexCount + currentVertices, maxVertices * 2);
Greg Danield5b45932018-06-07 13:15:10 -0400289 if (maxVertices * vertexStride > SK_MaxS32) {
290 sk_free(vertices);
291 sk_free(indices);
292 return;
293 }
mtklein002c2ce2015-08-26 05:43:22 -0700294 vertices = (uint8_t*) sk_realloc_throw(vertices, maxVertices * vertexStride);
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700295 }
Greg Danield5b45932018-06-07 13:15:10 -0400296 int currentIndices = tess.numIndices();
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700297 if (indexCount + currentIndices > maxIndices) {
298 maxIndices = SkTMax(indexCount + currentIndices, maxIndices * 2);
Greg Danield5b45932018-06-07 13:15:10 -0400299 if (maxIndices * sizeof(uint16_t) > SK_MaxS32) {
300 sk_free(vertices);
301 sk_free(indices);
302 return;
303 }
mtklein002c2ce2015-08-26 05:43:22 -0700304 indices = (uint16_t*) sk_realloc_throw(indices, maxIndices * sizeof(uint16_t));
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700305 }
306
mtklein002c2ce2015-08-26 05:43:22 -0700307 extract_verts(tess, vertices + vertexStride * vertexCount, vertexStride, args.fColor,
Brian Salomonb2955732017-07-13 16:42:55 -0400308 vertexCount, indices + indexCount,
309 fHelper.compatibleWithAlphaAsCoverage());
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700310 vertexCount += currentVertices;
311 indexCount += currentIndices;
312 }
Greg Danield5b45932018-06-07 13:15:10 -0400313 if (vertexCount <= SK_MaxS32 && indexCount <= SK_MaxS32) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000314 this->draw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, vertexCount,
Brian Salomon49348902018-06-26 09:12:38 -0400315 vertexStride, vertices, indexCount, indices);
Greg Danield5b45932018-06-07 13:15:10 -0400316 }
mtklein002c2ce2015-08-26 05:43:22 -0700317 sk_free(vertices);
318 sk_free(indices);
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700319 }
320
Brian Salomon7eae3e02018-08-07 14:02:38 +0000321 CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
Brian Salomon780dad12016-12-15 18:08:40 -0500322 AAFlatteningConvexPathOp* that = t->cast<AAFlatteningConvexPathOp>();
Brian Salomonb2955732017-07-13 16:42:55 -0400323 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000324 return CombineResult::kCannotCombine;
joshualitt8cab9a72015-07-16 09:13:50 -0700325 }
326
Brian Salomon780dad12016-12-15 18:08:40 -0500327 fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
bsalomon88cf17d2016-07-08 06:40:56 -0700328 this->joinBounds(*that);
Brian Salomon7eae3e02018-08-07 14:02:38 +0000329 return CombineResult::kMerged;
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700330 }
331
Brian Salomon780dad12016-12-15 18:08:40 -0500332 const SkMatrix& viewMatrix() const { return fPaths[0].fViewMatrix; }
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700333
Brian Salomon780dad12016-12-15 18:08:40 -0500334 struct PathData {
bsalomon0432dd62016-06-30 07:19:27 -0700335 GrColor fColor;
336 SkMatrix fViewMatrix;
337 SkPath fPath;
338 SkScalar fStrokeWidth;
robertphillips8c170972016-09-22 12:42:30 -0700339 SkStrokeRec::Style fStyle;
bsalomon0432dd62016-06-30 07:19:27 -0700340 SkPaint::Join fJoin;
341 SkScalar fMiterLimit;
342 };
343
Brian Salomon780dad12016-12-15 18:08:40 -0500344 SkSTArray<1, PathData, true> fPaths;
Brian Salomonb2955732017-07-13 16:42:55 -0400345 Helper fHelper;
reed1b55a962015-09-17 20:16:13 -0700346
Brian Salomonb2955732017-07-13 16:42:55 -0400347 typedef GrMeshDrawOp INHERITED;
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700348};
349
Brian Salomonb2955732017-07-13 16:42:55 -0400350} // anonymous namespace
351
bsalomon0aff2fa2015-07-31 06:48:27 -0700352bool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
Brian Osman11052242016-10-27 14:47:55 -0400353 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
joshualittde83b412016-01-14 09:58:36 -0800354 "GrAALinearizingConvexPathRenderer::onDrawPath");
Brian Salomon7c8460e2017-05-12 11:36:10 -0400355 SkASSERT(GrFSAAType::kUnifiedMSAA != args.fRenderTargetContext->fsaaType());
bsalomon8acedde2016-06-24 10:42:16 -0700356 SkASSERT(!args.fShape->isEmpty());
robertphillips8c170972016-09-22 12:42:30 -0700357 SkASSERT(!args.fShape->style().pathEffect());
csmartdaltonecbc12b2016-06-08 10:08:43 -0700358
bsalomon0432dd62016-06-30 07:19:27 -0700359 SkPath path;
360 args.fShape->asPath(&path);
bsalomon8acedde2016-06-24 10:42:16 -0700361 bool fill = args.fShape->style().isSimpleFill();
362 const SkStrokeRec& stroke = args.fShape->style().strokeRec();
bsalomon0432dd62016-06-30 07:19:27 -0700363 SkScalar strokeWidth = fill ? -1.0f : stroke.getWidth();
364 SkPaint::Join join = fill ? SkPaint::Join::kMiter_Join : stroke.getJoin();
365 SkScalar miterLimit = stroke.getMiter();
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700366
Brian Salomonb2955732017-07-13 16:42:55 -0400367 std::unique_ptr<GrDrawOp> op = AAFlatteningConvexPathOp::Make(
Robert Phillips7c525e62018-06-12 10:11:12 -0400368 args.fContext, std::move(args.fPaint), *args.fViewMatrix, path, strokeWidth,
369 stroke.getStyle(), join, miterLimit, args.fUserStencilSettings);
Brian Salomonb2955732017-07-13 16:42:55 -0400370 args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700371 return true;
372}
373
374///////////////////////////////////////////////////////////////////////////////////////////////////
375
Hal Canary6f6961e2017-01-31 13:50:44 -0500376#if GR_TEST_UTILS
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700377
Brian Salomonb2955732017-07-13 16:42:55 -0400378GR_DRAW_OP_TEST_DEFINE(AAFlatteningConvexPathOp) {
Brian Salomon780dad12016-12-15 18:08:40 -0500379 SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random);
bsalomon0432dd62016-06-30 07:19:27 -0700380 SkPath path = GrTest::TestPathConvex(random);
robertphillips8c170972016-09-22 12:42:30 -0700381
382 SkStrokeRec::Style styles[3] = { SkStrokeRec::kFill_Style,
Herb Derby60c05f92016-12-13 15:18:55 -0500383 SkStrokeRec::kStroke_Style,
robertphillips8c170972016-09-22 12:42:30 -0700384 SkStrokeRec::kStrokeAndFill_Style };
385
386 SkStrokeRec::Style style = styles[random->nextU() % 3];
387
388 SkScalar strokeWidth = -1.f;
bsalomon0432dd62016-06-30 07:19:27 -0700389 SkPaint::Join join = SkPaint::kMiter_Join;
390 SkScalar miterLimit = 0.5f;
robertphillips8c170972016-09-22 12:42:30 -0700391
392 if (SkStrokeRec::kFill_Style != style) {
393 strokeWidth = random->nextRangeF(1.0f, 10.0f);
394 if (random->nextBool()) {
395 join = SkPaint::kMiter_Join;
396 } else {
397 join = SkPaint::kBevel_Join;
398 }
399 miterLimit = random->nextRangeF(0.5f, 2.0f);
400 }
Brian Salomonb2955732017-07-13 16:42:55 -0400401 const GrUserStencilSettings* stencilSettings = GrGetRandomStencil(random, context);
Robert Phillips7c525e62018-06-12 10:11:12 -0400402 return AAFlatteningConvexPathOp::Make(context, std::move(paint), viewMatrix, path, strokeWidth,
403 style, join, miterLimit, stencilSettings);
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700404}
405
406#endif