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 "SkPictureShader.h" | 8 #include "SkPictureShader.h" |
9 | 9 |
10 #include "SkBitmap.h" | 10 #include "SkBitmap.h" |
11 #include "SkBitmapProcShader.h" | 11 #include "SkBitmapProcShader.h" |
12 #include "SkCanvas.h" | 12 #include "SkCanvas.h" |
13 #include "SkImageGenerator.h" | |
14 #include "SkMatrixUtils.h" | 13 #include "SkMatrixUtils.h" |
15 #include "SkPicture.h" | 14 #include "SkPicture.h" |
16 #include "SkReadBuffer.h" | 15 #include "SkReadBuffer.h" |
17 #include "SkResourceCache.h" | 16 #include "SkResourceCache.h" |
18 | 17 |
19 #if SK_SUPPORT_GPU | 18 #if SK_SUPPORT_GPU |
20 #include "GrContext.h" | 19 #include "GrContext.h" |
21 #endif | 20 #endif |
22 | 21 |
23 namespace { | 22 namespace { |
24 static unsigned gBitmapSkaderKeyNamespaceLabel; | 23 static unsigned gBitmapSkaderKeyNamespaceLabel; |
25 | 24 |
26 class PictureImageGenerator : public SkImageGenerator { | |
27 public: | |
28 PictureImageGenerator(const SkPicture* picture, | |
29 const SkRect& pictureTile, | |
30 const SkISize& tileSize) | |
31 : fPicture(SkRef(picture)) | |
32 , fPictureTile(pictureTile) | |
33 , fRasterTileInfo(SkImageInfo::MakeN32Premul(tileSize)) {} | |
34 | |
35 protected: | |
36 virtual bool onGetInfo(SkImageInfo *info) SK_OVERRIDE { | |
37 *info = fRasterTileInfo; | |
38 return true; | |
39 } | |
40 | |
41 virtual Result onGetPixels(const SkImageInfo& info, void *pixels, size_t row
Bytes, | |
42 SkPMColor ctable[], int *ctableCount) SK_OVERRIDE { | |
43 if (info != fRasterTileInfo || SkToBool(ctable) || SkToBool(ctableCount)
) { | |
44 return kInvalidConversion; | |
45 } | |
46 | |
47 SkSize tileScale = SkSize::Make(SkIntToScalar(info.width()) / fPictureTi
le.width(), | |
48 SkIntToScalar(info.height()) / fPictureT
ile.height()); | |
49 SkBitmap tileBitmap; | |
50 if (!tileBitmap.installPixels(info, pixels, rowBytes)) { | |
51 return kInvalidParameters; | |
52 } | |
53 tileBitmap.eraseColor(SK_ColorTRANSPARENT); | |
54 | |
55 // Always disable LCD text, since we can't assume our image will be opaq
ue. | |
56 SkCanvas tileCanvas(tileBitmap, SkSurfaceProps(0, kUnknown_SkPixelGeomet
ry)); | |
57 tileCanvas.scale(tileScale.width(), tileScale.height()); | |
58 tileCanvas.translate(-fPictureTile.x(), -fPictureTile.y()); | |
59 tileCanvas.drawPicture(fPicture); | |
60 | |
61 return kSuccess; | |
62 } | |
63 | |
64 private: | |
65 SkAutoTUnref<const SkPicture> fPicture; | |
66 const SkRect fPictureTile; | |
67 const SkImageInfo fRasterTileInfo; | |
68 }; | |
69 | |
70 struct BitmapShaderKey : public SkResourceCache::Key { | 25 struct BitmapShaderKey : public SkResourceCache::Key { |
71 public: | 26 public: |
72 BitmapShaderKey(uint32_t pictureID, | 27 BitmapShaderKey(uint32_t pictureID, |
73 const SkRect& tile, | 28 const SkRect& tile, |
74 SkShader::TileMode tmx, | 29 SkShader::TileMode tmx, |
75 SkShader::TileMode tmy, | 30 SkShader::TileMode tmy, |
76 const SkSize& scale, | 31 const SkSize& scale, |
77 const SkMatrix& localMatrix) | 32 const SkMatrix& localMatrix) |
78 : fPictureID(pictureID) | 33 : fPictureID(pictureID) |
79 , fTile(tile) | 34 , fTile(tile) |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 size_t bytesUsed() const SK_OVERRIDE { | 74 size_t bytesUsed() const SK_OVERRIDE { |
120 return sizeof(fKey) + sizeof(SkShader) + fBitmapBytes; | 75 return sizeof(fKey) + sizeof(SkShader) + fBitmapBytes; |
121 } | 76 } |
122 | 77 |
123 static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextShader
) { | 78 static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextShader
) { |
124 const BitmapShaderRec& rec = static_cast<const BitmapShaderRec&>(baseRec
); | 79 const BitmapShaderRec& rec = static_cast<const BitmapShaderRec&>(baseRec
); |
125 SkAutoTUnref<SkShader>* result = reinterpret_cast<SkAutoTUnref<SkShader>
*>(contextShader); | 80 SkAutoTUnref<SkShader>* result = reinterpret_cast<SkAutoTUnref<SkShader>
*>(contextShader); |
126 | 81 |
127 result->reset(SkRef(rec.fShader.get())); | 82 result->reset(SkRef(rec.fShader.get())); |
128 | 83 |
129 // The bitmap shader is backed by an image generator, thus it can always
re-generate its | 84 SkBitmap tile; |
130 // pixels if discarded. | 85 rec.fShader.get()->asABitmap(&tile, NULL, NULL); |
131 return true; | 86 // FIXME: this doesn't protect the pixels from being discarded as soon a
s we unlock. |
| 87 // Should be handled via a pixel ref generator instead |
| 88 // (https://code.google.com/p/skia/issues/detail?id=3220). |
| 89 SkAutoLockPixels alp(tile, true); |
| 90 return tile.getPixels() != NULL; |
132 } | 91 } |
133 }; | 92 }; |
134 | 93 |
| 94 static bool cache_try_alloc_pixels(SkBitmap* bitmap) { |
| 95 SkBitmap::Allocator* allocator = SkResourceCache::GetAllocator(); |
| 96 |
| 97 return NULL != allocator |
| 98 ? allocator->allocPixelRef(bitmap, NULL) |
| 99 : bitmap->tryAllocPixels(); |
| 100 } |
| 101 |
135 } // namespace | 102 } // namespace |
136 | 103 |
137 SkPictureShader::SkPictureShader(const SkPicture* picture, TileMode tmx, TileMod
e tmy, | 104 SkPictureShader::SkPictureShader(const SkPicture* picture, TileMode tmx, TileMod
e tmy, |
138 const SkMatrix* localMatrix, const SkRect* tile
) | 105 const SkMatrix* localMatrix, const SkRect* tile
) |
139 : INHERITED(localMatrix) | 106 : INHERITED(localMatrix) |
140 , fPicture(SkRef(picture)) | 107 , fPicture(SkRef(picture)) |
141 , fTile(tile ? *tile : picture->cullRect()) | 108 , fTile(tile ? *tile : picture->cullRect()) |
142 , fTmx(tmx) | 109 , fTmx(tmx) |
143 , fTmy(tmy) { | 110 , fTmy(tmy) { |
144 } | 111 } |
145 | 112 |
| 113 SkPictureShader::~SkPictureShader() { |
| 114 fPicture->unref(); |
| 115 } |
| 116 |
146 SkPictureShader* SkPictureShader::Create(const SkPicture* picture, TileMode tmx,
TileMode tmy, | 117 SkPictureShader* SkPictureShader::Create(const SkPicture* picture, TileMode tmx,
TileMode tmy, |
147 const SkMatrix* localMatrix, const SkRe
ct* tile) { | 118 const SkMatrix* localMatrix, const SkRe
ct* tile) { |
148 if (!picture || picture->cullRect().isEmpty() || (tile && tile->isEmpty()))
{ | 119 if (!picture || picture->cullRect().isEmpty() || (tile && tile->isEmpty()))
{ |
149 return NULL; | 120 return NULL; |
150 } | 121 } |
151 return SkNEW_ARGS(SkPictureShader, (picture, tmx, tmy, localMatrix, tile)); | 122 return SkNEW_ARGS(SkPictureShader, (picture, tmx, tmy, localMatrix, tile)); |
152 } | 123 } |
153 | 124 |
154 SkFlattenable* SkPictureShader::CreateProc(SkReadBuffer& buffer) { | 125 SkFlattenable* SkPictureShader::CreateProc(SkReadBuffer& buffer) { |
155 SkMatrix lm; | 126 SkMatrix lm; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 SkAutoTUnref<SkShader> tileShader; | 181 SkAutoTUnref<SkShader> tileShader; |
211 BitmapShaderKey key(fPicture->uniqueID(), | 182 BitmapShaderKey key(fPicture->uniqueID(), |
212 fTile, | 183 fTile, |
213 fTmx, | 184 fTmx, |
214 fTmy, | 185 fTmy, |
215 tileScale, | 186 tileScale, |
216 this->getLocalMatrix()); | 187 this->getLocalMatrix()); |
217 | 188 |
218 if (!SkResourceCache::Find(key, BitmapShaderRec::Visitor, &tileShader)) { | 189 if (!SkResourceCache::Find(key, BitmapShaderRec::Visitor, &tileShader)) { |
219 SkBitmap bm; | 190 SkBitmap bm; |
220 if (!SkInstallDiscardablePixelRef(SkNEW_ARGS(PictureImageGenerator, | 191 bm.setInfo(SkImageInfo::MakeN32Premul(tileSize)); |
221 (fPicture, fTile, tileSize)
), &bm)) { | 192 if (!cache_try_alloc_pixels(&bm)) { |
222 return NULL; | 193 return NULL; |
223 } | 194 } |
| 195 bm.eraseColor(SK_ColorTRANSPARENT); |
| 196 |
| 197 // Always disable LCD text, since we can't assume our image will be opaq
ue. |
| 198 SkCanvas canvas(bm, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); |
| 199 |
| 200 canvas.scale(tileScale.width(), tileScale.height()); |
| 201 canvas.translate(-fTile.x(), -fTile.y()); |
| 202 canvas.drawPicture(fPicture); |
224 | 203 |
225 SkMatrix shaderMatrix = this->getLocalMatrix(); | 204 SkMatrix shaderMatrix = this->getLocalMatrix(); |
226 shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height()); | 205 shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height()); |
227 tileShader.reset(CreateBitmapShader(bm, fTmx, fTmy, &shaderMatrix)); | 206 tileShader.reset(CreateBitmapShader(bm, fTmx, fTmy, &shaderMatrix)); |
228 | 207 |
229 SkResourceCache::Add(SkNEW_ARGS(BitmapShaderRec, (key, tileShader.get(),
bm.getSize()))); | 208 SkResourceCache::Add(SkNEW_ARGS(BitmapShaderRec, (key, tileShader.get(),
bm.getSize()))); |
230 } | 209 } |
231 | 210 |
232 return tileShader.detach(); | 211 return tileShader.detach(); |
233 } | 212 } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 fBitmapShaderContext->shadeSpan16(x, y, dstC, count); | 273 fBitmapShaderContext->shadeSpan16(x, y, dstC, count); |
295 } | 274 } |
296 | 275 |
297 #ifndef SK_IGNORE_TO_STRING | 276 #ifndef SK_IGNORE_TO_STRING |
298 void SkPictureShader::toString(SkString* str) const { | 277 void SkPictureShader::toString(SkString* str) const { |
299 static const char* gTileModeName[SkShader::kTileModeCount] = { | 278 static const char* gTileModeName[SkShader::kTileModeCount] = { |
300 "clamp", "repeat", "mirror" | 279 "clamp", "repeat", "mirror" |
301 }; | 280 }; |
302 | 281 |
303 str->appendf("PictureShader: [%f:%f:%f:%f] ", | 282 str->appendf("PictureShader: [%f:%f:%f:%f] ", |
304 fPicture->cullRect().fLeft, | 283 fPicture ? fPicture->cullRect().fLeft : 0, |
305 fPicture->cullRect().fTop, | 284 fPicture ? fPicture->cullRect().fTop : 0, |
306 fPicture->cullRect().fRight, | 285 fPicture ? fPicture->cullRect().fRight : 0, |
307 fPicture->cullRect().fBottom); | 286 fPicture ? fPicture->cullRect().fBottom : 0); |
308 | 287 |
309 str->appendf("(%s, %s)", gTileModeName[fTmx], gTileModeName[fTmy]); | 288 str->appendf("(%s, %s)", gTileModeName[fTmx], gTileModeName[fTmy]); |
310 | 289 |
311 this->INHERITED::toString(str); | 290 this->INHERITED::toString(str); |
312 } | 291 } |
313 #endif | 292 #endif |
314 | 293 |
315 #if SK_SUPPORT_GPU | 294 #if SK_SUPPORT_GPU |
316 bool SkPictureShader::asFragmentProcessor(GrContext* context, const SkPaint& pai
nt, | 295 bool SkPictureShader::asFragmentProcessor(GrContext* context, const SkPaint& pai
nt, |
317 const SkMatrix& viewM, const SkMatrix*
localMatrix, | 296 const SkMatrix& viewM, const SkMatrix*
localMatrix, |
318 GrColor* paintColor, | 297 GrColor* paintColor, |
319 GrFragmentProcessor** fp) const { | 298 GrFragmentProcessor** fp) const { |
320 SkAutoTUnref<SkShader> bitmapShader(this->refBitmapShader(viewM, localMatrix
)); | 299 SkAutoTUnref<SkShader> bitmapShader(this->refBitmapShader(viewM, localMatrix
)); |
321 if (!bitmapShader) { | 300 if (!bitmapShader) { |
322 return false; | 301 return false; |
323 } | 302 } |
324 return bitmapShader->asFragmentProcessor(context, paint, viewM, NULL, paintC
olor, fp); | 303 return bitmapShader->asFragmentProcessor(context, paint, viewM, NULL, paintC
olor, fp); |
325 } | 304 } |
326 #else | 305 #else |
327 bool SkPictureShader::asFragmentProcessor(GrContext*, const SkPaint&, const SkMa
trix&, | 306 bool SkPictureShader::asFragmentProcessor(GrContext*, const SkPaint&, const SkMa
trix&, |
328 const SkMatrix*, GrColor*, | 307 const SkMatrix*, GrColor*, |
329 GrFragmentProcessor**) const { | 308 GrFragmentProcessor**) const { |
330 SkDEBUGFAIL("Should not call in GPU-less build"); | 309 SkDEBUGFAIL("Should not call in GPU-less build"); |
331 return false; | 310 return false; |
332 } | 311 } |
333 #endif | 312 #endif |
OLD | NEW |