• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can
5  * be found in the LICENSE file.
6  */
7 
8 //
9 // C++
10 //
11 
12 #include "SkDevice_Compute.h"
13 
14 //
15 //
16 //
17 
18 #if SK_SUPPORT_GPU_COMPUTE
19 
20 //
21 // C++
22 //
23 
24 #include "SkImageInfo.h"
25 #include "SkDraw.h"
26 #include "SkMatrix.h"
27 #include "SkPath.h"
28 
29 //
30 // C
31 //
32 
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 
37 #include "../spinel/spinel/color.h"
38 #include "../compute/skc/skc.h"
39 
40 #ifdef __cplusplus
41 }
42 #endif
43 
44 //
45 //
46 //
47 
SkDevice_Compute(sk_sp<SkContext_Compute> compute,int w,int h)48 SkDevice_Compute::SkDevice_Compute(sk_sp<SkContext_Compute> compute, int w, int h)
49     : SkClipStackDevice(SkImageInfo::MakeN32Premul(w,h), SkSurfaceProps(0,kUnknown_SkPixelGeometry))
50     , fCompute(std::move(compute))
51 {
52   fTopCTM = this->ctm();
53   fTransformWeakref = SKC_WEAKREF_INVALID;
54 
55   fClipWeakref = SKC_WEAKREF_INVALID;
56 
57   skc_err err;
58 
59   //
60   // create a composition
61   //
62 #define LAYER_COUNT (1<<14)
63 
64   err = skc_composition_create(fCompute->context, &fComposition);
65   SKC_ERR_CHECK(err);
66 
67     // Is this correct?
68     int clipRect[] = { 0, 0, w - 1, h - 1 };
69   err = skc_composition_clip_set(fComposition, clipRect);
70   SKC_ERR_CHECK(err);
71 
72   //
73   // create styling
74   //
75   err = skc_styling_create(fCompute->context,
76                            LAYER_COUNT,
77                            10,
78                            2 * 1024 * 1024,
79                            &fStyling);
80 
81   //
82   // create a path builder
83   //
84   err = skc_path_builder_create(fCompute->context, &fPB);
85   SKC_ERR_CHECK(err);
86 
87   //
88   // create a raster builder
89   //
90   err = skc_raster_builder_create(fCompute->context, &fRB);
91   SKC_ERR_CHECK(err);
92 
93   //
94   // create the simplest styling group that encloses all layers
95   //
96   styling_group_init();
97 }
98 
99 
100 //
101 //
102 //
103 
~SkDevice_Compute()104 SkDevice_Compute::~SkDevice_Compute() {
105     skc_err err;
106 
107     err = skc_raster_builder_release(fRB);
108     SKC_ERR_CHECK(err);
109 
110     err = skc_path_builder_release(fPB);
111     SKC_ERR_CHECK(err);
112 
113     err = skc_styling_dispose(fStyling);
114     SKC_ERR_CHECK(err);
115 
116     err = skc_composition_dispose(fComposition);
117     SKC_ERR_CHECK(err);
118 }
119 
120 //
121 //
122 //
123 
flush()124 void SkDevice_Compute::flush() {
125     //
126     // seal the styling and composition objects
127     //
128     skc_err err;
129 
130     err = skc_composition_seal(fComposition);
131     SKC_ERR_CHECK(err);
132 
133     err = skc_styling_seal(fStyling);
134     SKC_ERR_CHECK(err);
135 
136     //
137     // we're going to block here -- API mismatch
138     //
139 
140     //
141     // render to surface
142     //
143     // note this implicitly seals composition and styling
144     //
145     err = skc_surface_render(fCompute->surface, fComposition, fStyling);
146     SKC_ERR_CHECK(err);
147 
148     //
149     // kick off pipeline and wait here -- not needed since skc_surface_reset() blocks
150     //
151     err = skc_surface_wait(fCompute->surface);
152     SKC_ERR_CHECK(err);
153 
154     //
155     // reset the surface -- implicitly waits for render to finish -- FIXME -- composition might be released too early
156     //
157     err = skc_surface_reset(fCompute->surface);
158     SKC_ERR_CHECK(err);
159 
160     //
161     // reset composition and styling
162     //
163     err = skc_composition_reset(fComposition);
164     SKC_ERR_CHECK(err);
165 
166     err = skc_styling_reset(fStyling);
167     SKC_ERR_CHECK(err);
168 
169     //
170     //
171     //
172     styling_group_init();
173 }
174 
175 //
176 //
177 //
178 
179 #define SKC_STYLING_CMDS(...) SK_ARRAY_COUNT(__VA_ARGS__),__VA_ARGS__
180 #define SKC_GROUP_IDS(...)    SK_ARRAY_COUNT(__VA_ARGS__),__VA_ARGS__
181 
styling_group_init()182 void SkDevice_Compute::styling_group_init() {
183     skc_styling_group_alloc(fStyling, &fGroupID);
184     fParents.push_back(fGroupID);
185 
186     // ENTER
187     skc_styling_cmd_t const styling_cmds_enter[] = {
188         SKC_STYLING_CMD_OP_COVER_ZERO_ACC,
189         SKC_STYLING_CMD_OP_COLOR_ZERO_ACC | SKC_STYLING_CMD_OP_IS_FINAL
190     };
191     skc_styling_group_enter(fStyling, fGroupID, SKC_STYLING_CMDS(styling_cmds_enter));
192 
193     skc_group_id const group_id_parents[] = { fGroupID };
194     skc_styling_group_parents(fStyling, fGroupID, SKC_GROUP_IDS(group_id_parents));
195 
196     // RANGE
197     skc_styling_group_range_lo(fStyling, fGroupID, 0);
198     skc_styling_group_range_hi(fStyling, fGroupID, LAYER_COUNT-1);
199 
200     // LEAVE
201     skc_styling_cmd_t const styling_cmds_leave[] = {
202         SKC_STYLING_CMD_OP_SURFACE_COMPOSITE | SKC_STYLING_CMD_OP_IS_FINAL
203     };
204     skc_styling_group_leave(fStyling, fGroupID, SKC_STYLING_CMDS(styling_cmds_leave));
205 
206     // START
207     fGroupLayerID = LAYER_COUNT-1;
208 }
209 
210 //
211 //
212 //
213 
214 #define SK_SCALE_F32      (1.0f/255.0f)
215 #define SK_TO_RGBA_F32(c) { SK_SCALE_F32 * SkColorGetR(c),      \
216                             SK_SCALE_F32 * SkColorGetG(c),      \
217                             SK_SCALE_F32 * SkColorGetB(c),      \
218                             SK_SCALE_F32 * SkColorGetA(c) }
219 //
220 //
221 //
222 
path_rasterize_and_place(const SkPaint & paint,const skc_path_t path,const SkMatrix * prePathMatrix)223 void SkDevice_Compute::path_rasterize_and_place(const SkPaint&   paint,
224                                                 const skc_path_t path,
225                                                 const SkMatrix*  prePathMatrix) {
226     float transform[9];
227     const SkMatrix& ctm = fTopCTM;
228     SkMatrix tmp;
229 
230     if (prePathMatrix) {
231         tmp.setConcat(ctm, *prePathMatrix);
232     }
233     transform[0] = tmp.get(SkMatrix::kMScaleX);
234     transform[1] = tmp.get(SkMatrix::kMSkewX );
235     transform[2] = tmp.get(SkMatrix::kMTransX);
236     transform[3] = tmp.get(SkMatrix::kMSkewY );
237     transform[4] = tmp.get(SkMatrix::kMScaleY);
238     transform[5] = tmp.get(SkMatrix::kMTransY);
239     transform[6] = tmp.get(SkMatrix::kMPersp0);
240     transform[7] = tmp.get(SkMatrix::kMPersp1);
241     transform[8] = tmp.get(SkMatrix::kMPersp2);
242 
243     skc_transform_weakref_t& transform_weakref = fTransformWeakref;
244     //
245 
246     // always invalid for now
247     //
248     skc_raster_clip_weakref_t clip_weakref = fClipWeakref;
249 
250     // TODO Support arbitrary path clip?
251     SkRect devClip = SkRect::Make(this->devClipBounds());
252     const float clip[] = { devClip.fLeft, devClip.fTop, devClip.fRight, devClip.fBottom };
253 
254     //
255     //
256     //
257     skc_err      err;
258     skc_raster_t raster;
259 
260     err = skc_raster_begin(fRB);
261     err = skc_raster_add_filled(fRB, path, &transform_weakref, transform, &clip_weakref, clip);
262     err = skc_raster_end(fRB, &raster);
263 
264     //
265     // can release path handle now because it is being referenced by raster
266     //
267     err = skc_path_release(fCompute->context, path);
268 
269     //
270     // style the path
271     //
272     skc_styling_cmd_t cmds[1 + 3 + 1];
273 
274     cmds[0]                      = SKC_STYLING_CMD_OP_COVER_NONZERO;
275     cmds[SK_ARRAY_COUNT(cmds)-1] = SKC_STYLING_CMD_OP_BLEND_OVER | SKC_STYLING_CMD_OP_IS_FINAL;
276 
277     {
278         SkColor4f rgba = paint.getColor4f().premul();
279 
280         skc_styling_layer_fill_solid_encoder(cmds+1, rgba.vec());
281 
282         skc_styling_group_layer(fStyling, fGroupID, fGroupLayerID, SKC_STYLING_CMDS(cmds));
283     }
284 
285     err = skc_composition_place(fComposition, fGroupLayerID, raster, 0, 0);
286 
287     //
288     // can release raster handle now because it is being referenced by composition
289     //
290     err = skc_raster_release(fCompute->context, raster);
291 
292     SkASSERT(err == SKC_ERR_SUCCESS);
293 
294     fGroupLayerID -= 1;
295 }
296 
297 //
298 //
299 //
300 
path_add(const SkPaint & paint,const SkPath & path,const SkMatrix * prePathMatrix)301 void SkDevice_Compute::path_add(const SkPaint&  paint,
302                                 const SkPath&   path,
303                                 const SkMatrix* prePathMatrix) {
304   skc_err err;
305 
306   err = skc_path_begin(fPB);
307 
308 #if 0
309   SkPath::Iter    pi(path,false);
310 #else
311   SkPath::RawIter pi(path); // this seems to work fine for now
312 #endif
313 
314   SkPoint xy0;
315 
316   //
317   // build path
318   //
319   while (true)
320     {
321       SkPoint            pts[4];
322       SkPath::Verb const verb = pi.next(pts);
323 
324       switch (verb)
325         {
326         case SkPath::kMove_Verb:
327 	  xy0 = pts[0];
328           err = skc_path_move_to(fPB,
329                                  pts[0].x(),pts[0].y());
330           continue;
331 
332         case SkPath::kLine_Verb:
333           err = skc_path_line_to(fPB,
334                                  pts[1].x(),pts[1].y());
335           continue;
336 
337         case SkPath::kQuad_Verb:
338           err = skc_path_quad_to(fPB,
339                                  pts[1].x(),pts[1].y(),
340                                  pts[2].x(),pts[2].y());
341           continue;
342 
343         case SkPath::kConic_Verb: // <--------------------- FIXME
344           err = skc_path_line_to(fPB,
345                                  pts[2].x(),pts[2].y());
346           continue;
347 
348         case SkPath::kCubic_Verb:
349           err = skc_path_cubic_to(fPB,
350                                   pts[1].x(),pts[1].y(),
351                                   pts[2].x(),pts[2].y(),
352                                   pts[3].x(),pts[3].y());
353           continue;
354 
355         case SkPath::kClose_Verb:
356           err = skc_path_line_to(fPB,xy0.x(),xy0.y());
357           continue;
358 
359         case SkPath::kDone_Verb:
360           break;
361         }
362 
363       //
364       // otherwise, kDone_Verb breaks out of while loop
365       //
366       break;
367     }
368 
369   //
370   // seal the path
371   //
372   skc_path_t skc_path;
373 
374   err = skc_path_end(fPB,&skc_path);
375 
376   //
377   // rasterize the path and place it in a composition
378   //
379   path_rasterize_and_place(paint,skc_path,prePathMatrix);
380 
381   SkASSERT(err == SKC_ERR_SUCCESS);
382 }
383 
384 //
385 //
386 //
387 
388 void
circles_add(const SkPaint & paint,const SkPoint points[],int32_t const count,SkScalar const radius)389 SkDevice_Compute::circles_add(
390 			      const SkPaint  & paint,
391 			      const SkPoint    points[],
392 			      int32_t  const   count,
393 			      SkScalar const   radius)
394 {
395 #define CIRCLE_KAPPA    0.55228474983079339840f // moar digits!
396 
397 #define CIRCLE_RADIUS_X radius
398 #define CIRCLE_RADIUS_Y radius
399 
400 #define CIRCLE_KAPPA_X  (CIRCLE_RADIUS_X * CIRCLE_KAPPA)
401 #define CIRCLE_KAPPA_Y  (CIRCLE_RADIUS_Y * CIRCLE_KAPPA)
402 
403   //
404   // use a 4 Bezier approximation
405   //
406   float const circle[] =
407     {
408       0.0f,             +CIRCLE_RADIUS_Y,   // move_to
409 
410       +CIRCLE_KAPPA_X,  +CIRCLE_RADIUS_Y,   // cubic_to
411       +CIRCLE_RADIUS_X, +CIRCLE_KAPPA_Y,
412       +CIRCLE_RADIUS_X,  0.0f,
413 
414       +CIRCLE_RADIUS_X, -CIRCLE_KAPPA_Y,    // cubic_to
415       +CIRCLE_KAPPA_X,  -CIRCLE_RADIUS_Y,
416       0.0f,             -CIRCLE_RADIUS_Y,
417 
418       -CIRCLE_KAPPA_X,  -CIRCLE_RADIUS_Y,   // cubic_to
419       -CIRCLE_RADIUS_X, -CIRCLE_KAPPA_Y,
420       -CIRCLE_RADIUS_X, 0.0f,
421 
422       -CIRCLE_RADIUS_X, +CIRCLE_KAPPA_Y,    // cubic_to
423       -CIRCLE_KAPPA_X,  +CIRCLE_RADIUS_Y,
424       0.0f,             +CIRCLE_RADIUS_Y
425     };
426 
427 #define CXLAT(x,y,t) circle[x]+t.fX,circle[y]+t.fY
428 
429   //
430   //
431   //
432 
433   skc_err err;
434 
435   err = skc_path_begin(fPB);
436 
437   //
438   //
439   //
440   for (int32_t ii=0; ii<count; ii++)
441     {
442       SkPoint const p = points[ii];
443 
444       err = skc_path_move_to(fPB,
445 			     CXLAT(0,1,p));
446 
447       err = skc_path_cubic_to(fPB,
448 			      CXLAT(2,3,p),
449 			      CXLAT(4,5,p),
450 			      CXLAT(6,7,p));
451 
452       err = skc_path_cubic_to(fPB,
453 			      CXLAT(8, 9,p),
454 			      CXLAT(10,11,p),
455 			      CXLAT(12,13,p));
456 
457       err = skc_path_cubic_to(fPB,
458 			      CXLAT(14,15,p),
459 			      CXLAT(16,17,p),
460 			      CXLAT(18,19,p));
461 
462       err = skc_path_cubic_to(fPB,
463 			      CXLAT(20,21,p),
464 			      CXLAT(22,23,p),
465 			      CXLAT(24,25,p));
466     }
467 
468   //
469   // seal the path
470   //
471   skc_path_t skc_path;
472 
473   err = skc_path_end(fPB,&skc_path);
474 
475   //
476   // rasterize the path and place it in a composition
477   //
478   path_rasterize_and_place(paint,skc_path,NULL);
479 
480   SkASSERT(err == SKC_ERR_SUCCESS);
481 }
482 
483 //
484 //
485 //
486 
487 void
squares_add(const SkPaint & paint,const SkPoint points[],int32_t const count,SkScalar const radius)488 SkDevice_Compute::squares_add(
489 			      const SkPaint  & paint,
490 			      const SkPoint    points[],
491 			      int32_t  const   count,
492 			      SkScalar const   radius)
493 {
494   float const square[] =
495     {
496       -radius,+radius, // move_to
497       +radius,+radius, // line_to
498       +radius,-radius, // line_to
499       -radius,-radius, // line_to
500       -radius,+radius  // line_to
501     };
502 
503 #define SXLAT(x,y,t) square[x]+t.fX,square[y]+t.fY
504 
505   //
506   //
507   //
508 
509   skc_err err;
510 
511   err = skc_path_begin(fPB);
512 
513   //
514   //
515   //
516   for (int32_t ii=0; ii<count; ii++)
517     {
518       SkPoint const p = points[ii];
519 
520       err = skc_path_move_to(fPB,SXLAT(0,1,p));
521       err = skc_path_line_to(fPB,SXLAT(2,3,p));
522       err = skc_path_line_to(fPB,SXLAT(4,5,p));
523       err = skc_path_line_to(fPB,SXLAT(6,7,p));
524       err = skc_path_line_to(fPB,SXLAT(8,9,p));
525     }
526 
527   //
528   // seal the path
529   //
530   skc_path_t skc_path;
531 
532   err = skc_path_end(fPB,&skc_path);
533 
534   //
535   // rasterize the path and place it in a composition
536   //
537   path_rasterize_and_place(paint,skc_path,NULL);
538 
539   SkASSERT(err == SKC_ERR_SUCCESS);
540 }
541 
542 //
543 // FIXME -- THIS IS NOT CORRECT
544 //
545 // Need to implement butt, round, square caps
546 //
547 
548 void
line_stroked_butt(SkPoint const xy0,SkPoint const xy1,SkScalar const radius)549 SkDevice_Compute::line_stroked_butt(SkPoint  const xy0,
550 				    SkPoint  const xy1,
551 				    SkScalar const radius)
552 {
553   float const dx    = xy1.fX - xy0.fX;
554   float const dy    = xy1.fY - xy0.fY;
555 
556   float const hypot = hypotf(dx,dy);
557 
558   // FIXME -- what's practical here?
559   if (hypot == 0.0f)
560     return;
561 
562   float const scale = radius / hypot;
563 
564   float const rx    = dy * scale;
565   float const ry    = dx * scale;
566 
567   skc_err err;
568 
569   err = skc_path_move_to(fPB,xy0.fX-rx,xy0.fY+ry);
570   err = skc_path_line_to(fPB,xy1.fX-rx,xy1.fY+ry);
571   err = skc_path_line_to(fPB,xy1.fX+rx,xy1.fY-ry);
572   err = skc_path_line_to(fPB,xy0.fX+rx,xy0.fY-ry);
573   err = skc_path_line_to(fPB,xy0.fX-rx,xy0.fY+ry);
574 
575   SkASSERT(err == SKC_ERR_SUCCESS);
576 }
577 
578 void
lines_stroked_add(const SkPaint & paint,const SkPoint points[],int32_t const count,SkScalar const radius)579 SkDevice_Compute::lines_stroked_add(
580 				    const SkPaint  & paint,
581 				    const SkPoint    points[],
582 				    int32_t  const   count,
583 				    SkScalar const   radius)
584 {
585   skc_err err;
586 
587   err = skc_path_begin(fPB);
588 
589   //
590   //
591   //
592   for (int32_t ii=0; ii<count; ii+=2)
593     line_stroked_butt(points[ii],points[ii+1],radius);
594 
595   //
596   // seal the path
597   //
598   skc_path_t skc_path;
599 
600   err = skc_path_end(fPB,&skc_path);
601 
602   //
603   // rasterize the path and place it in a composition
604   //
605   path_rasterize_and_place(paint,skc_path,NULL);
606 
607   SkASSERT(err == SKC_ERR_SUCCESS);
608 }
609 
610 
611 //
612 //
613 //
614 
615 //  drawPaint is really just a short-cut for drawRect(wide_open, paint)
616 //  so we have to respect everything (but stroking and maskfilter) in the paint
617 //  - color | shader
618 //  - colorFilter
619 //  - blendmode
620 //  - etc.
drawPaint(const SkPaint & paint)621 void SkDevice_Compute::drawPaint(const SkPaint& paint) {
622   //
623   // clear the surface -- will be postponed until render is complete
624   //
625   SkColor const c       = paint.getColor();
626   float         rgba[4] = SK_TO_RGBA_F32(c);
627 
628   skc_surface_clear(fCompute->surface,rgba);
629 }
630 
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint points[],const SkPaint & paint)631 void SkDevice_Compute::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint points[],
632                                   const SkPaint& paint) {
633     if (count == 0) {
634         return;
635     }
636 
637     const SkScalar radius = paint.getStrokeWidth() * 0.5f;
638 
639     /*
640      *  drawPoints draws each element (point, line) separately. This means our bulk-adding into the
641      *  same raster is not valid for most blendmodes.
642      */
643     switch (mode) {
644         case SkCanvas::kPoints_PointMode: {
645             if (paint.getStrokeCap() == SkPaint::kRound_Cap) {
646                 circles_add(paint, points, (int32_t)count, radius);
647             } else {
648                 squares_add(paint, points,(int32_t)count, radius);
649             }
650         } break;
651 
652         case SkCanvas::kLines_PointMode: {
653             if (count <= 1) {
654                 return;
655             }
656             lines_stroked_add(paint, points, (int32_t)count & ~1, radius);
657         } break;
658 
659         case SkCanvas::kPolygon_PointMode: {
660             SkPoint xy0 = points[0];
661             skc_err err = skc_path_begin(fPB);
662 
663             for (size_t i = 0; i < count; ++i) {
664                 const SkPoint xy1 = points[i];
665                 line_stroked_butt(xy0, xy1, radius);
666                 xy0 = xy1;
667             }
668 
669             //
670             // seal the path
671             //
672             skc_path_t skc_path;
673             err = skc_path_end(fPB, &skc_path);
674 
675             //
676             // rasterize the path and place it in a composition
677             //
678             path_rasterize_and_place(paint, skc_path, nullptr);
679 
680             SkASSERT(err == SKC_ERR_SUCCESS);
681         } break;
682 
683         default:
684             break;
685     }
686 }
687 
drawRect(const SkRect & rect,const SkPaint & paint)688 void SkDevice_Compute::drawRect(const SkRect& rect, const SkPaint& paint) {
689     SkPath path;
690 
691     path.addRect(rect);
692     this->drawPath(path, paint, nullptr, true);
693 }
694 
drawOval(const SkRect & oval,const SkPaint & paint)695 void SkDevice_Compute::drawOval(const SkRect& oval, const SkPaint& paint) {
696     SkPath path;
697 
698     path.addOval(oval);
699     this->drawPath(path, paint, nullptr, true);
700 }
701 
drawRRect(const SkRRect & rrect,const SkPaint & paint)702 void SkDevice_Compute::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
703     SkPath path;
704 
705     path.addRRect(rrect);
706     this->drawPath(path, paint, nullptr, true);
707 }
708 
drawPath(const SkPath & path,const SkPaint & paint,const SkMatrix * prePathMatrix,bool pathIsMutable)709 void SkDevice_Compute::drawPath(const SkPath& path, const SkPaint& paint,
710                                 const SkMatrix* prePathMatrix, bool pathIsMutable) {
711   if (paint.getStyle() == SkPaint::kFill_Style) {
712       path_add(paint,path,prePathMatrix);
713   } else {
714       SkPath stroked;
715 
716 #define SK_MAGIC_RES_SCALE 1024
717 
718         paint.getFillPath(path, &stroked, nullptr, SK_MAGIC_RES_SCALE);
719         this->path_add(paint, stroked, prePathMatrix);
720     }
721 }
722 
drawText(const void * text,size_t length,SkScalar x,SkScalar y,const SkPaint & paint)723 void SkDevice_Compute::drawText(const void*    text,
724                                 size_t         length,
725                                 SkScalar       x,
726                                 SkScalar       y,
727                                 const SkPaint& paint) {
728     SkPath outline;
729 
730     paint.getTextPath(text,length,x,y,&outline);
731     this->drawPath(outline, paint, nullptr, true);
732 }
733 
734 void
drawPosText(const void * text,size_t length,const SkScalar pos[],int scalarsPerPos,const SkPoint & offset,const SkPaint & paint)735 SkDevice_Compute::drawPosText(const void     * text,
736                               size_t           length,
737                               const SkScalar   pos[],
738                               int              scalarsPerPos,
739                               const SkPoint  & offset,
740                               const SkPaint  & paint)
741 {
742 #if 0
743   draw.drawPosText_asPaths((const char *)text,length,
744 			   pos,scalarsPerPos,offset,paint);
745 #endif
746 }
747 
onCreateDevice(const CreateInfo & cinfo,const SkPaint * paint)748 SkBaseDevice* SkDevice_Compute::onCreateDevice(const CreateInfo& cinfo, const SkPaint* paint) {
749 #ifdef SK_USE_COMPUTE_LAYER_GROUP
750     return this->createLayerGroup(cinfo, paint);
751 #else
752     // TODO return a new SkDevice_Compute when SkDevice_ComputeLayerGroup doesn't work
753     return nullptr;
754 #endif
755 }
756 
drawDevice(SkBaseDevice * device,int left,int top,const SkPaint & paint)757 void SkDevice_Compute::drawDevice(SkBaseDevice* device, int left, int top, const SkPaint& paint) {
758     // It seems that we won't support image filter until snapSpecial and drawSpecial are implemented
759     // (SkCanvas.cpp will call drawSpecial when the paint has an image filter).
760     SkASSERT(!paint.getImageFilter());
761 
762 #ifdef SK_USE_COMPUTE_LAYER_GROUP
763     // In case of SkDevice_ComputeLayerGroup, we close the group
764     SkDevice_ComputeLayerGroup* layerDevice = static_cast<SkDevice_ComputeLayerGroup*>(device);
765     SkASSERT(layerDevice->fRoot == this); // the layerDevice should belong to this root device
766     SkASSERT(layerDevice->fGroupID == fGroupID); // the layerDevice should be the top device
767 
768     // left, top should be the same as the origin,
769     // and we can ignore them because we have no offscreen buffer.
770     SkASSERT(SkIPoint::Make(left, top) == device->getOrigin());
771 
772     // close the group and pop the top device
773     skc_styling_group_range_lo(fStyling, fGroupID, fGroupLayerID + 1);
774     fGroupID = fParents.back();
775     fParents.pop_back();
776 #else
777     // TODO handle the case where the device is a SkDevice_Compute rather than
778     // SkDevice_ComputeLayerGroup (in which case an offscreen buffer is created).
779 #endif
780 }
781 
782 #ifdef SK_USE_COMPUTE_LAYER_GROUP
783 
createLayerGroup(const CreateInfo & cinfo,const SkPaint * paint)784 SkDevice_ComputeLayerGroup* SkDevice_Compute::createLayerGroup(const CreateInfo& cinfo,
785         const SkPaint* paint) {
786     return new SkDevice_ComputeLayerGroup(this, cinfo, paint);
787 }
788 
onCtmChanged()789 void SkDevice_Compute::onCtmChanged() {
790     fTopCTM = this->ctm();
791     fTransformWeakref = SKC_WEAKREF_INVALID;
792 }
793 
SkDevice_ComputeLayerGroup(SkDevice_Compute * root,const CreateInfo & cinfo,const SkPaint * paint)794 SkDevice_ComputeLayerGroup::SkDevice_ComputeLayerGroup(SkDevice_Compute* root,
795         const CreateInfo& cinfo, const SkPaint* paint)
796         : SkBaseDevice(SkImageInfo::MakeN32Premul(cinfo.fInfo.width(), cinfo.fInfo.height()),
797                        SkSurfaceProps(0,kUnknown_SkPixelGeometry)) {
798     // TODO clip the group using cinfo; handle the paint's alpha and maybe color filter?
799 
800     // Create a new group. We'll restore the previous group during onRestore.
801     skc_styling_group_alloc(fRoot->fStyling, &fRoot->fGroupID);
802     fRoot->fParents.push_back(fRoot->fGroupID);
803     fGroupID = fRoot->fGroupID;
804 
805     // ENTER
806     skc_styling_cmd_t const styling_cmds_enter[] = {
807         SKC_STYLING_CMD_OP_COVER_ZERO_ACC,
808         SKC_STYLING_CMD_OP_COLOR_ZERO_ACC
809     };
810     skc_styling_group_enter(fRoot->fStyling, fRoot->fGroupID, SKC_STYLING_CMDS(styling_cmds_enter));
811 
812     skc_styling_group_parents(fRoot->fStyling, fRoot->fGroupID, fRoot->fParents.count(),
813             fRoot->fParents.begin());
814 
815     // RANGE
816     // We'll set range_lo at restore
817     skc_styling_group_range_hi(fRoot->fStyling, fRoot->fGroupID, fRoot->fGroupLayerID);
818 
819     // LEAVE
820     skc_styling_cmd_t const styling_cmds_leave[] = {
821         SKC_STYLING_CMD_OP_SURFACE_COMPOSITE
822     };
823     skc_styling_group_leave(fRoot->fStyling, fRoot->fGroupID, SKC_STYLING_CMDS(styling_cmds_leave));
824 }
825 
drawDevice(SkBaseDevice * device,int left,int top,const SkPaint & paint)826 void SkDevice_ComputeLayerGroup::drawDevice(SkBaseDevice* device, int left, int top,
827         const SkPaint& paint) {
828     fRoot->drawDevice(device, left, top, paint); // the root will properly close the group
829 }
830 
onCreateDevice(const CreateInfo & cinfo,const SkPaint * paint)831 SkBaseDevice* SkDevice_ComputeLayerGroup::onCreateDevice(const CreateInfo& cinfo,
832         const SkPaint* paint) {
833     return fRoot->createLayerGroup(cinfo, paint);
834 }
835 
onCtmChanged()836 void SkDevice_ComputeLayerGroup::onCtmChanged() {
837     this->sanityCheck();
838 
839     // Cancels the translation as we're not using an offscreen buffer
840     const SkIPoint& origin = this->getOrigin();
841     fRoot->fTopCTM = this->ctm();
842     fRoot->fTopCTM.postTranslate(SkIntToScalar(origin.fX), SkIntToScalar(origin.fY));
843     fRoot->fTransformWeakref = SKC_WEAKREF_INVALID;
844 }
845 
onSave()846 void SkDevice_ComputeLayerGroup::onSave() {
847     this->sanityCheck();
848     fRoot->onSave();
849 }
850 
onRestore()851 void SkDevice_ComputeLayerGroup::onRestore() {
852     this->sanityCheck();
853     fRoot->onRestore();
854 }
855 
onClipRect(const SkRect & rect,SkClipOp op,bool aa)856 void SkDevice_ComputeLayerGroup::onClipRect(const SkRect& rect, SkClipOp op, bool aa) {
857     this->sanityCheck();
858     fRoot->fClipStack.clipRect(rect, fRoot->fTopCTM, op, aa);
859     fRoot->fClipWeakref = SKC_WEAKREF_INVALID;
860 }
861 
onClipRRect(const SkRRect & rrect,SkClipOp op,bool aa)862 void SkDevice_ComputeLayerGroup::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
863     this->sanityCheck();
864     fRoot->fClipStack.clipRRect(rrect, fRoot->fTopCTM, op, aa);
865     fRoot->fClipWeakref = SKC_WEAKREF_INVALID;
866 }
867 
onClipPath(const SkPath & path,SkClipOp op,bool aa)868 void SkDevice_ComputeLayerGroup::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
869     this->sanityCheck();
870     fRoot->fClipStack.clipPath(path, fRoot->fTopCTM, op, aa);
871     fRoot->fClipWeakref = SKC_WEAKREF_INVALID;
872 }
873 
onClipRegion(const SkRegion & deviceRgn,SkClipOp op)874 void SkDevice_ComputeLayerGroup::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) {
875     this->sanityCheck();
876     fRoot->onClipRegion(deviceRgn, op);
877 }
878 
onSetDeviceClipRestriction(SkIRect * mutableClipRestriction)879 void SkDevice_ComputeLayerGroup::onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) {
880     this->sanityCheck();
881     fRoot->onSetDeviceClipRestriction(mutableClipRestriction);
882 }
883 
884 #endif // SK_USE_COMPUTE_LAYER_GROUP
885 
886 #endif
887