OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2010 Google Inc. | 2 * Copyright 2010 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 "GrTextureMaker.h" | |
9 | 8 |
10 #include "SkGr.h" | 9 #include "SkGr.h" |
11 | 10 |
12 #include "GrCaps.h" | 11 #include "GrCaps.h" |
13 #include "GrContext.h" | 12 #include "GrContext.h" |
14 #include "GrDrawContext.h" | 13 #include "GrTextureParamsAdjuster.h" |
| 14 #include "GrGpuResourcePriv.h" |
15 #include "GrXferProcessor.h" | 15 #include "GrXferProcessor.h" |
16 #include "GrYUVProvider.h" | 16 #include "GrYUVProvider.h" |
17 | 17 |
18 #include "SkColorFilter.h" | 18 #include "SkColorFilter.h" |
19 #include "SkConfig8888.h" | 19 #include "SkConfig8888.h" |
20 #include "SkCanvas.h" | 20 #include "SkCanvas.h" |
21 #include "SkData.h" | 21 #include "SkData.h" |
22 #include "SkErrorInternals.h" | 22 #include "SkErrorInternals.h" |
23 #include "SkGrPixelRef.h" | 23 #include "SkGrPixelRef.h" |
24 #include "SkMessageBus.h" | 24 #include "SkMessageBus.h" |
(...skipping 16 matching lines...) Expand all Loading... |
41 GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo& info) { | 41 GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo& info) { |
42 GrSurfaceDesc desc; | 42 GrSurfaceDesc desc; |
43 desc.fFlags = kNone_GrSurfaceFlags; | 43 desc.fFlags = kNone_GrSurfaceFlags; |
44 desc.fWidth = info.width(); | 44 desc.fWidth = info.width(); |
45 desc.fHeight = info.height(); | 45 desc.fHeight = info.height(); |
46 desc.fConfig = SkImageInfo2GrPixelConfig(info); | 46 desc.fConfig = SkImageInfo2GrPixelConfig(info); |
47 desc.fSampleCnt = 0; | 47 desc.fSampleCnt = 0; |
48 return desc; | 48 return desc; |
49 } | 49 } |
50 | 50 |
51 static void get_stretch(const GrCaps& caps, int width, int height, | 51 void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& ima
geBounds) { |
52 const GrTextureParams& params, SkGrStretch* stretch) { | 52 SkASSERT(key); |
53 stretch->fType = SkGrStretch::kNone_Type; | 53 SkASSERT(imageID); |
54 bool doStretch = false; | 54 SkASSERT(!imageBounds.isEmpty()); |
55 if (params.isTiled() && !caps.npotTextureTileSupport() && | 55 static const GrUniqueKey::Domain kImageIDDomain = GrUniqueKey::GenerateDomai
n(); |
56 (!SkIsPow2(width) || !SkIsPow2(height))) { | 56 GrUniqueKey::Builder builder(key, kImageIDDomain, 5); |
57 doStretch = true; | |
58 stretch->fWidth = GrNextPow2(SkTMax(width, caps.minTextureSize())); | |
59 stretch->fHeight = GrNextPow2(SkTMax(height, caps.minTextureSize())); | |
60 } else if (width < caps.minTextureSize() || height < caps.minTextureSize())
{ | |
61 // The small texture issues appear to be with tiling. Hence it seems ok
to scale them | |
62 // up using the GPU. If issues persist we may need to CPU-stretch. | |
63 doStretch = true; | |
64 stretch->fWidth = SkTMax(width, caps.minTextureSize()); | |
65 stretch->fHeight = SkTMax(height, caps.minTextureSize()); | |
66 } | |
67 if (doStretch) { | |
68 switch (params.filterMode()) { | |
69 case GrTextureParams::kNone_FilterMode: | |
70 stretch->fType = SkGrStretch::kNearest_Type; | |
71 break; | |
72 case GrTextureParams::kBilerp_FilterMode: | |
73 case GrTextureParams::kMipMap_FilterMode: | |
74 stretch->fType = SkGrStretch::kBilerp_Type; | |
75 break; | |
76 } | |
77 } else { | |
78 stretch->fWidth = -1; | |
79 stretch->fHeight = -1; | |
80 stretch->fType = SkGrStretch::kNone_Type; | |
81 } | |
82 } | |
83 | |
84 static void make_unstretched_key(GrUniqueKey* key, uint32_t imageID, const SkIRe
ct& subset) { | |
85 SkASSERT(SkIsU16(subset.width())); | |
86 SkASSERT(SkIsU16(subset.height())); | |
87 | |
88 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); | |
89 GrUniqueKey::Builder builder(key, kDomain, 4); | |
90 builder[0] = imageID; | 57 builder[0] = imageID; |
91 builder[1] = subset.x(); | 58 builder[1] = imageBounds.fLeft; |
92 builder[2] = subset.y(); | 59 builder[2] = imageBounds.fTop; |
93 builder[3] = subset.width() | (subset.height() << 16); | 60 builder[3] = imageBounds.fRight; |
94 } | 61 builder[4] = imageBounds.fBottom; |
95 | |
96 void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& sub
set, | |
97 const GrCaps& caps, const GrTextureParams& params) { | |
98 SkGrStretch stretch; | |
99 get_stretch(caps, subset.width(), subset.height(), params, &stretch); | |
100 if (SkGrStretch::kNone_Type != stretch.fType) { | |
101 GrUniqueKey tmpKey; | |
102 make_unstretched_key(&tmpKey, imageID, subset); | |
103 if (!GrMakeStretchedKey(tmpKey, stretch, key)) { | |
104 *key = tmpKey; | |
105 } | |
106 } else { | |
107 make_unstretched_key(key, imageID, subset); | |
108 } | |
109 } | 62 } |
110 | 63 |
111 GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data, | 64 GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data, |
112 int expectedW, int expectedH, | 65 int expectedW, int expectedH, |
113 const void** outStartOfDataToUp
load) { | 66 const void** outStartOfDataToUp
load) { |
114 *outStartOfDataToUpload = nullptr; | 67 *outStartOfDataToUpload = nullptr; |
115 #ifndef SK_IGNORE_ETC1_SUPPORT | 68 #ifndef SK_IGNORE_ETC1_SUPPORT |
116 if (!ctx->caps()->isConfigTexturable(kETC1_GrPixelConfig)) { | 69 if (!ctx->caps()->isConfigTexturable(kETC1_GrPixelConfig)) { |
117 return kUnknown_GrPixelConfig; | 70 return kUnknown_GrPixelConfig; |
118 } | 71 } |
(...skipping 24 matching lines...) Expand all Loading... |
143 return kUnknown_GrPixelConfig; | 96 return kUnknown_GrPixelConfig; |
144 } | 97 } |
145 | 98 |
146 *outStartOfDataToUpload = ktx.pixelData(); | 99 *outStartOfDataToUpload = ktx.pixelData(); |
147 return kETC1_GrPixelConfig; | 100 return kETC1_GrPixelConfig; |
148 } | 101 } |
149 #endif | 102 #endif |
150 return kUnknown_GrPixelConfig; | 103 return kUnknown_GrPixelConfig; |
151 } | 104 } |
152 | 105 |
153 /* Fill out buffer with the compressed format Ganesh expects from a colortable | 106 ////////////////////////////////////////////////////////////////////////////// |
154 based bitmap. [palette (colortable) + indices]. | |
155 | 107 |
156 At the moment Ganesh only supports 8bit version. If Ganesh allowed we others | 108 /** |
157 we could detect that the colortable.count is <= 16, and then repack the | 109 * Fill out buffer with the compressed format Ganesh expects from a colortable |
158 indices as nibbles to save RAM, but it would take more time (i.e. a lot | 110 * based bitmap. [palette (colortable) + indices]. |
159 slower than memcpy), so skipping that for now. | 111 * |
160 | 112 * At the moment Ganesh only supports 8bit version. If Ganesh allowed we others |
161 Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big | 113 * we could detect that the colortable.count is <= 16, and then repack the |
162 as the colortable.count says it is. | 114 * indices as nibbles to save RAM, but it would take more time (i.e. a lot |
| 115 * slower than memcpy), so skipping that for now. |
| 116 * |
| 117 * Ganesh wants a full 256 palette entry, even though Skia's ctable is only as b
ig |
| 118 * as the colortable.count says it is. |
163 */ | 119 */ |
164 static void build_index8_data(void* buffer, const SkBitmap& bitmap) { | 120 static void build_index8_data(void* buffer, const SkBitmap& bitmap) { |
165 SkASSERT(kIndex_8_SkColorType == bitmap.colorType()); | 121 SkASSERT(kIndex_8_SkColorType == bitmap.colorType()); |
166 | 122 |
167 SkAutoLockPixels alp(bitmap); | 123 SkAutoLockPixels alp(bitmap); |
168 if (!bitmap.readyToDraw()) { | 124 if (!bitmap.readyToDraw()) { |
169 SkDEBUGFAIL("bitmap not ready to draw!"); | 125 SkDEBUGFAIL("bitmap not ready to draw!"); |
170 return; | 126 return; |
171 } | 127 } |
172 | 128 |
(...skipping 27 matching lines...) Expand all Loading... |
200 size_t rowBytes = bitmap.rowBytes(); | 156 size_t rowBytes = bitmap.rowBytes(); |
201 const char* src = (const char*)bitmap.getPixels(); | 157 const char* src = (const char*)bitmap.getPixels(); |
202 for (int y = 0; y < bitmap.height(); y++) { | 158 for (int y = 0; y < bitmap.height(); y++) { |
203 memcpy(dst, src, width); | 159 memcpy(dst, src, width); |
204 src += rowBytes; | 160 src += rowBytes; |
205 dst += width; | 161 dst += width; |
206 } | 162 } |
207 } | 163 } |
208 } | 164 } |
209 | 165 |
210 //////////////////////////////////////////////////////////////////////////////// | 166 /** |
211 | |
212 | |
213 bool GrMakeStretchedKey(const GrUniqueKey& origKey, const SkGrStretch& stretch, | |
214 GrUniqueKey* stretchedKey) { | |
215 if (origKey.isValid() && SkGrStretch::kNone_Type != stretch.fType) { | |
216 uint32_t width = SkToU16(stretch.fWidth); | |
217 uint32_t height = SkToU16(stretch.fHeight); | |
218 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; | |
219 GrUniqueKey::Builder builder(stretchedKey, origKey, kDomain, 2); | |
220 builder[0] = stretch.fType; | |
221 builder[1] = width | (height << 16); | |
222 builder.finish(); | |
223 return true; | |
224 } | |
225 SkASSERT(!stretchedKey->isValid()); | |
226 return false; | |
227 } | |
228 | |
229 namespace { | |
230 | |
231 // When the SkPixelRef genID changes, invalidate a corresponding GrResource desc
ribed by key. | |
232 class BitmapInvalidator : public SkPixelRef::GenIDChangeListener { | |
233 public: | |
234 explicit BitmapInvalidator(const GrUniqueKey& key) : fMsg(key) {} | |
235 private: | |
236 GrUniqueKeyInvalidatedMessage fMsg; | |
237 | |
238 void onChange() override { | |
239 SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); | |
240 } | |
241 }; | |
242 | |
243 } // namespace | |
244 | |
245 | |
246 GrTexture* GrCreateTextureForPixels(GrContext* ctx, | |
247 const GrUniqueKey& optionalKey, | |
248 GrSurfaceDesc desc, | |
249 SkPixelRef* pixelRefForInvalidationNotificat
ion, | |
250 const void* pixels, | |
251 size_t rowBytes) { | |
252 GrTexture* result = ctx->textureProvider()->createTexture(desc, true, pixels
, rowBytes); | |
253 if (result && optionalKey.isValid()) { | |
254 if (pixelRefForInvalidationNotification) { | |
255 BitmapInvalidator* listener = new BitmapInvalidator(optionalKey); | |
256 pixelRefForInvalidationNotification->addGenIDChangeListener(listener
); | |
257 } | |
258 ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, result); | |
259 } | |
260 return result; | |
261 } | |
262 | |
263 // creates a new texture that is the input texture scaled up. If optionalKey is
valid it will be | |
264 // set on the new texture. stretch controls whether the scaling is done using ne
arest or bilerp | |
265 // filtering and the size to stretch the texture to. | |
266 GrTexture* stretch_texture(GrTexture* inputTexture, const SkGrStretch& stretch, | |
267 SkPixelRef* pixelRef, | |
268 const GrUniqueKey& optionalKey) { | |
269 SkASSERT(SkGrStretch::kNone_Type != stretch.fType); | |
270 | |
271 GrContext* context = inputTexture->getContext(); | |
272 SkASSERT(context); | |
273 const GrCaps* caps = context->caps(); | |
274 | |
275 // Either it's a cache miss or the original wasn't cached to begin with. | |
276 GrSurfaceDesc rtDesc = inputTexture->desc(); | |
277 rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag; | |
278 rtDesc.fWidth = stretch.fWidth; | |
279 rtDesc.fHeight = stretch.fHeight; | |
280 rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig); | |
281 | |
282 // If the config isn't renderable try converting to either A8 or an 32 bit c
onfig. Otherwise, | |
283 // fail. | |
284 if (!caps->isConfigRenderable(rtDesc.fConfig, false)) { | |
285 if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) { | |
286 if (caps->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { | |
287 rtDesc.fConfig = kAlpha_8_GrPixelConfig; | |
288 } else if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false))
{ | |
289 rtDesc.fConfig = kSkia8888_GrPixelConfig; | |
290 } else { | |
291 return nullptr; | |
292 } | |
293 } else if (kRGB_GrColorComponentFlags == | |
294 (kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDe
sc.fConfig))) { | |
295 if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) { | |
296 rtDesc.fConfig = kSkia8888_GrPixelConfig; | |
297 } else { | |
298 return nullptr; | |
299 } | |
300 } else { | |
301 return nullptr; | |
302 } | |
303 } | |
304 | |
305 SkAutoTUnref<GrTexture> stretched(GrCreateTextureForPixels(context, optional
Key, rtDesc, | |
306 pixelRef, nullptr
,0)); | |
307 if (!stretched) { | |
308 return nullptr; | |
309 } | |
310 GrPaint paint; | |
311 | |
312 // If filtering is not desired then we want to ensure all texels in the resa
mpled image are | |
313 // copies of texels from the original. | |
314 GrTextureParams params(SkShader::kClamp_TileMode, | |
315 SkGrStretch::kBilerp_Type == stretch.fType ? | |
316 GrTextureParams::kBilerp_FilterMode : | |
317 GrTextureParams::kNone_FilterMode); | |
318 paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params); | |
319 | |
320 SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtD
esc.fHeight)); | |
321 SkRect localRect = SkRect::MakeWH(1.f, 1.f); | |
322 | |
323 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(stretched->asRe
nderTarget())); | |
324 if (!drawContext) { | |
325 return nullptr; | |
326 } | |
327 | |
328 drawContext->drawNonAARectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), r
ect, localRect); | |
329 | |
330 return stretched.detach(); | |
331 } | |
332 | |
333 /* | |
334 * Once we have made SkImages handle all lazy/deferred/generated content, the Y
UV apis will | 167 * Once we have made SkImages handle all lazy/deferred/generated content, the Y
UV apis will |
335 * be gone from SkPixelRef, and we can remove this subclass entirely. | 168 * be gone from SkPixelRef, and we can remove this subclass entirely. |
336 */ | 169 */ |
337 class PixelRef_GrYUVProvider : public GrYUVProvider { | 170 class PixelRef_GrYUVProvider : public GrYUVProvider { |
338 SkPixelRef* fPR; | 171 SkPixelRef* fPR; |
339 | 172 |
340 public: | 173 public: |
341 PixelRef_GrYUVProvider(SkPixelRef* pr) : fPR(pr) {} | 174 PixelRef_GrYUVProvider(SkPixelRef* pr) : fPR(pr) {} |
342 | 175 |
343 uint32_t onGetID() override { return fPR->getGenerationID(); } | 176 uint32_t onGetID() override { return fPR->getGenerationID(); } |
344 bool onGetYUVSizes(SkISize sizes[3]) override { | 177 bool onGetYUVSizes(SkISize sizes[3]) override { |
345 return fPR->getYUV8Planes(sizes, nullptr, nullptr, nullptr); | 178 return fPR->getYUV8Planes(sizes, nullptr, nullptr, nullptr); |
346 } | 179 } |
347 bool onGetYUVPlanes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], | 180 bool onGetYUVPlanes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], |
348 SkYUVColorSpace* space) override { | 181 SkYUVColorSpace* space) override { |
349 return fPR->getYUV8Planes(sizes, planes, rowBytes, space); | 182 return fPR->getYUV8Planes(sizes, planes, rowBytes, space); |
350 } | 183 } |
351 }; | 184 }; |
352 | 185 |
353 static GrTexture* load_yuv_texture(GrContext* ctx, const GrUniqueKey& optionalKe
y, | 186 static GrTexture* create_texture_from_yuv(GrContext* ctx, const SkBitmap& bm, |
354 const SkBitmap& bm, const GrSurfaceDesc& desc
) { | 187 const GrSurfaceDesc& desc) { |
355 // Subsets are not supported, the whole pixelRef is loaded when using YUV de
coding | 188 // Subsets are not supported, the whole pixelRef is loaded when using YUV de
coding |
356 SkPixelRef* pixelRef = bm.pixelRef(); | 189 SkPixelRef* pixelRef = bm.pixelRef(); |
357 if ((nullptr == pixelRef) || | 190 if ((nullptr == pixelRef) || |
358 (pixelRef->info().width() != bm.info().width()) || | 191 (pixelRef->info().width() != bm.info().width()) || |
359 (pixelRef->info().height() != bm.info().height())) { | 192 (pixelRef->info().height() != bm.info().height())) { |
360 return nullptr; | 193 return nullptr; |
361 } | 194 } |
362 | 195 |
363 const bool useCache = optionalKey.isValid(); | |
364 PixelRef_GrYUVProvider provider(pixelRef); | 196 PixelRef_GrYUVProvider provider(pixelRef); |
365 GrTexture* texture = provider.refAsTexture(ctx, desc, useCache); | |
366 if (!texture) { | |
367 return nullptr; | |
368 } | |
369 | 197 |
370 if (useCache) { | 198 return provider.refAsTexture(ctx, desc, !bm.isVolatile()); |
371 BitmapInvalidator* listener = new BitmapInvalidator(optionalKey); | |
372 pixelRef->addGenIDChangeListener(listener); | |
373 ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, texture); | |
374 } | |
375 return texture; | |
376 } | 199 } |
377 | 200 |
378 static GrTexture* load_etc1_texture(GrContext* ctx, const GrUniqueKey& optionalK
ey, | 201 static GrTexture* load_etc1_texture(GrContext* ctx, const SkBitmap &bm, GrSurfac
eDesc desc) { |
379 const SkBitmap &bm, GrSurfaceDesc desc) { | |
380 SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData()); | 202 SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData()); |
381 if (!data) { | 203 if (!data) { |
382 return nullptr; | 204 return nullptr; |
383 } | 205 } |
384 | 206 |
385 const void* startOfTexData; | 207 const void* startOfTexData; |
386 desc.fConfig = GrIsCompressedTextureDataSupported(ctx, data, bm.width(), bm.
height(), | 208 desc.fConfig = GrIsCompressedTextureDataSupported(ctx, data, bm.width(), bm.
height(), |
387 &startOfTexData); | 209 &startOfTexData); |
388 if (kUnknown_GrPixelConfig == desc.fConfig) { | 210 if (kUnknown_GrPixelConfig == desc.fConfig) { |
389 return nullptr; | 211 return nullptr; |
390 } | 212 } |
391 | 213 |
392 return GrCreateTextureForPixels(ctx, optionalKey, desc, bm.pixelRef(), start
OfTexData, 0); | 214 return ctx->textureProvider()->createTexture(desc, true, startOfTexData, 0); |
393 } | 215 } |
394 | 216 |
395 static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx, | 217 GrTexture* GrUploadBitmapToTexture(GrContext* ctx, const SkBitmap& bmp) { |
396 const SkBitmap& origBitmap, | 218 SkASSERT(!bmp.getTexture()); |
397 const GrUniqueKey& optionalK
ey) { | 219 |
398 if (origBitmap.width() < ctx->caps()->minTextureSize() || | 220 if (bmp.width() < ctx->caps()->minTextureSize() || |
399 origBitmap.height() < ctx->caps()->minTextureSize()) { | 221 bmp.height() < ctx->caps()->minTextureSize()) { |
400 return nullptr; | 222 return nullptr; |
401 } | 223 } |
| 224 |
402 SkBitmap tmpBitmap; | 225 SkBitmap tmpBitmap; |
403 | 226 const SkBitmap* bitmap = &bmp; |
404 const SkBitmap* bitmap = &origBitmap; | |
405 | 227 |
406 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bitmap->info()); | 228 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bitmap->info()); |
407 const GrCaps* caps = ctx->caps(); | 229 const GrCaps* caps = ctx->caps(); |
408 | 230 |
409 if (kIndex_8_SkColorType == bitmap->colorType()) { | 231 if (kIndex_8_SkColorType == bitmap->colorType()) { |
410 if (caps->isConfigTexturable(kIndex_8_GrPixelConfig)) { | 232 if (caps->isConfigTexturable(kIndex_8_GrPixelConfig)) { |
411 size_t imageSize = GrCompressedFormatDataSize(kIndex_8_GrPixelConfig
, | 233 size_t imageSize = GrCompressedFormatDataSize(kIndex_8_GrPixelConfig
, |
412 bitmap->width(), bitma
p->height()); | 234 bitmap->width(), bitma
p->height()); |
413 SkAutoMalloc storage(imageSize); | 235 SkAutoMalloc storage(imageSize); |
414 build_index8_data(storage.get(), origBitmap); | 236 build_index8_data(storage.get(), bmp); |
415 | 237 |
416 // our compressed data will be trimmed, so pass width() for its | 238 // our compressed data will be trimmed, so pass width() for its |
417 // "rowBytes", since they are the same now. | 239 // "rowBytes", since they are the same now. |
418 return GrCreateTextureForPixels(ctx, optionalKey, desc, origBitmap.p
ixelRef(), | 240 return ctx->textureProvider()->createTexture(desc, true, storage.get
(), |
419 storage.get(), bitmap->width()); | 241 bitmap->width()); |
420 } else { | 242 } else { |
421 origBitmap.copyTo(&tmpBitmap, kN32_SkColorType); | 243 bmp.copyTo(&tmpBitmap, kN32_SkColorType); |
422 // now bitmap points to our temp, which has been promoted to 32bits | 244 // now bitmap points to our temp, which has been promoted to 32bits |
423 bitmap = &tmpBitmap; | 245 bitmap = &tmpBitmap; |
424 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap->info()); | 246 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap->info()); |
425 } | 247 } |
426 } else if (!bitmap->readyToDraw()) { | 248 } else if (!bitmap->readyToDraw()) { |
427 // If the bitmap had compressed data and was then uncompressed, it'll st
ill return | 249 // If the bitmap had compressed data and was then uncompressed, it'll st
ill return |
428 // compressed data on 'refEncodedData' and upload it. Probably not good,
since if | 250 // compressed data on 'refEncodedData' and upload it. Probably not good,
since if |
429 // the bitmap has available pixels, then they might not be what the deco
mpressed | 251 // the bitmap has available pixels, then they might not be what the deco
mpressed |
430 // data is. | 252 // data is. |
431 GrTexture *texture = load_etc1_texture(ctx, optionalKey, *bitmap, desc); | 253 |
| 254 // Really?? We aren't doing this with YUV. |
| 255 |
| 256 GrTexture *texture = load_etc1_texture(ctx, *bitmap, desc); |
432 if (texture) { | 257 if (texture) { |
433 return texture; | 258 return texture; |
434 } | 259 } |
435 } | 260 } |
436 | 261 |
437 GrTexture *texture = load_yuv_texture(ctx, optionalKey, *bitmap, desc); | 262 GrTexture *texture = create_texture_from_yuv(ctx, *bitmap, desc); |
438 if (texture) { | 263 if (texture) { |
439 return texture; | 264 return texture; |
440 } | 265 } |
441 | 266 |
442 SkAutoLockPixels alp(*bitmap); | 267 SkAutoLockPixels alp(*bitmap); |
443 if (!bitmap->readyToDraw()) { | 268 if (!bitmap->readyToDraw()) { |
444 return nullptr; | 269 return nullptr; |
445 } | 270 } |
446 | 271 |
447 return GrCreateTextureForPixels(ctx, optionalKey, desc, origBitmap.pixelRef(
), | 272 return ctx->textureProvider()->createTexture(desc, true, bitmap->getPixels()
, |
448 bitmap->getPixels(), bitmap->rowBytes()); | 273 bitmap->rowBytes()); |
449 } | 274 } |
450 | 275 |
451 static SkBitmap stretch_on_cpu(const SkBitmap& bmp, const SkGrStretch& stretch)
{ | |
452 SkBitmap stretched; | |
453 stretched.allocN32Pixels(stretch.fWidth, stretch.fHeight); | |
454 SkCanvas canvas(stretched); | |
455 SkPaint paint; | |
456 switch (stretch.fType) { | |
457 case SkGrStretch::kNearest_Type: | |
458 paint.setFilterQuality(kNone_SkFilterQuality); | |
459 break; | |
460 case SkGrStretch::kBilerp_Type: | |
461 paint.setFilterQuality(kLow_SkFilterQuality); | |
462 break; | |
463 case SkGrStretch::kNone_Type: | |
464 SkDEBUGFAIL("Shouldn't get here."); | |
465 break; | |
466 } | |
467 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(stretch.fWidth), SkIntToScalar
(stretch.fHeight)); | |
468 canvas.drawBitmapRect(bmp, dstRect, &paint); | |
469 return stretched; | |
470 } | |
471 | 276 |
472 class Bitmap_GrTextureMaker : public GrTextureMaker { | 277 //////////////////////////////////////////////////////////////////////////////// |
| 278 |
| 279 class Bitmap_GrTextureParamsAdjuster : public GrTextureParamsAdjuster { |
473 public: | 280 public: |
474 Bitmap_GrTextureMaker(const SkBitmap& bitmap) | 281 Bitmap_GrTextureParamsAdjuster(const SkBitmap& bitmap) |
475 : INHERITED(bitmap.width(), bitmap.height()) | 282 : INHERITED(bitmap.width(), bitmap.height()) |
476 , fBitmap(bitmap) | 283 , fBitmap(bitmap) |
477 {} | 284 { |
| 285 if (!bitmap.isVolatile()) { |
| 286 SkIPoint origin = bitmap.pixelRefOrigin(); |
| 287 SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, bitmap.widt
h(), |
| 288 bitmap.height()); |
| 289 GrMakeKeyFromImageID(&fOriginalKey, bitmap.pixelRef()->getGeneration
ID(), subset); |
| 290 } |
| 291 } |
478 | 292 |
479 protected: | 293 protected: |
480 GrTexture* onRefUnstretchedTexture(GrContext* ctx) override { | 294 GrTexture* peekOriginalTexture() override { return fBitmap.getTexture(); } |
| 295 |
| 296 GrTexture* refOriginalTexture(GrContext* ctx) override { |
481 GrTexture* tex = fBitmap.getTexture(); | 297 GrTexture* tex = fBitmap.getTexture(); |
482 if (tex) { | 298 if (tex) { |
483 return SkRef(tex); | 299 return SkRef(tex); |
484 } | 300 } |
485 | 301 |
486 GrUniqueKey unstretchedKey; | 302 if (fOriginalKey.isValid()) { |
487 make_unstretched_key(&unstretchedKey, fBitmap.getGenerationID(), fBitmap
.getSubset()); | 303 tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(fOriginal
Key); |
| 304 if (tex) { |
| 305 return tex; |
| 306 } |
| 307 } |
488 | 308 |
489 GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey
(unstretchedKey); | 309 tex = GrUploadBitmapToTexture(ctx, fBitmap); |
490 if (result) { | 310 if (tex && fOriginalKey.isValid()) { |
491 return result; | 311 tex->resourcePriv().setUniqueKey(fOriginalKey); |
| 312 InstallInvalidator(fOriginalKey, fBitmap.pixelRef()); |
492 } | 313 } |
493 return create_unstretched_bitmap_texture(ctx, fBitmap, unstretchedKey); | 314 return tex; |
494 } | 315 } |
495 | 316 |
496 bool onMakeStretchedKey(const SkGrStretch& stretch, GrUniqueKey* stretchedKe
y) override { | 317 void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) overrid
e { |
497 if (fBitmap.isVolatile()) { | 318 if (fOriginalKey.isValid()) { |
498 return false; | 319 MakeCopyKeyFromOrigKey(fOriginalKey, copyParams, copyKey); |
499 } | 320 } |
500 | |
501 GrUniqueKey unstretchedKey; | |
502 make_unstretched_key(&unstretchedKey, fBitmap.getGenerationID(), fBitmap
.getSubset()); | |
503 return GrMakeStretchedKey(unstretchedKey, stretch, stretchedKey); | |
504 } | 321 } |
505 | 322 |
506 void onNotifyStretchCached(const GrUniqueKey& stretchedKey) override { | 323 void didCacheCopy(const GrUniqueKey& copyKey) override { |
507 fBitmap.pixelRef()->addGenIDChangeListener(new BitmapInvalidator(stretch
edKey)); | 324 InstallInvalidator(copyKey, fBitmap.pixelRef()); |
508 } | 325 } |
509 | 326 |
510 bool onGetROBitmap(SkBitmap* bitmap) override { | 327 bool getROBitmap(SkBitmap* bitmap) override { |
| 328 SkASSERT(!fBitmap.getTexture()); |
511 *bitmap = fBitmap; | 329 *bitmap = fBitmap; |
512 return true; | 330 return true; |
513 } | 331 } |
514 | 332 |
515 private: | 333 private: |
516 const SkBitmap fBitmap; | 334 static void InstallInvalidator(const GrUniqueKey& key, SkPixelRef* pixelRef)
{ |
| 335 class Invalidator : public SkPixelRef::GenIDChangeListener { |
| 336 public: |
| 337 explicit Invalidator(const GrUniqueKey& key) : fMsg(key) {} |
| 338 private: |
| 339 GrUniqueKeyInvalidatedMessage fMsg; |
517 | 340 |
518 typedef GrTextureMaker INHERITED; | 341 void onChange() override { |
| 342 SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); |
| 343 } |
| 344 }; |
| 345 Invalidator* listener = new Invalidator(key); |
| 346 pixelRef->addGenIDChangeListener(listener); |
| 347 } |
| 348 |
| 349 const SkBitmap fBitmap; |
| 350 GrUniqueKey fOriginalKey; |
| 351 |
| 352 typedef GrTextureParamsAdjuster INHERITED; |
519 }; | 353 }; |
520 | 354 |
521 GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap, | 355 GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap, |
522 const GrTextureParams& params) { | 356 const GrTextureParams& params) { |
523 return Bitmap_GrTextureMaker(bitmap).refCachedTexture(ctx, params); | 357 return Bitmap_GrTextureParamsAdjuster(bitmap).refTextureForParams(ctx, param
s); |
524 } | 358 } |
525 | 359 |
526 /////////////////////////////////////////////////////////////////////////////// | 360 /////////////////////////////////////////////////////////////////////////////// |
527 | 361 |
528 // alphatype is ignore for now, but if GrPixelConfig is expanded to encompass | 362 // alphatype is ignore for now, but if GrPixelConfig is expanded to encompass |
529 // alpha info, that will be considered. | 363 // alpha info, that will be considered. |
530 GrPixelConfig SkImageInfo2GrPixelConfig(SkColorType ct, SkAlphaType, SkColorProf
ileType pt) { | 364 GrPixelConfig SkImageInfo2GrPixelConfig(SkColorType ct, SkAlphaType, SkColorProf
ileType pt) { |
531 switch (ct) { | 365 switch (ct) { |
532 case kUnknown_SkColorType: | 366 case kUnknown_SkColorType: |
533 return kUnknown_GrPixelConfig; | 367 return kUnknown_GrPixelConfig; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
585 } | 419 } |
586 if (ctOut) { | 420 if (ctOut) { |
587 *ctOut = ct; | 421 *ctOut = ct; |
588 } | 422 } |
589 if (ptOut) { | 423 if (ptOut) { |
590 *ptOut = pt; | 424 *ptOut = pt; |
591 } | 425 } |
592 return true; | 426 return true; |
593 } | 427 } |
594 | 428 |
595 | |
596 ////////////////////////////////////////////////////////////////////////////////
//////////////// | 429 ////////////////////////////////////////////////////////////////////////////////
//////////////// |
597 | 430 |
598 static inline bool blend_requires_shader(const SkXfermode::Mode mode, bool primi
tiveIsSrc) { | 431 static inline bool blend_requires_shader(const SkXfermode::Mode mode, bool primi
tiveIsSrc) { |
599 if (primitiveIsSrc) { | 432 if (primitiveIsSrc) { |
600 return SkXfermode::kSrc_Mode != mode; | 433 return SkXfermode::kSrc_Mode != mode; |
601 } else { | 434 } else { |
602 return SkXfermode::kDst_Mode != mode; | 435 return SkXfermode::kDst_Mode != mode; |
603 } | 436 } |
604 } | 437 } |
605 | 438 |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
835 SkErrorInternals::SetError( kInvalidPaint_SkError, | 668 SkErrorInternals::SetError( kInvalidPaint_SkError, |
836 "Sorry, I don't understand the filtering
" | 669 "Sorry, I don't understand the filtering
" |
837 "mode you asked for. Falling back to " | 670 "mode you asked for. Falling back to " |
838 "MIPMaps."); | 671 "MIPMaps."); |
839 textureFilterMode = GrTextureParams::kMipMap_FilterMode; | 672 textureFilterMode = GrTextureParams::kMipMap_FilterMode; |
840 break; | 673 break; |
841 | 674 |
842 } | 675 } |
843 return textureFilterMode; | 676 return textureFilterMode; |
844 } | 677 } |
845 | |
846 ////////////////////////////////////////////////////////////////////////////////
//////////////// | |
847 | |
848 GrTexture* GrTextureMaker::refCachedTexture(GrContext* ctx, const GrTextureParam
s& params) { | |
849 SkGrStretch stretch; | |
850 get_stretch(*ctx->caps(), this->width(), this->height(), params, &stretch); | |
851 | |
852 if (SkGrStretch::kNone_Type == stretch.fType) { | |
853 return this->onRefUnstretchedTexture(ctx); | |
854 } | |
855 | |
856 GrUniqueKey stretchedKey; | |
857 if (this->onMakeStretchedKey(stretch, &stretchedKey)) { | |
858 GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey
(stretchedKey); | |
859 if (result) { | |
860 return result; | |
861 } | |
862 } | |
863 | |
864 GrTexture* result = this->onGenerateStretchedTexture(ctx, stretch); | |
865 if (!result) { | |
866 return nullptr; | |
867 } | |
868 | |
869 if (stretchedKey.isValid()) { | |
870 ctx->textureProvider()->assignUniqueKeyToTexture(stretchedKey, result); | |
871 this->onNotifyStretchCached(stretchedKey); | |
872 } | |
873 return result; | |
874 } | |
875 | |
876 GrTexture* GrTextureMaker::onGenerateStretchedTexture(GrContext* ctx, const SkGr
Stretch& stretch) { | |
877 if (this->width() < ctx->caps()->minTextureSize() || | |
878 this->height() < ctx->caps()->minTextureSize()) | |
879 { | |
880 // we can't trust our ability to use HW to perform the stretch, so we re
quest | |
881 // a raster instead, and perform the stretch on the CPU. | |
882 SkBitmap bitmap; | |
883 if (!this->onGetROBitmap(&bitmap)) { | |
884 return nullptr; | |
885 } | |
886 SkBitmap stretchedBmp = stretch_on_cpu(bitmap, stretch); | |
887 return create_unstretched_bitmap_texture(ctx, stretchedBmp, GrUniqueKey(
)); | |
888 } else { | |
889 SkAutoTUnref<GrTexture> unstretched(this->onRefUnstretchedTexture(ctx)); | |
890 if (!unstretched) { | |
891 return nullptr; | |
892 } | |
893 return stretch_texture(unstretched, stretch, nullptr, GrUniqueKey()); | |
894 } | |
895 } | |
OLD | NEW |