[graphite] Add fixed-function blending support
Bug: skia:12701 Change-Id: I1fd8dede3eb216c28408bd613119448704c0e7c7 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/512356 Reviewed-by: Michael Ludwig <michaelludwig@google.com> Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
02527b7182
commit
44263c5d08
@ -328,16 +328,104 @@ MTLVertexDescriptor* create_vertex_descriptor(const RenderStep* step) {
|
|||||||
return vertexDescriptor;
|
return vertexDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: share this w/ Ganesh Metal backend?
|
||||||
|
static MTLBlendFactor blend_coeff_to_mtl_blend(skgpu::BlendCoeff coeff) {
|
||||||
|
switch (coeff) {
|
||||||
|
case skgpu::BlendCoeff::kZero:
|
||||||
|
return MTLBlendFactorZero;
|
||||||
|
case skgpu::BlendCoeff::kOne:
|
||||||
|
return MTLBlendFactorOne;
|
||||||
|
case skgpu::BlendCoeff::kSC:
|
||||||
|
return MTLBlendFactorSourceColor;
|
||||||
|
case skgpu::BlendCoeff::kISC:
|
||||||
|
return MTLBlendFactorOneMinusSourceColor;
|
||||||
|
case skgpu::BlendCoeff::kDC:
|
||||||
|
return MTLBlendFactorDestinationColor;
|
||||||
|
case skgpu::BlendCoeff::kIDC:
|
||||||
|
return MTLBlendFactorOneMinusDestinationColor;
|
||||||
|
case skgpu::BlendCoeff::kSA:
|
||||||
|
return MTLBlendFactorSourceAlpha;
|
||||||
|
case skgpu::BlendCoeff::kISA:
|
||||||
|
return MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
case skgpu::BlendCoeff::kDA:
|
||||||
|
return MTLBlendFactorDestinationAlpha;
|
||||||
|
case skgpu::BlendCoeff::kIDA:
|
||||||
|
return MTLBlendFactorOneMinusDestinationAlpha;
|
||||||
|
case skgpu::BlendCoeff::kConstC:
|
||||||
|
return MTLBlendFactorBlendColor;
|
||||||
|
case skgpu::BlendCoeff::kIConstC:
|
||||||
|
return MTLBlendFactorOneMinusBlendColor;
|
||||||
|
case skgpu::BlendCoeff::kS2C:
|
||||||
|
if (@available(macOS 10.12, iOS 11.0, *)) {
|
||||||
|
return MTLBlendFactorSource1Color;
|
||||||
|
} else {
|
||||||
|
return MTLBlendFactorZero;
|
||||||
|
}
|
||||||
|
case skgpu::BlendCoeff::kIS2C:
|
||||||
|
if (@available(macOS 10.12, iOS 11.0, *)) {
|
||||||
|
return MTLBlendFactorOneMinusSource1Color;
|
||||||
|
} else {
|
||||||
|
return MTLBlendFactorZero;
|
||||||
|
}
|
||||||
|
case skgpu::BlendCoeff::kS2A:
|
||||||
|
if (@available(macOS 10.12, iOS 11.0, *)) {
|
||||||
|
return MTLBlendFactorSource1Alpha;
|
||||||
|
} else {
|
||||||
|
return MTLBlendFactorZero;
|
||||||
|
}
|
||||||
|
case skgpu::BlendCoeff::kIS2A:
|
||||||
|
if (@available(macOS 10.12, iOS 11.0, *)) {
|
||||||
|
return MTLBlendFactorOneMinusSource1Alpha;
|
||||||
|
} else {
|
||||||
|
return MTLBlendFactorZero;
|
||||||
|
}
|
||||||
|
case skgpu::BlendCoeff::kIllegal:
|
||||||
|
return MTLBlendFactorZero;
|
||||||
|
}
|
||||||
|
|
||||||
|
SK_ABORT("Unknown blend coefficient");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: share this w/ Ganesh Metal backend?
|
||||||
|
static MTLBlendOperation blend_equation_to_mtl_blend_op(skgpu::BlendEquation equation) {
|
||||||
|
static const MTLBlendOperation gTable[] = {
|
||||||
|
MTLBlendOperationAdd, // skgpu::BlendEquation::kAdd
|
||||||
|
MTLBlendOperationSubtract, // skgpu::BlendEquation::kSubtract
|
||||||
|
MTLBlendOperationReverseSubtract, // skgpu::BlendEquation::kReverseSubtract
|
||||||
|
};
|
||||||
|
static_assert(SK_ARRAY_COUNT(gTable) == (int)skgpu::BlendEquation::kFirstAdvanced);
|
||||||
|
static_assert(0 == (int)skgpu::BlendEquation::kAdd);
|
||||||
|
static_assert(1 == (int)skgpu::BlendEquation::kSubtract);
|
||||||
|
static_assert(2 == (int)skgpu::BlendEquation::kReverseSubtract);
|
||||||
|
|
||||||
|
SkASSERT((unsigned)equation < skgpu::kBlendEquationCnt);
|
||||||
|
return gTable[(int)equation];
|
||||||
|
}
|
||||||
|
|
||||||
static MTLRenderPipelineColorAttachmentDescriptor* create_color_attachment(
|
static MTLRenderPipelineColorAttachmentDescriptor* create_color_attachment(
|
||||||
MTLPixelFormat format,
|
MTLPixelFormat format,
|
||||||
const SkPipelineData::BlendInfo& blendInfo) {
|
const SkPipelineData::BlendInfo& blendInfo) {
|
||||||
|
|
||||||
|
skgpu::BlendEquation equation = blendInfo.fEquation;
|
||||||
|
skgpu::BlendCoeff srcCoeff = blendInfo.fSrcBlend;
|
||||||
|
skgpu::BlendCoeff dstCoeff = blendInfo.fDstBlend;
|
||||||
|
bool blendOn = !skgpu::BlendShouldDisable(equation, srcCoeff, dstCoeff);
|
||||||
|
|
||||||
// TODO: I *think* this gets cleaned up by the pipelineDescriptor?
|
// TODO: I *think* this gets cleaned up by the pipelineDescriptor?
|
||||||
auto mtlColorAttachment = [[MTLRenderPipelineColorAttachmentDescriptor alloc] init];
|
auto mtlColorAttachment = [[MTLRenderPipelineColorAttachmentDescriptor alloc] init];
|
||||||
|
|
||||||
mtlColorAttachment.pixelFormat = format;
|
mtlColorAttachment.pixelFormat = format;
|
||||||
|
|
||||||
mtlColorAttachment.blendingEnabled = FALSE;
|
mtlColorAttachment.blendingEnabled = blendOn;
|
||||||
|
|
||||||
|
if (blendOn) {
|
||||||
|
mtlColorAttachment.sourceRGBBlendFactor = blend_coeff_to_mtl_blend(srcCoeff);
|
||||||
|
mtlColorAttachment.destinationRGBBlendFactor = blend_coeff_to_mtl_blend(dstCoeff);
|
||||||
|
mtlColorAttachment.rgbBlendOperation = blend_equation_to_mtl_blend_op(equation);
|
||||||
|
mtlColorAttachment.sourceAlphaBlendFactor = blend_coeff_to_mtl_blend(srcCoeff);
|
||||||
|
mtlColorAttachment.destinationAlphaBlendFactor = blend_coeff_to_mtl_blend(dstCoeff);
|
||||||
|
mtlColorAttachment.alphaBlendOperation = blend_equation_to_mtl_blend_op(equation);
|
||||||
|
}
|
||||||
|
|
||||||
mtlColorAttachment.writeMask = blendInfo.fWritesColor ? MTLColorWriteMaskAll
|
mtlColorAttachment.writeMask = blendInfo.fWritesColor ? MTLColorWriteMaskAll
|
||||||
: MTLColorWriteMaskNone;
|
: MTLColorWriteMaskNone;
|
||||||
|
@ -50,8 +50,47 @@ sk_sp<SkShader> create_image_shader() {
|
|||||||
sk_sp<SkShader> create_blend_shader(SkBlendMode bm) {
|
sk_sp<SkShader> create_blend_shader(SkBlendMode bm) {
|
||||||
constexpr SkColor4f kTransYellow = {1.0f, 1.0f, 0.0f, 0.5f};
|
constexpr SkColor4f kTransYellow = {1.0f, 1.0f, 0.0f, 0.5f};
|
||||||
|
|
||||||
sk_sp<SkShader> solid = SkShaders::Color(kTransYellow, nullptr);
|
sk_sp<SkShader> dst = SkShaders::Color(kTransYellow, nullptr);
|
||||||
return SkShaders::Blend(bm, std::move(solid), create_image_shader());
|
return SkShaders::Blend(bm, std::move(dst), create_image_shader());
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_blend_mode_swatches(SkCanvas* canvas, SkRect clipRect) {
|
||||||
|
static const int kTileHeight = 16;
|
||||||
|
static const int kTileWidth = 16;
|
||||||
|
static const SkColor4f kOpaqueWhite { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||||
|
static const SkColor4f kTransBluish { 0.0f, 0.5f, 1.0f, 0.5f };
|
||||||
|
static const SkColor4f kTransWhite { 1.0f, 1.0f, 1.0f, 0.75f };
|
||||||
|
|
||||||
|
SkPaint dstPaint;
|
||||||
|
dstPaint.setColor(kOpaqueWhite);
|
||||||
|
dstPaint.setBlendMode(SkBlendMode::kSrc);
|
||||||
|
dstPaint.setAntiAlias(false);
|
||||||
|
|
||||||
|
SkPaint srcPaint;
|
||||||
|
srcPaint.setColor(kTransBluish);
|
||||||
|
srcPaint.setAntiAlias(false);
|
||||||
|
|
||||||
|
SkRect r = SkRect::MakeXYWH(clipRect.fLeft, clipRect.fTop, kTileWidth, kTileHeight);
|
||||||
|
|
||||||
|
// For the first pass we draw: transparent bluish on top of opaque white
|
||||||
|
// For the second pass we draw: transparent white on top of transparent bluish
|
||||||
|
for (int passes = 0; passes < 2; ++passes) {
|
||||||
|
for (int i = 0; i <= (int)SkBlendMode::kLastCoeffMode; ++i) {
|
||||||
|
if (r.fLeft+kTileWidth > clipRect.fRight) {
|
||||||
|
r.offsetTo(clipRect.fLeft, r.fTop+kTileHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas->drawRect(r.makeInset(1.0f, 1.0f), dstPaint);
|
||||||
|
srcPaint.setBlendMode(static_cast<SkBlendMode>(i));
|
||||||
|
canvas->drawRect(r.makeInset(2.0f, 2.0f), srcPaint);
|
||||||
|
|
||||||
|
r.offset(kTileWidth, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
r.offsetTo(clipRect.fLeft, r.fTop+kTileHeight);
|
||||||
|
srcPaint.setColor(kTransWhite);
|
||||||
|
dstPaint.setColor(kTransBluish);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
@ -62,17 +101,20 @@ namespace skiagm {
|
|||||||
class GraphiteStartGM : public GM {
|
class GraphiteStartGM : public GM {
|
||||||
public:
|
public:
|
||||||
GraphiteStartGM() {
|
GraphiteStartGM() {
|
||||||
this->setBGColor(0xFFCCCCCC);
|
this->setBGColor(SK_ColorBLACK);
|
||||||
GetResourceAsBitmap("images/color_wheel.gif", &fBitmap);
|
GetResourceAsBitmap("images/color_wheel.gif", &fBitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
static const int kWidth = 256;
|
||||||
|
static const int kHeight = 384;
|
||||||
|
|
||||||
SkString onShortName() override {
|
SkString onShortName() override {
|
||||||
return SkString("graphitestart");
|
return SkString("graphitestart");
|
||||||
}
|
}
|
||||||
|
|
||||||
SkISize onISize() override {
|
SkISize onISize() override {
|
||||||
return SkISize::Make(256, 384);
|
return SkISize::Make(kWidth, kHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onDraw(SkCanvas* canvas) override {
|
void onDraw(SkCanvas* canvas) override {
|
||||||
@ -110,8 +152,11 @@ protected:
|
|||||||
// TODO: failing serialize test on Linux, not sure what's going on
|
// TODO: failing serialize test on Linux, not sure what's going on
|
||||||
canvas->writePixels(fBitmap, 0, 256);
|
canvas->writePixels(fBitmap, 0, 256);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
draw_blend_mode_swatches(canvas, SkRect::MakeXYWH(128, 256, 128, 128));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
SkBitmap fBitmap;
|
SkBitmap fBitmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ enum class SkBuiltInCodeSnippetID : uint8_t {
|
|||||||
kBlendShader, // aka ComposeShader
|
kBlendShader, // aka ComposeShader
|
||||||
|
|
||||||
// BlendMode code snippets
|
// BlendMode code snippets
|
||||||
|
kFixedFunctionBlender,
|
||||||
kShaderBasedBlender,
|
kShaderBasedBlender,
|
||||||
|
|
||||||
kLast = kShaderBasedBlender
|
kLast = kShaderBasedBlender
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#ifdef SK_GRAPHITE_ENABLED
|
#ifdef SK_GRAPHITE_ENABLED
|
||||||
#include "experimental/graphite/src/UniformManager.h"
|
#include "experimental/graphite/src/UniformManager.h"
|
||||||
|
#include "src/gpu/Blend.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr SkPMColor4f kErrorColor = { 1, 0, 0, 1 };
|
constexpr SkPMColor4f kErrorColor = { 1, 0, 0, 1 };
|
||||||
@ -471,10 +472,53 @@ void AddToKey(SkShaderCodeDictionary* dict,
|
|||||||
} // namespace BlendShaderBlock
|
} // namespace BlendShaderBlock
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
#ifdef SK_GRAPHITE_ENABLED
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr SkPipelineData::BlendInfo make_simple_blendInfo(skgpu::BlendCoeff srcCoeff,
|
||||||
|
skgpu::BlendCoeff dstCoeff) {
|
||||||
|
return { skgpu::BlendEquation::kAdd,
|
||||||
|
srcCoeff,
|
||||||
|
dstCoeff,
|
||||||
|
SK_PMColor4fTRANSPARENT,
|
||||||
|
skgpu::BlendModifiesDst(skgpu::BlendEquation::kAdd, srcCoeff, dstCoeff) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/*>> No coverage, input color unknown <<*/
|
||||||
|
static constexpr SkPipelineData::BlendInfo gBlendTable[(int)SkBlendMode::kLastCoeffMode + 1] = {
|
||||||
|
/* clear */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kZero),
|
||||||
|
/* src */ make_simple_blendInfo(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kZero),
|
||||||
|
/* dst */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kOne),
|
||||||
|
/* src-over */ make_simple_blendInfo(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISA),
|
||||||
|
/* dst-over */ make_simple_blendInfo(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kOne),
|
||||||
|
/* src-in */ make_simple_blendInfo(skgpu::BlendCoeff::kDA, skgpu::BlendCoeff::kZero),
|
||||||
|
/* dst-in */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kSA),
|
||||||
|
/* src-out */ make_simple_blendInfo(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kZero),
|
||||||
|
/* dst-out */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kISA),
|
||||||
|
/* src-atop */ make_simple_blendInfo(skgpu::BlendCoeff::kDA, skgpu::BlendCoeff::kISA),
|
||||||
|
/* dst-atop */ make_simple_blendInfo(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kSA),
|
||||||
|
/* xor */ make_simple_blendInfo(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kISA),
|
||||||
|
/* plus */ make_simple_blendInfo(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kOne),
|
||||||
|
/* modulate */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kSC),
|
||||||
|
/* screen */ make_simple_blendInfo(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISC)
|
||||||
|
};
|
||||||
|
|
||||||
|
const SkPipelineData::BlendInfo& get_blend_info(SkBlendMode bm) {
|
||||||
|
if (bm <= SkBlendMode::kLastCoeffMode) {
|
||||||
|
return gBlendTable[(int) bm];
|
||||||
|
}
|
||||||
|
|
||||||
|
return gBlendTable[(int) SkBlendMode::kSrc];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
#endif // SK_GRAPHITE_ENABLED
|
||||||
|
|
||||||
namespace BlendModeBlock {
|
namespace BlendModeBlock {
|
||||||
|
|
||||||
#ifdef SK_GRAPHITE_ENABLED
|
#ifdef SK_GRAPHITE_ENABLED
|
||||||
static const int kBlockDataSize = 1;
|
static const int kFixedFunctionBlockDataSize = 1;
|
||||||
|
static const int kShaderBasedBlockDataSize = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void AddToKey(SkShaderCodeDictionary* dict,
|
void AddToKey(SkShaderCodeDictionary* dict,
|
||||||
@ -484,18 +528,32 @@ void AddToKey(SkShaderCodeDictionary* dict,
|
|||||||
|
|
||||||
#ifdef SK_GRAPHITE_ENABLED
|
#ifdef SK_GRAPHITE_ENABLED
|
||||||
if (builder->backend() == SkBackend::kGraphite) {
|
if (builder->backend() == SkBackend::kGraphite) {
|
||||||
|
if (bm <= SkBlendMode::kLastCoeffMode) {
|
||||||
|
builder->beginBlock(SkBuiltInCodeSnippetID::kFixedFunctionBlender);
|
||||||
|
add_blendmode_to_key(builder, bm);
|
||||||
|
builder->endBlock();
|
||||||
|
|
||||||
|
validate_block_header(builder,
|
||||||
|
SkBuiltInCodeSnippetID::kFixedFunctionBlender,
|
||||||
|
kFixedFunctionBlockDataSize);
|
||||||
|
|
||||||
|
if (pipelineData) {
|
||||||
|
pipelineData->setBlendInfo(get_blend_info(bm));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
builder->beginBlock(SkBuiltInCodeSnippetID::kShaderBasedBlender);
|
builder->beginBlock(SkBuiltInCodeSnippetID::kShaderBasedBlender);
|
||||||
add_blendmode_to_key(builder, bm);
|
add_blendmode_to_key(builder, bm);
|
||||||
builder->endBlock();
|
builder->endBlock();
|
||||||
|
|
||||||
validate_block_header(builder,
|
validate_block_header(builder,
|
||||||
SkBuiltInCodeSnippetID::kShaderBasedBlender,
|
SkBuiltInCodeSnippetID::kShaderBasedBlender,
|
||||||
kBlockDataSize);
|
kShaderBasedBlockDataSize);
|
||||||
|
|
||||||
if (pipelineData) {
|
if (pipelineData) {
|
||||||
// TODO: set up the correct blend info
|
// TODO: set up the correct blend info
|
||||||
pipelineData->setBlendInfo(SkPipelineData::BlendInfo());
|
pipelineData->setBlendInfo(SkPipelineData::BlendInfo());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif// SK_GRAPHITE_ENABLED
|
#endif// SK_GRAPHITE_ENABLED
|
||||||
@ -543,7 +601,7 @@ SkUniquePaintParamsID CreateKey(SkShaderCodeDictionary* dict,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: the blendInfo should be filled in by BlendModeBlock::AddToKey
|
// TODO: the blendInfo should be filled in by BlendModeBlock::AddToKey
|
||||||
SkPipelineData::BlendInfo blendInfo;
|
SkPipelineData::BlendInfo blendInfo = get_blend_info(bm);
|
||||||
BlendModeBlock::AddToKey(dict, builder, /* pipelineData*/ nullptr, bm);
|
BlendModeBlock::AddToKey(dict, builder, /* pipelineData*/ nullptr, bm);
|
||||||
SkPaintParamsKey key = builder->lockAsKey();
|
SkPaintParamsKey key = builder->lockAsKey();
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ std::string SkShaderInfo::toSkSL() const {
|
|||||||
std::string result = skgpu::mtl::GetMtlUniforms(2, "FS", fBlockReaders);
|
std::string result = skgpu::mtl::GetMtlUniforms(2, "FS", fBlockReaders);
|
||||||
|
|
||||||
std::set<const char*> emittedStaticSnippets;
|
std::set<const char*> emittedStaticSnippets;
|
||||||
for (auto reader : fBlockReaders) {
|
for (const auto& reader : fBlockReaders) {
|
||||||
const SkShaderSnippet* e = reader.entry();
|
const SkShaderSnippet* e = reader.entry();
|
||||||
if (emittedStaticSnippets.find(e->fStaticFunctionName) == emittedStaticSnippets.end()) {
|
if (emittedStaticSnippets.find(e->fStaticFunctionName) == emittedStaticSnippets.end()) {
|
||||||
result += e->fStaticSkSL;
|
result += e->fStaticSkSL;
|
||||||
@ -326,7 +326,7 @@ static const char* kImageShaderName = "image_shader";
|
|||||||
static const char* kImageShaderSkSL =
|
static const char* kImageShaderSkSL =
|
||||||
"half4 image_shader() {\n"
|
"half4 image_shader() {\n"
|
||||||
" float c = fract(abs(sk_FragCoord.x/10.0));\n"
|
" float c = fract(abs(sk_FragCoord.x/10.0));\n"
|
||||||
" return half4(c, c, c, 1.0);\n"
|
" return half4(1.0, 1.0 - c, 1.0 - c, 1.0);\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
static constexpr int kNumImageShaderFields = 2;
|
static constexpr int kNumImageShaderFields = 2;
|
||||||
@ -447,6 +447,36 @@ static const char* kErrorSkSL =
|
|||||||
" return half4(1.0, 0.0, 1.0, 1.0);\n"
|
" return half4(1.0, 0.0, 1.0, 1.0);\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
static constexpr int kNumFixedFunctionBlenderFields = 1;
|
||||||
|
static constexpr DataPayloadField kFixedFunctionBlenderFields[kNumFixedFunctionBlenderFields] = {
|
||||||
|
{ "blendmode", SkPaintParamsKey::DataPayloadType::kByte, 1 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// This method generates the glue code for the case where the SkBlendMode-based blending is
|
||||||
|
// handled with fixed function blending.
|
||||||
|
std::string GenerateFixedFunctionBlenderGlueCode(const std::string& resultName,
|
||||||
|
int entryIndex,
|
||||||
|
const SkPaintParamsKey::BlockReader& reader,
|
||||||
|
const std::string& priorStageOutputName,
|
||||||
|
const std::vector<std::string>& childNames,
|
||||||
|
int indent) {
|
||||||
|
SkASSERT(childNames.empty());
|
||||||
|
SkASSERT(reader.entry()->fUniforms.empty());
|
||||||
|
SkASSERT(reader.numDataPayloadFields() == 1);
|
||||||
|
|
||||||
|
// The actual blending is set up via the fixed function pipeline so we don't actually
|
||||||
|
// need to access the blend mode in the glue code.
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
add_indent(&result, indent);
|
||||||
|
result += "// Fixed-function blending\n";
|
||||||
|
add_indent(&result, indent);
|
||||||
|
SkSL::String::appendf(&result, "%s = %s;", resultName.c_str(), priorStageOutputName.c_str());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
static constexpr int kNumShaderBasedBlenderFields = 1;
|
static constexpr int kNumShaderBasedBlenderFields = 1;
|
||||||
static constexpr DataPayloadField kShaderBasedBlenderFields[kNumShaderBasedBlenderFields] = {
|
static constexpr DataPayloadField kShaderBasedBlenderFields[kNumShaderBasedBlenderFields] = {
|
||||||
@ -471,6 +501,8 @@ std::string GenerateShaderBasedBlenderGlueCode(const std::string& resultName,
|
|||||||
|
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
|
add_indent(&result, indent);
|
||||||
|
result += "// Shader-based blending\n";
|
||||||
// TODO: emit code to perform dest read
|
// TODO: emit code to perform dest read
|
||||||
add_indent(&result, indent);
|
add_indent(&result, indent);
|
||||||
result += "half4 dummyDst = half4(1.0, 1.0, 1.0, 1.0);\n";
|
result += "half4 dummyDst = half4(1.0, 1.0, 1.0, 1.0);\n";
|
||||||
@ -577,8 +609,15 @@ SkShaderCodeDictionary::SkShaderCodeDictionary() {
|
|||||||
kNumBlendShaderChildren,
|
kNumBlendShaderChildren,
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
fBuiltInCodeSnippets[(int) SkBuiltInCodeSnippetID::kFixedFunctionBlender] = {
|
||||||
|
{ }, // no uniforms
|
||||||
|
"", "", // fixed function blending doesn't have any static SkSL
|
||||||
|
GenerateFixedFunctionBlenderGlueCode,
|
||||||
|
kNoChildren,
|
||||||
|
{ kFixedFunctionBlenderFields, kNumFixedFunctionBlenderFields }
|
||||||
|
};
|
||||||
fBuiltInCodeSnippets[(int) SkBuiltInCodeSnippetID::kShaderBasedBlender] = {
|
fBuiltInCodeSnippets[(int) SkBuiltInCodeSnippetID::kShaderBasedBlender] = {
|
||||||
{ },
|
{ }, // no uniforms
|
||||||
kBlendHelperName, kBlendHelperSkSL,
|
kBlendHelperName, kBlendHelperSkSL,
|
||||||
GenerateShaderBasedBlenderGlueCode,
|
GenerateShaderBasedBlenderGlueCode,
|
||||||
kNoChildren,
|
kNoChildren,
|
||||||
|
@ -16,7 +16,7 @@ namespace skgpu {
|
|||||||
/**
|
/**
|
||||||
* Equations for alpha-blending.
|
* Equations for alpha-blending.
|
||||||
*/
|
*/
|
||||||
enum class BlendEquation {
|
enum class BlendEquation : uint8_t {
|
||||||
// Basic blend equations.
|
// Basic blend equations.
|
||||||
kAdd, //<! Cs*S + Cd*D
|
kAdd, //<! Cs*S + Cd*D
|
||||||
kSubtract, //<! Cs*S - Cd*D
|
kSubtract, //<! Cs*S - Cd*D
|
||||||
@ -51,7 +51,7 @@ static const int kBlendEquationCnt = static_cast<int>(BlendEquation::kLast) + 1;
|
|||||||
/**
|
/**
|
||||||
* Coefficients for alpha-blending.
|
* Coefficients for alpha-blending.
|
||||||
*/
|
*/
|
||||||
enum class BlendCoeff {
|
enum class BlendCoeff : uint8_t {
|
||||||
kZero, //<! 0
|
kZero, //<! 0
|
||||||
kOne, //<! 1
|
kOne, //<! 1
|
||||||
kSC, //<! src color
|
kSC, //<! src color
|
||||||
|
@ -95,20 +95,26 @@ DEF_GRAPHITE_TEST_FOR_CONTEXTS(UniformTest, reporter, context) {
|
|||||||
|
|
||||||
for (auto bm : { SkBlendMode::kSrc, SkBlendMode::kSrcOver }) {
|
for (auto bm : { SkBlendMode::kSrc, SkBlendMode::kSrcOver }) {
|
||||||
auto [ p, expectedNumUniforms ] = create_paint(s, tm, bm);
|
auto [ p, expectedNumUniforms ] = create_paint(s, tm, bm);
|
||||||
auto [ uniqueID1, uniformBlock] = ExtractPaintData(dict, &builder, PaintParams(p));
|
|
||||||
int actualNumUniforms = uniformBlock->count();
|
auto [ uniqueID1, pipelineData] = ExtractPaintData(dict, &builder, PaintParams(p));
|
||||||
|
|
||||||
SkUniquePaintParamsID uniqueID2 = CreateKey(dict, &builder, s, tm, bm);
|
SkUniquePaintParamsID uniqueID2 = CreateKey(dict, &builder, s, tm, bm);
|
||||||
|
|
||||||
// ExtractPaintData and CreateKey agree
|
// ExtractPaintData and CreateKey agree
|
||||||
REPORTER_ASSERT(reporter, uniqueID1 == uniqueID2);
|
REPORTER_ASSERT(reporter, uniqueID1 == uniqueID2);
|
||||||
|
|
||||||
|
// ExtractPaintData made the pipeline data we expected
|
||||||
|
{
|
||||||
|
int actualNumUniforms = pipelineData->count();
|
||||||
REPORTER_ASSERT(reporter, expectedNumUniforms == actualNumUniforms);
|
REPORTER_ASSERT(reporter, expectedNumUniforms == actualNumUniforms);
|
||||||
for (auto& u : *uniformBlock) {
|
for (const auto& u: *pipelineData) {
|
||||||
for (int i = 0; i < u->count(); ++i) {
|
for (int i = 0; i < u->count(); ++i) {
|
||||||
REPORTER_ASSERT(reporter,
|
REPORTER_ASSERT(reporter,
|
||||||
u->offset(i) >= 0 && u->offset(i) < u->dataSize());
|
u->offset(i) >= 0 && u->offset(i) < u->dataSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: check the blendInfo here too
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user