blob: 095a8676059a57c9224b4ded91bc47622b5fe236 [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"
Brian Osman3b66ab62016-11-28 09:26:31 -05009#include "GrBitmapTextureMaker.h"
bsalomon76228632015-05-29 08:02:10 -070010#include "GrCaps.h"
Brian Osman1cb41712017-10-19 12:54:52 -040011#include "GrColorSpaceXform.h"
bsalomonf276ac52015-10-09 13:36:42 -070012#include "GrContext.h"
Greg Daniel55afd6d2017-09-29 09:32:44 -040013#include "GrContextPriv.h"
bsalomon045802d2015-10-20 07:58:01 -070014#include "GrGpuResourcePriv.h"
Brian Salomonf3569f02017-10-24 12:52:33 -040015#include "GrPaint.h"
Robert Phillips1afd4cd2018-01-08 13:40:32 -050016#include "GrProxyProvider.h"
Hal Canary6f6961e2017-01-31 13:50:44 -050017#include "GrTextureProxy.h"
cblume55f2d2d2016-02-26 13:20:48 -080018#include "GrTypes.h"
egdaniel378092f2014-12-03 10:40:13 -080019#include "GrXferProcessor.h"
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"
Matt Sarett485c4992017-02-14 14:18:27 -050024#include "SkConvertPixels.h"
krajcevski9c0e6292014-06-02 07:38:14 -070025#include "SkData.h"
Robert Phillips7a926392018-02-01 15:49:54 -050026#include "SkImage_Base.h"
Brian Osman4075ec82017-01-17 16:41:03 +000027#include "SkImageInfoPriv.h"
Greg Daniel7e1912a2018-02-08 09:15:33 -050028#include "SkImagePriv.h"
Mike Reed80747ef2018-01-23 15:29:32 -050029#include "SkMaskFilterBase.h"
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000030#include "SkMessageBus.h"
cblume55f2d2d2016-02-26 13:20:48 -080031#include "SkMipMap.h"
Kevin Lubickc456b732017-01-11 17:21:57 +000032#include "SkPM4fPriv.h"
Florin Malitad4a70ee2017-06-19 10:21:43 -040033#include "SkPaintPriv.h"
Hal Canary95e3c052017-01-11 12:44:43 -050034#include "SkPixelRef.h"
sugoi692135f2015-01-19 10:10:27 -080035#include "SkResourceCache.h"
Florin Malita4aed1382017-05-25 10:38:07 -040036#include "SkShaderBase.h"
cblume55f2d2d2016-02-26 13:20:48 -080037#include "SkTemplates.h"
Derek Sollenberger559f5342017-08-17 12:34:54 -040038#include "SkTraceEvent.h"
joshualitt9bc39542015-08-12 12:57:54 -070039#include "effects/GrBicubicEffect.h"
bsalomonf1b7a1d2015-09-28 06:26:28 -070040#include "effects/GrConstColorProcessor.h"
krajcevskif461a8f2014-06-19 14:14:06 -070041#include "effects/GrDitherEffect.h"
egdaniel378092f2014-12-03 10:40:13 -080042#include "effects/GrPorterDuffXferProcessor.h"
bsalomonf1b7a1d2015-09-28 06:26:28 -070043#include "effects/GrXfermodeFragmentProcessor.h"
krajcevski9c0e6292014-06-02 07:38:14 -070044
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;
Robert Phillips019ff272017-07-24 14:47:57 -040048 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
bsalomon466c2c42015-10-16 12:01:18 -070049 desc.fWidth = info.width();
50 desc.fHeight = info.height();
brianosmana6359362016-03-21 06:55:37 -070051 desc.fConfig = SkImageInfo2GrPixelConfig(info, caps);
Brian Salomonbdecacf2018-02-02 20:32:49 -050052 desc.fSampleCnt = 1;
bsalomon466c2c42015-10-16 12:01:18 -070053 return desc;
54}
55
bsalomon045802d2015-10-20 07:58:01 -070056void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds) {
57 SkASSERT(key);
58 SkASSERT(imageID);
59 SkASSERT(!imageBounds.isEmpty());
60 static const GrUniqueKey::Domain kImageIDDomain = GrUniqueKey::GenerateDomain();
61 GrUniqueKey::Builder builder(key, kImageIDDomain, 5);
bsalomon466c2c42015-10-16 12:01:18 -070062 builder[0] = imageID;
bsalomon045802d2015-10-20 07:58:01 -070063 builder[1] = imageBounds.fLeft;
64 builder[2] = imageBounds.fTop;
65 builder[3] = imageBounds.fRight;
66 builder[4] = imageBounds.fBottom;
bsalomon466c2c42015-10-16 12:01:18 -070067}
68
bsalomon045802d2015-10-20 07:58:01 -070069//////////////////////////////////////////////////////////////////////////////
Robert Phillips1afd4cd2018-01-08 13:40:32 -050070sk_sp<GrTextureProxy> GrUploadBitmapToTextureProxy(GrProxyProvider* proxyProvider,
Matt Sarettdedac852017-05-12 10:56:49 -040071 const SkBitmap& bitmap,
72 SkColorSpace* dstColorSpace) {
Greg Daniel7619b642018-02-08 15:32:02 -050073 if (!bitmap.peekPixels(nullptr)) {
Brian Osman4075ec82017-01-17 16:41:03 +000074 return nullptr;
75 }
Greg Daniel7619b642018-02-08 15:32:02 -050076
77 SkDestinationSurfaceColorMode colorMode = dstColorSpace
78 ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware
79 : SkDestinationSurfaceColorMode::kLegacy;
80
81 if (!SkImageInfoIsValid(bitmap.info(), colorMode)) {
Robert Phillipsd3749482017-03-14 09:17:43 -040082 return nullptr;
83 }
Greg Daniel7619b642018-02-08 15:32:02 -050084
85 // In non-ddl we will always instantiate right away. Thus we never want to copy the SkBitmap
86 // even if it's mutable. In ddl, if the bitmap is mutable then we must make a copy since the
87 // upload of the data to the gpu can happen at anytime and the bitmap may change by then.
88 SkCopyPixelsMode cpyMode = proxyProvider->mutableBitmapsNeedCopy() ? kIfMutable_SkCopyPixelsMode
89 : kNever_SkCopyPixelsMode;
90 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, cpyMode);
91
92 return proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags,
93 kTopLeft_GrSurfaceOrigin, 1, SkBudgeted::kYes,
94 SkBackingFit::kExact);
Robert Phillipsd3749482017-03-14 09:17:43 -040095}
Brian Osman4075ec82017-01-17 16:41:03 +000096
bsalomon045802d2015-10-20 07:58:01 -070097////////////////////////////////////////////////////////////////////////////////
98
bsalomonc55271f2015-11-09 11:55:57 -080099void GrInstallBitmapUniqueKeyInvalidator(const GrUniqueKey& key, SkPixelRef* pixelRef) {
bsalomon89fe56b2015-10-29 10:49:28 -0700100 class Invalidator : public SkPixelRef::GenIDChangeListener {
101 public:
102 explicit Invalidator(const GrUniqueKey& key) : fMsg(key) {}
103 private:
104 GrUniqueKeyInvalidatedMessage fMsg;
105
106 void onChange() override { SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); }
107 };
108
109 pixelRef->addGenIDChangeListener(new Invalidator(key));
110}
111
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500112sk_sp<GrTextureProxy> GrCopyBaseMipMapToTextureProxy(GrContext* ctx, GrTextureProxy* baseProxy) {
Greg Daniel55afd6d2017-09-29 09:32:44 -0400113 SkASSERT(baseProxy);
114
Greg Danielbb76ace2017-09-29 15:58:22 -0400115 if (!ctx->caps()->isConfigCopyable(baseProxy->config())) {
116 return nullptr;
117 }
118
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500119 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
Greg Daniel55afd6d2017-09-29 09:32:44 -0400120 GrSurfaceDesc desc;
121 desc.fFlags = kNone_GrSurfaceFlags;
122 desc.fOrigin = baseProxy->origin();
123 desc.fWidth = baseProxy->width();
124 desc.fHeight = baseProxy->height();
125 desc.fConfig = baseProxy->config();
Brian Salomonbdecacf2018-02-02 20:32:49 -0500126 desc.fSampleCnt = 1;
Greg Daniel55afd6d2017-09-29 09:32:44 -0400127
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500128 sk_sp<GrTextureProxy> proxy = proxyProvider->createMipMapProxy(desc, SkBudgeted::kYes);
Greg Daniel55afd6d2017-09-29 09:32:44 -0400129 if (!proxy) {
130 return nullptr;
131 }
132
133 // Copy the base layer to our proxy
Brian Salomon366093f2018-02-13 09:25:22 -0500134 sk_sp<SkColorSpace> colorSpace;
135 if (GrPixelConfigIsSRGB(proxy->config())) {
136 colorSpace = SkColorSpace::MakeSRGB();
137 }
138 sk_sp<GrSurfaceContext> sContext =
139 ctx->contextPriv().makeWrappedSurfaceContext(proxy, std::move(colorSpace));
Greg Daniel55afd6d2017-09-29 09:32:44 -0400140 SkASSERT(sContext);
141 SkAssertResult(sContext->copy(baseProxy));
142
143 return proxy;
144}
145
Robert Phillipsbbd7a3b2017-03-21 08:48:40 -0400146sk_sp<GrTextureProxy> GrRefCachedBitmapTextureProxy(GrContext* ctx,
147 const SkBitmap& bitmap,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400148 const GrSamplerState& params,
Robert Phillipsbbd7a3b2017-03-21 08:48:40 -0400149 SkScalar scaleAdjust[2]) {
150 // Caller doesn't care about the texture's color space (they can always get it from the bitmap)
Robert Phillips3798c862017-03-27 11:08:16 -0400151 return GrBitmapTextureMaker(ctx, bitmap).refTextureProxyForParams(params, nullptr,
152 nullptr, scaleAdjust);
Robert Phillipsbbd7a3b2017-03-21 08:48:40 -0400153}
154
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500155sk_sp<GrTextureProxy> GrMakeCachedBitmapProxy(GrProxyProvider* proxyProvider,
Greg Daniel7e1912a2018-02-08 09:15:33 -0500156 const SkBitmap& bitmap,
157 SkBackingFit fit) {
158 if (!bitmap.peekPixels(nullptr)) {
159 return nullptr;
Robert Phillipse14d3052017-02-15 13:18:21 -0500160 }
161
Greg Daniel7e1912a2018-02-08 09:15:33 -0500162 // In non-ddl we will always instantiate right away. Thus we never want to copy the SkBitmap
163 // even if its mutable. In ddl, if the bitmap is mutable then we must make a copy since the
164 // upload of the data to the gpu can happen at anytime and the bitmap may change by then.
165 SkCopyPixelsMode cpyMode = proxyProvider->mutableBitmapsNeedCopy() ? kIfMutable_SkCopyPixelsMode
166 : kNever_SkCopyPixelsMode;
167 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, cpyMode);
Robert Phillipse14d3052017-02-15 13:18:21 -0500168
Greg Daniel7e1912a2018-02-08 09:15:33 -0500169 if (!image) {
170 return nullptr;
Robert Phillipse14d3052017-02-15 13:18:21 -0500171 }
172
Greg Daniel7e1912a2018-02-08 09:15:33 -0500173 return GrMakeCachedImageProxy(proxyProvider, std::move(image), fit);
Robert Phillipse14d3052017-02-15 13:18:21 -0500174}
175
Robert Phillips7a926392018-02-01 15:49:54 -0500176static void create_unique_key_for_image(const SkImage* image, GrUniqueKey* result) {
177 if (!image) {
178 result->reset(); // will be invalid
179 return;
180 }
181
182 if (const SkBitmap* bm = as_IB(image)->onPeekBitmap()) {
183 SkIPoint origin = bm->pixelRefOrigin();
184 SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, bm->width(), bm->height());
185 GrMakeKeyFromImageID(result, bm->getGenerationID(), subset);
186 return;
187 }
188
189 GrMakeKeyFromImageID(result, image->uniqueID(), image->bounds());
190}
191
192sk_sp<GrTextureProxy> GrMakeCachedImageProxy(GrProxyProvider* proxyProvider,
Greg Daniel490695b2018-02-05 09:34:02 -0500193 sk_sp<SkImage> srcImage,
194 SkBackingFit fit) {
Robert Phillips7a926392018-02-01 15:49:54 -0500195 sk_sp<GrTextureProxy> proxy;
196 GrUniqueKey originalKey;
197
198 create_unique_key_for_image(srcImage.get(), &originalKey);
199
200 if (originalKey.isValid()) {
201 proxy = proxyProvider->findOrCreateProxyByUniqueKey(originalKey, kTopLeft_GrSurfaceOrigin);
202 }
203 if (!proxy) {
204 proxy = proxyProvider->createTextureProxy(std::move(srcImage), kNone_GrSurfaceFlags,
Brian Salomonbdecacf2018-02-02 20:32:49 -0500205 kTopLeft_GrSurfaceOrigin, 1, SkBudgeted::kYes,
Greg Daniel490695b2018-02-05 09:34:02 -0500206 fit);
Robert Phillips7a926392018-02-01 15:49:54 -0500207 if (proxy && originalKey.isValid()) {
208 proxyProvider->assignUniqueKeyToProxy(originalKey, proxy.get());
209 }
210 }
211
212 return proxy;
213}
214
rileya@google.com24f3ad12012-07-18 21:47:40 +0000215///////////////////////////////////////////////////////////////////////////////
216
Brian Salomon4cbb6e62017-10-25 15:12:19 -0400217GrColor4f SkColorToPremulGrColor4f(SkColor c, const GrColorSpaceInfo& colorSpaceInfo) {
Brian Osman72ae4312016-10-20 16:53:45 -0400218 // We want to premultiply after linearizing, so this is easy:
Brian Salomon4cbb6e62017-10-25 15:12:19 -0400219 return SkColorToUnpremulGrColor4f(c, colorSpaceInfo).premul();
Brian Osman72ae4312016-10-20 16:53:45 -0400220}
221
Brian Salomon4cbb6e62017-10-25 15:12:19 -0400222GrColor4f SkColorToPremulGrColor4fLegacy(SkColor c) {
223 return GrColor4f::FromGrColor(SkColorToUnpremulGrColor(c)).premul();
Brian Osman72ae4312016-10-20 16:53:45 -0400224}
225
Brian Salomon4cbb6e62017-10-25 15:12:19 -0400226GrColor4f SkColorToUnpremulGrColor4f(SkColor c, const GrColorSpaceInfo& colorSpaceInfo) {
Brian Osmanc68d4aa2016-09-30 11:41:59 -0400227 GrColor4f color;
Brian Salomon4cbb6e62017-10-25 15:12:19 -0400228 if (colorSpaceInfo.colorSpace()) {
Brian Osmanc68d4aa2016-09-30 11:41:59 -0400229 // SkColor4f::FromColor does sRGB -> Linear
230 color = GrColor4f::FromSkColor4f(SkColor4f::FromColor(c));
231 } else {
232 // GrColor4f::FromGrColor just multiplies by 1/255
233 color = GrColor4f::FromGrColor(SkColorToUnpremulGrColor(c));
234 }
235
Brian Salomon4cbb6e62017-10-25 15:12:19 -0400236 if (auto* xform = colorSpaceInfo.colorSpaceXformFromSRGB()) {
237 color = xform->clampedXform(color);
Brian Osmanc68d4aa2016-09-30 11:41:59 -0400238 }
239
240 return color;
241}
242
243///////////////////////////////////////////////////////////////////////////////
244
Greg Daniel81e7bf82017-07-19 14:47:42 -0400245GrPixelConfig SkImageInfo2GrPixelConfig(const SkColorType type, SkColorSpace* cs,
246 const GrCaps& caps) {
Greg Daniel81e7bf82017-07-19 14:47:42 -0400247 switch (type) {
brianosmanc571c002016-03-17 13:01:26 -0700248 case kUnknown_SkColorType:
249 return kUnknown_GrPixelConfig;
250 case kAlpha_8_SkColorType:
251 return kAlpha_8_GrPixelConfig;
252 case kRGB_565_SkColorType:
253 return kRGB_565_GrPixelConfig;
254 case kARGB_4444_SkColorType:
255 return kRGBA_4444_GrPixelConfig;
256 case kRGBA_8888_SkColorType:
Matt Sarettf3880932017-03-24 10:06:03 -0400257 return (caps.srgbSupport() && cs && cs->gammaCloseToSRGB())
brianosmana6359362016-03-21 06:55:37 -0700258 ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig;
Brian Osman9d440812018-01-04 09:35:04 -0500259 // TODO: We're checking for srgbSupport, but we can then end up picking sBGRA as our pixel
260 // config (which may not be supported). We need a better test here.
Brian Salomone41e1762018-01-25 14:07:47 -0500261 case kRGB_888x_SkColorType:
262 return kUnknown_GrPixelConfig;
brianosmanc571c002016-03-17 13:01:26 -0700263 case kBGRA_8888_SkColorType:
Matt Sarettf3880932017-03-24 10:06:03 -0400264 return (caps.srgbSupport() && cs && cs->gammaCloseToSRGB())
brianosmana6359362016-03-21 06:55:37 -0700265 ? kSBGRA_8888_GrPixelConfig : kBGRA_8888_GrPixelConfig;
Brian Salomone41e1762018-01-25 14:07:47 -0500266 case kRGBA_1010102_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -0500267 return kRGBA_1010102_GrPixelConfig;
Brian Salomone41e1762018-01-25 14:07:47 -0500268 case kRGB_101010x_SkColorType:
269 return kUnknown_GrPixelConfig;
brianosmanc571c002016-03-17 13:01:26 -0700270 case kGray_8_SkColorType:
Brian Osman986563b2017-01-10 14:20:02 -0500271 return kGray_8_GrPixelConfig;
brianosmanc571c002016-03-17 13:01:26 -0700272 case kRGBA_F16_SkColorType:
273 return kRGBA_half_GrPixelConfig;
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000274 }
275 SkASSERT(0); // shouldn't get here
276 return kUnknown_GrPixelConfig;
277}
278
Greg Daniel81e7bf82017-07-19 14:47:42 -0400279GrPixelConfig SkImageInfo2GrPixelConfig(const SkImageInfo& info, const GrCaps& caps) {
280 return SkImageInfo2GrPixelConfig(info.colorType(), info.colorSpace(), caps);
281}
282
brianosman396fcdb2016-07-22 06:26:11 -0700283bool GrPixelConfigToColorType(GrPixelConfig config, SkColorType* ctOut) {
reed@google.combf790232013-12-13 19:45:58 +0000284 SkColorType ct;
285 switch (config) {
Greg Danielef59d872017-11-17 16:47:21 -0500286 case kAlpha_8_GrPixelConfig: // fall through
287 case kAlpha_8_as_Alpha_GrPixelConfig: // fall through
288 case kAlpha_8_as_Red_GrPixelConfig:
reed@google.combf790232013-12-13 19:45:58 +0000289 ct = kAlpha_8_SkColorType;
290 break;
Greg Daniel7af060a2017-12-05 16:27:11 -0500291 case kGray_8_GrPixelConfig: // fall through
292 case kGray_8_as_Lum_GrPixelConfig: // fall through
293 case kGray_8_as_Red_GrPixelConfig:
Brian Osman986563b2017-01-10 14:20:02 -0500294 ct = kGray_8_SkColorType;
295 break;
reed@google.combf790232013-12-13 19:45:58 +0000296 case kRGB_565_GrPixelConfig:
297 ct = kRGB_565_SkColorType;
298 break;
299 case kRGBA_4444_GrPixelConfig:
300 ct = kARGB_4444_SkColorType;
301 break;
302 case kRGBA_8888_GrPixelConfig:
303 ct = kRGBA_8888_SkColorType;
304 break;
305 case kBGRA_8888_GrPixelConfig:
306 ct = kBGRA_8888_SkColorType;
307 break;
jvanverthfa1e8a72014-12-22 08:31:49 -0800308 case kSRGBA_8888_GrPixelConfig:
309 ct = kRGBA_8888_SkColorType;
jvanverthfa1e8a72014-12-22 08:31:49 -0800310 break;
brianosmana6359362016-03-21 06:55:37 -0700311 case kSBGRA_8888_GrPixelConfig:
312 ct = kBGRA_8888_SkColorType;
brianosmana6359362016-03-21 06:55:37 -0700313 break;
Brian Osman10fc6fd2018-03-02 11:01:10 -0500314 case kRGBA_1010102_GrPixelConfig:
315 ct = kRGBA_1010102_SkColorType;
316 break;
brianosman9ac5b912016-04-12 13:49:53 -0700317 case kRGBA_half_GrPixelConfig:
318 ct = kRGBA_F16_SkColorType;
319 break;
reed@google.combf790232013-12-13 19:45:58 +0000320 default:
321 return false;
322 }
323 if (ctOut) {
324 *ctOut = ct;
325 }
326 return true;
327}
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000328
brianosman27a3aa52016-09-23 07:11:34 -0700329GrPixelConfig GrRenderableConfigForColorSpace(const SkColorSpace* colorSpace) {
Matt Sarettf3880932017-03-24 10:06:03 -0400330 if (!colorSpace) {
brianosman2695eaa2016-09-21 06:45:09 -0700331 return kRGBA_8888_GrPixelConfig;
332 } else if (colorSpace->gammaIsLinear()) {
333 return kRGBA_half_GrPixelConfig;
334 } else if (colorSpace->gammaCloseToSRGB()) {
335 return kSRGBA_8888_GrPixelConfig;
336 } else {
337 SkDEBUGFAIL("No renderable config exists for color space with strange gamma");
338 return kUnknown_GrPixelConfig;
339 }
340}
341
bsalomonf1b7a1d2015-09-28 06:26:28 -0700342////////////////////////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000343
Mike Reed185ba212017-04-28 12:31:05 -0400344static inline bool blend_requires_shader(const SkBlendMode mode) {
345 return SkBlendMode::kDst != mode;
bsalomonaa48d362015-10-01 08:34:17 -0700346}
347
bsalomonf1b7a1d2015-09-28 06:26:28 -0700348static inline bool skpaint_to_grpaint_impl(GrContext* context,
Brian Salomonf3569f02017-10-24 12:52:33 -0400349 const GrColorSpaceInfo& colorSpaceInfo,
bsalomonf1b7a1d2015-09-28 06:26:28 -0700350 const SkPaint& skPaint,
351 const SkMatrix& viewM,
Brian Salomonaff329b2017-08-11 09:40:37 -0400352 std::unique_ptr<GrFragmentProcessor>* shaderProcessor,
Mike Reed7d954ad2016-10-28 15:42:34 -0400353 SkBlendMode* primColorMode,
bsalomonf1b7a1d2015-09-28 06:26:28 -0700354 GrPaint* grPaint) {
Brian Salomonf3569f02017-10-24 12:52:33 -0400355 grPaint->setAllowSRGBInputs(colorSpaceInfo.isGammaCorrect());
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000356
Brian Osmanc68d4aa2016-09-30 11:41:59 -0400357 // Convert SkPaint color to 4f format, including optional linearizing and gamut conversion.
Brian Salomon4cbb6e62017-10-25 15:12:19 -0400358 GrColor4f origColor = SkColorToUnpremulGrColor4f(skPaint.getColor(), colorSpaceInfo);
brianosmana4535a32016-06-24 12:50:19 -0700359
Mike Reed3bc266b2018-01-20 22:24:41 +0000360 const GrFPArgs fpArgs(context, &viewM, skPaint.getFilterQuality(), &colorSpaceInfo);
Mike Reedbfadcf02018-01-20 22:24:21 +0000361
bsalomonf1b7a1d2015-09-28 06:26:28 -0700362 // Setup the initial color considering the shader, the SkPaint color, and the presence or not
363 // of per-vertex colors.
Brian Salomonaff329b2017-08-11 09:40:37 -0400364 std::unique_ptr<GrFragmentProcessor> shaderFP;
Mike Reed185ba212017-04-28 12:31:05 -0400365 if (!primColorMode || blend_requires_shader(*primColorMode)) {
bsalomonaa48d362015-10-01 08:34:17 -0700366 if (shaderProcessor) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400367 shaderFP = std::move(*shaderProcessor);
Florin Malita4aed1382017-05-25 10:38:07 -0400368 } else if (const auto* shader = as_SB(skPaint.getShader())) {
Mike Reedbfadcf02018-01-20 22:24:21 +0000369 shaderFP = shader->asFragmentProcessor(fpArgs);
Yuqian Liaad2ec62018-02-26 10:34:52 -0500370 if (!shaderFP) {
371 return false;
372 }
bsalomonf1b7a1d2015-09-28 06:26:28 -0700373 }
374 }
375
376 // Set this in below cases if the output of the shader/paint-color/paint-alpha/primXfermode is
377 // a known constant value. In that case we can simply apply a color filter during this
378 // conversion without converting the color filter to a GrFragmentProcessor.
379 bool applyColorFilterToPaintColor = false;
380 if (shaderFP) {
381 if (primColorMode) {
382 // There is a blend between the primitive color and the shader color. The shader sees
383 // the opaque paint color. The shader's output is blended using the provided mode by
384 // the primitive color. The blended color is then modulated by the paint's alpha.
385
386 // The geometry processor will insert the primitive color to start the color chain, so
387 // the GrPaint color will be ignored.
388
brianosman4cea3b92016-09-08 09:33:50 -0700389 GrColor4f shaderInput = origColor.opaque();
Brian Salomonaff329b2017-08-11 09:40:37 -0400390 shaderFP = GrFragmentProcessor::OverrideInput(std::move(shaderFP), shaderInput);
Mike Reed185ba212017-04-28 12:31:05 -0400391 shaderFP = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(shaderFP),
392 *primColorMode);
393
bsalomonf1b7a1d2015-09-28 06:26:28 -0700394 // The above may return null if compose results in a pass through of the prim color.
395 if (shaderFP) {
Robert Phillips1c9686b2017-06-30 08:40:28 -0400396 grPaint->addColorFragmentProcessor(std::move(shaderFP));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700397 }
398
brianosmana4535a32016-06-24 12:50:19 -0700399 // We can ignore origColor here - alpha is unchanged by gamma
bsalomonf1b7a1d2015-09-28 06:26:28 -0700400 GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor());
401 if (GrColor_WHITE != paintAlpha) {
Brian Osman618d3042016-10-25 10:51:28 -0400402 // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
403 // color channels. It's value should be treated as the same in ANY color space.
bungeman06ca8ec2016-06-09 08:01:03 -0700404 grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make(
Brian Osman618d3042016-10-25 10:51:28 -0400405 GrColor4f::FromGrColor(paintAlpha),
Ethan Nicholase9d172a2017-11-20 12:12:24 -0500406 GrConstColorProcessor::InputMode::kModulateRGBA));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700407 }
408 } else {
409 // The shader's FP sees the paint unpremul color
brianosmana4535a32016-06-24 12:50:19 -0700410 grPaint->setColor4f(origColor);
bungeman06ca8ec2016-06-09 08:01:03 -0700411 grPaint->addColorFragmentProcessor(std::move(shaderFP));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700412 }
413 } else {
414 if (primColorMode) {
415 // There is a blend between the primitive color and the paint color. The blend considers
416 // the opaque paint color. The paint's alpha is applied to the post-blended color.
Brian Salomonaff329b2017-08-11 09:40:37 -0400417 auto processor = GrConstColorProcessor::Make(origColor.opaque(),
Ethan Nicholase9d172a2017-11-20 12:12:24 -0500418 GrConstColorProcessor::InputMode::kIgnore);
Mike Reed185ba212017-04-28 12:31:05 -0400419 processor = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(processor),
420 *primColorMode);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700421 if (processor) {
bungeman06ca8ec2016-06-09 08:01:03 -0700422 grPaint->addColorFragmentProcessor(std::move(processor));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700423 }
424
brianosmana4535a32016-06-24 12:50:19 -0700425 grPaint->setColor4f(origColor.opaque());
bsalomonf1b7a1d2015-09-28 06:26:28 -0700426
brianosmana4535a32016-06-24 12:50:19 -0700427 // We can ignore origColor here - alpha is unchanged by gamma
bsalomonf1b7a1d2015-09-28 06:26:28 -0700428 GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor());
bsalomonaa48d362015-10-01 08:34:17 -0700429 if (GrColor_WHITE != paintAlpha) {
Brian Osman618d3042016-10-25 10:51:28 -0400430 // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
431 // color channels. It's value should be treated as the same in ANY color space.
bungeman06ca8ec2016-06-09 08:01:03 -0700432 grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make(
Brian Osman618d3042016-10-25 10:51:28 -0400433 GrColor4f::FromGrColor(paintAlpha),
Ethan Nicholase9d172a2017-11-20 12:12:24 -0500434 GrConstColorProcessor::InputMode::kModulateRGBA));
bsalomonaa48d362015-10-01 08:34:17 -0700435 }
bsalomonf1b7a1d2015-09-28 06:26:28 -0700436 } else {
437 // No shader, no primitive color.
brianosmana4535a32016-06-24 12:50:19 -0700438 grPaint->setColor4f(origColor.premul());
bsalomonf1b7a1d2015-09-28 06:26:28 -0700439 applyColorFilterToPaintColor = true;
440 }
441 }
442
443 SkColorFilter* colorFilter = skPaint.getColorFilter();
444 if (colorFilter) {
445 if (applyColorFilterToPaintColor) {
Brian Osman8bf4e672016-10-17 16:54:49 -0400446 // If we're in legacy mode, we *must* avoid using the 4f version of the color filter,
447 // because that will combine with the linearized version of the stored color.
Brian Salomonf3569f02017-10-24 12:52:33 -0400448 if (colorSpaceInfo.isGammaCorrect()) {
Brian Osman8bf4e672016-10-17 16:54:49 -0400449 grPaint->setColor4f(GrColor4f::FromSkColor4f(
450 colorFilter->filterColor4f(origColor.toSkColor4f())).premul());
451 } else {
Brian Salomon4cbb6e62017-10-25 15:12:19 -0400452 grPaint->setColor4f(SkColorToPremulGrColor4fLegacy(
453 colorFilter->filterColor(skPaint.getColor())));
Brian Osman8bf4e672016-10-17 16:54:49 -0400454 }
bsalomonf1b7a1d2015-09-28 06:26:28 -0700455 } else {
Brian Salomon4cbb6e62017-10-25 15:12:19 -0400456 auto cfFP = colorFilter->asFragmentProcessor(context, colorSpaceInfo);
bsalomone25eea42015-09-29 06:38:55 -0700457 if (cfFP) {
bungeman06ca8ec2016-06-09 08:01:03 -0700458 grPaint->addColorFragmentProcessor(std::move(cfFP));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700459 } else {
460 return false;
461 }
462 }
463 }
464
Mike Reed80747ef2018-01-23 15:29:32 -0500465 SkMaskFilterBase* maskFilter = as_MFB(skPaint.getMaskFilter());
Robert Phillipsa29a9562016-10-20 09:40:55 -0400466 if (maskFilter) {
Mike Reedbfadcf02018-01-20 22:24:21 +0000467 if (auto mfFP = maskFilter->asFragmentProcessor(fpArgs)) {
468 grPaint->addCoverageFragmentProcessor(std::move(mfFP));
Robert Phillipsa29a9562016-10-20 09:40:55 -0400469 }
470 }
471
robertphillips4f037942016-02-09 05:09:27 -0800472 // When the xfermode is null on the SkPaint (meaning kSrcOver) we need the XPFactory field on
473 // the GrPaint to also be null (also kSrcOver).
474 SkASSERT(!grPaint->getXPFactory());
reed374772b2016-10-05 17:33:02 -0700475 if (!skPaint.isSrcOver()) {
476 grPaint->setXPFactory(SkBlendMode_AsXPFactory(skPaint.getBlendMode()));
robertphillips4f037942016-02-09 05:09:27 -0800477 }
mtklein775b8192014-12-02 09:11:25 -0800478
krajcevskif461a8f2014-06-19 14:14:06 -0700479#ifndef SK_IGNORE_GPU_DITHER
Florin Malitad4a70ee2017-06-19 10:21:43 -0400480 // Conservative default, in case GrPixelConfigToColorType() fails.
481 SkColorType ct = SkColorType::kRGB_565_SkColorType;
Brian Salomonf3569f02017-10-24 12:52:33 -0400482 GrPixelConfigToColorType(colorSpaceInfo.config(), &ct);
483 if (SkPaintPriv::ShouldDither(skPaint, ct) && grPaint->numColorFragmentProcessors() > 0 &&
484 !colorSpaceInfo.isGammaCorrect()) {
485 auto ditherFP = GrDitherEffect::Make(colorSpaceInfo.config());
Brian Salomon0c15ae82017-07-19 15:39:56 +0000486 if (ditherFP) {
487 grPaint->addColorFragmentProcessor(std::move(ditherFP));
488 }
krajcevskif461a8f2014-06-19 14:14:06 -0700489 }
490#endif
bsalomonbed83a62015-04-15 14:18:34 -0700491 return true;
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000492}
493
Brian Salomonf3569f02017-10-24 12:52:33 -0400494bool SkPaintToGrPaint(GrContext* context, const GrColorSpaceInfo& colorSpaceInfo,
495 const SkPaint& skPaint, const SkMatrix& viewM, GrPaint* grPaint) {
496 return skpaint_to_grpaint_impl(context, colorSpaceInfo, skPaint, viewM, nullptr, nullptr,
497 grPaint);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700498}
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000499
bsalomonf1b7a1d2015-09-28 06:26:28 -0700500/** Replaces the SkShader (if any) on skPaint with the passed in GrFragmentProcessor. */
501bool SkPaintToGrPaintReplaceShader(GrContext* context,
Brian Salomonf3569f02017-10-24 12:52:33 -0400502 const GrColorSpaceInfo& colorSpaceInfo,
bsalomonf1b7a1d2015-09-28 06:26:28 -0700503 const SkPaint& skPaint,
Brian Salomonaff329b2017-08-11 09:40:37 -0400504 std::unique_ptr<GrFragmentProcessor> shaderFP,
bsalomonf1b7a1d2015-09-28 06:26:28 -0700505 GrPaint* grPaint) {
506 if (!shaderFP) {
bsalomonc21b09e2015-08-28 18:46:56 -0700507 return false;
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000508 }
Brian Salomonf3569f02017-10-24 12:52:33 -0400509 return skpaint_to_grpaint_impl(context, colorSpaceInfo, skPaint, SkMatrix::I(), &shaderFP,
510 nullptr, grPaint);
commit-bot@chromium.org8dcff642014-05-15 20:32:48 +0000511}
reed8b26b992015-05-07 15:36:17 -0700512
bsalomonf1b7a1d2015-09-28 06:26:28 -0700513/** Ignores the SkShader (if any) on skPaint. */
514bool SkPaintToGrPaintNoShader(GrContext* context,
Brian Salomonf3569f02017-10-24 12:52:33 -0400515 const GrColorSpaceInfo& colorSpaceInfo,
bsalomonf1b7a1d2015-09-28 06:26:28 -0700516 const SkPaint& skPaint,
517 GrPaint* grPaint) {
518 // Use a ptr to a nullptr to to indicate that the SkShader is ignored and not replaced.
Brian Salomonaff329b2017-08-11 09:40:37 -0400519 static std::unique_ptr<GrFragmentProcessor> kNullShaderFP(nullptr);
520 static std::unique_ptr<GrFragmentProcessor>* kIgnoreShader = &kNullShaderFP;
Brian Salomonf3569f02017-10-24 12:52:33 -0400521 return skpaint_to_grpaint_impl(context, colorSpaceInfo, skPaint, SkMatrix::I(), kIgnoreShader,
522 nullptr, grPaint);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700523}
524
525/** Blends the SkPaint's shader (or color if no shader) with a per-primitive color which must
Mike Reed7d954ad2016-10-28 15:42:34 -0400526be setup as a vertex attribute using the specified SkBlendMode. */
bsalomonf1b7a1d2015-09-28 06:26:28 -0700527bool SkPaintToGrPaintWithXfermode(GrContext* context,
Brian Salomonf3569f02017-10-24 12:52:33 -0400528 const GrColorSpaceInfo& colorSpaceInfo,
bsalomonf1b7a1d2015-09-28 06:26:28 -0700529 const SkPaint& skPaint,
530 const SkMatrix& viewM,
Mike Reed7d954ad2016-10-28 15:42:34 -0400531 SkBlendMode primColorMode,
bsalomonf1b7a1d2015-09-28 06:26:28 -0700532 GrPaint* grPaint) {
Brian Salomonf3569f02017-10-24 12:52:33 -0400533 return skpaint_to_grpaint_impl(context, colorSpaceInfo, skPaint, viewM, nullptr, &primColorMode,
Mike Reed185ba212017-04-28 12:31:05 -0400534 grPaint);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700535}
536
joshualitt33a5fce2015-11-18 13:28:51 -0800537bool SkPaintToGrPaintWithTexture(GrContext* context,
Brian Salomonf3569f02017-10-24 12:52:33 -0400538 const GrColorSpaceInfo& colorSpaceInfo,
joshualitt33a5fce2015-11-18 13:28:51 -0800539 const SkPaint& paint,
540 const SkMatrix& viewM,
Brian Salomonaff329b2017-08-11 09:40:37 -0400541 std::unique_ptr<GrFragmentProcessor> fp,
joshualitt33a5fce2015-11-18 13:28:51 -0800542 bool textureIsAlphaOnly,
543 GrPaint* grPaint) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400544 std::unique_ptr<GrFragmentProcessor> shaderFP;
joshualitt33a5fce2015-11-18 13:28:51 -0800545 if (textureIsAlphaOnly) {
Florin Malita4aed1382017-05-25 10:38:07 -0400546 if (const auto* shader = as_SB(paint.getShader())) {
Mike Reede3429e62018-01-19 11:43:34 -0500547 shaderFP = shader->asFragmentProcessor(GrFPArgs(
Brian Salomon4cbb6e62017-10-25 15:12:19 -0400548 context, &viewM, nullptr, paint.getFilterQuality(), &colorSpaceInfo));
joshualitt33a5fce2015-11-18 13:28:51 -0800549 if (!shaderFP) {
550 return false;
551 }
Brian Salomonaff329b2017-08-11 09:40:37 -0400552 std::unique_ptr<GrFragmentProcessor> fpSeries[] = { std::move(shaderFP), std::move(fp) };
bungeman06ca8ec2016-06-09 08:01:03 -0700553 shaderFP = GrFragmentProcessor::RunInSeries(fpSeries, 2);
joshualitt33a5fce2015-11-18 13:28:51 -0800554 } else {
Brian Salomonaff329b2017-08-11 09:40:37 -0400555 shaderFP = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp));
joshualitt33a5fce2015-11-18 13:28:51 -0800556 }
557 } else {
Mike Reed28eaed22018-02-01 11:24:53 -0500558 shaderFP = GrFragmentProcessor::MulChildByInputAlpha(std::move(fp));
joshualitt33a5fce2015-11-18 13:28:51 -0800559 }
560
Brian Salomonf3569f02017-10-24 12:52:33 -0400561 return SkPaintToGrPaintReplaceShader(context, colorSpaceInfo, paint, std::move(shaderFP),
562 grPaint);
joshualitt33a5fce2015-11-18 13:28:51 -0800563}
564
bsalomonf1b7a1d2015-09-28 06:26:28 -0700565
566////////////////////////////////////////////////////////////////////////////////////////////////
567
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400568GrSamplerState::Filter GrSkFilterQualityToGrFilterMode(SkFilterQuality paintFilterQuality,
569 const SkMatrix& viewM,
570 const SkMatrix& localM,
Brian Osmandb78cba2018-02-15 10:09:48 -0500571 bool sharpenMipmappedTextures,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400572 bool* doBicubic) {
joshualitt9bc39542015-08-12 12:57:54 -0700573 *doBicubic = false;
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400574 GrSamplerState::Filter textureFilterMode;
joshualitt9bc39542015-08-12 12:57:54 -0700575 switch (paintFilterQuality) {
576 case kNone_SkFilterQuality:
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400577 textureFilterMode = GrSamplerState::Filter::kNearest;
joshualitt9bc39542015-08-12 12:57:54 -0700578 break;
579 case kLow_SkFilterQuality:
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400580 textureFilterMode = GrSamplerState::Filter::kBilerp;
joshualitt9bc39542015-08-12 12:57:54 -0700581 break;
582 case kMedium_SkFilterQuality: {
583 SkMatrix matrix;
584 matrix.setConcat(viewM, localM);
Brian Osmandb78cba2018-02-15 10:09:48 -0500585 // With sharp mips, we bias lookups by -0.5. That means our final LOD is >= 0 until the
586 // computed LOD is >= 0.5. At what scale factor does a texture get an LOD of 0.5?
587 //
588 // Want: 0 = log2(1/s) - 0.5
589 // 0.5 = log2(1/s)
590 // 2^0.5 = 1/s
591 // 1/2^0.5 = s
592 // 2^0.5/2 = s
593 SkScalar mipScale = sharpenMipmappedTextures ? SK_ScalarRoot2Over2 : SK_Scalar1;
594 if (matrix.getMinScale() < mipScale) {
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400595 textureFilterMode = GrSamplerState::Filter::kMipMap;
joshualitt9bc39542015-08-12 12:57:54 -0700596 } else {
597 // Don't trigger MIP level generation unnecessarily.
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400598 textureFilterMode = GrSamplerState::Filter::kBilerp;
joshualitt9bc39542015-08-12 12:57:54 -0700599 }
600 break;
601 }
602 case kHigh_SkFilterQuality: {
603 SkMatrix matrix;
604 matrix.setConcat(viewM, localM);
605 *doBicubic = GrBicubicEffect::ShouldUseBicubic(matrix, &textureFilterMode);
606 break;
607 }
608 default:
Mike Kleine54c75f2016-10-13 14:18:09 -0400609 // Should be unreachable. If not, fall back to mipmaps.
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400610 textureFilterMode = GrSamplerState::Filter::kMipMap;
joshualitt9bc39542015-08-12 12:57:54 -0700611 break;
612
613 }
614 return textureFilterMode;
615}