SkMultiPictureDraw.cpp revision 96fcdcc219d2a0d3579719b84b28bede76efba64
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 "SkCanvasPriv.h" 13#include "SkMultiPictureDraw.h" 14#include "SkPicture.h" 15#include "SkTaskGroup.h" 16 17#if SK_SUPPORT_GPU 18#include "GrContext.h" 19#include "GrLayerHoister.h" 20#include "GrRecordReplaceDraw.h" 21#include "GrRenderTarget.h" 22#endif 23 24void SkMultiPictureDraw::DrawData::draw() { 25 fCanvas->drawPicture(fPicture, &fMatrix, fPaint); 26} 27 28void SkMultiPictureDraw::DrawData::init(SkCanvas* canvas, const SkPicture* picture, 29 const SkMatrix* matrix, const SkPaint* paint) { 30 fPicture = SkRef(picture); 31 fCanvas = SkRef(canvas); 32 if (matrix) { 33 fMatrix = *matrix; 34 } else { 35 fMatrix.setIdentity(); 36 } 37 if (paint) { 38 fPaint = new SkPaint(*paint); 39 } else { 40 fPaint = nullptr; 41 } 42} 43 44void SkMultiPictureDraw::DrawData::Reset(SkTDArray<DrawData>& data) { 45 for (int i = 0; i < data.count(); ++i) { 46 data[i].fPicture->unref(); 47 data[i].fCanvas->unref(); 48 delete data[i].fPaint; 49 } 50 data.rewind(); 51} 52 53////////////////////////////////////////////////////////////////////////////////////// 54 55SkMultiPictureDraw::SkMultiPictureDraw(int reserve) { 56 if (reserve > 0) { 57 fGPUDrawData.setReserve(reserve); 58 fThreadSafeDrawData.setReserve(reserve); 59 } 60} 61 62void SkMultiPictureDraw::reset() { 63 DrawData::Reset(fGPUDrawData); 64 DrawData::Reset(fThreadSafeDrawData); 65} 66 67void SkMultiPictureDraw::add(SkCanvas* canvas, 68 const SkPicture* picture, 69 const SkMatrix* matrix, 70 const SkPaint* paint) { 71 if (nullptr == canvas || nullptr == picture) { 72 SkDEBUGFAIL("parameters to SkMultiPictureDraw::add should be non-nullptr"); 73 return; 74 } 75 76 SkTDArray<DrawData>& array = canvas->getGrContext() ? fGPUDrawData : fThreadSafeDrawData; 77 array.append()->init(canvas, picture, matrix, paint); 78} 79 80class AutoMPDReset : SkNoncopyable { 81 SkMultiPictureDraw* fMPD; 82public: 83 AutoMPDReset(SkMultiPictureDraw* mpd) : fMPD(mpd) {} 84 ~AutoMPDReset() { fMPD->reset(); } 85}; 86 87//#define FORCE_SINGLE_THREAD_DRAWING_FOR_TESTING 88 89void SkMultiPictureDraw::draw(bool flush) { 90 AutoMPDReset mpdreset(this); 91 92#ifdef FORCE_SINGLE_THREAD_DRAWING_FOR_TESTING 93 for (int i = 0; i < fThreadSafeDrawData.count(); ++i) { 94 fThreadSafeDrawData[i].draw(); 95 } 96#else 97 sk_parallel_for(fThreadSafeDrawData.count(), [&](int i) { 98 fThreadSafeDrawData[i].draw(); 99 }); 100#endif 101 102 // N.B. we could get going on any GPU work from this main thread while the CPU work runs. 103 // But in practice, we've either got GPU work or CPU work, not both. 104 105 const int count = fGPUDrawData.count(); 106 if (0 == count) { 107 return; 108 } 109 110#if !defined(SK_IGNORE_GPU_LAYER_HOISTING) && SK_SUPPORT_GPU 111 GrContext* context = fGPUDrawData[0].fCanvas->getGrContext(); 112 SkASSERT(context); 113 114 // Start by collecting all the layers that are going to be atlased and render 115 // them (if necessary). Hoisting the free floating layers is deferred until 116 // drawing the canvas that requires them. 117 SkTDArray<GrHoistedLayer> atlasedNeedRendering, atlasedRecycled; 118 119 for (int i = 0; i < count; ++i) { 120 const DrawData& data = fGPUDrawData[i]; 121 // we only expect 1 context for all the canvases 122 SkASSERT(data.fCanvas->getGrContext() == context); 123 124 if (!data.fPaint) { 125 SkRect clipBounds; 126 if (!data.fCanvas->getClipBounds(&clipBounds)) { 127 continue; 128 } 129 130 SkMatrix initialMatrix = data.fCanvas->getTotalMatrix(); 131 initialMatrix.preConcat(data.fMatrix); 132 133 GrRenderTarget* rt = data.fCanvas->internal_private_accessTopLayerRenderTarget(); 134 SkASSERT(rt); 135 136 // TODO: sorting the cacheable layers from smallest to largest 137 // would improve the packing and reduce the number of swaps 138 // TODO: another optimization would be to make a first pass to 139 // lock any required layer that is already in the atlas 140 GrLayerHoister::FindLayersToAtlas(context, data.fPicture, initialMatrix, 141 clipBounds, 142 &atlasedNeedRendering, &atlasedRecycled, 143 rt->numColorSamples()); 144 } 145 } 146 147 GrLayerHoister::DrawLayersToAtlas(context, atlasedNeedRendering); 148 149 SkTDArray<GrHoistedLayer> needRendering, recycled; 150#endif 151 152 for (int i = 0; i < count; ++i) { 153 const DrawData& data = fGPUDrawData[i]; 154 SkCanvas* canvas = data.fCanvas; 155 const SkPicture* picture = data.fPicture; 156 157#if !defined(SK_IGNORE_GPU_LAYER_HOISTING) && SK_SUPPORT_GPU 158 if (!data.fPaint) { 159 160 SkRect clipBounds; 161 if (!canvas->getClipBounds(&clipBounds)) { 162 continue; 163 } 164 165 SkAutoCanvasMatrixPaint acmp(canvas, &data.fMatrix, data.fPaint, picture->cullRect()); 166 167 const SkMatrix initialMatrix = canvas->getTotalMatrix(); 168 169 GrRenderTarget* rt = data.fCanvas->internal_private_accessTopLayerRenderTarget(); 170 SkASSERT(rt); 171 172 // Find the layers required by this canvas. It will return atlased 173 // layers in the 'recycled' list since they have already been drawn. 174 GrLayerHoister::FindLayersToHoist(context, picture, initialMatrix, 175 clipBounds, &needRendering, &recycled, 176 rt->numColorSamples()); 177 178 GrLayerHoister::DrawLayers(context, needRendering); 179 180 // Render the entire picture using new layers 181 GrRecordReplaceDraw(picture, canvas, context->getLayerCache(), 182 initialMatrix, nullptr); 183 184 GrLayerHoister::UnlockLayers(context, needRendering); 185 GrLayerHoister::UnlockLayers(context, recycled); 186 187 needRendering.rewind(); 188 recycled.rewind(); 189 } else 190#endif 191 { 192 canvas->drawPicture(picture, &data.fMatrix, data.fPaint); 193 } 194 if (flush) { 195 canvas->flush(); 196 } 197 } 198 199#if !defined(SK_IGNORE_GPU_LAYER_HOISTING) && SK_SUPPORT_GPU 200 GrLayerHoister::UnlockLayers(context, atlasedNeedRendering); 201 GrLayerHoister::UnlockLayers(context, atlasedRecycled); 202#if !GR_CACHE_HOISTED_LAYERS 203 GrLayerHoister::PurgeCache(context); 204#endif 205#endif 206} 207 208