blob: ae16a4957e96317564288b2cefb56e9409cabaf3 [file] [log] [blame]
joshualittac977922014-07-22 09:52:11 -07001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Mike Kleinc0bd9f92019-04-23 12:05:21 -05007#include "src/gpu/effects/GrMatrixConvolutionEffect.h"
Robert Phillips296b1cc2017-03-15 10:42:12 -04008
Adlai Holler00ddb002020-05-11 19:25:52 -04009#include "include/private/SkHalf.h"
Adlai Hollera0693042020-10-14 11:23:11 -040010#include "src/gpu/GrDirectContextPriv.h"
Adlai Holler00ddb002020-05-11 19:25:52 -040011#include "src/gpu/GrProxyProvider.h"
12#include "src/gpu/GrRecordingContextPriv.h"
Greg Daniel456f9b52020-03-05 19:14:18 +000013#include "src/gpu/GrTexture.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040014#include "src/gpu/GrTextureProxy.h"
Robert Phillipsd464feb2020-10-08 11:00:02 -040015#include "src/gpu/GrThreadSafeCache.h"
Brian Salomon27c42022021-04-28 12:39:21 -040016#include "src/gpu/SkGr.h"
Brian Salomon694ec492020-04-14 13:39:31 -040017#include "src/gpu/effects/GrTextureEffect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
19#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
20#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
21#include "src/gpu/glsl/GrGLSLUniformHandler.h"
joshualittac977922014-07-22 09:52:11 -070022
Brian Salomonb25560a2021-08-10 13:56:13 -040023class GrMatrixConvolutionEffect::Impl : public ProgramImpl {
joshualittac977922014-07-22 09:52:11 -070024public:
robertphillips9cdb9922016-02-03 12:25:40 -080025 void emitCode(EmitArgs&) override;
joshualittac977922014-07-22 09:52:11 -070026
Brian Salomonb25560a2021-08-10 13:56:13 -040027private:
Brian Salomonab015ef2017-04-04 10:15:51 -040028 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
joshualittac977922014-07-22 09:52:11 -070029
egdaniel018fb622015-10-28 07:26:40 -070030 typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
joshualittac977922014-07-22 09:52:11 -070031
Adlai Holler00ddb002020-05-11 19:25:52 -040032 void emitKernelBlock(EmitArgs&, SkIPoint);
33
joshualitt5ae5fc52014-07-29 12:59:27 -070034 UniformHandle fKernelUni;
joshualitt5ae5fc52014-07-29 12:59:27 -070035 UniformHandle fKernelOffsetUni;
36 UniformHandle fGainUni;
37 UniformHandle fBiasUni;
Adlai Holler00ddb002020-05-11 19:25:52 -040038 UniformHandle fKernelBiasUni;
joshualittac977922014-07-22 09:52:11 -070039
Brian Salomon3176e862021-08-09 11:23:04 -040040 using INHERITED = ProgramImpl;
joshualittac977922014-07-22 09:52:11 -070041};
42
Brian Salomon1b0b0042020-06-12 15:15:50 -040043GrMatrixConvolutionEffect::KernelWrapper::MakeResult
Robert Phillipsf3fc25e2020-09-30 15:24:21 -040044GrMatrixConvolutionEffect::KernelWrapper::Make(GrRecordingContext* rContext,
Brian Salomon1b0b0042020-06-12 15:15:50 -040045 SkISize size,
46 const GrCaps& caps,
47 const SkScalar* values) {
Robert Phillipsf3fc25e2020-09-30 15:24:21 -040048 if (!rContext || !values || size.isEmpty()) {
Adlai Holler00ddb002020-05-11 19:25:52 -040049 return {};
50 }
Robert Phillipsf3fc25e2020-09-30 15:24:21 -040051
Adlai Holler00ddb002020-05-11 19:25:52 -040052 const int length = size.area();
53 // Small kernel -> just fill the array.
54 KernelWrapper result(size);
55 if (length <= kMaxUniformSize) {
56 for (int i = 0; i < length; i++) {
57 result.fArray[i] = SkScalarToFloat(values[i]);
58 }
Brian Salomon1b0b0042020-06-12 15:15:50 -040059 return {result, nullptr};
Adlai Holler00ddb002020-05-11 19:25:52 -040060 }
61
Brian Salomon1b0b0042020-06-12 15:15:50 -040062 BiasAndGain& scalableSampler = result.fBiasAndGain;
Adlai Holler00ddb002020-05-11 19:25:52 -040063 bool useA16 =
Robert Phillipsf3fc25e2020-09-30 15:24:21 -040064 rContext->defaultBackendFormat(kA16_float_SkColorType, GrRenderable::kNo).isValid();
Adlai Holler00ddb002020-05-11 19:25:52 -040065 SkScalar min = values[0];
66 if (!useA16) {
67 // Determine min and max values to figure out inner gain & bias.
68 SkScalar max = values[0];
69 for (int i = 1; i < length; i++) {
70 if (values[i] < min) {
71 min = values[i];
72 }
73 if (values[i] > max) {
74 max = values[i];
75 }
76 }
77 // Treat near-0 gain (i.e. box blur) as 1, and let the kernelBias
78 // move everything up to the final value.
79 const SkScalar computedGain = max - min;
80 scalableSampler.fGain =
81 SkScalarNearlyZero(computedGain) ? 1.0f : SkScalarToFloat(computedGain);
82 // Inner bias is pre-inner-gain so we divide that out.
83 scalableSampler.fBias = SkScalarToFloat(min) / scalableSampler.fGain;
84 }
85
Adlai Hollerdcfb2332020-05-13 15:02:28 -040086 // TODO: Pick cache or dont-cache based on observed perf.
87 static constexpr bool kCacheKernelTexture = true;
Adlai Holler00ddb002020-05-11 19:25:52 -040088
89 GrUniqueKey key;
90 if (kCacheKernelTexture) {
91 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
92 GrUniqueKey::Builder builder(&key, kDomain, length, "Matrix Convolution Kernel");
93 // Texture cache key is the exact content of the kernel.
94 static_assert(sizeof(float) == 4);
95 for (int i = 0; i < length; i++) {
96 builder[i] = *(const uint32_t*)&values[i];
97 }
98 builder.finish();
99 }
100
101 // Find or create a texture.
Robert Phillipsd464feb2020-10-08 11:00:02 -0400102 auto threadSafeCache = rContext->priv().threadSafeCache();
Robert Phillipsf3fc25e2020-09-30 15:24:21 -0400103
Adlai Holler00ddb002020-05-11 19:25:52 -0400104 SkColorType colorType = useA16 ? kA16_float_SkColorType : kAlpha_8_SkColorType;
Robert Phillipsf3fc25e2020-09-30 15:24:21 -0400105
106 GrSurfaceProxyView view;
Robert Phillipsd464feb2020-10-08 11:00:02 -0400107 if (kCacheKernelTexture && (view = threadSafeCache->find(key))) {
Robert Phillipsf3fc25e2020-09-30 15:24:21 -0400108 SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin);
109 auto kernelFP = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType);
110 return {result, std::move(kernelFP)};
111 }
112
113 SkBitmap bm;
114 auto info = SkImageInfo::Make({length, 1}, colorType, kPremul_SkAlphaType, nullptr);
115 if (!bm.tryAllocPixels(info)) {
116 return {};
117 }
118 for (int i = 0; i < length; i++) {
119 if (useA16) {
120 *bm.getAddr16(i, 0) = SkFloatToHalf(values[i]);
121 } else {
122 *bm.getAddr8(i, 0) =
123 SkScalarRoundToInt((values[i] - min) / scalableSampler.fGain * 255);
Adlai Holler00ddb002020-05-11 19:25:52 -0400124 }
125 }
Robert Phillipsf3fc25e2020-09-30 15:24:21 -0400126 bm.setImmutable();
127
Brian Salomon27c42022021-04-28 12:39:21 -0400128 view = std::get<0>(GrMakeUncachedBitmapProxyView(rContext, bm));
Robert Phillipsf3fc25e2020-09-30 15:24:21 -0400129 if (!view) {
130 return {};
131 }
132
133 if (kCacheKernelTexture) {
Robert Phillipsd464feb2020-10-08 11:00:02 -0400134 view = threadSafeCache->add(key, view);
Robert Phillipsf3fc25e2020-09-30 15:24:21 -0400135 }
136
137 SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin);
Brian Salomon1b0b0042020-06-12 15:15:50 -0400138 auto kernelFP = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType);
139 return {result, std::move(kernelFP)};
Adlai Holler00ddb002020-05-11 19:25:52 -0400140}
141
142bool GrMatrixConvolutionEffect::KernelWrapper::operator==(const KernelWrapper& k) const {
143 if (fSize != k.fSize) {
144 return false;
145 } else if (this->isSampled()) {
Brian Salomon1b0b0042020-06-12 15:15:50 -0400146 return fBiasAndGain == k.fBiasAndGain;
Adlai Holler00ddb002020-05-11 19:25:52 -0400147 } else {
148 return std::equal(fArray.begin(), fArray.begin() + fSize.area(), k.fArray.begin());
149 }
150}
151
Brian Salomon1b0b0042020-06-12 15:15:50 -0400152bool GrMatrixConvolutionEffect::KernelWrapper::BiasAndGain::operator==(
153 const BiasAndGain& k) const {
154 return fGain == k.fGain && fBias == k.fBias;
Adlai Holler00ddb002020-05-11 19:25:52 -0400155}
156
157// For sampled kernels, emit a for loop that does all the kernel accumulation.
158// For uniform kernels, emit a single iteration. Function is called repeatedly in a for loop.
159// loc is ignored for sampled kernels.
Brian Salomonb25560a2021-08-10 13:56:13 -0400160void GrMatrixConvolutionEffect::Impl::emitKernelBlock(EmitArgs& args, SkIPoint loc) {
Adlai Holler00ddb002020-05-11 19:25:52 -0400161 const GrMatrixConvolutionEffect& mce = args.fFp.cast<GrMatrixConvolutionEffect>();
162 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
163 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Brian Salomonb25560a2021-08-10 13:56:13 -0400164 int kernelWidth = mce.fKernel.size().width();
165 int kernelHeight = mce.fKernel.size().height();
Adlai Holler00ddb002020-05-11 19:25:52 -0400166 int kernelArea = kernelWidth * kernelHeight;
167
Brian Salomonb25560a2021-08-10 13:56:13 -0400168 if (mce.fKernel.isSampled()) {
Adlai Holler00ddb002020-05-11 19:25:52 -0400169 fragBuilder->codeAppendf("for (int i = 0; i < %d; ++i)", (int)kernelArea);
170 }
171
172 GrGLSLShaderBuilder::ShaderBlock block(fragBuilder);
173
174 fragBuilder->codeAppend("half k;");
175 fragBuilder->codeAppend("half2 sourceOffset;");
Brian Salomonb25560a2021-08-10 13:56:13 -0400176 if (mce.fKernel.isSampled()) {
Adlai Holler00ddb002020-05-11 19:25:52 -0400177 const char* kernelBias = uniformHandler->getUniformCStr(fKernelBiasUni);
John Stilesd1eab8b2020-12-15 09:47:26 -0500178 SkString kernelSample = this->invokeChild(1, args, "float2(float(i) + 0.5, 0.5)");
Brian Salomon1b0b0042020-06-12 15:15:50 -0400179 fragBuilder->codeAppendf("k = %s.w + %s;", kernelSample.c_str(), kernelBias);
John Stilesaf9b58e2021-01-13 17:48:36 -0500180 fragBuilder->codeAppendf("sourceOffset.y = floor(half(i) / %d);", kernelWidth);
181 fragBuilder->codeAppendf("sourceOffset.x = half(i) - sourceOffset.y * %d;", kernelWidth);
Adlai Holler00ddb002020-05-11 19:25:52 -0400182 } else {
183 fragBuilder->codeAppendf("sourceOffset = half2(%d, %d);", loc.x(), loc.y());
184 int offset = loc.y() * kernelWidth + loc.x();
Adlai Holler00ddb002020-05-11 19:25:52 -0400185 const char* kernel = uniformHandler->getUniformCStr(fKernelUni);
John Stilesd1eab8b2020-12-15 09:47:26 -0500186 fragBuilder->codeAppendf("k = %s[%d][%d];", kernel, offset / 4, offset & 0x3);
Adlai Holler00ddb002020-05-11 19:25:52 -0400187 }
188
189 auto sample = this->invokeChild(0, args, "coord + sourceOffset");
190 fragBuilder->codeAppendf("half4 c = %s;", sample.c_str());
Brian Salomonb25560a2021-08-10 13:56:13 -0400191 if (!mce.fConvolveAlpha) {
Brian Osman08f986d2020-05-13 17:06:46 -0400192 fragBuilder->codeAppend("c = unpremul(c);");
Adlai Holler00ddb002020-05-11 19:25:52 -0400193 fragBuilder->codeAppend("c.rgb = saturate(c.rgb);");
194 }
195 fragBuilder->codeAppend("sum += c * k;");
196}
197
Brian Salomonb25560a2021-08-10 13:56:13 -0400198void GrMatrixConvolutionEffect::Impl::emitCode(EmitArgs& args) {
robertphillipsbf536af2016-02-04 06:11:53 -0800199 const GrMatrixConvolutionEffect& mce = args.fFp.cast<GrMatrixConvolutionEffect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800200
Brian Salomonb25560a2021-08-10 13:56:13 -0400201 int kernelWidth = mce.fKernel.size().width();
202 int kernelHeight = mce.fKernel.size().height();
robertphillipsbf536af2016-02-04 06:11:53 -0800203
Adlai Holler00ddb002020-05-11 19:25:52 -0400204 int arrayCount = (kernelWidth * kernelHeight + 3) / 4;
205 SkASSERT(4 * arrayCount >= kernelWidth * kernelHeight);
jvanverth78d6eb02016-03-02 13:21:16 -0800206
egdaniel7ea439b2015-12-03 09:20:44 -0800207 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Brian Salomonb25560a2021-08-10 13:56:13 -0400208 if (mce.fKernel.isSampled()) {
Adlai Holler00ddb002020-05-11 19:25:52 -0400209 fKernelBiasUni = uniformHandler->addUniform(&mce, kFragment_GrShaderFlag,
210 kHalf_GrSLType, "KernelBias");
211 } else {
212 fKernelUni = uniformHandler->addUniformArray(&mce, kFragment_GrShaderFlag,
213 kHalf4_GrSLType, "Kernel", arrayCount);
214 }
Ethan Nicholas16464c32020-04-06 13:53:05 -0400215 fKernelOffsetUni = uniformHandler->addUniform(&mce, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800216 "KernelOffset");
Brian Salomon41e377d2020-05-05 01:27:57 +0000217 fGainUni = uniformHandler->addUniform(&mce, kFragment_GrShaderFlag, kHalf_GrSLType, "Gain");
218 fBiasUni = uniformHandler->addUniform(&mce, kFragment_GrShaderFlag, kHalf_GrSLType, "Bias");
joshualittac977922014-07-22 09:52:11 -0700219
egdaniel7ea439b2015-12-03 09:20:44 -0800220 const char* kernelOffset = uniformHandler->getUniformCStr(fKernelOffsetUni);
egdaniel7ea439b2015-12-03 09:20:44 -0800221 const char* gain = uniformHandler->getUniformCStr(fGainUni);
222 const char* bias = uniformHandler->getUniformCStr(fBiasUni);
joshualittac977922014-07-22 09:52:11 -0700223
cdalton85285412016-02-18 12:37:07 -0800224 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
John Stiles15b48922020-11-25 10:34:59 -0500225 fragBuilder->codeAppend("half4 sum = half4(0);");
Michael Ludwige88320b2020-06-24 09:04:56 -0400226 fragBuilder->codeAppendf("float2 coord = %s - %s;", args.fSampleCoord, kernelOffset);
joshualitt5ae5fc52014-07-29 12:59:27 -0700227
Brian Salomonb25560a2021-08-10 13:56:13 -0400228 if (mce.fKernel.isSampled()) {
Adlai Holler00ddb002020-05-11 19:25:52 -0400229 this->emitKernelBlock(args, {});
230 } else {
231 for (int x = 0; x < kernelWidth; ++x) {
232 for (int y = 0; y < kernelHeight; ++y) {
233 this->emitKernelBlock(args, SkIPoint::Make(x, y));
joshualitt5ae5fc52014-07-29 12:59:27 -0700234 }
joshualitt5ae5fc52014-07-29 12:59:27 -0700235 }
joshualittac977922014-07-22 09:52:11 -0700236 }
Adlai Holler00ddb002020-05-11 19:25:52 -0400237
John Stilesd1eab8b2020-12-15 09:47:26 -0500238 fragBuilder->codeAppendf("half4 color;");
Brian Salomonb25560a2021-08-10 13:56:13 -0400239 if (mce.fConvolveAlpha) {
John Stilesd1eab8b2020-12-15 09:47:26 -0500240 fragBuilder->codeAppendf("color = sum * %s + %s;", gain, bias);
241 fragBuilder->codeAppendf("color.a = saturate(color.a);");
242 fragBuilder->codeAppendf("color.rgb = clamp(color.rgb, 0.0, color.a);");
joshualittac977922014-07-22 09:52:11 -0700243 } else {
Michael Ludwige88320b2020-06-24 09:04:56 -0400244 auto sample = this->invokeChild(0, args);
Adlai Holler00ddb002020-05-11 19:25:52 -0400245 fragBuilder->codeAppendf("half4 c = %s;", sample.c_str());
John Stilesd1eab8b2020-12-15 09:47:26 -0500246 fragBuilder->codeAppendf("color.a = c.a;");
247 fragBuilder->codeAppendf("color.rgb = saturate(sum.rgb * %s + %s);", gain, bias);
248 fragBuilder->codeAppendf("color.rgb *= color.a;");
joshualittac977922014-07-22 09:52:11 -0700249 }
John Stilesd1eab8b2020-12-15 09:47:26 -0500250 fragBuilder->codeAppendf("return color;");
joshualittac977922014-07-22 09:52:11 -0700251}
252
Brian Salomonb25560a2021-08-10 13:56:13 -0400253void GrMatrixConvolutionEffect::Impl::onSetData(const GrGLSLProgramDataManager& pdman,
254 const GrFragmentProcessor& processor) {
joshualittb0a8a372014-09-23 09:50:21 -0700255 const GrMatrixConvolutionEffect& conv = processor.cast<GrMatrixConvolutionEffect>();
Brian Salomonb25560a2021-08-10 13:56:13 -0400256 pdman.set2f(fKernelOffsetUni, conv.fKernelOffset.fX, conv.fKernelOffset.fY);
257 float totalGain = conv.fGain;
258 if (conv.fKernel.isSampled()) {
259 totalGain *= conv.fKernel.biasAndGain().fGain;
260 pdman.set1f(fKernelBiasUni, conv.fKernel.biasAndGain().fBias);
Adlai Holler00ddb002020-05-11 19:25:52 -0400261 } else {
Brian Salomonb25560a2021-08-10 13:56:13 -0400262 int kernelCount = conv.fKernel.size().area();
Adlai Holler00ddb002020-05-11 19:25:52 -0400263 int arrayCount = (kernelCount + 3) / 4;
264 SkASSERT(4 * arrayCount >= kernelCount);
Brian Salomonb25560a2021-08-10 13:56:13 -0400265 pdman.set4fv(fKernelUni, arrayCount, conv.fKernel.array().data());
Adlai Holler00ddb002020-05-11 19:25:52 -0400266 }
Brian Salomonb25560a2021-08-10 13:56:13 -0400267 pdman.set1f(fBiasUni, conv.fBias);
Adlai Holler00ddb002020-05-11 19:25:52 -0400268 pdman.set1f(fGainUni, totalGain);
joshualittac977922014-07-22 09:52:11 -0700269}
270
Brian Salomon694ec492020-04-14 13:39:31 -0400271GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(std::unique_ptr<GrFragmentProcessor> child,
Brian Salomon1b0b0042020-06-12 15:15:50 -0400272 const KernelWrapper& kernel,
273 std::unique_ptr<GrFragmentProcessor> kernelFP,
Robert Phillips40fd7c92017-01-30 08:06:27 -0500274 SkScalar gain,
275 SkScalar bias,
276 const SkIPoint& kernelOffset,
Robert Phillips40fd7c92017-01-30 08:06:27 -0500277 bool convolveAlpha)
Brian Salomon6cd51b52017-07-26 19:07:15 -0400278 // To advertise either the modulation or opaqueness optimizations we'd have to examine the
279 // parameters.
Ethan Nicholasabff9562017-10-09 10:54:08 -0400280 : INHERITED(kGrMatrixConvolutionEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon1b0b0042020-06-12 15:15:50 -0400281 , fKernel(kernel)
Brian Salomon6cd51b52017-07-26 19:07:15 -0400282 , fGain(SkScalarToFloat(gain))
283 , fBias(SkScalarToFloat(bias) / 255.0f)
284 , fConvolveAlpha(convolveAlpha) {
Brian Osman1298bc42020-06-30 13:39:35 -0400285 this->registerChild(std::move(child), SkSL::SampleUsage::Explicit());
Brian Osman54867de2020-07-10 14:22:57 -0400286 this->registerChild(std::move(kernelFP), SkSL::SampleUsage::Explicit());
Brian Salomon694ec492020-04-14 13:39:31 -0400287 fKernelOffset = {static_cast<float>(kernelOffset.x()),
288 static_cast<float>(kernelOffset.y())};
Michael Ludwigfbe28592020-06-26 16:02:15 -0400289 this->setUsesSampleCoordsDirectly();
Robert Phillips40fd7c92017-01-30 08:06:27 -0500290}
291
Brian Salomon3f6f9652017-07-28 07:34:05 -0400292GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(const GrMatrixConvolutionEffect& that)
John Stiles307f8f52021-08-09 15:36:59 -0400293 : INHERITED(that)
Adlai Holler00ddb002020-05-11 19:25:52 -0400294 , fKernel(that.fKernel)
Brian Salomon3f6f9652017-07-28 07:34:05 -0400295 , fGain(that.fGain)
296 , fBias(that.fBias)
Brian Salomon694ec492020-04-14 13:39:31 -0400297 , fKernelOffset(that.fKernelOffset)
John Stiles307f8f52021-08-09 15:36:59 -0400298 , fConvolveAlpha(that.fConvolveAlpha) {}
Brian Salomon3f6f9652017-07-28 07:34:05 -0400299
Brian Salomonaff329b2017-08-11 09:40:37 -0400300std::unique_ptr<GrFragmentProcessor> GrMatrixConvolutionEffect::clone() const {
301 return std::unique_ptr<GrFragmentProcessor>(new GrMatrixConvolutionEffect(*this));
Brian Salomon3f6f9652017-07-28 07:34:05 -0400302}
303
Brian Salomon13b28732021-08-06 15:33:58 -0400304void GrMatrixConvolutionEffect::onAddToKey(const GrShaderCaps& caps,
305 GrProcessorKeyBuilder* b) const {
Brian Salomonb25560a2021-08-10 13:56:13 -0400306 SkASSERT(this->fKernel.size().width() <= 0x7FFF && this->fKernel.size().height() <= 0xFFFF);
307 uint32_t key = this->fKernel.size().width() << 16 | this->fKernel.size().height();
308 key |= fConvolveAlpha ? 1U << 31 : 0;
309 b->add32(key);
joshualitteb2a6762014-12-04 11:35:33 -0800310}
311
Brian Salomon3176e862021-08-09 11:23:04 -0400312std::unique_ptr<GrFragmentProcessor::ProgramImpl>
313GrMatrixConvolutionEffect::onMakeProgramImpl() const {
Brian Salomonb25560a2021-08-10 13:56:13 -0400314 return std::make_unique<Impl>();
joshualittac977922014-07-22 09:52:11 -0700315}
316
bsalomon0e08fc12014-10-15 08:19:04 -0700317bool GrMatrixConvolutionEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -0700318 const GrMatrixConvolutionEffect& s = sBase.cast<GrMatrixConvolutionEffect>();
Brian Salomonb25560a2021-08-10 13:56:13 -0400319 return fKernel == s.fKernel &&
320 fGain == s.fGain &&
321 fBias == s.fBias &&
322 fKernelOffset == s.fKernelOffset &&
323 fConvolveAlpha == s.fConvolveAlpha;
joshualittac977922014-07-22 09:52:11 -0700324}
325
Adlai Holler00ddb002020-05-11 19:25:52 -0400326std::unique_ptr<GrFragmentProcessor> GrMatrixConvolutionEffect::Make(GrRecordingContext* context,
327 GrSurfaceProxyView srcView,
Brian Salomon694ec492020-04-14 13:39:31 -0400328 const SkIRect& srcBounds,
329 const SkISize& kernelSize,
330 const SkScalar* kernel,
331 SkScalar gain,
332 SkScalar bias,
333 const SkIPoint& kernelOffset,
334 GrSamplerState::WrapMode wm,
335 bool convolveAlpha,
336 const GrCaps& caps) {
Brian Salomon1b0b0042020-06-12 15:15:50 -0400337 auto [kernelWrapper, kernelFP] = KernelWrapper::Make(context, kernelSize, caps, kernel);
338 if (!kernelWrapper.isValid()) {
Adlai Holler00ddb002020-05-11 19:25:52 -0400339 return nullptr;
340 }
Brian Salomon694ec492020-04-14 13:39:31 -0400341 GrSamplerState sampler(wm, GrSamplerState::Filter::kNearest);
342 auto child = GrTextureEffect::MakeSubset(std::move(srcView), kPremul_SkAlphaType, SkMatrix::I(),
343 sampler, SkRect::Make(srcBounds), caps);
Brian Salomon1b0b0042020-06-12 15:15:50 -0400344 return std::unique_ptr<GrFragmentProcessor>(
345 new GrMatrixConvolutionEffect(std::move(child), kernelWrapper, std::move(kernelFP),
346 gain, bias, kernelOffset, convolveAlpha));
Brian Salomon694ec492020-04-14 13:39:31 -0400347}
348
joshualittb0a8a372014-09-23 09:50:21 -0700349GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMatrixConvolutionEffect);
joshualittac977922014-07-22 09:52:11 -0700350
Hal Canary6f6961e2017-01-31 13:50:44 -0500351#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400352std::unique_ptr<GrFragmentProcessor> GrMatrixConvolutionEffect::TestCreate(GrProcessorTestData* d) {
Greg Daniel026a60c2020-02-12 10:53:51 -0500353 auto [view, ct, at] = d->randomView();
Robert Phillipsdbc8eeb2017-02-21 10:04:31 -0500354
Adlai Holler00ddb002020-05-11 19:25:52 -0400355 static constexpr size_t kMaxTestKernelSize = 2 * kMaxUniformSize;
356 int width = d->fRandom->nextRangeU(1, kMaxTestKernelSize);
357 int height = d->fRandom->nextRangeU(1, kMaxTestKernelSize / width);
joshualittac977922014-07-22 09:52:11 -0700358 SkISize kernelSize = SkISize::Make(width, height);
Ben Wagner7ecc5962016-11-02 17:07:33 -0400359 std::unique_ptr<SkScalar[]> kernel(new SkScalar[width * height]);
joshualittac977922014-07-22 09:52:11 -0700360 for (int i = 0; i < width * height; i++) {
joshualitt0067ff52015-07-08 14:26:19 -0700361 kernel.get()[i] = d->fRandom->nextSScalar1();
joshualittac977922014-07-22 09:52:11 -0700362 }
joshualitt0067ff52015-07-08 14:26:19 -0700363 SkScalar gain = d->fRandom->nextSScalar1();
364 SkScalar bias = d->fRandom->nextSScalar1();
Greg Daniel026a60c2020-02-12 10:53:51 -0500365
366 uint32_t kernalOffsetX = d->fRandom->nextRangeU(0, kernelSize.width());
367 uint32_t kernalOffsetY = d->fRandom->nextRangeU(0, kernelSize.height());
368 SkIPoint kernelOffset = SkIPoint::Make(kernalOffsetX, kernalOffsetY);
369
370 uint32_t boundsX = d->fRandom->nextRangeU(0, view.width());
371 uint32_t boundsY = d->fRandom->nextRangeU(0, view.height());
372 uint32_t boundsW = d->fRandom->nextRangeU(0, view.width());
373 uint32_t boundsH = d->fRandom->nextRangeU(0, view.height());
374 SkIRect bounds = SkIRect::MakeXYWH(boundsX, boundsY, boundsW, boundsH);
375
Brian Salomon694ec492020-04-14 13:39:31 -0400376 auto wm = static_cast<GrSamplerState::WrapMode>(
377 d->fRandom->nextULessThan(GrSamplerState::kWrapModeCount));
joshualitt0067ff52015-07-08 14:26:19 -0700378 bool convolveAlpha = d->fRandom->nextBool();
Robert Phillips4e105e22020-07-16 09:18:50 -0400379 return GrMatrixConvolutionEffect::Make(d->context(),
Adlai Holler00ddb002020-05-11 19:25:52 -0400380 std::move(view),
bungeman06ca8ec2016-06-09 08:01:03 -0700381 bounds,
382 kernelSize,
383 kernel.get(),
384 gain,
385 bias,
386 kernelOffset,
Brian Salomon694ec492020-04-14 13:39:31 -0400387 wm,
388 convolveAlpha,
389 *d->caps());
joshualittac977922014-07-22 09:52:11 -0700390}
Hal Canary6f6961e2017-01-31 13:50:44 -0500391#endif