blob: b4f9e8b9493666ea3686651de5957bd3a536d3d7 [file] [log] [blame]
reed8f343722015-08-13 13:32:39 -07001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkBitmap.h"
9#include "SkBitmapCache.h"
Brian Osman7992da32016-11-18 11:28:24 -050010#include "SkColorSpace_Base.h"
fmalita3b0d5322015-09-18 08:07:31 -070011#include "SkImage_Base.h"
reed8f343722015-08-13 13:32:39 -070012#include "SkImageCacherator.h"
reed935d6cf2015-08-18 11:16:09 -070013#include "SkMallocPixelRef.h"
14#include "SkNextID.h"
reed8f343722015-08-13 13:32:39 -070015#include "SkPixelRef.h"
reed4b3d3be2015-09-17 13:35:19 -070016#include "SkResourceCache.h"
reed8f343722015-08-13 13:32:39 -070017
18#if SK_SUPPORT_GPU
19#include "GrContext.h"
Brian Osman46da1cc2017-02-14 14:15:48 -050020#include "GrContextPriv.h"
reed8f343722015-08-13 13:32:39 -070021#include "GrGpuResourcePriv.h"
Brian Osman3b66ab62016-11-28 09:26:31 -050022#include "GrImageTextureMaker.h"
reed8f343722015-08-13 13:32:39 -070023#include "GrResourceKey.h"
Brian Osman32342f02017-03-04 08:12:46 -050024#include "GrResourceProvider.h"
Brian Salomon514baff2016-11-17 15:17:07 -050025#include "GrSamplerParams.h"
reed85d91782015-09-10 14:33:38 -070026#include "GrYUVProvider.h"
reed8f343722015-08-13 13:32:39 -070027#include "SkGr.h"
28#include "SkGrPriv.h"
29#endif
30
reed93eeadf2016-05-11 08:06:11 -070031// Until we actually have codecs/etc. that can contain/support a GPU texture format
32// skip this step, since for some generators, returning their encoded data as a SkData
33// can be somewhat expensive, and this call doesn't indicate to the generator that we're
34// only interested in GPU datas...
35// see skbug.com/ 4971, 5128, ...
36//#define SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR
37
fmalitaf0c38f52016-10-27 14:22:41 -070038// Helper for exclusive access to a shared generator.
39class SkImageCacherator::ScopedGenerator {
40public:
41 ScopedGenerator(const sk_sp<SharedGenerator>& gen)
42 : fSharedGenerator(gen)
43 , fAutoAquire(gen->fMutex) {}
44
45 SkImageGenerator* operator->() const {
46 fSharedGenerator->fMutex.assertHeld();
47 return fSharedGenerator->fGenerator.get();
48 }
49
50 operator SkImageGenerator*() const {
51 fSharedGenerator->fMutex.assertHeld();
52 return fSharedGenerator->fGenerator.get();
53 }
54
55private:
56 const sk_sp<SharedGenerator>& fSharedGenerator;
57 SkAutoExclusive fAutoAquire;
58};
59
fmalita8bd45cd2016-11-04 11:36:31 -070060SkImageCacherator::Validator::Validator(sk_sp<SharedGenerator> gen, const SkIRect* subset)
61 : fSharedGenerator(std::move(gen)) {
reed3a100d32015-09-14 09:59:28 -070062
fmalitaf0c38f52016-10-27 14:22:41 -070063 if (!fSharedGenerator) {
fmalita7929e3a2016-10-27 08:15:44 -070064 return;
65 }
reed3a100d32015-09-14 09:59:28 -070066
fmalita8bd45cd2016-11-04 11:36:31 -070067 // The following generator accessors are safe without acquiring the mutex (const getters).
68 // TODO: refactor to use a ScopedGenerator instead, for clarity.
69 const SkImageInfo& info = fSharedGenerator->fGenerator->getInfo();
reed935d6cf2015-08-18 11:16:09 -070070 if (info.isEmpty()) {
fmalitaf0c38f52016-10-27 14:22:41 -070071 fSharedGenerator.reset();
fmalita7929e3a2016-10-27 08:15:44 -070072 return;
reed935d6cf2015-08-18 11:16:09 -070073 }
74
fmalita8bd45cd2016-11-04 11:36:31 -070075 fUniqueID = fSharedGenerator->fGenerator->uniqueID();
reed935d6cf2015-08-18 11:16:09 -070076 const SkIRect bounds = SkIRect::MakeWH(info.width(), info.height());
77 if (subset) {
78 if (!bounds.contains(*subset)) {
fmalitaf0c38f52016-10-27 14:22:41 -070079 fSharedGenerator.reset();
fmalita7929e3a2016-10-27 08:15:44 -070080 return;
reed935d6cf2015-08-18 11:16:09 -070081 }
82 if (*subset != bounds) {
83 // we need a different uniqueID since we really are a subset of the raw generator
fmalita7929e3a2016-10-27 08:15:44 -070084 fUniqueID = SkNextID::ImageID();
reed935d6cf2015-08-18 11:16:09 -070085 }
86 } else {
87 subset = &bounds;
88 }
89
Brian Osman57ae6cf2016-11-15 18:07:26 +000090 fInfo = info.makeWH(subset->width(), subset->height());
fmalita7929e3a2016-10-27 08:15:44 -070091 fOrigin = SkIPoint::Make(subset->x(), subset->y());
Brian Osman7992da32016-11-18 11:28:24 -050092
93 // If the encoded data is in a strange color space (it's not an XYZ matrix space), we won't be
94 // able to preserve the gamut of the encoded data when we decode it. Instead, we'll have to
95 // decode to a known color space (linear sRGB is a good choice). But we need to adjust the
96 // stored color space, because drawing code will ask the SkImage for its color space, which
97 // will in turn ask the cacherator. If we return the A2B color space, then we will be unable to
98 // construct a source-to-dest gamut transformation matrix.
99 if (fInfo.colorSpace() &&
100 SkColorSpace_Base::Type::kXYZ != as_CSB(fInfo.colorSpace())->type()) {
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500101 fInfo = fInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear());
Brian Osman7992da32016-11-18 11:28:24 -0500102 }
reed8f4fe372015-08-13 14:06:46 -0700103}
104
Mike Reed185130c2017-02-15 15:14:16 -0500105SkImageCacherator* SkImageCacherator::NewFromGenerator(std::unique_ptr<SkImageGenerator> gen,
fmalita7929e3a2016-10-27 08:15:44 -0700106 const SkIRect* subset) {
Mike Reed185130c2017-02-15 15:14:16 -0500107 Validator validator(SharedGenerator::Make(std::move(gen)), subset);
fmalita7929e3a2016-10-27 08:15:44 -0700108
109 return validator ? new SkImageCacherator(&validator) : nullptr;
110}
111
112SkImageCacherator::SkImageCacherator(Validator* validator)
fmalitaf0c38f52016-10-27 14:22:41 -0700113 : fSharedGenerator(std::move(validator->fSharedGenerator)) // we take ownership
fmalita7929e3a2016-10-27 08:15:44 -0700114 , fInfo(validator->fInfo)
115 , fOrigin(validator->fOrigin)
fmalita7929e3a2016-10-27 08:15:44 -0700116{
Brian Osman7992da32016-11-18 11:28:24 -0500117 fUniqueIDs[kLegacy_CachedFormat] = validator->fUniqueID;
118 for (int i = 1; i < kNumCachedFormats; ++i) {
119 // We lazily allocate IDs for non-default caching cases
120 fUniqueIDs[i] = kNeedNewImageUniqueID;
121 }
fmalitaf0c38f52016-10-27 14:22:41 -0700122 SkASSERT(fSharedGenerator);
fmalita7929e3a2016-10-27 08:15:44 -0700123}
reed8f343722015-08-13 13:32:39 -0700124
fmalitaf0c38f52016-10-27 14:22:41 -0700125SkImageCacherator::~SkImageCacherator() {}
126
reed05dd2512016-01-05 09:16:19 -0800127SkData* SkImageCacherator::refEncoded(GrContext* ctx) {
fmalitaf0c38f52016-10-27 14:22:41 -0700128 ScopedGenerator generator(fSharedGenerator);
reed05dd2512016-01-05 09:16:19 -0800129 return generator->refEncodedData(ctx);
reedd5c448f2015-08-26 14:16:43 -0700130}
reed8f343722015-08-13 13:32:39 -0700131
132static bool check_output_bitmap(const SkBitmap& bitmap, uint32_t expectedID) {
133 SkASSERT(bitmap.getGenerationID() == expectedID);
134 SkASSERT(bitmap.isImmutable());
135 SkASSERT(bitmap.getPixels());
136 return true;
137}
138
reed995b4bd2015-09-14 10:27:57 -0700139// Note, this returns a new, mutable, bitmap, with a new genID.
140// If you want the immutable bitmap with the same ID as our cacherator, call tryLockAsBitmap()
141//
Brian Osman7992da32016-11-18 11:28:24 -0500142bool SkImageCacherator::generateBitmap(SkBitmap* bitmap, const SkImageInfo& decodeInfo) {
reed4b3d3be2015-09-17 13:35:19 -0700143 SkBitmap::Allocator* allocator = SkResourceCache::GetAllocator();
144
fmalitaf0c38f52016-10-27 14:22:41 -0700145 ScopedGenerator generator(fSharedGenerator);
reed935d6cf2015-08-18 11:16:09 -0700146 const SkImageInfo& genInfo = generator->getInfo();
Brian Osman7992da32016-11-18 11:28:24 -0500147 if (decodeInfo.dimensions() == genInfo.dimensions()) {
reedd5c448f2015-08-26 14:16:43 -0700148 SkASSERT(fOrigin.x() == 0 && fOrigin.y() == 0);
reed935d6cf2015-08-18 11:16:09 -0700149 // fast-case, no copy needed
Brian Osman7992da32016-11-18 11:28:24 -0500150 return generator->tryGenerateBitmap(bitmap, decodeInfo, allocator);
reed935d6cf2015-08-18 11:16:09 -0700151 } else {
reedc4a83e22015-09-11 11:47:27 -0700152 // need to handle subsetting, so we first generate the full size version, and then
halcanary6950de62015-11-07 05:29:00 -0800153 // "read" from it to get our subset. See https://bug.skia.org/4213
reedc4a83e22015-09-11 11:47:27 -0700154
reed935d6cf2015-08-18 11:16:09 -0700155 SkBitmap full;
Brian Osman7992da32016-11-18 11:28:24 -0500156 if (!generator->tryGenerateBitmap(&full,
157 decodeInfo.makeWH(genInfo.width(), genInfo.height()),
158 allocator)) {
reed935d6cf2015-08-18 11:16:09 -0700159 return false;
160 }
Brian Osman7992da32016-11-18 11:28:24 -0500161 if (!bitmap->tryAllocPixels(decodeInfo, nullptr, full.getColorTable())) {
reed935d6cf2015-08-18 11:16:09 -0700162 return false;
163 }
reedc4a83e22015-09-11 11:47:27 -0700164 return full.readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(),
165 fOrigin.x(), fOrigin.y());
reed935d6cf2015-08-18 11:16:09 -0700166 }
reed8f343722015-08-13 13:32:39 -0700167}
168
reed6868c3f2015-11-24 11:44:47 -0800169bool SkImageCacherator::directGeneratePixels(const SkImageInfo& info, void* pixels, size_t rb,
170 int srcX, int srcY) {
fmalitaf0c38f52016-10-27 14:22:41 -0700171 ScopedGenerator generator(fSharedGenerator);
reed6868c3f2015-11-24 11:44:47 -0800172 const SkImageInfo& genInfo = generator->getInfo();
173 // Currently generators do not natively handle subsets, so check that first.
174 if (srcX || srcY || genInfo.width() != info.width() || genInfo.height() != info.height()) {
175 return false;
176 }
177 return generator->getPixels(info, pixels, rb);
178}
179
reed8f343722015-08-13 13:32:39 -0700180//////////////////////////////////////////////////////////////////////////////////////////////////
181
Brian Osman7992da32016-11-18 11:28:24 -0500182bool SkImageCacherator::lockAsBitmapOnlyIfAlreadyCached(SkBitmap* bitmap, CachedFormat format) {
183 return kNeedNewImageUniqueID != fUniqueIDs[format] &&
184 SkBitmapCache::Find(fUniqueIDs[format], bitmap) &&
185 check_output_bitmap(*bitmap, fUniqueIDs[format]);
reed6868c3f2015-11-24 11:44:47 -0800186}
187
reed09553032015-11-23 12:32:16 -0800188bool SkImageCacherator::tryLockAsBitmap(SkBitmap* bitmap, const SkImage* client,
Brian Osman7992da32016-11-18 11:28:24 -0500189 SkImage::CachingHint chint, CachedFormat format,
190 const SkImageInfo& info) {
191 if (this->lockAsBitmapOnlyIfAlreadyCached(bitmap, format)) {
reed6868c3f2015-11-24 11:44:47 -0800192 return true;
reed8f343722015-08-13 13:32:39 -0700193 }
Brian Osman7992da32016-11-18 11:28:24 -0500194 if (!this->generateBitmap(bitmap, info)) {
reed8f343722015-08-13 13:32:39 -0700195 return false;
196 }
197
Brian Osman7992da32016-11-18 11:28:24 -0500198 if (kNeedNewImageUniqueID == fUniqueIDs[format]) {
199 fUniqueIDs[format] = SkNextID::ImageID();
200 }
201 bitmap->pixelRef()->setImmutableWithID(fUniqueIDs[format]);
reed09553032015-11-23 12:32:16 -0800202 if (SkImage::kAllow_CachingHint == chint) {
Brian Osman7992da32016-11-18 11:28:24 -0500203 SkBitmapCache::Add(fUniqueIDs[format], *bitmap);
reed09553032015-11-23 12:32:16 -0800204 if (client) {
205 as_IB(client)->notifyAddedToCache();
206 }
fmalita3b0d5322015-09-18 08:07:31 -0700207 }
reed8f343722015-08-13 13:32:39 -0700208 return true;
209}
210
Robert Phillips4447b642017-03-03 11:10:18 -0500211bool SkImageCacherator::lockAsBitmap(GrContext* context, SkBitmap* bitmap, const SkImage* client,
Brian Osman61624f02016-12-09 14:51:59 -0500212 SkColorSpace* dstColorSpace,
reed09553032015-11-23 12:32:16 -0800213 SkImage::CachingHint chint) {
Brian Osman61624f02016-12-09 14:51:59 -0500214 CachedFormat format = this->chooseCacheFormat(dstColorSpace);
Brian Osman7992da32016-11-18 11:28:24 -0500215 SkImageInfo cacheInfo = this->buildCacheInfo(format);
216
217 if (kNeedNewImageUniqueID == fUniqueIDs[format]) {
218 fUniqueIDs[format] = SkNextID::ImageID();
219 }
220
221 if (this->tryLockAsBitmap(bitmap, client, chint, format, cacheInfo)) {
222 return check_output_bitmap(*bitmap, fUniqueIDs[format]);
reed8f343722015-08-13 13:32:39 -0700223 }
224
225#if SK_SUPPORT_GPU
Robert Phillips4447b642017-03-03 11:10:18 -0500226 if (!context) {
227 bitmap->reset();
228 return false;
229 }
230
reed8f343722015-08-13 13:32:39 -0700231 // Try to get a texture and read it back to raster (and then cache that with our ID)
Robert Phillips4447b642017-03-03 11:10:18 -0500232 sk_sp<GrTextureProxy> proxy;
reed8f343722015-08-13 13:32:39 -0700233
reedd5c448f2015-08-26 14:16:43 -0700234 {
fmalitaf0c38f52016-10-27 14:22:41 -0700235 ScopedGenerator generator(fSharedGenerator);
Robert Phillips4447b642017-03-03 11:10:18 -0500236 proxy = generator->generateTexture(context, cacheInfo, fOrigin);
reedd5c448f2015-08-26 14:16:43 -0700237 }
Robert Phillips4447b642017-03-03 11:10:18 -0500238 if (!proxy) {
reed8f343722015-08-13 13:32:39 -0700239 bitmap->reset();
240 return false;
241 }
242
Brian Osman7992da32016-11-18 11:28:24 -0500243 if (!bitmap->tryAllocPixels(cacheInfo)) {
reed8f343722015-08-13 13:32:39 -0700244 bitmap->reset();
245 return false;
246 }
247
Robert Phillips4447b642017-03-03 11:10:18 -0500248 sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeWrappedSurfaceContext(
249 proxy,
250 fInfo.refColorSpace())); // src colorSpace
251 if (!sContext) {
252 bitmap->reset();
253 return false;
254 }
255
256 if (!sContext->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
reed8f343722015-08-13 13:32:39 -0700257 bitmap->reset();
258 return false;
259 }
260
Brian Osman7992da32016-11-18 11:28:24 -0500261 bitmap->pixelRef()->setImmutableWithID(fUniqueIDs[format]);
reed09553032015-11-23 12:32:16 -0800262 if (SkImage::kAllow_CachingHint == chint) {
Brian Osman7992da32016-11-18 11:28:24 -0500263 SkBitmapCache::Add(fUniqueIDs[format], *bitmap);
reed09553032015-11-23 12:32:16 -0800264 if (client) {
265 as_IB(client)->notifyAddedToCache();
266 }
fmalita3b0d5322015-09-18 08:07:31 -0700267 }
Brian Osman7992da32016-11-18 11:28:24 -0500268 return check_output_bitmap(*bitmap, fUniqueIDs[format]);
reed8f343722015-08-13 13:32:39 -0700269#else
270 return false;
271#endif
272}
273
274//////////////////////////////////////////////////////////////////////////////////////////////////
275
Brian Osman7992da32016-11-18 11:28:24 -0500276// Abstraction of GrCaps that handles the cases where we don't have a caps pointer (because
277// we're in raster mode), or where GPU support is entirely missing. In theory, we only need the
278// chosen format to be texturable, but that lets us choose F16 on GLES implemenations where we
279// won't be able to read the texture back. We'd like to ensure that SkImake::makeNonTextureImage
280// works, so we require that the formats we choose are renderable (as a proxy for being readable).
281struct CacheCaps {
282 CacheCaps(const GrCaps* caps) : fCaps(caps) {}
283
Brian Osmand6010872016-11-15 18:06:18 +0000284#if SK_SUPPORT_GPU
Brian Osman7992da32016-11-18 11:28:24 -0500285 bool supportsHalfFloat() const {
286 return !fCaps ||
287 (fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig) &&
288 fCaps->isConfigRenderable(kRGBA_half_GrPixelConfig, false));
289 }
290
291 bool supportsSRGB() const {
292 return !fCaps ||
293 (fCaps->srgbSupport() && fCaps->isConfigTexturable(kSRGBA_8888_GrPixelConfig));
294 }
295
296 bool supportsSBGR() const {
297 return !fCaps || fCaps->srgbSupport();
298 }
299#else
300 bool supportsHalfFloat() const { return true; }
301 bool supportsSRGB() const { return true; }
302 bool supportsSBGR() const { return true; }
303#endif
304
305 const GrCaps* fCaps;
306};
307
Brian Osman61624f02016-12-09 14:51:59 -0500308SkImageCacherator::CachedFormat SkImageCacherator::chooseCacheFormat(SkColorSpace* dstColorSpace,
309 const GrCaps* grCaps) {
Brian Osman7992da32016-11-18 11:28:24 -0500310 SkColorSpace* cs = fInfo.colorSpace();
Brian Osman61624f02016-12-09 14:51:59 -0500311 if (!cs || !dstColorSpace) {
Brian Osman7992da32016-11-18 11:28:24 -0500312 return kLegacy_CachedFormat;
313 }
314
315 CacheCaps caps(grCaps);
316 switch (fInfo.colorType()) {
317 case kUnknown_SkColorType:
318 case kAlpha_8_SkColorType:
319 case kRGB_565_SkColorType:
320 case kARGB_4444_SkColorType:
321 // We don't support color space on these formats, so always decode in legacy mode:
322 // TODO: Ask the codec to decode these to something else (at least sRGB 8888)?
323 return kLegacy_CachedFormat;
324
325 case kIndex_8_SkColorType:
326 // We can't draw from indexed textures with a color space, so ask the codec to expand
327 if (cs->gammaCloseToSRGB()) {
328 if (caps.supportsSRGB()) {
329 return kSRGB8888_CachedFormat;
330 } else if (caps.supportsHalfFloat()) {
331 return kLinearF16_CachedFormat;
332 } else {
333 return kLegacy_CachedFormat;
334 }
335 } else {
336 if (caps.supportsHalfFloat()) {
337 return kLinearF16_CachedFormat;
338 } else if (caps.supportsSRGB()) {
339 return kSRGB8888_CachedFormat;
340 } else {
341 return kLegacy_CachedFormat;
342 }
343 }
344
345 case kGray_8_SkColorType:
346 // TODO: What do we do with grayscale sources that have strange color spaces attached?
347 // The codecs and color space xform don't handle this correctly (yet), so drop it on
348 // the floor. (Also, inflating by a factor of 8 is going to be unfortunate).
349 // As it is, we don't directly support sRGB grayscale, so ask the codec to convert
350 // it for us. This bypasses some really sketchy code GrUploadPixmapToTexture.
351 if (cs->gammaCloseToSRGB() && caps.supportsSRGB()) {
352 return kSRGB8888_CachedFormat;
353 } else {
354 return kLegacy_CachedFormat;
355 }
356
357 case kRGBA_8888_SkColorType:
358 if (cs->gammaCloseToSRGB()) {
359 if (caps.supportsSRGB()) {
360 return kAsIs_CachedFormat;
361 } else if (caps.supportsHalfFloat()) {
362 return kLinearF16_CachedFormat;
363 } else {
364 return kLegacy_CachedFormat;
365 }
366 } else {
367 if (caps.supportsHalfFloat()) {
368 return kLinearF16_CachedFormat;
369 } else if (caps.supportsSRGB()) {
370 return kSRGB8888_CachedFormat;
371 } else {
372 return kLegacy_CachedFormat;
373 }
374 }
375
376 case kBGRA_8888_SkColorType:
377 // Odd case. sBGRA isn't a real thing, so we may not have this texturable.
378 if (caps.supportsSBGR()) {
379 if (cs->gammaCloseToSRGB()) {
380 return kAsIs_CachedFormat;
381 } else if (caps.supportsHalfFloat()) {
382 return kLinearF16_CachedFormat;
383 } else if (caps.supportsSRGB()) {
384 return kSRGB8888_CachedFormat;
385 } else {
386 // sBGRA support without sRGBA is highly unlikely (impossible?) Nevertheless.
387 return kLegacy_CachedFormat;
388 }
389 } else {
390 if (cs->gammaCloseToSRGB()) {
391 if (caps.supportsSRGB()) {
392 return kSRGB8888_CachedFormat;
393 } else if (caps.supportsHalfFloat()) {
394 return kLinearF16_CachedFormat;
395 } else {
396 return kLegacy_CachedFormat;
397 }
398 } else {
399 if (caps.supportsHalfFloat()) {
400 return kLinearF16_CachedFormat;
401 } else if (caps.supportsSRGB()) {
402 return kSRGB8888_CachedFormat;
403 } else {
404 return kLegacy_CachedFormat;
405 }
406 }
407 }
408
409 case kRGBA_F16_SkColorType:
410 if (!caps.supportsHalfFloat()) {
411 if (caps.supportsSRGB()) {
412 return kSRGB8888_CachedFormat;
413 } else {
414 return kLegacy_CachedFormat;
415 }
416 } else if (cs->gammaIsLinear()) {
417 return kAsIs_CachedFormat;
418 } else {
419 return kLinearF16_CachedFormat;
420 }
421 }
422 SkDEBUGFAIL("Unreachable");
423 return kLegacy_CachedFormat;
424}
425
426SkImageInfo SkImageCacherator::buildCacheInfo(CachedFormat format) {
427 switch (format) {
428 case kLegacy_CachedFormat:
429 return fInfo.makeColorSpace(nullptr);
430 case kAsIs_CachedFormat:
431 return fInfo;
432 case kLinearF16_CachedFormat:
433 return fInfo
434 .makeColorType(kRGBA_F16_SkColorType)
435 .makeColorSpace(as_CSB(fInfo.colorSpace())->makeLinearGamma());
436 case kSRGB8888_CachedFormat:
437 return fInfo
438 .makeColorType(kRGBA_8888_SkColorType)
439 .makeColorSpace(as_CSB(fInfo.colorSpace())->makeSRGBGamma());
440 default:
441 SkDEBUGFAIL("Invalid cached format");
442 return fInfo;
443 }
444}
445
446//////////////////////////////////////////////////////////////////////////////////////////////////
447
448#if SK_SUPPORT_GPU
449
450void SkImageCacherator::makeCacheKeyFromOrigKey(const GrUniqueKey& origKey, CachedFormat format,
451 GrUniqueKey* cacheKey) {
452 SkASSERT(!cacheKey->isValid());
453 if (origKey.isValid()) {
454 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
455 GrUniqueKey::Builder builder(cacheKey, origKey, kDomain, 1);
456 builder[0] = format;
457 }
458}
Brian Osmand6010872016-11-15 18:06:18 +0000459
460#ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR
461static GrTexture* load_compressed_into_texture(GrContext* ctx, SkData* data, GrSurfaceDesc desc) {
462 const void* rawStart;
463 GrPixelConfig config = GrIsCompressedTextureDataSupported(ctx, data, desc.fWidth, desc.fHeight,
464 &rawStart);
465 if (kUnknown_GrPixelConfig == config) {
466 return nullptr;
467 }
468
469 desc.fConfig = config;
Brian Osman32342f02017-03-04 08:12:46 -0500470 return ctx->resourceProvider()->createTexture(desc, SkBudgeted::kYes, rawStart, 0);
Brian Osmand6010872016-11-15 18:06:18 +0000471}
472#endif
473
474class Generator_GrYUVProvider : public GrYUVProvider {
475 SkImageGenerator* fGen;
476
477public:
478 Generator_GrYUVProvider(SkImageGenerator* gen) : fGen(gen) {}
479
480 uint32_t onGetID() override { return fGen->uniqueID(); }
481 bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const override {
482 return fGen->queryYUV8(sizeInfo, colorSpace);
483 }
484 bool onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) override {
485 return fGen->getYUV8Planes(sizeInfo, planes);
486 }
487};
488
Brian Osman32342f02017-03-04 08:12:46 -0500489static GrTexture* set_key_and_return(GrResourceProvider* resourceProvider,
Robert Phillipsf7cf81a2017-03-02 10:23:52 -0500490 GrTexture* tex, const GrUniqueKey& key) {
Brian Osmand6010872016-11-15 18:06:18 +0000491 if (key.isValid()) {
Brian Osman32342f02017-03-04 08:12:46 -0500492 resourceProvider->assignUniqueKeyToTexture(key, tex);
Brian Osmand6010872016-11-15 18:06:18 +0000493 }
494 return tex;
495}
496
Brian Osman61624f02016-12-09 14:51:59 -0500497sk_sp<SkColorSpace> SkImageCacherator::getColorSpace(GrContext* ctx, SkColorSpace* dstColorSpace) {
Brian Osman7992da32016-11-18 11:28:24 -0500498 // TODO: This isn't always correct. Picture generator currently produces textures in N32,
499 // and will (soon) emit them in an arbitrary (destination) space. We will need to stash that
500 // information in/on the key so we can return the correct space in case #1 of lockTexture.
Brian Osman61624f02016-12-09 14:51:59 -0500501 CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps());
Brian Osman7992da32016-11-18 11:28:24 -0500502 SkImageInfo cacheInfo = this->buildCacheInfo(format);
503 return sk_ref_sp(cacheInfo.colorSpace());
504}
505
reedd5c448f2015-08-26 14:16:43 -0700506/*
507 * We have a 5 ways to try to return a texture (in sorted order)
508 *
509 * 1. Check the cache for a pre-existing one
bsalomonafa95e22015-10-12 10:39:46 -0700510 * 2. Ask the generator to natively create one
reedd5c448f2015-08-26 14:16:43 -0700511 * 3. Ask the generator to return a compressed form that the GPU might support
512 * 4. Ask the generator to return YUV planes, which the GPU can convert
513 * 5. Ask the generator to return RGB(A) data, which the GPU can convert
514 */
Brian Osman7992da32016-11-18 11:28:24 -0500515GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& origKey,
cblume55f2d2d2016-02-26 13:20:48 -0800516 const SkImage* client, SkImage::CachingHint chint,
Brian Osman61624f02016-12-09 14:51:59 -0500517 bool willBeMipped, SkColorSpace* dstColorSpace) {
ericrk369e9372016-02-05 15:32:36 -0800518 // Values representing the various texture lock paths we can take. Used for logging the path
519 // taken to a histogram.
520 enum LockTexturePath {
521 kFailure_LockTexturePath,
522 kPreExisting_LockTexturePath,
523 kNative_LockTexturePath,
524 kCompressed_LockTexturePath,
525 kYUV_LockTexturePath,
526 kRGBA_LockTexturePath,
527 };
528
529 enum { kLockTexturePathCount = kRGBA_LockTexturePath + 1 };
530
Brian Osman7992da32016-11-18 11:28:24 -0500531 // Determine which cached format we're going to use (which may involve decoding to a different
532 // info than the generator provides).
Brian Osman61624f02016-12-09 14:51:59 -0500533 CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps());
Brian Osman7992da32016-11-18 11:28:24 -0500534
535 // Fold the cache format into our texture key
536 GrUniqueKey key;
537 this->makeCacheKeyFromOrigKey(origKey, format, &key);
538
Brian Salomonbc0bcc02015-10-19 15:12:32 -0400539 // 1. Check the cache for a pre-existing one
bsalomon045802d2015-10-20 07:58:01 -0700540 if (key.isValid()) {
Brian Osman32342f02017-03-04 08:12:46 -0500541 if (GrTexture* tex = ctx->resourceProvider()->findAndRefTextureByUniqueKey(key)) {
ericrk369e9372016-02-05 15:32:36 -0800542 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kPreExisting_LockTexturePath,
543 kLockTexturePathCount);
bsalomon045802d2015-10-20 07:58:01 -0700544 return tex;
545 }
Brian Salomonbc0bcc02015-10-19 15:12:32 -0400546 }
547
Brian Osman222e9ad2016-12-14 15:42:36 -0500548 // The CachedFormat is both an index for which cache "slot" we'll use to store this particular
549 // decoded variant of the encoded data, and also a recipe for how to transform the original
550 // info to get the one that we're going to decode to.
551 SkImageInfo cacheInfo = this->buildCacheInfo(format);
552
bsalomon045802d2015-10-20 07:58:01 -0700553 // 2. Ask the generator to natively create one
reedd5c448f2015-08-26 14:16:43 -0700554 {
fmalitaf0c38f52016-10-27 14:22:41 -0700555 ScopedGenerator generator(fSharedGenerator);
Robert Phillips4447b642017-03-03 11:10:18 -0500556 if (sk_sp<GrTextureProxy> proxy = generator->generateTexture(ctx, cacheInfo, fOrigin)) {
ericrk369e9372016-02-05 15:32:36 -0800557 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kNative_LockTexturePath,
558 kLockTexturePathCount);
Brian Osman32342f02017-03-04 08:12:46 -0500559 GrTexture* tex2 = proxy->instantiate(ctx->resourceProvider());
Robert Phillips4447b642017-03-03 11:10:18 -0500560 if (tex2) {
Brian Osman32342f02017-03-04 08:12:46 -0500561 return set_key_and_return(ctx->resourceProvider(), SkSafeRef(tex2), key);
Robert Phillips4447b642017-03-03 11:10:18 -0500562 }
reedd5c448f2015-08-26 14:16:43 -0700563 }
564 }
reed8f343722015-08-13 13:32:39 -0700565
Brian Osman7992da32016-11-18 11:28:24 -0500566 const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(cacheInfo, *ctx->caps());
reed3322a812015-09-16 10:09:24 -0700567
reed93eeadf2016-05-11 08:06:11 -0700568#ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR
reedd5c448f2015-08-26 14:16:43 -0700569 // 3. Ask the generator to return a compressed form that the GPU might support
bungemanffae30d2016-08-03 13:32:32 -0700570 sk_sp<SkData> data(this->refEncoded(ctx));
reed85d91782015-09-10 14:33:38 -0700571 if (data) {
572 GrTexture* tex = load_compressed_into_texture(ctx, data, desc);
573 if (tex) {
ericrk369e9372016-02-05 15:32:36 -0800574 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kCompressed_LockTexturePath,
575 kLockTexturePathCount);
reed85d91782015-09-10 14:33:38 -0700576 return set_key_and_return(tex, key);
577 }
578 }
reed93eeadf2016-05-11 08:06:11 -0700579#endif
reedd5c448f2015-08-26 14:16:43 -0700580
581 // 4. Ask the generator to return YUV planes, which the GPU can convert
Brian Osman46da1cc2017-02-14 14:15:48 -0500582 if (!ctx->contextPriv().disableGpuYUVConversion()) {
fmalitaf0c38f52016-10-27 14:22:41 -0700583 ScopedGenerator generator(fSharedGenerator);
reed85d91782015-09-10 14:33:38 -0700584 Generator_GrYUVProvider provider(generator);
robertphillips677da9d2016-05-11 05:15:55 -0700585 sk_sp<GrTexture> tex = provider.refAsTexture(ctx, desc, true);
reed85d91782015-09-10 14:33:38 -0700586 if (tex) {
ericrk369e9372016-02-05 15:32:36 -0800587 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kYUV_LockTexturePath,
588 kLockTexturePathCount);
Brian Osman32342f02017-03-04 08:12:46 -0500589 return set_key_and_return(ctx->resourceProvider(), tex.release(), key);
reed85d91782015-09-10 14:33:38 -0700590 }
591 }
reedd5c448f2015-08-26 14:16:43 -0700592
593 // 5. Ask the generator to return RGB(A) data, which the GPU can convert
reed8f343722015-08-13 13:32:39 -0700594 SkBitmap bitmap;
Brian Osman7992da32016-11-18 11:28:24 -0500595 if (this->tryLockAsBitmap(&bitmap, client, chint, format, cacheInfo)) {
cblume55f2d2d2016-02-26 13:20:48 -0800596 GrTexture* tex = nullptr;
597 if (willBeMipped) {
Brian Osman61624f02016-12-09 14:51:59 -0500598 tex = GrGenerateMipMapsAndUploadToTexture(ctx, bitmap, dstColorSpace);
brianosmaneb3429c2016-03-25 13:03:03 -0700599 }
600 if (!tex) {
cblume55f2d2d2016-02-26 13:20:48 -0800601 tex = GrUploadBitmapToTexture(ctx, bitmap);
602 }
bsalomon045802d2015-10-20 07:58:01 -0700603 if (tex) {
ericrk369e9372016-02-05 15:32:36 -0800604 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kRGBA_LockTexturePath,
605 kLockTexturePathCount);
Brian Osman32342f02017-03-04 08:12:46 -0500606 return set_key_and_return(ctx->resourceProvider(), tex, key);
bsalomon045802d2015-10-20 07:58:01 -0700607 }
reed8f343722015-08-13 13:32:39 -0700608 }
ericrk369e9372016-02-05 15:32:36 -0800609 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kFailure_LockTexturePath,
610 kLockTexturePathCount);
reed85d91782015-09-10 14:33:38 -0700611 return nullptr;
reed8f343722015-08-13 13:32:39 -0700612}
613
reed856e9d92015-09-30 12:21:45 -0700614///////////////////////////////////////////////////////////////////////////////////////////////////
615
Brian Salomon514baff2016-11-17 15:17:07 -0500616GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrSamplerParams& params,
Brian Osman61624f02016-12-09 14:51:59 -0500617 SkColorSpace* dstColorSpace,
Brian Osman7992da32016-11-18 11:28:24 -0500618 sk_sp<SkColorSpace>* texColorSpace,
Robert Phillips67c18d62017-01-20 12:44:06 -0500619 const SkImage* client,
620 SkScalar scaleAdjust[2],
621 SkImage::CachingHint chint) {
reed856e9d92015-09-30 12:21:45 -0700622 if (!ctx) {
623 return nullptr;
624 }
625
Brian Osman61624f02016-12-09 14:51:59 -0500626 return GrImageTextureMaker(ctx, this, client, chint).refTextureForParams(params, dstColorSpace,
Robert Phillips67c18d62017-01-20 12:44:06 -0500627 texColorSpace,
628 scaleAdjust);
reed856e9d92015-09-30 12:21:45 -0700629}
630
631#else
632
Brian Salomon514baff2016-11-17 15:17:07 -0500633GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrSamplerParams&,
Brian Osman61624f02016-12-09 14:51:59 -0500634 SkColorSpace* dstColorSpace,
Brian Osman7992da32016-11-18 11:28:24 -0500635 sk_sp<SkColorSpace>* texColorSpace,
Robert Phillips67c18d62017-01-20 12:44:06 -0500636 const SkImage* client,
637 SkScalar scaleAdjust[2], SkImage::CachingHint) {
reed856e9d92015-09-30 12:21:45 -0700638 return nullptr;
639}
640
641#endif