blob: f36af3f259ee7cc60cbba6b5057573bb1a814094 [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 Salomon514baff2016-11-17 15:17:07 -050024#include "GrSamplerParams.h"
reed85d91782015-09-10 14:33:38 -070025#include "GrYUVProvider.h"
reed8f343722015-08-13 13:32:39 -070026#include "SkGr.h"
27#include "SkGrPriv.h"
28#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
92 // If the encoded data is in a strange color space (it's not an XYZ matrix space), we won't be
93 // able to preserve the gamut of the encoded data when we decode it. Instead, we'll have to
94 // decode to a known color space (linear sRGB is a good choice). But we need to adjust the
95 // stored color space, because drawing code will ask the SkImage for its color space, which
96 // will in turn ask the cacherator. If we return the A2B color space, then we will be unable to
97 // construct a source-to-dest gamut transformation matrix.
98 if (fInfo.colorSpace() &&
99 SkColorSpace_Base::Type::kXYZ != as_CSB(fInfo.colorSpace())->type()) {
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500100 fInfo = fInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear());
Brian Osman7992da32016-11-18 11:28:24 -0500101 }
reed8f4fe372015-08-13 14:06:46 -0700102}
103
Mike Reed185130c2017-02-15 15:14:16 -0500104SkImageCacherator* SkImageCacherator::NewFromGenerator(std::unique_ptr<SkImageGenerator> gen,
fmalita7929e3a2016-10-27 08:15:44 -0700105 const SkIRect* subset) {
Mike Reed185130c2017-02-15 15:14:16 -0500106 Validator validator(SharedGenerator::Make(std::move(gen)), subset);
fmalita7929e3a2016-10-27 08:15:44 -0700107
108 return validator ? new SkImageCacherator(&validator) : nullptr;
109}
110
111SkImageCacherator::SkImageCacherator(Validator* validator)
fmalitaf0c38f52016-10-27 14:22:41 -0700112 : fSharedGenerator(std::move(validator->fSharedGenerator)) // we take ownership
fmalita7929e3a2016-10-27 08:15:44 -0700113 , fInfo(validator->fInfo)
114 , fOrigin(validator->fOrigin)
fmalita7929e3a2016-10-27 08:15:44 -0700115{
Brian Osman7992da32016-11-18 11:28:24 -0500116 fUniqueIDs[kLegacy_CachedFormat] = validator->fUniqueID;
117 for (int i = 1; i < kNumCachedFormats; ++i) {
118 // We lazily allocate IDs for non-default caching cases
119 fUniqueIDs[i] = kNeedNewImageUniqueID;
120 }
fmalitaf0c38f52016-10-27 14:22:41 -0700121 SkASSERT(fSharedGenerator);
fmalita7929e3a2016-10-27 08:15:44 -0700122}
reed8f343722015-08-13 13:32:39 -0700123
fmalitaf0c38f52016-10-27 14:22:41 -0700124SkImageCacherator::~SkImageCacherator() {}
125
reed05dd2512016-01-05 09:16:19 -0800126SkData* SkImageCacherator::refEncoded(GrContext* ctx) {
fmalitaf0c38f52016-10-27 14:22:41 -0700127 ScopedGenerator generator(fSharedGenerator);
reed05dd2512016-01-05 09:16:19 -0800128 return generator->refEncodedData(ctx);
reedd5c448f2015-08-26 14:16:43 -0700129}
reed8f343722015-08-13 13:32:39 -0700130
131static bool check_output_bitmap(const SkBitmap& bitmap, uint32_t expectedID) {
132 SkASSERT(bitmap.getGenerationID() == expectedID);
133 SkASSERT(bitmap.isImmutable());
134 SkASSERT(bitmap.getPixels());
135 return true;
136}
137
reed995b4bd2015-09-14 10:27:57 -0700138// Note, this returns a new, mutable, bitmap, with a new genID.
139// If you want the immutable bitmap with the same ID as our cacherator, call tryLockAsBitmap()
140//
Brian Osman7992da32016-11-18 11:28:24 -0500141bool SkImageCacherator::generateBitmap(SkBitmap* bitmap, const SkImageInfo& decodeInfo) {
reed4b3d3be2015-09-17 13:35:19 -0700142 SkBitmap::Allocator* allocator = SkResourceCache::GetAllocator();
143
fmalitaf0c38f52016-10-27 14:22:41 -0700144 ScopedGenerator generator(fSharedGenerator);
reed935d6cf2015-08-18 11:16:09 -0700145 const SkImageInfo& genInfo = generator->getInfo();
Brian Osman7992da32016-11-18 11:28:24 -0500146 if (decodeInfo.dimensions() == genInfo.dimensions()) {
reedd5c448f2015-08-26 14:16:43 -0700147 SkASSERT(fOrigin.x() == 0 && fOrigin.y() == 0);
reed935d6cf2015-08-18 11:16:09 -0700148 // fast-case, no copy needed
Brian Osman7992da32016-11-18 11:28:24 -0500149 return generator->tryGenerateBitmap(bitmap, decodeInfo, allocator);
reed935d6cf2015-08-18 11:16:09 -0700150 } else {
reedc4a83e22015-09-11 11:47:27 -0700151 // need to handle subsetting, so we first generate the full size version, and then
halcanary6950de62015-11-07 05:29:00 -0800152 // "read" from it to get our subset. See https://bug.skia.org/4213
reedc4a83e22015-09-11 11:47:27 -0700153
reed935d6cf2015-08-18 11:16:09 -0700154 SkBitmap full;
Brian Osman7992da32016-11-18 11:28:24 -0500155 if (!generator->tryGenerateBitmap(&full,
156 decodeInfo.makeWH(genInfo.width(), genInfo.height()),
157 allocator)) {
reed935d6cf2015-08-18 11:16:09 -0700158 return false;
159 }
Brian Osman7992da32016-11-18 11:28:24 -0500160 if (!bitmap->tryAllocPixels(decodeInfo, nullptr, full.getColorTable())) {
reed935d6cf2015-08-18 11:16:09 -0700161 return false;
162 }
reedc4a83e22015-09-11 11:47:27 -0700163 return full.readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(),
164 fOrigin.x(), fOrigin.y());
reed935d6cf2015-08-18 11:16:09 -0700165 }
reed8f343722015-08-13 13:32:39 -0700166}
167
reed6868c3f2015-11-24 11:44:47 -0800168bool SkImageCacherator::directGeneratePixels(const SkImageInfo& info, void* pixels, size_t rb,
169 int srcX, int srcY) {
fmalitaf0c38f52016-10-27 14:22:41 -0700170 ScopedGenerator generator(fSharedGenerator);
reed6868c3f2015-11-24 11:44:47 -0800171 const SkImageInfo& genInfo = generator->getInfo();
172 // Currently generators do not natively handle subsets, so check that first.
173 if (srcX || srcY || genInfo.width() != info.width() || genInfo.height() != info.height()) {
174 return false;
175 }
176 return generator->getPixels(info, pixels, rb);
177}
178
reed8f343722015-08-13 13:32:39 -0700179//////////////////////////////////////////////////////////////////////////////////////////////////
180
Brian Osman7992da32016-11-18 11:28:24 -0500181bool SkImageCacherator::lockAsBitmapOnlyIfAlreadyCached(SkBitmap* bitmap, CachedFormat format) {
182 return kNeedNewImageUniqueID != fUniqueIDs[format] &&
183 SkBitmapCache::Find(fUniqueIDs[format], bitmap) &&
184 check_output_bitmap(*bitmap, fUniqueIDs[format]);
reed6868c3f2015-11-24 11:44:47 -0800185}
186
reed09553032015-11-23 12:32:16 -0800187bool SkImageCacherator::tryLockAsBitmap(SkBitmap* bitmap, const SkImage* client,
Brian Osman7992da32016-11-18 11:28:24 -0500188 SkImage::CachingHint chint, CachedFormat format,
189 const SkImageInfo& info) {
190 if (this->lockAsBitmapOnlyIfAlreadyCached(bitmap, format)) {
reed6868c3f2015-11-24 11:44:47 -0800191 return true;
reed8f343722015-08-13 13:32:39 -0700192 }
Brian Osman7992da32016-11-18 11:28:24 -0500193 if (!this->generateBitmap(bitmap, info)) {
reed8f343722015-08-13 13:32:39 -0700194 return false;
195 }
196
Brian Osman7992da32016-11-18 11:28:24 -0500197 if (kNeedNewImageUniqueID == fUniqueIDs[format]) {
198 fUniqueIDs[format] = SkNextID::ImageID();
199 }
200 bitmap->pixelRef()->setImmutableWithID(fUniqueIDs[format]);
reed09553032015-11-23 12:32:16 -0800201 if (SkImage::kAllow_CachingHint == chint) {
Brian Osman7992da32016-11-18 11:28:24 -0500202 SkBitmapCache::Add(fUniqueIDs[format], *bitmap);
reed09553032015-11-23 12:32:16 -0800203 if (client) {
204 as_IB(client)->notifyAddedToCache();
205 }
fmalita3b0d5322015-09-18 08:07:31 -0700206 }
reed8f343722015-08-13 13:32:39 -0700207 return true;
208}
209
reed09553032015-11-23 12:32:16 -0800210bool SkImageCacherator::lockAsBitmap(SkBitmap* bitmap, const SkImage* client,
Brian Osman61624f02016-12-09 14:51:59 -0500211 SkColorSpace* dstColorSpace,
reed09553032015-11-23 12:32:16 -0800212 SkImage::CachingHint chint) {
Brian Osman61624f02016-12-09 14:51:59 -0500213 CachedFormat format = this->chooseCacheFormat(dstColorSpace);
Brian Osman7992da32016-11-18 11:28:24 -0500214 SkImageInfo cacheInfo = this->buildCacheInfo(format);
215
216 if (kNeedNewImageUniqueID == fUniqueIDs[format]) {
217 fUniqueIDs[format] = SkNextID::ImageID();
218 }
219
220 if (this->tryLockAsBitmap(bitmap, client, chint, format, cacheInfo)) {
221 return check_output_bitmap(*bitmap, fUniqueIDs[format]);
reed8f343722015-08-13 13:32:39 -0700222 }
223
224#if SK_SUPPORT_GPU
225 // Try to get a texture and read it back to raster (and then cache that with our ID)
Hal Canary704cd322016-11-07 14:13:52 -0500226 sk_sp<GrTexture> tex;
reed8f343722015-08-13 13:32:39 -0700227
reedd5c448f2015-08-26 14:16:43 -0700228 {
fmalitaf0c38f52016-10-27 14:22:41 -0700229 ScopedGenerator generator(fSharedGenerator);
Brian Osman222e9ad2016-12-14 15:42:36 -0500230 tex.reset(generator->generateTexture(nullptr, cacheInfo, fOrigin));
reedd5c448f2015-08-26 14:16:43 -0700231 }
reed8f343722015-08-13 13:32:39 -0700232 if (!tex) {
233 bitmap->reset();
234 return false;
235 }
236
Brian Osman7992da32016-11-18 11:28:24 -0500237 if (!bitmap->tryAllocPixels(cacheInfo)) {
reed8f343722015-08-13 13:32:39 -0700238 bitmap->reset();
239 return false;
240 }
241
Brian Osmanb62ea222016-12-22 11:12:16 -0500242 if (!tex->readPixels(fInfo.colorSpace(), 0, 0, bitmap->width(), bitmap->height(),
Brian Osman7992da32016-11-18 11:28:24 -0500243 SkImageInfo2GrPixelConfig(cacheInfo, *tex->getContext()->caps()),
Robert Phillipsc949ce92017-01-19 16:59:04 -0500244 cacheInfo.colorSpace(), bitmap->getPixels(), bitmap->rowBytes())) {
reed8f343722015-08-13 13:32:39 -0700245 bitmap->reset();
246 return false;
247 }
248
Brian Osman7992da32016-11-18 11:28:24 -0500249 bitmap->pixelRef()->setImmutableWithID(fUniqueIDs[format]);
reed09553032015-11-23 12:32:16 -0800250 if (SkImage::kAllow_CachingHint == chint) {
Brian Osman7992da32016-11-18 11:28:24 -0500251 SkBitmapCache::Add(fUniqueIDs[format], *bitmap);
reed09553032015-11-23 12:32:16 -0800252 if (client) {
253 as_IB(client)->notifyAddedToCache();
254 }
fmalita3b0d5322015-09-18 08:07:31 -0700255 }
Brian Osman7992da32016-11-18 11:28:24 -0500256 return check_output_bitmap(*bitmap, fUniqueIDs[format]);
reed8f343722015-08-13 13:32:39 -0700257#else
258 return false;
259#endif
260}
261
262//////////////////////////////////////////////////////////////////////////////////////////////////
263
Brian Osman7992da32016-11-18 11:28:24 -0500264// Abstraction of GrCaps that handles the cases where we don't have a caps pointer (because
265// we're in raster mode), or where GPU support is entirely missing. In theory, we only need the
266// chosen format to be texturable, but that lets us choose F16 on GLES implemenations where we
267// won't be able to read the texture back. We'd like to ensure that SkImake::makeNonTextureImage
268// works, so we require that the formats we choose are renderable (as a proxy for being readable).
269struct CacheCaps {
270 CacheCaps(const GrCaps* caps) : fCaps(caps) {}
271
Brian Osmand6010872016-11-15 18:06:18 +0000272#if SK_SUPPORT_GPU
Brian Osman7992da32016-11-18 11:28:24 -0500273 bool supportsHalfFloat() const {
274 return !fCaps ||
275 (fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig) &&
276 fCaps->isConfigRenderable(kRGBA_half_GrPixelConfig, false));
277 }
278
279 bool supportsSRGB() const {
280 return !fCaps ||
281 (fCaps->srgbSupport() && fCaps->isConfigTexturable(kSRGBA_8888_GrPixelConfig));
282 }
283
284 bool supportsSBGR() const {
285 return !fCaps || fCaps->srgbSupport();
286 }
287#else
288 bool supportsHalfFloat() const { return true; }
289 bool supportsSRGB() const { return true; }
290 bool supportsSBGR() const { return true; }
291#endif
292
293 const GrCaps* fCaps;
294};
295
Brian Osman61624f02016-12-09 14:51:59 -0500296SkImageCacherator::CachedFormat SkImageCacherator::chooseCacheFormat(SkColorSpace* dstColorSpace,
297 const GrCaps* grCaps) {
Brian Osman7992da32016-11-18 11:28:24 -0500298 SkColorSpace* cs = fInfo.colorSpace();
Brian Osman61624f02016-12-09 14:51:59 -0500299 if (!cs || !dstColorSpace) {
Brian Osman7992da32016-11-18 11:28:24 -0500300 return kLegacy_CachedFormat;
301 }
302
303 CacheCaps caps(grCaps);
304 switch (fInfo.colorType()) {
305 case kUnknown_SkColorType:
306 case kAlpha_8_SkColorType:
307 case kRGB_565_SkColorType:
308 case kARGB_4444_SkColorType:
309 // We don't support color space on these formats, so always decode in legacy mode:
310 // TODO: Ask the codec to decode these to something else (at least sRGB 8888)?
311 return kLegacy_CachedFormat;
312
313 case kIndex_8_SkColorType:
314 // We can't draw from indexed textures with a color space, so ask the codec to expand
315 if (cs->gammaCloseToSRGB()) {
316 if (caps.supportsSRGB()) {
317 return kSRGB8888_CachedFormat;
318 } else if (caps.supportsHalfFloat()) {
319 return kLinearF16_CachedFormat;
320 } else {
321 return kLegacy_CachedFormat;
322 }
323 } else {
324 if (caps.supportsHalfFloat()) {
325 return kLinearF16_CachedFormat;
326 } else if (caps.supportsSRGB()) {
327 return kSRGB8888_CachedFormat;
328 } else {
329 return kLegacy_CachedFormat;
330 }
331 }
332
333 case kGray_8_SkColorType:
334 // TODO: What do we do with grayscale sources that have strange color spaces attached?
335 // The codecs and color space xform don't handle this correctly (yet), so drop it on
336 // the floor. (Also, inflating by a factor of 8 is going to be unfortunate).
337 // As it is, we don't directly support sRGB grayscale, so ask the codec to convert
338 // it for us. This bypasses some really sketchy code GrUploadPixmapToTexture.
339 if (cs->gammaCloseToSRGB() && caps.supportsSRGB()) {
340 return kSRGB8888_CachedFormat;
341 } else {
342 return kLegacy_CachedFormat;
343 }
344
345 case kRGBA_8888_SkColorType:
346 if (cs->gammaCloseToSRGB()) {
347 if (caps.supportsSRGB()) {
348 return kAsIs_CachedFormat;
349 } else if (caps.supportsHalfFloat()) {
350 return kLinearF16_CachedFormat;
351 } else {
352 return kLegacy_CachedFormat;
353 }
354 } else {
355 if (caps.supportsHalfFloat()) {
356 return kLinearF16_CachedFormat;
357 } else if (caps.supportsSRGB()) {
358 return kSRGB8888_CachedFormat;
359 } else {
360 return kLegacy_CachedFormat;
361 }
362 }
363
364 case kBGRA_8888_SkColorType:
365 // Odd case. sBGRA isn't a real thing, so we may not have this texturable.
366 if (caps.supportsSBGR()) {
367 if (cs->gammaCloseToSRGB()) {
368 return kAsIs_CachedFormat;
369 } else if (caps.supportsHalfFloat()) {
370 return kLinearF16_CachedFormat;
371 } else if (caps.supportsSRGB()) {
372 return kSRGB8888_CachedFormat;
373 } else {
374 // sBGRA support without sRGBA is highly unlikely (impossible?) Nevertheless.
375 return kLegacy_CachedFormat;
376 }
377 } else {
378 if (cs->gammaCloseToSRGB()) {
379 if (caps.supportsSRGB()) {
380 return kSRGB8888_CachedFormat;
381 } else if (caps.supportsHalfFloat()) {
382 return kLinearF16_CachedFormat;
383 } else {
384 return kLegacy_CachedFormat;
385 }
386 } else {
387 if (caps.supportsHalfFloat()) {
388 return kLinearF16_CachedFormat;
389 } else if (caps.supportsSRGB()) {
390 return kSRGB8888_CachedFormat;
391 } else {
392 return kLegacy_CachedFormat;
393 }
394 }
395 }
396
397 case kRGBA_F16_SkColorType:
398 if (!caps.supportsHalfFloat()) {
399 if (caps.supportsSRGB()) {
400 return kSRGB8888_CachedFormat;
401 } else {
402 return kLegacy_CachedFormat;
403 }
404 } else if (cs->gammaIsLinear()) {
405 return kAsIs_CachedFormat;
406 } else {
407 return kLinearF16_CachedFormat;
408 }
409 }
410 SkDEBUGFAIL("Unreachable");
411 return kLegacy_CachedFormat;
412}
413
414SkImageInfo SkImageCacherator::buildCacheInfo(CachedFormat format) {
415 switch (format) {
416 case kLegacy_CachedFormat:
417 return fInfo.makeColorSpace(nullptr);
418 case kAsIs_CachedFormat:
419 return fInfo;
420 case kLinearF16_CachedFormat:
421 return fInfo
422 .makeColorType(kRGBA_F16_SkColorType)
423 .makeColorSpace(as_CSB(fInfo.colorSpace())->makeLinearGamma());
424 case kSRGB8888_CachedFormat:
425 return fInfo
426 .makeColorType(kRGBA_8888_SkColorType)
427 .makeColorSpace(as_CSB(fInfo.colorSpace())->makeSRGBGamma());
428 default:
429 SkDEBUGFAIL("Invalid cached format");
430 return fInfo;
431 }
432}
433
434//////////////////////////////////////////////////////////////////////////////////////////////////
435
436#if SK_SUPPORT_GPU
437
438void SkImageCacherator::makeCacheKeyFromOrigKey(const GrUniqueKey& origKey, CachedFormat format,
439 GrUniqueKey* cacheKey) {
440 SkASSERT(!cacheKey->isValid());
441 if (origKey.isValid()) {
442 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
443 GrUniqueKey::Builder builder(cacheKey, origKey, kDomain, 1);
444 builder[0] = format;
445 }
446}
Brian Osmand6010872016-11-15 18:06:18 +0000447
448#ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR
449static GrTexture* load_compressed_into_texture(GrContext* ctx, SkData* data, GrSurfaceDesc desc) {
450 const void* rawStart;
451 GrPixelConfig config = GrIsCompressedTextureDataSupported(ctx, data, desc.fWidth, desc.fHeight,
452 &rawStart);
453 if (kUnknown_GrPixelConfig == config) {
454 return nullptr;
455 }
456
457 desc.fConfig = config;
458 return ctx->textureProvider()->createTexture(desc, SkBudgeted::kYes, rawStart, 0);
459}
460#endif
461
462class Generator_GrYUVProvider : public GrYUVProvider {
463 SkImageGenerator* fGen;
464
465public:
466 Generator_GrYUVProvider(SkImageGenerator* gen) : fGen(gen) {}
467
468 uint32_t onGetID() override { return fGen->uniqueID(); }
469 bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const override {
470 return fGen->queryYUV8(sizeInfo, colorSpace);
471 }
472 bool onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) override {
473 return fGen->getYUV8Planes(sizeInfo, planes);
474 }
475};
476
Robert Phillipsf7cf81a2017-03-02 10:23:52 -0500477static GrTexture* set_key_and_return(GrTextureProvider* texProvider,
478 GrTexture* tex, const GrUniqueKey& key) {
Brian Osmand6010872016-11-15 18:06:18 +0000479 if (key.isValid()) {
Robert Phillipsf7cf81a2017-03-02 10:23:52 -0500480 texProvider->assignUniqueKeyToTexture(key, tex);
Brian Osmand6010872016-11-15 18:06:18 +0000481 }
482 return tex;
483}
484
Brian Osman61624f02016-12-09 14:51:59 -0500485sk_sp<SkColorSpace> SkImageCacherator::getColorSpace(GrContext* ctx, SkColorSpace* dstColorSpace) {
Brian Osman7992da32016-11-18 11:28:24 -0500486 // TODO: This isn't always correct. Picture generator currently produces textures in N32,
487 // and will (soon) emit them in an arbitrary (destination) space. We will need to stash that
488 // information in/on the key so we can return the correct space in case #1 of lockTexture.
Brian Osman61624f02016-12-09 14:51:59 -0500489 CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps());
Brian Osman7992da32016-11-18 11:28:24 -0500490 SkImageInfo cacheInfo = this->buildCacheInfo(format);
491 return sk_ref_sp(cacheInfo.colorSpace());
492}
493
reedd5c448f2015-08-26 14:16:43 -0700494/*
495 * We have a 5 ways to try to return a texture (in sorted order)
496 *
497 * 1. Check the cache for a pre-existing one
bsalomonafa95e22015-10-12 10:39:46 -0700498 * 2. Ask the generator to natively create one
reedd5c448f2015-08-26 14:16:43 -0700499 * 3. Ask the generator to return a compressed form that the GPU might support
500 * 4. Ask the generator to return YUV planes, which the GPU can convert
501 * 5. Ask the generator to return RGB(A) data, which the GPU can convert
502 */
Brian Osman7992da32016-11-18 11:28:24 -0500503GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& origKey,
cblume55f2d2d2016-02-26 13:20:48 -0800504 const SkImage* client, SkImage::CachingHint chint,
Brian Osman61624f02016-12-09 14:51:59 -0500505 bool willBeMipped, SkColorSpace* dstColorSpace) {
ericrk369e9372016-02-05 15:32:36 -0800506 // Values representing the various texture lock paths we can take. Used for logging the path
507 // taken to a histogram.
508 enum LockTexturePath {
509 kFailure_LockTexturePath,
510 kPreExisting_LockTexturePath,
511 kNative_LockTexturePath,
512 kCompressed_LockTexturePath,
513 kYUV_LockTexturePath,
514 kRGBA_LockTexturePath,
515 };
516
517 enum { kLockTexturePathCount = kRGBA_LockTexturePath + 1 };
518
Brian Osman7992da32016-11-18 11:28:24 -0500519 // Determine which cached format we're going to use (which may involve decoding to a different
520 // info than the generator provides).
Brian Osman61624f02016-12-09 14:51:59 -0500521 CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps());
Brian Osman7992da32016-11-18 11:28:24 -0500522
523 // Fold the cache format into our texture key
524 GrUniqueKey key;
525 this->makeCacheKeyFromOrigKey(origKey, format, &key);
526
Brian Salomonbc0bcc02015-10-19 15:12:32 -0400527 // 1. Check the cache for a pre-existing one
bsalomon045802d2015-10-20 07:58:01 -0700528 if (key.isValid()) {
529 if (GrTexture* tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(key)) {
ericrk369e9372016-02-05 15:32:36 -0800530 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kPreExisting_LockTexturePath,
531 kLockTexturePathCount);
bsalomon045802d2015-10-20 07:58:01 -0700532 return tex;
533 }
Brian Salomonbc0bcc02015-10-19 15:12:32 -0400534 }
535
Brian Osman222e9ad2016-12-14 15:42:36 -0500536 // The CachedFormat is both an index for which cache "slot" we'll use to store this particular
537 // decoded variant of the encoded data, and also a recipe for how to transform the original
538 // info to get the one that we're going to decode to.
539 SkImageInfo cacheInfo = this->buildCacheInfo(format);
540
bsalomon045802d2015-10-20 07:58:01 -0700541 // 2. Ask the generator to natively create one
reedd5c448f2015-08-26 14:16:43 -0700542 {
fmalitaf0c38f52016-10-27 14:22:41 -0700543 ScopedGenerator generator(fSharedGenerator);
Brian Osman222e9ad2016-12-14 15:42:36 -0500544 if (GrTexture* tex = generator->generateTexture(ctx, cacheInfo, fOrigin)) {
ericrk369e9372016-02-05 15:32:36 -0800545 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kNative_LockTexturePath,
546 kLockTexturePathCount);
Robert Phillipsf7cf81a2017-03-02 10:23:52 -0500547 return set_key_and_return(ctx->textureProvider(), tex, key);
reedd5c448f2015-08-26 14:16:43 -0700548 }
549 }
reed8f343722015-08-13 13:32:39 -0700550
Brian Osman7992da32016-11-18 11:28:24 -0500551 const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(cacheInfo, *ctx->caps());
reed3322a812015-09-16 10:09:24 -0700552
reed93eeadf2016-05-11 08:06:11 -0700553#ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR
reedd5c448f2015-08-26 14:16:43 -0700554 // 3. Ask the generator to return a compressed form that the GPU might support
bungemanffae30d2016-08-03 13:32:32 -0700555 sk_sp<SkData> data(this->refEncoded(ctx));
reed85d91782015-09-10 14:33:38 -0700556 if (data) {
557 GrTexture* tex = load_compressed_into_texture(ctx, data, desc);
558 if (tex) {
ericrk369e9372016-02-05 15:32:36 -0800559 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kCompressed_LockTexturePath,
560 kLockTexturePathCount);
reed85d91782015-09-10 14:33:38 -0700561 return set_key_and_return(tex, key);
562 }
563 }
reed93eeadf2016-05-11 08:06:11 -0700564#endif
reedd5c448f2015-08-26 14:16:43 -0700565
566 // 4. Ask the generator to return YUV planes, which the GPU can convert
Brian Osman46da1cc2017-02-14 14:15:48 -0500567 if (!ctx->contextPriv().disableGpuYUVConversion()) {
fmalitaf0c38f52016-10-27 14:22:41 -0700568 ScopedGenerator generator(fSharedGenerator);
reed85d91782015-09-10 14:33:38 -0700569 Generator_GrYUVProvider provider(generator);
robertphillips677da9d2016-05-11 05:15:55 -0700570 sk_sp<GrTexture> tex = provider.refAsTexture(ctx, desc, true);
reed85d91782015-09-10 14:33:38 -0700571 if (tex) {
ericrk369e9372016-02-05 15:32:36 -0800572 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kYUV_LockTexturePath,
573 kLockTexturePathCount);
Robert Phillipsf7cf81a2017-03-02 10:23:52 -0500574 return set_key_and_return(ctx->textureProvider(), tex.release(), key);
reed85d91782015-09-10 14:33:38 -0700575 }
576 }
reedd5c448f2015-08-26 14:16:43 -0700577
578 // 5. Ask the generator to return RGB(A) data, which the GPU can convert
reed8f343722015-08-13 13:32:39 -0700579 SkBitmap bitmap;
Brian Osman7992da32016-11-18 11:28:24 -0500580 if (this->tryLockAsBitmap(&bitmap, client, chint, format, cacheInfo)) {
cblume55f2d2d2016-02-26 13:20:48 -0800581 GrTexture* tex = nullptr;
582 if (willBeMipped) {
Brian Osman61624f02016-12-09 14:51:59 -0500583 tex = GrGenerateMipMapsAndUploadToTexture(ctx, bitmap, dstColorSpace);
brianosmaneb3429c2016-03-25 13:03:03 -0700584 }
585 if (!tex) {
cblume55f2d2d2016-02-26 13:20:48 -0800586 tex = GrUploadBitmapToTexture(ctx, bitmap);
587 }
bsalomon045802d2015-10-20 07:58:01 -0700588 if (tex) {
ericrk369e9372016-02-05 15:32:36 -0800589 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kRGBA_LockTexturePath,
590 kLockTexturePathCount);
Robert Phillipsf7cf81a2017-03-02 10:23:52 -0500591 return set_key_and_return(ctx->textureProvider(), tex, key);
bsalomon045802d2015-10-20 07:58:01 -0700592 }
reed8f343722015-08-13 13:32:39 -0700593 }
ericrk369e9372016-02-05 15:32:36 -0800594 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kFailure_LockTexturePath,
595 kLockTexturePathCount);
reed85d91782015-09-10 14:33:38 -0700596 return nullptr;
reed8f343722015-08-13 13:32:39 -0700597}
598
reed856e9d92015-09-30 12:21:45 -0700599///////////////////////////////////////////////////////////////////////////////////////////////////
600
Brian Salomon514baff2016-11-17 15:17:07 -0500601GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrSamplerParams& params,
Brian Osman61624f02016-12-09 14:51:59 -0500602 SkColorSpace* dstColorSpace,
Brian Osman7992da32016-11-18 11:28:24 -0500603 sk_sp<SkColorSpace>* texColorSpace,
Robert Phillips67c18d62017-01-20 12:44:06 -0500604 const SkImage* client,
605 SkScalar scaleAdjust[2],
606 SkImage::CachingHint chint) {
reed856e9d92015-09-30 12:21:45 -0700607 if (!ctx) {
608 return nullptr;
609 }
610
Brian Osman61624f02016-12-09 14:51:59 -0500611 return GrImageTextureMaker(ctx, this, client, chint).refTextureForParams(params, dstColorSpace,
Robert Phillips67c18d62017-01-20 12:44:06 -0500612 texColorSpace,
613 scaleAdjust);
reed856e9d92015-09-30 12:21:45 -0700614}
615
616#else
617
Brian Salomon514baff2016-11-17 15:17:07 -0500618GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrSamplerParams&,
Brian Osman61624f02016-12-09 14:51:59 -0500619 SkColorSpace* dstColorSpace,
Brian Osman7992da32016-11-18 11:28:24 -0500620 sk_sp<SkColorSpace>* texColorSpace,
Robert Phillips67c18d62017-01-20 12:44:06 -0500621 const SkImage* client,
622 SkScalar scaleAdjust[2], SkImage::CachingHint) {
reed856e9d92015-09-30 12:21:45 -0700623 return nullptr;
624}
625
626#endif