blob: 1b5c0b6369c5b03abc4cb1286176a09a7009b7f8 [file] [log] [blame]
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef skgpu_graphite_KeyHelpers_DEFINED
#define skgpu_graphite_KeyHelpers_DEFINED
#include "include/core/SkBitmap.h"
#include "include/core/SkBlendMode.h"
#include "include/core/SkM44.h"
#include "include/core/SkPoint3.h"
#include "include/core/SkSamplingOptions.h"
#include "include/core/SkShader.h"
#include "include/core/SkSpan.h"
#include "include/core/SkTileMode.h"
#include "include/effects/SkGradientShader.h"
#include "include/gpu/graphite/Context.h"
#include "include/private/SkColorData.h"
#include "src/core/SkColorSpaceXformSteps.h"
#include "src/gpu/graphite/TextureProxy.h"
#include "src/shaders/SkShaderBase.h"
class SkColorFilter;
class SkData;
class SkRuntimeEffect;
namespace skgpu::graphite {
class DrawContext;
class KeyContext;
class PaintParamsKeyBuilder;
class PipelineDataGatherer;
class UniquePaintParamsID;
enum class ReadSwizzle;
// Types of logical "destinations" that a blender might blend with.
enum class DstColorType {
// A color read from the framebuffer.
kSurface,
// A color provided by geometry.
kPrimitive,
// A color evaluated by a child shader.
kChildOutput,
};
/**
* The KeyHelpers can be used to manually construct an SkPaintParamsKey.
*
* TODO: If we restructure how the keys are made, we can utilize a single block type for the
* different blend blocks outlined below. The different Src/Dst pairings could instead be encoded
* as parent-child relationships.
*/
struct DstReadSampleBlock {
static void AddBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
sk_sp<TextureProxy> dst,
SkIPoint dstOffset);
};
struct SolidColorShaderBlock {
static void AddBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
const SkPMColor4f&);
};
struct RGBPaintColorBlock {
static void AddBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*);
};
struct AlphaOnlyPaintColorBlock {
static void AddBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*);
};
struct GradientShaderBlocks {
struct GradientData {
// The number of stops stored internal to this data structure before falling back to
// bitmap storage.
static constexpr int kNumInternalStorageStops = 8;
// This ctor is used during pre-compilation when we don't have enough information to
// extract uniform data. However, we must be able to provide enough data to make all the
// relevant decisions about which code snippets to use.
GradientData(SkShaderBase::GradientType, int numStops);
// This ctor is used when extracting information from PaintParams. It must provide
// enough data to generate the uniform data the selected code snippet will require.
GradientData(SkShaderBase::GradientType,
SkPoint point0, SkPoint point1,
float radius0, float radius1,
float bias, float scale,
SkTileMode,
int numStops,
const SkPMColor4f* colors,
const float* offsets,
sk_sp<TextureProxy> colorsAndOffsetsProxy,
const SkGradientShader::Interpolation&);
bool operator==(const GradientData& rhs) const = delete;
bool operator!=(const GradientData& rhs) const = delete;
// Layout options.
SkShaderBase::GradientType fType;
SkPoint fPoints[2];
float fRadii[2];
// Layout options for sweep gradient.
float fBias;
float fScale;
SkTileMode fTM;
int fNumStops;
// For gradients w/ <= kNumInternalStorageStops stops we use fColors and fOffsets.
// The offsets are packed into a single float4 to save space when the layout is std140.
// Otherwise we use fColorsAndOffsetsProxy.
SkPMColor4f fColors[kNumInternalStorageStops];
SkV4 fOffsets[kNumInternalStorageStops / 4];
sk_sp<TextureProxy> fColorsAndOffsetsProxy;
SkGradientShader::Interpolation fInterpolation;
};
static void AddBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
const GradientData&);
};
struct LocalMatrixShaderBlock {
struct LMShaderData {
LMShaderData(const SkMatrix& localMatrix)
: fLocalMatrix(localMatrix) {
}
const SkM44 fLocalMatrix;
};
static void BeginBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
const LMShaderData&);
};
struct ImageShaderBlock {
struct ImageData {
ImageData(const SkSamplingOptions& sampling,
SkTileMode tileModeX,
SkTileMode tileModeY,
SkISize imgSize,
SkRect subset,
ReadSwizzle readSwizzle);
SkSamplingOptions fSampling;
SkTileMode fTileModes[2];
SkISize fImgSize;
SkRect fSubset;
ReadSwizzle fReadSwizzle;
SkColorSpaceXformSteps fSteps;
// TODO: Currently this is only filled in when we're generating the key from an actual
// SkImageShader. In the pre-compile case we will need to create a Graphite promise
// image which holds the appropriate data.
sk_sp<TextureProxy> fTextureProxy;
};
static void AddBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
const ImageData&);
};
struct YUVImageShaderBlock {
struct ImageData {
ImageData(const SkSamplingOptions& sampling,
SkTileMode tileModeX,
SkTileMode tileModeY,
SkISize imgSize,
SkRect subset);
SkSamplingOptions fSampling;
SkSamplingOptions fSamplingUV;
SkTileMode fTileModes[2];
SkISize fImgSize;
SkISize fImgSizeUV; // Size of UV planes relative to Y's texel space
SkRect fSubset;
SkPoint fLinearFilterUVInset = { 0.50001f, 0.50001f };
SkV4 fChannelSelect[4];
SkMatrix fYUVtoRGBMatrix;
SkPoint3 fYUVtoRGBTranslate;
// TODO: Currently these are only filled in when we're generating the key from an actual
// SkImageShader. In the pre-compile case we will need to create Graphite promise
// images which hold the appropriate data.
sk_sp<TextureProxy> fTextureProxies[4];
};
static void AddBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
const ImageData&);
};
struct CoordClampShaderBlock {
struct CoordClampData {
CoordClampData(SkRect subset) : fSubset(subset) {}
SkRect fSubset;
};
// The gatherer and data should be null or non-null together
static void BeginBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
const CoordClampData&);
};
struct DitherShaderBlock {
struct DitherData {
DitherData(float range, sk_sp<TextureProxy> proxy)
: fRange(range)
, fLUTProxy(std::move(proxy)) {}
float fRange;
sk_sp<TextureProxy> fLUTProxy;
};
static void AddBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
const DitherData&);
};
struct PerlinNoiseShaderBlock {
enum class Type {
kFractalNoise,
kTurbulence,
};
struct PerlinNoiseData {
PerlinNoiseData(Type type,
SkVector baseFrequency,
int numOctaves,
SkISize stitchData)
: fType(type)
, fBaseFrequency(baseFrequency)
, fNumOctaves(numOctaves)
, fStitchData{ SkIntToFloat(stitchData.fWidth), SkIntToFloat(stitchData.fHeight) } {
}
bool stitching() const { return !fStitchData.isZero(); }
Type fType;
SkVector fBaseFrequency;
int fNumOctaves;
SkVector fStitchData;
sk_sp<TextureProxy> fPermutationsProxy;
sk_sp<TextureProxy> fNoiseProxy;
};
// The gatherer and data should be null or non-null together
static void AddBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
const PerlinNoiseData&);
};
struct BlendShaderBlock {
static void BeginBlock(const KeyContext&, PaintParamsKeyBuilder*, PipelineDataGatherer*);
};
struct BlendModeBlenderBlock {
static void AddBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
SkBlendMode);
};
struct CoeffBlenderBlock {
static void AddBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
SkSpan<const float> coeffs);
};
struct ClipShaderBlock {
static void BeginBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*);
};
struct ComposeBlock {
static void BeginBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*);
};
struct MatrixColorFilterBlock {
struct MatrixColorFilterData {
MatrixColorFilterData(const float matrix[20],
bool inHSLA)
: fMatrix(matrix[ 0], matrix[ 1], matrix[ 2], matrix[ 3],
matrix[ 5], matrix[ 6], matrix[ 7], matrix[ 8],
matrix[10], matrix[11], matrix[12], matrix[13],
matrix[15], matrix[16], matrix[17], matrix[18])
, fTranslate{matrix[4], matrix[9], matrix[14], matrix[19]}
, fInHSLA(inHSLA) {
}
SkM44 fMatrix;
SkV4 fTranslate;
bool fInHSLA;
};
// The gatherer and matrixCFData should be null or non-null together
static void AddBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
const MatrixColorFilterData&);
};
struct TableColorFilterBlock {
struct TableColorFilterData {
TableColorFilterData(sk_sp<TextureProxy> proxy) : fTextureProxy(std::move(proxy)) {}
sk_sp<TextureProxy> fTextureProxy;
};
static void AddBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
const TableColorFilterData&);
};
struct ColorSpaceTransformBlock {
struct ColorSpaceTransformData {
ColorSpaceTransformData(const SkColorSpace* src,
SkAlphaType srcAT,
const SkColorSpace* dst,
SkAlphaType dstAT);
ColorSpaceTransformData(const SkColorSpaceXformSteps& steps) { fSteps = steps; }
SkColorSpaceXformSteps fSteps;
};
static void AddBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
const ColorSpaceTransformData&);
};
/**
* Blend mode color filters blend their input (as the dst color) with some given color (supplied
* via a uniform) as the src color.
*/
void AddBlendModeColorFilter(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
SkBlendMode,
const SkPMColor4f& srcColor);
struct RuntimeEffectBlock {
struct ShaderData {
// This ctor is used during pre-compilation when we don't have enough information to
// extract uniform data.
ShaderData(sk_sp<const SkRuntimeEffect> effect);
// This ctor is used when extracting information from PaintParams.
ShaderData(sk_sp<const SkRuntimeEffect> effect,
sk_sp<const SkData> uniforms);
bool operator==(const ShaderData& rhs) const;
bool operator!=(const ShaderData& rhs) const { return !(*this == rhs); }
// Runtime shader data.
sk_sp<const SkRuntimeEffect> fEffect;
sk_sp<const SkData> fUniforms;
};
static void BeginBlock(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
const ShaderData&);
};
void AddToKey(const KeyContext&,
PaintParamsKeyBuilder*,
PipelineDataGatherer*,
const SkBlender*);
/**
* Add implementation details, for the specified backend, of this SkColorFilter to the
* provided key.
*
* @param keyContext backend context for key creation
* @param builder builder for creating the key for this SkShader
* @param gatherer if non-null, storage for this colorFilter's data
* @param filter This function is a no-op if filter is null.
*/
void AddToKey(const KeyContext& keyContext,
PaintParamsKeyBuilder* builder,
PipelineDataGatherer* gatherer,
const SkColorFilter* filter);
/**
* Add implementation details, for the specified backend, of this SkShader to the
* provided key.
*
* @param keyContext backend context for key creation
* @param builder builder for creating the key for this SkShader
* @param gatherer if non-null, storage for this colorFilter's data
* @param shader This function is a no-op if shader is null.
*/
void AddToKey(const KeyContext& keyContext,
PaintParamsKeyBuilder* builder,
PipelineDataGatherer* gatherer,
const SkShader* shader);
// TODO(b/330864257) These visitation functions are redundant with AddToKey, except that they are
// executed in the Device::drawGeometry() stack frame, whereas the keys are currently deferred until
// DrawPass::Make. Image use needs to be detected in the draw frame to split tasks to match client
// actions. Once paint keys are extracted in the draw frame, this can go away entirely.
void NotifyImagesInUse(Recorder*, DrawContext*, const SkBlender*);
void NotifyImagesInUse(Recorder*, DrawContext*, const SkColorFilter*);
void NotifyImagesInUse(Recorder*, DrawContext*, const SkShader*);
} // namespace skgpu::graphite
#endif // skgpu_graphite_KeyHelpers_DEFINED