blob: 4293194de3a49fae504616f8b98f40fd5d08765e [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2010 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.
reed@google.comac10a2d2010-12-22 21:39:39 +00006 */
7
reed@google.comac10a2d2010-12-22 21:39:39 +00008#include "SkGr.h"
egdaniel378092f2014-12-03 10:40:13 -08009
bsalomon76228632015-05-29 08:02:10 -070010#include "GrCaps.h"
robertphillipsea461502015-05-26 11:38:03 -070011#include "GrDrawContext.h"
egdaniel378092f2014-12-03 10:40:13 -080012#include "GrXferProcessor.h"
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +000013#include "SkColorFilter.h"
commit-bot@chromium.orgea476e12013-10-14 18:29:23 +000014#include "SkConfig8888.h"
bsalomonb4d40ef2015-07-15 10:12:16 -070015#include "SkCanvas.h"
krajcevski9c0e6292014-06-02 07:38:14 -070016#include "SkData.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080017#include "SkErrorInternals.h"
reed8b26b992015-05-07 15:36:17 -070018#include "SkGrPixelRef.h"
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000019#include "SkMessageBus.h"
20#include "SkPixelRef.h"
sugoi692135f2015-01-19 10:10:27 -080021#include "SkResourceCache.h"
krajcevski40a1e112014-08-05 14:13:36 -070022#include "SkTextureCompressor.h"
sugoi692135f2015-01-19 10:10:27 -080023#include "SkYUVPlanesCache.h"
joshualitt9bc39542015-08-12 12:57:54 -070024#include "effects/GrBicubicEffect.h"
krajcevskif461a8f2014-06-19 14:14:06 -070025#include "effects/GrDitherEffect.h"
egdaniel378092f2014-12-03 10:40:13 -080026#include "effects/GrPorterDuffXferProcessor.h"
sugoi518d83d2014-07-21 11:37:39 -070027#include "effects/GrYUVtoRGBEffect.h"
krajcevski9c0e6292014-06-02 07:38:14 -070028
krajcevski8c111f72014-06-02 13:51:34 -070029#ifndef SK_IGNORE_ETC1_SUPPORT
krajcevski99ffe242014-06-03 13:04:35 -070030# include "ktx.h"
krajcevski9c0e6292014-06-02 07:38:14 -070031# include "etc1.h"
32#endif
reed@google.comac10a2d2010-12-22 21:39:39 +000033
34/* Fill out buffer with the compressed format Ganesh expects from a colortable
35 based bitmap. [palette (colortable) + indices].
bsalomon@google.com5782d712011-01-21 21:03:59 +000036
37 At the moment Ganesh only supports 8bit version. If Ganesh allowed we others
reed@google.comac10a2d2010-12-22 21:39:39 +000038 we could detect that the colortable.count is <= 16, and then repack the
39 indices as nibbles to save RAM, but it would take more time (i.e. a lot
40 slower than memcpy), so skipping that for now.
bsalomon@google.com5782d712011-01-21 21:03:59 +000041
reed@google.comac10a2d2010-12-22 21:39:39 +000042 Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big
43 as the colortable.count says it is.
44 */
bsalomone79a2da2014-10-24 12:42:51 -070045static void build_index8_data(void* buffer, const SkBitmap& bitmap) {
reed0689d7b2014-06-14 05:30:20 -070046 SkASSERT(kIndex_8_SkColorType == bitmap.colorType());
bsalomon@google.com5782d712011-01-21 21:03:59 +000047
bsalomon@google.com7f4ad5a2013-05-07 19:36:43 +000048 SkAutoLockPixels alp(bitmap);
reed@google.comac10a2d2010-12-22 21:39:39 +000049 if (!bitmap.readyToDraw()) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000050 SkDEBUGFAIL("bitmap not ready to draw!");
reed@google.comac10a2d2010-12-22 21:39:39 +000051 return;
52 }
53
54 SkColorTable* ctable = bitmap.getColorTable();
55 char* dst = (char*)buffer;
bsalomon@google.com5782d712011-01-21 21:03:59 +000056
reed@google.com7111d462014-03-25 16:20:24 +000057 const int count = ctable->count();
58
59 SkDstPixelInfo dstPI;
60 dstPI.fColorType = kRGBA_8888_SkColorType;
61 dstPI.fAlphaType = kPremul_SkAlphaType;
62 dstPI.fPixels = buffer;
63 dstPI.fRowBytes = count * sizeof(SkPMColor);
64
65 SkSrcPixelInfo srcPI;
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +000066 srcPI.fColorType = kN32_SkColorType;
reed@google.com7111d462014-03-25 16:20:24 +000067 srcPI.fAlphaType = kPremul_SkAlphaType;
mtklein775b8192014-12-02 09:11:25 -080068 srcPI.fPixels = ctable->readColors();
reed@google.com7111d462014-03-25 16:20:24 +000069 srcPI.fRowBytes = count * sizeof(SkPMColor);
70
71 srcPI.convertPixelsTo(&dstPI, count, 1);
72
reed@google.comac10a2d2010-12-22 21:39:39 +000073 // always skip a full 256 number of entries, even if we memcpy'd fewer
bsalomond4cb9222014-08-11 14:19:09 -070074 dst += 256 * sizeof(GrColor);
reed@google.comac10a2d2010-12-22 21:39:39 +000075
scroggo@google.com0ba4bf42013-02-25 16:02:36 +000076 if ((unsigned)bitmap.width() == bitmap.rowBytes()) {
reed@google.comac10a2d2010-12-22 21:39:39 +000077 memcpy(dst, bitmap.getPixels(), bitmap.getSize());
78 } else {
79 // need to trim off the extra bytes per row
80 size_t width = bitmap.width();
81 size_t rowBytes = bitmap.rowBytes();
82 const char* src = (const char*)bitmap.getPixels();
83 for (int y = 0; y < bitmap.height(); y++) {
84 memcpy(dst, src, width);
85 src += rowBytes;
86 dst += width;
87 }
88 }
89}
90
91////////////////////////////////////////////////////////////////////////////////
92
bsalomonc59a1df2015-06-01 07:13:42 -070093struct Stretch {
94 enum Type {
95 kNone_Type,
96 kBilerp_Type,
97 kNearest_Type
98 } fType;
99 int fWidth;
100 int fHeight;
bsalomon37f9a262015-02-02 13:00:10 -0800101};
102
bsalomonc59a1df2015-06-01 07:13:42 -0700103static void get_stretch(const GrContext* ctx, int width, int height,
104 const GrTextureParams* params, Stretch* stretch) {
105 stretch->fType = Stretch::kNone_Type;
106 bool doStretch = false;
107 if (params && params->isTiled() && !ctx->caps()->npotTextureTileSupport() &&
108 (!SkIsPow2(width) || !SkIsPow2(height))) {
109 doStretch = true;
bsalomonb4d40ef2015-07-15 10:12:16 -0700110 stretch->fWidth = GrNextPow2(SkTMax(width, ctx->caps()->minTextureSize()));
111 stretch->fHeight = GrNextPow2(SkTMax(height, ctx->caps()->minTextureSize()));
112 } else if (width < ctx->caps()->minTextureSize() || height < ctx->caps()->minTextureSize()) {
bsalomonc59a1df2015-06-01 07:13:42 -0700113 // The small texture issues appear to be with tiling. Hence it seems ok to scale them
114 // up using the GPU. If issues persist we may need to CPU-stretch.
115 doStretch = true;
116 stretch->fWidth = SkTMax(width, ctx->caps()->minTextureSize());
117 stretch->fHeight = SkTMax(height, ctx->caps()->minTextureSize());
bsalomon37f9a262015-02-02 13:00:10 -0800118 }
bsalomonc59a1df2015-06-01 07:13:42 -0700119 if (doStretch) {
bsalomon0513c832015-06-01 10:22:48 -0700120 if (params) {
121 switch(params->filterMode()) {
122 case GrTextureParams::kNone_FilterMode:
123 stretch->fType = Stretch::kNearest_Type;
124 break;
125 case GrTextureParams::kBilerp_FilterMode:
126 case GrTextureParams::kMipMap_FilterMode:
127 stretch->fType = Stretch::kBilerp_Type;
128 break;
129 }
130 } else {
131 stretch->fType = Stretch::kBilerp_Type;
bsalomonc59a1df2015-06-01 07:13:42 -0700132 }
133 } else {
134 stretch->fWidth = -1;
135 stretch->fHeight = -1;
136 stretch->fType = Stretch::kNone_Type;
137 }
bsalomon37f9a262015-02-02 13:00:10 -0800138}
139
bsalomonc59a1df2015-06-01 07:13:42 -0700140static bool make_stretched_key(const GrUniqueKey& origKey, const Stretch& stretch,
bsalomon8718aaf2015-02-19 07:24:21 -0800141 GrUniqueKey* stretchedKey) {
bsalomonc59a1df2015-06-01 07:13:42 -0700142 if (origKey.isValid() && Stretch::kNone_Type != stretch.fType) {
143 uint32_t width = SkToU16(stretch.fWidth);
144 uint32_t height = SkToU16(stretch.fHeight);
bsalomon8718aaf2015-02-19 07:24:21 -0800145 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
reed8f343722015-08-13 13:32:39 -0700146 GrUniqueKey::Builder builder(stretchedKey, origKey, kDomain, 2);
bsalomonc59a1df2015-06-01 07:13:42 -0700147 builder[0] = stretch.fType;
148 builder[1] = width | (height << 16);
bsalomon37f9a262015-02-02 13:00:10 -0800149 builder.finish();
150 return true;
151 }
bsalomon23e619c2015-02-06 11:54:28 -0800152 SkASSERT(!stretchedKey->isValid());
bsalomon37f9a262015-02-02 13:00:10 -0800153 return false;
154}
155
reed8f343722015-08-13 13:32:39 -0700156static void make_unstretched_key(GrUniqueKey* key, uint32_t imageID,
157 U16CPU width, U16CPU height, SkIPoint origin) {
158 SkASSERT((uint16_t)width == width);
159 SkASSERT((uint16_t)height == height);
bsalomon@google.com0797c2c2012-12-20 15:13:01 +0000160
bsalomon8718aaf2015-02-19 07:24:21 -0800161 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
162 GrUniqueKey::Builder builder(key, kDomain, 4);
reed8f343722015-08-13 13:32:39 -0700163 builder[0] = imageID;
bsalomon24db3b12015-01-23 04:24:04 -0800164 builder[1] = origin.fX;
165 builder[2] = origin.fY;
166 builder[3] = width | (height << 16);
bsalomon23e619c2015-02-06 11:54:28 -0800167}
bsalomon37f9a262015-02-02 13:00:10 -0800168
reed8f343722015-08-13 13:32:39 -0700169void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID,
170 U16CPU width, U16CPU height, SkIPoint origin,
171 const GrCaps& caps, SkImageUsageType usage) {
172 const Stretch::Type stretches[] = {
173 Stretch::kNone_Type, // kUntiled_SkImageUsageType
174 Stretch::kNearest_Type, // kTiled_Unfiltered_SkImageUsageType
175 Stretch::kBilerp_Type, // kTiled_Filtered_SkImageUsageType
176 };
177
178 const bool isPow2 = SkIsPow2(width) && SkIsPow2(height);
179 const bool needToStretch = !isPow2 &&
180 usage != kUntiled_SkImageUsageType &&
181 !caps.npotTextureTileSupport();
182
183 if (needToStretch) {
184 GrUniqueKey tmpKey;
185 make_unstretched_key(&tmpKey, imageID, width, height, origin);
186
187 Stretch stretch;
188 stretch.fType = stretches[usage];
189 stretch.fWidth = SkNextPow2(width);
190 stretch.fHeight = SkNextPow2(height);
191 if (!make_stretched_key(tmpKey, stretch, key)) {
192 goto UNSTRETCHED;
193 }
194 } else {
195 UNSTRETCHED:
196 make_unstretched_key(key, imageID, width, height, origin);
197 }
198}
199
200static void make_unstretched_key(const SkBitmap& bitmap, GrUniqueKey* key) {
201 make_unstretched_key(key, bitmap.getGenerationID(), bitmap.width(), bitmap.height(),
202 bitmap.pixelRefOrigin());
203}
204
bsalomon23e619c2015-02-06 11:54:28 -0800205static void make_bitmap_keys(const SkBitmap& bitmap,
bsalomonc59a1df2015-06-01 07:13:42 -0700206 const Stretch& stretch,
bsalomon8718aaf2015-02-19 07:24:21 -0800207 GrUniqueKey* key,
208 GrUniqueKey* stretchedKey) {
bsalomon23e619c2015-02-06 11:54:28 -0800209 make_unstretched_key(bitmap, key);
bsalomonc59a1df2015-06-01 07:13:42 -0700210 if (Stretch::kNone_Type != stretch.fType) {
bsalomon23e619c2015-02-06 11:54:28 -0800211 make_stretched_key(*key, stretch, stretchedKey);
bsalomon37f9a262015-02-02 13:00:10 -0800212 }
bsalomon@google.com0797c2c2012-12-20 15:13:01 +0000213}
214
bsalomonf2703d82014-10-28 14:33:06 -0700215static void generate_bitmap_texture_desc(const SkBitmap& bitmap, GrSurfaceDesc* desc) {
216 desc->fFlags = kNone_GrSurfaceFlags;
bsalomon@google.com0797c2c2012-12-20 15:13:01 +0000217 desc->fWidth = bitmap.width();
218 desc->fHeight = bitmap.height();
commit-bot@chromium.org3adcc342014-04-23 19:18:09 +0000219 desc->fConfig = SkImageInfo2GrPixelConfig(bitmap.info());
bsalomon@google.com0797c2c2012-12-20 15:13:01 +0000220 desc->fSampleCnt = 0;
221}
222
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000223namespace {
224
225// When the SkPixelRef genID changes, invalidate a corresponding GrResource described by key.
bsalomon23e619c2015-02-06 11:54:28 -0800226class BitmapInvalidator : public SkPixelRef::GenIDChangeListener {
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000227public:
bsalomon8718aaf2015-02-19 07:24:21 -0800228 explicit BitmapInvalidator(const GrUniqueKey& key) : fMsg(key) {}
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000229private:
bsalomon8718aaf2015-02-19 07:24:21 -0800230 GrUniqueKeyInvalidatedMessage fMsg;
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000231
mtklein36352bf2015-03-25 18:17:31 -0700232 void onChange() override {
bsalomon8718aaf2015-02-19 07:24:21 -0800233 SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000234 }
235};
236
237} // namespace
238
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000239
bsalomon37f9a262015-02-02 13:00:10 -0800240static GrTexture* create_texture_for_bmp(GrContext* ctx,
bsalomon8718aaf2015-02-19 07:24:21 -0800241 const GrUniqueKey& optionalKey,
bsalomonf2703d82014-10-28 14:33:06 -0700242 GrSurfaceDesc desc,
bsalomon23e619c2015-02-06 11:54:28 -0800243 SkPixelRef* pixelRefForInvalidationNotification,
sugoi0249ec22014-09-09 08:12:34 -0700244 const void* pixels,
245 size_t rowBytes) {
bsalomond309e7a2015-04-30 14:18:54 -0700246 GrTexture* result = ctx->textureProvider()->createTexture(desc, true, pixels, rowBytes);
bsalomond0423582015-02-06 08:49:24 -0800247 if (result && optionalKey.isValid()) {
halcanary385fe4d2015-08-26 13:07:48 -0700248 BitmapInvalidator* listener = new BitmapInvalidator(optionalKey);
bsalomon23e619c2015-02-06 11:54:28 -0800249 pixelRefForInvalidationNotification->addGenIDChangeListener(listener);
bsalomond309e7a2015-04-30 14:18:54 -0700250 ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, result);
sugoi0249ec22014-09-09 08:12:34 -0700251 }
252 return result;
253}
254
bsalomonc59a1df2015-06-01 07:13:42 -0700255// creates a new texture that is the input texture scaled up. If optionalKey is valid it will be
256// set on the new texture. stretch controls whether the scaling is done using nearest or bilerp
257// filtering and the size to stretch the texture to.
258GrTexture* stretch_texture(GrTexture* inputTexture, const Stretch& stretch,
259 SkPixelRef* pixelRef,
260 const GrUniqueKey& optionalKey) {
261 SkASSERT(Stretch::kNone_Type != stretch.fType);
bsalomon37f9a262015-02-02 13:00:10 -0800262
263 GrContext* context = inputTexture->getContext();
264 SkASSERT(context);
bsalomon76228632015-05-29 08:02:10 -0700265 const GrCaps* caps = context->caps();
bsalomon37f9a262015-02-02 13:00:10 -0800266
267 // Either it's a cache miss or the original wasn't cached to begin with.
268 GrSurfaceDesc rtDesc = inputTexture->desc();
bsalomon6bc1b5f2015-02-23 09:06:38 -0800269 rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag;
bsalomonc59a1df2015-06-01 07:13:42 -0700270 rtDesc.fWidth = stretch.fWidth;
271 rtDesc.fHeight = stretch.fHeight;
bsalomon37f9a262015-02-02 13:00:10 -0800272 rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig);
273
274 // If the config isn't renderable try converting to either A8 or an 32 bit config. Otherwise,
275 // fail.
bsalomon76228632015-05-29 08:02:10 -0700276 if (!caps->isConfigRenderable(rtDesc.fConfig, false)) {
bsalomon37f9a262015-02-02 13:00:10 -0800277 if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) {
bsalomon76228632015-05-29 08:02:10 -0700278 if (caps->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
bsalomon37f9a262015-02-02 13:00:10 -0800279 rtDesc.fConfig = kAlpha_8_GrPixelConfig;
bsalomon76228632015-05-29 08:02:10 -0700280 } else if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
bsalomon37f9a262015-02-02 13:00:10 -0800281 rtDesc.fConfig = kSkia8888_GrPixelConfig;
282 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700283 return nullptr;
bsalomon37f9a262015-02-02 13:00:10 -0800284 }
285 } else if (kRGB_GrColorComponentFlags ==
286 (kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) {
bsalomon76228632015-05-29 08:02:10 -0700287 if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
bsalomon37f9a262015-02-02 13:00:10 -0800288 rtDesc.fConfig = kSkia8888_GrPixelConfig;
289 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700290 return nullptr;
bsalomon37f9a262015-02-02 13:00:10 -0800291 }
292 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700293 return nullptr;
bsalomon37f9a262015-02-02 13:00:10 -0800294 }
295 }
296
halcanary96fcdcc2015-08-27 07:41:13 -0700297 GrTexture* stretched = create_texture_for_bmp(context, optionalKey, rtDesc, pixelRef, nullptr, 0);
bsalomon37f9a262015-02-02 13:00:10 -0800298
bsalomon23e619c2015-02-06 11:54:28 -0800299 if (!stretched) {
halcanary96fcdcc2015-08-27 07:41:13 -0700300 return nullptr;
bsalomon37f9a262015-02-02 13:00:10 -0800301 }
302 GrPaint paint;
303
304 // If filtering is not desired then we want to ensure all texels in the resampled image are
305 // copies of texels from the original.
306 GrTextureParams params(SkShader::kClamp_TileMode,
bsalomonc59a1df2015-06-01 07:13:42 -0700307 Stretch::kBilerp_Type == stretch.fType ?
308 GrTextureParams::kBilerp_FilterMode :
309 GrTextureParams::kNone_FilterMode);
bsalomon37f9a262015-02-02 13:00:10 -0800310 paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params);
311
312 SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
313 SkRect localRect = SkRect::MakeWH(1.f, 1.f);
314
robertphillipsea461502015-05-26 11:38:03 -0700315 GrDrawContext* drawContext = context->drawContext();
316 if (!drawContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700317 return nullptr;
robertphillipsea461502015-05-26 11:38:03 -0700318 }
319
320 drawContext->drawNonAARectToRect(stretched->asRenderTarget(), GrClip::WideOpen(), paint,
321 SkMatrix::I(), rect, localRect);
bsalomon37f9a262015-02-02 13:00:10 -0800322
bsalomon23e619c2015-02-06 11:54:28 -0800323 return stretched;
bsalomon37f9a262015-02-02 13:00:10 -0800324}
325
krajcevski8c111f72014-06-02 13:51:34 -0700326#ifndef SK_IGNORE_ETC1_SUPPORT
bsalomon8718aaf2015-02-19 07:24:21 -0800327static GrTexture *load_etc1_texture(GrContext* ctx, const GrUniqueKey& optionalKey,
bsalomonf2703d82014-10-28 14:33:06 -0700328 const SkBitmap &bm, GrSurfaceDesc desc) {
krajcevski99ffe242014-06-03 13:04:35 -0700329 SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData());
krajcevski9c0e6292014-06-02 07:38:14 -0700330
331 // Is this even encoded data?
halcanary96fcdcc2015-08-27 07:41:13 -0700332 if (nullptr == data) {
333 return nullptr;
krajcevski9c0e6292014-06-02 07:38:14 -0700334 }
335
336 // Is this a valid PKM encoded data?
337 const uint8_t *bytes = data->bytes();
krajcevski99ffe242014-06-03 13:04:35 -0700338 if (etc1_pkm_is_valid(bytes)) {
339 uint32_t encodedWidth = etc1_pkm_get_width(bytes);
340 uint32_t encodedHeight = etc1_pkm_get_height(bytes);
341
342 // Does the data match the dimensions of the bitmap? If not,
343 // then we don't know how to scale the image to match it...
344 if (encodedWidth != static_cast<uint32_t>(bm.width()) ||
345 encodedHeight != static_cast<uint32_t>(bm.height())) {
halcanary96fcdcc2015-08-27 07:41:13 -0700346 return nullptr;
krajcevski99ffe242014-06-03 13:04:35 -0700347 }
348
349 // Everything seems good... skip ahead to the data.
350 bytes += ETC_PKM_HEADER_SIZE;
351 desc.fConfig = kETC1_GrPixelConfig;
352 } else if (SkKTXFile::is_ktx(bytes)) {
353 SkKTXFile ktx(data);
354
355 // Is it actually an ETC1 texture?
krajcevski40a1e112014-08-05 14:13:36 -0700356 if (!ktx.isCompressedFormat(SkTextureCompressor::kETC1_Format)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700357 return nullptr;
krajcevski99ffe242014-06-03 13:04:35 -0700358 }
359
360 // Does the data match the dimensions of the bitmap? If not,
361 // then we don't know how to scale the image to match it...
362 if (ktx.width() != bm.width() || ktx.height() != bm.height()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700363 return nullptr;
mtklein775b8192014-12-02 09:11:25 -0800364 }
krajcevski99ffe242014-06-03 13:04:35 -0700365
366 bytes = ktx.pixelData();
367 desc.fConfig = kETC1_GrPixelConfig;
368 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700369 return nullptr;
krajcevski9c0e6292014-06-02 07:38:14 -0700370 }
371
bsalomon23e619c2015-02-06 11:54:28 -0800372 return create_texture_for_bmp(ctx, optionalKey, desc, bm.pixelRef(), bytes, 0);
krajcevski9c0e6292014-06-02 07:38:14 -0700373}
krajcevski8c111f72014-06-02 13:51:34 -0700374#endif // SK_IGNORE_ETC1_SUPPORT
krajcevski9c0e6292014-06-02 07:38:14 -0700375
bsalomon8718aaf2015-02-19 07:24:21 -0800376static GrTexture* load_yuv_texture(GrContext* ctx, const GrUniqueKey& optionalKey,
bsalomonf2703d82014-10-28 14:33:06 -0700377 const SkBitmap& bm, const GrSurfaceDesc& desc) {
sugoiff58e462014-10-16 05:19:31 -0700378 // Subsets are not supported, the whole pixelRef is loaded when using YUV decoding
sugoi518d83d2014-07-21 11:37:39 -0700379 SkPixelRef* pixelRef = bm.pixelRef();
halcanary96fcdcc2015-08-27 07:41:13 -0700380 if ((nullptr == pixelRef) ||
sugoi692135f2015-01-19 10:10:27 -0800381 (pixelRef->info().width() != bm.info().width()) ||
382 (pixelRef->info().height() != bm.info().height())) {
halcanary96fcdcc2015-08-27 07:41:13 -0700383 return nullptr;
sugoi518d83d2014-07-21 11:37:39 -0700384 }
385
sugoiba18f912015-02-04 10:53:03 -0800386 const bool useCache = optionalKey.isValid();
sugoi692135f2015-01-19 10:10:27 -0800387 SkYUVPlanesCache::Info yuvInfo;
sugoiba18f912015-02-04 10:53:03 -0800388 SkAutoTUnref<SkCachedData> cachedData;
389 SkAutoMalloc storage;
390 if (useCache) {
391 cachedData.reset(SkYUVPlanesCache::FindAndRef(pixelRef->getGenerationID(), &yuvInfo));
392 }
sugoi692135f2015-01-19 10:10:27 -0800393
sugoi518d83d2014-07-21 11:37:39 -0700394 void* planes[3];
sugoiba18f912015-02-04 10:53:03 -0800395 if (cachedData.get()) {
sugoi692135f2015-01-19 10:10:27 -0800396 planes[0] = (void*)cachedData->data();
397 planes[1] = (uint8_t*)planes[0] + yuvInfo.fSizeInMemory[0];
398 planes[2] = (uint8_t*)planes[1] + yuvInfo.fSizeInMemory[1];
399 } else {
400 // Fetch yuv plane sizes for memory allocation. Here, width and height can be
401 // rounded up to JPEG block size and be larger than the image's width and height.
halcanary96fcdcc2015-08-27 07:41:13 -0700402 if (!pixelRef->getYUV8Planes(yuvInfo.fSize, nullptr, nullptr, nullptr)) {
403 return nullptr;
sugoi692135f2015-01-19 10:10:27 -0800404 }
sugoi518d83d2014-07-21 11:37:39 -0700405
sugoi692135f2015-01-19 10:10:27 -0800406 // Allocate the memory for YUV
407 size_t totalSize(0);
408 for (int i = 0; i < 3; ++i) {
409 yuvInfo.fRowBytes[i] = yuvInfo.fSize[i].fWidth;
410 yuvInfo.fSizeInMemory[i] = yuvInfo.fRowBytes[i] * yuvInfo.fSize[i].fHeight;
411 totalSize += yuvInfo.fSizeInMemory[i];
412 }
sugoiba18f912015-02-04 10:53:03 -0800413 if (useCache) {
414 cachedData.reset(SkResourceCache::NewCachedData(totalSize));
415 planes[0] = cachedData->writable_data();
416 } else {
417 storage.reset(totalSize);
418 planes[0] = storage.get();
419 }
sugoi692135f2015-01-19 10:10:27 -0800420 planes[1] = (uint8_t*)planes[0] + yuvInfo.fSizeInMemory[0];
421 planes[2] = (uint8_t*)planes[1] + yuvInfo.fSizeInMemory[1];
rileyaabaef862014-09-12 17:45:58 -0700422
sugoi692135f2015-01-19 10:10:27 -0800423 // Get the YUV planes and update plane sizes to actual image size
424 if (!pixelRef->getYUV8Planes(yuvInfo.fSize, planes, yuvInfo.fRowBytes,
425 &yuvInfo.fColorSpace)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700426 return nullptr;
sugoi692135f2015-01-19 10:10:27 -0800427 }
428
sugoiba18f912015-02-04 10:53:03 -0800429 if (useCache) {
430 // Decoding is done, cache the resulting YUV planes
431 SkYUVPlanesCache::Add(pixelRef->getGenerationID(), cachedData, &yuvInfo);
432 }
sugoi518d83d2014-07-21 11:37:39 -0700433 }
434
bsalomonf2703d82014-10-28 14:33:06 -0700435 GrSurfaceDesc yuvDesc;
sugoi518d83d2014-07-21 11:37:39 -0700436 yuvDesc.fConfig = kAlpha_8_GrPixelConfig;
bsalomone3059732014-10-14 11:47:22 -0700437 SkAutoTUnref<GrTexture> yuvTextures[3];
sugoi518d83d2014-07-21 11:37:39 -0700438 for (int i = 0; i < 3; ++i) {
sugoi692135f2015-01-19 10:10:27 -0800439 yuvDesc.fWidth = yuvInfo.fSize[i].fWidth;
440 yuvDesc.fHeight = yuvInfo.fSize[i].fHeight;
sugoi4ab3dbb2015-03-06 05:16:52 -0800441 bool needsExactTexture =
442 (yuvDesc.fWidth != yuvInfo.fSize[0].fWidth) ||
443 (yuvDesc.fHeight != yuvInfo.fSize[0].fHeight);
bsalomoneae62002015-07-31 13:59:30 -0700444 if (needsExactTexture) {
445 yuvTextures[i].reset(ctx->textureProvider()->createTexture(yuvDesc, true));
446 } else {
447 yuvTextures[i].reset(ctx->textureProvider()->createApproxTexture(yuvDesc));
448 }
bsalomone3059732014-10-14 11:47:22 -0700449 if (!yuvTextures[i] ||
450 !yuvTextures[i]->writePixels(0, 0, yuvDesc.fWidth, yuvDesc.fHeight,
sugoi692135f2015-01-19 10:10:27 -0800451 yuvDesc.fConfig, planes[i], yuvInfo.fRowBytes[i])) {
halcanary96fcdcc2015-08-27 07:41:13 -0700452 return nullptr;
sugoi518d83d2014-07-21 11:37:39 -0700453 }
454 }
455
bsalomonf2703d82014-10-28 14:33:06 -0700456 GrSurfaceDesc rtDesc = desc;
bsalomon6bc1b5f2015-02-23 09:06:38 -0800457 rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag;
sugoi518d83d2014-07-21 11:37:39 -0700458
halcanary96fcdcc2015-08-27 07:41:13 -0700459 GrTexture* result = create_texture_for_bmp(ctx, optionalKey, rtDesc, pixelRef, nullptr, 0);
bsalomon37f9a262015-02-02 13:00:10 -0800460 if (!result) {
halcanary96fcdcc2015-08-27 07:41:13 -0700461 return nullptr;
sugoi518d83d2014-07-21 11:37:39 -0700462 }
463
bsalomon37f9a262015-02-02 13:00:10 -0800464 GrRenderTarget* renderTarget = result->asRenderTarget();
465 SkASSERT(renderTarget);
466
bsalomon37f9a262015-02-02 13:00:10 -0800467 GrPaint paint;
joshualitt2cdec312015-07-09 07:31:31 -0700468 SkAutoTUnref<GrFragmentProcessor>
469 yuvToRgbProcessor(GrYUVtoRGBEffect::Create(paint.getProcessorDataManager(), yuvTextures[0],
470 yuvTextures[1], yuvTextures[2],
471 yuvInfo.fSize, yuvInfo.fColorSpace));
bsalomonac856c92015-08-27 06:30:17 -0700472 paint.addColorFragmentProcessor(yuvToRgbProcessor);
bsalomon37f9a262015-02-02 13:00:10 -0800473 SkRect r = SkRect::MakeWH(SkIntToScalar(yuvInfo.fSize[0].fWidth),
474 SkIntToScalar(yuvInfo.fSize[0].fHeight));
joshualitt570d2f82015-02-25 13:19:48 -0800475
robertphillipsea461502015-05-26 11:38:03 -0700476 GrDrawContext* drawContext = ctx->drawContext();
477 if (!drawContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700478 return nullptr;
robertphillipsea461502015-05-26 11:38:03 -0700479 }
480
481 drawContext->drawRect(renderTarget, GrClip::WideOpen(), paint, SkMatrix::I(), r);
bsalomon37f9a262015-02-02 13:00:10 -0800482
sugoi518d83d2014-07-21 11:37:39 -0700483 return result;
484}
485
bsalomon37f9a262015-02-02 13:00:10 -0800486static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx,
487 const SkBitmap& origBitmap,
bsalomon8718aaf2015-02-19 07:24:21 -0800488 const GrUniqueKey& optionalKey) {
bsalomonb4d40ef2015-07-15 10:12:16 -0700489 if (origBitmap.width() < ctx->caps()->minTextureSize() ||
490 origBitmap.height() < ctx->caps()->minTextureSize()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700491 return nullptr;
bsalomonb4d40ef2015-07-15 10:12:16 -0700492 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000493 SkBitmap tmpBitmap;
494
495 const SkBitmap* bitmap = &origBitmap;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000496
bsalomonf2703d82014-10-28 14:33:06 -0700497 GrSurfaceDesc desc;
bsalomon@google.com0797c2c2012-12-20 15:13:01 +0000498 generate_bitmap_texture_desc(*bitmap, &desc);
bsalomon76228632015-05-29 08:02:10 -0700499 const GrCaps* caps = ctx->caps();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000500
reed0689d7b2014-06-14 05:30:20 -0700501 if (kIndex_8_SkColorType == bitmap->colorType()) {
bsalomon76228632015-05-29 08:02:10 -0700502 if (caps->isConfigTexturable(kIndex_8_GrPixelConfig)) {
bsalomond4cb9222014-08-11 14:19:09 -0700503 size_t imageSize = GrCompressedFormatDataSize(kIndex_8_GrPixelConfig,
504 bitmap->width(), bitmap->height());
505 SkAutoMalloc storage(imageSize);
bsalomone79a2da2014-10-24 12:42:51 -0700506 build_index8_data(storage.get(), origBitmap);
reed@google.comac10a2d2010-12-22 21:39:39 +0000507
508 // our compressed data will be trimmed, so pass width() for its
509 // "rowBytes", since they are the same now.
bsalomon23e619c2015-02-06 11:54:28 -0800510 return create_texture_for_bmp(ctx, optionalKey, desc, origBitmap.pixelRef(),
511 storage.get(), bitmap->width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000512 } else {
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000513 origBitmap.copyTo(&tmpBitmap, kN32_SkColorType);
reed@google.comac10a2d2010-12-22 21:39:39 +0000514 // now bitmap points to our temp, which has been promoted to 32bits
515 bitmap = &tmpBitmap;
commit-bot@chromium.org3adcc342014-04-23 19:18:09 +0000516 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap->info());
reed@google.comac10a2d2010-12-22 21:39:39 +0000517 }
krajcevski309e8692014-06-02 08:02:45 -0700518 }
krajcevski9c0e6292014-06-02 07:38:14 -0700519
520 // Is this an ETC1 encoded texture?
krajcevski8c111f72014-06-02 13:51:34 -0700521#ifndef SK_IGNORE_ETC1_SUPPORT
bsalomond2a6f4e2015-02-04 10:55:54 -0800522 // Make sure that the underlying device supports ETC1 textures before we go ahead
523 // and check the data.
bsalomon76228632015-05-29 08:02:10 -0700524 else if (caps->isConfigTexturable(kETC1_GrPixelConfig)
bsalomond2a6f4e2015-02-04 10:55:54 -0800525 // If the bitmap had compressed data and was then uncompressed, it'll still return
526 // compressed data on 'refEncodedData' and upload it. Probably not good, since if
527 // the bitmap has available pixels, then they might not be what the decompressed
528 // data is.
529 && !(bitmap->readyToDraw())) {
bsalomon37f9a262015-02-02 13:00:10 -0800530 GrTexture *texture = load_etc1_texture(ctx, optionalKey, *bitmap, desc);
bsalomon49f085d2014-09-05 13:34:00 -0700531 if (texture) {
krajcevski9c0e6292014-06-02 07:38:14 -0700532 return texture;
533 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000534 }
krajcevski8c111f72014-06-02 13:51:34 -0700535#endif // SK_IGNORE_ETC1_SUPPORT
reed@google.comac10a2d2010-12-22 21:39:39 +0000536
bsalomond2a6f4e2015-02-04 10:55:54 -0800537 GrTexture *texture = load_yuv_texture(ctx, optionalKey, *bitmap, desc);
538 if (texture) {
539 return texture;
sugoi518d83d2014-07-21 11:37:39 -0700540 }
bsalomond2a6f4e2015-02-04 10:55:54 -0800541
bsalomon@google.com7f4ad5a2013-05-07 19:36:43 +0000542 SkAutoLockPixels alp(*bitmap);
543 if (!bitmap->readyToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700544 return nullptr;
bsalomon@google.com7f4ad5a2013-05-07 19:36:43 +0000545 }
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000546
bsalomon23e619c2015-02-06 11:54:28 -0800547 return create_texture_for_bmp(ctx, optionalKey, desc, origBitmap.pixelRef(),
548 bitmap->getPixels(), bitmap->rowBytes());
bsalomon37f9a262015-02-02 13:00:10 -0800549}
550
bsalomonb4d40ef2015-07-15 10:12:16 -0700551static SkBitmap stretch_on_cpu(const SkBitmap& bmp, const Stretch& stretch) {
552 SkBitmap stretched;
553 stretched.allocN32Pixels(stretch.fWidth, stretch.fHeight);
554 SkCanvas canvas(stretched);
555 SkPaint paint;
556 switch (stretch.fType) {
557 case Stretch::kNearest_Type:
558 paint.setFilterQuality(kNone_SkFilterQuality);
559 break;
560 case Stretch::kBilerp_Type:
561 paint.setFilterQuality(kLow_SkFilterQuality);
562 break;
563 case Stretch::kNone_Type:
564 SkDEBUGFAIL("Shouldn't get here.");
565 break;
566 }
567 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(stretch.fWidth), SkIntToScalar(stretch.fHeight));
reed84984ef2015-07-17 07:09:43 -0700568 canvas.drawBitmapRect(bmp, dstRect, &paint);
bsalomonb4d40ef2015-07-15 10:12:16 -0700569 return stretched;
570}
571
bsalomon37f9a262015-02-02 13:00:10 -0800572static GrTexture* create_bitmap_texture(GrContext* ctx,
573 const SkBitmap& bmp,
bsalomonc59a1df2015-06-01 07:13:42 -0700574 const Stretch& stretch,
bsalomon8718aaf2015-02-19 07:24:21 -0800575 const GrUniqueKey& unstretchedKey,
576 const GrUniqueKey& stretchedKey) {
bsalomonc59a1df2015-06-01 07:13:42 -0700577 if (Stretch::kNone_Type != stretch.fType) {
bsalomon37f9a262015-02-02 13:00:10 -0800578 SkAutoTUnref<GrTexture> unstretched;
579 // Check if we have the unstretched version in the cache, if not create it.
580 if (unstretchedKey.isValid()) {
bsalomond309e7a2015-04-30 14:18:54 -0700581 unstretched.reset(ctx->textureProvider()->findAndRefTextureByUniqueKey(unstretchedKey));
bsalomon37f9a262015-02-02 13:00:10 -0800582 }
583 if (!unstretched) {
584 unstretched.reset(create_unstretched_bitmap_texture(ctx, bmp, unstretchedKey));
585 if (!unstretched) {
bsalomonb4d40ef2015-07-15 10:12:16 -0700586 // We might not have been able to create a unstrecthed texture because it is smaller
587 // than the min texture size. In that case do cpu stretching.
588 SkBitmap stretchedBmp = stretch_on_cpu(bmp, stretch);
589 return create_unstretched_bitmap_texture(ctx, stretchedBmp, stretchedKey);
bsalomon37f9a262015-02-02 13:00:10 -0800590 }
591 }
bsalomonb4d40ef2015-07-15 10:12:16 -0700592 return stretch_texture(unstretched, stretch, bmp.pixelRef(), stretchedKey);
bsalomon37f9a262015-02-02 13:00:10 -0800593 }
bsalomon37f9a262015-02-02 13:00:10 -0800594 return create_unstretched_bitmap_texture(ctx, bmp, unstretchedKey);
reed@google.comac10a2d2010-12-22 21:39:39 +0000595}
596
bsalomon@google.com0797c2c2012-12-20 15:13:01 +0000597bool GrIsBitmapInCache(const GrContext* ctx,
598 const SkBitmap& bitmap,
599 const GrTextureParams* params) {
bsalomonc59a1df2015-06-01 07:13:42 -0700600 Stretch stretch;
601 get_stretch(ctx, bitmap.width(), bitmap.height(), params, &stretch);
bsalomon88425562015-02-04 09:12:46 -0800602
603 // Handle the case where the bitmap is explicitly texture backed.
604 GrTexture* texture = bitmap.getTexture();
605 if (texture) {
bsalomonc59a1df2015-06-01 07:13:42 -0700606 if (Stretch::kNone_Type == stretch.fType) {
bsalomon88425562015-02-04 09:12:46 -0800607 return true;
608 }
609 // No keys for volatile bitmaps.
610 if (bitmap.isVolatile()) {
611 return false;
612 }
bsalomon8718aaf2015-02-19 07:24:21 -0800613 const GrUniqueKey& key = texture->getUniqueKey();
bsalomon88425562015-02-04 09:12:46 -0800614 if (!key.isValid()) {
615 return false;
616 }
bsalomon8718aaf2015-02-19 07:24:21 -0800617 GrUniqueKey stretchedKey;
bsalomon23e619c2015-02-06 11:54:28 -0800618 make_stretched_key(key, stretch, &stretchedKey);
bsalomond309e7a2015-04-30 14:18:54 -0700619 return ctx->textureProvider()->existsTextureWithUniqueKey(stretchedKey);
bsalomon9ed7f572014-12-19 12:26:37 -0800620 }
621
bsalomon37f9a262015-02-02 13:00:10 -0800622 // We don't cache volatile bitmaps
623 if (bitmap.isVolatile()) {
624 return false;
625 }
626
bsalomon8718aaf2015-02-19 07:24:21 -0800627 GrUniqueKey key, stretchedKey;
bsalomon23e619c2015-02-06 11:54:28 -0800628 make_bitmap_keys(bitmap, stretch, &key, &stretchedKey);
bsalomond309e7a2015-04-30 14:18:54 -0700629 return ctx->textureProvider()->existsTextureWithUniqueKey(
bsalomonc59a1df2015-06-01 07:13:42 -0700630 (Stretch::kNone_Type == stretch.fType) ? key : stretchedKey);
bsalomon@google.com0797c2c2012-12-20 15:13:01 +0000631}
reed@google.comac10a2d2010-12-22 21:39:39 +0000632
bsalomonbcf0a522014-10-08 08:40:09 -0700633GrTexture* GrRefCachedBitmapTexture(GrContext* ctx,
634 const SkBitmap& bitmap,
635 const GrTextureParams* params) {
rileya@google.com24f3ad12012-07-18 21:47:40 +0000636
bsalomonc59a1df2015-06-01 07:13:42 -0700637 Stretch stretch;
638 get_stretch(ctx, bitmap.width(), bitmap.height(), params, &stretch);
bsalomon88425562015-02-04 09:12:46 -0800639
640 GrTexture* result = bitmap.getTexture();
641 if (result) {
bsalomonc59a1df2015-06-01 07:13:42 -0700642 if (Stretch::kNone_Type == stretch.fType) {
bsalomon88425562015-02-04 09:12:46 -0800643 return SkRef(result);
644 }
bsalomon8718aaf2015-02-19 07:24:21 -0800645 GrUniqueKey stretchedKey;
bsalomon88425562015-02-04 09:12:46 -0800646 // Don't create a key for the resized version if the bmp is volatile.
647 if (!bitmap.isVolatile()) {
bsalomon8718aaf2015-02-19 07:24:21 -0800648 const GrUniqueKey& key = result->getUniqueKey();
bsalomon88425562015-02-04 09:12:46 -0800649 if (key.isValid()) {
bsalomon23e619c2015-02-06 11:54:28 -0800650 make_stretched_key(key, stretch, &stretchedKey);
bsalomond309e7a2015-04-30 14:18:54 -0700651 GrTexture* stretched =
652 ctx->textureProvider()->findAndRefTextureByUniqueKey(stretchedKey);
bsalomon88425562015-02-04 09:12:46 -0800653 if (stretched) {
654 return stretched;
655 }
656 }
657 }
bsalomonc59a1df2015-06-01 07:13:42 -0700658 return stretch_texture(result, stretch, bitmap.pixelRef(), stretchedKey);
bsalomon88425562015-02-04 09:12:46 -0800659 }
660
bsalomon8718aaf2015-02-19 07:24:21 -0800661 GrUniqueKey key, resizedKey;
bsalomon@google.com0797c2c2012-12-20 15:13:01 +0000662
bsalomon37f9a262015-02-02 13:00:10 -0800663 if (!bitmap.isVolatile()) {
bsalomon@google.com0797c2c2012-12-20 15:13:01 +0000664 // If the bitmap isn't changing try to find a cached copy first.
bsalomon23e619c2015-02-06 11:54:28 -0800665 make_bitmap_keys(bitmap, stretch, &key, &resizedKey);
bsalomon@google.com0797c2c2012-12-20 15:13:01 +0000666
bsalomond309e7a2015-04-30 14:18:54 -0700667 result = ctx->textureProvider()->findAndRefTextureByUniqueKey(
668 resizedKey.isValid() ? resizedKey : key);
bsalomon37f9a262015-02-02 13:00:10 -0800669 if (result) {
670 return result;
671 }
672 }
bsalomone137db82015-01-31 20:10:56 -0800673
bsalomon37f9a262015-02-02 13:00:10 -0800674 result = create_bitmap_texture(ctx, bitmap, stretch, key, resizedKey);
675 if (result) {
676 return result;
677 }
bsalomone137db82015-01-31 20:10:56 -0800678
joshualitt5f5a8d72015-02-25 14:09:45 -0800679 SkErrorInternals::SetError( kInternalError_SkError,
680 "---- failed to create texture for cache [%d %d]\n",
681 bitmap.width(), bitmap.height());
bsalomon37f9a262015-02-02 13:00:10 -0800682
halcanary96fcdcc2015-08-27 07:41:13 -0700683 return nullptr;
rileya@google.com24f3ad12012-07-18 21:47:40 +0000684}
reed8f343722015-08-13 13:32:39 -0700685
686// TODO: make this be the canonical signature, and turn the version that takes GrTextureParams*
687// into a wrapper that contains the inverse of these tables.
688GrTexture* GrRefCachedBitmapTexture(GrContext* ctx,
689 const SkBitmap& bitmap,
690 SkImageUsageType usage) {
691 // Just need a params that will trigger the correct cache key / etc, since the usage doesn't
692 // tell us the specifics about filter level or specific tiling.
693
694 const SkShader::TileMode tiles[] = {
695 SkShader::kClamp_TileMode, // kUntiled_SkImageUsageType
696 SkShader::kRepeat_TileMode, // kTiled_Unfiltered_SkImageUsageType
697 SkShader::kRepeat_TileMode, // kTiled_Filtered_SkImageUsageType
698 };
699
700 const GrTextureParams::FilterMode filters[] = {
701 GrTextureParams::kNone_FilterMode, // kUntiled_SkImageUsageType
702 GrTextureParams::kNone_FilterMode, // kTiled_Unfiltered_SkImageUsageType
703 GrTextureParams::kBilerp_FilterMode, // kTiled_Filtered_SkImageUsageType
704 };
705
706 GrTextureParams params(tiles[usage], filters[usage]);
707 return GrRefCachedBitmapTexture(ctx, bitmap, &params);
708}
709
rileya@google.com24f3ad12012-07-18 21:47:40 +0000710///////////////////////////////////////////////////////////////////////////////
711
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000712// alphatype is ignore for now, but if GrPixelConfig is expanded to encompass
713// alpha info, that will be considered.
jvanverthfa1e8a72014-12-22 08:31:49 -0800714GrPixelConfig SkImageInfo2GrPixelConfig(SkColorType ct, SkAlphaType, SkColorProfileType pt) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000715 switch (ct) {
716 case kUnknown_SkColorType:
717 return kUnknown_GrPixelConfig;
718 case kAlpha_8_SkColorType:
719 return kAlpha_8_GrPixelConfig;
720 case kRGB_565_SkColorType:
721 return kRGB_565_GrPixelConfig;
722 case kARGB_4444_SkColorType:
723 return kRGBA_4444_GrPixelConfig;
724 case kRGBA_8888_SkColorType:
jvanverth99babf22015-05-22 06:06:40 -0700725 //if (kSRGB_SkColorProfileType == pt) {
726 // return kSRGBA_8888_GrPixelConfig;
727 //}
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000728 return kRGBA_8888_GrPixelConfig;
729 case kBGRA_8888_SkColorType:
730 return kBGRA_8888_GrPixelConfig;
731 case kIndex_8_SkColorType:
732 return kIndex_8_GrPixelConfig;
reed0c9b1a82015-03-17 17:44:06 -0700733 case kGray_8_SkColorType:
734 return kAlpha_8_GrPixelConfig; // TODO: gray8 support on gpu
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000735 }
736 SkASSERT(0); // shouldn't get here
737 return kUnknown_GrPixelConfig;
738}
739
jvanverthfa1e8a72014-12-22 08:31:49 -0800740bool GrPixelConfig2ColorAndProfileType(GrPixelConfig config, SkColorType* ctOut,
741 SkColorProfileType* ptOut) {
reed@google.combf790232013-12-13 19:45:58 +0000742 SkColorType ct;
jvanverthfa1e8a72014-12-22 08:31:49 -0800743 SkColorProfileType pt = kLinear_SkColorProfileType;
reed@google.combf790232013-12-13 19:45:58 +0000744 switch (config) {
745 case kAlpha_8_GrPixelConfig:
746 ct = kAlpha_8_SkColorType;
747 break;
748 case kIndex_8_GrPixelConfig:
749 ct = kIndex_8_SkColorType;
750 break;
751 case kRGB_565_GrPixelConfig:
752 ct = kRGB_565_SkColorType;
753 break;
754 case kRGBA_4444_GrPixelConfig:
755 ct = kARGB_4444_SkColorType;
756 break;
757 case kRGBA_8888_GrPixelConfig:
758 ct = kRGBA_8888_SkColorType;
759 break;
760 case kBGRA_8888_GrPixelConfig:
761 ct = kBGRA_8888_SkColorType;
762 break;
jvanverthfa1e8a72014-12-22 08:31:49 -0800763 case kSRGBA_8888_GrPixelConfig:
764 ct = kRGBA_8888_SkColorType;
765 pt = kSRGB_SkColorProfileType;
766 break;
reed@google.combf790232013-12-13 19:45:58 +0000767 default:
768 return false;
769 }
770 if (ctOut) {
771 *ctOut = ct;
772 }
jvanverthfa1e8a72014-12-22 08:31:49 -0800773 if (ptOut) {
774 *ptOut = pt;
775 }
reed@google.combf790232013-12-13 19:45:58 +0000776 return true;
777}
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000778
779///////////////////////////////////////////////////////////////////////////////
780
bsalomonbed83a62015-04-15 14:18:34 -0700781bool SkPaint2GrPaintNoShader(GrContext* context, GrRenderTarget* rt, const SkPaint& skPaint,
joshualitt25d9c152015-02-18 12:29:52 -0800782 GrColor paintColor, bool constantColor, GrPaint* grPaint) {
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000783
784 grPaint->setDither(skPaint.isDither());
785 grPaint->setAntiAlias(skPaint.isAntiAlias());
786
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000787 SkXfermode* mode = skPaint.getXfermode();
halcanary96fcdcc2015-08-27 07:41:13 -0700788 GrXPFactory* xpFactory = nullptr;
egdaniel58136162015-01-20 10:19:22 -0800789 if (!SkXfermode::AsXPFactory(mode, &xpFactory)) {
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000790 // Fall back to src-over
bsalomonbed83a62015-04-15 14:18:34 -0700791 // return false here?
egdanielc016fb82014-12-03 11:41:54 -0800792 xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode);
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000793 }
egdaniel378092f2014-12-03 10:40:13 -0800794 SkASSERT(xpFactory);
795 grPaint->setXPFactory(xpFactory)->unref();
mtklein775b8192014-12-02 09:11:25 -0800796
dandov9de5b512014-06-10 14:38:28 -0700797 //set the color of the paint to the one of the parameter
bsalomon83d081a2014-07-08 09:56:10 -0700798 grPaint->setColor(paintColor);
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000799
800 SkColorFilter* colorFilter = skPaint.getColorFilter();
bsalomon49f085d2014-09-05 13:34:00 -0700801 if (colorFilter) {
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000802 // if the source color is a constant then apply the filter here once rather than per pixel
803 // in a shader.
804 if (constantColor) {
805 SkColor filtered = colorFilter->filterColor(skPaint.getColor());
806 grPaint->setColor(SkColor2GrColor(filtered));
807 } else {
reedcff10b22015-03-03 06:41:45 -0800808 SkTDArray<GrFragmentProcessor*> array;
bsalomonbed83a62015-04-15 14:18:34 -0700809 // return false if failed?
joshualitt9cc17752015-07-09 06:28:14 -0700810 if (colorFilter->asFragmentProcessors(context, grPaint->getProcessorDataManager(),
joshualitt2cff1762015-07-08 07:58:18 -0700811 &array)) {
reedcff10b22015-03-03 06:41:45 -0800812 for (int i = 0; i < array.count(); ++i) {
bsalomonac856c92015-08-27 06:30:17 -0700813 grPaint->addColorFragmentProcessor(array[i]);
reedcff10b22015-03-03 06:41:45 -0800814 array[i]->unref();
815 }
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000816 }
817 }
818 }
krajcevskif461a8f2014-06-19 14:14:06 -0700819
820#ifndef SK_IGNORE_GPU_DITHER
821 // If the dither flag is set, then we need to see if the underlying context
822 // supports it. If not, then install a dither effect.
bsalomonac856c92015-08-27 06:30:17 -0700823 if (skPaint.isDither() && grPaint->numColorFragmentProcessors() > 0) {
krajcevskif461a8f2014-06-19 14:14:06 -0700824 // What are we rendering into?
joshualitt25d9c152015-02-18 12:29:52 -0800825 SkASSERT(rt);
krajcevskif461a8f2014-06-19 14:14:06 -0700826
827 // Suspect the dithering flag has no effect on these configs, otherwise
828 // fall back on setting the appropriate state.
joshualitt25d9c152015-02-18 12:29:52 -0800829 if (GrPixelConfigIs8888(rt->config()) ||
830 GrPixelConfigIs8888(rt->config())) {
krajcevskif461a8f2014-06-19 14:14:06 -0700831 // The dither flag is set and the target is likely
832 // not going to be dithered by the GPU.
joshualittb0a8a372014-09-23 09:50:21 -0700833 SkAutoTUnref<GrFragmentProcessor> fp(GrDitherEffect::Create());
834 if (fp.get()) {
bsalomonac856c92015-08-27 06:30:17 -0700835 grPaint->addColorFragmentProcessor(fp);
krajcevskif461a8f2014-06-19 14:14:06 -0700836 grPaint->setDither(false);
837 }
838 }
839 }
840#endif
bsalomonbed83a62015-04-15 14:18:34 -0700841 return true;
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000842}
843
bsalomonbed83a62015-04-15 14:18:34 -0700844bool SkPaint2GrPaint(GrContext* context, GrRenderTarget* rt, const SkPaint& skPaint,
845 const SkMatrix& viewM, bool constantColor, GrPaint* grPaint) {
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000846 SkShader* shader = skPaint.getShader();
halcanary96fcdcc2015-08-27 07:41:13 -0700847 if (nullptr == shader) {
bsalomonbed83a62015-04-15 14:18:34 -0700848 return SkPaint2GrPaintNoShader(context, rt, skPaint, SkColor2GrColor(skPaint.getColor()),
849 constantColor, grPaint);
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000850 }
851
bsalomon83d081a2014-07-08 09:56:10 -0700852 GrColor paintColor = SkColor2GrColor(skPaint.getColor());
krajcevskif461a8f2014-06-19 14:14:06 -0700853
bsalomonc21b09e2015-08-28 18:46:56 -0700854 const GrFragmentProcessor* fp = shader->asFragmentProcessor(context, viewM, NULL,
855 skPaint.getFilterQuality(), grPaint->getProcessorDataManager());
856 if (!fp) {
857 return false;
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000858 }
bsalomonc21b09e2015-08-28 18:46:56 -0700859 grPaint->addColorFragmentProcessor(fp)->unref();
860 constantColor = false;
krajcevskif461a8f2014-06-19 14:14:06 -0700861
joshualittb0a8a372014-09-23 09:50:21 -0700862 // The grcolor is automatically set when calling asFragmentProcessor.
dandov9de5b512014-06-10 14:38:28 -0700863 // If the shader can be seen as an effect it returns true and adds its effect to the grpaint.
bsalomonbed83a62015-04-15 14:18:34 -0700864 return SkPaint2GrPaintNoShader(context, rt, skPaint, paintColor, constantColor, grPaint);
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000865}
reed8b26b992015-05-07 15:36:17 -0700866
867SkImageInfo GrMakeInfoFromTexture(GrTexture* tex, int w, int h, bool isOpaque) {
868#ifdef SK_DEBUG
869 const GrSurfaceDesc& desc = tex->desc();
870 SkASSERT(w <= desc.fWidth);
871 SkASSERT(h <= desc.fHeight);
872#endif
873 const GrPixelConfig config = tex->config();
874 SkColorType ct;
875 SkAlphaType at = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
halcanary96fcdcc2015-08-27 07:41:13 -0700876 if (!GrPixelConfig2ColorAndProfileType(config, &ct, nullptr)) {
reed8b26b992015-05-07 15:36:17 -0700877 ct = kUnknown_SkColorType;
878 }
879 return SkImageInfo::Make(w, h, ct, at);
880}
881
882
883void GrWrapTextureInBitmap(GrTexture* src, int w, int h, bool isOpaque, SkBitmap* dst) {
884 const SkImageInfo info = GrMakeInfoFromTexture(src, w, h, isOpaque);
885 dst->setInfo(info);
halcanary385fe4d2015-08-26 13:07:48 -0700886 dst->setPixelRef(new SkGrPixelRef(info, src))->unref();
reed8b26b992015-05-07 15:36:17 -0700887}
joshualitt9bc39542015-08-12 12:57:54 -0700888
889GrTextureParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality paintFilterQuality,
890 const SkMatrix& viewM,
891 const SkMatrix& localM,
892 bool* doBicubic) {
893 *doBicubic = false;
894 GrTextureParams::FilterMode textureFilterMode;
895 switch (paintFilterQuality) {
896 case kNone_SkFilterQuality:
897 textureFilterMode = GrTextureParams::kNone_FilterMode;
898 break;
899 case kLow_SkFilterQuality:
900 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
901 break;
902 case kMedium_SkFilterQuality: {
903 SkMatrix matrix;
904 matrix.setConcat(viewM, localM);
905 if (matrix.getMinScale() < SK_Scalar1) {
906 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
907 } else {
908 // Don't trigger MIP level generation unnecessarily.
909 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
910 }
911 break;
912 }
913 case kHigh_SkFilterQuality: {
914 SkMatrix matrix;
915 matrix.setConcat(viewM, localM);
916 *doBicubic = GrBicubicEffect::ShouldUseBicubic(matrix, &textureFilterMode);
917 break;
918 }
919 default:
920 SkErrorInternals::SetError( kInvalidPaint_SkError,
921 "Sorry, I don't understand the filtering "
922 "mode you asked for. Falling back to "
923 "MIPMaps.");
924 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
925 break;
926
927 }
928 return textureFilterMode;
929}