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