Add ShaderType::kSolidColor and make Combinations work w/ PaintParams

This is split out of Michael's CL:
https://skia-review.googlesource.com/c/skia/+/468459

Bug: skia:12466
Change-Id: Ic38ee577553cf2c0d4da8130e80a11422fa2b92e
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/472177
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2021-11-16 10:39:56 -05:00 committed by SkCQ
parent 24e7ec7713
commit 80ee93d2f5
11 changed files with 66 additions and 50 deletions

View File

@ -2129,7 +2129,7 @@ namespace {
void precompile(skgpu::Context* context) {
using ShaderType = skgpu::ShaderCombo::ShaderType;
skgpu::PaintCombo c1 { { skgpu::ShaderCombo({ ShaderType::kNone },
skgpu::PaintCombo c1 { { skgpu::ShaderCombo({ ShaderType::kSolidColor },
{ SkTileMode::kRepeat }) },
{ SkBlendMode::kSrcOver, SkBlendMode::kSrc } };
context->preCompile(c1);

View File

@ -26,7 +26,8 @@ namespace mtl { struct BackendContext; }
struct ShaderCombo {
enum class ShaderType {
kNone,
kNone, // does not modify color buffer, e.g. depth and/or stencil only
kSolidColor,
kLinearGradient,
kRadialGradient,
kSweepGradient,

View File

@ -8,6 +8,7 @@
#include "experimental/graphite/src/ContextUtils.h"
#include <string>
#include "experimental/graphite/src/DrawList.h" // TODO: split PaintParams out into their own header
#include "experimental/graphite/src/DrawTypes.h"
#include "experimental/graphite/src/Uniform.h"
#include "experimental/graphite/src/UniformCache.h"
@ -178,11 +179,12 @@ sk_sp<UniformData> UniformData::Make(int count,
return sk_sp<UniformData>(new UniformData(count, uniforms, offsets, data, dataSize));
}
std::tuple<Combination, sk_sp<UniformData>> ExtractCombo(UniformCache* cache, const SkPaint& p) {
std::tuple<Combination, sk_sp<UniformData>> ExtractCombo(UniformCache* cache,
const PaintParams& p) {
Combination result;
sk_sp<UniformData> uniforms;
if (auto s = p.getShader()) {
if (auto s = p.shader()) {
SkColor colors[kMaxStops];
SkColor4f color4fs[kMaxStops];
float offsets[kMaxStops];
@ -250,21 +252,21 @@ std::tuple<Combination, sk_sp<UniformData>> ExtractCombo(UniformCache* cache, co
case SkShader::GradientType::kColor_GradientType:
case SkShader::GradientType::kNone_GradientType:
default:
result.fShaderType = ShaderCombo::ShaderType::kNone;
result.fTileMode = SkTileMode::kRepeat;
result.fShaderType = ShaderCombo::ShaderType::kSolidColor;
result.fTileMode = SkTileMode::kClamp;
uniforms = make_solid_uniform_data(p.getColor4f());
uniforms = make_solid_uniform_data(p.color());
break;
}
} else {
// Solid colored paint
result.fShaderType = ShaderCombo::ShaderType::kNone;
result.fTileMode = SkTileMode::kRepeat;
result.fShaderType = ShaderCombo::ShaderType::kSolidColor;
result.fTileMode = SkTileMode::kClamp;
uniforms = make_solid_uniform_data(p.getColor4f());
uniforms = make_solid_uniform_data(p.color());
}
result.fBlendMode = p.getBlendMode_or(SkBlendMode::kSrcOver);
result.fBlendMode = p.blendMode();
sk_sp<UniformData> trueUD = cache->findOrCreate(std::move(uniforms));
return { result, std::move(trueUD) };
@ -320,6 +322,8 @@ std::string GetMSLUniformStruct(ShaderCombo::ShaderType shaderType) {
case ShaderCombo::ShaderType::kConicalGradient:
return emit_MSL_uniform_struct(kGradientUniforms, kNumGradientUniforms);
case ShaderCombo::ShaderType::kNone:
return "";
case ShaderCombo::ShaderType::kSolidColor:
default:
return emit_MSL_uniform_struct(kSolidUniforms, kNumSolidUniforms);
}

View File

@ -13,15 +13,14 @@
#include "include/core/SkRefCnt.h"
#include "include/core/SkTileMode.h"
class SkPaint;
namespace skgpu {
class PaintParams;
class Uniform;
class UniformCache;
// A single, fully specified combination resulting from a PaintCombo (i.e., it corresponds to a
// specific SkPaint)
// specific skgpu::PaintParams object (a subset of SkPaint))
struct Combination {
bool operator==(const Combination& other) const {
return fShaderType == other.fShaderType &&
@ -29,8 +28,16 @@ struct Combination {
fBlendMode == other.fBlendMode;
}
uint32_t key() const {
return (static_cast<int>(fShaderType) << 9) | // 6 values -> 3 bits
(static_cast<int>(fTileMode) << 7) | // 4 values -> 2 bits
(static_cast<int>(fBlendMode) << 2); // 29 values -> 5 bits
}
ShaderCombo::ShaderType fShaderType = ShaderCombo::ShaderType::kNone;
SkTileMode fTileMode = SkTileMode::kRepeat;
// Tile mode and blend mode are ignored if shader type is kNone; tile mode is ignored if
// shader type is kSolidColor.
SkTileMode fTileMode = SkTileMode::kClamp;
SkBlendMode fBlendMode = SkBlendMode::kSrc;
};
@ -86,7 +93,7 @@ private:
const size_t fDataSize;
};
std::tuple<Combination, sk_sp<UniformData>> ExtractCombo(UniformCache*, const SkPaint&);
std::tuple<Combination, sk_sp<UniformData>> ExtractCombo(UniformCache*, const PaintParams&);
std::string GetMSLUniformStruct(ShaderCombo::ShaderType);
} // namespace skgpu

View File

@ -278,14 +278,10 @@ void Device::drawShape(const Shape& shape,
// A draw's order always depends on the clips that must be drawn before it
order.dependsOnPaintersOrder(clipOrder);
auto blendMode = paint.asBlendMode();
PaintParams shading{paint.getColor4f(),
blendMode.has_value() ? *blendMode : SkBlendMode::kSrcOver,
paint.refShader()};
// If a draw is not opaque, it must be drawn after the most recent draw it intersects with in
// order to blend correctly. We always query the most recent draw (even when opaque) because it
// also lets Device easily track whether or not there are any overlapping draws.
PaintParams shading{paint};
const bool opaque = is_opaque(shading);
CompressedPaintersOrder prevDraw =
fColorDepthBoundsManager->getMostRecentDraw(clip.drawBounds());

View File

@ -18,21 +18,16 @@ PaintParams::PaintParams(const SkColor4f& color,
sk_sp<SkShader> shader)
: fColor(color)
, fBlendMode(blendMode)
, fShader(std::move(shader)) {
}
PaintParams::PaintParams(const PaintParams& other)
: fColor(other.fColor)
, fBlendMode(other.fBlendMode)
, fShader(other.fShader) {
}
PaintParams::~PaintParams() {}
, fShader(std::move(shader)) {}
PaintParams& PaintParams::operator=(const PaintParams& other) {
fColor = other.fColor;
fBlendMode = other.fBlendMode;
fShader = other.fShader;
return *this;
}
PaintParams::PaintParams(const SkPaint& paint)
: fColor(paint.getColor4f())
, fBlendMode(paint.getBlendMode_or(SkBlendMode::kSrcOver))
, fShader(paint.refShader()) {}
PaintParams::PaintParams(const PaintParams& other) = default;
PaintParams::~PaintParams() = default;
PaintParams& PaintParams::operator=(const PaintParams& other) = default;
sk_sp<SkShader> PaintParams::refShader() const { return fShader; }

View File

@ -38,6 +38,8 @@ struct VertexWriter;
class PaintParams {
public:
PaintParams(const SkColor4f& color, SkBlendMode, sk_sp<SkShader>);
explicit PaintParams(const SkPaint& paint);
PaintParams(const PaintParams&);
~PaintParams();

View File

@ -31,15 +31,8 @@ namespace {
// Retrieve the program ID and uniformData ID
std::tuple<uint32_t, uint32_t> get_ids_from_paint(skgpu::Recorder* recorder,
skgpu::PaintParams params) {
// TODO: add an ExtractCombo that takes PaintParams directly?
SkPaint p;
p.setColor(params.color());
p.setBlendMode(params.blendMode());
p.setShader(params.refShader());
// TODO: perhaps just return the ids here rather than the sk_sps?
auto [ combo, uniformData] = ExtractCombo(recorder->uniformCache(), p);
auto [ combo, uniformData] = ExtractCombo(recorder->uniformCache(), params);
auto programInfo = recorder->programCache()->findOrCreateProgram(combo);
return { programInfo->id(), uniformData->id() };

View File

@ -46,10 +46,18 @@ std::string ProgramCache::ProgramInfo::getMSL() const {
"return result;\n"
"}\n");
break;
case ShaderCombo::ShaderType::kNone:
// TODO: kNone is for depth-only draws, so should actually have a fragment output type
// that only defines a [[depth]] attribute but no color calculation.
msl +=
"fragment float4 fragmentMain(VertexOutput interpolated [[stage_in]]) {\n"
" return float4(0.0, 0.0, 1.0, 1.0);\n"
"}\n";
break;
case ShaderCombo::ShaderType::kRadialGradient:
case ShaderCombo::ShaderType::kSweepGradient:
case ShaderCombo::ShaderType::kConicalGradient:
case ShaderCombo::ShaderType::kNone:
case ShaderCombo::ShaderType::kSolidColor:
default:
msl += std::string(
"fragment float4 fragmentShader(VertexOut interpolated [[stage_in]],\n"

View File

@ -23,7 +23,9 @@ DEF_GRAPHITE_TEST_FOR_CONTEXTS(ProgramCacheTest, reporter, context) {
// Add an initial unique program
sk_sp<ProgramCache::ProgramInfo> pi1;
{
Combination c1 { ShaderCombo::ShaderType::kNone, SkTileMode::kRepeat, SkBlendMode::kSrc };
Combination c1 { ShaderCombo::ShaderType::kSolidColor,
SkTileMode::kRepeat,
SkBlendMode::kSrc };
pi1 = cache->findOrCreateProgram(c1);
REPORTER_ASSERT(reporter, pi1->id() != ProgramCache::kInvalidProgramID);
REPORTER_ASSERT(reporter, pi1->combo() == c1);
@ -35,7 +37,9 @@ DEF_GRAPHITE_TEST_FOR_CONTEXTS(ProgramCacheTest, reporter, context) {
// Try to add a duplicate program
{
Combination c2 { ShaderCombo::ShaderType::kNone, SkTileMode::kRepeat, SkBlendMode::kSrc };
Combination c2 { ShaderCombo::ShaderType::kSolidColor,
SkTileMode::kRepeat,
SkBlendMode::kSrc };
sk_sp<ProgramCache::ProgramInfo> pi2 = cache->findOrCreateProgram(c2);
REPORTER_ASSERT(reporter, pi2->id() != ProgramCache::kInvalidProgramID);
REPORTER_ASSERT(reporter, pi2->id() == pi1->id());

View File

@ -8,6 +8,7 @@
#include "tests/Test.h"
#include "experimental/graphite/src/ContextUtils.h"
#include "experimental/graphite/src/DrawList.h" // TODO: split PaintParams out into their own header
#include "experimental/graphite/src/UniformCache.h"
#include "include/core/SkPaint.h"
#include "include/effects/SkGradientShader.h"
@ -24,6 +25,9 @@ std::tuple<SkPaint, int> create_paint(skgpu::Combination combo) {
int numUniforms = 0;
switch (combo.fShaderType) {
case skgpu::ShaderCombo::ShaderType::kNone:
SkDEBUGFAIL("kNone cannot be represented as an SkPaint");
break;
case skgpu::ShaderCombo::ShaderType::kSolidColor:
numUniforms += 1;
break;
case skgpu::ShaderCombo::ShaderType::kLinearGradient:
@ -60,7 +64,9 @@ DEF_GRAPHITE_TEST(UniformTest, reporter) {
UniformCache cache;
for (auto s : { ShaderCombo::ShaderType::kNone,
// Intentionally does not include ShaderType::kNone, which represents no fragment shading stage
// and is thus not relevant to uniform extraction/caching.
for (auto s : { ShaderCombo::ShaderType::kSolidColor,
ShaderCombo::ShaderType::kLinearGradient,
ShaderCombo::ShaderType::kRadialGradient,
ShaderCombo::ShaderType::kSweepGradient,
@ -69,8 +75,8 @@ DEF_GRAPHITE_TEST(UniformTest, reporter) {
SkTileMode::kRepeat,
SkTileMode::kMirror,
SkTileMode::kDecal }) {
if (s == ShaderCombo::ShaderType::kNone) {
tm = SkTileMode::kRepeat; // the TileMode doesn't matter for this case
if (s == ShaderCombo::ShaderType::kSolidColor) {
tm = SkTileMode::kClamp; // the TileMode doesn't matter for this case
}
for (auto bm : { SkBlendMode::kSrc, SkBlendMode::kSrcOver }) {
@ -81,7 +87,7 @@ DEF_GRAPHITE_TEST(UniformTest, reporter) {
expected.fBlendMode = bm;
auto [ p, expectedNumUniforms ] = create_paint(expected);
auto [ actual, ud] = ExtractCombo(&cache, p);
auto [ actual, ud] = ExtractCombo(&cache, PaintParams(p));
REPORTER_ASSERT(reporter, expected == actual);
REPORTER_ASSERT(reporter, expectedNumUniforms == ud->count());
for (int i = 0; i < ud->count(); ++i) {