blob: 2ed5b0ae80e0678ba9be015627ab6386bc511360 [file] [log] [blame]
robertphillips98d709b2014-09-02 10:20:50 -07001/*
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 "GrLayerCache.h"
9#include "GrLayerHoister.h"
robertphillips98d709b2014-09-02 10:20:50 -070010#include "SkCanvas.h"
robertphillips274b4ba2014-09-04 07:24:18 -070011#include "SkRecordDraw.h"
robertphillips98d709b2014-09-02 10:20:50 -070012#include "SkSurface.h"
13
14// Return true if any layers are suitable for hoisting
15bool GrLayerHoister::FindLayersToHoist(const GrAccelData *gpuData,
robertphillips98d709b2014-09-02 10:20:50 -070016 const SkRect& query,
17 bool pullForward[]) {
18 bool anyHoisted = false;
robertphillips98d709b2014-09-02 10:20:50 -070019
20 // Layer hoisting pre-renders the entire layer since it will be cached and potentially
21 // reused with different clips (e.g., in different tiles). Because of this the
22 // clip will not be limiting the size of the pre-rendered layer. kSaveLayerMaxSize
23 // is used to limit which clips are pre-rendered.
24 static const int kSaveLayerMaxSize = 256;
25
robertphillips2ed8a752014-09-03 13:46:02 -070026 // Pre-render all the layers that intersect the query rect
27 for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
28 pullForward[i] = false;
robertphillips98d709b2014-09-02 10:20:50 -070029
robertphillips2ed8a752014-09-03 13:46:02 -070030 const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
robertphillips98d709b2014-09-02 10:20:50 -070031
robertphillips2ed8a752014-09-03 13:46:02 -070032 SkRect layerRect = SkRect::MakeXYWH(SkIntToScalar(info.fOffset.fX),
33 SkIntToScalar(info.fOffset.fY),
34 SkIntToScalar(info.fSize.fWidth),
35 SkIntToScalar(info.fSize.fHeight));
robertphillips98d709b2014-09-02 10:20:50 -070036
robertphillips2ed8a752014-09-03 13:46:02 -070037 if (!SkRect::Intersects(query, layerRect)) {
38 continue;
robertphillips98d709b2014-09-02 10:20:50 -070039 }
robertphillips98d709b2014-09-02 10:20:50 -070040
robertphillips2ed8a752014-09-03 13:46:02 -070041 // TODO: once this code is more stable unsuitable layers can
42 // just be omitted during the optimization stage
43 if (!info.fValid ||
44 kSaveLayerMaxSize < info.fSize.fWidth ||
45 kSaveLayerMaxSize < info.fSize.fHeight ||
46 info.fIsNested) {
47 continue;
robertphillips98d709b2014-09-02 10:20:50 -070048 }
robertphillips2ed8a752014-09-03 13:46:02 -070049
50 pullForward[i] = true;
51 anyHoisted = true;
robertphillips98d709b2014-09-02 10:20:50 -070052 }
53
54 return anyHoisted;
55}
56
57void GrLayerHoister::DrawLayers(const SkPicture* picture,
58 const SkTDArray<GrCachedLayer*>& atlased,
59 const SkTDArray<GrCachedLayer*>& nonAtlased) {
60 // Render the atlased layers that require it
61 if (atlased.count() > 0) {
62 // All the atlased layers are rendered into the same GrTexture
63 SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
64 atlased[0]->texture()->asRenderTarget(),
65 SkSurface::kStandard_TextRenderMode,
66 SkSurface::kDontClear_RenderTargetFlag));
67
68 SkCanvas* atlasCanvas = surface->getCanvas();
69
70 SkPaint paint;
71 paint.setColor(SK_ColorTRANSPARENT);
72 paint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode))->unref();
73
74 for (int i = 0; i < atlased.count(); ++i) {
75 GrCachedLayer* layer = atlased[i];
76
77 atlasCanvas->save();
78
79 // Add a rect clip to make sure the rendering doesn't
80 // extend beyond the boundaries of the atlased sub-rect
81 SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft),
82 SkIntToScalar(layer->rect().fTop),
83 SkIntToScalar(layer->rect().width()),
84 SkIntToScalar(layer->rect().height()));
85 atlasCanvas->clipRect(bound);
86
87 // Since 'clear' doesn't respect the clip we need to draw a rect
88 // TODO: ensure none of the atlased layers contain a clear call!
89 atlasCanvas->drawRect(bound, paint);
90
91 // info.fCTM maps the layer's top/left to the origin.
92 // Since this layer is atlased, the top/left corner needs
93 // to be offset to the correct location in the backing texture.
94 atlasCanvas->translate(bound.fLeft, bound.fTop);
95 atlasCanvas->concat(layer->ctm());
96
robertphillips274b4ba2014-09-04 07:24:18 -070097 SkRecordPartialDraw(*picture->fRecord.get(), atlasCanvas, bound,
98 layer->start(), layer->stop());
robertphillips98d709b2014-09-02 10:20:50 -070099
100 atlasCanvas->restore();
101 }
102
103 atlasCanvas->flush();
104 }
105
106 // Render the non-atlased layers that require it
107 for (int i = 0; i < nonAtlased.count(); ++i) {
108 GrCachedLayer* layer = nonAtlased[i];
109
110 // Each non-atlased layer has its own GrTexture
111 SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
robertphillips274b4ba2014-09-04 07:24:18 -0700112 layer->texture()->asRenderTarget(),
113 SkSurface::kStandard_TextRenderMode,
114 SkSurface::kDontClear_RenderTargetFlag));
robertphillips98d709b2014-09-02 10:20:50 -0700115
116 SkCanvas* layerCanvas = surface->getCanvas();
117
118 // Add a rect clip to make sure the rendering doesn't
119 // extend beyond the boundaries of the atlased sub-rect
120 SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft),
121 SkIntToScalar(layer->rect().fTop),
122 SkIntToScalar(layer->rect().width()),
123 SkIntToScalar(layer->rect().height()));
124
125 layerCanvas->clipRect(bound); // TODO: still useful?
126
127 layerCanvas->clear(SK_ColorTRANSPARENT);
128
129 layerCanvas->concat(layer->ctm());
130
robertphillips274b4ba2014-09-04 07:24:18 -0700131 SkRecordPartialDraw(*picture->fRecord.get(), layerCanvas, bound,
132 layer->start(), layer->stop());
robertphillips98d709b2014-09-02 10:20:50 -0700133
134 layerCanvas->flush();
135 }
136}
137
138void GrLayerHoister::UnlockLayers(GrLayerCache* layerCache, const SkPicture* picture) {
139 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
140
141 const SkPicture::AccelData* data = picture->EXPERIMENTAL_getAccelData(key);
142 SkASSERT(NULL != data);
143
144 const GrAccelData *gpuData = static_cast<const GrAccelData*>(data);
145 SkASSERT(0 != gpuData->numSaveLayers());
146
147 // unlock the layers
148 for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
149 const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
150
151 GrCachedLayer* layer = layerCache->findLayer(picture->uniqueID(),
152 info.fSaveLayerOpID,
153 info.fRestoreOpID,
154 info.fOriginXform);
155 layerCache->unlock(layer);
156 }
157
158#if DISABLE_CACHING
159 // This code completely clears out the atlas. It is required when
160 // caching is disabled so the atlas doesn't fill up and force more
161 // free floating layers
162 layerCache->purge(picture->uniqueID());
163
164 layerCache->purgeAll();
165#endif
166}
167