OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrLayerCache.h" | 8 #include "GrLayerCache.h" |
9 #include "GrLayerHoister.h" | 9 #include "GrLayerHoister.h" |
10 #include "SkCanvas.h" | 10 #include "SkCanvas.h" |
11 #include "SkRecordDraw.h" | 11 #include "SkRecordDraw.h" |
12 #include "GrRecordReplaceDraw.h" | 12 #include "GrRecordReplaceDraw.h" |
13 #include "SkGrPixelRef.h" | 13 #include "SkGrPixelRef.h" |
14 #include "SkSurface.h" | 14 #include "SkSurface.h" |
15 | 15 |
| 16 // Create the layer information for the hoisted layer and secure the |
| 17 // required texture/render target resources. |
| 18 static void prepare_for_hoisting(GrLayerCache* layerCache, |
| 19 const SkPicture* topLevelPicture, |
| 20 const GrAccelData::SaveLayerInfo& info, |
| 21 SkTDArray<GrHoistedLayer>* atlased, |
| 22 SkTDArray<GrHoistedLayer>* nonAtlased, |
| 23 SkTDArray<GrHoistedLayer>* recycled) { |
| 24 const SkPicture* pict = info.fPicture ? info.fPicture : topLevelPicture; |
| 25 |
| 26 GrCachedLayer* layer = layerCache->findLayerOrCreate(pict->uniqueID(), |
| 27 info.fSaveLayerOpID, |
| 28 info.fRestoreOpID, |
| 29 info.fOriginXform, |
| 30 info.fPaint); |
| 31 |
| 32 GrTextureDesc desc; |
| 33 desc.fFlags = kRenderTarget_GrTextureFlagBit; |
| 34 desc.fWidth = info.fSize.fWidth; |
| 35 desc.fHeight = info.fSize.fHeight; |
| 36 desc.fConfig = kSkia8888_GrPixelConfig; |
| 37 // TODO: need to deal with sample count |
| 38 |
| 39 bool needsRendering = layerCache->lock(layer, desc, info.fHasNestedLayers ||
info.fIsNested); |
| 40 if (NULL == layer->texture()) { |
| 41 // GPU resources could not be secured for the hoisting of this layer |
| 42 return; |
| 43 } |
| 44 |
| 45 GrHoistedLayer* hl; |
| 46 |
| 47 if (needsRendering) { |
| 48 if (layer->isAtlased()) { |
| 49 hl = atlased->append(); |
| 50 } else { |
| 51 hl = nonAtlased->append(); |
| 52 } |
| 53 } else { |
| 54 hl = recycled->append(); |
| 55 } |
| 56 |
| 57 hl->fLayer = layer; |
| 58 hl->fPicture = pict; |
| 59 hl->fOffset = info.fOffset; |
| 60 hl->fCTM = info.fOriginXform; |
| 61 } |
| 62 |
16 // Return true if any layers are suitable for hoisting | 63 // Return true if any layers are suitable for hoisting |
17 bool GrLayerHoister::FindLayersToHoist(GrContext* context, | 64 bool GrLayerHoister::FindLayersToHoist(GrContext* context, |
18 const SkPicture* topLevelPicture, | 65 const SkPicture* topLevelPicture, |
19 const SkRect& query, | 66 const SkRect& query, |
20 SkTDArray<GrHoistedLayer>* atlased, | 67 SkTDArray<GrHoistedLayer>* atlased, |
21 SkTDArray<GrHoistedLayer>* nonAtlased, | 68 SkTDArray<GrHoistedLayer>* nonAtlased, |
22 SkTDArray<GrHoistedLayer>* recycled) { | 69 SkTDArray<GrHoistedLayer>* recycled) { |
23 bool anyHoisted = false; | |
24 | 70 |
25 GrLayerCache* layerCache = context->getLayerCache(); | 71 GrLayerCache* layerCache = context->getLayerCache(); |
26 | 72 |
27 layerCache->processDeletedPictures(); | 73 layerCache->processDeletedPictures(); |
28 | 74 |
29 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); | 75 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); |
30 | 76 |
31 const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_get
AccelData(key); | 77 const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_get
AccelData(key); |
32 if (NULL == topLevelData) { | 78 if (!topLevelData) { |
33 return false; | 79 return false; |
34 } | 80 } |
35 | 81 |
36 const GrAccelData *topLevelGPUData = static_cast<const GrAccelData*>(topLeve
lData); | 82 const GrAccelData *topLevelGPUData = static_cast<const GrAccelData*>(topLeve
lData); |
37 if (0 == topLevelGPUData->numSaveLayers()) { | 83 if (0 == topLevelGPUData->numSaveLayers()) { |
38 return false; | 84 return false; |
39 } | 85 } |
40 | 86 |
41 // Layer hoisting pre-renders the entire layer since it will be cached and p
otentially | 87 bool anyHoisted = false; |
42 // reused with different clips (e.g., in different tiles). Because of this t
he | |
43 // clip will not be limiting the size of the pre-rendered layer. kSaveLayerM
axSize | |
44 // is used to limit which clips are pre-rendered. | |
45 static const int kSaveLayerMaxSize = 256; | |
46 | 88 |
47 SkAutoTArray<bool> pullForward(topLevelGPUData->numSaveLayers()); | 89 // The layer hoisting code will pre-render and cache an entire layer if most |
| 90 // of it is being used (~70%) and it will fit in a texture. This is to allow |
| 91 // such layers to be re-used for different clips/tiles. |
| 92 // Small layers will additionally be atlased. |
| 93 // The only limitation right now is that nested layers are currently not hoi
sted. |
| 94 // Parent layers are hoisted but are never atlased (so that we never swap |
| 95 // away from the atlas rendertarget when generating the hoisted layers). |
48 | 96 |
49 // Pre-render all the layers that intersect the query rect | 97 atlased->setReserve(atlased->count() + topLevelGPUData->numSaveLayers()); |
| 98 |
| 99 // Find and prepare for hoisting all the layers that intersect the query rec
t |
50 for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) { | 100 for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) { |
51 pullForward[i] = false; | |
52 | 101 |
53 const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(
i); | 102 const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(
i); |
54 | 103 |
55 SkRect layerRect = SkRect::MakeXYWH(SkIntToScalar(info.fOffset.fX), | 104 SkRect layerRect = SkRect::MakeXYWH(SkIntToScalar(info.fOffset.fX), |
56 SkIntToScalar(info.fOffset.fY), | 105 SkIntToScalar(info.fOffset.fY), |
57 SkIntToScalar(info.fSize.fWidth), | 106 SkIntToScalar(info.fSize.fWidth), |
58 SkIntToScalar(info.fSize.fHeight)); | 107 SkIntToScalar(info.fSize.fHeight)); |
59 | 108 |
60 if (!SkRect::Intersects(query, layerRect)) { | 109 if (!SkRect::Intersects(query, layerRect)) { |
61 continue; | 110 continue; |
62 } | 111 } |
63 | 112 |
64 // TODO: ignore perspective projected layers here! | 113 // TODO: ignore perspective projected layers here! |
65 // TODO: once this code is more stable unsuitable layers can | 114 // TODO: once this code is more stable unsuitable layers can |
66 // just be omitted during the optimization stage | 115 // just be omitted during the optimization stage |
67 if (!info.fValid || | 116 if (!info.fValid || info.fIsNested) { |
68 kSaveLayerMaxSize < info.fSize.fWidth || | |
69 kSaveLayerMaxSize < info.fSize.fHeight || | |
70 info.fIsNested) { | |
71 continue; | 117 continue; |
72 } | 118 } |
73 | 119 |
74 pullForward[i] = true; | 120 prepare_for_hoisting(layerCache, topLevelPicture, info, atlased, nonAtla
sed, recycled); |
75 anyHoisted = true; | 121 anyHoisted = true; |
76 } | 122 } |
77 | 123 |
78 if (!anyHoisted) { | |
79 return false; | |
80 } | |
81 | |
82 atlased->setReserve(atlased->reserved() + topLevelGPUData->numSaveLayers()); | |
83 | |
84 // Generate the layer and/or ensure it is locked | |
85 for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) { | |
86 if (pullForward[i]) { | |
87 const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerI
nfo(i); | |
88 const SkPicture* pict = info.fPicture ? info.fPicture : topLevelPict
ure; | |
89 | |
90 GrCachedLayer* layer = layerCache->findLayerOrCreate(pict->uniqueID(
), | |
91 info.fSaveLayer
OpID, | |
92 info.fRestoreOp
ID, | |
93 info.fOriginXfo
rm, | |
94 info.fPaint); | |
95 | |
96 GrTextureDesc desc; | |
97 desc.fFlags = kRenderTarget_GrTextureFlagBit; | |
98 desc.fWidth = info.fSize.fWidth; | |
99 desc.fHeight = info.fSize.fHeight; | |
100 desc.fConfig = kSkia8888_GrPixelConfig; | |
101 // TODO: need to deal with sample count | |
102 | |
103 bool needsRendering = layerCache->lock(layer, desc, | |
104 info.fHasNestedLayers || info
.fIsNested); | |
105 if (NULL == layer->texture()) { | |
106 continue; | |
107 } | |
108 | |
109 GrHoistedLayer* hl; | |
110 | |
111 if (needsRendering) { | |
112 if (layer->isAtlased()) { | |
113 hl = atlased->append(); | |
114 } else { | |
115 hl = nonAtlased->append(); | |
116 } | |
117 } else { | |
118 hl = recycled->append(); | |
119 } | |
120 | |
121 hl->fLayer = layer; | |
122 hl->fPicture = pict; | |
123 hl->fOffset = info.fOffset; | |
124 hl->fCTM = info.fOriginXform; | |
125 } | |
126 } | |
127 | |
128 return anyHoisted; | 124 return anyHoisted; |
129 } | 125 } |
130 | 126 |
131 static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* re
sult) { | 127 static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* re
sult) { |
132 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); | 128 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); |
133 result->setInfo(info); | 129 result->setInfo(info); |
134 result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref(); | 130 result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref(); |
135 } | 131 } |
136 | 132 |
137 static void convert_layers_to_replacements(const SkTDArray<GrHoistedLayer>& laye
rs, | 133 static void convert_layers_to_replacements(const SkTDArray<GrHoistedLayer>& laye
rs, |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 } | 295 } |
300 | 296 |
301 #if DISABLE_CACHING | 297 #if DISABLE_CACHING |
302 // This code completely clears out the atlas. It is required when | 298 // This code completely clears out the atlas. It is required when |
303 // caching is disabled so the atlas doesn't fill up and force more | 299 // caching is disabled so the atlas doesn't fill up and force more |
304 // free floating layers | 300 // free floating layers |
305 layerCache->purgeAll(); | 301 layerCache->purgeAll(); |
306 #endif | 302 #endif |
307 } | 303 } |
308 | 304 |
OLD | NEW |