1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2016 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 8cb93a386Sopenharmony_ci#include "tests/Test.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 11cb93a386Sopenharmony_ci#include "src/gpu/GrClip.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 13cb93a386Sopenharmony_ci#include "src/gpu/GrFragmentProcessor.h" 14cb93a386Sopenharmony_ci#include "src/gpu/GrGpuResource.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrImageInfo.h" 16cb93a386Sopenharmony_ci#include "src/gpu/GrMemoryPool.h" 17cb93a386Sopenharmony_ci#include "src/gpu/GrProxyProvider.h" 18cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h" 19cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h" 20cb93a386Sopenharmony_ci#include "src/gpu/effects/GrTextureEffect.h" 21cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 22cb93a386Sopenharmony_ci#include "src/gpu/ops/GrMeshDrawOp.h" 23cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 24cb93a386Sopenharmony_ci#include "tests/TestUtils.h" 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci#include <atomic> 27cb93a386Sopenharmony_ci#include <random> 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_cinamespace { 30cb93a386Sopenharmony_ciclass TestOp : public GrMeshDrawOp { 31cb93a386Sopenharmony_cipublic: 32cb93a386Sopenharmony_ci DEFINE_OP_CLASS_ID 33cb93a386Sopenharmony_ci static GrOp::Owner Make(GrRecordingContext* rContext, 34cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> fp) { 35cb93a386Sopenharmony_ci return GrOp::Make<TestOp>(rContext, std::move(fp)); 36cb93a386Sopenharmony_ci } 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci const char* name() const override { return "TestOp"; } 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_ci void visitProxies(const GrVisitProxyFunc& func) const override { 41cb93a386Sopenharmony_ci fProcessors.visitProxies(func); 42cb93a386Sopenharmony_ci } 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ci GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip, 47cb93a386Sopenharmony_ci GrClampType clampType) override { 48cb93a386Sopenharmony_ci static constexpr GrProcessorAnalysisColor kUnknownColor; 49cb93a386Sopenharmony_ci SkPMColor4f overrideColor; 50cb93a386Sopenharmony_ci return fProcessors.finalize( 51cb93a386Sopenharmony_ci kUnknownColor, GrProcessorAnalysisCoverage::kNone, clip, 52cb93a386Sopenharmony_ci &GrUserStencilSettings::kUnused, caps, clampType, &overrideColor); 53cb93a386Sopenharmony_ci } 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_ciprivate: 56cb93a386Sopenharmony_ci friend class ::GrOp; // for ctor 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ci TestOp(std::unique_ptr<GrFragmentProcessor> fp) 59cb93a386Sopenharmony_ci : INHERITED(ClassID()), fProcessors(std::move(fp)) { 60cb93a386Sopenharmony_ci this->setBounds(SkRect::MakeWH(100, 100), HasAABloat::kNo, IsHairline::kNo); 61cb93a386Sopenharmony_ci } 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_ci GrProgramInfo* programInfo() override { return nullptr; } 64cb93a386Sopenharmony_ci void onCreateProgramInfo(const GrCaps*, 65cb93a386Sopenharmony_ci SkArenaAlloc*, 66cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 67cb93a386Sopenharmony_ci bool usesMSAASurface, 68cb93a386Sopenharmony_ci GrAppliedClip&&, 69cb93a386Sopenharmony_ci const GrDstProxyView&, 70cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 71cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) override {} 72cb93a386Sopenharmony_ci void onPrePrepareDraws(GrRecordingContext*, 73cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 74cb93a386Sopenharmony_ci GrAppliedClip*, 75cb93a386Sopenharmony_ci const GrDstProxyView&, 76cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 77cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) override {} 78cb93a386Sopenharmony_ci void onPrepareDraws(GrMeshDrawTarget*) override { return; } 79cb93a386Sopenharmony_ci void onExecute(GrOpFlushState*, const SkRect&) override { return; } 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_ci GrProcessorSet fProcessors; 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci using INHERITED = GrMeshDrawOp; 84cb93a386Sopenharmony_ci}; 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ci/** 87cb93a386Sopenharmony_ci * FP used to test ref counts on owned GrGpuResources. Can also be a parent FP to test counts 88cb93a386Sopenharmony_ci * of resources owned by child FPs. 89cb93a386Sopenharmony_ci */ 90cb93a386Sopenharmony_ciclass TestFP : public GrFragmentProcessor { 91cb93a386Sopenharmony_cipublic: 92cb93a386Sopenharmony_ci static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child) { 93cb93a386Sopenharmony_ci return std::unique_ptr<GrFragmentProcessor>(new TestFP(std::move(child))); 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci static std::unique_ptr<GrFragmentProcessor> Make(const SkTArray<GrSurfaceProxyView>& views) { 96cb93a386Sopenharmony_ci return std::unique_ptr<GrFragmentProcessor>(new TestFP(views)); 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci const char* name() const override { return "test"; } 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { 102cb93a386Sopenharmony_ci static std::atomic<int32_t> nextKey{0}; 103cb93a386Sopenharmony_ci b->add32(nextKey++); 104cb93a386Sopenharmony_ci } 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> clone() const override { 107cb93a386Sopenharmony_ci return std::unique_ptr<GrFragmentProcessor>(new TestFP(*this)); 108cb93a386Sopenharmony_ci } 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ciprivate: 111cb93a386Sopenharmony_ci TestFP(const SkTArray<GrSurfaceProxyView>& views) 112cb93a386Sopenharmony_ci : INHERITED(kTestFP_ClassID, kNone_OptimizationFlags) { 113cb93a386Sopenharmony_ci for (const GrSurfaceProxyView& view : views) { 114cb93a386Sopenharmony_ci this->registerChild(GrTextureEffect::Make(view, kUnknown_SkAlphaType)); 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci } 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_ci TestFP(std::unique_ptr<GrFragmentProcessor> child) 119cb93a386Sopenharmony_ci : INHERITED(kTestFP_ClassID, kNone_OptimizationFlags) { 120cb93a386Sopenharmony_ci this->registerChild(std::move(child)); 121cb93a386Sopenharmony_ci } 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci explicit TestFP(const TestFP& that) : INHERITED(that) {} 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ci std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override { 126cb93a386Sopenharmony_ci class Impl : public ProgramImpl { 127cb93a386Sopenharmony_ci public: 128cb93a386Sopenharmony_ci void emitCode(EmitArgs& args) override { 129cb93a386Sopenharmony_ci args.fFragBuilder->codeAppendf("return half4(1);"); 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci private: 133cb93a386Sopenharmony_ci }; 134cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 135cb93a386Sopenharmony_ci } 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_ci bool onIsEqual(const GrFragmentProcessor&) const override { return false; } 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci using INHERITED = GrFragmentProcessor; 140cb93a386Sopenharmony_ci}; 141cb93a386Sopenharmony_ci} // namespace 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_ALL_CONTEXTS(ProcessorRefTest, reporter, ctxInfo) { 144cb93a386Sopenharmony_ci auto dContext = ctxInfo.directContext(); 145cb93a386Sopenharmony_ci GrProxyProvider* proxyProvider = dContext->priv().proxyProvider(); 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci static constexpr SkISize kDims = {10, 10}; 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_ci const GrBackendFormat format = 150cb93a386Sopenharmony_ci dContext->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888, 151cb93a386Sopenharmony_ci GrRenderable::kNo); 152cb93a386Sopenharmony_ci GrSwizzle swizzle = dContext->priv().caps()->getReadSwizzle(format, GrColorType::kRGBA_8888); 153cb93a386Sopenharmony_ci 154cb93a386Sopenharmony_ci for (bool makeClone : {false, true}) { 155cb93a386Sopenharmony_ci for (int parentCnt = 0; parentCnt < 2; parentCnt++) { 156cb93a386Sopenharmony_ci auto sdc = skgpu::v1::SurfaceDrawContext::Make( 157cb93a386Sopenharmony_ci dContext, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox, {1, 1}, 158cb93a386Sopenharmony_ci SkSurfaceProps()); 159cb93a386Sopenharmony_ci { 160cb93a386Sopenharmony_ci sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy( 161cb93a386Sopenharmony_ci format, kDims, GrRenderable::kNo, 1, GrMipmapped::kNo, SkBackingFit::kExact, 162cb93a386Sopenharmony_ci SkBudgeted::kYes, GrProtected::kNo); 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ci { 165cb93a386Sopenharmony_ci SkTArray<GrSurfaceProxyView> views; 166cb93a386Sopenharmony_ci views.push_back({proxy, kTopLeft_GrSurfaceOrigin, swizzle}); 167cb93a386Sopenharmony_ci auto fp = TestFP::Make(std::move(views)); 168cb93a386Sopenharmony_ci for (int i = 0; i < parentCnt; ++i) { 169cb93a386Sopenharmony_ci fp = TestFP::Make(std::move(fp)); 170cb93a386Sopenharmony_ci } 171cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> clone; 172cb93a386Sopenharmony_ci if (makeClone) { 173cb93a386Sopenharmony_ci clone = fp->clone(); 174cb93a386Sopenharmony_ci } 175cb93a386Sopenharmony_ci GrOp::Owner op = TestOp::Make(dContext, std::move(fp)); 176cb93a386Sopenharmony_ci sdc->addDrawOp(std::move(op)); 177cb93a386Sopenharmony_ci if (clone) { 178cb93a386Sopenharmony_ci op = TestOp::Make(dContext, std::move(clone)); 179cb93a386Sopenharmony_ci sdc->addDrawOp(std::move(op)); 180cb93a386Sopenharmony_ci } 181cb93a386Sopenharmony_ci } 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ci // If the fp is cloned the number of refs should increase by one (for the clone) 184cb93a386Sopenharmony_ci int expectedProxyRefs = makeClone ? 3 : 2; 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_ci CheckSingleThreadedProxyRefs(reporter, proxy.get(), expectedProxyRefs, -1); 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci dContext->flushAndSubmit(); 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci // just one from the 'proxy' sk_sp 191cb93a386Sopenharmony_ci CheckSingleThreadedProxyRefs(reporter, proxy.get(), 1, 1); 192cb93a386Sopenharmony_ci } 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci } 195cb93a386Sopenharmony_ci} 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_ci#include "tools/flags/CommandLineFlags.h" 198cb93a386Sopenharmony_cistatic DEFINE_bool(randomProcessorTest, false, 199cb93a386Sopenharmony_ci "Use non-deterministic seed for random processor tests?"); 200cb93a386Sopenharmony_cistatic DEFINE_int(processorSeed, 0, 201cb93a386Sopenharmony_ci "Use specific seed for processor tests. Overridden by --randomProcessorTest."); 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci#if GR_TEST_UTILS 204cb93a386Sopenharmony_ci 205cb93a386Sopenharmony_cistatic GrColor input_texel_color(int x, int y, SkScalar delta) { 206cb93a386Sopenharmony_ci // Delta must be less than 0.5 to prevent over/underflow issues with the input color 207cb93a386Sopenharmony_ci SkASSERT(delta <= 0.5); 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci SkColor color = SkColorSetARGB((uint8_t)(x & 0xFF), 210cb93a386Sopenharmony_ci (uint8_t)(y & 0xFF), 211cb93a386Sopenharmony_ci (uint8_t)((x + y) & 0xFF), 212cb93a386Sopenharmony_ci (uint8_t)((2 * y - x) & 0xFF)); 213cb93a386Sopenharmony_ci SkColor4f color4f = SkColor4f::FromColor(color); 214cb93a386Sopenharmony_ci // We only apply delta to the r,g, and b channels. This is because we're using this 215cb93a386Sopenharmony_ci // to test the canTweakAlphaForCoverage() optimization. A processor is allowed 216cb93a386Sopenharmony_ci // to use the input color's alpha in its calculation and report this optimization. 217cb93a386Sopenharmony_ci for (int i = 0; i < 3; i++) { 218cb93a386Sopenharmony_ci if (color4f[i] > 0.5) { 219cb93a386Sopenharmony_ci color4f[i] -= delta; 220cb93a386Sopenharmony_ci } else { 221cb93a386Sopenharmony_ci color4f[i] += delta; 222cb93a386Sopenharmony_ci } 223cb93a386Sopenharmony_ci } 224cb93a386Sopenharmony_ci return color4f.premul().toBytes_RGBA(); 225cb93a386Sopenharmony_ci} 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci// The output buffer must be the same size as the render-target context. 228cb93a386Sopenharmony_cistatic void render_fp(GrDirectContext* dContext, 229cb93a386Sopenharmony_ci skgpu::v1::SurfaceDrawContext* sdc, 230cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> fp, 231cb93a386Sopenharmony_ci GrColor* outBuffer) { 232cb93a386Sopenharmony_ci sdc->fillWithFP(std::move(fp)); 233cb93a386Sopenharmony_ci std::fill_n(outBuffer, sdc->width() * sdc->height(), 0); 234cb93a386Sopenharmony_ci auto ii = SkImageInfo::Make(sdc->dimensions(), kRGBA_8888_SkColorType, kPremul_SkAlphaType); 235cb93a386Sopenharmony_ci GrPixmap resultPM(ii, outBuffer, sdc->width()*sizeof(uint32_t)); 236cb93a386Sopenharmony_ci sdc->readPixels(dContext, resultPM, {0, 0}); 237cb93a386Sopenharmony_ci} 238cb93a386Sopenharmony_ci 239cb93a386Sopenharmony_ci// This class is responsible for reproducibly generating a random fragment processor. 240cb93a386Sopenharmony_ci// An identical randomly-designed FP can be generated as many times as needed. 241cb93a386Sopenharmony_ciclass TestFPGenerator { 242cb93a386Sopenharmony_ci public: 243cb93a386Sopenharmony_ci TestFPGenerator() = delete; 244cb93a386Sopenharmony_ci TestFPGenerator(GrDirectContext* context, GrResourceProvider* resourceProvider) 245cb93a386Sopenharmony_ci : fContext(context) 246cb93a386Sopenharmony_ci , fResourceProvider(resourceProvider) 247cb93a386Sopenharmony_ci , fInitialSeed(synthesizeInitialSeed()) 248cb93a386Sopenharmony_ci , fRandomSeed(fInitialSeed) {} 249cb93a386Sopenharmony_ci 250cb93a386Sopenharmony_ci uint32_t initialSeed() { return fInitialSeed; } 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci bool init() { 253cb93a386Sopenharmony_ci // Initializes the two test texture proxies that are available to the FP test factories. 254cb93a386Sopenharmony_ci SkRandom random{fRandomSeed}; 255cb93a386Sopenharmony_ci static constexpr int kTestTextureSize = 256; 256cb93a386Sopenharmony_ci 257cb93a386Sopenharmony_ci { 258cb93a386Sopenharmony_ci // Put premul data into the RGBA texture that the test FPs can optionally use. 259cb93a386Sopenharmony_ci GrColor* rgbaData = new GrColor[kTestTextureSize * kTestTextureSize]; 260cb93a386Sopenharmony_ci for (int y = 0; y < kTestTextureSize; ++y) { 261cb93a386Sopenharmony_ci for (int x = 0; x < kTestTextureSize; ++x) { 262cb93a386Sopenharmony_ci rgbaData[kTestTextureSize * y + x] = input_texel_color( 263cb93a386Sopenharmony_ci random.nextULessThan(256), random.nextULessThan(256), 0.0f); 264cb93a386Sopenharmony_ci } 265cb93a386Sopenharmony_ci } 266cb93a386Sopenharmony_ci 267cb93a386Sopenharmony_ci SkImageInfo ii = SkImageInfo::Make(kTestTextureSize, kTestTextureSize, 268cb93a386Sopenharmony_ci kRGBA_8888_SkColorType, kPremul_SkAlphaType); 269cb93a386Sopenharmony_ci SkBitmap bitmap; 270cb93a386Sopenharmony_ci bitmap.installPixels( 271cb93a386Sopenharmony_ci ii, rgbaData, ii.minRowBytes(), 272cb93a386Sopenharmony_ci [](void* addr, void* context) { delete[](GrColor*) addr; }, nullptr); 273cb93a386Sopenharmony_ci bitmap.setImmutable(); 274cb93a386Sopenharmony_ci auto view = std::get<0>(GrMakeUncachedBitmapProxyView(fContext, bitmap)); 275cb93a386Sopenharmony_ci if (!view || !view.proxy()->instantiate(fResourceProvider)) { 276cb93a386Sopenharmony_ci SkDebugf("Unable to instantiate RGBA8888 test texture."); 277cb93a386Sopenharmony_ci return false; 278cb93a386Sopenharmony_ci } 279cb93a386Sopenharmony_ci fTestViews[0] = GrProcessorTestData::ViewInfo{view, GrColorType::kRGBA_8888, 280cb93a386Sopenharmony_ci kPremul_SkAlphaType}; 281cb93a386Sopenharmony_ci } 282cb93a386Sopenharmony_ci 283cb93a386Sopenharmony_ci { 284cb93a386Sopenharmony_ci // Put random values into the alpha texture that the test FPs can optionally use. 285cb93a386Sopenharmony_ci uint8_t* alphaData = new uint8_t[kTestTextureSize * kTestTextureSize]; 286cb93a386Sopenharmony_ci for (int y = 0; y < kTestTextureSize; ++y) { 287cb93a386Sopenharmony_ci for (int x = 0; x < kTestTextureSize; ++x) { 288cb93a386Sopenharmony_ci alphaData[kTestTextureSize * y + x] = random.nextULessThan(256); 289cb93a386Sopenharmony_ci } 290cb93a386Sopenharmony_ci } 291cb93a386Sopenharmony_ci 292cb93a386Sopenharmony_ci SkImageInfo ii = SkImageInfo::Make(kTestTextureSize, kTestTextureSize, 293cb93a386Sopenharmony_ci kAlpha_8_SkColorType, kPremul_SkAlphaType); 294cb93a386Sopenharmony_ci SkBitmap bitmap; 295cb93a386Sopenharmony_ci bitmap.installPixels( 296cb93a386Sopenharmony_ci ii, alphaData, ii.minRowBytes(), 297cb93a386Sopenharmony_ci [](void* addr, void* context) { delete[](uint8_t*) addr; }, nullptr); 298cb93a386Sopenharmony_ci bitmap.setImmutable(); 299cb93a386Sopenharmony_ci auto view = std::get<0>(GrMakeUncachedBitmapProxyView(fContext, bitmap)); 300cb93a386Sopenharmony_ci if (!view || !view.proxy()->instantiate(fResourceProvider)) { 301cb93a386Sopenharmony_ci SkDebugf("Unable to instantiate A8 test texture."); 302cb93a386Sopenharmony_ci return false; 303cb93a386Sopenharmony_ci } 304cb93a386Sopenharmony_ci fTestViews[1] = GrProcessorTestData::ViewInfo{view, GrColorType::kAlpha_8, 305cb93a386Sopenharmony_ci kPremul_SkAlphaType}; 306cb93a386Sopenharmony_ci } 307cb93a386Sopenharmony_ci 308cb93a386Sopenharmony_ci return true; 309cb93a386Sopenharmony_ci } 310cb93a386Sopenharmony_ci 311cb93a386Sopenharmony_ci void reroll() { 312cb93a386Sopenharmony_ci // Feed our current random seed into SkRandom to generate a new seed. 313cb93a386Sopenharmony_ci SkRandom random{fRandomSeed}; 314cb93a386Sopenharmony_ci fRandomSeed = random.nextU(); 315cb93a386Sopenharmony_ci } 316cb93a386Sopenharmony_ci 317cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> make(int type, int randomTreeDepth, 318cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> inputFP) { 319cb93a386Sopenharmony_ci // This will generate the exact same randomized FP (of each requested type) each time 320cb93a386Sopenharmony_ci // it's called. Call `reroll` to get a different FP. 321cb93a386Sopenharmony_ci SkRandom random{fRandomSeed}; 322cb93a386Sopenharmony_ci GrProcessorTestData testData{&random, fContext, randomTreeDepth, 323cb93a386Sopenharmony_ci SK_ARRAY_COUNT(fTestViews), fTestViews, 324cb93a386Sopenharmony_ci std::move(inputFP)}; 325cb93a386Sopenharmony_ci return GrFragmentProcessorTestFactory::MakeIdx(type, &testData); 326cb93a386Sopenharmony_ci } 327cb93a386Sopenharmony_ci 328cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> make(int type, int randomTreeDepth, 329cb93a386Sopenharmony_ci GrSurfaceProxyView view, 330cb93a386Sopenharmony_ci SkAlphaType alpha = kPremul_SkAlphaType) { 331cb93a386Sopenharmony_ci return make(type, randomTreeDepth, GrTextureEffect::Make(view, alpha)); 332cb93a386Sopenharmony_ci } 333cb93a386Sopenharmony_ci 334cb93a386Sopenharmony_ci private: 335cb93a386Sopenharmony_ci static uint32_t synthesizeInitialSeed() { 336cb93a386Sopenharmony_ci if (FLAGS_randomProcessorTest) { 337cb93a386Sopenharmony_ci std::random_device rd; 338cb93a386Sopenharmony_ci return rd(); 339cb93a386Sopenharmony_ci } else { 340cb93a386Sopenharmony_ci return FLAGS_processorSeed; 341cb93a386Sopenharmony_ci } 342cb93a386Sopenharmony_ci } 343cb93a386Sopenharmony_ci 344cb93a386Sopenharmony_ci GrDirectContext* fContext; // owned by caller 345cb93a386Sopenharmony_ci GrResourceProvider* fResourceProvider; // owned by caller 346cb93a386Sopenharmony_ci const uint32_t fInitialSeed; 347cb93a386Sopenharmony_ci uint32_t fRandomSeed; 348cb93a386Sopenharmony_ci GrProcessorTestData::ViewInfo fTestViews[2]; 349cb93a386Sopenharmony_ci}; 350cb93a386Sopenharmony_ci 351cb93a386Sopenharmony_ci// Creates an array of color values from input_texel_color(), to be used as an input texture. 352cb93a386Sopenharmony_cistatic std::vector<GrColor> make_input_pixels(int width, int height, SkScalar delta) { 353cb93a386Sopenharmony_ci std::vector<GrColor> pixel(width * height); 354cb93a386Sopenharmony_ci for (int y = 0; y < width; ++y) { 355cb93a386Sopenharmony_ci for (int x = 0; x < height; ++x) { 356cb93a386Sopenharmony_ci pixel[width * y + x] = input_texel_color(x, y, delta); 357cb93a386Sopenharmony_ci } 358cb93a386Sopenharmony_ci } 359cb93a386Sopenharmony_ci 360cb93a386Sopenharmony_ci return pixel; 361cb93a386Sopenharmony_ci} 362cb93a386Sopenharmony_ci 363cb93a386Sopenharmony_ci// Creates a texture of premul colors used as the output of the fragment processor that precedes 364cb93a386Sopenharmony_ci// the fragment processor under test. An array of W*H colors are passed in as the texture data. 365cb93a386Sopenharmony_cistatic GrSurfaceProxyView make_input_texture(GrRecordingContext* context, 366cb93a386Sopenharmony_ci int width, int height, GrColor* pixel) { 367cb93a386Sopenharmony_ci SkImageInfo ii = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 368cb93a386Sopenharmony_ci SkBitmap bitmap; 369cb93a386Sopenharmony_ci bitmap.installPixels(ii, pixel, ii.minRowBytes()); 370cb93a386Sopenharmony_ci bitmap.setImmutable(); 371cb93a386Sopenharmony_ci return std::get<0>(GrMakeUncachedBitmapProxyView(context, bitmap)); 372cb93a386Sopenharmony_ci} 373cb93a386Sopenharmony_ci 374cb93a386Sopenharmony_ci// We tag logged data as unpremul to avoid conversion when encoding as PNG. The input texture 375cb93a386Sopenharmony_ci// actually contains unpremul data. Also, even though we made the result data by rendering into 376cb93a386Sopenharmony_ci// a "unpremul" SurfaceDrawContext, our input texture is unpremul and outside of the random 377cb93a386Sopenharmony_ci// effect configuration, we didn't do anything to ensure the output is actually premul. We just 378cb93a386Sopenharmony_ci// don't currently allow kUnpremul GrSurfaceDrawContexts. 379cb93a386Sopenharmony_cistatic constexpr auto kLogAlphaType = kUnpremul_SkAlphaType; 380cb93a386Sopenharmony_ci 381cb93a386Sopenharmony_cistatic bool log_pixels(GrColor* pixels, int widthHeight, SkString* dst) { 382cb93a386Sopenharmony_ci SkImageInfo info = 383cb93a386Sopenharmony_ci SkImageInfo::Make(widthHeight, widthHeight, kRGBA_8888_SkColorType, kLogAlphaType); 384cb93a386Sopenharmony_ci SkBitmap bmp; 385cb93a386Sopenharmony_ci bmp.installPixels(info, pixels, widthHeight * sizeof(GrColor)); 386cb93a386Sopenharmony_ci return BipmapToBase64DataURI(bmp, dst); 387cb93a386Sopenharmony_ci} 388cb93a386Sopenharmony_ci 389cb93a386Sopenharmony_cistatic bool log_texture_view(GrDirectContext* dContext, GrSurfaceProxyView src, SkString* dst) { 390cb93a386Sopenharmony_ci SkImageInfo ii = SkImageInfo::Make(src.proxy()->dimensions(), kRGBA_8888_SkColorType, 391cb93a386Sopenharmony_ci kLogAlphaType); 392cb93a386Sopenharmony_ci 393cb93a386Sopenharmony_ci auto sContext = dContext->priv().makeSC(std::move(src), ii.colorInfo()); 394cb93a386Sopenharmony_ci SkBitmap bm; 395cb93a386Sopenharmony_ci SkAssertResult(bm.tryAllocPixels(ii)); 396cb93a386Sopenharmony_ci SkAssertResult(sContext->readPixels(dContext, bm.pixmap(), {0, 0})); 397cb93a386Sopenharmony_ci return BipmapToBase64DataURI(bm, dst); 398cb93a386Sopenharmony_ci} 399cb93a386Sopenharmony_ci 400cb93a386Sopenharmony_cistatic bool fuzzy_color_equals(const SkPMColor4f& c1, const SkPMColor4f& c2) { 401cb93a386Sopenharmony_ci // With the loss of precision of rendering into 32-bit color, then estimating the FP's output 402cb93a386Sopenharmony_ci // from that, it is not uncommon for a valid output to differ from estimate by up to 0.01 403cb93a386Sopenharmony_ci // (really 1/128 ~ .0078, but frequently floating point issues make that tolerance a little 404cb93a386Sopenharmony_ci // too unforgiving). 405cb93a386Sopenharmony_ci static constexpr SkScalar kTolerance = 0.01f; 406cb93a386Sopenharmony_ci for (int i = 0; i < 4; i++) { 407cb93a386Sopenharmony_ci if (!SkScalarNearlyEqual(c1[i], c2[i], kTolerance)) { 408cb93a386Sopenharmony_ci return false; 409cb93a386Sopenharmony_ci } 410cb93a386Sopenharmony_ci } 411cb93a386Sopenharmony_ci return true; 412cb93a386Sopenharmony_ci} 413cb93a386Sopenharmony_ci 414cb93a386Sopenharmony_ci// Given three input colors (color preceding the FP being tested) provided to the FP at the same 415cb93a386Sopenharmony_ci// local coord and the three corresponding FP outputs, this ensures that either: 416cb93a386Sopenharmony_ci// out[0] = fp * in[0].a, out[1] = fp * in[1].a, and out[2] = fp * in[2].a 417cb93a386Sopenharmony_ci// where fp is the pre-modulated color that should not be changing across frames (FP's state doesn't 418cb93a386Sopenharmony_ci// change), OR: 419cb93a386Sopenharmony_ci// out[0] = fp * in[0], out[1] = fp * in[1], and out[2] = fp * in[2] 420cb93a386Sopenharmony_ci// (per-channel modulation instead of modulation by just the alpha channel) 421cb93a386Sopenharmony_ci// It does this by estimating the pre-modulated fp color from one of the input/output pairs and 422cb93a386Sopenharmony_ci// confirms the conditions hold for the other two pairs. 423cb93a386Sopenharmony_ci// It is required that the three input colors have the same alpha as fp is allowed to be a function 424cb93a386Sopenharmony_ci// of the input alpha (but not r, g, or b). 425cb93a386Sopenharmony_cistatic bool legal_modulation(const GrColor inGr[3], const GrColor outGr[3]) { 426cb93a386Sopenharmony_ci // Convert to floating point, which is the number space the FP operates in (more or less) 427cb93a386Sopenharmony_ci SkPMColor4f inf[3], outf[3]; 428cb93a386Sopenharmony_ci for (int i = 0; i < 3; ++i) { 429cb93a386Sopenharmony_ci inf[i] = SkPMColor4f::FromBytes_RGBA(inGr[i]); 430cb93a386Sopenharmony_ci outf[i] = SkPMColor4f::FromBytes_RGBA(outGr[i]); 431cb93a386Sopenharmony_ci } 432cb93a386Sopenharmony_ci // This test is only valid if all the input alphas are the same. 433cb93a386Sopenharmony_ci SkASSERT(inf[0].fA == inf[1].fA && inf[1].fA == inf[2].fA); 434cb93a386Sopenharmony_ci 435cb93a386Sopenharmony_ci // Reconstruct the output of the FP before the shader modulated its color with the input value. 436cb93a386Sopenharmony_ci // When the original input is very small, it may cause the final output color to round 437cb93a386Sopenharmony_ci // to 0, in which case we estimate the pre-modulated color using one of the stepped frames that 438cb93a386Sopenharmony_ci // will then have a guaranteed larger channel value (since the offset will be added to it). 439cb93a386Sopenharmony_ci SkPMColor4f fpPreColorModulation = {0,0,0,0}; 440cb93a386Sopenharmony_ci SkPMColor4f fpPreAlphaModulation = {0,0,0,0}; 441cb93a386Sopenharmony_ci for (int i = 0; i < 4; i++) { 442cb93a386Sopenharmony_ci // Use the most stepped up frame 443cb93a386Sopenharmony_ci int maxInIdx = inf[0][i] > inf[1][i] ? 0 : 1; 444cb93a386Sopenharmony_ci maxInIdx = inf[maxInIdx][i] > inf[2][i] ? maxInIdx : 2; 445cb93a386Sopenharmony_ci const SkPMColor4f& in = inf[maxInIdx]; 446cb93a386Sopenharmony_ci const SkPMColor4f& out = outf[maxInIdx]; 447cb93a386Sopenharmony_ci if (in[i] > 0) { 448cb93a386Sopenharmony_ci fpPreColorModulation[i] = out[i] / in[i]; 449cb93a386Sopenharmony_ci } 450cb93a386Sopenharmony_ci if (in[3] > 0) { 451cb93a386Sopenharmony_ci fpPreAlphaModulation[i] = out[i] / in[3]; 452cb93a386Sopenharmony_ci } 453cb93a386Sopenharmony_ci } 454cb93a386Sopenharmony_ci 455cb93a386Sopenharmony_ci // With reconstructed pre-modulated FP output, derive the expected value of fp * input for each 456cb93a386Sopenharmony_ci // of the transformed input colors. 457cb93a386Sopenharmony_ci SkPMColor4f expectedForAlphaModulation[3]; 458cb93a386Sopenharmony_ci SkPMColor4f expectedForColorModulation[3]; 459cb93a386Sopenharmony_ci for (int i = 0; i < 3; ++i) { 460cb93a386Sopenharmony_ci expectedForAlphaModulation[i] = fpPreAlphaModulation * inf[i].fA; 461cb93a386Sopenharmony_ci expectedForColorModulation[i] = fpPreColorModulation * inf[i]; 462cb93a386Sopenharmony_ci // If the input alpha is 0 then the other channels should also be zero 463cb93a386Sopenharmony_ci // since the color is assumed to be premul. Modulating zeros by anything 464cb93a386Sopenharmony_ci // should produce zeros. 465cb93a386Sopenharmony_ci if (inf[i].fA == 0) { 466cb93a386Sopenharmony_ci SkASSERT(inf[i].fR == 0 && inf[i].fG == 0 && inf[i].fB == 0); 467cb93a386Sopenharmony_ci expectedForColorModulation[i] = expectedForAlphaModulation[i] = {0, 0, 0, 0}; 468cb93a386Sopenharmony_ci } 469cb93a386Sopenharmony_ci } 470cb93a386Sopenharmony_ci 471cb93a386Sopenharmony_ci bool isLegalColorModulation = fuzzy_color_equals(outf[0], expectedForColorModulation[0]) && 472cb93a386Sopenharmony_ci fuzzy_color_equals(outf[1], expectedForColorModulation[1]) && 473cb93a386Sopenharmony_ci fuzzy_color_equals(outf[2], expectedForColorModulation[2]); 474cb93a386Sopenharmony_ci 475cb93a386Sopenharmony_ci bool isLegalAlphaModulation = fuzzy_color_equals(outf[0], expectedForAlphaModulation[0]) && 476cb93a386Sopenharmony_ci fuzzy_color_equals(outf[1], expectedForAlphaModulation[1]) && 477cb93a386Sopenharmony_ci fuzzy_color_equals(outf[2], expectedForAlphaModulation[2]); 478cb93a386Sopenharmony_ci 479cb93a386Sopenharmony_ci // This can be enabled to print the values that caused this check to fail. 480cb93a386Sopenharmony_ci if (0 && !isLegalColorModulation && !isLegalAlphaModulation) { 481cb93a386Sopenharmony_ci SkDebugf("Color modulation test\n\timplied mod color: (%.03f, %.03f, %.03f, %.03f)\n", 482cb93a386Sopenharmony_ci fpPreColorModulation[0], 483cb93a386Sopenharmony_ci fpPreColorModulation[1], 484cb93a386Sopenharmony_ci fpPreColorModulation[2], 485cb93a386Sopenharmony_ci fpPreColorModulation[3]); 486cb93a386Sopenharmony_ci for (int i = 0; i < 3; ++i) { 487cb93a386Sopenharmony_ci SkDebugf("\t(%.03f, %.03f, %.03f, %.03f) -> " 488cb93a386Sopenharmony_ci "(%.03f, %.03f, %.03f, %.03f) | " 489cb93a386Sopenharmony_ci "(%.03f, %.03f, %.03f, %.03f), ok: %d\n", 490cb93a386Sopenharmony_ci inf[i].fR, inf[i].fG, inf[i].fB, inf[i].fA, 491cb93a386Sopenharmony_ci outf[i].fR, outf[i].fG, outf[i].fB, outf[i].fA, 492cb93a386Sopenharmony_ci expectedForColorModulation[i].fR, expectedForColorModulation[i].fG, 493cb93a386Sopenharmony_ci expectedForColorModulation[i].fB, expectedForColorModulation[i].fA, 494cb93a386Sopenharmony_ci fuzzy_color_equals(outf[i], expectedForColorModulation[i])); 495cb93a386Sopenharmony_ci } 496cb93a386Sopenharmony_ci SkDebugf("Alpha modulation test\n\timplied mod color: (%.03f, %.03f, %.03f, %.03f)\n", 497cb93a386Sopenharmony_ci fpPreAlphaModulation[0], 498cb93a386Sopenharmony_ci fpPreAlphaModulation[1], 499cb93a386Sopenharmony_ci fpPreAlphaModulation[2], 500cb93a386Sopenharmony_ci fpPreAlphaModulation[3]); 501cb93a386Sopenharmony_ci for (int i = 0; i < 3; ++i) { 502cb93a386Sopenharmony_ci SkDebugf("\t(%.03f, %.03f, %.03f, %.03f) -> " 503cb93a386Sopenharmony_ci "(%.03f, %.03f, %.03f, %.03f) | " 504cb93a386Sopenharmony_ci "(%.03f, %.03f, %.03f, %.03f), ok: %d\n", 505cb93a386Sopenharmony_ci inf[i].fR, inf[i].fG, inf[i].fB, inf[i].fA, 506cb93a386Sopenharmony_ci outf[i].fR, outf[i].fG, outf[i].fB, outf[i].fA, 507cb93a386Sopenharmony_ci expectedForAlphaModulation[i].fR, expectedForAlphaModulation[i].fG, 508cb93a386Sopenharmony_ci expectedForAlphaModulation[i].fB, expectedForAlphaModulation[i].fA, 509cb93a386Sopenharmony_ci fuzzy_color_equals(outf[i], expectedForAlphaModulation[i])); 510cb93a386Sopenharmony_ci } 511cb93a386Sopenharmony_ci } 512cb93a386Sopenharmony_ci return isLegalColorModulation || isLegalAlphaModulation; 513cb93a386Sopenharmony_ci} 514cb93a386Sopenharmony_ci 515cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorOptimizationValidationTest, reporter, ctxInfo) { 516cb93a386Sopenharmony_ci GrDirectContext* context = ctxInfo.directContext(); 517cb93a386Sopenharmony_ci GrResourceProvider* resourceProvider = context->priv().resourceProvider(); 518cb93a386Sopenharmony_ci using FPFactory = GrFragmentProcessorTestFactory; 519cb93a386Sopenharmony_ci 520cb93a386Sopenharmony_ci TestFPGenerator fpGenerator{context, resourceProvider}; 521cb93a386Sopenharmony_ci if (!fpGenerator.init()) { 522cb93a386Sopenharmony_ci ERRORF(reporter, "Could not initialize TestFPGenerator"); 523cb93a386Sopenharmony_ci return; 524cb93a386Sopenharmony_ci } 525cb93a386Sopenharmony_ci 526cb93a386Sopenharmony_ci // Make the destination context for the test. 527cb93a386Sopenharmony_ci static constexpr int kRenderSize = 256; 528cb93a386Sopenharmony_ci auto sdc = skgpu::v1::SurfaceDrawContext::Make( 529cb93a386Sopenharmony_ci context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kExact, 530cb93a386Sopenharmony_ci {kRenderSize, kRenderSize}, SkSurfaceProps()); 531cb93a386Sopenharmony_ci 532cb93a386Sopenharmony_ci // Coverage optimization uses three frames with a linearly transformed input texture. The first 533cb93a386Sopenharmony_ci // frame has no offset, second frames add .2 and .4, which should then be present as a fixed 534cb93a386Sopenharmony_ci // difference between the frame outputs if the FP is properly following the modulation 535cb93a386Sopenharmony_ci // requirements of the coverage optimization. 536cb93a386Sopenharmony_ci static constexpr SkScalar kInputDelta = 0.2f; 537cb93a386Sopenharmony_ci std::vector<GrColor> inputPixels1 = make_input_pixels(kRenderSize, kRenderSize, 0.0f); 538cb93a386Sopenharmony_ci std::vector<GrColor> inputPixels2 = 539cb93a386Sopenharmony_ci make_input_pixels(kRenderSize, kRenderSize, 1 * kInputDelta); 540cb93a386Sopenharmony_ci std::vector<GrColor> inputPixels3 = 541cb93a386Sopenharmony_ci make_input_pixels(kRenderSize, kRenderSize, 2 * kInputDelta); 542cb93a386Sopenharmony_ci GrSurfaceProxyView inputTexture1 = 543cb93a386Sopenharmony_ci make_input_texture(context, kRenderSize, kRenderSize, inputPixels1.data()); 544cb93a386Sopenharmony_ci GrSurfaceProxyView inputTexture2 = 545cb93a386Sopenharmony_ci make_input_texture(context, kRenderSize, kRenderSize, inputPixels2.data()); 546cb93a386Sopenharmony_ci GrSurfaceProxyView inputTexture3 = 547cb93a386Sopenharmony_ci make_input_texture(context, kRenderSize, kRenderSize, inputPixels3.data()); 548cb93a386Sopenharmony_ci 549cb93a386Sopenharmony_ci // Encoded images are very verbose and this tests many potential images, so only export the 550cb93a386Sopenharmony_ci // first failure (subsequent failures have a reasonable chance of being related). 551cb93a386Sopenharmony_ci bool loggedFirstFailure = false; 552cb93a386Sopenharmony_ci bool loggedFirstWarning = false; 553cb93a386Sopenharmony_ci 554cb93a386Sopenharmony_ci // Storage for the three frames required for coverage compatibility optimization testing. 555cb93a386Sopenharmony_ci // Each frame uses the correspondingly numbered inputTextureX. 556cb93a386Sopenharmony_ci std::vector<GrColor> readData1(kRenderSize * kRenderSize); 557cb93a386Sopenharmony_ci std::vector<GrColor> readData2(kRenderSize * kRenderSize); 558cb93a386Sopenharmony_ci std::vector<GrColor> readData3(kRenderSize * kRenderSize); 559cb93a386Sopenharmony_ci 560cb93a386Sopenharmony_ci // Because processor factories configure themselves in random ways, this is not exhaustive. 561cb93a386Sopenharmony_ci for (int i = 0; i < FPFactory::Count(); ++i) { 562cb93a386Sopenharmony_ci int optimizedForOpaqueInput = 0; 563cb93a386Sopenharmony_ci int optimizedForCoverageAsAlpha = 0; 564cb93a386Sopenharmony_ci int optimizedForConstantOutputForInput = 0; 565cb93a386Sopenharmony_ci 566cb93a386Sopenharmony_ci#ifdef __MSVC_RUNTIME_CHECKS 567cb93a386Sopenharmony_ci // This test is infuriatingly slow with MSVC runtime checks enabled 568cb93a386Sopenharmony_ci static constexpr int kMinimumTrials = 1; 569cb93a386Sopenharmony_ci static constexpr int kMaximumTrials = 1; 570cb93a386Sopenharmony_ci static constexpr int kExpectedSuccesses = 1; 571cb93a386Sopenharmony_ci#else 572cb93a386Sopenharmony_ci // We start by testing each fragment-processor 100 times, watching the optimization bits 573cb93a386Sopenharmony_ci // that appear. If we see an optimization bit appear in those first 100 trials, we keep 574cb93a386Sopenharmony_ci // running tests until we see at least five successful trials that have this optimization 575cb93a386Sopenharmony_ci // bit enabled. If we never see a particular optimization bit after 100 trials, we assume 576cb93a386Sopenharmony_ci // that this FP doesn't support that optimization at all. 577cb93a386Sopenharmony_ci static constexpr int kMinimumTrials = 100; 578cb93a386Sopenharmony_ci static constexpr int kMaximumTrials = 2000; 579cb93a386Sopenharmony_ci static constexpr int kExpectedSuccesses = 5; 580cb93a386Sopenharmony_ci#endif 581cb93a386Sopenharmony_ci 582cb93a386Sopenharmony_ci for (int trial = 0;; ++trial) { 583cb93a386Sopenharmony_ci // Create a randomly-configured FP. 584cb93a386Sopenharmony_ci fpGenerator.reroll(); 585cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> fp = 586cb93a386Sopenharmony_ci fpGenerator.make(i, /*randomTreeDepth=*/1, inputTexture1); 587cb93a386Sopenharmony_ci 588cb93a386Sopenharmony_ci // If we have iterated enough times and seen a sufficient number of successes on each 589cb93a386Sopenharmony_ci // optimization bit that can be returned, stop running trials. 590cb93a386Sopenharmony_ci if (trial >= kMinimumTrials) { 591cb93a386Sopenharmony_ci bool moreTrialsNeeded = (optimizedForOpaqueInput > 0 && 592cb93a386Sopenharmony_ci optimizedForOpaqueInput < kExpectedSuccesses) || 593cb93a386Sopenharmony_ci (optimizedForCoverageAsAlpha > 0 && 594cb93a386Sopenharmony_ci optimizedForCoverageAsAlpha < kExpectedSuccesses) || 595cb93a386Sopenharmony_ci (optimizedForConstantOutputForInput > 0 && 596cb93a386Sopenharmony_ci optimizedForConstantOutputForInput < kExpectedSuccesses); 597cb93a386Sopenharmony_ci if (!moreTrialsNeeded) break; 598cb93a386Sopenharmony_ci 599cb93a386Sopenharmony_ci if (trial >= kMaximumTrials) { 600cb93a386Sopenharmony_ci SkDebugf("Abandoning ProcessorOptimizationValidationTest after %d trials. " 601cb93a386Sopenharmony_ci "Seed: 0x%08x, processor:\n%s", 602cb93a386Sopenharmony_ci kMaximumTrials, fpGenerator.initialSeed(), fp->dumpTreeInfo().c_str()); 603cb93a386Sopenharmony_ci break; 604cb93a386Sopenharmony_ci } 605cb93a386Sopenharmony_ci } 606cb93a386Sopenharmony_ci 607cb93a386Sopenharmony_ci // Skip further testing if this trial has no optimization bits enabled. 608cb93a386Sopenharmony_ci if (!fp->hasConstantOutputForConstantInput() && !fp->preservesOpaqueInput() && 609cb93a386Sopenharmony_ci !fp->compatibleWithCoverageAsAlpha()) { 610cb93a386Sopenharmony_ci continue; 611cb93a386Sopenharmony_ci } 612cb93a386Sopenharmony_ci 613cb93a386Sopenharmony_ci // We can make identical copies of the test FP in order to test coverage-as-alpha. 614cb93a386Sopenharmony_ci if (fp->compatibleWithCoverageAsAlpha()) { 615cb93a386Sopenharmony_ci // Create and render two identical versions of this FP, but using different input 616cb93a386Sopenharmony_ci // textures, to check coverage optimization. We don't need to do this step for 617cb93a386Sopenharmony_ci // constant-output or preserving-opacity tests. 618cb93a386Sopenharmony_ci render_fp(context, sdc.get(), 619cb93a386Sopenharmony_ci fpGenerator.make(i, /*randomTreeDepth=*/1, inputTexture2), 620cb93a386Sopenharmony_ci readData2.data()); 621cb93a386Sopenharmony_ci render_fp(context, sdc.get(), 622cb93a386Sopenharmony_ci fpGenerator.make(i, /*randomTreeDepth=*/1, inputTexture3), 623cb93a386Sopenharmony_ci readData3.data()); 624cb93a386Sopenharmony_ci ++optimizedForCoverageAsAlpha; 625cb93a386Sopenharmony_ci } 626cb93a386Sopenharmony_ci 627cb93a386Sopenharmony_ci if (fp->hasConstantOutputForConstantInput()) { 628cb93a386Sopenharmony_ci ++optimizedForConstantOutputForInput; 629cb93a386Sopenharmony_ci } 630cb93a386Sopenharmony_ci 631cb93a386Sopenharmony_ci if (fp->preservesOpaqueInput()) { 632cb93a386Sopenharmony_ci ++optimizedForOpaqueInput; 633cb93a386Sopenharmony_ci } 634cb93a386Sopenharmony_ci 635cb93a386Sopenharmony_ci // Draw base frame last so that rtc holds the original FP behavior if we need to dump 636cb93a386Sopenharmony_ci // the image to the log. 637cb93a386Sopenharmony_ci render_fp(context, sdc.get(), fpGenerator.make(i, /*randomTreeDepth=*/1, inputTexture1), 638cb93a386Sopenharmony_ci readData1.data()); 639cb93a386Sopenharmony_ci 640cb93a386Sopenharmony_ci // This test has a history of being flaky on a number of devices. If an FP is logically 641cb93a386Sopenharmony_ci // violating the optimizations, it's reasonable to expect it to violate requirements on 642cb93a386Sopenharmony_ci // a large number of pixels in the image. Sporadic pixel violations are more indicative 643cb93a386Sopenharmony_ci // of device errors and represents a separate problem. 644cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_SKQP) 645cb93a386Sopenharmony_ci static constexpr int kMaxAcceptableFailedPixels = 0; // Strict when running as SKQP 646cb93a386Sopenharmony_ci#else 647cb93a386Sopenharmony_ci static constexpr int kMaxAcceptableFailedPixels = 2 * kRenderSize; // ~0.7% of the image 648cb93a386Sopenharmony_ci#endif 649cb93a386Sopenharmony_ci 650cb93a386Sopenharmony_ci // Collect first optimization failure message, to be output later as a warning or an 651cb93a386Sopenharmony_ci // error depending on whether the rendering "passed" or failed. 652cb93a386Sopenharmony_ci int failedPixelCount = 0; 653cb93a386Sopenharmony_ci SkString coverageMessage; 654cb93a386Sopenharmony_ci SkString opaqueMessage; 655cb93a386Sopenharmony_ci SkString constMessage; 656cb93a386Sopenharmony_ci for (int y = 0; y < kRenderSize; ++y) { 657cb93a386Sopenharmony_ci for (int x = 0; x < kRenderSize; ++x) { 658cb93a386Sopenharmony_ci bool passing = true; 659cb93a386Sopenharmony_ci GrColor input = inputPixels1[y * kRenderSize + x]; 660cb93a386Sopenharmony_ci GrColor output = readData1[y * kRenderSize + x]; 661cb93a386Sopenharmony_ci 662cb93a386Sopenharmony_ci if (fp->compatibleWithCoverageAsAlpha()) { 663cb93a386Sopenharmony_ci GrColor ins[3]; 664cb93a386Sopenharmony_ci ins[0] = input; 665cb93a386Sopenharmony_ci ins[1] = inputPixels2[y * kRenderSize + x]; 666cb93a386Sopenharmony_ci ins[2] = inputPixels3[y * kRenderSize + x]; 667cb93a386Sopenharmony_ci 668cb93a386Sopenharmony_ci GrColor outs[3]; 669cb93a386Sopenharmony_ci outs[0] = output; 670cb93a386Sopenharmony_ci outs[1] = readData2[y * kRenderSize + x]; 671cb93a386Sopenharmony_ci outs[2] = readData3[y * kRenderSize + x]; 672cb93a386Sopenharmony_ci 673cb93a386Sopenharmony_ci if (!legal_modulation(ins, outs)) { 674cb93a386Sopenharmony_ci passing = false; 675cb93a386Sopenharmony_ci if (coverageMessage.isEmpty()) { 676cb93a386Sopenharmony_ci coverageMessage.printf( 677cb93a386Sopenharmony_ci "\"Modulating\" processor did not match alpha-modulation " 678cb93a386Sopenharmony_ci "nor color-modulation rules.\n" 679cb93a386Sopenharmony_ci "Input: 0x%08x, Output: 0x%08x, pixel (%d, %d).", 680cb93a386Sopenharmony_ci input, output, x, y); 681cb93a386Sopenharmony_ci } 682cb93a386Sopenharmony_ci } 683cb93a386Sopenharmony_ci } 684cb93a386Sopenharmony_ci 685cb93a386Sopenharmony_ci SkPMColor4f input4f = SkPMColor4f::FromBytes_RGBA(input); 686cb93a386Sopenharmony_ci SkPMColor4f output4f = SkPMColor4f::FromBytes_RGBA(output); 687cb93a386Sopenharmony_ci SkPMColor4f expected4f; 688cb93a386Sopenharmony_ci if (fp->hasConstantOutputForConstantInput(input4f, &expected4f)) { 689cb93a386Sopenharmony_ci float rDiff = fabsf(output4f.fR - expected4f.fR); 690cb93a386Sopenharmony_ci float gDiff = fabsf(output4f.fG - expected4f.fG); 691cb93a386Sopenharmony_ci float bDiff = fabsf(output4f.fB - expected4f.fB); 692cb93a386Sopenharmony_ci float aDiff = fabsf(output4f.fA - expected4f.fA); 693cb93a386Sopenharmony_ci static constexpr float kTol = 4 / 255.f; 694cb93a386Sopenharmony_ci if (rDiff > kTol || gDiff > kTol || bDiff > kTol || aDiff > kTol) { 695cb93a386Sopenharmony_ci if (constMessage.isEmpty()) { 696cb93a386Sopenharmony_ci passing = false; 697cb93a386Sopenharmony_ci 698cb93a386Sopenharmony_ci constMessage.printf( 699cb93a386Sopenharmony_ci "Processor claimed output for const input doesn't match " 700cb93a386Sopenharmony_ci "actual output.\n" 701cb93a386Sopenharmony_ci "Error: %f, Tolerance: %f, input: (%f, %f, %f, %f), " 702cb93a386Sopenharmony_ci "actual: (%f, %f, %f, %f), expected(%f, %f, %f, %f).", 703cb93a386Sopenharmony_ci std::max(rDiff, std::max(gDiff, std::max(bDiff, aDiff))), 704cb93a386Sopenharmony_ci kTol, input4f.fR, input4f.fG, input4f.fB, input4f.fA, 705cb93a386Sopenharmony_ci output4f.fR, output4f.fG, output4f.fB, output4f.fA, 706cb93a386Sopenharmony_ci expected4f.fR, expected4f.fG, expected4f.fB, expected4f.fA); 707cb93a386Sopenharmony_ci } 708cb93a386Sopenharmony_ci } 709cb93a386Sopenharmony_ci } 710cb93a386Sopenharmony_ci if (input4f.isOpaque() && fp->preservesOpaqueInput() && !output4f.isOpaque()) { 711cb93a386Sopenharmony_ci passing = false; 712cb93a386Sopenharmony_ci 713cb93a386Sopenharmony_ci if (opaqueMessage.isEmpty()) { 714cb93a386Sopenharmony_ci opaqueMessage.printf( 715cb93a386Sopenharmony_ci "Processor claimed opaqueness is preserved but " 716cb93a386Sopenharmony_ci "it is not. Input: 0x%08x, Output: 0x%08x.", 717cb93a386Sopenharmony_ci input, output); 718cb93a386Sopenharmony_ci } 719cb93a386Sopenharmony_ci } 720cb93a386Sopenharmony_ci 721cb93a386Sopenharmony_ci if (!passing) { 722cb93a386Sopenharmony_ci // Regardless of how many optimizations the pixel violates, count it as a 723cb93a386Sopenharmony_ci // single bad pixel. 724cb93a386Sopenharmony_ci failedPixelCount++; 725cb93a386Sopenharmony_ci } 726cb93a386Sopenharmony_ci } 727cb93a386Sopenharmony_ci } 728cb93a386Sopenharmony_ci 729cb93a386Sopenharmony_ci // Finished analyzing the entire image, see if the number of pixel failures meets the 730cb93a386Sopenharmony_ci // threshold for an FP violating the optimization requirements. 731cb93a386Sopenharmony_ci if (failedPixelCount > kMaxAcceptableFailedPixels) { 732cb93a386Sopenharmony_ci ERRORF(reporter, 733cb93a386Sopenharmony_ci "Processor violated %d of %d pixels, seed: 0x%08x.\n" 734cb93a386Sopenharmony_ci "Processor:\n%s\nFirst failing pixel details are below:", 735cb93a386Sopenharmony_ci failedPixelCount, kRenderSize * kRenderSize, fpGenerator.initialSeed(), 736cb93a386Sopenharmony_ci fp->dumpTreeInfo().c_str()); 737cb93a386Sopenharmony_ci 738cb93a386Sopenharmony_ci // Print first failing pixel's details. 739cb93a386Sopenharmony_ci if (!coverageMessage.isEmpty()) { 740cb93a386Sopenharmony_ci ERRORF(reporter, coverageMessage.c_str()); 741cb93a386Sopenharmony_ci } 742cb93a386Sopenharmony_ci if (!constMessage.isEmpty()) { 743cb93a386Sopenharmony_ci ERRORF(reporter, constMessage.c_str()); 744cb93a386Sopenharmony_ci } 745cb93a386Sopenharmony_ci if (!opaqueMessage.isEmpty()) { 746cb93a386Sopenharmony_ci ERRORF(reporter, opaqueMessage.c_str()); 747cb93a386Sopenharmony_ci } 748cb93a386Sopenharmony_ci 749cb93a386Sopenharmony_ci if (!loggedFirstFailure) { 750cb93a386Sopenharmony_ci // Print with ERRORF to make sure the encoded image is output 751cb93a386Sopenharmony_ci SkString input; 752cb93a386Sopenharmony_ci log_texture_view(context, inputTexture1, &input); 753cb93a386Sopenharmony_ci SkString output; 754cb93a386Sopenharmony_ci log_pixels(readData1.data(), kRenderSize, &output); 755cb93a386Sopenharmony_ci ERRORF(reporter, "Input image: %s\n\n" 756cb93a386Sopenharmony_ci "===========================================================\n\n" 757cb93a386Sopenharmony_ci "Output image: %s\n", input.c_str(), output.c_str()); 758cb93a386Sopenharmony_ci loggedFirstFailure = true; 759cb93a386Sopenharmony_ci } 760cb93a386Sopenharmony_ci } else if (failedPixelCount > 0) { 761cb93a386Sopenharmony_ci // Don't trigger an error, but don't just hide the failures either. 762cb93a386Sopenharmony_ci INFOF(reporter, "Processor violated %d of %d pixels (below error threshold), seed: " 763cb93a386Sopenharmony_ci "0x%08x, processor: %s", failedPixelCount, kRenderSize * kRenderSize, 764cb93a386Sopenharmony_ci fpGenerator.initialSeed(), fp->dumpInfo().c_str()); 765cb93a386Sopenharmony_ci if (!coverageMessage.isEmpty()) { 766cb93a386Sopenharmony_ci INFOF(reporter, "%s", coverageMessage.c_str()); 767cb93a386Sopenharmony_ci } 768cb93a386Sopenharmony_ci if (!constMessage.isEmpty()) { 769cb93a386Sopenharmony_ci INFOF(reporter, "%s", constMessage.c_str()); 770cb93a386Sopenharmony_ci } 771cb93a386Sopenharmony_ci if (!opaqueMessage.isEmpty()) { 772cb93a386Sopenharmony_ci INFOF(reporter, "%s", opaqueMessage.c_str()); 773cb93a386Sopenharmony_ci } 774cb93a386Sopenharmony_ci if (!loggedFirstWarning) { 775cb93a386Sopenharmony_ci SkString input; 776cb93a386Sopenharmony_ci log_texture_view(context, inputTexture1, &input); 777cb93a386Sopenharmony_ci SkString output; 778cb93a386Sopenharmony_ci log_pixels(readData1.data(), kRenderSize, &output); 779cb93a386Sopenharmony_ci INFOF(reporter, "Input image: %s\n\n" 780cb93a386Sopenharmony_ci "===========================================================\n\n" 781cb93a386Sopenharmony_ci "Output image: %s\n", input.c_str(), output.c_str()); 782cb93a386Sopenharmony_ci loggedFirstWarning = true; 783cb93a386Sopenharmony_ci } 784cb93a386Sopenharmony_ci } 785cb93a386Sopenharmony_ci } 786cb93a386Sopenharmony_ci } 787cb93a386Sopenharmony_ci} 788cb93a386Sopenharmony_ci 789cb93a386Sopenharmony_cistatic void assert_processor_equality(skiatest::Reporter* reporter, 790cb93a386Sopenharmony_ci const GrFragmentProcessor& fp, 791cb93a386Sopenharmony_ci const GrFragmentProcessor& clone) { 792cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !strcmp(fp.name(), clone.name()), 793cb93a386Sopenharmony_ci "\n%s", fp.dumpTreeInfo().c_str()); 794cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, fp.compatibleWithCoverageAsAlpha() == 795cb93a386Sopenharmony_ci clone.compatibleWithCoverageAsAlpha(), 796cb93a386Sopenharmony_ci "\n%s", fp.dumpTreeInfo().c_str()); 797cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, fp.isEqual(clone), 798cb93a386Sopenharmony_ci "\n%s", fp.dumpTreeInfo().c_str()); 799cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, fp.preservesOpaqueInput() == clone.preservesOpaqueInput(), 800cb93a386Sopenharmony_ci "\n%s", fp.dumpTreeInfo().c_str()); 801cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, fp.hasConstantOutputForConstantInput() == 802cb93a386Sopenharmony_ci clone.hasConstantOutputForConstantInput(), 803cb93a386Sopenharmony_ci "\n%s", fp.dumpTreeInfo().c_str()); 804cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, fp.numChildProcessors() == clone.numChildProcessors(), 805cb93a386Sopenharmony_ci "\n%s", fp.dumpTreeInfo().c_str()); 806cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, fp.sampleUsage() == clone.sampleUsage(), 807cb93a386Sopenharmony_ci "\n%s", fp.dumpTreeInfo().c_str()); 808cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, fp.usesSampleCoords() == clone.usesSampleCoords(), 809cb93a386Sopenharmony_ci "\n%s", fp.dumpTreeInfo().c_str()); 810cb93a386Sopenharmony_ci} 811cb93a386Sopenharmony_ci 812cb93a386Sopenharmony_cistatic bool verify_identical_render(skiatest::Reporter* reporter, int renderSize, 813cb93a386Sopenharmony_ci const char* processorType, 814cb93a386Sopenharmony_ci const GrColor readData1[], const GrColor readData2[]) { 815cb93a386Sopenharmony_ci // The ProcessorClone test has a history of being flaky on a number of devices. If an FP clone 816cb93a386Sopenharmony_ci // is logically wrong, it's reasonable to expect it produce a large number of pixel differences 817cb93a386Sopenharmony_ci // in the image. Sporadic pixel violations are more indicative device errors and represents a 818cb93a386Sopenharmony_ci // separate problem. 819cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_SKQP) 820cb93a386Sopenharmony_ci const int maxAcceptableFailedPixels = 0; // Strict when running as SKQP 821cb93a386Sopenharmony_ci#else 822cb93a386Sopenharmony_ci const int maxAcceptableFailedPixels = 2 * renderSize; // ~0.002% of the pixels (size 1024*1024) 823cb93a386Sopenharmony_ci#endif 824cb93a386Sopenharmony_ci 825cb93a386Sopenharmony_ci int failedPixelCount = 0; 826cb93a386Sopenharmony_ci int firstWrongX = 0; 827cb93a386Sopenharmony_ci int firstWrongY = 0; 828cb93a386Sopenharmony_ci int idx = 0; 829cb93a386Sopenharmony_ci for (int y = 0; y < renderSize; ++y) { 830cb93a386Sopenharmony_ci for (int x = 0; x < renderSize; ++x, ++idx) { 831cb93a386Sopenharmony_ci if (readData1[idx] != readData2[idx]) { 832cb93a386Sopenharmony_ci if (!failedPixelCount) { 833cb93a386Sopenharmony_ci firstWrongX = x; 834cb93a386Sopenharmony_ci firstWrongY = y; 835cb93a386Sopenharmony_ci } 836cb93a386Sopenharmony_ci ++failedPixelCount; 837cb93a386Sopenharmony_ci } 838cb93a386Sopenharmony_ci if (failedPixelCount > maxAcceptableFailedPixels) { 839cb93a386Sopenharmony_ci idx = firstWrongY * renderSize + firstWrongX; 840cb93a386Sopenharmony_ci ERRORF(reporter, 841cb93a386Sopenharmony_ci "%s produced different output at (%d, %d). " 842cb93a386Sopenharmony_ci "Input color: 0x%08x, Original Output Color: 0x%08x, " 843cb93a386Sopenharmony_ci "Clone Output Color: 0x%08x.", 844cb93a386Sopenharmony_ci processorType, firstWrongX, firstWrongY, input_texel_color(x, y, 0.0f), 845cb93a386Sopenharmony_ci readData1[idx], readData2[idx]); 846cb93a386Sopenharmony_ci 847cb93a386Sopenharmony_ci return false; 848cb93a386Sopenharmony_ci } 849cb93a386Sopenharmony_ci } 850cb93a386Sopenharmony_ci } 851cb93a386Sopenharmony_ci 852cb93a386Sopenharmony_ci return true; 853cb93a386Sopenharmony_ci} 854cb93a386Sopenharmony_ci 855cb93a386Sopenharmony_cistatic void log_clone_failure(skiatest::Reporter* reporter, int renderSize, 856cb93a386Sopenharmony_ci GrDirectContext* context, const GrSurfaceProxyView& inputTexture, 857cb93a386Sopenharmony_ci GrColor pixelsFP[], GrColor pixelsClone[], GrColor pixelsRegen[]) { 858cb93a386Sopenharmony_ci // Write the images out as data URLs for inspection. 859cb93a386Sopenharmony_ci SkString inputURL, origURL, cloneURL, regenURL; 860cb93a386Sopenharmony_ci if (log_texture_view(context, inputTexture, &inputURL) && 861cb93a386Sopenharmony_ci log_pixels(pixelsFP, renderSize, &origURL) && 862cb93a386Sopenharmony_ci log_pixels(pixelsClone, renderSize, &cloneURL) && 863cb93a386Sopenharmony_ci log_pixels(pixelsRegen, renderSize, ®enURL)) { 864cb93a386Sopenharmony_ci ERRORF(reporter, 865cb93a386Sopenharmony_ci "\nInput image:\n%s\n\n" 866cb93a386Sopenharmony_ci "===========================================================" 867cb93a386Sopenharmony_ci "\n\n" 868cb93a386Sopenharmony_ci "Orig output image:\n%s\n" 869cb93a386Sopenharmony_ci "===========================================================" 870cb93a386Sopenharmony_ci "\n\n" 871cb93a386Sopenharmony_ci "Clone output image:\n%s\n" 872cb93a386Sopenharmony_ci "===========================================================" 873cb93a386Sopenharmony_ci "\n\n" 874cb93a386Sopenharmony_ci "Regen output image:\n%s\n", 875cb93a386Sopenharmony_ci inputURL.c_str(), origURL.c_str(), cloneURL.c_str(), regenURL.c_str()); 876cb93a386Sopenharmony_ci } 877cb93a386Sopenharmony_ci} 878cb93a386Sopenharmony_ci 879cb93a386Sopenharmony_ci// Tests that a fragment processor returned by GrFragmentProcessor::clone() is equivalent to its 880cb93a386Sopenharmony_ci// progenitor. 881cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorCloneTest, reporter, ctxInfo) { 882cb93a386Sopenharmony_ci GrDirectContext* context = ctxInfo.directContext(); 883cb93a386Sopenharmony_ci GrResourceProvider* resourceProvider = context->priv().resourceProvider(); 884cb93a386Sopenharmony_ci 885cb93a386Sopenharmony_ci TestFPGenerator fpGenerator{context, resourceProvider}; 886cb93a386Sopenharmony_ci if (!fpGenerator.init()) { 887cb93a386Sopenharmony_ci ERRORF(reporter, "Could not initialize TestFPGenerator"); 888cb93a386Sopenharmony_ci return; 889cb93a386Sopenharmony_ci } 890cb93a386Sopenharmony_ci 891cb93a386Sopenharmony_ci // Make the destination context for the test. 892cb93a386Sopenharmony_ci static constexpr int kRenderSize = 1024; 893cb93a386Sopenharmony_ci auto sdc = skgpu::v1::SurfaceDrawContext::Make( 894cb93a386Sopenharmony_ci context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kExact, 895cb93a386Sopenharmony_ci {kRenderSize, kRenderSize}, SkSurfaceProps()); 896cb93a386Sopenharmony_ci 897cb93a386Sopenharmony_ci std::vector<GrColor> inputPixels = make_input_pixels(kRenderSize, kRenderSize, 0.0f); 898cb93a386Sopenharmony_ci GrSurfaceProxyView inputTexture = 899cb93a386Sopenharmony_ci make_input_texture(context, kRenderSize, kRenderSize, inputPixels.data()); 900cb93a386Sopenharmony_ci 901cb93a386Sopenharmony_ci // On failure we write out images, but just write the first failing set as the print is very 902cb93a386Sopenharmony_ci // large. 903cb93a386Sopenharmony_ci bool loggedFirstFailure = false; 904cb93a386Sopenharmony_ci 905cb93a386Sopenharmony_ci // Storage for the original frame's readback and the readback of its clone. 906cb93a386Sopenharmony_ci std::vector<GrColor> readDataFP(kRenderSize * kRenderSize); 907cb93a386Sopenharmony_ci std::vector<GrColor> readDataClone(kRenderSize * kRenderSize); 908cb93a386Sopenharmony_ci std::vector<GrColor> readDataRegen(kRenderSize * kRenderSize); 909cb93a386Sopenharmony_ci 910cb93a386Sopenharmony_ci // Because processor factories configure themselves in random ways, this is not exhaustive. 911cb93a386Sopenharmony_ci for (int i = 0; i < GrFragmentProcessorTestFactory::Count(); ++i) { 912cb93a386Sopenharmony_ci static constexpr int kTimesToInvokeFactory = 10; 913cb93a386Sopenharmony_ci for (int j = 0; j < kTimesToInvokeFactory; ++j) { 914cb93a386Sopenharmony_ci fpGenerator.reroll(); 915cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> fp = 916cb93a386Sopenharmony_ci fpGenerator.make(i, /*randomTreeDepth=*/1, /*inputFP=*/nullptr); 917cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> regen = 918cb93a386Sopenharmony_ci fpGenerator.make(i, /*randomTreeDepth=*/1, /*inputFP=*/nullptr); 919cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> clone = fp->clone(); 920cb93a386Sopenharmony_ci if (!clone) { 921cb93a386Sopenharmony_ci ERRORF(reporter, "Clone of processor %s failed.", fp->dumpTreeInfo().c_str()); 922cb93a386Sopenharmony_ci continue; 923cb93a386Sopenharmony_ci } 924cb93a386Sopenharmony_ci assert_processor_equality(reporter, *fp, *clone); 925cb93a386Sopenharmony_ci 926cb93a386Sopenharmony_ci // Draw with original and read back the results. 927cb93a386Sopenharmony_ci render_fp(context, sdc.get(), std::move(fp), readDataFP.data()); 928cb93a386Sopenharmony_ci 929cb93a386Sopenharmony_ci // Draw with clone and read back the results. 930cb93a386Sopenharmony_ci render_fp(context, sdc.get(), std::move(clone), readDataClone.data()); 931cb93a386Sopenharmony_ci 932cb93a386Sopenharmony_ci // Check that the results are the same. 933cb93a386Sopenharmony_ci if (!verify_identical_render(reporter, kRenderSize, "Processor clone", 934cb93a386Sopenharmony_ci readDataFP.data(), readDataClone.data())) { 935cb93a386Sopenharmony_ci // Dump a description from the regenerated processor (since the original FP has 936cb93a386Sopenharmony_ci // already been consumed). 937cb93a386Sopenharmony_ci ERRORF(reporter, "FP hierarchy:\n%s", regen->dumpTreeInfo().c_str()); 938cb93a386Sopenharmony_ci 939cb93a386Sopenharmony_ci // Render and readback output from the regenerated FP. If this also mismatches, the 940cb93a386Sopenharmony_ci // FP itself doesn't generate consistent output. This could happen if: 941cb93a386Sopenharmony_ci // - the FP's TestCreate() does not always generate the same FP from a given seed 942cb93a386Sopenharmony_ci // - the FP's Make() does not always generate the same FP when given the same inputs 943cb93a386Sopenharmony_ci // - the FP itself generates inconsistent pixels (shader UB?) 944cb93a386Sopenharmony_ci // - the driver has a bug 945cb93a386Sopenharmony_ci render_fp(context, sdc.get(), std::move(regen), readDataRegen.data()); 946cb93a386Sopenharmony_ci 947cb93a386Sopenharmony_ci if (!verify_identical_render(reporter, kRenderSize, "Regenerated processor", 948cb93a386Sopenharmony_ci readDataFP.data(), readDataRegen.data())) { 949cb93a386Sopenharmony_ci ERRORF(reporter, "Output from regen did not match original!\n"); 950cb93a386Sopenharmony_ci } else { 951cb93a386Sopenharmony_ci ERRORF(reporter, "Regenerated processor output matches original results.\n"); 952cb93a386Sopenharmony_ci } 953cb93a386Sopenharmony_ci 954cb93a386Sopenharmony_ci // If this is the first time we've encountered a cloning failure, log the generated 955cb93a386Sopenharmony_ci // images to the reporter as data URLs. 956cb93a386Sopenharmony_ci if (!loggedFirstFailure) { 957cb93a386Sopenharmony_ci log_clone_failure(reporter, kRenderSize, context, inputTexture, 958cb93a386Sopenharmony_ci readDataFP.data(), readDataClone.data(), 959cb93a386Sopenharmony_ci readDataRegen.data()); 960cb93a386Sopenharmony_ci loggedFirstFailure = true; 961cb93a386Sopenharmony_ci } 962cb93a386Sopenharmony_ci } 963cb93a386Sopenharmony_ci } 964cb93a386Sopenharmony_ci } 965cb93a386Sopenharmony_ci} 966cb93a386Sopenharmony_ci 967cb93a386Sopenharmony_ci#endif // GR_TEST_UTILS 968