• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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 "SkTypes.h"
9 
10 #if SK_SUPPORT_GPU
11 
12 #include "GrContextPriv.h"
13 #include "GrPathUtils.h"
14 #include "GrRenderTargetContext.h"
15 #include "GrRenderTargetContextPriv.h"
16 #include "GrResourceProvider.h"
17 #include "SampleCode.h"
18 #include "SkCanvas.h"
19 #include "SkMakeUnique.h"
20 #include "SkPaint.h"
21 #include "SkPath.h"
22 #include "SkRectPriv.h"
23 #include "SkView.h"
24 #include "ccpr/GrCCCoverageProcessor.h"
25 #include "ccpr/GrCCGeometry.h"
26 #include "gl/GrGLGpu.cpp"
27 #include "ops/GrDrawOp.h"
28 
29 using TriPointInstance = GrCCCoverageProcessor::TriPointInstance;
30 using QuadPointInstance = GrCCCoverageProcessor::QuadPointInstance;
31 using RenderPass = GrCCCoverageProcessor::RenderPass;
32 
33 static constexpr float kDebugBloat = 40;
34 
is_quadratic(RenderPass pass)35 static int is_quadratic(RenderPass pass) {
36     return pass == RenderPass::kQuadraticHulls || pass == RenderPass::kQuadraticCorners;
37 }
38 
39 /**
40  * This sample visualizes the AA bloat geometry generated by the ccpr geometry shaders. It
41  * increases the AA bloat by 50x and outputs color instead of coverage (coverage=+1 -> green,
42  * coverage=0 -> black, coverage=-1 -> red). Use the keys 1-7 to cycle through the different
43  * geometry processors.
44  */
45 class CCPRGeometryView : public SampleView {
46 public:
CCPRGeometryView()47     CCPRGeometryView() { this->updateGpuData(); }
48     void onDrawContent(SkCanvas*) override;
49 
50     SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned) override;
51     bool onClick(SampleView::Click*) override;
52     bool onQuery(SkEvent* evt) override;
53 
54 private:
55     class Click;
56     class Op;
57 
updateAndInval()58     void updateAndInval() { this->updateGpuData(); }
59 
60     void updateGpuData();
61 
62     RenderPass fRenderPass = RenderPass::kTriangleHulls;
63     SkCubicType fCubicType;
64     SkMatrix fCubicKLM;
65 
66     SkPoint fPoints[4] = {
67             {100.05f, 100.05f}, {400.75f, 100.05f}, {400.75f, 300.95f}, {100.05f, 300.95f}};
68 
69     SkTArray<TriPointInstance> fTriPointInstances;
70     SkTArray<QuadPointInstance> fQuadPointInstances;
71 
72     typedef SampleView INHERITED;
73 };
74 
75 class CCPRGeometryView::Op : public GrDrawOp {
76     DEFINE_OP_CLASS_ID
77 
78 public:
Op(CCPRGeometryView * view)79     Op(CCPRGeometryView* view) : INHERITED(ClassID()), fView(view) {
80         this->setBounds(SkRectPriv::MakeLargest(), GrOp::HasAABloat::kNo, GrOp::IsZeroArea::kNo);
81     }
82 
name() const83     const char* name() const override { return "[Testing/Sample code] CCPRGeometryView::Op"; }
84 
85 private:
fixedFunctionFlags() const86     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
finalize(const GrCaps &,const GrAppliedClip *,GrPixelConfigIsClamped)87     RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
88                                 GrPixelConfigIsClamped) override {
89         return RequiresDstTexture::kNo;
90     }
onCombineIfPossible(GrOp * other,const GrCaps & caps)91     bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
onPrepare(GrOpFlushState *)92     void onPrepare(GrOpFlushState*) override {}
93     void onExecute(GrOpFlushState*) override;
94 
95     CCPRGeometryView* fView;
96 
97     typedef GrDrawOp INHERITED;
98 };
99 
draw_klm_line(int w,int h,SkCanvas * canvas,const SkScalar line[3],SkColor color)100 static void draw_klm_line(int w, int h, SkCanvas* canvas, const SkScalar line[3], SkColor color) {
101     SkPoint p1, p2;
102     if (SkScalarAbs(line[1]) > SkScalarAbs(line[0])) {
103         // Draw from vertical edge to vertical edge.
104         p1 = {0, -line[2] / line[1]};
105         p2 = {(SkScalar)w, (-line[2] - w * line[0]) / line[1]};
106     } else {
107         // Draw from horizontal edge to horizontal edge.
108         p1 = {-line[2] / line[0], 0};
109         p2 = {(-line[2] - h * line[1]) / line[0], (SkScalar)h};
110     }
111 
112     SkPaint linePaint;
113     linePaint.setColor(color);
114     linePaint.setAlpha(128);
115     linePaint.setStyle(SkPaint::kStroke_Style);
116     linePaint.setStrokeWidth(0);
117     linePaint.setAntiAlias(true);
118     canvas->drawLine(p1, p2, linePaint);
119 }
120 
onDrawContent(SkCanvas * canvas)121 void CCPRGeometryView::onDrawContent(SkCanvas* canvas) {
122     SkAutoCanvasRestore acr(canvas, true);
123     canvas->setMatrix(SkMatrix::I());
124 
125     SkPath outline;
126     outline.moveTo(fPoints[0]);
127     if (GrCCCoverageProcessor::RenderPassIsCubic(fRenderPass)) {
128         outline.cubicTo(fPoints[1], fPoints[2], fPoints[3]);
129     } else if (is_quadratic(fRenderPass)) {
130         outline.quadTo(fPoints[1], fPoints[3]);
131     } else {
132         outline.lineTo(fPoints[1]);
133         outline.lineTo(fPoints[3]);
134         outline.close();
135     }
136 
137     SkPaint outlinePaint;
138     outlinePaint.setColor(0x30000000);
139     outlinePaint.setStyle(SkPaint::kStroke_Style);
140     outlinePaint.setStrokeWidth(0);
141     outlinePaint.setAntiAlias(true);
142     canvas->drawPath(outline, outlinePaint);
143 
144 #if 0
145     SkPaint gridPaint;
146     gridPaint.setColor(0x10000000);
147     gridPaint.setStyle(SkPaint::kStroke_Style);
148     gridPaint.setStrokeWidth(0);
149     gridPaint.setAntiAlias(true);
150     for (int y = 0; y < this->height(); y += kDebugBloat) {
151         canvas->drawLine(0, y, this->width(), y, gridPaint);
152     }
153     for (int x = 0; x < this->width(); x += kDebugBloat) {
154         canvas->drawLine(x, 0, x, this->height(), outlinePaint);
155     }
156 #endif
157 
158     SkString caption;
159     if (GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext()) {
160         rtc->priv().testingOnly_addDrawOp(skstd::make_unique<Op>(this));
161         caption.appendf("RenderPass_%s", GrCCCoverageProcessor::RenderPassName(fRenderPass));
162         if (GrCCCoverageProcessor::RenderPassIsCubic(fRenderPass)) {
163             caption.appendf(" (%s)", SkCubicTypeName(fCubicType));
164         }
165     } else {
166         caption = "Use GPU backend to visualize geometry.";
167     }
168 
169     SkPaint pointsPaint;
170     pointsPaint.setColor(SK_ColorBLUE);
171     pointsPaint.setStrokeWidth(8);
172     pointsPaint.setAntiAlias(true);
173 
174     if (GrCCCoverageProcessor::RenderPassIsCubic(fRenderPass)) {
175         int w = this->width(), h = this->height();
176         canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, fPoints, pointsPaint);
177         draw_klm_line(w, h, canvas, &fCubicKLM[0], SK_ColorYELLOW);
178         draw_klm_line(w, h, canvas, &fCubicKLM[3], SK_ColorBLUE);
179         draw_klm_line(w, h, canvas, &fCubicKLM[6], SK_ColorRED);
180     } else {
181         canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, fPoints, pointsPaint);
182         canvas->drawPoints(SkCanvas::kPoints_PointMode, 1, fPoints + 3, pointsPaint);
183     }
184 
185     SkPaint captionPaint;
186     captionPaint.setTextSize(20);
187     captionPaint.setColor(SK_ColorBLACK);
188     captionPaint.setAntiAlias(true);
189     canvas->drawText(caption.c_str(), caption.size(), 10, 30, captionPaint);
190 }
191 
updateGpuData()192 void CCPRGeometryView::updateGpuData() {
193     fTriPointInstances.reset();
194     fQuadPointInstances.reset();
195 
196     if (GrCCCoverageProcessor::RenderPassIsCubic(fRenderPass)) {
197         double t[2], s[2];
198         fCubicType = GrPathUtils::getCubicKLM(fPoints, &fCubicKLM, t, s);
199         GrCCGeometry geometry;
200         geometry.beginContour(fPoints[0]);
201         geometry.cubicTo(fPoints[1], fPoints[2], fPoints[3], kDebugBloat / 2, kDebugBloat / 2);
202         geometry.endContour();
203         int ptsIdx = 0;
204         for (GrCCGeometry::Verb verb : geometry.verbs()) {
205             switch (verb) {
206                 case GrCCGeometry::Verb::kLineTo:
207                     ++ptsIdx;
208                     continue;
209                 case GrCCGeometry::Verb::kMonotonicQuadraticTo:
210                     ptsIdx += 2;
211                     continue;
212                 case GrCCGeometry::Verb::kMonotonicCubicTo:
213                     fQuadPointInstances.push_back().set(&geometry.points()[ptsIdx], 0, 0);
214                     ptsIdx += 3;
215                     continue;
216                 default:
217                     continue;
218             }
219         }
220     } else if (is_quadratic(fRenderPass)) {
221         GrCCGeometry geometry;
222         geometry.beginContour(fPoints[0]);
223         geometry.quadraticTo(fPoints[1], fPoints[3]);
224         geometry.endContour();
225         int ptsIdx = 0;
226         for (GrCCGeometry::Verb verb : geometry.verbs()) {
227             if (GrCCGeometry::Verb::kBeginContour == verb ||
228                 GrCCGeometry::Verb::kEndOpenContour == verb ||
229                 GrCCGeometry::Verb::kEndClosedContour == verb) {
230                 continue;
231             }
232             if (GrCCGeometry::Verb::kLineTo == verb) {
233                 ++ptsIdx;
234                 continue;
235             }
236             SkASSERT(GrCCGeometry::Verb::kMonotonicQuadraticTo == verb);
237             fTriPointInstances.push_back().set(&geometry.points()[ptsIdx], Sk2f(0, 0));
238             ptsIdx += 2;
239         }
240     } else {
241         fTriPointInstances.push_back().set(fPoints[0], fPoints[1], fPoints[3], Sk2f(0, 0));
242     }
243 }
244 
onExecute(GrOpFlushState * state)245 void CCPRGeometryView::Op::onExecute(GrOpFlushState* state) {
246     GrResourceProvider* rp = state->resourceProvider();
247     GrContext* context = state->gpu()->getContext();
248     GrGLGpu* glGpu = kOpenGL_GrBackend == context->contextPriv().getBackend()
249                              ? static_cast<GrGLGpu*>(state->gpu())
250                              : nullptr;
251 
252     if (!GrCCCoverageProcessor::DoesRenderPass(fView->fRenderPass, state->caps())) {
253         return;
254     }
255 
256     GrCCCoverageProcessor proc(rp, fView->fRenderPass,
257                                GrCCCoverageProcessor::WindMethod::kCrossProduct);
258     SkDEBUGCODE(proc.enableDebugVisualizations(kDebugBloat));
259 
260     SkSTArray<1, GrMesh> mesh;
261     if (GrCCCoverageProcessor::RenderPassIsCubic(fView->fRenderPass)) {
262         sk_sp<GrBuffer> instBuff(rp->createBuffer(
263                 fView->fQuadPointInstances.count() * sizeof(QuadPointInstance),
264                 kVertex_GrBufferType, kDynamic_GrAccessPattern,
265                 GrResourceProvider::kNoPendingIO_Flag | GrResourceProvider::kRequireGpuMemory_Flag,
266                 fView->fQuadPointInstances.begin()));
267         if (!fView->fQuadPointInstances.empty() && instBuff) {
268             proc.appendMesh(instBuff.get(), fView->fQuadPointInstances.count(), 0, &mesh);
269         }
270     } else {
271         sk_sp<GrBuffer> instBuff(rp->createBuffer(
272                 fView->fTriPointInstances.count() * sizeof(TriPointInstance), kVertex_GrBufferType,
273                 kDynamic_GrAccessPattern,
274                 GrResourceProvider::kNoPendingIO_Flag | GrResourceProvider::kRequireGpuMemory_Flag,
275                 fView->fTriPointInstances.begin()));
276         if (!fView->fTriPointInstances.empty() && instBuff) {
277             proc.appendMesh(instBuff.get(), fView->fTriPointInstances.count(), 0, &mesh);
278         }
279     }
280 
281     GrPipeline pipeline(state->drawOpArgs().fProxy, GrPipeline::ScissorState::kDisabled,
282                         SkBlendMode::kSrcOver);
283 
284     if (glGpu) {
285         glGpu->handleDirtyContext();
286         GR_GL_CALL(glGpu->glInterface(), PolygonMode(GR_GL_FRONT_AND_BACK, GR_GL_LINE));
287         GR_GL_CALL(glGpu->glInterface(), Enable(GR_GL_LINE_SMOOTH));
288     }
289 
290     if (!mesh.empty()) {
291         SkASSERT(1 == mesh.count());
292         state->rtCommandBuffer()->draw(pipeline, proc, mesh.begin(), nullptr, 1, this->bounds());
293     }
294 
295     if (glGpu) {
296         context->resetContext(kMisc_GrGLBackendState);
297     }
298 }
299 
300 class CCPRGeometryView::Click : public SampleView::Click {
301 public:
Click(SkView * target,int ptIdx)302     Click(SkView* target, int ptIdx) : SampleView::Click(target), fPtIdx(ptIdx) {}
303 
doClick(SkPoint points[])304     void doClick(SkPoint points[]) {
305         if (fPtIdx >= 0) {
306             this->dragPoint(points, fPtIdx);
307         } else {
308             for (int i = 0; i < 4; ++i) {
309                 this->dragPoint(points, i);
310             }
311         }
312     }
313 
314 private:
dragPoint(SkPoint points[],int idx)315     void dragPoint(SkPoint points[], int idx) {
316         SkIPoint delta = fICurr - fIPrev;
317         points[idx] += SkPoint::Make(delta.x(), delta.y());
318     }
319 
320     int fPtIdx;
321 };
322 
onFindClickHandler(SkScalar x,SkScalar y,unsigned)323 SkView::Click* CCPRGeometryView::onFindClickHandler(SkScalar x, SkScalar y, unsigned) {
324     for (int i = 0; i < 4; ++i) {
325         if (!GrCCCoverageProcessor::RenderPassIsCubic(fRenderPass) && 2 == i) {
326             continue;
327         }
328         if (fabs(x - fPoints[i].x()) < 20 && fabsf(y - fPoints[i].y()) < 20) {
329             return new Click(this, i);
330         }
331     }
332     return new Click(this, -1);
333 }
334 
onClick(SampleView::Click * click)335 bool CCPRGeometryView::onClick(SampleView::Click* click) {
336     Click* myClick = (Click*)click;
337     myClick->doClick(fPoints);
338     this->updateAndInval();
339     return true;
340 }
341 
onQuery(SkEvent * evt)342 bool CCPRGeometryView::onQuery(SkEvent* evt) {
343     if (SampleCode::TitleQ(*evt)) {
344         SampleCode::TitleR(evt, "CCPRGeometry");
345         return true;
346     }
347     SkUnichar unichar;
348     if (SampleCode::CharQ(*evt, &unichar)) {
349         if (unichar >= '1' && unichar <= '7') {
350             fRenderPass = RenderPass(unichar - '1');
351             this->updateAndInval();
352             return true;
353         }
354         if (unichar == 'D') {
355             SkDebugf("    SkPoint fPoints[4] = {\n");
356             SkDebugf("        {%ff, %ff},\n", fPoints[0].x(), fPoints[0].y());
357             SkDebugf("        {%ff, %ff},\n", fPoints[1].x(), fPoints[1].y());
358             SkDebugf("        {%ff, %ff},\n", fPoints[2].x(), fPoints[2].y());
359             SkDebugf("        {%ff, %ff}\n", fPoints[3].x(), fPoints[3].y());
360             SkDebugf("    };\n");
361             return true;
362         }
363     }
364     return this->INHERITED::onQuery(evt);
365 }
366 
367 DEF_SAMPLE(return new CCPRGeometryView;)
368 
369 #endif  // SK_SUPPORT_GPU
370