blob: f64a8e3a7b3e2aa1ae80663e9ff788e4dbe5e264 [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_CombinationBuilder_DEFINED
#define skgpu_graphite_CombinationBuilder_DEFINED
#include "include/core/SkTypes.h"
#include <functional>
#include <memory>
#include <vector>
#include "include/core/SkBlendMode.h"
#include "include/core/SkSpan.h"
#include "include/core/SkTileMode.h"
#include "include/private/SkTArray.h"
#include "include/private/SkTHash.h"
class SkArenaAllocWithReset;
class SkUniquePaintParamsID;
namespace skgpu::graphite {
class CombinationBuilder;
class CombinationBuilderTestAccess;
class Context;
class KeyContext;
class Option;
class PaintParamsKeyBuilder;
class ShaderCodeDictionary;
enum class ShaderType : uint32_t {
kLast = kBlendShader
static constexpr int kShaderTypeCount = static_cast<int>(ShaderType::kLast) + 1;
struct TileModePair {
SkTileMode fX;
SkTileMode fY;
bool operator==(const TileModePair& other) const { return fX == other.fX && fY == other.fY; }
bool operator!=(const TileModePair& other) const { return !(*this == other); }
// TODO: add ShaderID and ColorFilterID too
class BlenderID {
BlenderID() : fID(0) {} // 0 is an invalid blender ID
BlenderID(const BlenderID& src) : fID(src.fID) {}
bool isValid() const { return fID > 0; }
bool operator==(const BlenderID& other) const { return fID == other.fID; }
BlenderID& operator=(const BlenderID& src) {
fID = src.fID;
return *this;
friend class ShaderCodeDictionary; // for ctor and asUInt access
friend class CombinationBuilder; // for asUInt access
BlenderID(uint32_t id) : fID(id) {}
uint32_t asUInt() const { return fID; }
uint32_t fID;
// When combination options are added to the combination builder an CombinationOption
// object is frequently returned. This allows options to be added, recursively, to the
// previously added options.
// Note: CombinationOptions are stable memory-wise so, once returned, they are valid
// until CombinationBuilder::reset is called.
class CombinationOption {
CombinationOption addChildOption(int childIndex, ShaderType);
CombinationOption addChildOption(int childIndex, ShaderType,
int minNumStops, int maxNumStops);
CombinationOption addChildOption(int childIndex, ShaderType,
SkSpan<TileModePair> tileModes);
bool isValid() const { return fDataInArena; }
friend class CombinationBuilder; // for ctor
friend class CombinationBuilderTestAccess;
CombinationOption(CombinationBuilder* builder, Option* dataInArena)
: fBuilder(builder)
, fDataInArena(dataInArena) {}
ShaderType type() const;
int numChildSlots() const;
SkDEBUGCODE(int epoch() const;)
CombinationBuilder* fBuilder;
Option* fDataInArena;
class CombinationBuilder {
enum class BlendModeGroup {
kPorterDuff, // [ kClear .. kScreen ]
kAdvanced, // [ kOverlay .. kMultiply ]
kColorAware, // [ kHue .. kLuminosity ]
// Blend Modes
void addOption(SkBlendMode);
void addOption(SkBlendMode rangeStart, SkBlendMode rangeEnd); // inclusive
void addOption(BlendModeGroup);
// TODO: have this variant return an CombinationOption object
void addOption(BlenderID);
// Shaders
CombinationOption addOption(ShaderType);
CombinationOption addOption(ShaderType, int minNumStops, int maxNumStops); // inclusive
CombinationOption addOption(ShaderType, SkSpan<TileModePair> tileModes);
void reset();
friend class Context; // for access to 'buildCombinations'
friend class CombinationOption; // for 'addOptionInternal' and 'arena'
friend class CombinationBuilderTestAccess; // for 'num*Combinations' and 'epoch'
int numShaderCombinations() const;
int numBlendModeCombinations() const;
int numCombinations() {
return this->numShaderCombinations() * this->numBlendModeCombinations();
// 'desiredCombination' must be less than numCombinations
void createKey(const KeyContext&, int desiredCombination, PaintParamsKeyBuilder*);
#ifdef SK_DEBUG
void dump() const;
int epoch() const { return fEpoch; }
SkArenaAllocWithReset* arena() { return fArena.get(); }
template<typename T, typename... Args>
Option* allocInArena(Args&&... args);
Option* addOptionInternal(ShaderType);
Option* addOptionInternal(ShaderType, int minNumStops, int maxNumStops);
Option* addOptionInternal(ShaderType, SkSpan<TileModePair> tileModes);
void buildCombinations(ShaderCodeDictionary*,
const std::function<void(SkUniquePaintParamsID)>&);
ShaderCodeDictionary* fDictionary;
std::unique_ptr<SkArenaAllocWithReset> fArena;
SkTArray<Option*> fShaderOptions;
uint32_t fBlendModes;
// TODO: store the SkBlender-based blenders in the arena
SkTHashSet<BlenderID> fBlenders;
SkDEBUGCODE(int fEpoch = 0;)
} // namespace skgpu::graphite
#endif // skgpu_graphite_CombinationBuilder_DEFINED