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