SkMultiPictureDraw.cpp revision 6d5b5455743414ddb11d2b8c1fe9d7959f2b853d
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#if SK_SUPPORT_GPU 9#include "GrLayerHoister.h" 10#include "GrRecordReplaceDraw.h" 11#endif 12 13#include "SkCanvas.h" 14#include "SkMultiPictureDraw.h" 15#include "SkPicture.h" 16 17SkMultiPictureDraw::SkMultiPictureDraw(int reserve) { 18 if (reserve > 0) { 19 fDrawData.setReserve(reserve); 20 } 21} 22 23void SkMultiPictureDraw::reset() { 24 for (int i = 0; i < fDrawData.count(); ++i) { 25 fDrawData[i].picture->unref(); 26 fDrawData[i].canvas->unref(); 27 SkDELETE(fDrawData[i].paint); 28 } 29 30 fDrawData.rewind(); 31} 32 33void SkMultiPictureDraw::add(SkCanvas* canvas, 34 const SkPicture* picture, 35 const SkMatrix* matrix, 36 const SkPaint* paint) { 37 if (NULL == canvas || NULL == picture) { 38 SkDEBUGFAIL("parameters to SkMultiPictureDraw::add should be non-NULL"); 39 return; 40 } 41 42 DrawData* data = fDrawData.append(); 43 44 data->picture = SkRef(picture); 45 data->canvas = SkRef(canvas); 46 if (matrix) { 47 data->matrix = *matrix; 48 } else { 49 data->matrix.setIdentity(); 50 } 51 if (paint) { 52 data->paint = SkNEW_ARGS(SkPaint, (*paint)); 53 } else { 54 data->paint = NULL; 55 } 56} 57 58#undef SK_IGNORE_GPU_LAYER_HOISTING 59#define SK_IGNORE_GPU_LAYER_HOISTING 1 60 61void SkMultiPictureDraw::draw() { 62 63#ifndef SK_IGNORE_GPU_LAYER_HOISTING 64 GrContext* context = NULL; 65 66 // Start by collecting all the layers that are going to be atlased and render 67 // them (if necessary). Hoisting the free floating layers is deferred until 68 // drawing the canvas that requires them. 69 SkTDArray<GrHoistedLayer> atlasedNeedRendering, atlasedRecycled; 70 71 for (int i = 0; i < fDrawData.count(); ++i) { 72 if (fDrawData[i].canvas->getGrContext() && 73 !fDrawData[i].paint && fDrawData[i].matrix.isIdentity()) { 74 SkASSERT(NULL == context || context == fDrawData[i].canvas->getGrContext()); 75 context = fDrawData[i].canvas->getGrContext(); 76 77 // TODO: this path always tries to optimize pictures. Should we 78 // switch to this API approach (vs. SkCanvas::EXPERIMENTAL_optimize)? 79 fDrawData[i].canvas->EXPERIMENTAL_optimize(fDrawData[i].picture); 80 81 SkRect clipBounds; 82 if (!fDrawData[i].canvas->getClipBounds(&clipBounds)) { 83 continue; 84 } 85 86 // TODO: sorting the cacheable layers from smallest to largest 87 // would improve the packing and reduce the number of swaps 88 // TODO: another optimization would be to make a first pass to 89 // lock any required layer that is already in the atlas 90 GrLayerHoister::FindLayersToAtlas(context, fDrawData[i].picture, 91 clipBounds, 92 &atlasedNeedRendering, &atlasedRecycled); 93 } 94 } 95 96 if (NULL != context) { 97 GrLayerHoister::DrawLayersToAtlas(context, atlasedNeedRendering); 98 } 99 100 SkTDArray<GrHoistedLayer> needRendering, recycled; 101#endif 102 103 for (int i = 0; i < fDrawData.count(); ++i) { 104#ifndef SK_IGNORE_GPU_LAYER_HOISTING 105 if (fDrawData[i].canvas->getGrContext() && 106 !fDrawData[i].paint && fDrawData[i].matrix.isIdentity()) { 107 108 SkRect clipBounds; 109 if (!fDrawData[i].canvas->getClipBounds(&clipBounds)) { 110 continue; 111 } 112 113 // Find the layers required by this canvas. It will return atlased 114 // layers in the 'recycled' list since they have already been drawn. 115 GrLayerHoister::FindLayersToHoist(context, fDrawData[i].picture, 116 clipBounds, &needRendering, &recycled); 117 118 GrLayerHoister::DrawLayers(context, needRendering); 119 120 GrReplacements replacements; 121 122 GrLayerHoister::ConvertLayersToReplacements(needRendering, &replacements); 123 GrLayerHoister::ConvertLayersToReplacements(recycled, &replacements); 124 125 const SkMatrix initialMatrix = fDrawData[i].canvas->getTotalMatrix(); 126 127 // Render the entire picture using new layers 128 GrRecordReplaceDraw(fDrawData[i].picture, fDrawData[i].canvas, 129 &replacements, initialMatrix, NULL); 130 131 GrLayerHoister::UnlockLayers(context, needRendering); 132 GrLayerHoister::UnlockLayers(context, recycled); 133 134 needRendering.rewind(); 135 recycled.rewind(); 136 } else 137#endif 138 { 139 fDrawData[i].canvas->drawPicture(fDrawData[i].picture, 140 &fDrawData[i].matrix, 141 fDrawData[i].paint); 142 } 143 } 144 145#ifndef SK_IGNORE_GPU_LAYER_HOISTING 146 if (NULL != context) { 147 GrLayerHoister::UnlockLayers(context, atlasedNeedRendering); 148 GrLayerHoister::UnlockLayers(context, atlasedRecycled); 149#if !GR_CACHE_HOISTED_LAYERS 150 GrLayerHoister::PurgeCache(context); 151#endif 152 } 153#endif 154 155 this->reset(); 156} 157 158