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