Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Namespaces | Macros | Functions
KeyHelpers.cpp File Reference
#include "src/gpu/graphite/KeyHelpers.h"
#include "include/core/SkColorFilter.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkData.h"
#include "include/core/SkImageInfo.h"
#include "include/effects/SkRuntimeEffect.h"
#include "include/gpu/graphite/Surface.h"
#include "src/base/SkHalf.h"
#include "src/core/SkBlendModeBlender.h"
#include "src/core/SkBlenderBase.h"
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkDebugUtils.h"
#include "src/core/SkRuntimeBlender.h"
#include "src/core/SkRuntimeEffectPriv.h"
#include "src/core/SkYUVMath.h"
#include "src/effects/colorfilters/SkBlendModeColorFilter.h"
#include "src/effects/colorfilters/SkColorFilterBase.h"
#include "src/effects/colorfilters/SkColorSpaceXformColorFilter.h"
#include "src/effects/colorfilters/SkComposeColorFilter.h"
#include "src/effects/colorfilters/SkGaussianColorFilter.h"
#include "src/effects/colorfilters/SkMatrixColorFilter.h"
#include "src/effects/colorfilters/SkRuntimeColorFilter.h"
#include "src/effects/colorfilters/SkTableColorFilter.h"
#include "src/effects/colorfilters/SkWorkingFormatColorFilter.h"
#include "src/gpu/Blend.h"
#include "src/gpu/DitherUtils.h"
#include "src/gpu/Swizzle.h"
#include "src/gpu/graphite/Caps.h"
#include "src/gpu/graphite/DrawContext.h"
#include "src/gpu/graphite/Image_Graphite.h"
#include "src/gpu/graphite/Image_YUVA_Graphite.h"
#include "src/gpu/graphite/KeyContext.h"
#include "src/gpu/graphite/Log.h"
#include "src/gpu/graphite/PaintParams.h"
#include "src/gpu/graphite/PaintParamsKey.h"
#include "src/gpu/graphite/PipelineData.h"
#include "src/gpu/graphite/ReadSwizzle.h"
#include "src/gpu/graphite/RecorderPriv.h"
#include "src/gpu/graphite/ResourceProvider.h"
#include "src/gpu/graphite/RuntimeEffectDictionary.h"
#include "src/gpu/graphite/ShaderCodeDictionary.h"
#include "src/gpu/graphite/Texture.h"
#include "src/gpu/graphite/TextureProxy.h"
#include "src/gpu/graphite/TextureProxyView.h"
#include "src/gpu/graphite/TextureUtils.h"
#include "src/gpu/graphite/Uniform.h"
#include "src/gpu/graphite/UniformManager.h"
#include "src/image/SkImage_Base.h"
#include "src/shaders/SkBlendShader.h"
#include "src/shaders/SkColorFilterShader.h"
#include "src/shaders/SkColorShader.h"
#include "src/shaders/SkCoordClampShader.h"
#include "src/shaders/SkEmptyShader.h"
#include "src/shaders/SkImageShader.h"
#include "src/shaders/SkLocalMatrixShader.h"
#include "src/shaders/SkPerlinNoiseShaderImpl.h"
#include "src/shaders/SkPerlinNoiseShaderType.h"
#include "src/shaders/SkPictureShader.h"
#include "src/shaders/SkRuntimeShader.h"
#include "src/shaders/SkShaderBase.h"
#include "src/shaders/SkTransformShader.h"
#include "src/shaders/SkTriColorShader.h"
#include "src/shaders/SkWorkingColorSpaceShader.h"
#include "src/shaders/gradients/SkConicalGradient.h"
#include "src/shaders/gradients/SkGradientBaseShader.h"
#include "src/shaders/gradients/SkLinearGradient.h"
#include "src/shaders/gradients/SkRadialGradient.h"
#include "src/shaders/gradients/SkSweepGradient.h"

Go to the source code of this file.

Namespaces

namespace  skgpu
 
namespace  skgpu::graphite
 

Macros

#define VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)    SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, dict->getUniforms(codeSnippetID));)
 
#define M(type)
 
#define M(type)
 
#define M(type)
 
#define M(type)
 
#define M(type)
 

Functions

static bool skgpu::graphite::can_do_tiling_in_hw (const Caps *caps, const ImageShaderBlock::ImageData &imgData)
 
void skgpu::graphite::AddBlendModeColorFilter (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, SkBlendMode bm, const SkPMColor4f &srcColor)
 
static bool skgpu::graphite::skdata_matches (const SkData *a, const SkData *b)
 
static void skgpu::graphite::gather_runtime_effect_uniforms (const KeyContext &keyContext, const SkRuntimeEffect *effect, SkSpan< const Uniform > graphiteUniforms, const SkData *uniformData, PipelineDataGatherer *gatherer)
 
void skgpu::graphite::AddToKey (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkBlender *blender)
 
void skgpu::graphite::NotifyImagesInUse (Recorder *recorder, DrawContext *drawContext, const SkBlender *blender)
 
static SkPMColor4f skgpu::graphite::map_color (const SkColor4f &c, SkColorSpace *src, SkColorSpace *dst)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkBlendModeColorFilter *filter)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkColorSpaceXformColorFilter *filter)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *keyBuilder, PipelineDataGatherer *gatherer, const SkComposeColorFilter *filter)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkGaussianColorFilter *)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkMatrixColorFilter *filter)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkRuntimeColorFilter *filter)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkTableColorFilter *filter)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkWorkingFormatColorFilter *filter)
 
void skgpu::graphite::AddToKey (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkColorFilter *filter)
 
void skgpu::graphite::NotifyImagesInUse (Recorder *recorder, DrawContext *drawContext, const SkColorFilter *filter)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkBlendShader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *recorder, DrawContext *drawContext, const SkBlendShader *shader)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkCTMShader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *recorder, DrawContext *drawContext, const SkCTMShader *shader)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkColorShader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *, DrawContext *, const SkColorShader *)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkColor4Shader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *, DrawContext *, const SkColor4Shader *)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkColorFilterShader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *recorder, DrawContext *drawContext, const SkColorFilterShader *shader)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkCoordClampShader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *recorder, DrawContext *drawContext, const SkCoordClampShader *shader)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkEmptyShader *)
 
static void skgpu::graphite::notify_in_use (Recorder *, DrawContext *, const SkEmptyShader *)
 
static void skgpu::graphite::add_yuv_image_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkImageShader *origShader, sk_sp< const SkImage > imageToDraw, SkSamplingOptions sampling)
 
static skgpu::graphite::ReadSwizzle skgpu::graphite::swizzle_class_to_read_enum (const skgpu::Swizzle &swizzle)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkImageShader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *recorder, DrawContext *, const SkImageShader *shader)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkLocalMatrixShader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *recorder, DrawContext *drawContext, const SkLocalMatrixShader *shader)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkPerlinNoiseShader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *, DrawContext *, const SkPerlinNoiseShader *)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkPictureShader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *, DrawContext *, const SkPictureShader *)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkRuntimeShader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *recorder, DrawContext *drawContext, const SkRuntimeShader *shader)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkTransformShader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *, DrawContext *, const SkTransformShader *)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkTriColorShader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *, DrawContext *, const SkTriColorShader *)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkWorkingColorSpaceShader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *recorder, DrawContext *drawContext, const SkWorkingColorSpaceShader *shader)
 
static SkBitmap skgpu::graphite::create_color_and_offset_bitmap (int numStops, const SkPMColor4f *colors, const float *offsets)
 
static void skgpu::graphite::make_interpolated_to_dst (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const GradientShaderBlocks::GradientData &gradData, const SkGradientShader::Interpolation &interp, SkColorSpace *intermediateCS)
 
static void skgpu::graphite::add_gradient_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkGradientBaseShader *shader, SkPoint point0, SkPoint point1, float radius0, float radius1, float bias, float scale)
 
static void skgpu::graphite::add_gradient_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkConicalGradient *shader)
 
static void skgpu::graphite::add_gradient_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkLinearGradient *shader)
 
static void skgpu::graphite::add_gradient_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkRadialGradient *shader)
 
static void skgpu::graphite::add_gradient_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkSweepGradient *shader)
 
static void skgpu::graphite::add_to_key (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkGradientBaseShader *shader)
 
static void skgpu::graphite::notify_in_use (Recorder *, DrawContext *, const SkGradientBaseShader *)
 
void skgpu::graphite::AddToKey (const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkShader *shader)
 
void skgpu::graphite::NotifyImagesInUse (Recorder *recorder, DrawContext *drawContext, const SkShader *shader)
 

Macro Definition Documentation

◆ M [1/5]

