1 /*
2 * Copyright 2014 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 "SkCanvas.h"
9 #include "SkCanvasPriv.h"
10 #include "SkMultiPictureDraw.h"
11 #include "SkPicture.h"
12 #include "SkTaskGroup.h"
13
draw()14 void SkMultiPictureDraw::DrawData::draw() {
15 fCanvas->drawPicture(fPicture, &fMatrix, fPaint);
16 }
17
init(SkCanvas * canvas,const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)18 void SkMultiPictureDraw::DrawData::init(SkCanvas* canvas, const SkPicture* picture,
19 const SkMatrix* matrix, const SkPaint* paint) {
20 fPicture = SkRef(picture);
21 fCanvas = canvas;
22 if (matrix) {
23 fMatrix = *matrix;
24 } else {
25 fMatrix.setIdentity();
26 }
27 if (paint) {
28 fPaint = new SkPaint(*paint);
29 } else {
30 fPaint = nullptr;
31 }
32 }
33
Reset(SkTDArray<DrawData> & data)34 void SkMultiPictureDraw::DrawData::Reset(SkTDArray<DrawData>& data) {
35 for (int i = 0; i < data.count(); ++i) {
36 data[i].fPicture->unref();
37 delete data[i].fPaint;
38 }
39 data.rewind();
40 }
41
42 //////////////////////////////////////////////////////////////////////////////////////
43
SkMultiPictureDraw(int reserve)44 SkMultiPictureDraw::SkMultiPictureDraw(int reserve) {
45 if (reserve > 0) {
46 fGPUDrawData.setReserve(reserve);
47 fThreadSafeDrawData.setReserve(reserve);
48 }
49 }
50
reset()51 void SkMultiPictureDraw::reset() {
52 DrawData::Reset(fGPUDrawData);
53 DrawData::Reset(fThreadSafeDrawData);
54 }
55
add(SkCanvas * canvas,const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)56 void SkMultiPictureDraw::add(SkCanvas* canvas,
57 const SkPicture* picture,
58 const SkMatrix* matrix,
59 const SkPaint* paint) {
60 if (nullptr == canvas || nullptr == picture) {
61 SkDEBUGFAIL("parameters to SkMultiPictureDraw::add should be non-nullptr");
62 return;
63 }
64
65 SkTDArray<DrawData>& array = canvas->getGrContext() ? fGPUDrawData : fThreadSafeDrawData;
66 array.append()->init(canvas, picture, matrix, paint);
67 }
68
69 class AutoMPDReset : SkNoncopyable {
70 SkMultiPictureDraw* fMPD;
71 public:
AutoMPDReset(SkMultiPictureDraw * mpd)72 AutoMPDReset(SkMultiPictureDraw* mpd) : fMPD(mpd) {}
~AutoMPDReset()73 ~AutoMPDReset() { fMPD->reset(); }
74 };
75
76 //#define FORCE_SINGLE_THREAD_DRAWING_FOR_TESTING
77
draw(bool flush)78 void SkMultiPictureDraw::draw(bool flush) {
79 AutoMPDReset mpdreset(this);
80
81 #ifdef FORCE_SINGLE_THREAD_DRAWING_FOR_TESTING
82 for (int i = 0; i < fThreadSafeDrawData.count(); ++i) {
83 fThreadSafeDrawData[i].draw();
84 }
85 #else
86 SkTaskGroup().batch(fThreadSafeDrawData.count(), [&](int i) {
87 fThreadSafeDrawData[i].draw();
88 });
89 #endif
90
91 // N.B. we could get going on any GPU work from this main thread while the CPU work runs.
92 // But in practice, we've either got GPU work or CPU work, not both.
93
94 const int count = fGPUDrawData.count();
95 if (0 == count) {
96 return;
97 }
98
99 for (int i = 0; i < count; ++i) {
100 const DrawData& data = fGPUDrawData[i];
101 SkCanvas* canvas = data.fCanvas;
102 const SkPicture* picture = data.fPicture;
103
104 canvas->drawPicture(picture, &data.fMatrix, data.fPaint);
105 if (flush) {
106 canvas->flush();
107 }
108 }
109 }
110