blob: a9db283c3a7961cb0ae15e6d0761002bb0099fd7 [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"
reed8f343722015-08-13 13:32:39 -070028#endif
29
reed93eeadf2016-05-11 08:06:11 -070030// Until we actually have codecs/etc. that can contain/support a GPU texture format
31// skip this step, since for some generators, returning their encoded data as a SkData
32// can be somewhat expensive, and this call doesn't indicate to the generator that we're
33// only interested in GPU datas...
34// see skbug.com/ 4971, 5128, ...
35//#define SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR
36
fmalitaf0c38f52016-10-27 14:22:41 -070037// Helper for exclusive access to a shared generator.
38class SkImageCacherator::ScopedGenerator {
39public:
40 ScopedGenerator(const sk_sp<SharedGenerator>& gen)
41 : fSharedGenerator(gen)
42 , fAutoAquire(gen->fMutex) {}
43
44 SkImageGenerator* operator->() const {
45 fSharedGenerator->fMutex.assertHeld();
46 return fSharedGenerator->fGenerator.get();
47 }
48
49 operator SkImageGenerator*() const {
50 fSharedGenerator->fMutex.assertHeld();
51 return fSharedGenerator->fGenerator.get();
52 }
53
54private:
55 const sk_sp<SharedGenerator>& fSharedGenerator;
56 SkAutoExclusive fAutoAquire;
57};
58
fmalita8bd45cd2016-11-04 11:36:31 -070059SkImageCacherator::Validator::Validator(sk_sp<SharedGenerator> gen, const SkIRect* subset)
60 : fSharedGenerator(std::move(gen)) {
reed3a100d32015-09-14 09:59:28 -070061
fmalitaf0c38f52016-10-27 14:22:41 -070062 if (!fSharedGenerator) {
fmalita7929e3a2016-10-27 08:15:44 -070063 return;
64 }
reed3a100d32015-09-14 09:59:28 -070065
fmalita8bd45cd2016-11-04 11:36:31 -070066 // The following generator accessors are safe without acquiring the mutex (const getters).
67 // TODO: refactor to use a ScopedGenerator instead, for clarity.
68 const SkImageInfo& info = fSharedGenerator->fGenerator->getInfo();
reed935d6cf2015-08-18 11:16:09 -070069 if (info.isEmpty()) {
fmalitaf0c38f52016-10-27 14:22:41 -070070 fSharedGenerator.reset();
fmalita7929e3a2016-10-27 08:15:44 -070071 return;
reed935d6cf2015-08-18 11:16:09 -070072 }
73
fmalita8bd45cd2016-11-04 11:36:31 -070074 fUniqueID = fSharedGenerator->fGenerator->uniqueID();
reed935d6cf2015-08-18 11:16:09 -070075 const SkIRect bounds = SkIRect::MakeWH(info.width(), info.height());
76 if (subset) {
77 if (!bounds.contains(*subset)) {
fmalitaf0c38f52016-10-27 14:22:41 -070078 fSharedGenerator.reset();
fmalita7929e3a2016-10-27 08:15:44 -070079 return;
reed935d6cf2015-08-18 11:16:09 -070080 }
81 if (*subset != bounds) {
82 // we need a different uniqueID since we really are a subset of the raw generator
fmalita7929e3a2016-10-27 08:15:44 -070083 fUniqueID = SkNextID::ImageID();
reed935d6cf2015-08-18 11:16:09 -070084 }
85 } else {
86 subset = &bounds;
87 }
88
Brian Osman57ae6cf2016-11-15 18:07:26 +000089 fInfo = info.makeWH(subset->width(), subset->height());
fmalita7929e3a2016-10-27 08:15:44 -070090 fOrigin = SkIPoint::Make(subset->x(), subset->y());
Brian Osman7992da32016-11-18 11:28:24 -050091
Mike Reed4e3abc12017-04-07 12:04:23 -040092 // colortables are poorly to not-at-all supported in our resourcecache, so we
93 // bully them into N32 (the generator will perform the up-sample)
94 if (fInfo.colorType() == kIndex_8_SkColorType) {
95 fInfo = fInfo.makeColorType(kN32_SkColorType);
96 }
97
Brian Osman7992da32016-11-18 11:28:24 -050098 // If the encoded data is in a strange color space (it's not an XYZ matrix space), we won't be
99 // able to preserve the gamut of the encoded data when we decode it. Instead, we'll have to
100 // decode to a known color space (linear sRGB is a good choice). But we need to adjust the
101 // stored color space, because drawing code will ask the SkImage for its color space, which
102 // will in turn ask the cacherator. If we return the A2B color space, then we will be unable to
103 // construct a source-to-dest gamut transformation matrix.
104 if (fInfo.colorSpace() &&
105 SkColorSpace_Base::Type::kXYZ != as_CSB(fInfo.colorSpace())->type()) {
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500106 fInfo = fInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear());
Brian Osman7992da32016-11-18 11:28:24 -0500107 }
reed8f4fe372015-08-13 14:06:46 -0700108}
109
Mike Reed185130c2017-02-15 15:14:16 -0500110SkImageCacherator* SkImageCacherator::NewFromGenerator(std::unique_ptr<SkImageGenerator> gen,
fmalita7929e3a2016-10-27 08:15:44 -0700111 const SkIRect* subset) {
Mike Reed185130c2017-02-15 15:14:16 -0500112 Validator validator(SharedGenerator::Make(std::move(gen)), subset);
fmalita7929e3a2016-10-27 08:15:44 -0700113
114 return validator ? new SkImageCacherator(&validator) : nullptr;
115}
116
117SkImageCacherator::SkImageCacherator(Validator* validator)
fmalitaf0c38f52016-10-27 14:22:41 -0700118 : fSharedGenerator(std::move(validator->fSharedGenerator)) // we take ownership
fmalita7929e3a2016-10-27 08:15:44 -0700119 , fInfo(validator->fInfo)
120 , fOrigin(validator->fOrigin)
fmalita7929e3a2016-10-27 08:15:44 -0700121{
Brian Osman7992da32016-11-18 11:28:24 -0500122 fUniqueIDs[kLegacy_CachedFormat] = validator->fUniqueID;
123 for (int i = 1; i < kNumCachedFormats; ++i) {
124 // We lazily allocate IDs for non-default caching cases
125 fUniqueIDs[i] = kNeedNewImageUniqueID;
126 }
fmalitaf0c38f52016-10-27 14:22:41 -0700127 SkASSERT(fSharedGenerator);
Mike Reed4e3abc12017-04-07 12:04:23 -0400128 SkASSERT(fInfo.colorType() != kIndex_8_SkColorType);
fmalita7929e3a2016-10-27 08:15:44 -0700129}
reed8f343722015-08-13 13:32:39 -0700130
fmalitaf0c38f52016-10-27 14:22:41 -0700131SkImageCacherator::~SkImageCacherator() {}
132
reed05dd2512016-01-05 09:16:19 -0800133SkData* SkImageCacherator::refEncoded(GrContext* ctx) {
fmalitaf0c38f52016-10-27 14:22:41 -0700134 ScopedGenerator generator(fSharedGenerator);
reed05dd2512016-01-05 09:16:19 -0800135 return generator->refEncodedData(ctx);
reedd5c448f2015-08-26 14:16:43 -0700136}
reed8f343722015-08-13 13:32:39 -0700137
138static bool check_output_bitmap(const SkBitmap& bitmap, uint32_t expectedID) {
139 SkASSERT(bitmap.getGenerationID() == expectedID);
140 SkASSERT(bitmap.isImmutable());
141 SkASSERT(bitmap.getPixels());
142 return true;
143}
144
Mike Reed4e3abc12017-04-07 12:04:23 -0400145static bool reset_and_return_false(SkBitmap* bitmap) {
146 bitmap->reset();
147 return false;
148}
149
150static bool try_generate_bitmap(SkImageGenerator* gen, SkBitmap* bitmap, const SkImageInfo& info,
151 SkBitmap::Allocator* allocator) {
152 SkASSERT(info.colorType() != kIndex_8_SkColorType);
153 if (0 == info.getSafeSize(info.minRowBytes())) {
154 return false;
155 }
156 if (!bitmap->setInfo(info)) {
157 return reset_and_return_false(bitmap);
158 }
159 if (!bitmap->tryAllocPixels(allocator, nullptr)) {
160 return reset_and_return_false(bitmap);
161 }
162 SkASSERT(bitmap->getPixels()); // we're already locked
163
164 if (!gen->getPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes())) {
165 return reset_and_return_false(bitmap);
166 }
167 return true;
168}
169
reed995b4bd2015-09-14 10:27:57 -0700170// Note, this returns a new, mutable, bitmap, with a new genID.
171// If you want the immutable bitmap with the same ID as our cacherator, call tryLockAsBitmap()
172//
Brian Osman7992da32016-11-18 11:28:24 -0500173bool SkImageCacherator::generateBitmap(SkBitmap* bitmap, const SkImageInfo& decodeInfo) {
reed4b3d3be2015-09-17 13:35:19 -0700174 SkBitmap::Allocator* allocator = SkResourceCache::GetAllocator();
175
fmalitaf0c38f52016-10-27 14:22:41 -0700176 ScopedGenerator generator(fSharedGenerator);
reed935d6cf2015-08-18 11:16:09 -0700177 const SkImageInfo& genInfo = generator->getInfo();
Brian Osman7992da32016-11-18 11:28:24 -0500178 if (decodeInfo.dimensions() == genInfo.dimensions()) {
reedd5c448f2015-08-26 14:16:43 -0700179 SkASSERT(fOrigin.x() == 0 && fOrigin.y() == 0);
reed935d6cf2015-08-18 11:16:09 -0700180 // fast-case, no copy needed
Mike Reed4e3abc12017-04-07 12:04:23 -0400181 return try_generate_bitmap(generator, bitmap, decodeInfo, allocator);
reed935d6cf2015-08-18 11:16:09 -0700182 } else {
reedc4a83e22015-09-11 11:47:27 -0700183 // need to handle subsetting, so we first generate the full size version, and then
halcanary6950de62015-11-07 05:29:00 -0800184 // "read" from it to get our subset. See https://bug.skia.org/4213
reedc4a83e22015-09-11 11:47:27 -0700185
reed935d6cf2015-08-18 11:16:09 -0700186 SkBitmap full;
Mike Reed4e3abc12017-04-07 12:04:23 -0400187 if (!try_generate_bitmap(generator, &full,
188 decodeInfo.makeWH(genInfo.width(), genInfo.height()), allocator)) {
reed935d6cf2015-08-18 11:16:09 -0700189 return false;
190 }
Mike Reed4e3abc12017-04-07 12:04:23 -0400191 SkASSERT(decodeInfo.colorType() != kIndex_8_SkColorType);
192 if (!bitmap->tryAllocPixels(decodeInfo)) {
reed935d6cf2015-08-18 11:16:09 -0700193 return false;
194 }
reedc4a83e22015-09-11 11:47:27 -0700195 return full.readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(),
196 fOrigin.x(), fOrigin.y());
reed935d6cf2015-08-18 11:16:09 -0700197 }
reed8f343722015-08-13 13:32:39 -0700198}
199
reed6868c3f2015-11-24 11:44:47 -0800200bool SkImageCacherator::directGeneratePixels(const SkImageInfo& info, void* pixels, size_t rb,
Matt Sarettd531ca02017-03-24 16:31:19 -0400201 int srcX, int srcY,
202 SkTransferFunctionBehavior behavior) {
fmalitaf0c38f52016-10-27 14:22:41 -0700203 ScopedGenerator generator(fSharedGenerator);
reed6868c3f2015-11-24 11:44:47 -0800204 const SkImageInfo& genInfo = generator->getInfo();
205 // Currently generators do not natively handle subsets, so check that first.
206 if (srcX || srcY || genInfo.width() != info.width() || genInfo.height() != info.height()) {
207 return false;
208 }
Matt Sarettd531ca02017-03-24 16:31:19 -0400209
210 SkImageGenerator::Options opts;
211 opts.fBehavior = behavior;
212 return generator->getPixels(info, pixels, rb, &opts);
reed6868c3f2015-11-24 11:44:47 -0800213}
214
reed8f343722015-08-13 13:32:39 -0700215//////////////////////////////////////////////////////////////////////////////////////////////////
216
Brian Osman7992da32016-11-18 11:28:24 -0500217bool SkImageCacherator::lockAsBitmapOnlyIfAlreadyCached(SkBitmap* bitmap, CachedFormat format) {
218 return kNeedNewImageUniqueID != fUniqueIDs[format] &&
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400219 SkBitmapCache::Find(SkBitmapCacheDesc::Make(fUniqueIDs[format],
220 fInfo.width(), fInfo.height()), bitmap) &&
Brian Osman7992da32016-11-18 11:28:24 -0500221 check_output_bitmap(*bitmap, fUniqueIDs[format]);
reed6868c3f2015-11-24 11:44:47 -0800222}
223
reed09553032015-11-23 12:32:16 -0800224bool SkImageCacherator::tryLockAsBitmap(SkBitmap* bitmap, const SkImage* client,
Brian Osman7992da32016-11-18 11:28:24 -0500225 SkImage::CachingHint chint, CachedFormat format,
226 const SkImageInfo& info) {
227 if (this->lockAsBitmapOnlyIfAlreadyCached(bitmap, format)) {
reed6868c3f2015-11-24 11:44:47 -0800228 return true;
reed8f343722015-08-13 13:32:39 -0700229 }
Brian Osman7992da32016-11-18 11:28:24 -0500230 if (!this->generateBitmap(bitmap, info)) {
reed8f343722015-08-13 13:32:39 -0700231 return false;
232 }
233
Brian Osman7992da32016-11-18 11:28:24 -0500234 if (kNeedNewImageUniqueID == fUniqueIDs[format]) {
235 fUniqueIDs[format] = SkNextID::ImageID();
236 }
237 bitmap->pixelRef()->setImmutableWithID(fUniqueIDs[format]);
reed09553032015-11-23 12:32:16 -0800238 if (SkImage::kAllow_CachingHint == chint) {
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400239 SkBitmapCache::Add(SkBitmapCacheDesc::Make(fUniqueIDs[format],
240 fInfo.width(), fInfo.height()), *bitmap);
reed09553032015-11-23 12:32:16 -0800241 if (client) {
242 as_IB(client)->notifyAddedToCache();
243 }
fmalita3b0d5322015-09-18 08:07:31 -0700244 }
reed8f343722015-08-13 13:32:39 -0700245 return true;
246}
247
Robert Phillips4447b642017-03-03 11:10:18 -0500248bool SkImageCacherator::lockAsBitmap(GrContext* context, SkBitmap* bitmap, const SkImage* client,
Brian Osman61624f02016-12-09 14:51:59 -0500249 SkColorSpace* dstColorSpace,
reed09553032015-11-23 12:32:16 -0800250 SkImage::CachingHint chint) {
Brian Osman61624f02016-12-09 14:51:59 -0500251 CachedFormat format = this->chooseCacheFormat(dstColorSpace);
Brian Osman7992da32016-11-18 11:28:24 -0500252 SkImageInfo cacheInfo = this->buildCacheInfo(format);
253
254 if (kNeedNewImageUniqueID == fUniqueIDs[format]) {
255 fUniqueIDs[format] = SkNextID::ImageID();
256 }
257
258 if (this->tryLockAsBitmap(bitmap, client, chint, format, cacheInfo)) {
259 return check_output_bitmap(*bitmap, fUniqueIDs[format]);
reed8f343722015-08-13 13:32:39 -0700260 }
261
262#if SK_SUPPORT_GPU
Robert Phillips4447b642017-03-03 11:10:18 -0500263 if (!context) {
264 bitmap->reset();
265 return false;
266 }
267
reed8f343722015-08-13 13:32:39 -0700268 // 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 -0500269 sk_sp<GrTextureProxy> proxy;
reed8f343722015-08-13 13:32:39 -0700270
reedd5c448f2015-08-26 14:16:43 -0700271 {
fmalitaf0c38f52016-10-27 14:22:41 -0700272 ScopedGenerator generator(fSharedGenerator);
Robert Phillips4447b642017-03-03 11:10:18 -0500273 proxy = generator->generateTexture(context, cacheInfo, fOrigin);
reedd5c448f2015-08-26 14:16:43 -0700274 }
Robert Phillips4447b642017-03-03 11:10:18 -0500275 if (!proxy) {
reed8f343722015-08-13 13:32:39 -0700276 bitmap->reset();
277 return false;
278 }
279
Brian Osman7992da32016-11-18 11:28:24 -0500280 if (!bitmap->tryAllocPixels(cacheInfo)) {
reed8f343722015-08-13 13:32:39 -0700281 bitmap->reset();
282 return false;
283 }
284
Robert Phillips4447b642017-03-03 11:10:18 -0500285 sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeWrappedSurfaceContext(
286 proxy,
287 fInfo.refColorSpace())); // src colorSpace
288 if (!sContext) {
289 bitmap->reset();
290 return false;
291 }
292
293 if (!sContext->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
reed8f343722015-08-13 13:32:39 -0700294 bitmap->reset();
295 return false;
296 }
297
Brian Osman7992da32016-11-18 11:28:24 -0500298 bitmap->pixelRef()->setImmutableWithID(fUniqueIDs[format]);
reed09553032015-11-23 12:32:16 -0800299 if (SkImage::kAllow_CachingHint == chint) {
Mike Reed5fa3d6d2017-03-25 09:51:00 -0400300 SkBitmapCache::Add(SkBitmapCacheDesc::Make(fUniqueIDs[format],
301 fInfo.width(), fInfo.height()), *bitmap);
reed09553032015-11-23 12:32:16 -0800302 if (client) {
303 as_IB(client)->notifyAddedToCache();
304 }
fmalita3b0d5322015-09-18 08:07:31 -0700305 }
Brian Osman7992da32016-11-18 11:28:24 -0500306 return check_output_bitmap(*bitmap, fUniqueIDs[format]);
reed8f343722015-08-13 13:32:39 -0700307#else
308 return false;
309#endif
310}
311
312//////////////////////////////////////////////////////////////////////////////////////////////////
313
Brian Osman7992da32016-11-18 11:28:24 -0500314// Abstraction of GrCaps that handles the cases where we don't have a caps pointer (because
315// we're in raster mode), or where GPU support is entirely missing. In theory, we only need the
316// chosen format to be texturable, but that lets us choose F16 on GLES implemenations where we
317// won't be able to read the texture back. We'd like to ensure that SkImake::makeNonTextureImage
318// works, so we require that the formats we choose are renderable (as a proxy for being readable).
319struct CacheCaps {
320 CacheCaps(const GrCaps* caps) : fCaps(caps) {}
321
Brian Osmand6010872016-11-15 18:06:18 +0000322#if SK_SUPPORT_GPU
Brian Osman7992da32016-11-18 11:28:24 -0500323 bool supportsHalfFloat() const {
324 return !fCaps ||
325 (fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig) &&
326 fCaps->isConfigRenderable(kRGBA_half_GrPixelConfig, false));
327 }
328
329 bool supportsSRGB() const {
330 return !fCaps ||
331 (fCaps->srgbSupport() && fCaps->isConfigTexturable(kSRGBA_8888_GrPixelConfig));
332 }
333
334 bool supportsSBGR() const {
335 return !fCaps || fCaps->srgbSupport();
336 }
337#else
338 bool supportsHalfFloat() const { return true; }
339 bool supportsSRGB() const { return true; }
340 bool supportsSBGR() const { return true; }
341#endif
342
343 const GrCaps* fCaps;
344};
345
Brian Osman61624f02016-12-09 14:51:59 -0500346SkImageCacherator::CachedFormat SkImageCacherator::chooseCacheFormat(SkColorSpace* dstColorSpace,
347 const GrCaps* grCaps) {
Brian Osman7992da32016-11-18 11:28:24 -0500348 SkColorSpace* cs = fInfo.colorSpace();
Brian Osman61624f02016-12-09 14:51:59 -0500349 if (!cs || !dstColorSpace) {
Brian Osman7992da32016-11-18 11:28:24 -0500350 return kLegacy_CachedFormat;
351 }
352
353 CacheCaps caps(grCaps);
354 switch (fInfo.colorType()) {
355 case kUnknown_SkColorType:
356 case kAlpha_8_SkColorType:
357 case kRGB_565_SkColorType:
358 case kARGB_4444_SkColorType:
359 // We don't support color space on these formats, so always decode in legacy mode:
360 // TODO: Ask the codec to decode these to something else (at least sRGB 8888)?
361 return kLegacy_CachedFormat;
362
363 case kIndex_8_SkColorType:
364 // We can't draw from indexed textures with a color space, so ask the codec to expand
365 if (cs->gammaCloseToSRGB()) {
366 if (caps.supportsSRGB()) {
367 return kSRGB8888_CachedFormat;
368 } else if (caps.supportsHalfFloat()) {
369 return kLinearF16_CachedFormat;
370 } else {
371 return kLegacy_CachedFormat;
372 }
373 } else {
374 if (caps.supportsHalfFloat()) {
375 return kLinearF16_CachedFormat;
376 } else if (caps.supportsSRGB()) {
377 return kSRGB8888_CachedFormat;
378 } else {
379 return kLegacy_CachedFormat;
380 }
381 }
382
383 case kGray_8_SkColorType:
384 // TODO: What do we do with grayscale sources that have strange color spaces attached?
385 // The codecs and color space xform don't handle this correctly (yet), so drop it on
386 // the floor. (Also, inflating by a factor of 8 is going to be unfortunate).
387 // As it is, we don't directly support sRGB grayscale, so ask the codec to convert
388 // it for us. This bypasses some really sketchy code GrUploadPixmapToTexture.
389 if (cs->gammaCloseToSRGB() && caps.supportsSRGB()) {
390 return kSRGB8888_CachedFormat;
391 } else {
392 return kLegacy_CachedFormat;
393 }
394
395 case kRGBA_8888_SkColorType:
396 if (cs->gammaCloseToSRGB()) {
397 if (caps.supportsSRGB()) {
Brian Osman84c009f2017-03-31 17:02:41 -0400398 return kSRGB8888_CachedFormat;
Brian Osman7992da32016-11-18 11:28:24 -0500399 } else if (caps.supportsHalfFloat()) {
400 return kLinearF16_CachedFormat;
401 } else {
402 return kLegacy_CachedFormat;
403 }
404 } else {
405 if (caps.supportsHalfFloat()) {
406 return kLinearF16_CachedFormat;
407 } else if (caps.supportsSRGB()) {
408 return kSRGB8888_CachedFormat;
409 } else {
410 return kLegacy_CachedFormat;
411 }
412 }
413
414 case kBGRA_8888_SkColorType:
415 // Odd case. sBGRA isn't a real thing, so we may not have this texturable.
416 if (caps.supportsSBGR()) {
417 if (cs->gammaCloseToSRGB()) {
Brian Osman84c009f2017-03-31 17:02:41 -0400418 return kSBGR8888_CachedFormat;
Brian Osman7992da32016-11-18 11:28:24 -0500419 } else if (caps.supportsHalfFloat()) {
420 return kLinearF16_CachedFormat;
421 } else if (caps.supportsSRGB()) {
422 return kSRGB8888_CachedFormat;
423 } else {
424 // sBGRA support without sRGBA is highly unlikely (impossible?) Nevertheless.
425 return kLegacy_CachedFormat;
426 }
427 } else {
428 if (cs->gammaCloseToSRGB()) {
429 if (caps.supportsSRGB()) {
430 return kSRGB8888_CachedFormat;
431 } else if (caps.supportsHalfFloat()) {
432 return kLinearF16_CachedFormat;
433 } else {
434 return kLegacy_CachedFormat;
435 }
436 } else {
437 if (caps.supportsHalfFloat()) {
438 return kLinearF16_CachedFormat;
439 } else if (caps.supportsSRGB()) {
440 return kSRGB8888_CachedFormat;
441 } else {
442 return kLegacy_CachedFormat;
443 }
444 }
445 }
446
447 case kRGBA_F16_SkColorType:
Brian Osman84c009f2017-03-31 17:02:41 -0400448 if (caps.supportsHalfFloat()) {
Brian Osman7992da32016-11-18 11:28:24 -0500449 return kLinearF16_CachedFormat;
Brian Osman84c009f2017-03-31 17:02:41 -0400450 } else if (caps.supportsSRGB()) {
451 return kSRGB8888_CachedFormat;
452 } else {
453 return kLegacy_CachedFormat;
Brian Osman7992da32016-11-18 11:28:24 -0500454 }
455 }
456 SkDEBUGFAIL("Unreachable");
457 return kLegacy_CachedFormat;
458}
459
460SkImageInfo SkImageCacherator::buildCacheInfo(CachedFormat format) {
461 switch (format) {
462 case kLegacy_CachedFormat:
463 return fInfo.makeColorSpace(nullptr);
Brian Osman7992da32016-11-18 11:28:24 -0500464 case kLinearF16_CachedFormat:
Brian Osman944feea2017-04-05 11:26:02 -0400465 return fInfo.makeColorType(kRGBA_F16_SkColorType)
466 .makeColorSpace(as_CSB(fInfo.colorSpace())->makeLinearGamma());
Brian Osman7992da32016-11-18 11:28:24 -0500467 case kSRGB8888_CachedFormat:
Brian Osman944feea2017-04-05 11:26:02 -0400468 // If the transfer function is nearly (but not exactly) sRGB, we don't want the codec
469 // to bother trans-coding. It would be slow, and do more harm than good visually,
470 // so we make sure to leave the colorspace as-is.
471 if (fInfo.colorSpace()->gammaCloseToSRGB()) {
472 return fInfo.makeColorType(kRGBA_8888_SkColorType);
473 } else {
474 return fInfo.makeColorType(kRGBA_8888_SkColorType)
475 .makeColorSpace(as_CSB(fInfo.colorSpace())->makeSRGBGamma());
476 }
Brian Osman84c009f2017-03-31 17:02:41 -0400477 case kSBGR8888_CachedFormat:
Brian Osman944feea2017-04-05 11:26:02 -0400478 // See note above about not-quite-sRGB transfer functions.
479 if (fInfo.colorSpace()->gammaCloseToSRGB()) {
480 return fInfo.makeColorType(kBGRA_8888_SkColorType);
481 } else {
482 return fInfo.makeColorType(kBGRA_8888_SkColorType)
483 .makeColorSpace(as_CSB(fInfo.colorSpace())->makeSRGBGamma());
484 }
Brian Osman7992da32016-11-18 11:28:24 -0500485 default:
486 SkDEBUGFAIL("Invalid cached format");
487 return fInfo;
488 }
489}
490
491//////////////////////////////////////////////////////////////////////////////////////////////////
492
493#if SK_SUPPORT_GPU
494
495void SkImageCacherator::makeCacheKeyFromOrigKey(const GrUniqueKey& origKey, CachedFormat format,
496 GrUniqueKey* cacheKey) {
497 SkASSERT(!cacheKey->isValid());
498 if (origKey.isValid()) {
499 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
500 GrUniqueKey::Builder builder(cacheKey, origKey, kDomain, 1);
501 builder[0] = format;
502 }
503}
Brian Osmand6010872016-11-15 18:06:18 +0000504
505#ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR
506static GrTexture* load_compressed_into_texture(GrContext* ctx, SkData* data, GrSurfaceDesc desc) {
507 const void* rawStart;
508 GrPixelConfig config = GrIsCompressedTextureDataSupported(ctx, data, desc.fWidth, desc.fHeight,
509 &rawStart);
510 if (kUnknown_GrPixelConfig == config) {
511 return nullptr;
512 }
513
514 desc.fConfig = config;
Brian Osman32342f02017-03-04 08:12:46 -0500515 return ctx->resourceProvider()->createTexture(desc, SkBudgeted::kYes, rawStart, 0);
Brian Osmand6010872016-11-15 18:06:18 +0000516}
517#endif
518
519class Generator_GrYUVProvider : public GrYUVProvider {
520 SkImageGenerator* fGen;
521
522public:
523 Generator_GrYUVProvider(SkImageGenerator* gen) : fGen(gen) {}
524
525 uint32_t onGetID() override { return fGen->uniqueID(); }
526 bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const override {
527 return fGen->queryYUV8(sizeInfo, colorSpace);
528 }
529 bool onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) override {
530 return fGen->getYUV8Planes(sizeInfo, planes);
531 }
532};
533
Robert Phillipsd3749482017-03-14 09:17:43 -0400534static void set_key_on_proxy(GrResourceProvider* resourceProvider,
535 GrTextureProxy* proxy, const GrUniqueKey& key) {
536 if (key.isValid()) {
537 resourceProvider->assignUniqueKeyToProxy(key, proxy);
538 }
539}
Robert Phillipsd3749482017-03-14 09:17:43 -0400540
Brian Osman61624f02016-12-09 14:51:59 -0500541sk_sp<SkColorSpace> SkImageCacherator::getColorSpace(GrContext* ctx, SkColorSpace* dstColorSpace) {
Brian Osman7992da32016-11-18 11:28:24 -0500542 // TODO: This isn't always correct. Picture generator currently produces textures in N32,
543 // and will (soon) emit them in an arbitrary (destination) space. We will need to stash that
544 // information in/on the key so we can return the correct space in case #1 of lockTexture.
Brian Osman61624f02016-12-09 14:51:59 -0500545 CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps());
Brian Osman7992da32016-11-18 11:28:24 -0500546 SkImageInfo cacheInfo = this->buildCacheInfo(format);
547 return sk_ref_sp(cacheInfo.colorSpace());
548}
549
reedd5c448f2015-08-26 14:16:43 -0700550/*
551 * We have a 5 ways to try to return a texture (in sorted order)
552 *
553 * 1. Check the cache for a pre-existing one
bsalomonafa95e22015-10-12 10:39:46 -0700554 * 2. Ask the generator to natively create one
reedd5c448f2015-08-26 14:16:43 -0700555 * 3. Ask the generator to return a compressed form that the GPU might support
556 * 4. Ask the generator to return YUV planes, which the GPU can convert
557 * 5. Ask the generator to return RGB(A) data, which the GPU can convert
558 */
Robert Phillips4f358be2017-03-23 08:21:00 -0400559sk_sp<GrTextureProxy> SkImageCacherator::lockTextureProxy(GrContext* ctx,
560 const GrUniqueKey& origKey,
561 const SkImage* client,
562 SkImage::CachingHint chint,
563 bool willBeMipped,
564 SkColorSpace* dstColorSpace) {
ericrk369e9372016-02-05 15:32:36 -0800565 // Values representing the various texture lock paths we can take. Used for logging the path
566 // taken to a histogram.
567 enum LockTexturePath {
568 kFailure_LockTexturePath,
569 kPreExisting_LockTexturePath,
570 kNative_LockTexturePath,
571 kCompressed_LockTexturePath,
572 kYUV_LockTexturePath,
573 kRGBA_LockTexturePath,
574 };
575
576 enum { kLockTexturePathCount = kRGBA_LockTexturePath + 1 };
577
Brian Osman7992da32016-11-18 11:28:24 -0500578 // Determine which cached format we're going to use (which may involve decoding to a different
579 // info than the generator provides).
Brian Osman61624f02016-12-09 14:51:59 -0500580 CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps());
Brian Osman7992da32016-11-18 11:28:24 -0500581
582 // Fold the cache format into our texture key
583 GrUniqueKey key;
584 this->makeCacheKeyFromOrigKey(origKey, format, &key);
585
Brian Salomonbc0bcc02015-10-19 15:12:32 -0400586 // 1. Check the cache for a pre-existing one
bsalomon045802d2015-10-20 07:58:01 -0700587 if (key.isValid()) {
Robert Phillips4f358be2017-03-23 08:21:00 -0400588 if (sk_sp<GrTextureProxy> proxy = ctx->resourceProvider()->findProxyByUniqueKey(key)) {
ericrk369e9372016-02-05 15:32:36 -0800589 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kPreExisting_LockTexturePath,
590 kLockTexturePathCount);
Robert Phillips4f358be2017-03-23 08:21:00 -0400591 return proxy;
bsalomon045802d2015-10-20 07:58:01 -0700592 }
Brian Salomonbc0bcc02015-10-19 15:12:32 -0400593 }
594
Brian Osman222e9ad2016-12-14 15:42:36 -0500595 // The CachedFormat is both an index for which cache "slot" we'll use to store this particular
596 // decoded variant of the encoded data, and also a recipe for how to transform the original
597 // info to get the one that we're going to decode to.
598 SkImageInfo cacheInfo = this->buildCacheInfo(format);
599
bsalomon045802d2015-10-20 07:58:01 -0700600 // 2. Ask the generator to natively create one
reedd5c448f2015-08-26 14:16:43 -0700601 {
fmalitaf0c38f52016-10-27 14:22:41 -0700602 ScopedGenerator generator(fSharedGenerator);
Robert Phillips4447b642017-03-03 11:10:18 -0500603 if (sk_sp<GrTextureProxy> proxy = generator->generateTexture(ctx, cacheInfo, fOrigin)) {
ericrk369e9372016-02-05 15:32:36 -0800604 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kNative_LockTexturePath,
605 kLockTexturePathCount);
Robert Phillips4f358be2017-03-23 08:21:00 -0400606 set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key);
607 return proxy;
reedd5c448f2015-08-26 14:16:43 -0700608 }
609 }
reed8f343722015-08-13 13:32:39 -0700610
Brian Osman7992da32016-11-18 11:28:24 -0500611 const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(cacheInfo, *ctx->caps());
reed3322a812015-09-16 10:09:24 -0700612
reed93eeadf2016-05-11 08:06:11 -0700613#ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR
reedd5c448f2015-08-26 14:16:43 -0700614 // 3. Ask the generator to return a compressed form that the GPU might support
bungemanffae30d2016-08-03 13:32:32 -0700615 sk_sp<SkData> data(this->refEncoded(ctx));
reed85d91782015-09-10 14:33:38 -0700616 if (data) {
617 GrTexture* tex = load_compressed_into_texture(ctx, data, desc);
618 if (tex) {
ericrk369e9372016-02-05 15:32:36 -0800619 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kCompressed_LockTexturePath,
620 kLockTexturePathCount);
reed85d91782015-09-10 14:33:38 -0700621 return set_key_and_return(tex, key);
622 }
623 }
reed93eeadf2016-05-11 08:06:11 -0700624#endif
reedd5c448f2015-08-26 14:16:43 -0700625
626 // 4. Ask the generator to return YUV planes, which the GPU can convert
Brian Osman46da1cc2017-02-14 14:15:48 -0500627 if (!ctx->contextPriv().disableGpuYUVConversion()) {
fmalitaf0c38f52016-10-27 14:22:41 -0700628 ScopedGenerator generator(fSharedGenerator);
reed85d91782015-09-10 14:33:38 -0700629 Generator_GrYUVProvider provider(generator);
Robert Phillips538f1a32017-03-08 14:32:55 -0500630 if (sk_sp<GrTextureProxy> proxy = provider.refAsTextureProxy(ctx, desc, true)) {
ericrk369e9372016-02-05 15:32:36 -0800631 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kYUV_LockTexturePath,
632 kLockTexturePathCount);
Robert Phillips4f358be2017-03-23 08:21:00 -0400633 set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key);
634 return proxy;
reed85d91782015-09-10 14:33:38 -0700635 }
636 }
reedd5c448f2015-08-26 14:16:43 -0700637
638 // 5. Ask the generator to return RGB(A) data, which the GPU can convert
reed8f343722015-08-13 13:32:39 -0700639 SkBitmap bitmap;
Brian Osman7992da32016-11-18 11:28:24 -0500640 if (this->tryLockAsBitmap(&bitmap, client, chint, format, cacheInfo)) {
Robert Phillips4f358be2017-03-23 08:21:00 -0400641 sk_sp<GrTextureProxy> proxy;
cblume55f2d2d2016-02-26 13:20:48 -0800642 if (willBeMipped) {
Robert Phillips4f358be2017-03-23 08:21:00 -0400643 proxy = GrGenerateMipMapsAndUploadToTextureProxy(ctx, bitmap, dstColorSpace);
brianosmaneb3429c2016-03-25 13:03:03 -0700644 }
Robert Phillips4f358be2017-03-23 08:21:00 -0400645 if (!proxy) {
646 proxy = GrUploadBitmapToTextureProxy(ctx->resourceProvider(), bitmap);
cblume55f2d2d2016-02-26 13:20:48 -0800647 }
Robert Phillips4f358be2017-03-23 08:21:00 -0400648 if (proxy) {
ericrk369e9372016-02-05 15:32:36 -0800649 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kRGBA_LockTexturePath,
650 kLockTexturePathCount);
Robert Phillips4f358be2017-03-23 08:21:00 -0400651 set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key);
652 return proxy;
bsalomon045802d2015-10-20 07:58:01 -0700653 }
reed8f343722015-08-13 13:32:39 -0700654 }
ericrk369e9372016-02-05 15:32:36 -0800655 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kFailure_LockTexturePath,
656 kLockTexturePathCount);
reed85d91782015-09-10 14:33:38 -0700657 return nullptr;
reed8f343722015-08-13 13:32:39 -0700658}
659
reed856e9d92015-09-30 12:21:45 -0700660///////////////////////////////////////////////////////////////////////////////////////////////////
661
Robert Phillips4f358be2017-03-23 08:21:00 -0400662sk_sp<GrTextureProxy> SkImageCacherator::lockAsTextureProxy(GrContext* ctx,
663 const GrSamplerParams& params,
664 SkColorSpace* dstColorSpace,
665 sk_sp<SkColorSpace>* texColorSpace,
666 const SkImage* client,
667 SkScalar scaleAdjust[2],
668 SkImage::CachingHint chint) {
reed856e9d92015-09-30 12:21:45 -0700669 if (!ctx) {
670 return nullptr;
671 }
672
Robert Phillips3798c862017-03-27 11:08:16 -0400673 return GrImageTextureMaker(ctx, this, client, chint).refTextureProxyForParams(params,
Robert Phillips4f358be2017-03-23 08:21:00 -0400674 dstColorSpace,
675 texColorSpace,
Robert Phillips3798c862017-03-27 11:08:16 -0400676 scaleAdjust);
reed856e9d92015-09-30 12:21:45 -0700677}
678
679#endif