#define M (   type)
Value:
case SkBlenderBase::BlenderType::k##type: \
add_to_key(keyContext, \
builder, \
gatherer, \
static_cast<const Sk##type##Blender*>(blender)); \
return;

◆ M [2/5]

#define M (   type)
Value:
case SkColorFilterBase::Type::k##type: \
add_to_key(keyContext, \
builder, \
gatherer, \
static_cast<const Sk##type##ColorFilter*>(filter)); \
return;

◆ M [3/5]

#define M (   type)
Value:
case SkShaderBase::GradientType::k##type: \
add_gradient_to_key(keyContext, \
builder, \
gatherer, \
static_cast<const Sk##type##Gradient*>(shader)); \
return;

◆ M [4/5]

#define M (   type)
Value:
case SkShaderBase::ShaderType::k##type: \
add_to_key(keyContext, \
builder, \
gatherer, \
static_cast<const Sk##type##Shader*>(shader)); \
return;

◆ M [5/5]

#define M (   type)
Value:
case SkShaderBase::ShaderType::k##type: \
notify_in_use(recorder, \
drawContext, \
static_cast<const Sk##type##Shader*>(shader)); \
return;

◆ VALIDATE_UNIFORMS

#define VALIDATE_UNIFORMS (   gatherer,
  dict,
  codeSnippetID 
)     SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, dict->getUniforms(codeSnippetID));)

Definition at line 79 of file KeyHelpers.cpp.

81 {
82
83//--------------------------------------------------------------------------------------------------
84
85namespace {
86
87void add_solid_uniform_data(const ShaderCodeDictionary* dict,
88 const SkPMColor4f& premulColor,
89 PipelineDataGatherer* gatherer) {
90 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kSolidColorShader)
91 gatherer->write(premulColor);
92}
93
94} // anonymous namespace
95
96void SolidColorShaderBlock::AddBlock(const KeyContext& keyContext,
97 PaintParamsKeyBuilder* builder,
98 PipelineDataGatherer* gatherer,
99 const SkPMColor4f& premulColor) {
100 add_solid_uniform_data(keyContext.dict(), premulColor, gatherer);
101
102 builder->addBlock(BuiltInCodeSnippetID::kSolidColorShader);
103}
104
105//--------------------------------------------------------------------------------------------------
106
107namespace {
108
109void add_rgb_paint_color_uniform_data(const ShaderCodeDictionary* dict,
110 const SkPMColor4f& premulColor,
111 PipelineDataGatherer* gatherer) {
112 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kRGBPaintColor)
113 gatherer->writePaintColor(premulColor);
114}
115
116void add_alpha_only_paint_color_uniform_data(const ShaderCodeDictionary* dict,
117 const SkPMColor4f& premulColor,
118 PipelineDataGatherer* gatherer) {
119 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kAlphaOnlyPaintColor)
120 gatherer->writePaintColor(premulColor);
121}
122
123} // anonymous namespace
124
125void RGBPaintColorBlock::AddBlock(const KeyContext& keyContext,
126 PaintParamsKeyBuilder* builder,
127 PipelineDataGatherer* gatherer) {
128 add_rgb_paint_color_uniform_data(keyContext.dict(), keyContext.paintColor(), gatherer);
129
130 builder->addBlock(BuiltInCodeSnippetID::kRGBPaintColor);
131}
132
133void AlphaOnlyPaintColorBlock::AddBlock(const KeyContext& keyContext,
134 PaintParamsKeyBuilder* builder,
135 PipelineDataGatherer* gatherer) {
136 add_alpha_only_paint_color_uniform_data(keyContext.dict(), keyContext.paintColor(), gatherer);
137
138 builder->addBlock(BuiltInCodeSnippetID::kAlphaOnlyPaintColor);
139}
140
141//--------------------------------------------------------------------------------------------------
142
143namespace {
144
145void add_dst_read_sample_uniform_data(const ShaderCodeDictionary* dict,
146 PipelineDataGatherer* gatherer,
147 sk_sp<TextureProxy> dstTexture,
148 SkIPoint dstOffset) {
149 static const SkTileMode kTileModes[2] = {SkTileMode::kClamp, SkTileMode::kClamp};
150 gatherer->add(SkSamplingOptions(), kTileModes, dstTexture);
151
152 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kDstReadSample)
153
154 SkV4 coords{static_cast<float>(dstOffset.x()),
155 static_cast<float>(dstOffset.y()),
156 dstTexture ? 1.0f / dstTexture->dimensions().width() : 1.0f,
157 dstTexture ? 1.0f / dstTexture->dimensions().height() : 1.0f };
158 gatherer->write(coords);
159}
160
161} // anonymous namespace
162
163void DstReadSampleBlock::AddBlock(const KeyContext& keyContext,
164 PaintParamsKeyBuilder* builder,
165 PipelineDataGatherer* gatherer,
166 sk_sp<TextureProxy> dstTexture,
167 SkIPoint dstOffset) {
168 add_dst_read_sample_uniform_data(keyContext.dict(), gatherer, std::move(dstTexture), dstOffset);
169
170 builder->addBlock(BuiltInCodeSnippetID::kDstReadSample);
171}
172
173//--------------------------------------------------------------------------------------------------
174
175namespace {
176
177void add_gradient_preamble(const GradientShaderBlocks::GradientData& gradData,
178 PipelineDataGatherer* gatherer) {
179 constexpr int kInternalStopLimit = GradientShaderBlocks::GradientData::kNumInternalStorageStops;
180
181 if (gradData.fNumStops <= kInternalStopLimit) {
182 if (gradData.fNumStops <= 4) {
183 // Round up to 4 stops.
184 gatherer->writeArray(SkSpan{gradData.fColors, 4});
185 gatherer->write(gradData.fOffsets[0]);
186 } else if (gradData.fNumStops <= 8) {
187 // Round up to 8 stops.
188 gatherer->writeArray(SkSpan{gradData.fColors, 8});
189 gatherer->writeArray(SkSpan{gradData.fOffsets, 2});
190 } else {
191 // Did kNumInternalStorageStops change?
193 }
194 }
195}
196
197// All the gradients share a common postamble of:
198// numStops - for texture-based gradients
199// tilemode
200// colorSpace
201// doUnPremul
202void add_gradient_postamble(const GradientShaderBlocks::GradientData& gradData,
203 PipelineDataGatherer* gatherer) {
205
206 constexpr int kInternalStopLimit = GradientShaderBlocks::GradientData::kNumInternalStorageStops;
207
208 static_assert(static_cast<int>(ColorSpace::kLab) == 2);
209 static_assert(static_cast<int>(ColorSpace::kOKLab) == 3);
210 static_assert(static_cast<int>(ColorSpace::kOKLabGamutMap) == 4);
211 static_assert(static_cast<int>(ColorSpace::kLCH) == 5);
212 static_assert(static_cast<int>(ColorSpace::kOKLCH) == 6);
213 static_assert(static_cast<int>(ColorSpace::kOKLCHGamutMap) == 7);
214 static_assert(static_cast<int>(ColorSpace::kHSL) == 9);
215 static_assert(static_cast<int>(ColorSpace::kHWB) == 10);
216
217 bool inputPremul = static_cast<bool>(gradData.fInterpolation.fInPremul);
218
219 if (gradData.fNumStops > kInternalStopLimit) {
220 gatherer->write(gradData.fNumStops);
221 }
222
223 gatherer->write(static_cast<int>(gradData.fTM));
224 gatherer->write(static_cast<int>(gradData.fInterpolation.fColorSpace));
225 gatherer->write(static_cast<int>(inputPremul));
226}
227
228void add_linear_gradient_uniform_data(const ShaderCodeDictionary* dict,
229 BuiltInCodeSnippetID codeSnippetID,
230 const GradientShaderBlocks::GradientData& gradData,
231 PipelineDataGatherer* gatherer) {
232 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
233
234 add_gradient_preamble(gradData, gatherer);
235 gatherer->write(gradData.fPoints[0]);
236 gatherer->write(gradData.fPoints[1]);
237 add_gradient_postamble(gradData, gatherer);
238};
239
240void add_radial_gradient_uniform_data(const ShaderCodeDictionary* dict,
241 BuiltInCodeSnippetID codeSnippetID,
242 const GradientShaderBlocks::GradientData& gradData,
243 PipelineDataGatherer* gatherer) {
244 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
245
246 add_gradient_preamble(gradData, gatherer);
247 gatherer->write(gradData.fPoints[0]);
248 gatherer->write(gradData.fRadii[0]);
249 add_gradient_postamble(gradData, gatherer);
250};
251
252void add_sweep_gradient_uniform_data(const ShaderCodeDictionary* dict,
253 BuiltInCodeSnippetID codeSnippetID,
254 const GradientShaderBlocks::GradientData& gradData,
255 PipelineDataGatherer* gatherer) {
256 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
257
258 add_gradient_preamble(gradData, gatherer);
259 gatherer->write(gradData.fPoints[0]);
260 gatherer->write(gradData.fBias);
261 gatherer->write(gradData.fScale);
262 add_gradient_postamble(gradData, gatherer);
263};
264
265void add_conical_gradient_uniform_data(const ShaderCodeDictionary* dict,
266 BuiltInCodeSnippetID codeSnippetID,
267 const GradientShaderBlocks::GradientData& gradData,
268 PipelineDataGatherer* gatherer) {
269 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
270
271 add_gradient_preamble(gradData, gatherer);
272 gatherer->write(gradData.fPoints[0]);
273 gatherer->write(gradData.fPoints[1]);
274 gatherer->write(gradData.fRadii[0]);
275 gatherer->write(gradData.fRadii[1]);
276 add_gradient_postamble(gradData, gatherer);
277};
278
279} // anonymous namespace
280
281GradientShaderBlocks::GradientData::GradientData(SkShaderBase::GradientType type, int numStops)
282 : fType(type)
283 , fPoints{{0.0f, 0.0f}, {0.0f, 0.0f}}
284 , fRadii{0.0f, 0.0f}
285 , fBias(0.0f)
286 , fScale(0.0f)
287 , fTM(SkTileMode::kClamp)
288 , fNumStops(numStops) {
289 sk_bzero(fColors, sizeof(fColors));
290 sk_bzero(fOffsets, sizeof(fOffsets));
291}
292
293GradientShaderBlocks::GradientData::GradientData(SkShaderBase::GradientType type,
294 SkPoint point0, SkPoint point1,
295 float radius0, float radius1,
296 float bias, float scale,
297 SkTileMode tm,
298 int numStops,
299 const SkPMColor4f* colors,
300 const float* offsets,
301 sk_sp<TextureProxy> colorsAndOffsetsProxy,
303 : fType(type)
304 , fBias(bias)
305 , fScale(scale)
306 , fTM(tm)
307 , fNumStops(numStops)
308 , fInterpolation(interp) {
309 SkASSERT(fNumStops >= 1);
310
311 fPoints[0] = point0;
312 fPoints[1] = point1;
313 fRadii[0] = radius0;
314 fRadii[1] = radius1;
315
316 if (fNumStops <= kNumInternalStorageStops) {
317 memcpy(fColors, colors, fNumStops * sizeof(SkColor4f));
318 float* rawOffsets = fOffsets[0].ptr();
319 if (offsets) {
320 memcpy(rawOffsets, offsets, fNumStops * sizeof(float));
321 } else {
322 for (int i = 0; i < fNumStops; ++i) {
323 rawOffsets[i] = SkIntToFloat(i) / (fNumStops-1);
324 }
325 }
326
327 // Extend the colors and offset, if necessary, to fill out the arrays.
328 // The unrolled binary search implementation assumes excess stops match the last real value.
329 for (int i = fNumStops; i < kNumInternalStorageStops; ++i) {
330 fColors[i] = fColors[fNumStops-1];
331 rawOffsets[i] = rawOffsets[fNumStops-1];
332 }
333 } else {
334 fColorsAndOffsetsProxy = std::move(colorsAndOffsetsProxy);
335 SkASSERT(fColorsAndOffsetsProxy);
336 }
337}
338
339void GradientShaderBlocks::AddBlock(const KeyContext& keyContext,
340 PaintParamsKeyBuilder* builder,
341 PipelineDataGatherer* gatherer,
342 const GradientData& gradData) {
343 auto dict = keyContext.dict();
344
345 if (gradData.fNumStops > GradientData::kNumInternalStorageStops && gatherer) {
346 SkASSERT(gradData.fColorsAndOffsetsProxy);
347
349 static constexpr SkTileMode kClampTiling[2] = {SkTileMode::kClamp, SkTileMode::kClamp};
350 gatherer->add(kNearest, kClampTiling, gradData.fColorsAndOffsetsProxy);
351 }
352
353 BuiltInCodeSnippetID codeSnippetID = BuiltInCodeSnippetID::kSolidColorShader;
354 switch (gradData.fType) {
355 case SkShaderBase::GradientType::kLinear:
356 codeSnippetID =
357 gradData.fNumStops <= 4 ? BuiltInCodeSnippetID::kLinearGradientShader4
358 : gradData.fNumStops <= 8 ? BuiltInCodeSnippetID::kLinearGradientShader8
359 : BuiltInCodeSnippetID::kLinearGradientShaderTexture;
360 add_linear_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
361 break;
362 case SkShaderBase::GradientType::kRadial:
363 codeSnippetID =
364 gradData.fNumStops <= 4 ? BuiltInCodeSnippetID::kRadialGradientShader4
365 : gradData.fNumStops <= 8 ? BuiltInCodeSnippetID::kRadialGradientShader8
366 : BuiltInCodeSnippetID::kRadialGradientShaderTexture;
367 add_radial_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
368 break;
369 case SkShaderBase::GradientType::kSweep:
370 codeSnippetID =
371 gradData.fNumStops <= 4 ? BuiltInCodeSnippetID::kSweepGradientShader4
372 : gradData.fNumStops <= 8 ? BuiltInCodeSnippetID::kSweepGradientShader8
373 : BuiltInCodeSnippetID::kSweepGradientShaderTexture;
374 add_sweep_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
375 break;
376 case SkShaderBase::GradientType::kConical:
377 codeSnippetID =
378 gradData.fNumStops <= 4 ? BuiltInCodeSnippetID::kConicalGradientShader4
379 : gradData.fNumStops <= 8 ? BuiltInCodeSnippetID::kConicalGradientShader8
380 : BuiltInCodeSnippetID::kConicalGradientShaderTexture;
381 add_conical_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
382 break;
384 default:
385 SkDEBUGFAIL("Expected a gradient shader, but it wasn't one.");
386 break;
387 }
388
389 builder->addBlock(codeSnippetID);
390}
391
392//--------------------------------------------------------------------------------------------------
393
394namespace {
395
396void add_localmatrixshader_uniform_data(const ShaderCodeDictionary* dict,
397 const SkM44& localMatrix,
398 PipelineDataGatherer* gatherer) {
399 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kLocalMatrixShader)
400
401 SkM44 lmInverse;
402 bool wasInverted = localMatrix.invert(&lmInverse); // TODO: handle failure up stack
403 if (!wasInverted) {
404 lmInverse.setIdentity();
405 }
406
407 gatherer->write(lmInverse);
408}
409
410} // anonymous namespace
411
412void LocalMatrixShaderBlock::BeginBlock(const KeyContext& keyContext,
413 PaintParamsKeyBuilder* builder,
414 PipelineDataGatherer* gatherer,
415 const LMShaderData& lmShaderData) {
416
417 add_localmatrixshader_uniform_data(keyContext.dict(), lmShaderData.fLocalMatrix, gatherer);
418
419 builder->beginBlock(BuiltInCodeSnippetID::kLocalMatrixShader);
420}
421
422//--------------------------------------------------------------------------------------------------
423
424namespace {
425
426static constexpr int kColorSpaceXformFlagAlphaSwizzle = 0x20;
427
428void add_color_space_uniforms(const SkColorSpaceXformSteps& steps,
429 ReadSwizzle readSwizzle,
430 PipelineDataGatherer* gatherer) {
431 // We have 7 source coefficients and 7 destination coefficients. We pass them via a 4x4 matrix;
432 // the first two columns hold the source values, and the second two hold the destination.
433 // (The final value of each 8-element group is ignored.)
434 // In std140, this arrangement is much more efficient than a simple array of scalars.
436
437 int colorXformFlags = SkTo<int>(steps.flags.mask());
438 if (readSwizzle != ReadSwizzle::kRGBA) {
439 // Ensure that we do the gamut step
440 SkColorSpaceXformSteps gamutSteps;
441 gamutSteps.flags.gamut_transform = true;
442 colorXformFlags |= SkTo<int>(gamutSteps.flags.mask());
443 if (readSwizzle != ReadSwizzle::kBGRA) {
444 // TODO: Maybe add a fullMask() method to XformSteps?
445 SkASSERT(colorXformFlags < kColorSpaceXformFlagAlphaSwizzle);
446 colorXformFlags |= kColorSpaceXformFlagAlphaSwizzle;
447 }
448 }
449 gatherer->write(colorXformFlags);
450
451 if (steps.flags.linearize) {
452 gatherer->write(SkTo<int>(skcms_TransferFunction_getType(&steps.srcTF)));
453 coeffs.setCol(0, {steps.srcTF.g, steps.srcTF.a, steps.srcTF.b, steps.srcTF.c});
454 coeffs.setCol(1, {steps.srcTF.d, steps.srcTF.e, steps.srcTF.f, 0.0f});
455 } else {
456 gatherer->write(SkTo<int>(skcms_TFType::skcms_TFType_Invalid));
457 }
458
459 SkMatrix gamutTransform;
460 const float identity[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 };
461 // TODO: it seems odd to copy this into an SkMatrix just to write it to the gatherer
462 // src_to_dst_matrix is column-major, SkMatrix is row-major.
463 const float* m = steps.flags.gamut_transform ? steps.src_to_dst_matrix : identity;
464 if (readSwizzle == ReadSwizzle::kRRR1) {
465 gamutTransform.setAll(m[0] + m[3] + m[6], 0, 0,
466 m[1] + m[4] + m[7], 0, 0,
467 m[2] + m[5] + m[8], 0, 0);
468 } else if (readSwizzle == ReadSwizzle::kBGRA) {
469 gamutTransform.setAll(m[6], m[3], m[0],
470 m[7], m[4], m[1],
471 m[8], m[5], m[2]);
472 } else if (readSwizzle == ReadSwizzle::k000R) {
473 gamutTransform.setAll(0, 0, 0,
474 0, 0, 0,
475 0, 0, 0);
476 } else if (steps.flags.gamut_transform) {
477 gamutTransform.setAll(m[0], m[3], m[6],
478 m[1], m[4], m[7],
479 m[2], m[5], m[8]);
480 }
481 gatherer->writeHalf(gamutTransform);
482
483 if (steps.flags.encode) {
484 gatherer->write(SkTo<int>(skcms_TransferFunction_getType(&steps.dstTFInv)));
485 coeffs.setCol(2, {steps.dstTFInv.g, steps.dstTFInv.a, steps.dstTFInv.b, steps.dstTFInv.c});
486 coeffs.setCol(3, {steps.dstTFInv.d, steps.dstTFInv.e, steps.dstTFInv.f, 0.0f});
487 } else {
488 gatherer->write(SkTo<int>(skcms_TFType::skcms_TFType_Invalid));
489 }
490
491 // Pack alpha swizzle in the unused coeff entries.
492 switch (readSwizzle) {
493 case ReadSwizzle::k000R:
494 coeffs.setRC(3, 1, 1.f);
495 coeffs.setRC(3, 3, 0.f);
496 break;
497 case ReadSwizzle::kRGB1:
498 case ReadSwizzle::kRRR1:
499 coeffs.setRC(3, 1, 0.f);
500 coeffs.setRC(3, 3, 1.f);
501 break;
502 default:
503 coeffs.setRC(3, 1, 0.f);
504 coeffs.setRC(3, 3, 0.f);
505 break;
506 }
507
508 gatherer->writeHalf(coeffs);
509}
510
511void add_image_uniform_data(const ShaderCodeDictionary* dict,
512 const ImageShaderBlock::ImageData& imgData,
513 PipelineDataGatherer* gatherer) {
514 SkASSERT(!imgData.fSampling.useCubic);
515 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kImageShader)
516
517 gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
518 gatherer->write(imgData.fSubset);
519 gatherer->write(SkTo<int>(imgData.fTileModes[0]));
520 gatherer->write(SkTo<int>(imgData.fTileModes[1]));
521 gatherer->write(SkTo<int>(imgData.fSampling.filter));
522
523 add_color_space_uniforms(imgData.fSteps, imgData.fReadSwizzle, gatherer);
524}
525
526void add_cubic_image_uniform_data(const ShaderCodeDictionary* dict,
527 const ImageShaderBlock::ImageData& imgData,
528 PipelineDataGatherer* gatherer) {
529 SkASSERT(imgData.fSampling.useCubic);
530 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kCubicImageShader)
531
532 gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
533 gatherer->write(imgData.fSubset);
534 gatherer->write(SkTo<int>(imgData.fTileModes[0]));
535 gatherer->write(SkTo<int>(imgData.fTileModes[1]));
536 const SkCubicResampler& cubic = imgData.fSampling.cubic;
537 gatherer->writeHalf(SkImageShader::CubicResamplerMatrix(cubic.B, cubic.C));
538
539 add_color_space_uniforms(imgData.fSteps, imgData.fReadSwizzle, gatherer);
540}
541
542void add_hw_image_uniform_data(const ShaderCodeDictionary* dict,
543 const ImageShaderBlock::ImageData& imgData,
544 PipelineDataGatherer* gatherer) {
545 SkASSERT(!imgData.fSampling.useCubic);
546 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kHWImageShader)
547
548 gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
549
550 add_color_space_uniforms(imgData.fSteps, imgData.fReadSwizzle, gatherer);
551}
552
553} // anonymous namespace
554
555ImageShaderBlock::ImageData::ImageData(const SkSamplingOptions& sampling,
556 SkTileMode tileModeX,
557 SkTileMode tileModeY,
558 SkISize imgSize,
559 SkRect subset,
560 ReadSwizzle readSwizzle)
561 : fSampling(sampling)
562 , fTileModes{tileModeX, tileModeY}
563 , fImgSize(imgSize)
564 , fSubset(subset)
565 , fReadSwizzle(readSwizzle) {
566 SkASSERT(fSteps.flags.mask() == 0); // By default, the colorspace should have no effect
567}
568
569static bool can_do_tiling_in_hw(const Caps* caps, const ImageShaderBlock::ImageData& imgData) {
570 if (!caps->clampToBorderSupport() && (imgData.fTileModes[0] == SkTileMode::kDecal ||
571 imgData.fTileModes[1] == SkTileMode::kDecal)) {
572 return false;
573 }
574 return imgData.fSubset.contains(SkRect::Make(imgData.fImgSize));
575}
576
577void ImageShaderBlock::AddBlock(const KeyContext& keyContext,
578 PaintParamsKeyBuilder* builder,
579 PipelineDataGatherer* gatherer,
580 const ImageData& imgData) {
581
582 if (keyContext.recorder() && !imgData.fTextureProxy) {
583 builder->addBlock(BuiltInCodeSnippetID::kError);
584 return;
585 }
586
587 const Caps* caps = keyContext.caps();
588 const bool doTilingInHw = !imgData.fSampling.useCubic && can_do_tiling_in_hw(caps, imgData);
589
590 static constexpr SkTileMode kDefaultTileModes[2] = {SkTileMode::kClamp, SkTileMode::kClamp};
591 gatherer->add(imgData.fSampling,
592 doTilingInHw ? imgData.fTileModes : kDefaultTileModes,
593 imgData.fTextureProxy);
594
595 if (doTilingInHw) {
596 add_hw_image_uniform_data(keyContext.dict(), imgData, gatherer);
597 builder->addBlock(BuiltInCodeSnippetID::kHWImageShader);
598 } else if (imgData.fSampling.useCubic) {
599 add_cubic_image_uniform_data(keyContext.dict(), imgData, gatherer);
600 builder->addBlock(BuiltInCodeSnippetID::kCubicImageShader);
601 } else {
602 add_image_uniform_data(keyContext.dict(), imgData, gatherer);
603 builder->addBlock(BuiltInCodeSnippetID::kImageShader);
604 }
605}
606
607//--------------------------------------------------------------------------------------------------
608
609// makes use of ImageShader functions, above
610namespace {
611
612void add_yuv_image_uniform_data(const ShaderCodeDictionary* dict,
613 const YUVImageShaderBlock::ImageData& imgData,
614 PipelineDataGatherer* gatherer) {
615 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kYUVImageShader)
616
617 gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
618 gatherer->write(SkSize::Make(1.f/imgData.fImgSizeUV.width(), 1.f/imgData.fImgSizeUV.height()));
619 gatherer->write(imgData.fSubset);
620 gatherer->write(imgData.fLinearFilterUVInset);
621 gatherer->write(SkTo<int>(imgData.fTileModes[0]));
622 gatherer->write(SkTo<int>(imgData.fTileModes[1]));
623 gatherer->write(SkTo<int>(imgData.fSampling.filter));
624 gatherer->write(SkTo<int>(imgData.fSamplingUV.filter));
625
626 for (int i = 0; i < 4; ++i) {
627 gatherer->writeHalf(imgData.fChannelSelect[i]);
628 }
629 gatherer->writeHalf(imgData.fYUVtoRGBMatrix);
630 gatherer->write(imgData.fYUVtoRGBTranslate);
631}
632
633void add_cubic_yuv_image_uniform_data(const ShaderCodeDictionary* dict,
634 const YUVImageShaderBlock::ImageData& imgData,
635 PipelineDataGatherer* gatherer) {
636 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kCubicYUVImageShader)
637
638 gatherer->write(SkSize::Make(1.f/imgData.fImgSize.width(), 1.f/imgData.fImgSize.height()));
639 gatherer->write(SkSize::Make(1.f/imgData.fImgSizeUV.width(), 1.f/imgData.fImgSizeUV.height()));
640 gatherer->write(imgData.fSubset);
641 gatherer->write(SkTo<int>(imgData.fTileModes[0]));
642 gatherer->write(SkTo<int>(imgData.fTileModes[1]));
643 const SkCubicResampler& cubic = imgData.fSampling.cubic;
644 gatherer->writeHalf(SkImageShader::CubicResamplerMatrix(cubic.B, cubic.C));
645
646 for (int i = 0; i < 4; ++i) {
647 gatherer->writeHalf(imgData.fChannelSelect[i]);
648 }
649 gatherer->writeHalf(imgData.fYUVtoRGBMatrix);
650 gatherer->write(imgData.fYUVtoRGBTranslate);
651}
652
653} // anonymous namespace
654
655YUVImageShaderBlock::ImageData::ImageData(const SkSamplingOptions& sampling,
656 SkTileMode tileModeX,
657 SkTileMode tileModeY,
658 SkISize imgSize,
659 SkRect subset)
660 : fSampling(sampling)
661 , fSamplingUV(sampling)
662 , fTileModes{tileModeX, tileModeY}
663 , fImgSize(imgSize)
664 , fImgSizeUV(imgSize)
665 , fSubset(subset) {
666}
667
668void YUVImageShaderBlock::AddBlock(const KeyContext& keyContext,
669 PaintParamsKeyBuilder* builder,
670 PipelineDataGatherer* gatherer,
671 const ImageData& imgData) {
672 if (keyContext.recorder() &&
673 (!imgData.fTextureProxies[0] || !imgData.fTextureProxies[1] ||
674 !imgData.fTextureProxies[2] || !imgData.fTextureProxies[3])) {
675 builder->addBlock(BuiltInCodeSnippetID::kError);
676 return;
677 }
678
679 SkTileMode uvTileModes[2] = { imgData.fTileModes[0] == SkTileMode::kDecal
680 ? SkTileMode::kClamp : imgData.fTileModes[0],
681 imgData.fTileModes[1] == SkTileMode::kDecal
682 ? SkTileMode::kClamp : imgData.fTileModes[1] };
683 gatherer->add(imgData.fSampling, imgData.fTileModes, imgData.fTextureProxies[0]);
684 gatherer->add(imgData.fSamplingUV, uvTileModes, imgData.fTextureProxies[1]);
685 gatherer->add(imgData.fSamplingUV, uvTileModes, imgData.fTextureProxies[2]);
686 gatherer->add(imgData.fSampling, imgData.fTileModes, imgData.fTextureProxies[3]);
687
688 if (imgData.fSampling.useCubic) {
689 add_cubic_yuv_image_uniform_data(keyContext.dict(), imgData, gatherer);
690 builder->addBlock(BuiltInCodeSnippetID::kCubicYUVImageShader);
691 } else {
692 add_yuv_image_uniform_data(keyContext.dict(), imgData, gatherer);
693 builder->addBlock(BuiltInCodeSnippetID::kYUVImageShader);
694 }
695}
696
697//--------------------------------------------------------------------------------------------------
698
699namespace {
700
701void add_coordclamp_uniform_data(const ShaderCodeDictionary* dict,
702 const CoordClampShaderBlock::CoordClampData& clampData,
703 PipelineDataGatherer* gatherer) {
704 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kCoordClampShader)
705
706 gatherer->write(clampData.fSubset);
707}
708
709} // anonymous namespace
710
711void CoordClampShaderBlock::BeginBlock(const KeyContext& keyContext,
712 PaintParamsKeyBuilder* builder,
713 PipelineDataGatherer* gatherer,
714 const CoordClampData& clampData) {
715 add_coordclamp_uniform_data(keyContext.dict(), clampData, gatherer);
716
717 builder->beginBlock(BuiltInCodeSnippetID::kCoordClampShader);
718}
719
720//--------------------------------------------------------------------------------------------------
721
722namespace {
723
724void add_dither_uniform_data(const ShaderCodeDictionary* dict,
725 const DitherShaderBlock::DitherData& ditherData,
726 PipelineDataGatherer* gatherer) {
727 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kDitherShader)
728
729 gatherer->writeHalf(ditherData.fRange);
730}
731
732} // anonymous namespace
733
734void DitherShaderBlock::AddBlock(const KeyContext& keyContext,
735 PaintParamsKeyBuilder* builder,
736 PipelineDataGatherer* gatherer,
737 const DitherData& data) {
738 add_dither_uniform_data(keyContext.dict(), data, gatherer);
739
741 static constexpr SkTileMode kRepeatTiling[2] = { SkTileMode::kRepeat, SkTileMode::kRepeat };
742
743 SkASSERT(data.fLUTProxy || !keyContext.recorder());
744 gatherer->add(kNearest, kRepeatTiling, data.fLUTProxy);
745
746 builder->addBlock(BuiltInCodeSnippetID::kDitherShader);
747}
748
749//--------------------------------------------------------------------------------------------------
750
751namespace {
752
753void add_perlin_noise_uniform_data(const ShaderCodeDictionary* dict,
754 const PerlinNoiseShaderBlock::PerlinNoiseData& noiseData,
755 PipelineDataGatherer* gatherer) {
756 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kPerlinNoiseShader)
757
758 gatherer->write(noiseData.fBaseFrequency);
759 gatherer->write(noiseData.fStitchData);
760 gatherer->write(static_cast<int>(noiseData.fType));
761 gatherer->write(noiseData.fNumOctaves);
762 gatherer->write(static_cast<int>(noiseData.stitching()));
763
764 static const SkTileMode kRepeatXTileModes[2] = { SkTileMode::kRepeat, SkTileMode::kClamp };
765 static const SkSamplingOptions kNearestSampling { SkFilterMode::kNearest };
766
767 gatherer->add(kNearestSampling, kRepeatXTileModes, noiseData.fPermutationsProxy);
768 gatherer->add(kNearestSampling, kRepeatXTileModes, noiseData.fNoiseProxy);
769}
770
771} // anonymous namespace
772
773void PerlinNoiseShaderBlock::AddBlock(const KeyContext& keyContext,
774 PaintParamsKeyBuilder* builder,
775 PipelineDataGatherer* gatherer,
776 const PerlinNoiseData& noiseData) {
777 add_perlin_noise_uniform_data(keyContext.dict(), noiseData, gatherer);
778
779 builder->addBlock(BuiltInCodeSnippetID::kPerlinNoiseShader);
780}
781
782//--------------------------------------------------------------------------------------------------
783
784void BlendShaderBlock::BeginBlock(const KeyContext& keyContext,
785 PaintParamsKeyBuilder* builder,
786 PipelineDataGatherer* gatherer) {
787 VALIDATE_UNIFORMS(gatherer, keyContext.dict(), BuiltInCodeSnippetID::kBlendShader)
788
789 builder->beginBlock(BuiltInCodeSnippetID::kBlendShader);
790}
791
792//--------------------------------------------------------------------------------------------------
793
794void BlendModeBlenderBlock::AddBlock(const KeyContext& keyContext,
795 PaintParamsKeyBuilder* builder,
796 PipelineDataGatherer* gatherer,
797 SkBlendMode blendMode) {
798 VALIDATE_UNIFORMS(gatherer, keyContext.dict(), BuiltInCodeSnippetID::kBlendModeBlender)
799 gatherer->write(SkTo<int>(blendMode));
800
801 builder->addBlock(BuiltInCodeSnippetID::kBlendModeBlender);
802}
803
804//--------------------------------------------------------------------------------------------------
805
806void CoeffBlenderBlock::AddBlock(const KeyContext& keyContext,
807 PaintParamsKeyBuilder* builder,
808 PipelineDataGatherer* gatherer,
809 SkSpan<const float> coeffs) {
810 VALIDATE_UNIFORMS(gatherer, keyContext.dict(), BuiltInCodeSnippetID::kCoeffBlender)
811 SkASSERT(coeffs.size() == 4);
812 gatherer->writeHalf(SkV4{coeffs[0], coeffs[1], coeffs[2], coeffs[3]});
813
814 builder->addBlock(BuiltInCodeSnippetID::kCoeffBlender);
815}
816
817//--------------------------------------------------------------------------------------------------
818
819void ClipShaderBlock::BeginBlock(const KeyContext& keyContext,
820 PaintParamsKeyBuilder* builder,
821 PipelineDataGatherer* gatherer) {
822 VALIDATE_UNIFORMS(gatherer, keyContext.dict(), BuiltInCodeSnippetID::kClipShader)
823
824 builder->beginBlock(BuiltInCodeSnippetID::kClipShader);
825}
826
827//--------------------------------------------------------------------------------------------------
828
829void ComposeBlock::BeginBlock(const KeyContext& keyContext,
830 PaintParamsKeyBuilder* builder,
831 PipelineDataGatherer* gatherer) {
832 builder->beginBlock(BuiltInCodeSnippetID::kCompose);
833}
834
835//--------------------------------------------------------------------------------------------------
836
837namespace {
838
839void add_matrix_colorfilter_uniform_data(const ShaderCodeDictionary* dict,
840 const MatrixColorFilterBlock::MatrixColorFilterData& data,
841 PipelineDataGatherer* gatherer) {
842 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kMatrixColorFilter)
843 gatherer->write(data.fMatrix);
844 gatherer->write(data.fTranslate);
845 gatherer->write(static_cast<int>(data.fInHSLA));
846}
847
848} // anonymous namespace
849
850void MatrixColorFilterBlock::AddBlock(const KeyContext& keyContext,
851 PaintParamsKeyBuilder* builder,
852 PipelineDataGatherer* gatherer,
853 const MatrixColorFilterData& matrixCFData) {
854
855 add_matrix_colorfilter_uniform_data(keyContext.dict(), matrixCFData, gatherer);
856
857 builder->addBlock(BuiltInCodeSnippetID::kMatrixColorFilter);
858}
859
860//--------------------------------------------------------------------------------------------------
861
862namespace {
863
864void add_table_colorfilter_uniform_data(const ShaderCodeDictionary* dict,
865 const TableColorFilterBlock::TableColorFilterData& data,
866 PipelineDataGatherer* gatherer) {
867 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kTableColorFilter)
868
869 static const SkTileMode kTileModes[2] = { SkTileMode::kClamp, SkTileMode::kClamp };
870 gatherer->add(SkSamplingOptions(), kTileModes, data.fTextureProxy);
871}
872
873} // anonymous namespace
874
875void TableColorFilterBlock::AddBlock(const KeyContext& keyContext,
876 PaintParamsKeyBuilder* builder,
877 PipelineDataGatherer* gatherer,
878 const TableColorFilterData& data) {
879 SkASSERT(data.fTextureProxy || !keyContext.recorder());
880
881 add_table_colorfilter_uniform_data(keyContext.dict(), data, gatherer);
882
883 builder->addBlock(BuiltInCodeSnippetID::kTableColorFilter);
884}
885
886//--------------------------------------------------------------------------------------------------
887namespace {
888
889void add_color_space_xform_uniform_data(
890 const ShaderCodeDictionary* dict,
891 const ColorSpaceTransformBlock::ColorSpaceTransformData& data,
892 PipelineDataGatherer* gatherer) {
893
894 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kColorSpaceXformColorFilter)
895 add_color_space_uniforms(data.fSteps, ReadSwizzle::kRGBA, gatherer);
896}
897
898} // anonymous namespace
899
900ColorSpaceTransformBlock::ColorSpaceTransformData::ColorSpaceTransformData(const SkColorSpace* src,
901 SkAlphaType srcAT,
902 const SkColorSpace* dst,
903 SkAlphaType dstAT)
904 : fSteps(src, srcAT, dst, dstAT) {}
905
906void ColorSpaceTransformBlock::AddBlock(const KeyContext& keyContext,
907 PaintParamsKeyBuilder* builder,
908 PipelineDataGatherer* gatherer,
909 const ColorSpaceTransformData& data) {
910 add_color_space_xform_uniform_data(keyContext.dict(), data, gatherer);
911 builder->addBlock(BuiltInCodeSnippetID::kColorSpaceXformColorFilter);
912}
913
914//--------------------------------------------------------------------------------------------------
915
916void AddBlendModeColorFilter(const KeyContext& keyContext,
917 PaintParamsKeyBuilder* builder,
918 PipelineDataGatherer* gatherer,
919 SkBlendMode bm,
920 const SkPMColor4f& srcColor) {
921 Blend(keyContext, builder, gatherer,
922 /* addBlendToKey= */ [&] () -> void {
923 // Note, we're playing a bit of a game here. By explicitly adding a
924 // BlendModeBlenderBlock we're always forcing the SkSL to call 'sk_blend'
925 // rather than allowing it to sometimes call 'blend_porter_duff'. This reduces
926 // the number of shader combinations and allows the pre-compilation system to more
927 // easily match the rendering path.
928 BlendModeBlenderBlock::AddBlock(keyContext, builder, gatherer, bm);
929 },
930 /* addSrcToKey= */ [&]() -> void {
931 SolidColorShaderBlock::AddBlock(keyContext, builder, gatherer, srcColor);
932 },
933 /* addDstToKey= */ [&]() -> void {
934 builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
935 });
936}
937
938RuntimeEffectBlock::ShaderData::ShaderData(sk_sp<const SkRuntimeEffect> effect)
939 : fEffect(std::move(effect)) {}
940
941RuntimeEffectBlock::ShaderData::ShaderData(sk_sp<const SkRuntimeEffect> effect,
942 sk_sp<const SkData> uniforms)
943 : fEffect(std::move(effect))
944 , fUniforms(std::move(uniforms)) {}
945
946static bool skdata_matches(const SkData* a, const SkData* b) {
947 // Returns true if both SkData objects hold the same contents, or if they are both null.
948 // (SkData::equals supports passing null, and returns false.)
949 return a ? a->equals(b) : (a == b);
950}
951
952bool RuntimeEffectBlock::ShaderData::operator==(const ShaderData& rhs) const {
953 return fEffect == rhs.fEffect && skdata_matches(fUniforms.get(), rhs.fUniforms.get());
954}
955
956static void gather_runtime_effect_uniforms(const KeyContext& keyContext,
957 const SkRuntimeEffect* effect,
958 SkSpan<const Uniform> graphiteUniforms,
959 const SkData* uniformData,
960 PipelineDataGatherer* gatherer) {
961 if (!uniformData) {
962 return; // precompiling
963 }
964
965 SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, graphiteUniforms);)
966
967 SkSpan<const SkRuntimeEffect::Uniform> rtsUniforms = effect->uniforms();
968
969 if (!rtsUniforms.empty() && uniformData) {
970 // Collect all the other uniforms from the provided SkData.
971 const uint8_t* uniformBase = uniformData->bytes();
972 for (size_t index = 0; index < rtsUniforms.size(); ++index) {
973 const Uniform& uniform = graphiteUniforms[index];
974 // Get a pointer to the offset in our data for this uniform.
975 const uint8_t* uniformPtr = uniformBase + rtsUniforms[index].offset;
976 // Pass the uniform data to the gatherer.
977 gatherer->write(uniform, uniformPtr);
978 }
979 }
980
982 SkColorSpace* dstCS = keyContext.dstColorInfo().colorSpace();
983 if (!dstCS) {
984 dstCS = sk_srgb_linear_singleton(); // turn colorspace conversion into a noop
985 }
986
987 // TODO(b/332565302): If the runtime shader only uses one of these
988 // transforms, we could upload only one set of uniforms.
989 ColorSpaceTransformBlock::ColorSpaceTransformData dstToLinear(dstCS,
993 ColorSpaceTransformBlock::ColorSpaceTransformData linearToDst(sk_srgb_linear_singleton(),
995 dstCS,
997
998 add_color_space_uniforms(dstToLinear.fSteps, ReadSwizzle::kRGBA, gatherer);
999 add_color_space_uniforms(linearToDst.fSteps, ReadSwizzle::kRGBA, gatherer);
1000 }
1001}
1002
1003void RuntimeEffectBlock::BeginBlock(const KeyContext& keyContext,
1004 PaintParamsKeyBuilder* builder,
1005 PipelineDataGatherer* gatherer,
1006 const ShaderData& shaderData) {
1007 ShaderCodeDictionary* dict = keyContext.dict();
1008 int codeSnippetID = dict->findOrCreateRuntimeEffectSnippet(shaderData.fEffect.get());
1009
1011 keyContext.rtEffectDict()->set(codeSnippetID, shaderData.fEffect);
1012 }
1013
1014 const ShaderSnippet* entry = dict->getEntry(codeSnippetID);
1015 SkASSERT(entry);
1016
1018 shaderData.fEffect.get(),
1019 entry->fUniforms,
1020 shaderData.fUniforms.get(),
1021 gatherer);
1022
1023 builder->beginBlock(codeSnippetID);
1024}
1025
1026// ==================================================================
1027
1028namespace {
1029
1030void add_to_key(const KeyContext& keyContext,
1031 PaintParamsKeyBuilder* builder,
1032 PipelineDataGatherer* gatherer,
1033 const SkBlendModeBlender* blender) {
1034 SkASSERT(blender);
1035
1036 AddModeBlend(keyContext, builder, gatherer, blender->mode());
1037}
1038
1039// Be sure to keep this function in sync w/ its correlate in FactoryFunctions.cpp
1040void add_children_to_key(const KeyContext& keyContext,
1041 PaintParamsKeyBuilder* builder,
1042 PipelineDataGatherer* gatherer,
1045 SkASSERT(children.size() == childInfo.size());
1046
1048
1049 KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
1050
1051 for (size_t index = 0; index < children.size(); ++index) {
1052 const SkRuntimeEffect::ChildPtr& child = children[index];
1053 std::optional<ChildType> type = child.type();
1054 if (type == ChildType::kShader) {
1055 AddToKey(childContext, builder, gatherer, child.shader());
1056 } else if (type == ChildType::kColorFilter) {
1057 AddToKey(childContext, builder, gatherer, child.colorFilter());
1058 } else if (type == ChildType::kBlender) {
1059 AddToKey(childContext, builder, gatherer, child.blender());
1060 } else {
1061 // We don't have a child effect. Substitute in a no-op effect.
1062 switch (childInfo[index].type) {
1063 case ChildType::kShader:
1064 // A missing shader returns transparent black
1065 SolidColorShaderBlock::AddBlock(childContext, builder, gatherer,
1067 break;
1068
1069 case ChildType::kColorFilter:
1070 // A "passthrough" color filter returns the input color as-is.
1071 builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
1072 break;
1073
1074 case ChildType::kBlender:
1075 // A "passthrough" blender performs `blend_src_over(src, dest)`.
1076 AddKnownModeBlend(childContext, builder, gatherer, SkBlendMode::kSrcOver);
1077 break;
1078 }
1079 }
1080 }
1081}
1082
1083void add_to_key(const KeyContext& keyContext,
1084 PaintParamsKeyBuilder* builder,
1085 PipelineDataGatherer* gatherer,
1086 const SkRuntimeBlender* blender) {
1087 SkASSERT(blender);
1088 sk_sp<SkRuntimeEffect> effect = blender->effect();
1089 SkASSERT(effect);
1091 effect->uniforms(),
1092 blender->uniforms(),
1093 keyContext.dstColorInfo().colorSpace());
1094 SkASSERT(uniforms);
1095
1096 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
1097 { effect, std::move(uniforms) });
1098
1099 add_children_to_key(keyContext, builder, gatherer,
1100 blender->children(), effect->children());
1101
1102 builder->endBlock();
1103}
1104
1105void notify_in_use(Recorder* recorder,
1106 DrawContext* drawContext,
1108 for (const auto& child : children) {
1109 if (child.type().has_value()) {
1110 switch (*child.type()) {
1111 case SkRuntimeEffect::ChildType::kShader:
1112 NotifyImagesInUse(recorder, drawContext, child.shader());
1113 break;
1114 case SkRuntimeEffect::ChildType::kColorFilter:
1115 NotifyImagesInUse(recorder, drawContext, child.colorFilter());
1116 break;
1117 case SkRuntimeEffect::ChildType::kBlender:
1118 NotifyImagesInUse(recorder, drawContext, child.blender());
1119 break;
1120 }
1121 } // else a null child is a no-op, so cannot sample an image
1122 }
1123}
1124
1125} // anonymous namespace
1126
1127void AddToKey(const KeyContext& keyContext,
1128 PaintParamsKeyBuilder* builder,
1129 PipelineDataGatherer* gatherer,
1130 const SkBlender* blender) {
1131 if (!blender) {
1132 return;
1133 }
1134 switch (as_BB(blender)->type()) {
1135#define M(type) \
1136 case SkBlenderBase::BlenderType::k##type: \
1137 add_to_key(keyContext, \
1138 builder, \
1139 gatherer, \
1140 static_cast<const Sk##type##Blender*>(blender)); \
1141 return;
1143#undef M
1144 }
1146}
1147
1148void NotifyImagesInUse(Recorder* recorder, DrawContext* drawContext, const SkBlender* blender) {
1149 if (!blender) {
1150 return;
1151 }
1152 if (as_BB(blender)->type() == SkBlenderBase::BlenderType::kRuntime) {
1153 const auto* rbb = static_cast<const SkRuntimeBlender*>(blender);
1154 notify_in_use(recorder, drawContext, rbb->children());
1155 } // else blend mode doesn't reference images
1156}
1157
1158//--------------------------------------------------------------------------------------------------
1159//--------------------------------------------------------------------------------------------------
1160static SkPMColor4f map_color(const SkColor4f& c, SkColorSpace* src, SkColorSpace* dst) {
1161 SkPMColor4f color = {c.fR, c.fG, c.fB, c.fA};
1163 return color;
1164}
1165static void add_to_key(const KeyContext& keyContext,
1166 PaintParamsKeyBuilder* builder,
1167 PipelineDataGatherer* gatherer,
1168 const SkBlendModeColorFilter* filter) {
1169 SkASSERT(filter);
1170
1172 keyContext.dstColorInfo().colorSpace());
1173
1174 AddBlendModeColorFilter(keyContext, builder, gatherer, filter->mode(), color);
1175}
1176
1177static void add_to_key(const KeyContext& keyContext,
1178 PaintParamsKeyBuilder* builder,
1179 PipelineDataGatherer* gatherer,
1180 const SkColorSpaceXformColorFilter* filter) {
1181 SkASSERT(filter);
1182
1183 constexpr SkAlphaType kAlphaType = kPremul_SkAlphaType;
1184 ColorSpaceTransformBlock::ColorSpaceTransformData csData(filter->src().get(), kAlphaType,
1185 filter->dst().get(), kAlphaType);
1186 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, csData);
1187}
1188
1189static void add_to_key(const KeyContext& keyContext,
1190 PaintParamsKeyBuilder* keyBuilder,
1191 PipelineDataGatherer* gatherer,
1192 const SkComposeColorFilter* filter) {
1193 SkASSERT(filter);
1194
1195 Compose(keyContext, keyBuilder, gatherer,
1196 /* addInnerToKey= */ [&]() -> void {
1197 AddToKey(keyContext, keyBuilder, gatherer, filter->inner().get());
1198 },
1199 /* addOuterToKey= */ [&]() -> void {
1200 AddToKey(keyContext, keyBuilder, gatherer, filter->outer().get());
1201 });
1202}
1203
1204static void add_to_key(const KeyContext& keyContext,
1205 PaintParamsKeyBuilder* builder,
1206 PipelineDataGatherer* gatherer,
1207 const SkGaussianColorFilter*) {
1208 builder->addBlock(BuiltInCodeSnippetID::kGaussianColorFilter);
1209}
1210
1211static void add_to_key(const KeyContext& keyContext,
1212 PaintParamsKeyBuilder* builder,
1213 PipelineDataGatherer* gatherer,
1214 const SkMatrixColorFilter* filter) {
1215 SkASSERT(filter);
1216
1217 bool inHSLA = filter->domain() == SkMatrixColorFilter::Domain::kHSLA;
1218 MatrixColorFilterBlock::MatrixColorFilterData matrixCFData(filter->matrix(), inHSLA);
1219
1220 MatrixColorFilterBlock::AddBlock(keyContext, builder, gatherer, matrixCFData);
1221}
1222
1223static void add_to_key(const KeyContext& keyContext,
1224 PaintParamsKeyBuilder* builder,
1225 PipelineDataGatherer* gatherer,
1226 const SkRuntimeColorFilter* filter) {
1227 SkASSERT(filter);
1228
1229 sk_sp<SkRuntimeEffect> effect = filter->effect();
1231 effect->uniforms(), filter->uniforms(), keyContext.dstColorInfo().colorSpace());
1232 SkASSERT(uniforms);
1233
1234 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, {effect, std::move(uniforms)});
1235
1236 add_children_to_key(keyContext, builder, gatherer,
1237 filter->children(), effect->children());
1238
1239 builder->endBlock();
1240}
1241
1242static void add_to_key(const KeyContext& keyContext,
1243 PaintParamsKeyBuilder* builder,
1244 PipelineDataGatherer* gatherer,
1245 const SkTableColorFilter* filter) {
1246 SkASSERT(filter);
1247
1248 sk_sp<TextureProxy> proxy = RecorderPriv::CreateCachedProxy(keyContext.recorder(),
1249 filter->bitmap());
1250 if (!proxy) {
1251 SKGPU_LOG_W("Couldn't create TableColorFilter's table");
1252
1253 // Return the input color as-is.
1254 builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
1255 return;
1256 }
1257
1258 TableColorFilterBlock::TableColorFilterData data(std::move(proxy));
1259
1260 TableColorFilterBlock::AddBlock(keyContext, builder, gatherer, data);
1261}
1262
1263static void add_to_key(const KeyContext& keyContext,
1264 PaintParamsKeyBuilder* builder,
1265 PipelineDataGatherer* gatherer,
1266 const SkWorkingFormatColorFilter* filter) {
1267 SkASSERT(filter);
1268
1269 const SkColorInfo& dstInfo = keyContext.dstColorInfo();
1270 const SkAlphaType dstAT = dstInfo.alphaType();
1271 sk_sp<SkColorSpace> dstCS = dstInfo.refColorSpace();
1272 if (!dstCS) {
1273 dstCS = SkColorSpace::MakeSRGB();
1274 }
1275
1276 SkAlphaType workingAT;
1277 sk_sp<SkColorSpace> workingCS = filter->workingFormat(dstCS, &workingAT);
1278 SkColorInfo workingInfo(dstInfo.colorType(), workingAT, workingCS);
1279 KeyContextWithColorInfo workingContext(keyContext, workingInfo);
1280
1281 // Use two nested compose blocks to chain (dst->working), child, and (working->dst) together
1282 // while appearing as one block to the parent node.
1283 Compose(keyContext, builder, gatherer,
1284 /* addInnerToKey= */ [&]() -> void {
1285 // Inner compose
1286 Compose(keyContext, builder, gatherer,
1287 /* addInnerToKey= */ [&]() -> void {
1288 // Innermost (inner of inner compose)
1289 ColorSpaceTransformBlock::ColorSpaceTransformData data1(
1290 dstCS.get(), dstAT, workingCS.get(), workingAT);
1291 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer,
1292 data1);
1293 },
1294 /* addOuterToKey= */ [&]() -> void {
1295 // Middle (outer of inner compose)
1296 AddToKey(workingContext, builder, gatherer, filter->child().get());
1297 });
1298 },
1299 /* addOuterToKey= */ [&]() -> void {
1300 // Outermost (outer of outer compose)
1301 ColorSpaceTransformBlock::ColorSpaceTransformData data2(
1302 workingCS.get(), workingAT, dstCS.get(), dstAT);
1303 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data2);
1304 });
1305}
1306
1307void AddToKey(const KeyContext& keyContext,
1308 PaintParamsKeyBuilder* builder,
1309 PipelineDataGatherer* gatherer,
1310 const SkColorFilter* filter) {
1311 if (!filter) {
1312 return;
1313 }
1314 switch (as_CFB(filter)->type()) {
1316 // Return the input color as-is.
1317 builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
1318 return;
1319#define M(type) \
1320 case SkColorFilterBase::Type::k##type: \
1321 add_to_key(keyContext, \
1322 builder, \
1323 gatherer, \
1324 static_cast<const Sk##type##ColorFilter*>(filter)); \
1325 return;
1327#undef M
1328 }
1330}
1331
1332void NotifyImagesInUse(Recorder* recorder, DrawContext* drawContext, const SkColorFilter* filter) {
1333 if (!filter) {
1334 return;
1335 }
1336 if (as_CFB(filter)->type() == SkColorFilterBase::Type::kCompose) {
1337 // Recurse to two children
1338 const auto* cf = static_cast<const SkComposeColorFilter*>(filter);
1339 NotifyImagesInUse(recorder, drawContext, cf->inner().get());
1340 NotifyImagesInUse(recorder, drawContext, cf->outer().get());
1341 } else if (as_CFB(filter)->type() == SkColorFilterBase::Type::kWorkingFormat) {
1342 // Recurse to one child
1343 const auto* wfcf = static_cast<const SkWorkingFormatColorFilter*>(filter);
1344 NotifyImagesInUse(recorder, drawContext, wfcf->child().get());
1345 } else if (as_CFB(filter)->type() == SkColorFilterBase::Type::kRuntime) {
1346 // Recurse to all children
1347 const auto* rcf = static_cast<const SkRuntimeColorFilter*>(filter);
1348 notify_in_use(recorder, drawContext, rcf->children());
1349 } // else other color filters do not rely on SkImages
1350}
1351
1352// ==================================================================
1353
1354static void add_to_key(const KeyContext& keyContext,
1355 PaintParamsKeyBuilder* builder,
1356 PipelineDataGatherer* gatherer,
1357 const SkBlendShader* shader) {
1358 SkASSERT(shader);
1359
1360 Blend(keyContext, builder, gatherer,
1361 /* addBlendToKey= */ [&] () -> void {
1362 AddModeBlend(keyContext, builder, gatherer, shader->mode());
1363 },
1364 /* addSrcToKey= */ [&]() -> void {
1365 AddToKey(keyContext, builder, gatherer, shader->src().get());
1366 },
1367 /* addDstToKey= */ [&]() -> void {
1368 AddToKey(keyContext, builder, gatherer, shader->dst().get());
1369 });
1370}
1371static void notify_in_use(Recorder* recorder,
1372 DrawContext* drawContext,
1373 const SkBlendShader* shader) {
1374 // SkBlendShader uses a fixed blend mode, so there's no blender to recurse through
1375 NotifyImagesInUse(recorder, drawContext, shader->src().get());
1376 NotifyImagesInUse(recorder, drawContext, shader->dst().get());
1377}
1378
1379static void add_to_key(const KeyContext& keyContext,
1380 PaintParamsKeyBuilder* builder,
1381 PipelineDataGatherer* gatherer,
1382 const SkCTMShader* shader) {
1383 // CTM shaders are always given device coordinates, so we don't have to modify the CTM itself
1384 // with keyContext's local transform.
1385 LocalMatrixShaderBlock::LMShaderData lmShaderData(shader->ctm());
1386
1387 KeyContextWithLocalMatrix newContext(keyContext, shader->ctm());
1388
1389 LocalMatrixShaderBlock::BeginBlock(newContext, builder, gatherer, lmShaderData);
1390
1391 AddToKey(newContext, builder, gatherer, shader->proxyShader().get());
1392
1393 builder->endBlock();
1394}
1395static void notify_in_use(Recorder* recorder, DrawContext* drawContext, const SkCTMShader* shader) {
1396 NotifyImagesInUse(recorder, drawContext, shader->proxyShader().get());
1397}
1398
1399static void add_to_key(const KeyContext& keyContext,
1400 PaintParamsKeyBuilder* builder,
1401 PipelineDataGatherer* gatherer,
1402 const SkColorShader* shader) {
1403 SkASSERT(shader);
1404
1405 SolidColorShaderBlock::AddBlock(keyContext, builder, gatherer,
1406 SkColor4f::FromColor(shader->color()).premul());
1407}
1408static void notify_in_use(Recorder*, DrawContext*, const SkColorShader*) {
1409 // No-op
1410}
1411
1412static void add_to_key(const KeyContext& keyContext,
1413 PaintParamsKeyBuilder* builder,
1414 PipelineDataGatherer* gatherer,
1415 const SkColor4Shader* shader) {
1416 SkASSERT(shader);
1417
1418 SkPMColor4f color = map_color(shader->color(), shader->colorSpace().get(),
1419 keyContext.dstColorInfo().colorSpace());
1420
1421 SolidColorShaderBlock::AddBlock(keyContext, builder, gatherer, color);
1422}
1423static void notify_in_use(Recorder*, DrawContext*, const SkColor4Shader*) {
1424 // No-op
1425}
1426
1427static void add_to_key(const KeyContext& keyContext,
1428 PaintParamsKeyBuilder* builder,
1429 PipelineDataGatherer* gatherer,
1430 const SkColorFilterShader* shader) {
1431 SkASSERT(shader);
1432
1433 Compose(keyContext, builder, gatherer,
1434 /* addInnerToKey= */ [&]() -> void {
1435 AddToKey(keyContext, builder, gatherer, shader->shader().get());
1436 },
1437 /* addOuterToKey= */ [&]() -> void {
1438 AddToKey(keyContext, builder, gatherer, shader->filter().get());
1439 });
1440}
1441static void notify_in_use(Recorder* recorder,
1442 DrawContext* drawContext,
1443 const SkColorFilterShader* shader) {
1444 NotifyImagesInUse(recorder, drawContext, shader->shader().get());
1445 NotifyImagesInUse(recorder, drawContext, shader->filter().get());
1446}
1447
1448static void add_to_key(const KeyContext& keyContext,
1449 PaintParamsKeyBuilder* builder,
1450 PipelineDataGatherer* gatherer,
1451 const SkCoordClampShader* shader) {
1452 SkASSERT(shader);
1453
1454 CoordClampShaderBlock::CoordClampData data(shader->subset());
1455
1456 CoordClampShaderBlock::BeginBlock(keyContext, builder, gatherer, data);
1457 AddToKey(keyContext, builder, gatherer, shader->shader().get());
1458 builder->endBlock();
1459}
1460static void notify_in_use(Recorder* recorder,
1461 DrawContext* drawContext,
1462 const SkCoordClampShader* shader) {
1463 NotifyImagesInUse(recorder, drawContext, shader->shader().get());
1464}
1465
1466static void add_to_key(const KeyContext& keyContext,
1467 PaintParamsKeyBuilder* builder,
1468 PipelineDataGatherer* gatherer,
1469 const SkEmptyShader*) {
1470 builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
1471}
1472static void notify_in_use(Recorder*, DrawContext*, const SkEmptyShader*) {
1473 // No-op
1474}
1475
1476static void add_yuv_image_to_key(const KeyContext& keyContext,
1477 PaintParamsKeyBuilder* builder,
1478 PipelineDataGatherer* gatherer,
1479 const SkImageShader* origShader,
1480 sk_sp<const SkImage> imageToDraw,
1481 SkSamplingOptions sampling) {
1482 SkASSERT(!imageToDraw->isAlphaOnly());
1483
1484 const Image_YUVA* yuvaImage = static_cast<const Image_YUVA*>(imageToDraw.get());
1485 const SkYUVAInfo& yuvaInfo = yuvaImage->yuvaInfo();
1486 // We would want to add a translation to the local matrix to handle other sitings.
1489 YUVImageShaderBlock::ImageData imgData(sampling,
1490 origShader->tileModeX(),
1491 origShader->tileModeY(),
1492 imageToDraw->dimensions(),
1493 origShader->subset());
1494 for (int locIndex = 0; locIndex < SkYUVAInfo::kYUVAChannelCount; ++locIndex) {
1495 const TextureProxyView& view = yuvaImage->proxyView(locIndex);
1496 if (view) {
1497 imgData.fTextureProxies[locIndex] = view.refProxy();
1498 // The view's swizzle has the data channel for the YUVA location in all slots, so read
1499 // the 0th slot to determine fChannelSelect
1500 switch(view.swizzle()[0]) {
1501 case 'r': imgData.fChannelSelect[locIndex] = {1.f, 0.f, 0.f, 0.f}; break;
1502 case 'g': imgData.fChannelSelect[locIndex] = {0.f, 1.f, 0.f, 0.f}; break;
1503 case 'b': imgData.fChannelSelect[locIndex] = {0.f, 0.f, 1.f, 0.f}; break;
1504 case 'a': imgData.fChannelSelect[locIndex] = {0.f, 0.f, 0.f, 1.f}; break;
1505 default:
1506 imgData.fChannelSelect[locIndex] = {0.f, 0.f, 0.f, 0.f};
1507 SkDEBUGFAILF("Unexpected swizzle for YUVA data: %c", view.swizzle()[0]);
1508 break;
1509 }
1510 } else {
1511 // Only the A proxy view should be null, in which case we bind the Y proxy view to
1512 // pass validation and send all 1s for the channel selection to signal opaque alpha.
1513 SkASSERT(locIndex == 3);
1514 imgData.fTextureProxies[locIndex] = yuvaImage->proxyView(SkYUVAInfo::kY).refProxy();
1515 imgData.fChannelSelect[locIndex] = {1.f, 1.f, 1.f, 1.f};
1516 }
1517 }
1518
1519 auto [ssx, ssy] = yuvaImage->uvSubsampleFactors();
1520 if (ssx > 1 || ssy > 1) {
1521 // We need to adjust the image size we use for sampling to reflect the actual image size of
1522 // the UV planes. However, since our coordinates are in Y's texel space we need to scale
1523 // accordingly.
1524 const TextureProxyView& view = yuvaImage->proxyView(SkYUVAInfo::kU);
1525 imgData.fImgSizeUV = {view.dimensions().width()*ssx, view.dimensions().height()*ssy};
1526 // This promotion of nearest to linear filtering for UV planes exists to mimic
1527 // libjpeg[-turbo]'s do_fancy_upsampling option. We will filter the subsampled plane,
1528 // however we want to filter at a fixed point for each logical image pixel to simulate
1529 // nearest neighbor. In the shader we detect that the UV filtermode doesn't match the Y
1530 // filtermode, and snap to Y pixel centers.
1531 if (imgData.fSampling.filter == SkFilterMode::kNearest) {
1532 imgData.fSamplingUV = SkSamplingOptions(SkFilterMode::kLinear,
1533 imgData.fSampling.mipmap);
1534 // Consider a logical image pixel at the edge of the subset. When computing the logical
1535 // pixel color value we should use a blend of two values from the subsampled plane.
1536 // Depending on where the subset edge falls in actual subsampled plane, one of those
1537 // values may come from outside the subset. Hence, we use this custom inset which
1538 // applies the wrap mode to the subset but allows linear filtering to read pixels from
1539 // that are just outside the subset. We only want to apply this offset in non-decal
1540 // modes, or when the image view size is not a multiple of the UV subsampling factor.
1541 if (imgData.fTileModes[0] != SkTileMode::kDecal ||
1542 view.dimensions().width()*ssx > yuvaInfo.width()) {
1543 imgData.fLinearFilterUVInset.fX = 1.f/(2*ssx);
1544 }
1545 if (imgData.fTileModes[1] != SkTileMode::kDecal ||
1546 view.dimensions().height()*ssy > yuvaInfo.height()) {
1547 imgData.fLinearFilterUVInset.fY = 1.f/(2*ssy);
1548 }
1549 }
1550 // Need to scale this just like we scale the image size
1551 imgData.fLinearFilterUVInset = {imgData.fLinearFilterUVInset.fX*ssx,
1552 imgData.fLinearFilterUVInset.fY*ssy};
1553 }
1554
1555 float yuvM[20];
1556 SkColorMatrix_YUV2RGB(yuvaInfo.yuvColorSpace(), yuvM);
1557 // We drop the fourth column entirely since the transformation
1558 // should not depend on alpha. The fifth column is sent as a separate
1559 // vector. The fourth row is also dropped entirely because alpha should
1560 // never be modified.
1561 SkASSERT(yuvM[3] == 0 && yuvM[8] == 0 && yuvM[13] == 0 && yuvM[18] == 1);
1562 SkASSERT(yuvM[15] == 0 && yuvM[16] == 0 && yuvM[17] == 0 && yuvM[19] == 0);
1563 imgData.fYUVtoRGBMatrix.setAll(
1564 yuvM[ 0], yuvM[ 1], yuvM[ 2],
1565 yuvM[ 5], yuvM[ 6], yuvM[ 7],
1566 yuvM[10], yuvM[11], yuvM[12]
1567 );
1568 imgData.fYUVtoRGBTranslate = {yuvM[4], yuvM[9], yuvM[14]};
1569
1570 // The YUV formats can encode their own origin including reflection and rotation,
1571 // so we need to wrap our block in an additional local matrix transform.
1572 SkMatrix originMatrix = yuvaInfo.originMatrix();
1573 LocalMatrixShaderBlock::LMShaderData lmShaderData(originMatrix);
1574
1575 KeyContextWithLocalMatrix newContext(keyContext, originMatrix);
1576
1578 SkASSERT(steps.flags.mask() == 0); // By default, the colorspace should have no effect
1579 if (!origShader->isRaw()) {
1580 steps = SkColorSpaceXformSteps(imageToDraw->colorSpace(),
1581 imageToDraw->alphaType(),
1582 keyContext.dstColorInfo().colorSpace(),
1583 keyContext.dstColorInfo().alphaType());
1584 }
1585 ColorSpaceTransformBlock::ColorSpaceTransformData data(steps);
1586
1587 Compose(keyContext, builder, gatherer,
1588 /* addInnerToKey= */ [&]() -> void {
1589 LocalMatrixShaderBlock::BeginBlock(newContext, builder, gatherer, lmShaderData);
1590 YUVImageShaderBlock::AddBlock(newContext, builder, gatherer, imgData);
1591 builder->endBlock();
1592 },
1593 /* addOuterToKey= */ [&]() -> void {
1594 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data);
1595 });
1596}
1597
1599 if (swizzle == skgpu::Swizzle::RGBA()) {
1601 } else if (swizzle == skgpu::Swizzle::RGB1()) {
1603 } else if (swizzle == skgpu::Swizzle("rrr1")) {
1605 } else if (swizzle == skgpu::Swizzle::BGRA()) {
1607 } else if (swizzle == skgpu::Swizzle("000r")) {
1609 } else {
1610 SKGPU_LOG_W("%s is an unsupported read swizzle. Defaulting to RGBA.\n",
1611 swizzle.asString().data());
1613 }
1614}
1615
1616static void add_to_key(const KeyContext& keyContext,
1617 PaintParamsKeyBuilder* builder,
1618 PipelineDataGatherer* gatherer,
1619 const SkImageShader* shader) {
1620 SkASSERT(shader);
1621
1622 auto [ imageToDraw, newSampling ] = GetGraphiteBacked(keyContext.recorder(),
1623 shader->image().get(),
1624 shader->sampling());
1625 if (!imageToDraw) {
1626 SKGPU_LOG_W("Couldn't convert ImageShader's image to a Graphite-backed image");
1627 builder->addBlock(BuiltInCodeSnippetID::kError);
1628 return;
1629 }
1630 if (as_IB(imageToDraw)->isYUVA()) {
1631 return add_yuv_image_to_key(keyContext,
1632 builder,
1633 gatherer,
1634 shader,
1635 std::move(imageToDraw),
1636 newSampling);
1637 }
1638
1639 auto view = AsView(imageToDraw.get());
1640 SkASSERT(newSampling.mipmap == SkMipmapMode::kNone || view.mipmapped() == Mipmapped::kYes);
1641
1642 ImageShaderBlock::ImageData imgData(shader->sampling(),
1643 shader->tileModeX(),
1644 shader->tileModeY(),
1645 view.proxy()->dimensions(),
1646 shader->subset(),
1647 ReadSwizzle::kRGBA);
1648 imgData.fSampling = newSampling;
1649 imgData.fTextureProxy = view.refProxy();
1650 skgpu::Swizzle readSwizzle = view.swizzle();
1651 // If the color type is alpha-only, propagate the alpha value to the other channels.
1652 if (imageToDraw->isAlphaOnly()) {
1653 readSwizzle = skgpu::Swizzle::Concat(readSwizzle, skgpu::Swizzle("000a"));
1654 }
1655 imgData.fReadSwizzle = swizzle_class_to_read_enum(readSwizzle);
1656
1657 if (!shader->isRaw()) {
1658 imgData.fSteps = SkColorSpaceXformSteps(imageToDraw->colorSpace(),
1659 imageToDraw->alphaType(),
1660 keyContext.dstColorInfo().colorSpace(),
1661 keyContext.dstColorInfo().alphaType());
1662
1663 if (imageToDraw->isAlphaOnly() && keyContext.scope() != KeyContext::Scope::kRuntimeEffect) {
1664 Blend(keyContext, builder, gatherer,
1665 /* addBlendToKey= */ [&] () -> void {
1666 AddKnownModeBlend(keyContext, builder, gatherer, SkBlendMode::kDstIn);
1667 },
1668 /* addSrcToKey= */ [&] () -> void {
1669 ImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
1670 },
1671 /* addDstToKey= */ [&]() -> void {
1672 RGBPaintColorBlock::AddBlock(keyContext, builder, gatherer);
1673 });
1674 return;
1675 }
1676 }
1677
1678 ImageShaderBlock::AddBlock(keyContext, builder, gatherer, imgData);
1679}
1680static void notify_in_use(Recorder* recorder,
1681 DrawContext*,
1682 const SkImageShader* shader) {
1683 auto image = as_IB(shader->image());
1684 if (!image->isGraphiteBacked()) {
1685 // If it's not graphite-backed, there's no pending graphite work.
1686 return;
1687 }
1688
1689 // TODO(b/323887207): Once scratch devices are linked to special images and their use needs to
1690 // be linked to specific draw contexts, that will be passed in here.
1691 static_cast<Image_Base*>(image)->notifyInUse(recorder);
1692}
1693
1694static void add_to_key(const KeyContext& keyContext,
1695 PaintParamsKeyBuilder* builder,
1696 PipelineDataGatherer* gatherer,
1697 const SkLocalMatrixShader* shader) {
1698 SkASSERT(shader);
1699 auto wrappedShader = shader->wrappedShader().get();
1700
1701 // Fold the texture's origin flip into the local matrix so that the image shader doesn't need
1702 // additional state
1704 if (as_SB(wrappedShader)->type() == SkShaderBase::ShaderType::kImage) {
1705 auto imgShader = static_cast<const SkImageShader*>(wrappedShader);
1706 // If the image is not graphite backed then we can assume the origin will be TopLeft as we
1707 // require that in the ImageProvider utility. Also Graphite YUV images are assumed to be
1708 // TopLeft origin.
1709 // TODO (b/336788317): Fold YUVAImage's origin into this matrix as well.
1710 auto imgBase = as_IB(imgShader->image());
1711 if (imgBase->isGraphiteBacked() && !imgBase->isYUVA()) {
1712 auto imgGraphite = static_cast<Image*>(imgBase);
1713 SkASSERT(imgGraphite);
1714 const auto& view = imgGraphite->textureProxyView();
1715 if (view.origin() == Origin::kBottomLeft) {
1716 matrix.setScaleY(-1);
1717 matrix.setTranslateY(view.height());
1718 }
1719 }
1720 }
1721
1722 matrix.postConcat(shader->localMatrix());
1723 LocalMatrixShaderBlock::LMShaderData lmShaderData(matrix);
1724
1725 KeyContextWithLocalMatrix newContext(keyContext, matrix);
1726
1727 LocalMatrixShaderBlock::BeginBlock(newContext, builder, gatherer, lmShaderData);
1728
1729 AddToKey(newContext, builder, gatherer, wrappedShader);
1730
1731 builder->endBlock();
1732}
1733
1734static void notify_in_use(Recorder* recorder,
1735 DrawContext* drawContext,
1736 const SkLocalMatrixShader* shader) {
1737 NotifyImagesInUse(recorder, drawContext, shader->wrappedShader().get());
1738}
1739
1740// If either of these change then the corresponding change must also be made in the SkSL
1741// perlin_noise_shader function.
1743 (int)PerlinNoiseShaderBlock::Type::kFractalNoise);
1745 (int)PerlinNoiseShaderBlock::Type::kTurbulence);
1746static void add_to_key(const KeyContext& keyContext,
1747 PaintParamsKeyBuilder* builder,
1748 PipelineDataGatherer* gatherer,
1749 const SkPerlinNoiseShader* shader) {
1750 SkASSERT(shader);
1751 SkASSERT(shader->numOctaves());
1752
1753 std::unique_ptr<SkPerlinNoiseShader::PaintingData> paintingData = shader->getPaintingData();
1754 paintingData->generateBitmaps();
1755
1756 sk_sp<TextureProxy> perm = RecorderPriv::CreateCachedProxy(
1757 keyContext.recorder(), paintingData->getPermutationsBitmap());
1758
1759 sk_sp<TextureProxy> noise =
1760 RecorderPriv::CreateCachedProxy(keyContext.recorder(), paintingData->getNoiseBitmap());
1761
1762 if (!perm || !noise) {
1763 SKGPU_LOG_W("Couldn't create tables for PerlinNoiseShader");
1764 builder->addBlock(BuiltInCodeSnippetID::kError);
1765 return;
1766 }
1767
1768 PerlinNoiseShaderBlock::PerlinNoiseData perlinData(
1769 static_cast<PerlinNoiseShaderBlock::Type>(shader->noiseType()),
1770 paintingData->fBaseFrequency,
1771 shader->numOctaves(),
1772 {paintingData->fStitchDataInit.fWidth, paintingData->fStitchDataInit.fHeight});
1773
1774 perlinData.fPermutationsProxy = std::move(perm);
1775 perlinData.fNoiseProxy = std::move(noise);
1776
1777 PerlinNoiseShaderBlock::AddBlock(keyContext, builder, gatherer, perlinData);
1778}
1779static void notify_in_use(Recorder*, DrawContext*, const SkPerlinNoiseShader*) {
1780 // No-op, perlin noise has no children.
1781}
1782
1783static void add_to_key(const KeyContext& keyContext,
1784 PaintParamsKeyBuilder* builder,
1785 PipelineDataGatherer* gatherer,
1786 const SkPictureShader* shader) {
1787 SkASSERT(shader);
1788
1789 Recorder* recorder = keyContext.recorder();
1790 const Caps* caps = recorder->priv().caps();
1791
1792 // TODO: We'll need additional plumbing to get the correct props from our callers. In
1793 // particular we'll need to expand the keyContext to have the surfaceProps.
1794 SkSurfaceProps props{};
1795
1796 SkMatrix totalM = keyContext.local2Dev().asM33();
1797 if (keyContext.localMatrix()) {
1798 totalM.preConcat(*keyContext.localMatrix());
1799 }
1801 totalM,
1802 keyContext.dstColorInfo().colorType(),
1803 keyContext.dstColorInfo().colorSpace(),
1804 caps->maxTextureSize(),
1805 props);
1806 if (!info.success) {
1807 SKGPU_LOG_W("Couldn't access PictureShaders' Image info");
1808 builder->addBlock(BuiltInCodeSnippetID::kError);
1809 return;
1810 }
1811
1812 // TODO: right now we're explicitly not caching here. We could expand the ImageProvider
1813 // API to include already Graphite-backed images, add a Recorder-local cache or add
1814 // rendered-picture images to the global cache.
1815 sk_sp<SkImage> img = info.makeImage(
1816 SkSurfaces::RenderTarget(recorder, info.imageInfo, skgpu::Mipmapped::kNo, &info.props),
1817 shader->picture().get());
1818 if (!img) {
1819 SKGPU_LOG_W("Couldn't create SkImage for PictureShader");
1820 builder->addBlock(BuiltInCodeSnippetID::kError);
1821 return;
1822 }
1823
1824 const auto shaderLM = SkMatrix::Scale(1.f/info.tileScale.width(), 1.f/info.tileScale.height());
1825 sk_sp<SkShader> imgShader = img->makeShader(shader->tileModeX(), shader->tileModeY(),
1826 SkSamplingOptions(shader->filter()), &shaderLM);
1827 if (!imgShader) {
1828 SKGPU_LOG_W("Couldn't create SkImageShader for PictureShader");
1829 builder->addBlock(BuiltInCodeSnippetID::kError);
1830 return;
1831 }
1832
1833 AddToKey(keyContext, builder, gatherer, imgShader.get());
1834}
1835static void notify_in_use(Recorder*, DrawContext*, const SkPictureShader*) {
1836 // While the SkPicture the shader points to, may have Graphite-backed shaders that need to be
1837 // notified, that will happen when the picture is rendered into an image in add_to_key
1838}
1839
1840static void add_to_key(const KeyContext& keyContext,
1841 PaintParamsKeyBuilder* builder,
1842 PipelineDataGatherer* gatherer,
1843 const SkRuntimeShader* shader) {
1844 SkASSERT(shader);
1845 sk_sp<SkRuntimeEffect> effect = shader->effect();
1847 effect->uniforms(),
1848 shader->uniformData(keyContext.dstColorInfo().colorSpace()),
1849 keyContext.dstColorInfo().colorSpace());
1850 SkASSERT(uniforms);
1851
1852 RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
1853 {effect, std::move(uniforms)});
1854
1855 add_children_to_key(keyContext, builder, gatherer,
1856 shader->children(), effect->children());
1857
1858 builder->endBlock();
1859}
1860static void notify_in_use(Recorder* recorder,
1861 DrawContext* drawContext,
1862 const SkRuntimeShader* shader) {
1863 notify_in_use(recorder, drawContext, shader->children());
1864}
1865
1866static void add_to_key(const KeyContext& keyContext,
1867 PaintParamsKeyBuilder* builder,
1868 PipelineDataGatherer* gatherer,
1869 const SkTransformShader* shader) {
1870 SKGPU_LOG_W("Raster-only SkShader (SkTransformShader) encountered");
1871 builder->addBlock(BuiltInCodeSnippetID::kError);
1872}
1873static void notify_in_use(Recorder*, DrawContext*, const SkTransformShader*) {
1874 // no-op
1875}
1876
1877static void add_to_key(const KeyContext& keyContext,
1878 PaintParamsKeyBuilder* builder,
1879 PipelineDataGatherer* gatherer,
1880 const SkTriColorShader* shader) {
1881 SKGPU_LOG_W("Raster-only SkShader (SkTriColorShader) encountered");
1882 builder->addBlock(BuiltInCodeSnippetID::kError);
1883}
1884static void notify_in_use(Recorder*, DrawContext*, const SkTriColorShader*) {
1885 // no-op
1886}
1887
1888static void add_to_key(const KeyContext& keyContext,
1889 PaintParamsKeyBuilder* builder,
1890 PipelineDataGatherer* gatherer,
1891 const SkWorkingColorSpaceShader* shader) {
1892 SkASSERT(shader);
1893
1894 const SkColorInfo& dstInfo = keyContext.dstColorInfo();
1895 const SkAlphaType dstAT = dstInfo.alphaType();
1896 sk_sp<SkColorSpace> dstCS = dstInfo.refColorSpace();
1897 if (!dstCS) {
1898 dstCS = SkColorSpace::MakeSRGB();
1899 }
1900
1901 sk_sp<SkColorSpace> workingCS = shader->workingSpace();
1902 SkColorInfo workingInfo(dstInfo.colorType(), dstAT, workingCS);
1903 KeyContextWithColorInfo workingContext(keyContext, workingInfo);
1904
1905 // Compose the inner shader (in the working space) with a (working->dst) transform:
1906 Compose(keyContext, builder, gatherer,
1907 /* addInnerToKey= */ [&]() -> void {
1908 AddToKey(workingContext, builder, gatherer, shader->shader().get());
1909 },
1910 /* addOuterToKey= */ [&]() -> void {
1911 ColorSpaceTransformBlock::ColorSpaceTransformData data(
1912 workingCS.get(), dstAT, dstCS.get(), dstAT);
1913 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data);
1914 });
1915}
1916static void notify_in_use(Recorder* recorder,
1917 DrawContext* drawContext,
1918 const SkWorkingColorSpaceShader* shader) {
1919 NotifyImagesInUse(recorder, drawContext, shader->shader().get());
1920}
1921
1922static SkBitmap create_color_and_offset_bitmap(int numStops,
1923 const SkPMColor4f* colors,
1924 const float* offsets) {
1925 SkBitmap colorsAndOffsetsBitmap;
1926
1927 colorsAndOffsetsBitmap.allocPixels(
1929
1930 for (int i = 0; i < numStops; i++) {
1931 // TODO: there should be a way to directly set a premul pixel in a bitmap with
1932 // a premul color.
1933 SkColor4f unpremulColor = colors[i].unpremul();
1934 colorsAndOffsetsBitmap.erase(unpremulColor, SkIRect::MakeXYWH(i, 0, 1, 1));
1935
1936 float offset = offsets ? offsets[i] : SkIntToFloat(i) / (numStops - 1);
1937 SkASSERT(offset >= 0.0f && offset <= 1.0f);
1938
1939 int exponent;
1940 float mantissa = frexp(offset, &exponent);
1941
1942 SkHalf halfE = SkFloatToHalf(exponent);
1943 if ((int)SkHalfToFloat(halfE) != exponent) {
1944 SKGPU_LOG_W("Encoding gradient to f16 failed");
1945 return {};
1946 }
1947
1948#if defined(SK_DEBUG)
1949 SkHalf halfM = SkFloatToHalf(mantissa);
1950
1951 float restored = ldexp(SkHalfToFloat(halfM), (int)SkHalfToFloat(halfE));
1952 float error = abs(restored - offset);
1953 SkASSERT(error < 0.001f);
1954#endif
1955
1956 // TODO: we're only using 2 of the f16s here. The encoding could be altered to better
1957 // preserve precision. This encoding yields < 0.001f error for 2^20 evenly spaced stops.
1958 colorsAndOffsetsBitmap.erase(SkColor4f{mantissa, (float)exponent, 0, 1},
1959 SkIRect::MakeXYWH(i, 1, 1, 1));
1960 }
1961
1962 return colorsAndOffsetsBitmap;
1963}
1964
1965// Please see GrGradientShader.cpp::make_interpolated_to_dst for substantial comments
1966// as to why this code is structured this way.
1967static void make_interpolated_to_dst(const KeyContext& keyContext,
1968 PaintParamsKeyBuilder* builder,
1969 PipelineDataGatherer* gatherer,
1970 const GradientShaderBlocks::GradientData& gradData,
1972 SkColorSpace* intermediateCS) {
1974
1975 bool inputPremul = static_cast<bool>(interp.fInPremul);
1976
1977 switch (interp.fColorSpace) {
1978 case ColorSpace::kLab:
1979 case ColorSpace::kOKLab:
1980 case ColorSpace::kOKLabGamutMap:
1981 case ColorSpace::kLCH:
1982 case ColorSpace::kOKLCH:
1983 case ColorSpace::kOKLCHGamutMap:
1984 case ColorSpace::kHSL:
1985 case ColorSpace::kHWB:
1986 inputPremul = false;
1987 break;
1988 default:
1989 break;
1990 }
1991
1992 const SkColorInfo& dstColorInfo = keyContext.dstColorInfo();
1993
1994 SkColorSpace* dstColorSpace =
1995 dstColorInfo.colorSpace() ? dstColorInfo.colorSpace() : sk_srgb_singleton();
1996
1997 SkAlphaType intermediateAlphaType = inputPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
1998
1999 ColorSpaceTransformBlock::ColorSpaceTransformData data(
2000 intermediateCS, intermediateAlphaType, dstColorSpace, dstColorInfo.alphaType());
2001
2002 // The gradient block and colorSpace conversion block need to be combined
2003 // (via the Compose block) so that the localMatrix block can treat them as
2004 // one child.
2005 Compose(keyContext, builder, gatherer,
2006 /* addInnerToKey= */ [&]() -> void {
2007 GradientShaderBlocks::AddBlock(keyContext, builder, gatherer, gradData);
2008 },
2009 /* addOuterToKey= */ [&]() -> void {
2010 ColorSpaceTransformBlock::AddBlock(keyContext, builder, gatherer, data);
2011 });
2012}
2013
2014static void add_gradient_to_key(const KeyContext& keyContext,
2015 PaintParamsKeyBuilder* builder,
2016 PipelineDataGatherer* gatherer,
2017 const SkGradientBaseShader* shader,
2018 SkPoint point0,
2019 SkPoint point1,
2020 float radius0,
2021 float radius1,
2022 float bias,
2023 float scale) {
2024 SkColor4fXformer xformedColors(shader, keyContext.dstColorInfo().colorSpace());
2025 const SkPMColor4f* colors = xformedColors.fColors.begin();
2026 const float* positions = xformedColors.fPositions;
2027 const int colorCount = xformedColors.fColors.size();
2028
2029 sk_sp<TextureProxy> proxy;
2030
2031 if (colorCount > GradientShaderBlocks::GradientData::kNumInternalStorageStops) {
2032 if (shader->cachedBitmap().empty()) {
2033 SkBitmap colorsAndOffsetsBitmap =
2034 create_color_and_offset_bitmap(colorCount, colors, positions);
2035 if (colorsAndOffsetsBitmap.empty()) {
2036 SKGPU_LOG_W("Couldn't create GradientShader's color and offset bitmap");
2037 builder->addBlock(BuiltInCodeSnippetID::kError);
2038 return;
2039 }
2040 shader->setCachedBitmap(colorsAndOffsetsBitmap);
2041 }
2042
2043 proxy = RecorderPriv::CreateCachedProxy(keyContext.recorder(), shader->cachedBitmap());
2044 if (!proxy) {
2045 SKGPU_LOG_W("Couldn't create GradientShader's color and offset bitmap proxy");
2046 builder->addBlock(BuiltInCodeSnippetID::kError);
2047 return;
2048 }
2049 }
2050
2051 GradientShaderBlocks::GradientData data(shader->asGradient(),
2052 point0,
2053 point1,
2054 radius0,
2055 radius1,
2056 bias,
2057 scale,
2058 shader->getTileMode(),
2059 colorCount,
2060 colors,
2061 positions,
2062 std::move(proxy),
2063 shader->getInterpolation());
2064
2065 make_interpolated_to_dst(keyContext,
2066 builder,
2067 gatherer,
2068 data,
2069 shader->getInterpolation(),
2070 xformedColors.fIntermediateColorSpace.get());
2071}
2072
2073static void add_gradient_to_key(const KeyContext& keyContext,
2074 PaintParamsKeyBuilder* builder,
2075 PipelineDataGatherer* gatherer,
2076 const SkConicalGradient* shader) {
2077 add_gradient_to_key(keyContext,
2078 builder,
2079 gatherer,
2080 shader,
2081 shader->getStartCenter(),
2082 shader->getEndCenter(),
2083 shader->getStartRadius(),
2084 shader->getEndRadius(),
2085 0.0f,
2086 0.0f);
2087}
2088
2089static void add_gradient_to_key(const KeyContext& keyContext,
2090 PaintParamsKeyBuilder* builder,
2091 PipelineDataGatherer* gatherer,
2092 const SkLinearGradient* shader) {
2093 add_gradient_to_key(keyContext,
2094 builder,
2095 gatherer,
2096 shader,
2097 shader->start(),
2098 shader->end(),
2099 0.0f,
2100 0.0f,
2101 0.0f,
2102 0.0f);
2103}
2104
2105static void add_gradient_to_key(const KeyContext& keyContext,
2106 PaintParamsKeyBuilder* builder,
2107 PipelineDataGatherer* gatherer,
2108 const SkRadialGradient* shader) {
2109 add_gradient_to_key(keyContext,
2110 builder,
2111 gatherer,
2112 shader,
2113 shader->center(),
2114 { 0.0f, 0.0f },
2115 shader->radius(),
2116 0.0f,
2117 0.0f,
2118 0.0f);
2119}
2120
2121static void add_gradient_to_key(const KeyContext& keyContext,
2122 PaintParamsKeyBuilder* builder,
2123 PipelineDataGatherer* gatherer,
2124 const SkSweepGradient* shader) {
2125 add_gradient_to_key(keyContext,
2126 builder,
2127 gatherer,
2128 shader,
2129 shader->center(),
2130 { 0.0f, 0.0f },
2131 0.0f,
2132 0.0f,
2133 shader->tBias(),
2134 shader->tScale());
2135}
2136
2137static void add_to_key(const KeyContext& keyContext,
2138 PaintParamsKeyBuilder* builder,
2139 PipelineDataGatherer* gatherer,
2140 const SkGradientBaseShader* shader) {
2141 SkASSERT(shader);
2142 switch (shader->asGradient()) {
2143#define M(type) \
2144 case SkShaderBase::GradientType::k##type: \
2145 add_gradient_to_key(keyContext, \
2146 builder, \
2147 gatherer, \
2148 static_cast<const Sk##type##Gradient*>(shader)); \
2149 return;
2151#undef M
2153 SkDEBUGFAIL("Gradient shader says its type is none");
2154 return;
2155 }
2157}
2158static void notify_in_use(Recorder*, DrawContext*, const SkGradientBaseShader*) {
2159 // Gradients do not have children, so no images to notify
2160}
2161
2162void AddToKey(const KeyContext& keyContext,
2163 PaintParamsKeyBuilder* builder,
2164 PipelineDataGatherer* gatherer,
2165 const SkShader* shader) {
2166 if (!shader) {
2167 return;
2168 }
2169 switch (as_SB(shader)->type()) {
2170#define M(type) \
2171 case SkShaderBase::ShaderType::k##type: \
2172 add_to_key(keyContext, \
2173 builder, \
2174 gatherer, \
2175 static_cast<const Sk##type##Shader*>(shader)); \
2176 return;
2178#undef M
2179 }
2181}
2182
2183void NotifyImagesInUse(Recorder* recorder,
2184 DrawContext* drawContext,
2185 const SkShader* shader) {
2186 if (!shader) {
2187 return;
2188 }
2189 switch (as_SB(shader)->type()) {
2190#define M(type) \
2191 case SkShaderBase::ShaderType::k##type: \
2192 notify_in_use(recorder, \
2193 drawContext, \
2194 static_cast<const Sk##type##Shader*>(shader)); \
2195 return;
2197#undef M
2198 }
2200}
2201
2202
2203} // namespace skgpu::graphite
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
static std::unique_ptr< GrFragmentProcessor > make_interpolated_to_dst(std::unique_ptr< GrFragmentProcessor > gradient, const SkGradientShader::Interpolation &interpolation, SkColorSpace *intermediateColorSpace, const GrColorInfo &dstInfo, bool allOpaque)
SkColor4f color
#define VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
#define M(type)
#define SKGPU_LOG_W(fmt,...)
Definition Log.h:40
kUnpremul_SkAlphaType
SkAlphaType
Definition SkAlphaType.h:26
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition SkAlphaType.h:29
#define SkUNREACHABLE
Definition SkAssert.h:135
#define SkDEBUGFAIL(message)
Definition SkAssert.h:118
#define SkDEBUGFAILF(fmt,...)
Definition SkAssert.h:119
#define SkASSERT(cond)
Definition SkAssert.h:116
static SkRGBA4f< kDstAT > map_color(const SkColor4f &c, SkColorSpace *src, SkColorSpace *dst)
SkBlendMode
Definition SkBlendMode.h:38
@ kDstIn
r = d * sa
@ kSrcOver
r = s + (1-sa)*d
#define SK_ALL_BLENDERS(M)
SkBlenderBase * as_BB(SkBlender *blend)
constexpr SkPMColor4f SK_PMColor4fTRANSPARENT
#define SK_ALL_COLOR_FILTERS(M)
static SkColorFilterBase * as_CFB(SkColorFilter *filter)
SkColorSpace * sk_srgb_linear_singleton()
SkColorSpace * sk_srgb_singleton()
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition SkColorType.h:38
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
static float2 interp(const float2 &v0, const float2 &v1, const float2 &t)
float SkHalfToFloat(SkHalf h)
Definition SkHalf.cpp:24
SkHalf SkFloatToHalf(float f)
Definition SkHalf.cpp:16
uint16_t SkHalf
Definition SkHalf.h:16
static SkImage_Base * as_IB(SkImage *image)
static void sk_bzero(void *buffer, size_t size)
Definition SkMalloc.h:105
#define SkIntToFloat(x)
Definition SkScalar.h:58
SkShaderBase * as_SB(SkShader *shader)
#define SK_ALL_GRADIENTS(M)
#define SK_ALL_SHADERS(M)
SkTileMode
Definition SkTileMode.h:13
void SkColorMatrix_YUV2RGB(SkYUVColorSpace cs, float m[20])
Type::kYUV Type::kRGBA() int(0.7 *637)
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition SkBitmap.cpp:258
bool empty() const
Definition SkBitmap.h:210
void erase(SkColor4f c, const SkIRect &area) const
Definition SkBitmap.cpp:420
SkBlendMode mode() const
sk_sp< SkShader > dst() const
SkBlendMode mode() const
sk_sp< SkShader > src() const
const SkMatrix & ctm() const
sk_sp< SkShader > proxyShader() const
SkColor4f color() const
sk_sp< SkColorSpace > colorSpace() const
sk_sp< SkColorFilterBase > filter() const
sk_sp< SkShader > shader() const
SkAlphaType alphaType() const
sk_sp< SkColorSpace > refColorSpace() const
SkColorSpace * colorSpace() const
SkColorType colorType() const
SkColor color() const
sk_sp< SkColorSpace > dst() const
sk_sp< SkColorSpace > src() const
static sk_sp< SkColorSpace > MakeSRGB()
sk_sp< SkColorFilterBase > inner() const
sk_sp< SkColorFilterBase > outer() const
const SkPoint & getEndCenter() const
SkScalar getEndRadius() const
const SkPoint & getStartCenter() const
SkScalar getStartRadius() const
sk_sp< SkShader > shader() const
const uint8_t * bytes() const
Definition SkData.h:43
const Interpolation & getInterpolation() const
void setCachedBitmap(SkBitmap b) const
const SkBitmap & cachedBitmap() const
SkTileMode getTileMode() const
SkSamplingOptions sampling() const
static SkM44 CubicResamplerMatrix(float B, float C)
SkTileMode tileModeX() const
sk_sp< SkImage > image() const
bool isRaw() const
SkTileMode tileModeY() const
SkRect subset() const
const SkPoint & start() const
const SkPoint & end() const
const SkMatrix & localMatrix() const
sk_sp< SkShader > wrappedShader() const
Definition SkM44.h:150
bool invert(SkM44 *inverse) const
Definition SkM44.cpp:247
SkM44 & setIdentity()
Definition SkM44.h:293
const float * matrix() const
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition SkMatrix.h:75
SkMatrix & setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2)
Definition SkMatrix.h:562
SkMatrix & preConcat(const SkMatrix &other)
Definition SkMatrix.cpp:674
SkPerlinNoiseShaderType noiseType() const
std::unique_ptr< PaintingData > getPaintingData() const
SkRect tile() const
SkTileMode tileModeY() const
SkTileMode tileModeX() const
SkFilterMode filter() const
sk_sp< SkPicture > picture() const
SkScalar radius() const
const SkPoint & center() const
sk_sp< SkRuntimeEffect > effect() const
SkSpan< const SkRuntimeEffect::ChildPtr > children() const
sk_sp< const SkData > uniforms() const
SkSpan< const SkRuntimeEffect::ChildPtr > children() const
sk_sp< SkRuntimeEffect > effect() const
sk_sp< const SkData > uniforms() const
static sk_sp< const SkData > TransformUniforms(SkSpan< const SkRuntimeEffect::Uniform > uniforms, sk_sp< const SkData > originalData, const SkColorSpaceXformSteps &)
static bool UsesColorTransform(const SkRuntimeEffect *effect)
SkBlender * blender() const
std::optional< ChildType > type() const
SkColorFilter * colorFilter() const
SkSpan< const Uniform > uniforms() const
SkSpan< const SkRuntimeEffect::ChildPtr > children() const
sk_sp< const SkData > uniformData(const SkColorSpace *dstCS) const
sk_sp< SkRuntimeEffect > effect() const
virtual GradientType asGradient(GradientInfo *info=nullptr, SkMatrix *localMatrix=nullptr) const
constexpr size_t size() const
Definition SkSpan_impl.h:95
const char * data() const
Definition SkString.h:132
SkScalar tBias() const
SkScalar tScale() const
const SkPoint & center() const
const SkBitmap & bitmap() const
sk_sp< SkShader > shader() const
sk_sp< SkColorSpace > workingSpace() const
sk_sp< SkColorFilter > child() const
sk_sp< SkColorSpace > workingFormat(const sk_sp< SkColorSpace > &dstCS, SkAlphaType *at) const
int width() const
Definition SkYUVAInfo.h:172
Siting sitingY() const
Definition SkYUVAInfo.h:177
SkMatrix originMatrix() const
Definition SkYUVAInfo.h:181
SkYUVColorSpace yuvColorSpace() const
Definition SkYUVAInfo.h:175
int height() const
Definition SkYUVAInfo.h:173
static constexpr int kYUVAChannelCount
Definition SkYUVAInfo.h:29
Siting sitingX() const
Definition SkYUVAInfo.h:176
T * get() const
Definition SkRefCnt.h:303
static constexpr Swizzle Concat(const Swizzle &a, const Swizzle &b)
Definition Swizzle.h:156
SkString asString() const
Definition Swizzle.cpp:46
static constexpr Swizzle BGRA()
Definition Swizzle.h:67
static constexpr Swizzle RGBA()
Definition Swizzle.h:66
static constexpr Swizzle RGB1()
Definition Swizzle.h:69
const Caps * caps() const
sk_sp< SkImage > image
Definition examples.cpp:29
static bool b
struct MyStruct a[10]
const uint8_t uint32_t uint32_t GError ** error
static constexpr int kUnknownRuntimeEffectIDStart
unsigned useCenter Optional< SkMatrix > matrix
Definition SkRecords.h:258
PODArray< SkColor > colors
Definition SkRecords.h:276
SkSamplingOptions sampling
Definition SkRecords.h:337
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
ColorSpace
Definition image.h:16
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
CanvasImage Image
Definition dart_ui.cc:55
dst
Definition cp.py:12
std::tuple< GrSurfaceProxyView, GrColorType > AsView(GrRecordingContext *rContext, const SkImage *img, skgpu::Mipmapped mipmapped, GrImageTexGenPolicy policy)
void AddToKey(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkBlender *blender)
void AddKnownModeBlend(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, SkBlendMode bm)
void AddBlendModeColorFilter(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, SkBlendMode bm, const SkPMColor4f &srcColor)
static void notify_in_use(Recorder *recorder, DrawContext *drawContext, const SkBlendShader *shader)
static void add_yuv_image_to_key(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkImageShader *origShader, sk_sp< const SkImage > imageToDraw, SkSamplingOptions sampling)
static bool can_do_tiling_in_hw(const Caps *caps, const ImageShaderBlock::ImageData &imgData)
static SkBitmap create_color_and_offset_bitmap(int numStops, const SkPMColor4f *colors, const float *offsets)
std::pair< sk_sp< SkImage >, SkSamplingOptions > GetGraphiteBacked(Recorder *recorder, const SkImage *imageIn, SkSamplingOptions sampling)
static void add_to_key(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkBlendModeColorFilter *filter)
static void add_gradient_to_key(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkGradientBaseShader *shader, SkPoint point0, SkPoint point1, float radius0, float radius1, float bias, float scale)
static skgpu::graphite::ReadSwizzle swizzle_class_to_read_enum(const skgpu::Swizzle &swizzle)
void AddModeBlend(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, SkBlendMode bm)
static void gather_runtime_effect_uniforms(const KeyContext &keyContext, const SkRuntimeEffect *effect, SkSpan< const Uniform > graphiteUniforms, const SkData *uniformData, PipelineDataGatherer *gatherer)
static bool skdata_matches(const SkData *a, const SkData *b)
void NotifyImagesInUse(Recorder *recorder, DrawContext *drawContext, const SkBlender *blender)
AI float cubic(float precision, const SkPoint pts[], const VectorXform &vectorXform=VectorXform())
SIN Vec< N, float > abs(const Vec< N, float > &x)
Definition SkVx.h:707
Definition ref_ptr.h:256
skcms_TFType skcms_TransferFunction_getType(const skcms_TransferFunction *tf)
Definition skcms.cc:183
const Scalar scale
Point offset
constexpr uint32_t mask() const
skcms_TransferFunction srcTF
void apply(float rgba[4]) const
skcms_TransferFunction dstTFInv
constexpr int32_t y() const
constexpr int32_t x() const
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition SkRect.h:104
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static CachedImageInfo Make(const SkRect &bounds, const SkMatrix &totalM, SkColorType dstColorType, SkColorSpace *dstColorSpace, const int maxTextureSize, const SkSurfaceProps &propsIn)
SkRGBA4f< kPremul_SkAlphaType > premul() const
Definition SkColor.h:385
static SkRGBA4f FromColor(SkColor color)
static SkRect Make(const SkISize &size)
Definition SkRect.h:669
static constexpr SkSize Make(SkScalar w, SkScalar h)
Definition SkSize.h:56
Definition SkM44.h:98