blob: f7949e2120eb025b15e88035caa559e25b6a796f [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"
bsalomon0d996862016-03-09 18:44:43 -08009#include "SkGrPriv.h"
egdaniel378092f2014-12-03 10:40:13 -080010
Brian Osman3b66ab62016-11-28 09:26:31 -050011#include "GrBitmapTextureMaker.h"
bsalomon76228632015-05-29 08:02:10 -070012#include "GrCaps.h"
bsalomonf276ac52015-10-09 13:36:42 -070013#include "GrContext.h"
bsalomon045802d2015-10-20 07:58:01 -070014#include "GrGpuResourcePriv.h"
Brian Osman3b66ab62016-11-28 09:26:31 -050015#include "GrRenderTargetContext.h"
brianosmanfe199872016-06-13 07:59:48 -070016#include "GrTexturePriv.h"
cblume55f2d2d2016-02-26 13:20:48 -080017#include "GrTypes.h"
egdaniel378092f2014-12-03 10:40:13 -080018#include "GrXferProcessor.h"
reed43fe6182015-09-08 08:37:36 -070019
Hal Canary95e3c052017-01-11 12:44:43 -050020#include "SkAutoMalloc.h"
reed374772b2016-10-05 17:33:02 -070021#include "SkBlendModePriv.h"
Hal Canary95e3c052017-01-11 12:44:43 -050022#include "SkCanvas.h"
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +000023#include "SkColorFilter.h"
commit-bot@chromium.orgea476e12013-10-14 18:29:23 +000024#include "SkConfig8888.h"
krajcevski9c0e6292014-06-02 07:38:14 -070025#include "SkData.h"
Brian Osman4075ec82017-01-17 16:41:03 +000026#include "SkImageInfoPriv.h"
Robert Phillipsa29a9562016-10-20 09:40:55 -040027#include "SkMaskFilter.h"
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000028#include "SkMessageBus.h"
cblume55f2d2d2016-02-26 13:20:48 -080029#include "SkMipMap.h"
Kevin Lubickc456b732017-01-11 17:21:57 +000030#include "SkPM4fPriv.h"
Hal Canary95e3c052017-01-11 12:44:43 -050031#include "SkPixelRef.h"
sugoi692135f2015-01-19 10:10:27 -080032#include "SkResourceCache.h"
cblume55f2d2d2016-02-26 13:20:48 -080033#include "SkTemplates.h"
joshualitt9bc39542015-08-12 12:57:54 -070034#include "effects/GrBicubicEffect.h"
bsalomonf1b7a1d2015-09-28 06:26:28 -070035#include "effects/GrConstColorProcessor.h"
krajcevskif461a8f2014-06-19 14:14:06 -070036#include "effects/GrDitherEffect.h"
egdaniel378092f2014-12-03 10:40:13 -080037#include "effects/GrPorterDuffXferProcessor.h"
bsalomonf1b7a1d2015-09-28 06:26:28 -070038#include "effects/GrXfermodeFragmentProcessor.h"
krajcevski9c0e6292014-06-02 07:38:14 -070039
krajcevski8c111f72014-06-02 13:51:34 -070040#ifndef SK_IGNORE_ETC1_SUPPORT
Leon Scroggins427da6f2016-12-16 13:51:59 +000041# include "ktx.h"
krajcevski9c0e6292014-06-02 07:38:14 -070042# include "etc1.h"
43#endif
reed@google.comac10a2d2010-12-22 21:39:39 +000044
brianosmana6359362016-03-21 06:55:37 -070045GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo& info, const GrCaps& caps) {
bsalomon466c2c42015-10-16 12:01:18 -070046 GrSurfaceDesc desc;
47 desc.fFlags = kNone_GrSurfaceFlags;
48 desc.fWidth = info.width();
49 desc.fHeight = info.height();
brianosmana6359362016-03-21 06:55:37 -070050 desc.fConfig = SkImageInfo2GrPixelConfig(info, caps);
bsalomon466c2c42015-10-16 12:01:18 -070051 desc.fSampleCnt = 0;
52 return desc;
53}
54
bsalomon045802d2015-10-20 07:58:01 -070055void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds) {
56 SkASSERT(key);
57 SkASSERT(imageID);
58 SkASSERT(!imageBounds.isEmpty());
59 static const GrUniqueKey::Domain kImageIDDomain = GrUniqueKey::GenerateDomain();
60 GrUniqueKey::Builder builder(key, kImageIDDomain, 5);
bsalomon466c2c42015-10-16 12:01:18 -070061 builder[0] = imageID;
bsalomon045802d2015-10-20 07:58:01 -070062 builder[1] = imageBounds.fLeft;
63 builder[2] = imageBounds.fTop;
64 builder[3] = imageBounds.fRight;
65 builder[4] = imageBounds.fBottom;
bsalomon466c2c42015-10-16 12:01:18 -070066}
67
68GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data,
69 int expectedW, int expectedH,
70 const void** outStartOfDataToUpload) {
71 *outStartOfDataToUpload = nullptr;
72#ifndef SK_IGNORE_ETC1_SUPPORT
73 if (!ctx->caps()->isConfigTexturable(kETC1_GrPixelConfig)) {
74 return kUnknown_GrPixelConfig;
75 }
76
77 const uint8_t* bytes = data->bytes();
78 if (data->size() > ETC_PKM_HEADER_SIZE && etc1_pkm_is_valid(bytes)) {
79 // Does the data match the dimensions of the bitmap? If not,
80 // then we don't know how to scale the image to match it...
81 if (etc1_pkm_get_width(bytes) != (unsigned)expectedW ||
82 etc1_pkm_get_height(bytes) != (unsigned)expectedH)
83 {
84 return kUnknown_GrPixelConfig;
85 }
86
87 *outStartOfDataToUpload = bytes + ETC_PKM_HEADER_SIZE;
88 return kETC1_GrPixelConfig;
Leon Scroggins427da6f2016-12-16 13:51:59 +000089 } else if (SkKTXFile::is_ktx(bytes, data->size())) {
90 SkKTXFile ktx(data);
91
92 // Is it actually an ETC1 texture?
93 if (!ktx.isCompressedFormat(SkTextureCompressor::kETC1_Format)) {
94 return kUnknown_GrPixelConfig;
95 }
96
97 // Does the data match the dimensions of the bitmap? If not,
98 // then we don't know how to scale the image to match it...
99 if (ktx.width() != expectedW || ktx.height() != expectedH) {
100 return kUnknown_GrPixelConfig;
101 }
102
103 *outStartOfDataToUpload = ktx.pixelData();
104 return kETC1_GrPixelConfig;
bsalomon466c2c42015-10-16 12:01:18 -0700105 }
106#endif
107 return kUnknown_GrPixelConfig;
108}
109
bsalomon045802d2015-10-20 07:58:01 -0700110//////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000111
bsalomon0d996862016-03-09 18:44:43 -0800112GrTexture* GrUploadBitmapToTexture(GrContext* ctx, const SkBitmap& bitmap) {
bsalomon0d996862016-03-09 18:44:43 -0800113 SkAutoLockPixels alp(bitmap);
114 if (!bitmap.readyToDraw()) {
115 return nullptr;
116 }
117 SkPixmap pixmap;
118 if (!bitmap.peekPixels(&pixmap)) {
119 return nullptr;
120 }
ericrk8bea8902016-03-18 11:52:20 -0700121 return GrUploadPixmapToTexture(ctx, pixmap, SkBudgeted::kYes);
bsalomon0d996862016-03-09 18:44:43 -0800122}
123
ericrk8bea8902016-03-18 11:52:20 -0700124GrTexture* GrUploadPixmapToTexture(GrContext* ctx, const SkPixmap& pixmap, SkBudgeted budgeted) {
bsalomon0d996862016-03-09 18:44:43 -0800125 const SkPixmap* pmap = &pixmap;
126 SkPixmap tmpPixmap;
bsalomon045802d2015-10-20 07:58:01 -0700127 SkBitmap tmpBitmap;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000128
Brian Osman4075ec82017-01-17 16:41:03 +0000129 if (!SkImageInfoIsValid(pixmap.info())) {
130 return nullptr;
131 }
132
bsalomon76228632015-05-29 08:02:10 -0700133 const GrCaps* caps = ctx->caps();
brianosmana6359362016-03-21 06:55:37 -0700134 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(pixmap.info(), *caps);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000135
Brian Osmand0be1ef2017-01-11 16:57:15 -0500136 // TODO: We're checking for srgbSupport, but we can then end up picking sBGRA as our pixel
137 // config (which may not be supported). We need better fallback management here.
138
brianosmanefded512016-07-26 08:11:50 -0700139 if (caps->srgbSupport() &&
140 pixmap.info().colorSpace() && pixmap.info().colorSpace()->gammaCloseToSRGB() &&
Brian Osmanc74dad62017-01-12 17:18:22 -0500141 !GrPixelConfigIsSRGB(desc.fConfig)) {
brianosmanb109b8c2016-06-16 13:03:24 -0700142 // We were supplied an sRGB-like color space, but we don't have a suitable pixel config.
brianosmana6359362016-03-21 06:55:37 -0700143 // Convert to 8888 sRGB so we can handle the data correctly. The raster backend doesn't
144 // handle sRGB Index8 -> sRGB 8888 correctly (yet), so lie about both the source and
145 // destination (claim they're linear):
146 SkImageInfo linSrcInfo = SkImageInfo::Make(pixmap.width(), pixmap.height(),
147 pixmap.colorType(), pixmap.alphaType());
148 SkPixmap linSrcPixmap(linSrcInfo, pixmap.addr(), pixmap.rowBytes(), pixmap.ctable());
149
brianosmanb109b8c2016-06-16 13:03:24 -0700150 SkImageInfo dstInfo = SkImageInfo::Make(pixmap.width(), pixmap.height(),
151 kN32_SkColorType, kPremul_SkAlphaType,
Robert Phillips70b49fd2017-01-13 11:21:36 -0500152 pixmap.info().refColorSpace());
brianosmanb109b8c2016-06-16 13:03:24 -0700153
brianosmana6359362016-03-21 06:55:37 -0700154 tmpBitmap.allocPixels(dstInfo);
155
156 SkImageInfo linDstInfo = SkImageInfo::MakeN32Premul(pixmap.width(), pixmap.height());
157 if (!linSrcPixmap.readPixels(linDstInfo, tmpBitmap.getPixels(), tmpBitmap.rowBytes())) {
158 return nullptr;
159 }
160 if (!tmpBitmap.peekPixels(&tmpPixmap)) {
161 return nullptr;
162 }
163 pmap = &tmpPixmap;
164 // must rebuild desc, since we've forced the info to be N32
165 desc = GrImageInfoToSurfaceDesc(pmap->info(), *caps);
166 } else if (kIndex_8_SkColorType == pixmap.colorType()) {
Brian Osmand0be1ef2017-01-11 16:57:15 -0500167 SkImageInfo info = SkImageInfo::MakeN32Premul(pixmap.width(), pixmap.height());
168 tmpBitmap.allocPixels(info);
169 if (!pixmap.readPixels(info, tmpBitmap.getPixels(), tmpBitmap.rowBytes())) {
170 return nullptr;
krajcevski9c0e6292014-06-02 07:38:14 -0700171 }
Brian Osmand0be1ef2017-01-11 16:57:15 -0500172 if (!tmpBitmap.peekPixels(&tmpPixmap)) {
173 return nullptr;
174 }
175 pmap = &tmpPixmap;
176 // must rebuild desc, since we've forced the info to be N32
177 desc = GrImageInfoToSurfaceDesc(pmap->info(), *caps);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000178 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000179
ericrk8bea8902016-03-18 11:52:20 -0700180 return ctx->textureProvider()->createTexture(desc, budgeted, pmap->addr(),
bsalomon0d996862016-03-09 18:44:43 -0800181 pmap->rowBytes());
bsalomon37f9a262015-02-02 13:00:10 -0800182}
183
bsalomonb4d40ef2015-07-15 10:12:16 -0700184
bsalomon045802d2015-10-20 07:58:01 -0700185////////////////////////////////////////////////////////////////////////////////
186
bsalomonc55271f2015-11-09 11:55:57 -0800187void GrInstallBitmapUniqueKeyInvalidator(const GrUniqueKey& key, SkPixelRef* pixelRef) {
bsalomon89fe56b2015-10-29 10:49:28 -0700188 class Invalidator : public SkPixelRef::GenIDChangeListener {
189 public:
190 explicit Invalidator(const GrUniqueKey& key) : fMsg(key) {}
191 private:
192 GrUniqueKeyInvalidatedMessage fMsg;
193
194 void onChange() override { SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); }
195 };
196
197 pixelRef->addGenIDChangeListener(new Invalidator(key));
198}
199
brianosman982eb7f2016-06-06 13:10:58 -0700200GrTexture* GrGenerateMipMapsAndUploadToTexture(GrContext* ctx, const SkBitmap& bitmap,
Brian Osman61624f02016-12-09 14:51:59 -0500201 SkColorSpace* dstColorSpace)
cblume55f2d2d2016-02-26 13:20:48 -0800202{
Brian Osman61624f02016-12-09 14:51:59 -0500203 SkDestinationSurfaceColorMode colorMode = dstColorSpace
204 ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware
205 : SkDestinationSurfaceColorMode::kLegacy;
206
Brian Osman4075ec82017-01-17 16:41:03 +0000207 if (!SkImageInfoIsValid(bitmap.info())) {
208 return nullptr;
209 }
210
brianosmana6359362016-03-21 06:55:37 -0700211 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bitmap.info(), *ctx->caps());
cblume55f2d2d2016-02-26 13:20:48 -0800212
brianosman7e5e5942016-06-21 12:08:24 -0700213 // We don't support Gray8 directly in the GL backend, so fail-over to GrUploadBitmapToTexture.
214 // That will transform the Gray8 to 8888, then use the driver/GPU to build mipmaps. If we build
215 // the mips on the CPU here, they'll all be Gray8, which isn't useful. (They get treated as A8).
216 // TODO: A better option might be to transform the initial bitmap here to 8888, then run the
217 // CPU mip-mapper on that data before uploading. This is much less code for a rare case though:
218 if (kGray_8_SkColorType == bitmap.colorType()) {
219 return nullptr;
220 }
221
cblume55f2d2d2016-02-26 13:20:48 -0800222 SkAutoPixmapUnlock srcUnlocker;
223 if (!bitmap.requestLock(&srcUnlocker)) {
224 return nullptr;
225 }
226 const SkPixmap& pixmap = srcUnlocker.pixmap();
227 // Try to catch where we might have returned nullptr for src crbug.com/492818
228 if (nullptr == pixmap.addr()) {
229 sk_throw();
230 }
231
Brian Osman7b8400d2016-11-08 17:08:54 -0500232 std::unique_ptr<SkMipMap> mipmaps(SkMipMap::Build(pixmap, colorMode, nullptr));
cblume55f2d2d2016-02-26 13:20:48 -0800233 if (!mipmaps) {
234 return nullptr;
235 }
236
237 const int mipLevelCount = mipmaps->countLevels() + 1;
238 if (mipLevelCount < 1) {
239 return nullptr;
240 }
241
242 const bool isMipMapped = mipLevelCount > 1;
243 desc.fIsMipMapped = isMipMapped;
244
Ben Wagner7ecc5962016-11-02 17:07:33 -0400245 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
cblume55f2d2d2016-02-26 13:20:48 -0800246
247 texels[0].fPixels = pixmap.addr();
248 texels[0].fRowBytes = pixmap.rowBytes();
249
250 for (int i = 1; i < mipLevelCount; ++i) {
251 SkMipMap::Level generatedMipLevel;
252 mipmaps->getLevel(i - 1, &generatedMipLevel);
253 texels[i].fPixels = generatedMipLevel.fPixmap.addr();
254 texels[i].fRowBytes = generatedMipLevel.fPixmap.rowBytes();
255 }
256
brianosmanfe199872016-06-13 07:59:48 -0700257 {
258 GrTexture* texture = ctx->textureProvider()->createMipMappedTexture(desc,
259 SkBudgeted::kYes,
260 texels.get(),
261 mipLevelCount);
brianosman7d2f6072016-06-17 07:03:45 -0700262 if (texture) {
Brian Osman7b8400d2016-11-08 17:08:54 -0500263 texture->texturePriv().setMipColorMode(colorMode);
brianosman7d2f6072016-06-17 07:03:45 -0700264 }
brianosmanfe199872016-06-13 07:59:48 -0700265 return texture;
266 }
cblume55f2d2d2016-02-26 13:20:48 -0800267}
268
cblume186d2d42016-06-03 11:17:42 -0700269GrTexture* GrUploadMipMapToTexture(GrContext* ctx, const SkImageInfo& info,
270 const GrMipLevel* texels, int mipLevelCount) {
Brian Osman4075ec82017-01-17 16:41:03 +0000271 if (!SkImageInfoIsValid(info)) {
272 return nullptr;
273 }
274
cblume186d2d42016-06-03 11:17:42 -0700275 const GrCaps* caps = ctx->caps();
276 return ctx->textureProvider()->createMipMappedTexture(GrImageInfoToSurfaceDesc(info, *caps),
277 SkBudgeted::kYes, texels,
278 mipLevelCount);
279}
280
reedb5d32632015-09-29 13:36:50 -0700281GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap,
Robert Phillips67c18d62017-01-20 12:44:06 -0500282 const GrSamplerParams& params, SkScalar scaleAdjust[2]) {
Brian Osman7992da32016-11-18 11:28:24 -0500283 // Caller doesn't care about the texture's color space (they can always get it from the bitmap)
Robert Phillips67c18d62017-01-20 12:44:06 -0500284 return GrBitmapTextureMaker(ctx, bitmap).refTextureForParams(params, nullptr,
285 nullptr, scaleAdjust);
rileya@google.com24f3ad12012-07-18 21:47:40 +0000286}
reed8f343722015-08-13 13:32:39 -0700287
reedc7ec7c92016-07-25 08:29:10 -0700288sk_sp<GrTexture> GrMakeCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap,
Robert Phillips67c18d62017-01-20 12:44:06 -0500289 const GrSamplerParams& params, SkScalar scaleAdjust[2]) {
Brian Osman7992da32016-11-18 11:28:24 -0500290 // Caller doesn't care about the texture's color space (they can always get it from the bitmap)
Brian Osman61624f02016-12-09 14:51:59 -0500291 GrTexture* tex = GrBitmapTextureMaker(ctx, bitmap).refTextureForParams(params, nullptr,
Robert Phillips67c18d62017-01-20 12:44:06 -0500292 nullptr, scaleAdjust);
reedc7ec7c92016-07-25 08:29:10 -0700293 return sk_sp<GrTexture>(tex);
294}
295
rileya@google.com24f3ad12012-07-18 21:47:40 +0000296///////////////////////////////////////////////////////////////////////////////
297
Brian Osman72ae4312016-10-20 16:53:45 -0400298GrColor4f SkColorToPremulGrColor4f(SkColor c, SkColorSpace* dstColorSpace) {
299 // We want to premultiply after linearizing, so this is easy:
300 return SkColorToUnpremulGrColor4f(c, dstColorSpace).premul();
301}
302
303GrColor4f SkColorToUnpremulGrColor4f(SkColor c, SkColorSpace* dstColorSpace) {
304 if (dstColorSpace) {
Brian Osman526972e2016-10-24 09:24:02 -0400305 auto srgbColorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
Brian Osman72ae4312016-10-20 16:53:45 -0400306 auto gamutXform = GrColorSpaceXform::Make(srgbColorSpace.get(), dstColorSpace);
307 return SkColorToUnpremulGrColor4f(c, true, gamutXform.get());
308 } else {
309 return SkColorToUnpremulGrColor4f(c, false, nullptr);
310 }
311}
312
Brian Osmanc68d4aa2016-09-30 11:41:59 -0400313GrColor4f SkColorToPremulGrColor4f(SkColor c, bool gammaCorrect, GrColorSpaceXform* gamutXform) {
314 // We want to premultiply after linearizing, so this is easy:
315 return SkColorToUnpremulGrColor4f(c, gammaCorrect, gamutXform).premul();
316}
317
318GrColor4f SkColorToUnpremulGrColor4f(SkColor c, bool gammaCorrect, GrColorSpaceXform* gamutXform) {
319 // You can't be color-space aware in legacy mode
320 SkASSERT(gammaCorrect || !gamutXform);
321
322 GrColor4f color;
323 if (gammaCorrect) {
324 // SkColor4f::FromColor does sRGB -> Linear
325 color = GrColor4f::FromSkColor4f(SkColor4f::FromColor(c));
326 } else {
327 // GrColor4f::FromGrColor just multiplies by 1/255
328 color = GrColor4f::FromGrColor(SkColorToUnpremulGrColor(c));
329 }
330
331 if (gamutXform) {
332 color = gamutXform->apply(color);
333 }
334
335 return color;
336}
337
338///////////////////////////////////////////////////////////////////////////////
339
Brian Osman0c2997b2017-01-11 16:58:42 -0500340GrPixelConfig SkImageInfo2GrPixelConfig(const SkImageInfo& info, const GrCaps& caps) {
brianosmana6359362016-03-21 06:55:37 -0700341 // We intentionally ignore profile type for non-8888 formats. Anything we can't support
342 // in hardware will be expanded to sRGB 8888 in GrUploadPixmapToTexture.
Brian Osman0c2997b2017-01-11 16:58:42 -0500343 SkColorSpace* cs = info.colorSpace();
344 switch (info.colorType()) {
brianosmanc571c002016-03-17 13:01:26 -0700345 case kUnknown_SkColorType:
346 return kUnknown_GrPixelConfig;
347 case kAlpha_8_SkColorType:
348 return kAlpha_8_GrPixelConfig;
349 case kRGB_565_SkColorType:
350 return kRGB_565_GrPixelConfig;
351 case kARGB_4444_SkColorType:
352 return kRGBA_4444_GrPixelConfig;
353 case kRGBA_8888_SkColorType:
brianosmanb109b8c2016-06-16 13:03:24 -0700354 return (caps.srgbSupport() && cs && cs->gammaCloseToSRGB())
brianosmana6359362016-03-21 06:55:37 -0700355 ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig;
brianosmanc571c002016-03-17 13:01:26 -0700356 case kBGRA_8888_SkColorType:
brianosmanb109b8c2016-06-16 13:03:24 -0700357 return (caps.srgbSupport() && cs && cs->gammaCloseToSRGB())
brianosmana6359362016-03-21 06:55:37 -0700358 ? kSBGRA_8888_GrPixelConfig : kBGRA_8888_GrPixelConfig;
brianosmanc571c002016-03-17 13:01:26 -0700359 case kIndex_8_SkColorType:
Brian Osmand0be1ef2017-01-11 16:57:15 -0500360 return kSkia8888_GrPixelConfig;
brianosmanc571c002016-03-17 13:01:26 -0700361 case kGray_8_SkColorType:
Brian Osman986563b2017-01-10 14:20:02 -0500362 return kGray_8_GrPixelConfig;
brianosmanc571c002016-03-17 13:01:26 -0700363 case kRGBA_F16_SkColorType:
364 return kRGBA_half_GrPixelConfig;
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000365 }
366 SkASSERT(0); // shouldn't get here
367 return kUnknown_GrPixelConfig;
368}
369
brianosman396fcdb2016-07-22 06:26:11 -0700370bool GrPixelConfigToColorType(GrPixelConfig config, SkColorType* ctOut) {
reed@google.combf790232013-12-13 19:45:58 +0000371 SkColorType ct;
372 switch (config) {
373 case kAlpha_8_GrPixelConfig:
374 ct = kAlpha_8_SkColorType;
375 break;
Brian Osman986563b2017-01-10 14:20:02 -0500376 case kGray_8_GrPixelConfig:
377 ct = kGray_8_SkColorType;
378 break;
reed@google.combf790232013-12-13 19:45:58 +0000379 case kRGB_565_GrPixelConfig:
380 ct = kRGB_565_SkColorType;
381 break;
382 case kRGBA_4444_GrPixelConfig:
383 ct = kARGB_4444_SkColorType;
384 break;
385 case kRGBA_8888_GrPixelConfig:
386 ct = kRGBA_8888_SkColorType;
387 break;
388 case kBGRA_8888_GrPixelConfig:
389 ct = kBGRA_8888_SkColorType;
390 break;
jvanverthfa1e8a72014-12-22 08:31:49 -0800391 case kSRGBA_8888_GrPixelConfig:
392 ct = kRGBA_8888_SkColorType;
jvanverthfa1e8a72014-12-22 08:31:49 -0800393 break;
brianosmana6359362016-03-21 06:55:37 -0700394 case kSBGRA_8888_GrPixelConfig:
395 ct = kBGRA_8888_SkColorType;
brianosmana6359362016-03-21 06:55:37 -0700396 break;
brianosman9ac5b912016-04-12 13:49:53 -0700397 case kRGBA_half_GrPixelConfig:
398 ct = kRGBA_F16_SkColorType;
399 break;
reed@google.combf790232013-12-13 19:45:58 +0000400 default:
401 return false;
402 }
403 if (ctOut) {
404 *ctOut = ct;
405 }
406 return true;
407}
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000408
brianosman27a3aa52016-09-23 07:11:34 -0700409GrPixelConfig GrRenderableConfigForColorSpace(const SkColorSpace* colorSpace) {
brianosman2695eaa2016-09-21 06:45:09 -0700410 if (!colorSpace) {
411 return kRGBA_8888_GrPixelConfig;
412 } else if (colorSpace->gammaIsLinear()) {
413 return kRGBA_half_GrPixelConfig;
414 } else if (colorSpace->gammaCloseToSRGB()) {
415 return kSRGBA_8888_GrPixelConfig;
416 } else {
417 SkDEBUGFAIL("No renderable config exists for color space with strange gamma");
418 return kUnknown_GrPixelConfig;
419 }
420}
421
bsalomonf1b7a1d2015-09-28 06:26:28 -0700422////////////////////////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000423
Mike Reed7d954ad2016-10-28 15:42:34 -0400424static inline bool blend_requires_shader(const SkBlendMode mode, bool primitiveIsSrc) {
bsalomonaa48d362015-10-01 08:34:17 -0700425 if (primitiveIsSrc) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400426 return SkBlendMode::kSrc != mode;
bsalomonaa48d362015-10-01 08:34:17 -0700427 } else {
Mike Reed7d954ad2016-10-28 15:42:34 -0400428 return SkBlendMode::kDst != mode;
bsalomonaa48d362015-10-01 08:34:17 -0700429 }
430}
431
bsalomonf1b7a1d2015-09-28 06:26:28 -0700432static inline bool skpaint_to_grpaint_impl(GrContext* context,
Brian Osman11052242016-10-27 14:47:55 -0400433 GrRenderTargetContext* rtc,
bsalomonf1b7a1d2015-09-28 06:26:28 -0700434 const SkPaint& skPaint,
435 const SkMatrix& viewM,
bungeman06ca8ec2016-06-09 08:01:03 -0700436 sk_sp<GrFragmentProcessor>* shaderProcessor,
Mike Reed7d954ad2016-10-28 15:42:34 -0400437 SkBlendMode* primColorMode,
bsalomonf1b7a1d2015-09-28 06:26:28 -0700438 bool primitiveIsSrc,
439 GrPaint* grPaint) {
Brian Osman11052242016-10-27 14:47:55 -0400440 grPaint->setAllowSRGBInputs(rtc->isGammaCorrect());
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000441
Brian Osmanc68d4aa2016-09-30 11:41:59 -0400442 // Convert SkPaint color to 4f format, including optional linearizing and gamut conversion.
Brian Osman11052242016-10-27 14:47:55 -0400443 GrColor4f origColor = SkColorToUnpremulGrColor4f(skPaint.getColor(), rtc->isGammaCorrect(),
444 rtc->getColorXformFromSRGB());
brianosmana4535a32016-06-24 12:50:19 -0700445
bsalomonf1b7a1d2015-09-28 06:26:28 -0700446 // Setup the initial color considering the shader, the SkPaint color, and the presence or not
447 // of per-vertex colors.
bungeman06ca8ec2016-06-09 08:01:03 -0700448 sk_sp<GrFragmentProcessor> shaderFP;
bsalomonaa48d362015-10-01 08:34:17 -0700449 if (!primColorMode || blend_requires_shader(*primColorMode, primitiveIsSrc)) {
450 if (shaderProcessor) {
451 shaderFP = *shaderProcessor;
452 } else if (const SkShader* shader = skPaint.getShader()) {
brianosman839345d2016-07-22 11:04:53 -0700453 shaderFP = shader->asFragmentProcessor(SkShader::AsFPArgs(context, &viewM, nullptr,
454 skPaint.getFilterQuality(),
Brian Osman61624f02016-12-09 14:51:59 -0500455 rtc->getColorSpace()));
bsalomonaa48d362015-10-01 08:34:17 -0700456 if (!shaderFP) {
457 return false;
458 }
bsalomonf1b7a1d2015-09-28 06:26:28 -0700459 }
460 }
461
462 // Set this in below cases if the output of the shader/paint-color/paint-alpha/primXfermode is
463 // a known constant value. In that case we can simply apply a color filter during this
464 // conversion without converting the color filter to a GrFragmentProcessor.
465 bool applyColorFilterToPaintColor = false;
466 if (shaderFP) {
467 if (primColorMode) {
468 // There is a blend between the primitive color and the shader color. The shader sees
469 // the opaque paint color. The shader's output is blended using the provided mode by
470 // the primitive color. The blended color is then modulated by the paint's alpha.
471
472 // The geometry processor will insert the primitive color to start the color chain, so
473 // the GrPaint color will be ignored.
474
brianosman4cea3b92016-09-08 09:33:50 -0700475 GrColor4f shaderInput = origColor.opaque();
bsalomonf1b7a1d2015-09-28 06:26:28 -0700476 shaderFP = GrFragmentProcessor::OverrideInput(shaderFP, shaderInput);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700477 if (primitiveIsSrc) {
bungeman06ca8ec2016-06-09 08:01:03 -0700478 shaderFP = GrXfermodeFragmentProcessor::MakeFromDstProcessor(std::move(shaderFP),
479 *primColorMode);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700480 } else {
bungeman06ca8ec2016-06-09 08:01:03 -0700481 shaderFP = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(shaderFP),
482 *primColorMode);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700483 }
bsalomonf1b7a1d2015-09-28 06:26:28 -0700484 // The above may return null if compose results in a pass through of the prim color.
485 if (shaderFP) {
486 grPaint->addColorFragmentProcessor(shaderFP);
487 }
488
brianosmana4535a32016-06-24 12:50:19 -0700489 // We can ignore origColor here - alpha is unchanged by gamma
bsalomonf1b7a1d2015-09-28 06:26:28 -0700490 GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor());
491 if (GrColor_WHITE != paintAlpha) {
Brian Osman618d3042016-10-25 10:51:28 -0400492 // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
493 // color channels. It's value should be treated as the same in ANY color space.
bungeman06ca8ec2016-06-09 08:01:03 -0700494 grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make(
Brian Osman618d3042016-10-25 10:51:28 -0400495 GrColor4f::FromGrColor(paintAlpha),
496 GrConstColorProcessor::kModulateRGBA_InputMode));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700497 }
498 } else {
499 // The shader's FP sees the paint unpremul color
brianosmana4535a32016-06-24 12:50:19 -0700500 grPaint->setColor4f(origColor);
bungeman06ca8ec2016-06-09 08:01:03 -0700501 grPaint->addColorFragmentProcessor(std::move(shaderFP));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700502 }
503 } else {
504 if (primColorMode) {
505 // There is a blend between the primitive color and the paint color. The blend considers
506 // the opaque paint color. The paint's alpha is applied to the post-blended color.
bungeman06ca8ec2016-06-09 08:01:03 -0700507 sk_sp<GrFragmentProcessor> processor(
Brian Osman618d3042016-10-25 10:51:28 -0400508 GrConstColorProcessor::Make(origColor.opaque(),
509 GrConstColorProcessor::kIgnore_InputMode));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700510 if (primitiveIsSrc) {
bungeman06ca8ec2016-06-09 08:01:03 -0700511 processor = GrXfermodeFragmentProcessor::MakeFromDstProcessor(std::move(processor),
512 *primColorMode);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700513 } else {
bungeman06ca8ec2016-06-09 08:01:03 -0700514 processor = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(processor),
515 *primColorMode);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700516 }
517 if (processor) {
bungeman06ca8ec2016-06-09 08:01:03 -0700518 grPaint->addColorFragmentProcessor(std::move(processor));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700519 }
520
brianosmana4535a32016-06-24 12:50:19 -0700521 grPaint->setColor4f(origColor.opaque());
bsalomonf1b7a1d2015-09-28 06:26:28 -0700522
brianosmana4535a32016-06-24 12:50:19 -0700523 // We can ignore origColor here - alpha is unchanged by gamma
bsalomonf1b7a1d2015-09-28 06:26:28 -0700524 GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor());
bsalomonaa48d362015-10-01 08:34:17 -0700525 if (GrColor_WHITE != paintAlpha) {
Brian Osman618d3042016-10-25 10:51:28 -0400526 // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
527 // color channels. It's value should be treated as the same in ANY color space.
bungeman06ca8ec2016-06-09 08:01:03 -0700528 grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make(
Brian Osman618d3042016-10-25 10:51:28 -0400529 GrColor4f::FromGrColor(paintAlpha),
530 GrConstColorProcessor::kModulateRGBA_InputMode));
bsalomonaa48d362015-10-01 08:34:17 -0700531 }
bsalomonf1b7a1d2015-09-28 06:26:28 -0700532 } else {
533 // No shader, no primitive color.
brianosmana4535a32016-06-24 12:50:19 -0700534 grPaint->setColor4f(origColor.premul());
bsalomonf1b7a1d2015-09-28 06:26:28 -0700535 applyColorFilterToPaintColor = true;
536 }
537 }
538
539 SkColorFilter* colorFilter = skPaint.getColorFilter();
540 if (colorFilter) {
541 if (applyColorFilterToPaintColor) {
Brian Osman8bf4e672016-10-17 16:54:49 -0400542 // If we're in legacy mode, we *must* avoid using the 4f version of the color filter,
543 // because that will combine with the linearized version of the stored color.
Brian Osman11052242016-10-27 14:47:55 -0400544 if (rtc->isGammaCorrect()) {
Brian Osman8bf4e672016-10-17 16:54:49 -0400545 grPaint->setColor4f(GrColor4f::FromSkColor4f(
546 colorFilter->filterColor4f(origColor.toSkColor4f())).premul());
547 } else {
548 grPaint->setColor4f(SkColorToPremulGrColor4f(
549 colorFilter->filterColor(skPaint.getColor()), false, nullptr));
550 }
bsalomonf1b7a1d2015-09-28 06:26:28 -0700551 } else {
Brian Osman618d3042016-10-25 10:51:28 -0400552 sk_sp<GrFragmentProcessor> cfFP(colorFilter->asFragmentProcessor(context,
Brian Osman11052242016-10-27 14:47:55 -0400553 rtc->getColorSpace()));
bsalomone25eea42015-09-29 06:38:55 -0700554 if (cfFP) {
bungeman06ca8ec2016-06-09 08:01:03 -0700555 grPaint->addColorFragmentProcessor(std::move(cfFP));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700556 } else {
557 return false;
558 }
559 }
560 }
561
Robert Phillipsa29a9562016-10-20 09:40:55 -0400562 SkMaskFilter* maskFilter = skPaint.getMaskFilter();
563 if (maskFilter) {
564 GrFragmentProcessor* mfFP;
565 if (maskFilter->asFragmentProcessor(&mfFP, nullptr, viewM)) {
566 grPaint->addCoverageFragmentProcessor(sk_sp<GrFragmentProcessor>(mfFP));
567 }
568 }
569
robertphillips4f037942016-02-09 05:09:27 -0800570 // When the xfermode is null on the SkPaint (meaning kSrcOver) we need the XPFactory field on
571 // the GrPaint to also be null (also kSrcOver).
572 SkASSERT(!grPaint->getXPFactory());
reed374772b2016-10-05 17:33:02 -0700573 if (!skPaint.isSrcOver()) {
574 grPaint->setXPFactory(SkBlendMode_AsXPFactory(skPaint.getBlendMode()));
robertphillips4f037942016-02-09 05:09:27 -0800575 }
mtklein775b8192014-12-02 09:11:25 -0800576
krajcevskif461a8f2014-06-19 14:14:06 -0700577#ifndef SK_IGNORE_GPU_DITHER
Brian Osman11052242016-10-27 14:47:55 -0400578 if (skPaint.isDither() && grPaint->numColorFragmentProcessors() > 0 && !rtc->isGammaCorrect()) {
bungeman06ca8ec2016-06-09 08:01:03 -0700579 grPaint->addColorFragmentProcessor(GrDitherEffect::Make());
krajcevskif461a8f2014-06-19 14:14:06 -0700580 }
581#endif
bsalomonbed83a62015-04-15 14:18:34 -0700582 return true;
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000583}
584
Brian Osman11052242016-10-27 14:47:55 -0400585bool SkPaintToGrPaint(GrContext* context, GrRenderTargetContext* rtc, const SkPaint& skPaint,
brianosman8fe485b2016-07-25 12:31:51 -0700586 const SkMatrix& viewM, GrPaint* grPaint) {
Brian Osman11052242016-10-27 14:47:55 -0400587 return skpaint_to_grpaint_impl(context, rtc, skPaint, viewM, nullptr, nullptr, false, grPaint);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700588}
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000589
bsalomonf1b7a1d2015-09-28 06:26:28 -0700590/** Replaces the SkShader (if any) on skPaint with the passed in GrFragmentProcessor. */
591bool SkPaintToGrPaintReplaceShader(GrContext* context,
Brian Osman11052242016-10-27 14:47:55 -0400592 GrRenderTargetContext* rtc,
bsalomonf1b7a1d2015-09-28 06:26:28 -0700593 const SkPaint& skPaint,
bungeman06ca8ec2016-06-09 08:01:03 -0700594 sk_sp<GrFragmentProcessor> shaderFP,
bsalomonf1b7a1d2015-09-28 06:26:28 -0700595 GrPaint* grPaint) {
596 if (!shaderFP) {
bsalomonc21b09e2015-08-28 18:46:56 -0700597 return false;
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000598 }
Brian Osman11052242016-10-27 14:47:55 -0400599 return skpaint_to_grpaint_impl(context, rtc, skPaint, SkMatrix::I(), &shaderFP, nullptr, false,
brianosman8fe485b2016-07-25 12:31:51 -0700600 grPaint);
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000601}
reed8b26b992015-05-07 15:36:17 -0700602
bsalomonf1b7a1d2015-09-28 06:26:28 -0700603/** Ignores the SkShader (if any) on skPaint. */
604bool SkPaintToGrPaintNoShader(GrContext* context,
Brian Osman11052242016-10-27 14:47:55 -0400605 GrRenderTargetContext* rtc,
bsalomonf1b7a1d2015-09-28 06:26:28 -0700606 const SkPaint& skPaint,
607 GrPaint* grPaint) {
608 // Use a ptr to a nullptr to to indicate that the SkShader is ignored and not replaced.
bungeman06ca8ec2016-06-09 08:01:03 -0700609 static sk_sp<GrFragmentProcessor> kNullShaderFP(nullptr);
610 static sk_sp<GrFragmentProcessor>* kIgnoreShader = &kNullShaderFP;
Brian Osman11052242016-10-27 14:47:55 -0400611 return skpaint_to_grpaint_impl(context, rtc, skPaint, SkMatrix::I(), kIgnoreShader, nullptr,
brianosman8fe485b2016-07-25 12:31:51 -0700612 false, grPaint);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700613}
614
615/** Blends the SkPaint's shader (or color if no shader) with a per-primitive color which must
Mike Reed7d954ad2016-10-28 15:42:34 -0400616be setup as a vertex attribute using the specified SkBlendMode. */
bsalomonf1b7a1d2015-09-28 06:26:28 -0700617bool SkPaintToGrPaintWithXfermode(GrContext* context,
Brian Osman11052242016-10-27 14:47:55 -0400618 GrRenderTargetContext* rtc,
bsalomonf1b7a1d2015-09-28 06:26:28 -0700619 const SkPaint& skPaint,
620 const SkMatrix& viewM,
Mike Reed7d954ad2016-10-28 15:42:34 -0400621 SkBlendMode primColorMode,
bsalomonf1b7a1d2015-09-28 06:26:28 -0700622 bool primitiveIsSrc,
623 GrPaint* grPaint) {
Brian Osman11052242016-10-27 14:47:55 -0400624 return skpaint_to_grpaint_impl(context, rtc, skPaint, viewM, nullptr, &primColorMode,
brianosman8fe485b2016-07-25 12:31:51 -0700625 primitiveIsSrc, grPaint);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700626}
627
joshualitt33a5fce2015-11-18 13:28:51 -0800628bool SkPaintToGrPaintWithTexture(GrContext* context,
Brian Osman11052242016-10-27 14:47:55 -0400629 GrRenderTargetContext* rtc,
joshualitt33a5fce2015-11-18 13:28:51 -0800630 const SkPaint& paint,
631 const SkMatrix& viewM,
bungeman06ca8ec2016-06-09 08:01:03 -0700632 sk_sp<GrFragmentProcessor> fp,
joshualitt33a5fce2015-11-18 13:28:51 -0800633 bool textureIsAlphaOnly,
634 GrPaint* grPaint) {
bungeman06ca8ec2016-06-09 08:01:03 -0700635 sk_sp<GrFragmentProcessor> shaderFP;
joshualitt33a5fce2015-11-18 13:28:51 -0800636 if (textureIsAlphaOnly) {
637 if (const SkShader* shader = paint.getShader()) {
brianosman839345d2016-07-22 11:04:53 -0700638 shaderFP = shader->asFragmentProcessor(SkShader::AsFPArgs(context,
639 &viewM,
640 nullptr,
641 paint.getFilterQuality(),
Brian Osman61624f02016-12-09 14:51:59 -0500642 rtc->getColorSpace()));
joshualitt33a5fce2015-11-18 13:28:51 -0800643 if (!shaderFP) {
644 return false;
645 }
bungeman06ca8ec2016-06-09 08:01:03 -0700646 sk_sp<GrFragmentProcessor> fpSeries[] = { std::move(shaderFP), std::move(fp) };
647 shaderFP = GrFragmentProcessor::RunInSeries(fpSeries, 2);
joshualitt33a5fce2015-11-18 13:28:51 -0800648 } else {
bungeman06ca8ec2016-06-09 08:01:03 -0700649 shaderFP = GrFragmentProcessor::MulOutputByInputUnpremulColor(fp);
joshualitt33a5fce2015-11-18 13:28:51 -0800650 }
651 } else {
bungeman06ca8ec2016-06-09 08:01:03 -0700652 shaderFP = GrFragmentProcessor::MulOutputByInputAlpha(fp);
joshualitt33a5fce2015-11-18 13:28:51 -0800653 }
654
Brian Osman11052242016-10-27 14:47:55 -0400655 return SkPaintToGrPaintReplaceShader(context, rtc, paint, std::move(shaderFP), grPaint);
joshualitt33a5fce2015-11-18 13:28:51 -0800656}
657
bsalomonf1b7a1d2015-09-28 06:26:28 -0700658
659////////////////////////////////////////////////////////////////////////////////////////////////
660
Brian Salomon514baff2016-11-17 15:17:07 -0500661GrSamplerParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality paintFilterQuality,
joshualitt9bc39542015-08-12 12:57:54 -0700662 const SkMatrix& viewM,
663 const SkMatrix& localM,
664 bool* doBicubic) {
665 *doBicubic = false;
Brian Salomon514baff2016-11-17 15:17:07 -0500666 GrSamplerParams::FilterMode textureFilterMode;
joshualitt9bc39542015-08-12 12:57:54 -0700667 switch (paintFilterQuality) {
668 case kNone_SkFilterQuality:
Brian Salomon514baff2016-11-17 15:17:07 -0500669 textureFilterMode = GrSamplerParams::kNone_FilterMode;
joshualitt9bc39542015-08-12 12:57:54 -0700670 break;
671 case kLow_SkFilterQuality:
Brian Salomon514baff2016-11-17 15:17:07 -0500672 textureFilterMode = GrSamplerParams::kBilerp_FilterMode;
joshualitt9bc39542015-08-12 12:57:54 -0700673 break;
674 case kMedium_SkFilterQuality: {
675 SkMatrix matrix;
676 matrix.setConcat(viewM, localM);
677 if (matrix.getMinScale() < SK_Scalar1) {
Brian Salomon514baff2016-11-17 15:17:07 -0500678 textureFilterMode = GrSamplerParams::kMipMap_FilterMode;
joshualitt9bc39542015-08-12 12:57:54 -0700679 } else {
680 // Don't trigger MIP level generation unnecessarily.
Brian Salomon514baff2016-11-17 15:17:07 -0500681 textureFilterMode = GrSamplerParams::kBilerp_FilterMode;
joshualitt9bc39542015-08-12 12:57:54 -0700682 }
683 break;
684 }
685 case kHigh_SkFilterQuality: {
686 SkMatrix matrix;
687 matrix.setConcat(viewM, localM);
688 *doBicubic = GrBicubicEffect::ShouldUseBicubic(matrix, &textureFilterMode);
689 break;
690 }
691 default:
Mike Kleine54c75f2016-10-13 14:18:09 -0400692 // Should be unreachable. If not, fall back to mipmaps.
Brian Salomon514baff2016-11-17 15:17:07 -0500693 textureFilterMode = GrSamplerParams::kMipMap_FilterMode;
joshualitt9bc39542015-08-12 12:57:54 -0700694 break;
695
696 }
697 return textureFilterMode;
698}