Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkMultiPictureDraw.cpp
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 // Need to include something before #if SK_SUPPORT_GPU so that the Android
9 // framework build, which gets its defines from SkTypes rather than a makefile,
10 // has the definition before checking it.
11 #include "SkCanvas.h"
12 #include "SkMultiPictureDraw.h"
13 #include "SkPicture.h"
14 #include "SkTaskGroup.h"
15
16 #if SK_SUPPORT_GPU
17 #include "GrLayerHoister.h"
18 #include "GrRecordReplaceDraw.h"
19 #endif
20
21 void SkMultiPictureDraw::DrawData::draw() {
22     fCanvas->drawPicture(fPicture, &fMatrix, fPaint);
23 }
24
25 void SkMultiPictureDraw::DrawData::init(SkCanvas* canvas, const SkPicture* picture,
26                                         const SkMatrix* matrix, const SkPaint* paint) {
27     fPicture = SkRef(picture);
28     fCanvas = SkRef(canvas);
29     if (matrix) {
30         fMatrix = *matrix;
31     } else {
32         fMatrix.setIdentity();
33     }
34     if (paint) {
35         fPaint = SkNEW_ARGS(SkPaint, (*paint));
36     } else {
37         fPaint = NULL;
38     }
39 }
40
41 void SkMultiPictureDraw::DrawData::Reset(SkTDArray<DrawData>& data) {
42     for (int i = 0; i < data.count(); ++i) {
43         data[i].fPicture->unref();
44         data[i].fCanvas->unref();
45         SkDELETE(data[i].fPaint);
46     }
47     data.rewind();
48 }
49
50 //////////////////////////////////////////////////////////////////////////////////////
51
52 SkMultiPictureDraw::SkMultiPictureDraw(int reserve) {
53     if (reserve > 0) {
54         fGPUDrawData.setReserve(reserve);
55         fThreadSafeDrawData.setReserve(reserve);
56     }
57 }
58
59 void SkMultiPictureDraw::reset() {
60     DrawData::Reset(fGPUDrawData);
61     DrawData::Reset(fThreadSafeDrawData);
62 }
63
64 void SkMultiPictureDraw::add(SkCanvas* canvas,
65                              const SkPicture* picture,
66                              const SkMatrix* matrix,
67                              const SkPaint* paint) {
68     if (NULL == canvas || NULL == picture) {
69         SkDEBUGFAIL("parameters to SkMultiPictureDraw::add should be non-NULL");
70         return;
71     }
72
73     SkTDArray<DrawData>& array = canvas->getGrContext() ? fGPUDrawData : fThreadSafeDrawData;
74     array.append()->init(canvas, picture, matrix, paint);
75 }
76
77 class AutoMPDReset : SkNoncopyable {
78     SkMultiPictureDraw* fMPD;
79 public:
80     AutoMPDReset(SkMultiPictureDraw* mpd) : fMPD(mpd) {}
81     ~AutoMPDReset() { fMPD->reset(); }
82 };
83
84 void SkMultiPictureDraw::draw() {
85     AutoMPDReset mpdreset(this);
86     // we place the taskgroup after the MPDReset, to ensure that we don't delete the DrawData
87     // objects until after we're finished the tasks (which have pointers to the data).
88
89     SkTaskGroup group;
90     group.batch(DrawData::Draw, fThreadSafeDrawData.begin(), fThreadSafeDrawData.count());
91     // we deliberately don't call wait() here, since the destructor will do that, this allows us
92     // to continue processing gpu-data without having to wait on the cpu tasks.
93
94     const int count = fGPUDrawData.count();
95     if (0 == count) {
96         return;
97     }
98
99 #if !defined(SK_IGNORE_GPU_LAYER_HOISTING) && SK_SUPPORT_GPU
100     GrContext* context = fGPUDrawData[0].fCanvas->getGrContext();
101     SkASSERT(context);
102
103     // Start by collecting all the layers that are going to be atlased and render
104     // them (if necessary). Hoisting the free floating layers is deferred until
105     // drawing the canvas that requires them.
106     SkTDArray<GrHoistedLayer> atlasedNeedRendering, atlasedRecycled;
107
108     for (int i = 0; i < count; ++i) {
109         const DrawData& data = fGPUDrawData[i];
110         // we only expect 1 context for all the canvases
111         SkASSERT(data.fCanvas->getGrContext() == context);
112
113         if (!data.fPaint && data.fMatrix.isIdentity()) {
114             // TODO: this path always tries to optimize pictures. Should we
115             // switch to this API approach (vs. SkCanvas::EXPERIMENTAL_optimize)?
116             data.fCanvas->EXPERIMENTAL_optimize(data.fPicture);
117
118             SkRect clipBounds;
119             if (!data.fCanvas->getClipBounds(&clipBounds)) {
120                 continue;
121             }
122
123             // TODO: sorting the cacheable layers from smallest to largest
124             // would improve the packing and reduce the number of swaps
125             // TODO: another optimization would be to make a first pass to
126             // lock any required layer that is already in the atlas
127             GrLayerHoister::FindLayersToAtlas(context, data.fPicture,
128                                               clipBounds,
129                                               &atlasedNeedRendering, &atlasedRecycled);
130         }
131     }
132
133     GrLayerHoister::DrawLayersToAtlas(context, atlasedNeedRendering);
134
135     SkTDArray<GrHoistedLayer> needRendering, recycled;
136 #endif
137
138     for (int i = 0; i < count; ++i) {
139         const DrawData& data = fGPUDrawData[i];
140         SkCanvas* canvas = data.fCanvas;
141         const SkPicture* picture = data.fPicture;
142
143 #if !defined(SK_IGNORE_GPU_LAYER_HOISTING) && SK_SUPPORT_GPU
144         if (!data.fPaint && data.fMatrix.isIdentity()) {
145
146             SkRect clipBounds;
147             if (!canvas->getClipBounds(&clipBounds)) {
148                 continue;
149             }
150
151             // Find the layers required by this canvas. It will return atlased
152             // layers in the 'recycled' list since they have already been drawn.
153             GrLayerHoister::FindLayersToHoist(context, picture,
154                                               clipBounds, &needRendering, &recycled);
155
156             GrLayerHoister::DrawLayers(context, needRendering);
157
158             GrReplacements replacements;
159
160             GrLayerHoister::ConvertLayersToReplacements(needRendering, &replacements);
161             GrLayerHoister::ConvertLayersToReplacements(recycled, &replacements);
162
163             const SkMatrix initialMatrix = canvas->getTotalMatrix();
164
165             // Render the entire picture using new layers
166             GrRecordReplaceDraw(picture, canvas, &replacements, initialMatrix, NULL);
167
168             GrLayerHoister::UnlockLayers(context, needRendering);
169             GrLayerHoister::UnlockLayers(context, recycled);
170
171             needRendering.rewind();
172             recycled.rewind();
173         } else
174 #endif
175         {
176             canvas->drawPicture(picture, &data.fMatrix, data.fPaint);
177         }
178     }
179
180 #if !defined(SK_IGNORE_GPU_LAYER_HOISTING) && SK_SUPPORT_GPU
181     GrLayerHoister::UnlockLayers(context, atlasedNeedRendering);
182     GrLayerHoister::UnlockLayers(context, atlasedRecycled);
183 #if !GR_CACHE_HOISTED_LAYERS
184     GrLayerHoister::PurgeCache(context);
185 #endif
186 #endif
187 }
188