blob: c19a85fddb9e4053d6d33789bc3c7f3356454b68 [file] [log] [blame]
/*
* 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/PrecompileRuntimeEffect.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"
#if defined (SK_VULKAN)
#include "include/gpu/graphite/vk/precompile/VulkanPrecompileShader.h"
#include "include/gpu/vk/VulkanTypes.h"
#include "src/base/SkBase64.h"
#include "src/gpu/graphite/vk/VulkanYcbcrConversion.h"
#endif // SK_VULKAN
#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 ImagePremulHWOnlyPlusColorSrcover() {
PaintOptions paintOptions;
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
SkBlendMode kBlendModes = SkBlendMode::kPlus;
paintOptions.setShaders({ PrecompileShaders::Blend({ &kBlendModes, 1 },
{ std::move(img) },
{ PrecompileShaders::Color() }) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions TransparentPaintImagePremulHWOnlyPlusColorSrcover() {
PaintOptions paintOptions;
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
SkBlendMode kBlendModes = SkBlendMode::kPlus;
paintOptions.setShaders({ PrecompileShaders::Blend({ &kBlendModes, 1 },
{ std::move(img) },
{ PrecompileShaders::Color() }) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setPaintColorIsOpaque(false);
return paintOptions;
}
PaintOptions SolidSrcover() {
PaintOptions paintOptions;
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 YUVImageSRGBSrcover() {
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 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 ImageAlphaClampNoCubicSrc() {
SkColorInfo ci { kAlpha_8_SkColorType, kUnpremul_SkAlphaType, nullptr };
SkTileMode tm = SkTileMode::kClamp;
PaintOptions paintOptions;
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 ImageSRGBHWOnlyMatrixCFSrcover() {
PaintOptions paintOptions;
SkColorInfo ci { kRGBA_8888_SkColorType,
kPremul_SkAlphaType,
SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };
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 {
// Note: passing in a name to 'makeEffect' is a difference from Android's factory functions.
sk_sp<SkRuntimeEffect> makeEffect(const SkString& sksl, const char* name) {
SkRuntimeEffect::Options options;
options.fName = name;
auto [effect, error] = SkRuntimeEffect::MakeForShader(sksl, options);
if (!effect) {
SkDebugf("%s\n", error.c_str());
}
return effect;
}
class MouriMap {
public:
MouriMap() {
// The following code blocks are just stubs for the Android code. For Skia's testing
// purposes they only need to have the same name and number of children as the real code.
// When the following PaintOptions are used in Android the real SkSL must be supplied.
static const SkString kCrosstalkAndChunk16x16Code(R"(
uniform shader img;
vec4 main(vec2 xy) {
float3 linear = toLinearSrgb(img.eval(0.25 * xy).rgb);
return float4(fromLinearSrgb(linear), 1.0);
}
)");
fCrosstalkAndChunk16x16Effect = makeEffect(kCrosstalkAndChunk16x16Code,
"RE_MouriMap_CrossTalkAndChunk16x16Effect");
static const SkString kChunk8x8Code(R"(
uniform shader img;
vec4 main(vec2 xy) {
return float4(img.eval(0.33 * xy).rgb, 1.0);
}
)");
fChunk8x8Effect = makeEffect(kChunk8x8Code, "RE_MouriMap_Chunk8x8Effect");
static const SkString kBlurCode(R"(
uniform shader img;
vec4 main(vec2 xy) {
return float4(img.eval(0.4 * xy).rgb, 0.0);
}
)");
fBlurEffect = makeEffect(kBlurCode, "RE_MouriMap_BlurEffect");
static const SkString kTonemapCode(R"(
uniform shader img1;
uniform shader img2;
vec4 main(vec2 xy) {
float alpha = img1.eval(xy).r;
float3 linear = toLinearSrgb(img2.eval(0.5 * xy).rgb);
return float4(fromLinearSrgb(linear), alpha);
}
)");
fToneMapEffect = makeEffect(kTonemapCode, "RE_MouriMap_TonemapEffect");
}
sk_sp<SkRuntimeEffect> crosstalkAndChunk16x16Effect() const {
return fCrosstalkAndChunk16x16Effect;
}
sk_sp<SkRuntimeEffect> chunk8x8Effect() const { return fChunk8x8Effect; }
sk_sp<SkRuntimeEffect> blurEffect() const { return fBlurEffect; }
sk_sp<SkRuntimeEffect> toneMapEffect() const { return fToneMapEffect; }
private:
sk_sp<SkRuntimeEffect> fCrosstalkAndChunk16x16Effect;
sk_sp<SkRuntimeEffect> fChunk8x8Effect;
sk_sp<SkRuntimeEffect> fBlurEffect;
sk_sp<SkRuntimeEffect> fToneMapEffect;
};
const MouriMap& MouriMap() {
static class MouriMap MouriMap;
return MouriMap;
}
} // anonymous namespace
skgpu::graphite::PaintOptions MouriMapCrosstalkAndChunk16x16Passthrough() {
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
sk_sp<PrecompileShader> crosstalk = PrecompileRuntimeEffects::MakePrecompileShader(
MouriMap().crosstalkAndChunk16x16Effect(),
{ { std::move(img) } });
PaintOptions paintOptions;
paintOptions.setShaders({ std::move(crosstalk) });
paintOptions.setBlendModes({ SkBlendMode::kSrc });
return paintOptions;
}
skgpu::graphite::PaintOptions MouriMapCrosstalkAndChunk16x16Premul() {
// This usage of kUnpremul is non-obvious. It acts to short circuit the identity-colorspace
// optimization for runtime effects. In this case, the Pipeline requires a
// ColorSpaceTransformPremul instead of the (optimized) Passthrough.
SkColorInfo ci { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
sk_sp<PrecompileShader> crosstalk = PrecompileRuntimeEffects::MakePrecompileShader(
MouriMap().crosstalkAndChunk16x16Effect(),
{ { std::move(img) } });
PaintOptions paintOptions;
paintOptions.setShaders({ std::move(crosstalk) });
paintOptions.setBlendModes({ SkBlendMode::kSrc });
return paintOptions;
}
skgpu::graphite::PaintOptions MouriMapChunk8x8Effect() {
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
sk_sp<PrecompileShader> chunk8x8 = PrecompileRuntimeEffects::MakePrecompileShader(
MouriMap().chunk8x8Effect(),
{ { std::move(img) } });
PaintOptions paintOptions;
paintOptions.setShaders({ std::move(chunk8x8) });
paintOptions.setBlendModes({ SkBlendMode::kSrc });
return paintOptions;
}
skgpu::graphite::PaintOptions MouriMapBlur() {
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
sk_sp<PrecompileShader> blur = PrecompileRuntimeEffects::MakePrecompileShader(
MouriMap().blurEffect(),
{ { std::move(img) } });
PaintOptions paintOptions;
paintOptions.setShaders({ std::move(blur) });
paintOptions.setBlendModes({ SkBlendMode::kSrc });
return paintOptions;
}
skgpu::graphite::PaintOptions MouriMapToneMap() {
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img1 = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
sk_sp<PrecompileShader> img2 = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
sk_sp<PrecompileShader> toneMap = PrecompileRuntimeEffects::MakePrecompileShader(
MouriMap().toneMapEffect(),
{ { std::move(img1) }, { std::move(img2) } });
PaintOptions paintOptions;
paintOptions.setShaders({ std::move(toneMap) });
paintOptions.setBlendModes({ SkBlendMode::kSrc });
return paintOptions;
}
skgpu::graphite::PaintOptions KawaseBlurLowSrcSrcOver() {
static const SkString kLowSampleBlurCode(R"(
uniform shader img;
half4 main(float2 xy) {
half3 c = img.eval(0.55 * xy).rgb;
return half4(c, 1.0);
}
)");
sk_sp<SkRuntimeEffect> lowSampleBlurEffect = makeEffect(
kLowSampleBlurCode,
"RE_KawaseBlurDualFilter_LowSampleBlurEffect");
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
sk_sp<PrecompileShader> kawase = PrecompileRuntimeEffects::MakePrecompileShader(
std::move(lowSampleBlurEffect),
{ { img } });
PaintOptions paintOptions;
paintOptions.setShaders({ std::move(kawase) });
paintOptions.setBlendModes({ SkBlendMode::kSrc, SkBlendMode::kSrcOver });
return paintOptions;
}
skgpu::graphite::PaintOptions KawaseBlurHighSrc() {
SkString kHighSampleBlurCode(R"(
uniform shader img;
half4 main(float2 xy) {
half3 c = img.eval(0.6 * xy).rgb;
return half4(c * 0.5, 1.0);
}
)");
sk_sp<SkRuntimeEffect> highSampleBlurEffect = makeEffect(
kHighSampleBlurCode,
"RE_KawaseBlurDualFilter_HighSampleBlurEffect");
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
sk_sp<PrecompileShader> kawase = PrecompileRuntimeEffects::MakePrecompileShader(
std::move(highSampleBlurEffect),
{ { img } });
PaintOptions paintOptions;
paintOptions.setShaders({ std::move(kawase) });
paintOptions.setBlendModes({ SkBlendMode::kSrc });
return paintOptions;
}
skgpu::graphite::PaintOptions BlurFilterMix() {
static const SkString kMixCode(R"(
uniform shader img1;
uniform shader img2;
half4 main(float2 xy) {
return half4(mix(img1.eval(xy), img2.eval(xy), 0.5)).rgb1;
}
)");
sk_sp<SkRuntimeEffect> mixEffect = makeEffect(kMixCode, "RE_BlurFilter_MixEffect");
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
sk_sp<PrecompileShader> mix = PrecompileRuntimeEffects::MakePrecompileShader(
std::move(mixEffect),
{ { img }, { img } });
PaintOptions paintOptions;
paintOptions.setShaders({ std::move(mix) });
paintOptions.setBlendModes({ SkBlendMode::kSrc });
return paintOptions;
}
namespace {
class EdgeExtension {
public:
EdgeExtension() {
// The following code block is just a stub for the Android code. For Skia's testing
// purposes it only needs to have the same name and number of children as the real code.
// When the following PaintOptions are used in Android the real SkSL must be supplied.
static const SkString kEdgeExtensionCode(R"(
uniform shader img;
vec4 main(vec2 xy) {
float3 sample = img.eval(0.115 * xy).rgb;
return float4(sample, 1.0);
}
)");
fEdgeExtensionEffect = makeEffect(kEdgeExtensionCode, "RE_EdgeExtensionEffect");
SkASSERT(fEdgeExtensionEffect);
}
sk_sp<SkRuntimeEffect> edgeExtensionEffect() const { return fEdgeExtensionEffect; }
private:
sk_sp<SkRuntimeEffect> fEdgeExtensionEffect;
};
const EdgeExtension& EdgeExtensionSingleton() {
static class EdgeExtension sEdgeExtension;
return sEdgeExtension;
}
} // anonymous namespace
skgpu::graphite::PaintOptions EdgeExtensionPassthroughSrcover() {
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
sk_sp<PrecompileShader> edgeEffect = PrecompileRuntimeEffects::MakePrecompileShader(
EdgeExtensionSingleton().edgeExtensionEffect(),
{ { std::move(img) } });
PaintOptions paintOptions;
paintOptions.setShaders({ std::move(edgeEffect) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
skgpu::graphite::PaintOptions EdgeExtensionPremulSrcover() {
// This usage of kUnpremul is non-obvious. It acts to short circuit the identity-colorspace
// optimization for runtime effects. In this case, the Pipeline requires a
// ColorSpaceTransformPremul instead of the (optimized) Passthrough.
SkColorInfo ci { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
sk_sp<PrecompileShader> edgeEffect = PrecompileRuntimeEffects::MakePrecompileShader(
EdgeExtensionSingleton().edgeExtensionEffect(),
{ { std::move(img) } });
PaintOptions paintOptions;
paintOptions.setShaders({ std::move(edgeEffect) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
skgpu::graphite::PaintOptions TransparentPaintEdgeExtensionPassthroughMatrixCFDitherSrcover() {
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
sk_sp<PrecompileShader> edgeEffect = PrecompileRuntimeEffects::MakePrecompileShader(
EdgeExtensionSingleton().edgeExtensionEffect(),
{ { std::move(img) } });
PaintOptions paintOptions;
paintOptions.setShaders({ std::move(edgeEffect) });
paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setPaintColorIsOpaque(false);
paintOptions.setDither(true);
return paintOptions;
}
skgpu::graphite::PaintOptions TransparentPaintEdgeExtensionPassthroughSrcover() {
SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
sk_sp<PrecompileShader> edgeEffect = PrecompileRuntimeEffects::MakePrecompileShader(
EdgeExtensionSingleton().edgeExtensionEffect(),
{ { std::move(img) } });
PaintOptions paintOptions;
paintOptions.setShaders({ std::move(edgeEffect) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setPaintColorIsOpaque(false);
return paintOptions;
}
skgpu::graphite::PaintOptions TransparentPaintEdgeExtensionPremulSrcover() {
// This usage of kUnpremul is non-obvious. It acts to short circuit the identity-colorspace
// optimization for runtime effects. In this case, the Pipeline requires a
// ColorSpaceTransformPremul instead of the (optimized) Passthrough.
SkColorInfo ci { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, nullptr };
sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
sk_sp<PrecompileShader> edgeEffect = PrecompileRuntimeEffects::MakePrecompileShader(
EdgeExtensionSingleton().edgeExtensionEffect(),
{ { std::move(img) } });
PaintOptions paintOptions;
paintOptions.setShaders({ std::move(edgeEffect) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setPaintColorIsOpaque(false);
return paintOptions;
}
#if defined(SK_VULKAN)
namespace {
sk_sp<PrecompileShader> vulkan_ycbcr_image_shader(uint64_t format,
VkSamplerYcbcrModelConversion model,
VkSamplerYcbcrRange range,
VkChromaLocation location,
bool pqCS = false) {
SkColorInfo ci { kRGBA_8888_SkColorType,
kPremul_SkAlphaType,
pqCS ? SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ,
SkNamedGamut::kRec2020)
: nullptr };
skgpu::VulkanYcbcrConversionInfo info;
info.fExternalFormat = format;
info.fYcbcrModel = model;
info.fYcbcrRange = range;
info.fXChromaOffset = location;
info.fYChromaOffset = location;
info.fChromaFilter = VK_FILTER_LINEAR;
return PrecompileShaders::VulkanYCbCrImage(info,
PrecompileShaders::ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
}
} // anonymous namespace
PaintOptions ImagePremulYCbCr238Srcover(bool narrow) {
PaintOptions paintOptions;
// HardwareImage(3: kHoAAO4AAAAAAAAA)
paintOptions.setShaders({ vulkan_ycbcr_image_shader(238,
VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709,
narrow ? VK_SAMPLER_YCBCR_RANGE_ITU_NARROW
: VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
VK_CHROMA_LOCATION_MIDPOINT) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions ImagePremulYCbCr240Srcover() {
PaintOptions paintOptions;
// HardwareImage(3: kHIAAPAAAAAAAAAA)
paintOptions.setShaders({ vulkan_ycbcr_image_shader(240,
VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709,
VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
VK_CHROMA_LOCATION_MIDPOINT) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
return paintOptions;
}
PaintOptions TransparentPaintImagePremulYCbCr238Srcover() {
PaintOptions paintOptions;
// HardwareImage(3: kHoAAO4AAAAAAAAA)
paintOptions.setShaders({ vulkan_ycbcr_image_shader(238,
VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709,
VK_SAMPLER_YCBCR_RANGE_ITU_NARROW,
VK_CHROMA_LOCATION_MIDPOINT) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setPaintColorIsOpaque(false);
return paintOptions;
}
PaintOptions TransparentPaintImagePremulYCbCr240Srcover() {
PaintOptions paintOptions;
// HardwareImage(3: kHIAAPAAAAAAAAAA)
paintOptions.setShaders({ vulkan_ycbcr_image_shader(240,
VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709,
VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
VK_CHROMA_LOCATION_MIDPOINT) });
paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
paintOptions.setPaintColorIsOpaque(false);
return paintOptions;
}
skgpu::graphite::PaintOptions MouriMapCrosstalkAndChunk16x16YCbCr247() {
PaintOptions paintOptions;
// HardwareImage(3: kEwAAPcAAAAAAAAA)
sk_sp<PrecompileShader> img = vulkan_ycbcr_image_shader(
247,
VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020,
VK_SAMPLER_YCBCR_RANGE_ITU_NARROW,
VK_CHROMA_LOCATION_COSITED_EVEN);
sk_sp<PrecompileShader> crosstalk = PrecompileRuntimeEffects::MakePrecompileShader(
MouriMap().crosstalkAndChunk16x16Effect(),
{ { std::move(img) } });
paintOptions.setShaders({ std::move(crosstalk) });
paintOptions.setBlendModes({ SkBlendMode::kSrc });
return paintOptions;
}
void Base642YCbCr(const char* str) {
size_t expectedDstLength;
SkBase64::Error error = SkBase64::Decode(str, strlen(str), nullptr, &expectedDstLength);
if (error != SkBase64::kNoError) {
return;
}
if (expectedDstLength % 4 != 0) {
return;
}
int numInts = expectedDstLength / 4;
skia_private::AutoTMalloc<uint32_t> dst(numInts);
size_t actualDstLength;
error = SkBase64::Decode(str, strlen(str), dst, &actualDstLength);
if (error != SkBase64::kNoError || expectedDstLength != actualDstLength) {
return;
}
SamplerDesc s(dst[0], dst[1], dst[2]);
SkDebugf("tileModes: %d %d filterMode: %d mipmap: %d ",
static_cast<int>(s.tileModeX()),
static_cast<int>(s.tileModeY()),
static_cast<int>(s.filterMode()),
static_cast<int>(s.mipmap()));
skgpu::VulkanYcbcrConversionInfo info =
VulkanYcbcrConversion::FromImmutableSamplerInfo(s.immutableSamplerInfo());
SkDebugf("VulkanYcbcrConversionInfo: format: %d extFormat: %llu model: %d range: %d "
"xOff: %d yOff: %d filter: %d explicit: %u features: %u components: %d %d %d %d\n",
info.fFormat,
(unsigned long long) info.fExternalFormat,
info.fYcbcrModel,
info.fYcbcrRange,
info.fXChromaOffset,
info.fYChromaOffset,
info.fChromaFilter,
info.fForceExplicitReconstruction,
info.fFormatFeatures,
info.fComponents.r,
info.fComponents.g,
info.fComponents.b,
info.fComponents.a);
}
#endif // SK_VULKAN
namespace {
// This assumes there is some Singleton in Android that can provide RE_LinearEffects
// given some input. For this mock up, the input is just the parameter portion
// of the RE_LinearEffect Pipeline label (e.g., "UNKNOWN__SRGB__false__UNKNOWN").
// Presumably, irl, the parameters would be the actual types used to create the label.
class LinearEffectSingleton {
public:
sk_sp<SkRuntimeEffect> findOrCreate(const char* parameterStr) {
SkString name = SkStringPrintf("RE_LinearEffect_%s__Shader",
parameterStr);
auto result = fEffects.find(name.c_str());
if (result != fEffects.end()) {
return result->second;
}
// Each code snippet must be unique, otherwise Skia will internally find a match
// and uniquify things. To avoid this we just add an arbitrary alpha constant
// to the code.
static float arbitraryAlpha = 0.051f;
SkString linearEffectCode = SkStringPrintf(
"uniform shader child;"
"vec4 main(vec2 xy) {"
"float3 linear = toLinearSrgb(child.eval(xy).rgb);"
"return float4(fromLinearSrgb(linear), %f);"
"}",
arbitraryAlpha);
arbitraryAlpha += 0.05f;
sk_sp<SkRuntimeEffect> linearEffect = makeEffect(linearEffectCode, name.c_str());
fEffects.insert({ name.c_str(), linearEffect });
return linearEffect;
}
private:
std::map<std::string, sk_sp<SkRuntimeEffect>> fEffects;
};
sk_sp<PrecompileShader> create_child_shader(ChildType childType) {
switch (childType) {
case ChildType::kSolidColor:
return PrecompileShaders::Color();
case ChildType::kHWTexture: {
SkColorInfo ci { kRGBA_8888_SkColorType,
kPremul_SkAlphaType,
SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
SkNamedGamut::kAdobeRGB) };
return PrecompileShaders::Image(PrecompileShaders::ImageShaderFlags::kExcludeCubic,
{ &ci, 1 },
{});
}
#if defined(SK_VULKAN)
case ChildType::kHWTextureYCbCr247:
// HardwareImage(3: kEwAAPcAAAAAAAAA)
return vulkan_ycbcr_image_shader(247,
VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020,
VK_SAMPLER_YCBCR_RANGE_ITU_NARROW,
VK_CHROMA_LOCATION_COSITED_EVEN,
/* pqCS= */ true);
#endif
}
return nullptr;
}
} // anonymous namespace
skgpu::graphite::PaintOptions LinearEffect(const char* parameterStr,
ChildType childType,
SkBlendMode blendMode,
bool paintColorIsOpaque,
bool matrixColorFilter,
bool dither) {
static LinearEffectSingleton gLinearEffectSingleton;
PaintOptions paintOptions;
sk_sp<SkRuntimeEffect> linearEffect = gLinearEffectSingleton.findOrCreate(parameterStr);
sk_sp<PrecompileShader> child = create_child_shader(childType);
paintOptions.setShaders({ PrecompileRuntimeEffects::MakePrecompileShader(
std::move(linearEffect),
{ { std::move(child) } }) });
if (matrixColorFilter) {
paintOptions.setColorFilters({PrecompileColorFilters::Matrix()});
}
paintOptions.setBlendModes({ blendMode });
paintOptions.setPaintColorIsOpaque(paintColorIsOpaque);
paintOptions.setDither(dither);
return paintOptions;
}
namespace {
[[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
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()) {
SkDEBUGCODE(auto prior = fOverGenerated.find(precompiledLabel);)
SkASSERTF(prior == fOverGenerated.end(),
"duplicate (unused) Pipeline found for cases %d %d:\n%s\n",
prior->second.fOriginatingSetting,
precompileCase,
precompiledLabel.c_str());
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.
SkASSERTF(result->second.fPrecompileCase == PipelineLabelInfo::kUninit,
"cases %d and %d cover the same label",
result->second.fPrecompileCase, precompileCase);
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,
static_cast<DrawTypeFlags>(settings.fDrawTypeFlags.value()),
settings.fRenderPassProps);
if (settings.fAnalyticClipping) {
SkASSERT(!(settings.fDrawTypeFlags & DrawTypeFlags::kAnalyticClip));
SkEnumBitMask<DrawTypeFlags> newFlags = settings.fDrawTypeFlags |
DrawTypeFlags::kAnalyticClip;
Precompile(precompileContext,
settings.fPaintOptions,
static_cast<DrawTypeFlags>(newFlags.value()),
settings.fRenderPassProps);
}
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);
}
}
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("// %d: %d%% (%zu/%zu) handles: ",
precompileSettingsIndex,
SkScalarRoundToInt(utilization * 100),
matchesInCases.size(), generatedLabels.size());
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