| /* |
| * Copyright 2021 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "tests/Test.h" |
| |
| #if defined(SK_GRAPHITE) |
| |
| #include "include/core/SkCanvas.h" |
| #include "include/core/SkShader.h" |
| #include "include/effects/SkRuntimeEffect.h" |
| #include "include/gpu/graphite/Surface.h" |
| #include "include/gpu/graphite/precompile/Precompile.h" |
| #include "include/gpu/graphite/precompile/PrecompileShader.h" |
| #include "src/base/SkRandom.h" |
| #include "src/gpu/graphite/ContextPriv.h" |
| #include "src/gpu/graphite/ContextUtils.h" |
| #include "src/gpu/graphite/DrawContext.h" |
| #include "src/gpu/graphite/GraphicsPipelineDesc.h" |
| #include "src/gpu/graphite/KeyContext.h" |
| #include "src/gpu/graphite/KeyHelpers.h" |
| #include "src/gpu/graphite/PaintParams.h" |
| #include "src/gpu/graphite/PipelineData.h" |
| #include "src/gpu/graphite/PrecompileContextPriv.h" |
| #include "src/gpu/graphite/RecorderPriv.h" |
| #include "src/gpu/graphite/RenderPassDesc.h" |
| #include "src/gpu/graphite/Renderer.h" |
| #include "src/gpu/graphite/ResourceProvider.h" |
| #include "src/gpu/graphite/RuntimeEffectDictionary.h" |
| #include "src/gpu/graphite/ShaderCodeDictionary.h" |
| #include "src/gpu/graphite/TextureInfoPriv.h" |
| #include "src/gpu/graphite/UniquePaintParamsID.h" |
| #include "src/gpu/graphite/precompile/PaintOptionsPriv.h" |
| #include "tools/graphite/GraphiteTestContext.h" |
| #include "tools/graphite/UniqueKeyUtils.h" |
| |
| #include "tests/graphite/precompile/PaintParamsTestUtils.h" |
| |
| // Set this to 1 for more expansive (aka far slower) local testing |
| #define EXPANDED_SET 0 |
| |
| constexpr uint32_t kDefaultSeed = 0; |
| |
| using namespace skgpu::graphite; |
| using namespace skiatest::graphite; |
| |
| namespace { |
| |
| //-------------------------------------------------------------------------------------------------- |
| // Helpers |
| //-------------------------------------------------------------------------------------------------- |
| |
| sk_sp<DrawContext> get_precompile_draw_context(const skgpu::graphite::Caps* caps, |
| Context* context) { |
| std::unique_ptr<Recorder> drawRecorder = context->makeRecorder(); |
| ResourceProvider* resourceProvider = drawRecorder->priv().resourceProvider(); |
| constexpr SkISize drawSize = {128, 128}; |
| const SkColorInfo colorInfo = SkColorInfo(kRGBA_8888_SkColorType, |
| kPremul_SkAlphaType, |
| SkColorSpace::MakeSRGB()); |
| TextureInfo texInfo = caps->getDefaultSampledTextureInfo(colorInfo.colorType(), |
| skgpu::Mipmapped::kNo, |
| skgpu::Protected::kNo, |
| skgpu::Renderable::kYes); |
| sk_sp<TextureProxy> target = TextureProxy::Make(caps, |
| resourceProvider, |
| drawSize, |
| texInfo, |
| "PrecompileTarget", |
| skgpu::Budgeted::kYes); |
| return DrawContext::Make(caps, |
| std::move(target), |
| drawSize, |
| colorInfo, |
| {}); |
| } |
| |
| void log_run(const char* label, |
| uint32_t seed, |
| ShaderType s, |
| BlenderType bm, |
| ColorFilterType cf, |
| MaskFilterType mf, |
| ImageFilterType imageFilter, |
| ClipType clipType, |
| DrawTypeFlags drawTypeFlags) { |
| SkDebugf("%s:\n" |
| "//------------------------\n" |
| "uint32_t seed = %u;\n" |
| "ShaderType shaderType = %s;\n" |
| "BlenderType blenderType = %s;\n" |
| "ColorFilterType colorFilterType = %s;\n" |
| "MaskFilterType maskFilterType = %s;\n" |
| "ImageFilterType imageFilterType = %s;\n" |
| "ClipType clipType = %s;\n" |
| "DrawTypeFlags drawTypeFlags = %s;\n" |
| "//-----------------------\n", |
| label, |
| seed, |
| ToStr(s), |
| ToStr(bm), |
| ToStr(cf), |
| ToStr(mf), |
| ToStr(imageFilter), |
| ToStr(clipType), |
| ToStr(drawTypeFlags)); |
| } |
| |
| #ifdef SK_DEBUG |
| void dump_keys(PrecompileContext* precompileContext, |
| const std::vector<skgpu::UniqueKey>& needleKeys, |
| const std::vector<skgpu::UniqueKey>& hayStackKeys, |
| const char* needleName, |
| const char* haystackName) { |
| |
| SkDebugf("-------------------------- %zu %s pipelines\n", needleKeys.size(), needleName); |
| |
| int count = 0; |
| for (const skgpu::UniqueKey& k : needleKeys) { |
| bool found = std::find(hayStackKeys.begin(), hayStackKeys.end(), k) != hayStackKeys.end(); |
| |
| GraphicsPipelineDesc originalPipelineDesc; |
| RenderPassDesc originalRenderPassDesc; |
| UniqueKeyUtils::ExtractKeyDescs(precompileContext, k, |
| &originalPipelineDesc, |
| &originalRenderPassDesc); |
| |
| SkString label; |
| label.appendf("--- %s key %d (%s in %s):\n", |
| needleName, count++, found ? "found" : "not-found", haystackName); |
| k.dump(label.c_str()); |
| UniqueKeyUtils::DumpDescs(precompileContext, |
| originalPipelineDesc, |
| originalRenderPassDesc); |
| } |
| } |
| #endif |
| |
| void check_draw(skiatest::Reporter* reporter, |
| Context* context, |
| PrecompileContext* precompileContext, |
| skiatest::graphite::GraphiteTestContext* testContext, |
| Recorder* recorder, |
| const SkPaint& paint, |
| DrawTypeFlags dt, |
| ClipType clipType, |
| sk_sp<SkShader> clipShader) { |
| static const DrawData kDrawData; |
| |
| std::vector<skgpu::UniqueKey> precompileKeys, drawKeys; |
| |
| UniqueKeyUtils::FetchUniqueKeys(precompileContext, &precompileKeys); |
| |
| precompileContext->priv().globalCache()->resetGraphicsPipelines(); |
| |
| { |
| // TODO: vary the colorType of the target surface too |
| SkImageInfo ii = SkImageInfo::Make(16, 16, |
| kBGRA_8888_SkColorType, |
| kPremul_SkAlphaType); |
| |
| SkSurfaceProps props; |
| |
| if (dt == DrawTypeFlags::kBitmapText_LCD || dt == DrawTypeFlags::kSDFText_LCD) { |
| props = SkSurfaceProps(/* flags= */ 0x0, SkPixelGeometry::kRGB_H_SkPixelGeometry); |
| } |
| |
| sk_sp<SkSurface> surf = SkSurfaces::RenderTarget(recorder, ii, |
| skgpu::Mipmapped::kNo, |
| &props); |
| SkCanvas* canvas = surf->getCanvas(); |
| |
| // NOTE: The specific coordinates for the clip[R]Rect and draw[R]Rect calls are chosen to |
| // avoid geometrically combining the clip into the geometry, and to avoid covering the |
| // render target entirely, both of which would simplify the pipeline required. |
| |
| switch (clipType) { |
| case ClipType::kNone: |
| break; |
| case ClipType::kShader: |
| SkASSERT(clipShader); |
| canvas->clipShader(clipShader, SkClipOp::kIntersect); |
| break; |
| case ClipType::kShader_Diff: |
| SkASSERT(clipShader); |
| canvas->clipShader(clipShader, SkClipOp::kDifference); |
| break; |
| case ClipType::kAnalytic: |
| canvas->clipRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(1, 1, 15, 15), 5, 5)); |
| break; |
| case ClipType::kAnalyticAndShader: |
| SkASSERT(clipShader); |
| canvas->clipRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(1, 1, 15, 15), 5, 5)); |
| canvas->clipShader(clipShader, SkClipOp::kIntersect); |
| break; |
| } |
| |
| ExecuteDraw(canvas, paint, kDrawData, dt); |
| std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap(); |
| context->insertRecording({ recording.get() }); |
| testContext->syncedSubmit(context); |
| } |
| |
| UniqueKeyUtils::FetchUniqueKeys(precompileContext, &drawKeys); |
| |
| // Actually using the SkPaint with the specified type of draw shouldn't have added |
| // any additional pipelines |
| int missingPipelines = 0; |
| for (const skgpu::UniqueKey& k : drawKeys) { |
| bool found = |
| std::find(precompileKeys.begin(), precompileKeys.end(), k) != precompileKeys.end(); |
| if (!found) { |
| ++missingPipelines; |
| } |
| } |
| |
| REPORTER_ASSERT(reporter, missingPipelines == 0, |
| "precompile pipelines: %zu draw pipelines: %zu - %d missing from precompile", |
| precompileKeys.size(), drawKeys.size(), missingPipelines); |
| #ifdef SK_DEBUG |
| if (missingPipelines) { |
| dump_keys(precompileContext, drawKeys, precompileKeys, "draw", "precompile"); |
| dump_keys(precompileContext, precompileKeys, drawKeys, "precompile", "draw"); |
| } |
| #endif // SK_DEBUG |
| |
| } |
| |
| // This subtest compares the output of paintParams.toKey() (applied to an SkPaint) and |
| // PaintOptions::buildCombinations (applied to a matching PaintOptions). The actual check |
| // performed is that the UniquePaintParamsID created by paintParams.toKey() is contained in the |
| // set of IDs generated by buildCombinations. |
| [[maybe_unused]] |
| void extract_vs_build_subtest(skiatest::Reporter* reporter, |
| Context* context, |
| DrawContext* drawContext, |
| skiatest::graphite::GraphiteTestContext* /* testContext */, |
| const KeyContext& precompileKeyContext, |
| Recorder* recorder, |
| const SkPaint& paint, |
| const PaintOptions& paintOptions, |
| ShaderType s, |
| BlenderType bm, |
| ColorFilterType cf, |
| MaskFilterType mf, |
| ImageFilterType imageFilter, |
| ClipType clipType, |
| sk_sp<SkShader> clipShader, |
| DrawTypeFlags dt, |
| uint32_t seed, |
| SkRandom* rand, |
| bool verbose) { |
| PipelineDataGatherer paramsGatherer(Layout::kMetal); |
| |
| for (bool withPrimitiveBlender: {false, true}) { |
| |
| sk_sp<SkBlender> primitiveBlender; |
| if (withPrimitiveBlender) { |
| if (dt != DrawTypeFlags::kDrawVertices) { |
| // Only drawVertices calls need a primitive blender |
| continue; |
| } |
| |
| primitiveBlender = SkBlender::Mode(SkBlendMode::kSrcOver); |
| } |
| |
| constexpr Coverage coverageOptions[3] = { |
| Coverage::kNone, Coverage::kSingleChannel, Coverage::kLCD |
| }; |
| Coverage coverage = coverageOptions[rand->nextULessThan(3)]; |
| |
| // In the normal API this modification happens in SkDevice::clipShader() |
| // All clipShaders get wrapped in a CTMShader |
| sk_sp<SkShader> modifiedClipShader = clipShader |
| ? as_SB(clipShader)->makeWithCTM(SkMatrix::I()) |
| : nullptr; |
| if (clipType == ClipType::kShader_Diff && modifiedClipShader) { |
| // The CTMShader gets further wrapped in a ColorFilterShader for kDifference clips |
| modifiedClipShader = modifiedClipShader->makeWithColorFilter( |
| SkColorFilters::Blend(0xFFFFFFFF, SkBlendMode::kSrcOut)); |
| } |
| |
| bool hasAnalyticClip = clipType == ClipType::kAnalytic || |
| clipType == ClipType::kAnalyticAndShader; |
| NonMSAAClip clipData; |
| if (hasAnalyticClip) { |
| clipData.fAnalyticClip.fBounds = SkRect::MakeWH(15, 15); |
| clipData.fAnalyticClip.fRadius = 5; |
| } |
| |
| PaintParams paintParams{paint, primitiveBlender.get()}; |
| ShadingParams shadingParams{recorder->priv().caps(), |
| paintParams, |
| clipData, |
| modifiedClipShader.get(), |
| coverage, |
| TextureFormat::kRGBA8}; |
| paramsGatherer.resetForDraw(); |
| KeyContext keyContext(recorder, |
| drawContext, |
| precompileKeyContext.floatStorageManager(), |
| precompileKeyContext.paintParamsKeyBuilder(), |
| ¶msGatherer, |
| {}, |
| precompileKeyContext.dstColorInfo(), |
| KeyGenFlags::kDisableSamplingOptimization, |
| paintParams.color()); |
| auto keyResult = shadingParams.toKey(keyContext); |
| UniquePaintParamsID paintID = keyResult.has_value() ? std::get<0>(*keyResult) |
| : UniquePaintParamsID::Invalid(); |
| |
| RenderPassDesc unusedRenderPassDesc; |
| std::vector<UniquePaintParamsID> precompileIDs; |
| paintOptions.priv().buildCombinations(precompileKeyContext, |
| hasAnalyticClip ? DrawTypeFlags::kAnalyticClip |
| : DrawTypeFlags::kNone, |
| withPrimitiveBlender, |
| coverage, |
| unusedRenderPassDesc, |
| [&precompileIDs](UniquePaintParamsID id, |
| DrawTypeFlags, |
| bool /* withPrimitiveBlender */, |
| Coverage, |
| const RenderPassDesc&) { |
| precompileIDs.push_back(id); |
| }); |
| |
| if (verbose) { |
| SkDebugf("Precompilation generated %zu unique keys\n", precompileIDs.size()); |
| } |
| |
| // Although we've gathered both sets of uniforms (i.e., from the paint |
| // params and the precompilation paths) we can't compare the two since the |
| // precompilation path may have generated multiple sets |
| // and the last one created may not be the one that matches the paint |
| // params' set. Additionally, for runtime effects we just skip gathering |
| // the uniforms in the precompilation path. |
| |
| // The specific key generated by paintParams.toKey() should be one of the |
| // combinations generated by the combination system. |
| auto result = std::find(precompileIDs.begin(), precompileIDs.end(), paintID); |
| |
| if (result == precompileIDs.end()) { |
| log_run("Failure on case", seed, s, bm, cf, mf, imageFilter, clipType, dt); |
| } |
| |
| #ifdef SK_DEBUG |
| if (result == precompileIDs.end()) { |
| SkDebugf("From paint: "); |
| precompileKeyContext.dict()->dump(precompileKeyContext.caps(), paintID); |
| |
| SkDebugf("From combination builder [%d]:", static_cast<int>(precompileIDs.size())); |
| for (auto iter: precompileIDs) { |
| precompileKeyContext.dict()->dump(precompileKeyContext.caps(), iter); |
| } |
| } |
| #endif |
| |
| REPORTER_ASSERT(reporter, result != precompileIDs.end()); |
| } |
| } |
| |
| // This subtest verifies that, given an equivalent SkPaint and PaintOptions, the |
| // Precompile system will, at least, generate all the pipelines a real draw would generate. |
| void precompile_vs_real_draws_subtest(skiatest::Reporter* reporter, |
| Context* context, |
| PrecompileContext* precompileContext, |
| skiatest::graphite::GraphiteTestContext* testContext, |
| Recorder* recorder, |
| const SkPaint& paint, |
| const PaintOptions& paintOptions, |
| ClipType clipType, |
| sk_sp<SkShader> clipShader, |
| DrawTypeFlags dt, |
| bool useSKPShader, |
| bool /* verbose */) { |
| GlobalCache* globalCache = precompileContext->priv().globalCache(); |
| |
| globalCache->resetGraphicsPipelines(); |
| |
| const skgpu::graphite::Caps* caps = context->priv().caps(); |
| |
| const SkColorType kColorType = kBGRA_8888_SkColorType; |
| |
| static const RenderPassProperties kDepth_Stencil_4 { DepthStencilFlags::kDepthStencil, |
| kColorType, |
| /* dstColorSpace= */ nullptr, |
| /* requiresMSAA= */ true }; |
| static const RenderPassProperties kDepth_1 { DepthStencilFlags::kDepth, |
| kColorType, |
| /* dstColorSpace= */ nullptr, |
| /* requiresMSAA= */ false }; |
| |
| TextureInfo textureInfo = caps->getDefaultSampledTextureInfo(kColorType, |
| skgpu::Mipmapped::kNo, |
| skgpu::Protected::kNo, |
| skgpu::Renderable::kYes); |
| |
| const bool msaaSupported = caps->getCompatibleMSAASampleCount(textureInfo) > SampleCount::k1; |
| |
| bool vello = false; |
| #ifdef SK_ENABLE_VELLO_SHADERS |
| vello = caps->computeSupport(); |
| #endif |
| |
| // Using Vello skips using MSAA for complex paths. Additionally, Intel Macs avoid MSAA |
| // in favor of path rendering. |
| const RenderPassProperties* pathProperties = (msaaSupported && !vello) ? &kDepth_Stencil_4 |
| : &kDepth_1; |
| |
| DrawTypeFlags combinedDrawType = dt; |
| if (clipType == ClipType::kAnalytic || clipType == ClipType::kAnalyticAndShader) { |
| combinedDrawType = static_cast<DrawTypeFlags>( |
| static_cast<int>(dt) | static_cast<int>(DrawTypeFlags::kAnalyticClip)); |
| } |
| |
| int before = globalCache->numGraphicsPipelines(); |
| Precompile(precompileContext, |
| paintOptions, |
| combinedDrawType, |
| dt == DrawTypeFlags::kNonSimpleShape ? SkSpan(pathProperties, 1) |
| : SkSpan(&kDepth_1, 1)); |
| if (useSKPShader) { |
| // The skp draws a rect w/ a default SkPaint and RGBA dst color type |
| PaintOptions skpPaintOptions; |
| Precompile(precompileContext, skpPaintOptions, DrawTypeFlags::kNonAAFillRect, |
| {{ { kDepth_1.fDSFlags, kRGBA_8888_SkColorType, kDepth_1.fDstCS, |
| kDepth_1.fRequiresMSAA } }}); |
| } |
| int after = globalCache->numGraphicsPipelines(); |
| |
| REPORTER_ASSERT(reporter, before == 0); |
| REPORTER_ASSERT(reporter, after > before); |
| |
| check_draw(reporter, |
| context, |
| precompileContext, |
| testContext, |
| recorder, |
| paint, |
| dt, |
| clipType, |
| clipShader); |
| } |
| |
| void run_test(skiatest::Reporter* reporter, |
| Context* context, |
| DrawContext* drawContext, |
| PrecompileContext* precompileContext, |
| skiatest::graphite::GraphiteTestContext* testContext, |
| const KeyContext& precompileKeyContext, |
| ShaderType s, |
| BlenderType bm, |
| ColorFilterType cf, |
| MaskFilterType mf, |
| ImageFilterType imageFilter, |
| ClipType clipType, |
| DrawTypeFlags dt, |
| uint32_t seed, |
| bool verbose) { |
| SkRandom rand(seed); |
| |
| std::unique_ptr<Recorder> recorder = context->makeRecorder(); |
| |
| sk_sp<SkShader> clipShader; |
| sk_sp<PrecompileShader> clipShaderOption; |
| |
| if (clipType == ClipType::kShader || |
| clipType == ClipType::kShader_Diff || |
| clipType == ClipType::kAnalyticAndShader) { |
| std::tie(clipShader, clipShaderOption) = CreateClipShader(&rand, recorder.get()); |
| SkASSERT(!clipShader == !clipShaderOption); |
| } |
| |
| bool reqSKP = false; |
| auto [paint, paintOptions] = |
| CreateRandomPaint(&rand, recorder.get(), s, bm, cf, mf, imageFilter, &reqSKP); |
| |
| // The PaintOptions' clipShader can be handled here while the SkPaint's clipShader handling |
| // must be performed later (in paintParams.toKey() or when an SkCanvas is accessible for |
| // a SkCanvas::clipShader call). |
| paintOptions.priv().setClipShaders({{clipShaderOption}}); |
| |
| extract_vs_build_subtest(reporter, context, drawContext, testContext, precompileKeyContext, |
| recorder.get(), paint, paintOptions, s, bm, cf, mf, imageFilter, |
| clipType, clipShader, dt, seed, &rand, verbose); |
| precompile_vs_real_draws_subtest(reporter, context, precompileContext, testContext, |
| recorder.get(), paint, paintOptions, clipType, clipShader, dt, |
| reqSKP, verbose); |
| } |
| |
| } // anonymous namespace |
| |
| DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(PaintParamsKeyTestReduced, |
| reporter, |
| context, |
| testContext, |
| true, |
| CtsEnforcement::kNever) { |
| const skgpu::graphite::Caps* caps = context->priv().caps(); |
| std::unique_ptr<PrecompileContext> precompileContext = context->makePrecompileContext(); |
| // Currently, we just use this as a valid parameter for keyContext (will hit asserts otherwise) |
| sk_sp<DrawContext> precompileDrawContext = get_precompile_draw_context(caps, context); |
| |
| FloatStorageManager floatStorageManager; |
| ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary(); |
| PaintParamsKeyBuilder builder(dict); |
| PipelineDataGatherer gatherer(Layout::kMetal); |
| sk_sp<RuntimeEffectDictionary> rtDict = sk_make_sp<RuntimeEffectDictionary>(); |
| KeyContext keyContext(caps, |
| &floatStorageManager, |
| &builder, |
| &gatherer, |
| dict, |
| rtDict, |
| SkColorInfo(kRGBA_8888_SkColorType, |
| kPremul_SkAlphaType, |
| SkColorSpace::MakeSRGB())); |
| |
| #if 1 |
| //---------------------- |
| uint32_t seed = std::time(nullptr) % std::numeric_limits<uint32_t>::max(); |
| SkRandom rand(seed); |
| ShaderType shaderType = |
| static_cast<ShaderType>(rand.nextULessThan(static_cast<int>(ShaderType::kLast) + 1)); |
| BlenderType blenderType = |
| static_cast<BlenderType>(rand.nextULessThan(static_cast<int>(BlenderType::kLast) + 1)); |
| ColorFilterType colorFilterType = static_cast<ColorFilterType>( |
| rand.nextULessThan(static_cast<int>(ColorFilterType::kLast) + 1)); |
| MaskFilterType maskFilterType = MaskFilterType::kNone; |
| if (rand.nextBool()) { |
| maskFilterType = static_cast<MaskFilterType>( |
| rand.nextULessThan(static_cast<int>(MaskFilterType::kLast) + 1)); |
| } |
| ImageFilterType imageFilterType = ImageFilterType::kNone; // random_imagefiltertype(&rand); |
| ClipType clipType = ClipType::kNone; |
| if (rand.nextBool()) { |
| clipType = static_cast<ClipType>(rand.nextULessThan(static_cast<int>(ClipType::kLast) + 1)); |
| } |
| DrawTypeFlags drawTypeFlags = RandomDrawType(&rand); |
| //---------------------- |
| #else |
| //------------------------ |
| uint32_t seed = 0; |
| ShaderType shaderType = ShaderType::kYUVImage; |
| BlenderType blenderType = BlenderType::kPorterDuff; |
| ColorFilterType colorFilterType = ColorFilterType::kNone; |
| MaskFilterType maskFilterType = MaskFilterType::kNone; |
| ImageFilterType imageFilterType = ImageFilterType::kNone; |
| ClipType clipType = ClipType::kNone; |
| DrawTypeFlags drawTypeFlags = DrawTypeFlags::kBitmapText_Mask; |
| //----------------------- |
| #endif |
| |
| SkString logMsg("Running "); |
| logMsg += BackendApiToStr(context->backend()); |
| |
| log_run(logMsg.c_str(), seed, shaderType, blenderType, colorFilterType, maskFilterType, |
| imageFilterType, clipType, drawTypeFlags); |
| |
| run_test(reporter, |
| context, |
| precompileDrawContext.get(), |
| precompileContext.get(), |
| testContext, |
| keyContext, |
| shaderType, |
| blenderType, |
| colorFilterType, |
| maskFilterType, |
| imageFilterType, |
| clipType, |
| drawTypeFlags, |
| seed, |
| /* verbose= */ true); |
| } |
| |
| // This is intended to be a smoke test for the agreement between the two ways of creating a |
| // PaintParamsKey: |
| // via paintParams.toKey() (i.e., from an SkPaint) |
| // and via the pre-compilation system |
| // |
| // TODO: keep this as a smoke test but add a fuzzer that reuses all the helpers |
| // TODO(b/306174708): enable in SkQP (if it's feasible) |
| DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(PaintParamsKeyTest, |
| reporter, |
| context, |
| testContext, |
| true, |
| CtsEnforcement::kNever) { |
| const skgpu::graphite::Caps* caps = context->priv().caps(); |
| std::unique_ptr<PrecompileContext> precompileContext = context->makePrecompileContext(); |
| // Currently, we just use this as a valid parameter for keyContext (will hit asserts otherwise) |
| sk_sp<DrawContext> precompileDrawContext = get_precompile_draw_context(caps, context); |
| |
| FloatStorageManager floatStorageManager; |
| ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary(); |
| PaintParamsKeyBuilder builder(dict); |
| PipelineDataGatherer gatherer(Layout::kMetal); |
| sk_sp<RuntimeEffectDictionary> rtDict = sk_make_sp<RuntimeEffectDictionary>(); |
| KeyContext precompileKeyContext(caps, |
| &floatStorageManager, |
| &builder, |
| &gatherer, |
| dict, |
| rtDict, |
| SkColorInfo(kRGBA_8888_SkColorType, |
| kPremul_SkAlphaType, |
| SkColorSpace::MakeSRGB())); |
| |
| ShaderType shaders[] = { |
| ShaderType::kImage, |
| ShaderType::kRadialGradient, |
| ShaderType::kSolidColor, |
| ShaderType::kYUVImage, |
| #if EXPANDED_SET |
| ShaderType::kNone, |
| ShaderType::kBlend, |
| ShaderType::kColorFilter, |
| ShaderType::kCoordClamp, |
| ShaderType::kConicalGradient, |
| ShaderType::kLinearGradient, |
| ShaderType::kLocalMatrix, |
| ShaderType::kPerlinNoise, |
| ShaderType::kPicture, |
| ShaderType::kRuntime, |
| ShaderType::kSweepGradient, |
| ShaderType::kWorkingColorSpace, |
| #endif |
| }; |
| |
| BlenderType blenders[] = { |
| BlenderType::kPorterDuff, |
| BlenderType::kShaderBased, |
| BlenderType::kRuntime, |
| #if EXPANDED_SET |
| BlenderType::kNone, |
| BlenderType::kArithmetic, |
| #endif |
| }; |
| |
| ColorFilterType colorFilters[] = { |
| ColorFilterType::kBlendMode, |
| ColorFilterType::kMatrix, |
| #if EXPANDED_SET |
| ColorFilterType::kNone, |
| ColorFilterType::kColorSpaceXform, |
| ColorFilterType::kCompose, |
| ColorFilterType::kGaussian, |
| ColorFilterType::kHighContrast, |
| ColorFilterType::kHSLAMatrix, |
| ColorFilterType::kLerp, |
| ColorFilterType::kLighting, |
| ColorFilterType::kLinearToSRGB, |
| ColorFilterType::kLuma, |
| ColorFilterType::kOverdraw, |
| ColorFilterType::kRuntime, |
| ColorFilterType::kSRGBToLinear, |
| ColorFilterType::kTable, |
| ColorFilterType::kWorkingFormat, |
| #endif |
| }; |
| |
| MaskFilterType maskFilters[] = { |
| MaskFilterType::kNone, |
| #if EXPANDED_SET |
| MaskFilterType::kBlur, |
| #endif |
| }; |
| |
| ImageFilterType imageFilters[] = { |
| ImageFilterType::kNone, |
| #if EXPANDED_SET |
| ImageFilterType::kArithmetic, |
| ImageFilterType::kBlendMode, |
| ImageFilterType::kRuntimeBlender, |
| ImageFilterType::kBlur, |
| ImageFilterType::kColorFilter, |
| ImageFilterType::kDisplacement, |
| ImageFilterType::kLighting, |
| ImageFilterType::kMatrixConvolution, |
| ImageFilterType::kMorphology, |
| #endif |
| }; |
| |
| ClipType clips[] = { |
| ClipType::kNone, |
| ClipType::kAnalytic, |
| #if EXPANDED_SET |
| ClipType::kShader, // w/ a SkClipOp::kIntersect |
| ClipType::kShader_Diff, // w/ a SkClipOp::kDifference |
| ClipType::kAnalyticAndShader, // w/ a SkClipOp::kIntersect |
| #endif |
| }; |
| |
| static const DrawTypeFlags kDrawTypeFlags[] = { |
| DrawTypeFlags::kBitmapText_Mask, |
| DrawTypeFlags::kBitmapText_LCD, |
| DrawTypeFlags::kBitmapText_Color, |
| DrawTypeFlags::kSDFText, |
| DrawTypeFlags::kSDFText_LCD, |
| DrawTypeFlags::kDrawVertices, |
| DrawTypeFlags::kCircularArc, |
| DrawTypeFlags::kAnalyticRRect, |
| DrawTypeFlags::kPerEdgeAAQuad, |
| DrawTypeFlags::kNonAAFillRect, |
| DrawTypeFlags::kNonSimpleShape, |
| }; |
| |
| #if EXPANDED_SET |
| size_t kExpected = std::size(shaders) * std::size(blenders) * std::size(colorFilters) * |
| std::size(maskFilters) * std::size(imageFilters) * std::size(clips) * |
| std::size(kDrawTypeFlags); |
| int current = 0; |
| #endif |
| |
| for (auto shader : shaders) { |
| for (auto blender : blenders) { |
| for (auto cf : colorFilters) { |
| for (auto mf : maskFilters) { |
| for (auto imageFilter : imageFilters) { |
| for (auto clip : clips) { |
| for (DrawTypeFlags dt : kDrawTypeFlags) { |
| #if EXPANDED_SET |
| SkDebugf("%d/%zu\n", current, kExpected); |
| ++current; |
| #endif |
| |
| run_test(reporter, context, precompileDrawContext.get(), |
| precompileContext.get(), |
| testContext, precompileKeyContext, |
| shader, blender, cf, mf, imageFilter, clip, dt, |
| kDefaultSeed, /* verbose= */ false); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| #if EXPANDED_SET |
| SkASSERT(current == (int) kExpected); |
| #endif |
| } |
| |
| #endif // SK_GRAPHITE |