blob: 6424fc529f57cb752f544cc6c6d7d77feae95744 [file]
/*
* Copyright 2025 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/gpu/graphite/precompile/PrecompileColorFilter.h"
#include "include/gpu/graphite/precompile/PrecompileShader.h"
#include "src/base/SkMathPriv.h"
#include "src/gpu/graphite/ContextPriv.h"
#include "src/gpu/graphite/ContextUtils.h"
#include "src/gpu/graphite/GraphicsPipelineDesc.h"
#include "src/gpu/graphite/PrecompileContextPriv.h"
#include "src/gpu/graphite/RenderPassDesc.h"
#include "src/gpu/graphite/RendererProvider.h"
#include "tests/graphite/precompile/PrecompileTestUtils.h"
#include "tools/graphite/UniqueKeyUtils.h"
#include <cstring>
#include <set>
using namespace skgpu::graphite;
using PrecompileShaders::GradientShaderFlags;
using PrecompileShaders::ImageShaderFlags;
using PrecompileShaders::YUVImageShaderFlags;
using ::skgpu::graphite::DepthStencilFlags;
using ::skgpu::graphite::DrawTypeFlags;
using ::skgpu::graphite::PaintOptions;
using ::skgpu::graphite::RenderPassProperties;
namespace PrecompileTestUtils {
PaintOptions SolidSrcover() {
PaintOptions paintOptions;
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions SolidMatrixCFSrcover() {
PaintOptions paintOptions;
paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions LinearGradSmSrcover() {
PaintOptions paintOptions;
paintOptions.setShaders({ PrecompileShaders::LinearGradient(GradientShaderFlags::kSmall) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions LinearGradSRGBSmMedDitherSrcover() {
PaintOptions paintOptions;
paintOptions.setShaders({ PrecompileShaders::LinearGradient(
GradientShaderFlags::kNoLarge,
{ SkGradientShader::Interpolation::InPremul::kNo,
SkGradientShader::Interpolation::ColorSpace::kSRGB,
SkGradientShader::Interpolation::HueMethod::kShorter }) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setDither(true);
return paintOptions;
}
PaintOptions TransparentPaintImagePremulHWAndClampSrcover() {
PaintOptions paintOptions;
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
SkTileMode tm = SkTileMode::kClamp;
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{ &tm, 1 }) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setPaintColorIsOpaque(false);
return paintOptions;
}
PaintOptions TransparentPaintImagePremulHWOnlyMatrixCFSrcover() {
PaintOptions paintOptions;
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setPaintColorIsOpaque(false);
return paintOptions;
}
PaintOptions TransparentPaintImagePremulHWOnlyMatrixCFDitherSrcover() {
PaintOptions paintOptions;
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setPaintColorIsOpaque(false);
paintOptions.setDither(true);
return paintOptions;
}
PaintOptions TransparentPaintImageSRGBHWOnlyMatrixCFDitherSrcover() {
SkColorInfo ci { kRGBA_8888_SkColorType,
kPremul_SkAlphaType,
SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };
PaintOptions paintOptions;
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setPaintColorIsOpaque(false);
paintOptions.setDither(true);
return paintOptions;
}
PaintOptions TransparentPaintImagePremulHWOnlySrcover() {
PaintOptions paintOptions;
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setPaintColorIsOpaque(false);
return paintOptions;
}
PaintOptions TransparentPaintImageSRGBHWOnlySrcover() {
SkColorInfo ci { kRGBA_8888_SkColorType,
kPremul_SkAlphaType,
SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };
PaintOptions paintOptions;
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setPaintColorIsOpaque(false);
return paintOptions;
}
PaintOptions TransparentPaintSrcover() {
PaintOptions paintOptions;
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setPaintColorIsOpaque(false);
return paintOptions;
}
PaintOptions SolidClearSrcSrcover() {
PaintOptions paintOptions;
paintOptions.setBlendModes({ SkBlendMode::kClear,
SkBlendMode::kSrc,
SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions SolidSrcSrcover() {
PaintOptions paintOptions;
paintOptions.setBlendModes({ SkBlendMode::kSrc, SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions ImagePremulNoCubicSrcover() {
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
SkTileMode tm = SkTileMode::kClamp;
PaintOptions paintOptions;
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{ &tm, 1 }) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions ImagePremulHWOnlySrc() {
PaintOptions paintOptions;
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setBlendModes({ SkBlendMode::kSrc });
return paintOptions;
}
PaintOptions ImagePremulHWOnlySrcover() {
PaintOptions paintOptions;
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions ImagePremulClampNoCubicDstin() {
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
SkTileMode tm = SkTileMode::kClamp;
PaintOptions paintOptions;
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{ &tm, 1}) });
paintOptions.setBlendModes({ SkBlendMode::kDstIn });
return paintOptions;
}
PaintOptions ImagePremulHWOnlyDstin() {
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
PaintOptions paintOptions;
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setBlendModes({ SkBlendMode::kDstIn });
return paintOptions;
}
PaintOptions YUVImageSRGBNoCubicSrcover() {
SkColorInfo ci { kRGBA_8888_SkColorType,
kPremul_SkAlphaType,
SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };
PaintOptions paintOptions;
paintOptions.setShaders({ PrecompileShaders::YUVImage(YUVImageShaderFlags::kExcludeCubic,
{ &ci, 1 }) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions YUVImageSRGBSrcover2() {
SkColorInfo ci { kRGBA_8888_SkColorType,
kPremul_SkAlphaType,
SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };
PaintOptions paintOptions;
paintOptions.setShaders({ PrecompileShaders::YUVImage(
YUVImageShaderFlags::kNoCubicNoNonSwizzledHW,
{ &ci, 1 }) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions ImagePremulNoCubicSrcSrcover() {
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
PaintOptions paintOptions;
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setBlendModes({ SkBlendMode::kSrc,
SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions ImageSRGBNoCubicSrc() {
PaintOptions paintOptions;
SkColorInfo ci { kRGBA_8888_SkColorType,
kPremul_SkAlphaType,
SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
SkNamedGamut::kAdobeRGB) };
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setBlendModes({ SkBlendMode::kSrc });
return paintOptions;
}
PaintOptions BlendPorterDuffCFSrcover() {
PaintOptions paintOptions;
// kSrcOver will trigger the PorterDuffBlender
paintOptions.setColorFilters(
{ PrecompileColorFilters::Blend({ SkBlendMode::kSrcOver }) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions ImageAlphaHWOnlySrcover() {
PaintOptions paintOptions;
SkColorInfo ci { kAlpha_8_SkColorType, kUnpremul_SkAlphaType, nullptr };
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions ImageAlphaPremulHWOnlyMatrixCFSrcover() {
PaintOptions paintOptions;
SkColorInfo ci { kAlpha_8_SkColorType, kUnpremul_SkAlphaType, nullptr };
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions ImageAlphaSRGBHWOnlyMatrixCFSrcover() {
// Note: this is different from the other SRGB ColorInfos
SkColorInfo ci { kAlpha_8_SkColorType,
kUnpremul_SkAlphaType,
SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };
PaintOptions paintOptions;
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions ImageAlphaNoCubicSrc() {
PaintOptions paintOptions;
SkColorInfo ci { kAlpha_8_SkColorType, kUnpremul_SkAlphaType, nullptr };
SkTileMode tm = SkTileMode::kRepeat;
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{ &tm, 1}) });
paintOptions.setBlendModes({ SkBlendMode::kSrc });
return paintOptions;
}
PaintOptions ImagePremulHWOnlyPorterDuffCFSrcover() {
PaintOptions paintOptions;
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setColorFilters(
{ PrecompileColorFilters::Blend({ SkBlendMode::kSrcOver }) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions ImagePremulHWOnlyMatrixCFSrcover() {
PaintOptions paintOptions;
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions ImagePremulHWOnlyMatrixCFDitherSrcover() {
PaintOptions paintOptions;
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setDither(true);
return paintOptions;
}
PaintOptions ImageSRGBHWOnlyMatrixCFDitherSrcover() {
SkColorInfo ci { kRGBA_8888_SkColorType,
kPremul_SkAlphaType,
SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };
PaintOptions paintOptions;
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setDither(true);
return paintOptions;
}
PaintOptions ImageHWOnlySRGBSrcover() {
PaintOptions paintOptions;
SkColorInfo ci { kRGBA_8888_SkColorType,
kPremul_SkAlphaType,
SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
SkNamedGamut::kAdobeRGB) };
paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{}) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
namespace {
#if defined(SK_DEBUG)
// This helper maps from the RenderPass string in the Pipeline label to the
// RenderPassProperties needed by the Precompile system
// TODO(robertphillips): converting this to a more piecemeal approach might better illuminate
// the mapping between the string and the RenderPassProperties
RenderPassProperties get_render_pass_properties(const char* str) {
static const struct {
RenderPassProperties fRenderPassProperties;
const char* fStr;
} kRenderPassPropertiesMapping[] = {
{ kR_1_D, "RP((R8+D16 x1).a000)" },
{ kBGRA_1_D, "RP((BGRA8+D16 x1).rgba)" },
{ kRGBA_1_D, "RP((RGBA8+D16 x1).rgba)" },
// These RPPs can generate two strings when Caps::loadOpAffectsMSAAPipelines.
{ kR_4_DS, "RP((R8+D24_S8 x4->1).a000)" },
{ kR_4_DS, "RP((R8+D24_S8 x4->1).a000 w/ msaa load)" },
{ kBGRA_4_D, "RP((BGRA8+D16 x4->1).rgba)" },
{ kBGRA_4_D, "RP((BGRA8+D16 x4->1).rgba w/ msaa load)" },
{ kRGBA_4_D, "RP((RGBA8+D16 x4->1).rgba)" },
{ kRGBA_4_D, "RP((RGBA8+D16 x4->1).rgba w/ msaa load)" },
{ kBGRA_4_DS, "RP((BGRA8+D24_S8 x4->1).rgba)" },
{ kBGRA_4_DS, "RP((BGRA8+D24_S8 x4->1).rgba w/ msaa load)" },
{ kRGBA_4_DS, "RP((RGBA8+D24_S8 x4->1).rgba)" },
{ kRGBA_4_DS, "RP((RGBA8+D24_S8 x4->1).rgba w/ msaa load)" },
{ kRGBA16F_1_D, "RP((RGBA16F+D16 x1).rgba)" },
};
for (const auto& rppm : kRenderPassPropertiesMapping) {
if (strstr(str, rppm.fStr)) {
return rppm.fRenderPassProperties;
}
}
SkAssertResult(0);
return {};
}
// This helper maps from the RenderStep's name in the Pipeline label to the DrawTypeFlag that
// resulted in its use.
DrawTypeFlags get_draw_type_flags(const char* str) {
static const struct {
const char* fStr;
DrawTypeFlags fFlags;
} kDrawTypeFlagsMapping[] = {
{ "BitmapTextRenderStep[Mask]", DrawTypeFlags::kBitmapText_Mask },
{ "BitmapTextRenderStep[LCD]", DrawTypeFlags::kBitmapText_LCD },
{ "BitmapTextRenderStep[Color]", DrawTypeFlags::kBitmapText_Color },
{ "SDFTextRenderStep", DrawTypeFlags::kSDFText },
{ "SDFTextLCDRenderStep", DrawTypeFlags::kSDFText_LCD },
{ "VerticesRenderStep[Tris]", DrawTypeFlags::kDrawVertices },
{ "VerticesRenderStep[TrisTexCoords]", DrawTypeFlags::kDrawVertices },
{ "VerticesRenderStep[TrisColor]", DrawTypeFlags::kDrawVertices },
{ "VerticesRenderStep[TrisColorTexCoords]", DrawTypeFlags::kDrawVertices },
{ "VerticesRenderStep[Tristrips]", DrawTypeFlags::kDrawVertices },
{ "VerticesRenderStep[TristripsTexCoords]", DrawTypeFlags::kDrawVertices },
{ "VerticesRenderStep[TristripsColor]", DrawTypeFlags::kDrawVertices },
{ "VerticesRenderStep[TristripsColorTexCoords]", DrawTypeFlags::kDrawVertices },
{ "CircularArcRenderStep", DrawTypeFlags::kCircularArc },
{ "AnalyticRRectRenderStep", DrawTypeFlags::kAnalyticRRect },
{ "CoverBoundsRenderStep[NonAAFill]", DrawTypeFlags::kNonAAFillRect },
{ "PerEdgeAAQuadRenderStep", DrawTypeFlags::kPerEdgeAAQuad },
{ "CoverageMaskRenderStep", DrawTypeFlags::kNonSimpleShape },
{ "CoverBoundsRenderStep[RegularCover]", DrawTypeFlags::kNonSimpleShape },
{ "CoverBoundsRenderStep[InverseCover]", DrawTypeFlags::kNonSimpleShape },
{ "MiddleOutFanRenderStep[EvenOdd]", DrawTypeFlags::kNonSimpleShape },
{ "MiddleOutFanRenderStep[Winding]", DrawTypeFlags::kNonSimpleShape },
{ "TessellateCurvesRenderStep[EvenOdd]", DrawTypeFlags::kNonSimpleShape },
{ "TessellateCurvesRenderStep[Winding]", DrawTypeFlags::kNonSimpleShape },
{ "TessellateStrokesRenderStep", DrawTypeFlags::kNonSimpleShape },
{ "TessellateWedgesRenderStep[Convex]", DrawTypeFlags::kNonSimpleShape },
{ "TessellateWedgesRenderStep[EvenOdd]", DrawTypeFlags::kNonSimpleShape },
{ "TessellateWedgesRenderStep[Winding]", DrawTypeFlags::kNonSimpleShape },
};
for (const auto& dtfm : kDrawTypeFlagsMapping) {
if (strstr(str, dtfm.fStr)) {
SkAssertResult(dtfm.fFlags != DrawTypeFlags::kNone);
return dtfm.fFlags;
}
}
SkAssertResult(0);
return DrawTypeFlags::kNone;
}
void deduce_settings_from_label(const char* testStr, PrecompileSettings* result) {
result->fDrawTypeFlags = get_draw_type_flags(testStr);
result->fRenderPassProps = get_render_pass_properties(testStr);
if (strstr(testStr, "LinearGradient4 ColorSpaceTransformSRGB") ||
strstr(testStr, "LinearGradient8 ColorSpaceTransformSRGB") ||
strstr(testStr, "PrimitiveColor ColorSpaceTransformSRGB")) {
result->fRenderPassProps.fDstCS = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
SkNamedGamut::kAdobeRGB);
} else if (strstr(testStr, "ColorSpaceTransformSRGB")) {
result->fRenderPassProps.fDstCS = SkColorSpace::MakeSRGB();
}
}
#endif // SK_DEBUG
[[maybe_unused]] void find_duplicates(SkSpan<const PipelineLabel> cases) {
for (size_t i = 0; i < std::size(cases); ++i) {
for (size_t j = i+1; j < std::size(cases); ++j) {
if (!strcmp(cases[i].fString, cases[j].fString)) {
SkDebugf("Duplicate %zu && %zu\n", i, j);
}
}
}
}
std::string rm_whitespace(const std::string& s) {
auto start = s.find_first_not_of(' ');
auto end = s.find_last_not_of(' ');
return s.substr(start, (end - start) + 1);
}
} // anonymous namespace
bool PrecompileSettings::isSubsetOf(const PrecompileSettings& superSet) const {
SkASSERT(SkPopCount(static_cast<uint32_t>(fDrawTypeFlags)) == 1);
// 'superSet' may have a wider range of DrawTypeFlags
return (fDrawTypeFlags & superSet.fDrawTypeFlags) &&
fRenderPassProps == superSet.fRenderPassProps;
}
PipelineLabelInfoCollector::PipelineLabelInfoCollector(SkSpan<const PipelineLabel> cases,
SkipFunc skip) {
for (size_t i = 0; i < std::size(cases); ++i) {
const char* testStr = cases[i].fString;
if (skip(testStr)) {
fMap.insert({ testStr, PipelineLabelInfo(i, PipelineLabelInfo::kSkipped) });
} else {
fMap.insert({ testStr, PipelineLabelInfo(i) });
}
}
}
int PipelineLabelInfoCollector::processLabel(const std::string& precompiledLabel,
int precompileCase) {
++fNumLabelsProcessed;
auto result = fMap.find(precompiledLabel.c_str());
if (result == fMap.end()) {
SkASSERT(fOverGenerated.find(precompiledLabel) == fOverGenerated.end());
fOverGenerated.insert({ precompiledLabel, OverGenInfo(precompileCase) });
return -1;
}
// We expect each PrecompileSettings case to handle disjoint sets of labels. If this
// assert fires some pair of PrecompileSettings are handling the same case.
SkASSERT(result->second.fPrecompileCase == PipelineLabelInfo::kUninit);
result->second.fPrecompileCase = precompileCase;
return result->second.fCasesIndex;
}
void PipelineLabelInfoCollector::finalReport() {
std::vector<int> skipped, missed;
int numCovered = 0, numIntentionallySkipped = 0, numMissed = 0;
for (const auto& iter : fMap) {
if (iter.second.fPrecompileCase == PipelineLabelInfo::kSkipped) {
++numIntentionallySkipped;
skipped.push_back(iter.second.fCasesIndex);
} else if (iter.second.fPrecompileCase == PipelineLabelInfo::kUninit) {
++numMissed;
missed.push_back(iter.second.fCasesIndex);
} else {
SkASSERT(iter.second.fPrecompileCase >= 0);
++numCovered;
}
}
SkASSERT(numMissed == (int) missed.size());
SkASSERT(numIntentionallySkipped == (int) skipped.size());
SkDebugf("-----------------------\n");
sort(missed.begin(), missed.end());
SkDebugf("not covered: ");
for (int i : missed) {
SkDebugf("%d, ", i);
}
SkDebugf("\n");
sort(skipped.begin(), skipped.end());
SkDebugf("skipped: ");
for (int i : skipped) {
SkDebugf("%d, ", i);
}
SkDebugf("\n");
SkASSERT(numCovered + static_cast<int>(fOverGenerated.size()) == fNumLabelsProcessed);
SkDebugf("covered %d notCovered %d skipped %d total %zu\n",
numCovered,
numMissed,
numIntentionallySkipped,
fMap.size());
SkDebugf("%d Pipelines were generated\n", fNumLabelsProcessed);
SkDebugf("of that %zu Pipelines were over-generated:\n", fOverGenerated.size());
#if 0 // enable to print out a list of the over-generated Pipeline labels
for (const auto& s : fOverGenerated) {
SkDebugf("from %d: %s\n", s.second.fOriginatingSetting, s.first.c_str());
}
#endif
}
// Precompile with the provided PrecompileSettings then verify that:
// 1) some case in 'kCases' is covered
// 2) more than 40% of the generated Pipelines are in kCases
void RunTest(skgpu::graphite::PrecompileContext* precompileContext,
skiatest::Reporter* reporter,
SkSpan<const PrecompileSettings> precompileSettings,
int precompileSettingsIndex,
SkSpan<const PipelineLabel> cases,
PipelineLabelInfoCollector* collector) {
using namespace skgpu::graphite;
const PrecompileSettings& settings = precompileSettings[precompileSettingsIndex];
precompileContext->priv().globalCache()->resetGraphicsPipelines();
Precompile(precompileContext,
settings.fPaintOptions,
settings.fDrawTypeFlags,
{ &settings.fRenderPassProps, 1 });
std::set<std::string> generatedLabels;
{
const RendererProvider* rendererProvider = precompileContext->priv().rendererProvider();
const ShaderCodeDictionary* dict = precompileContext->priv().shaderCodeDictionary();
std::vector<skgpu::UniqueKey> generatedKeys;
UniqueKeyUtils::FetchUniqueKeys(precompileContext, &generatedKeys);
for (const skgpu::UniqueKey& key : generatedKeys) {
GraphicsPipelineDesc pipelineDesc;
RenderPassDesc renderPassDesc;
UniqueKeyUtils::ExtractKeyDescs(precompileContext, key, &pipelineDesc, &renderPassDesc);
const RenderStep* renderStep = rendererProvider->lookup(pipelineDesc.renderStepID());
std::string tmp = GetPipelineLabel(dict, renderPassDesc, renderStep,
pipelineDesc.paintParamsID());
generatedLabels.insert(rm_whitespace(tmp));
}
}
std::vector<bool> localMatches;
std::vector<size_t> matchesInCases;
for (const std::string& g : generatedLabels) {
int matchInCases = collector->processLabel(g, precompileSettingsIndex);
localMatches.push_back(matchInCases >= 0);
if (matchInCases >= 0) {
matchesInCases.push_back(matchInCases);
#if defined(SK_DEBUG)
{
PrecompileSettings expectedSettings;
deduce_settings_from_label(cases[matchInCases].fString, &expectedSettings);
SkASSERT(expectedSettings.isSubsetOf(settings));
}
#endif
}
}
REPORTER_ASSERT(reporter, matchesInCases.size() >= 1, // This tests requirement 1, above
"%d: num matches: %zu", precompileSettingsIndex, matchesInCases.size());
float utilization = ((float) matchesInCases.size())/generatedLabels.size();
REPORTER_ASSERT(reporter, utilization >= 0.4f, // This tests requirement 2, above
"%d: utilization: %f", precompileSettingsIndex, utilization);
#if defined(PRINT_COVERAGE)
// This block will print out all the cases in 'kCases' that the given PrecompileSettings
// covered.
sort(matchesInCases.begin(), matchesInCases.end());
SkDebugf("precompile case %d handles %zu/%zu cases (%.2f utilization): ",
precompileSettingsIndex, matchesInCases.size(), generatedLabels.size(), utilization);
for (size_t h : matchesInCases) {
SkDebugf("%zu ", h);
}
SkDebugf("\n");
#endif
#if defined(PRINT_GENERATED_LABELS)
// This block will print out all the labels from the given PrecompileSettings marked with
// whether they were found in 'kCases'. This is useful for analyzing the set of Pipelines
// generated by a single PrecompileSettings and is usually used along with 'kChosenCase'.
SkASSERT(localMatches.size() == generatedLabels.size());
int index = 0;
for (const std::string& g : generatedLabels) {
SkDebugf("%c %d: %s\n", localMatches[index] ? 'h' : ' ', index, g.c_str());
++index;
}
#endif
}
} // namespace PrecompileTestUtils
#endif // SK_GRAPHITE