| 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" | 8 #include "GrTextureMaker.h" |
| 9 | 9 |
| 10 #include "SkGr.h" | 10 #include "SkGr.h" |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 #include "effects/GrDitherEffect.h" | 31 #include "effects/GrDitherEffect.h" |
| 32 #include "effects/GrPorterDuffXferProcessor.h" | 32 #include "effects/GrPorterDuffXferProcessor.h" |
| 33 #include "effects/GrXfermodeFragmentProcessor.h" | 33 #include "effects/GrXfermodeFragmentProcessor.h" |
| 34 #include "effects/GrYUVtoRGBEffect.h" | 34 #include "effects/GrYUVtoRGBEffect.h" |
| 35 | 35 |
| 36 #ifndef SK_IGNORE_ETC1_SUPPORT | 36 #ifndef SK_IGNORE_ETC1_SUPPORT |
| 37 # include "ktx.h" | 37 # include "ktx.h" |
| 38 # include "etc1.h" | 38 # include "etc1.h" |
| 39 #endif | 39 #endif |
| 40 | 40 |
| 41 GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo& info) { |
| 42 GrSurfaceDesc desc; |
| 43 desc.fFlags = kNone_GrSurfaceFlags; |
| 44 desc.fWidth = info.width(); |
| 45 desc.fHeight = info.height(); |
| 46 desc.fConfig = SkImageInfo2GrPixelConfig(info); |
| 47 desc.fSampleCnt = 0; |
| 48 return desc; |
| 49 } |
| 50 |
| 51 static void get_stretch(const GrCaps& caps, int width, int height, |
| 52 const GrTextureParams& params, SkGrStretch* stretch) { |
| 53 stretch->fType = SkGrStretch::kNone_Type; |
| 54 bool doStretch = false; |
| 55 if (params.isTiled() && !caps.npotTextureTileSupport() && |
| 56 (!SkIsPow2(width) || !SkIsPow2(height))) { |
| 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; |
| 91 builder[1] = subset.x(); |
| 92 builder[2] = subset.y(); |
| 93 builder[3] = subset.width() | (subset.height() << 16); |
| 94 } |
| 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 } |
| 110 |
| 111 GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data, |
| 112 int expectedW, int expectedH, |
| 113 const void** outStartOfDataToUp
load) { |
| 114 *outStartOfDataToUpload = nullptr; |
| 115 #ifndef SK_IGNORE_ETC1_SUPPORT |
| 116 if (!ctx->caps()->isConfigTexturable(kETC1_GrPixelConfig)) { |
| 117 return kUnknown_GrPixelConfig; |
| 118 } |
| 119 |
| 120 const uint8_t* bytes = data->bytes(); |
| 121 if (data->size() > ETC_PKM_HEADER_SIZE && etc1_pkm_is_valid(bytes)) { |
| 122 // Does the data match the dimensions of the bitmap? If not, |
| 123 // then we don't know how to scale the image to match it... |
| 124 if (etc1_pkm_get_width(bytes) != (unsigned)expectedW || |
| 125 etc1_pkm_get_height(bytes) != (unsigned)expectedH) |
| 126 { |
| 127 return kUnknown_GrPixelConfig; |
| 128 } |
| 129 |
| 130 *outStartOfDataToUpload = bytes + ETC_PKM_HEADER_SIZE; |
| 131 return kETC1_GrPixelConfig; |
| 132 } else if (SkKTXFile::is_ktx(bytes)) { |
| 133 SkKTXFile ktx(data); |
| 134 |
| 135 // Is it actually an ETC1 texture? |
| 136 if (!ktx.isCompressedFormat(SkTextureCompressor::kETC1_Format)) { |
| 137 return kUnknown_GrPixelConfig; |
| 138 } |
| 139 |
| 140 // Does the data match the dimensions of the bitmap? If not, |
| 141 // then we don't know how to scale the image to match it... |
| 142 if (ktx.width() != expectedW || ktx.height() != expectedH) { |
| 143 return kUnknown_GrPixelConfig; |
| 144 } |
| 145 |
| 146 *outStartOfDataToUpload = ktx.pixelData(); |
| 147 return kETC1_GrPixelConfig; |
| 148 } |
| 149 #endif |
| 150 return kUnknown_GrPixelConfig; |
| 151 } |
| 152 |
| 41 /* Fill out buffer with the compressed format Ganesh expects from a colortable | 153 /* Fill out buffer with the compressed format Ganesh expects from a colortable |
| 42 based bitmap. [palette (colortable) + indices]. | 154 based bitmap. [palette (colortable) + indices]. |
| 43 | 155 |
| 44 At the moment Ganesh only supports 8bit version. If Ganesh allowed we others | 156 At the moment Ganesh only supports 8bit version. If Ganesh allowed we others |
| 45 we could detect that the colortable.count is <= 16, and then repack the | 157 we could detect that the colortable.count is <= 16, and then repack the |
| 46 indices as nibbles to save RAM, but it would take more time (i.e. a lot | 158 indices as nibbles to save RAM, but it would take more time (i.e. a lot |
| 47 slower than memcpy), so skipping that for now. | 159 slower than memcpy), so skipping that for now. |
| 48 | 160 |
| 49 Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big | 161 Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big |
| 50 as the colortable.count says it is. | 162 as the colortable.count says it is. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 for (int y = 0; y < bitmap.height(); y++) { | 202 for (int y = 0; y < bitmap.height(); y++) { |
| 91 memcpy(dst, src, width); | 203 memcpy(dst, src, width); |
| 92 src += rowBytes; | 204 src += rowBytes; |
| 93 dst += width; | 205 dst += width; |
| 94 } | 206 } |
| 95 } | 207 } |
| 96 } | 208 } |
| 97 | 209 |
| 98 //////////////////////////////////////////////////////////////////////////////// | 210 //////////////////////////////////////////////////////////////////////////////// |
| 99 | 211 |
| 100 static void get_stretch(const GrCaps& caps, int width, int height, | |
| 101 const GrTextureParams& params, SkGrStretch* stretch) { | |
| 102 stretch->fType = SkGrStretch::kNone_Type; | |
| 103 bool doStretch = false; | |
| 104 if (params.isTiled() && !caps.npotTextureTileSupport() && | |
| 105 (!SkIsPow2(width) || !SkIsPow2(height))) { | |
| 106 doStretch = true; | |
| 107 stretch->fWidth = GrNextPow2(SkTMax(width, caps.minTextureSize())); | |
| 108 stretch->fHeight = GrNextPow2(SkTMax(height, caps.minTextureSize())); | |
| 109 } else if (width < caps.minTextureSize() || height < caps.minTextureSize())
{ | |
| 110 // The small texture issues appear to be with tiling. Hence it seems ok
to scale them | |
| 111 // up using the GPU. If issues persist we may need to CPU-stretch. | |
| 112 doStretch = true; | |
| 113 stretch->fWidth = SkTMax(width, caps.minTextureSize()); | |
| 114 stretch->fHeight = SkTMax(height, caps.minTextureSize()); | |
| 115 } | |
| 116 if (doStretch) { | |
| 117 switch(params.filterMode()) { | |
| 118 case GrTextureParams::kNone_FilterMode: | |
| 119 stretch->fType = SkGrStretch::kNearest_Type; | |
| 120 break; | |
| 121 case GrTextureParams::kBilerp_FilterMode: | |
| 122 case GrTextureParams::kMipMap_FilterMode: | |
| 123 stretch->fType = SkGrStretch::kBilerp_Type; | |
| 124 break; | |
| 125 } | |
| 126 } else { | |
| 127 stretch->fWidth = -1; | |
| 128 stretch->fHeight = -1; | |
| 129 stretch->fType = SkGrStretch::kNone_Type; | |
| 130 } | |
| 131 } | |
| 132 | 212 |
| 133 bool GrMakeStretchedKey(const GrUniqueKey& origKey, const SkGrStretch& stretch, | 213 bool GrMakeStretchedKey(const GrUniqueKey& origKey, const SkGrStretch& stretch, |
| 134 GrUniqueKey* stretchedKey) { | 214 GrUniqueKey* stretchedKey) { |
| 135 if (origKey.isValid() && SkGrStretch::kNone_Type != stretch.fType) { | 215 if (origKey.isValid() && SkGrStretch::kNone_Type != stretch.fType) { |
| 136 uint32_t width = SkToU16(stretch.fWidth); | 216 uint32_t width = SkToU16(stretch.fWidth); |
| 137 uint32_t height = SkToU16(stretch.fHeight); | 217 uint32_t height = SkToU16(stretch.fHeight); |
| 138 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; | 218 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; |
| 139 GrUniqueKey::Builder builder(stretchedKey, origKey, kDomain, 2); | 219 GrUniqueKey::Builder builder(stretchedKey, origKey, kDomain, 2); |
| 140 builder[0] = stretch.fType; | 220 builder[0] = stretch.fType; |
| 141 builder[1] = width | (height << 16); | 221 builder[1] = width | (height << 16); |
| 142 builder.finish(); | 222 builder.finish(); |
| 143 return true; | 223 return true; |
| 144 } | 224 } |
| 145 SkASSERT(!stretchedKey->isValid()); | 225 SkASSERT(!stretchedKey->isValid()); |
| 146 return false; | 226 return false; |
| 147 } | 227 } |
| 148 | 228 |
| 149 static void make_unstretched_key(GrUniqueKey* key, uint32_t imageID, const SkIRe
ct& subset) { | |
| 150 SkASSERT(SkIsU16(subset.width())); | |
| 151 SkASSERT(SkIsU16(subset.height())); | |
| 152 | |
| 153 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); | |
| 154 GrUniqueKey::Builder builder(key, kDomain, 4); | |
| 155 builder[0] = imageID; | |
| 156 builder[1] = subset.x(); | |
| 157 builder[2] = subset.y(); | |
| 158 builder[3] = subset.width() | (subset.height() << 16); | |
| 159 } | |
| 160 | |
| 161 void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& sub
set, | |
| 162 const GrCaps& caps, const GrTextureParams& params) { | |
| 163 SkGrStretch stretch; | |
| 164 get_stretch(caps, subset.width(), subset.height(), params, &stretch); | |
| 165 if (SkGrStretch::kNone_Type != stretch.fType) { | |
| 166 GrUniqueKey tmpKey; | |
| 167 make_unstretched_key(&tmpKey, imageID, subset); | |
| 168 if (!GrMakeStretchedKey(tmpKey, stretch, key)) { | |
| 169 *key = tmpKey; | |
| 170 } | |
| 171 } else { | |
| 172 make_unstretched_key(key, imageID, subset); | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo& info) { | |
| 177 GrSurfaceDesc desc; | |
| 178 desc.fFlags = kNone_GrSurfaceFlags; | |
| 179 desc.fWidth = info.width(); | |
| 180 desc.fHeight = info.height(); | |
| 181 desc.fConfig = SkImageInfo2GrPixelConfig(info); | |
| 182 desc.fSampleCnt = 0; | |
| 183 return desc; | |
| 184 } | |
| 185 | |
| 186 namespace { | 229 namespace { |
| 187 | 230 |
| 188 // When the SkPixelRef genID changes, invalidate a corresponding GrResource desc
ribed by key. | 231 // When the SkPixelRef genID changes, invalidate a corresponding GrResource desc
ribed by key. |
| 189 class BitmapInvalidator : public SkPixelRef::GenIDChangeListener { | 232 class BitmapInvalidator : public SkPixelRef::GenIDChangeListener { |
| 190 public: | 233 public: |
| 191 explicit BitmapInvalidator(const GrUniqueKey& key) : fMsg(key) {} | 234 explicit BitmapInvalidator(const GrUniqueKey& key) : fMsg(key) {} |
| 192 private: | 235 private: |
| 193 GrUniqueKeyInvalidatedMessage fMsg; | 236 GrUniqueKeyInvalidatedMessage fMsg; |
| 194 | 237 |
| 195 void onChange() override { | 238 void onChange() override { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(stretched->asRe
nderTarget())); | 323 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(stretched->asRe
nderTarget())); |
| 281 if (!drawContext) { | 324 if (!drawContext) { |
| 282 return nullptr; | 325 return nullptr; |
| 283 } | 326 } |
| 284 | 327 |
| 285 drawContext->drawNonAARectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), r
ect, localRect); | 328 drawContext->drawNonAARectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), r
ect, localRect); |
| 286 | 329 |
| 287 return stretched.detach(); | 330 return stretched.detach(); |
| 288 } | 331 } |
| 289 | 332 |
| 290 GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data, | |
| 291 int expectedW, int expectedH, | |
| 292 const void** outStartOfDataToUp
load) { | |
| 293 *outStartOfDataToUpload = nullptr; | |
| 294 #ifndef SK_IGNORE_ETC1_SUPPORT | |
| 295 if (!ctx->caps()->isConfigTexturable(kETC1_GrPixelConfig)) { | |
| 296 return kUnknown_GrPixelConfig; | |
| 297 } | |
| 298 | |
| 299 const uint8_t* bytes = data->bytes(); | |
| 300 if (data->size() > ETC_PKM_HEADER_SIZE && etc1_pkm_is_valid(bytes)) { | |
| 301 // Does the data match the dimensions of the bitmap? If not, | |
| 302 // then we don't know how to scale the image to match it... | |
| 303 if (etc1_pkm_get_width(bytes) != (unsigned)expectedW || | |
| 304 etc1_pkm_get_height(bytes) != (unsigned)expectedH) | |
| 305 { | |
| 306 return kUnknown_GrPixelConfig; | |
| 307 } | |
| 308 | |
| 309 *outStartOfDataToUpload = bytes + ETC_PKM_HEADER_SIZE; | |
| 310 return kETC1_GrPixelConfig; | |
| 311 } else if (SkKTXFile::is_ktx(bytes)) { | |
| 312 SkKTXFile ktx(data); | |
| 313 | |
| 314 // Is it actually an ETC1 texture? | |
| 315 if (!ktx.isCompressedFormat(SkTextureCompressor::kETC1_Format)) { | |
| 316 return kUnknown_GrPixelConfig; | |
| 317 } | |
| 318 | |
| 319 // Does the data match the dimensions of the bitmap? If not, | |
| 320 // then we don't know how to scale the image to match it... | |
| 321 if (ktx.width() != expectedW || ktx.height() != expectedH) { | |
| 322 return kUnknown_GrPixelConfig; | |
| 323 } | |
| 324 | |
| 325 *outStartOfDataToUpload = ktx.pixelData(); | |
| 326 return kETC1_GrPixelConfig; | |
| 327 } | |
| 328 #endif | |
| 329 return kUnknown_GrPixelConfig; | |
| 330 } | |
| 331 | |
| 332 static GrTexture* load_etc1_texture(GrContext* ctx, const GrUniqueKey& optionalK
ey, | |
| 333 const SkBitmap &bm, GrSurfaceDesc desc) { | |
| 334 SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData()); | |
| 335 if (!data) { | |
| 336 return nullptr; | |
| 337 } | |
| 338 | |
| 339 const void* startOfTexData; | |
| 340 desc.fConfig = GrIsCompressedTextureDataSupported(ctx, data, bm.width(), bm.
height(), | |
| 341 &startOfTexData); | |
| 342 if (kUnknown_GrPixelConfig == desc.fConfig) { | |
| 343 return nullptr; | |
| 344 } | |
| 345 | |
| 346 return GrCreateTextureForPixels(ctx, optionalKey, desc, bm.pixelRef(), start
OfTexData, 0); | |
| 347 } | |
| 348 | |
| 349 /* | 333 /* |
| 350 * Once we have made SkImages handle all lazy/deferred/generated content, the Y
UV apis will | 334 * Once we have made SkImages handle all lazy/deferred/generated content, the Y
UV apis will |
| 351 * be gone from SkPixelRef, and we can remove this subclass entirely. | 335 * be gone from SkPixelRef, and we can remove this subclass entirely. |
| 352 */ | 336 */ |
| 353 class PixelRef_GrYUVProvider : public GrYUVProvider { | 337 class PixelRef_GrYUVProvider : public GrYUVProvider { |
| 354 SkPixelRef* fPR; | 338 SkPixelRef* fPR; |
| 355 | 339 |
| 356 public: | 340 public: |
| 357 PixelRef_GrYUVProvider(SkPixelRef* pr) : fPR(pr) {} | 341 PixelRef_GrYUVProvider(SkPixelRef* pr) : fPR(pr) {} |
| 358 | 342 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 384 } | 368 } |
| 385 | 369 |
| 386 if (useCache) { | 370 if (useCache) { |
| 387 BitmapInvalidator* listener = new BitmapInvalidator(optionalKey); | 371 BitmapInvalidator* listener = new BitmapInvalidator(optionalKey); |
| 388 pixelRef->addGenIDChangeListener(listener); | 372 pixelRef->addGenIDChangeListener(listener); |
| 389 ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, texture); | 373 ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, texture); |
| 390 } | 374 } |
| 391 return texture; | 375 return texture; |
| 392 } | 376 } |
| 393 | 377 |
| 378 static GrTexture* load_etc1_texture(GrContext* ctx, const GrUniqueKey& optionalK
ey, |
| 379 const SkBitmap &bm, GrSurfaceDesc desc) { |
| 380 SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData()); |
| 381 if (!data) { |
| 382 return nullptr; |
| 383 } |
| 384 |
| 385 const void* startOfTexData; |
| 386 desc.fConfig = GrIsCompressedTextureDataSupported(ctx, data, bm.width(), bm.
height(), |
| 387 &startOfTexData); |
| 388 if (kUnknown_GrPixelConfig == desc.fConfig) { |
| 389 return nullptr; |
| 390 } |
| 391 |
| 392 return GrCreateTextureForPixels(ctx, optionalKey, desc, bm.pixelRef(), start
OfTexData, 0); |
| 393 } |
| 394 |
| 394 static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx, | 395 static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx, |
| 395 const SkBitmap& origBitmap, | 396 const SkBitmap& origBitmap, |
| 396 const GrUniqueKey& optionalK
ey) { | 397 const GrUniqueKey& optionalK
ey) { |
| 397 if (origBitmap.width() < ctx->caps()->minTextureSize() || | 398 if (origBitmap.width() < ctx->caps()->minTextureSize() || |
| 398 origBitmap.height() < ctx->caps()->minTextureSize()) { | 399 origBitmap.height() < ctx->caps()->minTextureSize()) { |
| 399 return nullptr; | 400 return nullptr; |
| 400 } | 401 } |
| 401 SkBitmap tmpBitmap; | 402 SkBitmap tmpBitmap; |
| 402 | 403 |
| 403 const SkBitmap* bitmap = &origBitmap; | 404 const SkBitmap* bitmap = &origBitmap; |
| (...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 885 SkBitmap stretchedBmp = stretch_on_cpu(bitmap, stretch); | 886 SkBitmap stretchedBmp = stretch_on_cpu(bitmap, stretch); |
| 886 return create_unstretched_bitmap_texture(ctx, stretchedBmp, GrUniqueKey(
)); | 887 return create_unstretched_bitmap_texture(ctx, stretchedBmp, GrUniqueKey(
)); |
| 887 } else { | 888 } else { |
| 888 SkAutoTUnref<GrTexture> unstretched(this->onRefUnstretchedTexture(ctx)); | 889 SkAutoTUnref<GrTexture> unstretched(this->onRefUnstretchedTexture(ctx)); |
| 889 if (!unstretched) { | 890 if (!unstretched) { |
| 890 return nullptr; | 891 return nullptr; |
| 891 } | 892 } |
| 892 return stretch_texture(unstretched, stretch, nullptr, GrUniqueKey()); | 893 return stretch_texture(unstretched, stretch, nullptr, GrUniqueKey()); |
| 893 } | 894 } |
| 894 } | 895 } |
| OLD | NEW |