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 | |
63 // Return true if any layers are suitable for hoisting | 16 // Return true if any layers are suitable for hoisting |
64 bool GrLayerHoister::FindLayersToHoist(GrContext* context, | 17 bool GrLayerHoister::FindLayersToHoist(GrContext* context, |
65 const SkPicture* topLevelPicture, | 18 const SkPicture* topLevelPicture, |
66 const SkRect& query, | 19 const SkRect& query, |
67 SkTDArray<GrHoistedLayer>* atlased, | 20 SkTDArray<GrHoistedLayer>* atlased, |
68 SkTDArray<GrHoistedLayer>* nonAtlased, | 21 SkTDArray<GrHoistedLayer>* nonAtlased, |
69 SkTDArray<GrHoistedLayer>* recycled) { | 22 SkTDArray<GrHoistedLayer>* recycled) { |
| 23 bool anyHoisted = false; |
70 | 24 |
71 GrLayerCache* layerCache = context->getLayerCache(); | 25 GrLayerCache* layerCache = context->getLayerCache(); |
72 | 26 |
73 layerCache->processDeletedPictures(); | 27 layerCache->processDeletedPictures(); |
74 | 28 |
75 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); | 29 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); |
76 | 30 |
77 const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_get
AccelData(key); | 31 const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_get
AccelData(key); |
78 if (!topLevelData) { | 32 if (NULL == topLevelData) { |
79 return false; | 33 return false; |
80 } | 34 } |
81 | 35 |
82 const GrAccelData *topLevelGPUData = static_cast<const GrAccelData*>(topLeve
lData); | 36 const GrAccelData *topLevelGPUData = static_cast<const GrAccelData*>(topLeve
lData); |
83 if (0 == topLevelGPUData->numSaveLayers()) { | 37 if (0 == topLevelGPUData->numSaveLayers()) { |
84 return false; | 38 return false; |
85 } | 39 } |
86 | 40 |
87 bool anyHoisted = false; | 41 // Layer hoisting pre-renders the entire layer since it will be cached and p
otentially |
| 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; |
88 | 46 |
89 // The layer hoisting code will pre-render and cache an entire layer if most | 47 SkAutoTArray<bool> pullForward(topLevelGPUData->numSaveLayers()); |
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). | |
96 | 48 |
97 atlased->setReserve(atlased->count() + topLevelGPUData->numSaveLayers()); | 49 // Pre-render all the layers that intersect the query rect |
98 | |
99 // Find and prepare for hoisting all the layers that intersect the query rec
t | |
100 for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) { | 50 for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) { |
| 51 pullForward[i] = false; |
101 | 52 |
102 const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(
i); | 53 const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(
i); |
103 | 54 |
104 SkRect layerRect = SkRect::MakeXYWH(SkIntToScalar(info.fOffset.fX), | 55 SkRect layerRect = SkRect::MakeXYWH(SkIntToScalar(info.fOffset.fX), |
105 SkIntToScalar(info.fOffset.fY), | 56 SkIntToScalar(info.fOffset.fY), |
106 SkIntToScalar(info.fSize.fWidth), | 57 SkIntToScalar(info.fSize.fWidth), |
107 SkIntToScalar(info.fSize.fHeight)); | 58 SkIntToScalar(info.fSize.fHeight)); |
108 | 59 |
109 if (!SkRect::Intersects(query, layerRect)) { | 60 if (!SkRect::Intersects(query, layerRect)) { |
110 continue; | 61 continue; |
111 } | 62 } |
112 | 63 |
113 // TODO: ignore perspective projected layers here! | 64 // TODO: ignore perspective projected layers here! |
114 // TODO: once this code is more stable unsuitable layers can | 65 // TODO: once this code is more stable unsuitable layers can |
115 // just be omitted during the optimization stage | 66 // just be omitted during the optimization stage |
116 if (!info.fValid || info.fIsNested) { | 67 if (!info.fValid || |
| 68 kSaveLayerMaxSize < info.fSize.fWidth || |
| 69 kSaveLayerMaxSize < info.fSize.fHeight || |
| 70 info.fIsNested) { |
117 continue; | 71 continue; |
118 } | 72 } |
119 | 73 |
120 prepare_for_hoisting(layerCache, topLevelPicture, info, atlased, nonAtla
sed, recycled); | 74 pullForward[i] = true; |
121 anyHoisted = true; | 75 anyHoisted = true; |
122 } | 76 } |
123 | 77 |
| 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 |
124 return anyHoisted; | 128 return anyHoisted; |
125 } | 129 } |
126 | 130 |
127 static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* re
sult) { | 131 static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* re
sult) { |
128 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); | 132 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); |
129 result->setInfo(info); | 133 result->setInfo(info); |
130 result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref(); | 134 result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref(); |
131 } | 135 } |
132 | 136 |
133 static void convert_layers_to_replacements(const SkTDArray<GrHoistedLayer>& laye
rs, | 137 static void convert_layers_to_replacements(const SkTDArray<GrHoistedLayer>& laye
rs, |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 } | 299 } |
296 | 300 |
297 #if DISABLE_CACHING | 301 #if DISABLE_CACHING |
298 // This code completely clears out the atlas. It is required when | 302 // This code completely clears out the atlas. It is required when |
299 // caching is disabled so the atlas doesn't fill up and force more | 303 // caching is disabled so the atlas doesn't fill up and force more |
300 // free floating layers | 304 // free floating layers |
301 layerCache->purgeAll(); | 305 layerCache->purgeAll(); |
302 #endif | 306 #endif |
303 } | 307 } |
304 | 308 |
OLD | NEW |