| /* | |
| * 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/core/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, | |
| skgpu::Budgeted::kYes, | |
| "PrecompileTarget"); | |
| return DrawContext::Make(caps, | |
| std::move(target), | |
| drawSize, | |
| colorInfo, | |
| {}, | |
| /*allowUnpremul=*/false); | |
| } | |
| 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); | |
| #if defined(SK_GRAPHITE_USE_LEGACY_RRECT_CLIP_SHADER) | |
| clipData.fAnalyticClip.fRadius = 5; | |
| #else | |
| clipData.fAnalyticClip.fRadii = SkV4{5.f, 5.f, 5.f, 5.f}; | |
| #endif | |
| } | |
| PaintParams paintParams{paint, primitiveBlender.get()}; | |
| ShadingParams shadingParams{recorder->priv().caps(), | |
| paintParams, | |
| clipData, | |
| modifiedClipShader.get(), | |
| coverage, | |
| TextureFormat::kRGBA8}; | |
| paramsGatherer.resetForDraw(); | |
| precompileKeyContext.paintParamsKeyBuilder()->resetForDraw(); | |
| KeyContext keyContext(recorder, | |
| drawContext, | |
| precompileKeyContext.paintParamsKeyBuilder(), | |
| ¶msGatherer, | |
| {}, | |
| SkRect::MakeEmpty(), | |
| 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; | |
| bool avoidDepthMode = context->priv().caps()->avoidDepthMode(); | |
| static const RenderPassProperties kDepth_Stencil_4{ | |
| avoidDepthMode ? DepthStencilFlags::kNone : DepthStencilFlags::kDepthStencil, | |
| kColorType, | |
| /* dstColorSpace= */ nullptr, | |
| /* requiresMSAA= */ true}; | |
| static const RenderPassProperties kDepth_1{ | |
| avoidDepthMode ? DepthStencilFlags::kNone : 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 } }}); | |
| } | |
| // We need to explicitly wait for the precompilation to finish here | |
| context->priv().sharedContext()->pipelineManager()->wait_TestOnly(); | |
| 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); | |
| ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary(); | |
| PaintParamsKeyBuilder builder(dict); | |
| PipelineDataGatherer gatherer(Layout::kMetal); | |
| sk_sp<RuntimeEffectDictionary> rtDict = sk_make_sp<RuntimeEffectDictionary>(); | |
| KeyContext keyContext(caps, | |
| &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); | |
| ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary(); | |
| PaintParamsKeyBuilder builder(dict); | |
| PipelineDataGatherer gatherer(Layout::kMetal); | |
| sk_sp<RuntimeEffectDictionary> rtDict = sk_make_sp<RuntimeEffectDictionary>(); | |
| KeyContext precompileKeyContext(caps, | |
| &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 |