1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci#include "src/gpu/effects/GrMatrixConvolutionEffect.h" 8cb93a386Sopenharmony_ci 9cb93a386Sopenharmony_ci#include "include/private/SkHalf.h" 10cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 11cb93a386Sopenharmony_ci#include "src/gpu/GrProxyProvider.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h" 13cb93a386Sopenharmony_ci#include "src/gpu/GrTexture.h" 14cb93a386Sopenharmony_ci#include "src/gpu/GrTextureProxy.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrThreadSafeCache.h" 16cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h" 17cb93a386Sopenharmony_ci#include "src/gpu/effects/GrTextureEffect.h" 18cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 19cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLProgramDataManager.h" 20cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLUniformHandler.h" 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ciclass GrMatrixConvolutionEffect::Impl : public ProgramImpl { 23cb93a386Sopenharmony_cipublic: 24cb93a386Sopenharmony_ci void emitCode(EmitArgs&) override; 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ciprivate: 27cb93a386Sopenharmony_ci void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ci typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci void emitKernelBlock(EmitArgs&, SkIPoint); 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci UniformHandle fKernelUni; 34cb93a386Sopenharmony_ci UniformHandle fKernelOffsetUni; 35cb93a386Sopenharmony_ci UniformHandle fGainUni; 36cb93a386Sopenharmony_ci UniformHandle fBiasUni; 37cb93a386Sopenharmony_ci UniformHandle fKernelBiasUni; 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci using INHERITED = ProgramImpl; 40cb93a386Sopenharmony_ci}; 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ciGrMatrixConvolutionEffect::KernelWrapper::MakeResult 43cb93a386Sopenharmony_ciGrMatrixConvolutionEffect::KernelWrapper::Make(GrRecordingContext* rContext, 44cb93a386Sopenharmony_ci SkISize size, 45cb93a386Sopenharmony_ci const GrCaps& caps, 46cb93a386Sopenharmony_ci const SkScalar* values) { 47cb93a386Sopenharmony_ci if (!rContext || !values || size.isEmpty()) { 48cb93a386Sopenharmony_ci return {}; 49cb93a386Sopenharmony_ci } 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci const int length = size.area(); 52cb93a386Sopenharmony_ci // Small kernel -> just fill the array. 53cb93a386Sopenharmony_ci KernelWrapper result(size); 54cb93a386Sopenharmony_ci if (length <= kMaxUniformSize) { 55cb93a386Sopenharmony_ci for (int i = 0; i < length; i++) { 56cb93a386Sopenharmony_ci result.fArray[i] = SkScalarToFloat(values[i]); 57cb93a386Sopenharmony_ci } 58cb93a386Sopenharmony_ci return {result, nullptr}; 59cb93a386Sopenharmony_ci } 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci BiasAndGain& scalableSampler = result.fBiasAndGain; 62cb93a386Sopenharmony_ci bool useA16 = 63cb93a386Sopenharmony_ci rContext->defaultBackendFormat(kA16_float_SkColorType, GrRenderable::kNo).isValid(); 64cb93a386Sopenharmony_ci SkScalar min = values[0]; 65cb93a386Sopenharmony_ci if (!useA16) { 66cb93a386Sopenharmony_ci // Determine min and max values to figure out inner gain & bias. 67cb93a386Sopenharmony_ci SkScalar max = values[0]; 68cb93a386Sopenharmony_ci for (int i = 1; i < length; i++) { 69cb93a386Sopenharmony_ci if (values[i] < min) { 70cb93a386Sopenharmony_ci min = values[i]; 71cb93a386Sopenharmony_ci } 72cb93a386Sopenharmony_ci if (values[i] > max) { 73cb93a386Sopenharmony_ci max = values[i]; 74cb93a386Sopenharmony_ci } 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci // Treat near-0 gain (i.e. box blur) as 1, and let the kernelBias 77cb93a386Sopenharmony_ci // move everything up to the final value. 78cb93a386Sopenharmony_ci const SkScalar computedGain = max - min; 79cb93a386Sopenharmony_ci scalableSampler.fGain = 80cb93a386Sopenharmony_ci SkScalarNearlyZero(computedGain) ? 1.0f : SkScalarToFloat(computedGain); 81cb93a386Sopenharmony_ci // Inner bias is pre-inner-gain so we divide that out. 82cb93a386Sopenharmony_ci scalableSampler.fBias = SkScalarToFloat(min) / scalableSampler.fGain; 83cb93a386Sopenharmony_ci } 84cb93a386Sopenharmony_ci 85cb93a386Sopenharmony_ci // TODO: Pick cache or dont-cache based on observed perf. 86cb93a386Sopenharmony_ci static constexpr bool kCacheKernelTexture = true; 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ci GrUniqueKey key; 89cb93a386Sopenharmony_ci if (kCacheKernelTexture) { 90cb93a386Sopenharmony_ci static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); 91cb93a386Sopenharmony_ci GrUniqueKey::Builder builder(&key, kDomain, length, "Matrix Convolution Kernel"); 92cb93a386Sopenharmony_ci // Texture cache key is the exact content of the kernel. 93cb93a386Sopenharmony_ci static_assert(sizeof(float) == 4); 94cb93a386Sopenharmony_ci for (int i = 0; i < length; i++) { 95cb93a386Sopenharmony_ci builder[i] = *(const uint32_t*)&values[i]; 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci builder.finish(); 98cb93a386Sopenharmony_ci } 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_ci // Find or create a texture. 101cb93a386Sopenharmony_ci auto threadSafeCache = rContext->priv().threadSafeCache(); 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ci SkColorType colorType = useA16 ? kA16_float_SkColorType : kAlpha_8_SkColorType; 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci GrSurfaceProxyView view; 106cb93a386Sopenharmony_ci if (kCacheKernelTexture && (view = threadSafeCache->find(key))) { 107cb93a386Sopenharmony_ci SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin); 108cb93a386Sopenharmony_ci auto kernelFP = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType); 109cb93a386Sopenharmony_ci return {result, std::move(kernelFP)}; 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci SkBitmap bm; 113cb93a386Sopenharmony_ci auto info = SkImageInfo::Make({length, 1}, colorType, kPremul_SkAlphaType, nullptr); 114cb93a386Sopenharmony_ci if (!bm.tryAllocPixels(info)) { 115cb93a386Sopenharmony_ci return {}; 116cb93a386Sopenharmony_ci } 117cb93a386Sopenharmony_ci for (int i = 0; i < length; i++) { 118cb93a386Sopenharmony_ci if (useA16) { 119cb93a386Sopenharmony_ci *bm.getAddr16(i, 0) = SkFloatToHalf(values[i]); 120cb93a386Sopenharmony_ci } else { 121cb93a386Sopenharmony_ci *bm.getAddr8(i, 0) = 122cb93a386Sopenharmony_ci SkScalarRoundToInt((values[i] - min) / scalableSampler.fGain * 255); 123cb93a386Sopenharmony_ci } 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci bm.setImmutable(); 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_ci view = std::get<0>(GrMakeUncachedBitmapProxyView(rContext, bm)); 128cb93a386Sopenharmony_ci if (!view) { 129cb93a386Sopenharmony_ci return {}; 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci if (kCacheKernelTexture) { 133cb93a386Sopenharmony_ci view = threadSafeCache->add(key, view); 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_ci SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin); 137cb93a386Sopenharmony_ci auto kernelFP = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType); 138cb93a386Sopenharmony_ci return {result, std::move(kernelFP)}; 139cb93a386Sopenharmony_ci} 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_cibool GrMatrixConvolutionEffect::KernelWrapper::operator==(const KernelWrapper& k) const { 142cb93a386Sopenharmony_ci if (fSize != k.fSize) { 143cb93a386Sopenharmony_ci return false; 144cb93a386Sopenharmony_ci } else if (this->isSampled()) { 145cb93a386Sopenharmony_ci return fBiasAndGain == k.fBiasAndGain; 146cb93a386Sopenharmony_ci } else { 147cb93a386Sopenharmony_ci return std::equal(fArray.begin(), fArray.begin() + fSize.area(), k.fArray.begin()); 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci} 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_cibool GrMatrixConvolutionEffect::KernelWrapper::BiasAndGain::operator==( 152cb93a386Sopenharmony_ci const BiasAndGain& k) const { 153cb93a386Sopenharmony_ci return fGain == k.fGain && fBias == k.fBias; 154cb93a386Sopenharmony_ci} 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci// For sampled kernels, emit a for loop that does all the kernel accumulation. 157cb93a386Sopenharmony_ci// For uniform kernels, emit a single iteration. Function is called repeatedly in a for loop. 158cb93a386Sopenharmony_ci// loc is ignored for sampled kernels. 159cb93a386Sopenharmony_civoid GrMatrixConvolutionEffect::Impl::emitKernelBlock(EmitArgs& args, SkIPoint loc) { 160cb93a386Sopenharmony_ci const GrMatrixConvolutionEffect& mce = args.fFp.cast<GrMatrixConvolutionEffect>(); 161cb93a386Sopenharmony_ci GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 162cb93a386Sopenharmony_ci GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 163cb93a386Sopenharmony_ci int kernelWidth = mce.fKernel.size().width(); 164cb93a386Sopenharmony_ci int kernelHeight = mce.fKernel.size().height(); 165cb93a386Sopenharmony_ci int kernelArea = kernelWidth * kernelHeight; 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci if (mce.fKernel.isSampled()) { 168cb93a386Sopenharmony_ci fragBuilder->codeAppendf("for (int i = 0; i < %d; ++i)", (int)kernelArea); 169cb93a386Sopenharmony_ci } 170cb93a386Sopenharmony_ci 171cb93a386Sopenharmony_ci GrGLSLShaderBuilder::ShaderBlock block(fragBuilder); 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci fragBuilder->codeAppend("half k;"); 174cb93a386Sopenharmony_ci fragBuilder->codeAppend("half2 sourceOffset;"); 175cb93a386Sopenharmony_ci if (mce.fKernel.isSampled()) { 176cb93a386Sopenharmony_ci const char* kernelBias = uniformHandler->getUniformCStr(fKernelBiasUni); 177cb93a386Sopenharmony_ci SkString kernelSample = this->invokeChild(1, args, "float2(float(i) + 0.5, 0.5)"); 178cb93a386Sopenharmony_ci fragBuilder->codeAppendf("k = %s.w + %s;", kernelSample.c_str(), kernelBias); 179cb93a386Sopenharmony_ci fragBuilder->codeAppendf("sourceOffset.y = floor(half(i) / %d);", kernelWidth); 180cb93a386Sopenharmony_ci fragBuilder->codeAppendf("sourceOffset.x = half(i) - sourceOffset.y * %d;", kernelWidth); 181cb93a386Sopenharmony_ci } else { 182cb93a386Sopenharmony_ci fragBuilder->codeAppendf("sourceOffset = half2(%d, %d);", loc.x(), loc.y()); 183cb93a386Sopenharmony_ci int offset = loc.y() * kernelWidth + loc.x(); 184cb93a386Sopenharmony_ci const char* kernel = uniformHandler->getUniformCStr(fKernelUni); 185cb93a386Sopenharmony_ci fragBuilder->codeAppendf("k = %s[%d][%d];", kernel, offset / 4, offset & 0x3); 186cb93a386Sopenharmony_ci } 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci auto sample = this->invokeChild(0, args, "coord + sourceOffset"); 189cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 c = %s;", sample.c_str()); 190cb93a386Sopenharmony_ci if (!mce.fConvolveAlpha) { 191cb93a386Sopenharmony_ci fragBuilder->codeAppend("c = unpremul(c);"); 192cb93a386Sopenharmony_ci fragBuilder->codeAppend("c.rgb = saturate(c.rgb);"); 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci fragBuilder->codeAppend("sum += c * k;"); 195cb93a386Sopenharmony_ci} 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_civoid GrMatrixConvolutionEffect::Impl::emitCode(EmitArgs& args) { 198cb93a386Sopenharmony_ci const GrMatrixConvolutionEffect& mce = args.fFp.cast<GrMatrixConvolutionEffect>(); 199cb93a386Sopenharmony_ci 200cb93a386Sopenharmony_ci int kernelWidth = mce.fKernel.size().width(); 201cb93a386Sopenharmony_ci int kernelHeight = mce.fKernel.size().height(); 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci int arrayCount = (kernelWidth * kernelHeight + 3) / 4; 204cb93a386Sopenharmony_ci SkASSERT(4 * arrayCount >= kernelWidth * kernelHeight); 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 207cb93a386Sopenharmony_ci if (mce.fKernel.isSampled()) { 208cb93a386Sopenharmony_ci fKernelBiasUni = uniformHandler->addUniform(&mce, kFragment_GrShaderFlag, 209cb93a386Sopenharmony_ci kHalf_GrSLType, "KernelBias"); 210cb93a386Sopenharmony_ci } else { 211cb93a386Sopenharmony_ci fKernelUni = uniformHandler->addUniformArray(&mce, kFragment_GrShaderFlag, 212cb93a386Sopenharmony_ci kHalf4_GrSLType, "Kernel", arrayCount); 213cb93a386Sopenharmony_ci } 214cb93a386Sopenharmony_ci fKernelOffsetUni = uniformHandler->addUniform(&mce, kFragment_GrShaderFlag, kHalf2_GrSLType, 215cb93a386Sopenharmony_ci "KernelOffset"); 216cb93a386Sopenharmony_ci fGainUni = uniformHandler->addUniform(&mce, kFragment_GrShaderFlag, kHalf_GrSLType, "Gain"); 217cb93a386Sopenharmony_ci fBiasUni = uniformHandler->addUniform(&mce, kFragment_GrShaderFlag, kHalf_GrSLType, "Bias"); 218cb93a386Sopenharmony_ci 219cb93a386Sopenharmony_ci const char* kernelOffset = uniformHandler->getUniformCStr(fKernelOffsetUni); 220cb93a386Sopenharmony_ci const char* gain = uniformHandler->getUniformCStr(fGainUni); 221cb93a386Sopenharmony_ci const char* bias = uniformHandler->getUniformCStr(fBiasUni); 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_ci GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 224cb93a386Sopenharmony_ci fragBuilder->codeAppend("half4 sum = half4(0);"); 225cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 coord = %s - %s;", args.fSampleCoord, kernelOffset); 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci if (mce.fKernel.isSampled()) { 228cb93a386Sopenharmony_ci this->emitKernelBlock(args, {}); 229cb93a386Sopenharmony_ci } else { 230cb93a386Sopenharmony_ci for (int x = 0; x < kernelWidth; ++x) { 231cb93a386Sopenharmony_ci for (int y = 0; y < kernelHeight; ++y) { 232cb93a386Sopenharmony_ci this->emitKernelBlock(args, SkIPoint::Make(x, y)); 233cb93a386Sopenharmony_ci } 234cb93a386Sopenharmony_ci } 235cb93a386Sopenharmony_ci } 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 color;"); 238cb93a386Sopenharmony_ci if (mce.fConvolveAlpha) { 239cb93a386Sopenharmony_ci fragBuilder->codeAppendf("color = sum * %s + %s;", gain, bias); 240cb93a386Sopenharmony_ci fragBuilder->codeAppendf("color.a = saturate(color.a);"); 241cb93a386Sopenharmony_ci fragBuilder->codeAppendf("color.rgb = clamp(color.rgb, 0.0, color.a);"); 242cb93a386Sopenharmony_ci } else { 243cb93a386Sopenharmony_ci auto sample = this->invokeChild(0, args); 244cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 c = %s;", sample.c_str()); 245cb93a386Sopenharmony_ci fragBuilder->codeAppendf("color.a = c.a;"); 246cb93a386Sopenharmony_ci fragBuilder->codeAppendf("color.rgb = saturate(sum.rgb * %s + %s);", gain, bias); 247cb93a386Sopenharmony_ci fragBuilder->codeAppendf("color.rgb *= color.a;"); 248cb93a386Sopenharmony_ci } 249cb93a386Sopenharmony_ci fragBuilder->codeAppendf("return color;"); 250cb93a386Sopenharmony_ci} 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_civoid GrMatrixConvolutionEffect::Impl::onSetData(const GrGLSLProgramDataManager& pdman, 253cb93a386Sopenharmony_ci const GrFragmentProcessor& processor) { 254cb93a386Sopenharmony_ci const GrMatrixConvolutionEffect& conv = processor.cast<GrMatrixConvolutionEffect>(); 255cb93a386Sopenharmony_ci pdman.set2f(fKernelOffsetUni, conv.fKernelOffset.fX, conv.fKernelOffset.fY); 256cb93a386Sopenharmony_ci float totalGain = conv.fGain; 257cb93a386Sopenharmony_ci if (conv.fKernel.isSampled()) { 258cb93a386Sopenharmony_ci totalGain *= conv.fKernel.biasAndGain().fGain; 259cb93a386Sopenharmony_ci pdman.set1f(fKernelBiasUni, conv.fKernel.biasAndGain().fBias); 260cb93a386Sopenharmony_ci } else { 261cb93a386Sopenharmony_ci int kernelCount = conv.fKernel.size().area(); 262cb93a386Sopenharmony_ci int arrayCount = (kernelCount + 3) / 4; 263cb93a386Sopenharmony_ci SkASSERT(4 * arrayCount >= kernelCount); 264cb93a386Sopenharmony_ci pdman.set4fv(fKernelUni, arrayCount, conv.fKernel.array().data()); 265cb93a386Sopenharmony_ci } 266cb93a386Sopenharmony_ci pdman.set1f(fBiasUni, conv.fBias); 267cb93a386Sopenharmony_ci pdman.set1f(fGainUni, totalGain); 268cb93a386Sopenharmony_ci} 269cb93a386Sopenharmony_ci 270cb93a386Sopenharmony_ciGrMatrixConvolutionEffect::GrMatrixConvolutionEffect(std::unique_ptr<GrFragmentProcessor> child, 271cb93a386Sopenharmony_ci const KernelWrapper& kernel, 272cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> kernelFP, 273cb93a386Sopenharmony_ci SkScalar gain, 274cb93a386Sopenharmony_ci SkScalar bias, 275cb93a386Sopenharmony_ci const SkIPoint& kernelOffset, 276cb93a386Sopenharmony_ci bool convolveAlpha) 277cb93a386Sopenharmony_ci // To advertise either the modulation or opaqueness optimizations we'd have to examine the 278cb93a386Sopenharmony_ci // parameters. 279cb93a386Sopenharmony_ci : INHERITED(kGrMatrixConvolutionEffect_ClassID, kNone_OptimizationFlags) 280cb93a386Sopenharmony_ci , fKernel(kernel) 281cb93a386Sopenharmony_ci , fGain(SkScalarToFloat(gain)) 282cb93a386Sopenharmony_ci , fBias(SkScalarToFloat(bias) / 255.0f) 283cb93a386Sopenharmony_ci , fConvolveAlpha(convolveAlpha) { 284cb93a386Sopenharmony_ci this->registerChild(std::move(child), SkSL::SampleUsage::Explicit()); 285cb93a386Sopenharmony_ci this->registerChild(std::move(kernelFP), SkSL::SampleUsage::Explicit()); 286cb93a386Sopenharmony_ci fKernelOffset = {static_cast<float>(kernelOffset.x()), 287cb93a386Sopenharmony_ci static_cast<float>(kernelOffset.y())}; 288cb93a386Sopenharmony_ci this->setUsesSampleCoordsDirectly(); 289cb93a386Sopenharmony_ci} 290cb93a386Sopenharmony_ci 291cb93a386Sopenharmony_ciGrMatrixConvolutionEffect::GrMatrixConvolutionEffect(const GrMatrixConvolutionEffect& that) 292cb93a386Sopenharmony_ci : INHERITED(that) 293cb93a386Sopenharmony_ci , fKernel(that.fKernel) 294cb93a386Sopenharmony_ci , fGain(that.fGain) 295cb93a386Sopenharmony_ci , fBias(that.fBias) 296cb93a386Sopenharmony_ci , fKernelOffset(that.fKernelOffset) 297cb93a386Sopenharmony_ci , fConvolveAlpha(that.fConvolveAlpha) {} 298cb93a386Sopenharmony_ci 299cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor> GrMatrixConvolutionEffect::clone() const { 300cb93a386Sopenharmony_ci return std::unique_ptr<GrFragmentProcessor>(new GrMatrixConvolutionEffect(*this)); 301cb93a386Sopenharmony_ci} 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ciSkString GrMatrixConvolutionEffect::getShaderDfxInfo() const 304cb93a386Sopenharmony_ci{ 305cb93a386Sopenharmony_ci SkString format; 306cb93a386Sopenharmony_ci format.printf("ShaderDfx_GrMatrixConvolutionEffect_%d_%d_%d", 307cb93a386Sopenharmony_ci fKernel.size().width(), fKernel.size().height(), fConvolveAlpha); 308cb93a386Sopenharmony_ci return format; 309cb93a386Sopenharmony_ci} 310cb93a386Sopenharmony_ci 311cb93a386Sopenharmony_civoid GrMatrixConvolutionEffect::onAddToKey(const GrShaderCaps& caps, 312cb93a386Sopenharmony_ci GrProcessorKeyBuilder* b) const { 313cb93a386Sopenharmony_ci SkASSERT(this->fKernel.size().width() <= 0x7FFF && this->fKernel.size().height() <= 0xFFFF); 314cb93a386Sopenharmony_ci uint32_t key = this->fKernel.size().width() << 16 | this->fKernel.size().height(); 315cb93a386Sopenharmony_ci key |= fConvolveAlpha ? 1U << 31 : 0; 316cb93a386Sopenharmony_ci b->add32(key); 317cb93a386Sopenharmony_ci} 318cb93a386Sopenharmony_ci 319cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor::ProgramImpl> 320cb93a386Sopenharmony_ciGrMatrixConvolutionEffect::onMakeProgramImpl() const { 321cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 322cb93a386Sopenharmony_ci} 323cb93a386Sopenharmony_ci 324cb93a386Sopenharmony_cibool GrMatrixConvolutionEffect::onIsEqual(const GrFragmentProcessor& sBase) const { 325cb93a386Sopenharmony_ci const GrMatrixConvolutionEffect& s = sBase.cast<GrMatrixConvolutionEffect>(); 326cb93a386Sopenharmony_ci return fKernel == s.fKernel && 327cb93a386Sopenharmony_ci fGain == s.fGain && 328cb93a386Sopenharmony_ci fBias == s.fBias && 329cb93a386Sopenharmony_ci fKernelOffset == s.fKernelOffset && 330cb93a386Sopenharmony_ci fConvolveAlpha == s.fConvolveAlpha; 331cb93a386Sopenharmony_ci} 332cb93a386Sopenharmony_ci 333cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor> GrMatrixConvolutionEffect::Make(GrRecordingContext* context, 334cb93a386Sopenharmony_ci GrSurfaceProxyView srcView, 335cb93a386Sopenharmony_ci const SkIRect& srcBounds, 336cb93a386Sopenharmony_ci const SkISize& kernelSize, 337cb93a386Sopenharmony_ci const SkScalar* kernel, 338cb93a386Sopenharmony_ci SkScalar gain, 339cb93a386Sopenharmony_ci SkScalar bias, 340cb93a386Sopenharmony_ci const SkIPoint& kernelOffset, 341cb93a386Sopenharmony_ci GrSamplerState::WrapMode wm, 342cb93a386Sopenharmony_ci bool convolveAlpha, 343cb93a386Sopenharmony_ci const GrCaps& caps) { 344cb93a386Sopenharmony_ci auto [kernelWrapper, kernelFP] = KernelWrapper::Make(context, kernelSize, caps, kernel); 345cb93a386Sopenharmony_ci if (!kernelWrapper.isValid()) { 346cb93a386Sopenharmony_ci return nullptr; 347cb93a386Sopenharmony_ci } 348cb93a386Sopenharmony_ci GrSamplerState sampler(wm, GrSamplerState::Filter::kNearest); 349cb93a386Sopenharmony_ci auto child = GrTextureEffect::MakeSubset(std::move(srcView), kPremul_SkAlphaType, SkMatrix::I(), 350cb93a386Sopenharmony_ci sampler, SkRect::Make(srcBounds), caps); 351cb93a386Sopenharmony_ci return std::unique_ptr<GrFragmentProcessor>( 352cb93a386Sopenharmony_ci new GrMatrixConvolutionEffect(std::move(child), kernelWrapper, std::move(kernelFP), 353cb93a386Sopenharmony_ci gain, bias, kernelOffset, convolveAlpha)); 354cb93a386Sopenharmony_ci} 355cb93a386Sopenharmony_ci 356cb93a386Sopenharmony_ciGR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMatrixConvolutionEffect); 357cb93a386Sopenharmony_ci 358cb93a386Sopenharmony_ci#if GR_TEST_UTILS 359cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor> GrMatrixConvolutionEffect::TestCreate(GrProcessorTestData* d) { 360cb93a386Sopenharmony_ci auto [view, ct, at] = d->randomView(); 361cb93a386Sopenharmony_ci 362cb93a386Sopenharmony_ci static constexpr size_t kMaxTestKernelSize = 2 * kMaxUniformSize; 363cb93a386Sopenharmony_ci int width = d->fRandom->nextRangeU(1, kMaxTestKernelSize); 364cb93a386Sopenharmony_ci int height = d->fRandom->nextRangeU(1, kMaxTestKernelSize / width); 365cb93a386Sopenharmony_ci SkISize kernelSize = SkISize::Make(width, height); 366cb93a386Sopenharmony_ci std::unique_ptr<SkScalar[]> kernel(new SkScalar[width * height]); 367cb93a386Sopenharmony_ci for (int i = 0; i < width * height; i++) { 368cb93a386Sopenharmony_ci kernel.get()[i] = d->fRandom->nextSScalar1(); 369cb93a386Sopenharmony_ci } 370cb93a386Sopenharmony_ci SkScalar gain = d->fRandom->nextSScalar1(); 371cb93a386Sopenharmony_ci SkScalar bias = d->fRandom->nextSScalar1(); 372cb93a386Sopenharmony_ci 373cb93a386Sopenharmony_ci uint32_t kernalOffsetX = d->fRandom->nextRangeU(0, kernelSize.width()); 374cb93a386Sopenharmony_ci uint32_t kernalOffsetY = d->fRandom->nextRangeU(0, kernelSize.height()); 375cb93a386Sopenharmony_ci SkIPoint kernelOffset = SkIPoint::Make(kernalOffsetX, kernalOffsetY); 376cb93a386Sopenharmony_ci 377cb93a386Sopenharmony_ci uint32_t boundsX = d->fRandom->nextRangeU(0, view.width()); 378cb93a386Sopenharmony_ci uint32_t boundsY = d->fRandom->nextRangeU(0, view.height()); 379cb93a386Sopenharmony_ci uint32_t boundsW = d->fRandom->nextRangeU(0, view.width()); 380cb93a386Sopenharmony_ci uint32_t boundsH = d->fRandom->nextRangeU(0, view.height()); 381cb93a386Sopenharmony_ci SkIRect bounds = SkIRect::MakeXYWH(boundsX, boundsY, boundsW, boundsH); 382cb93a386Sopenharmony_ci 383cb93a386Sopenharmony_ci auto wm = static_cast<GrSamplerState::WrapMode>( 384cb93a386Sopenharmony_ci d->fRandom->nextULessThan(GrSamplerState::kWrapModeCount)); 385cb93a386Sopenharmony_ci bool convolveAlpha = d->fRandom->nextBool(); 386cb93a386Sopenharmony_ci return GrMatrixConvolutionEffect::Make(d->context(), 387cb93a386Sopenharmony_ci std::move(view), 388cb93a386Sopenharmony_ci bounds, 389cb93a386Sopenharmony_ci kernelSize, 390cb93a386Sopenharmony_ci kernel.get(), 391cb93a386Sopenharmony_ci gain, 392cb93a386Sopenharmony_ci bias, 393cb93a386Sopenharmony_ci kernelOffset, 394cb93a386Sopenharmony_ci wm, 395cb93a386Sopenharmony_ci convolveAlpha, 396cb93a386Sopenharmony_ci *d->caps()); 397cb93a386Sopenharmony_ci} 398cb93a386Sopenharmony_ci#endif 399