SkRuntimeEffect: Support late bound uniforms in raster

Supports marked matrices and srgb_unpremul colors

Change-Id: Icabd329758ac0a12ee323d73724d68c7927106c3
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/289242
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
Brian Osman 2020-05-12 13:40:01 -04:00 committed by Skia Commit-Bot
parent da50cb84a4
commit 7190399725
5 changed files with 64 additions and 39 deletions

View File

@ -13,8 +13,8 @@
// See skia.org/user/color (== site/user/color.md).
SkColorSpaceXformSteps::SkColorSpaceXformSteps(SkColorSpace* src, SkAlphaType srcAT,
SkColorSpace* dst, SkAlphaType dstAT) {
SkColorSpaceXformSteps::SkColorSpaceXformSteps(const SkColorSpace* src, SkAlphaType srcAT,
const SkColorSpace* dst, SkAlphaType dstAT) {
// Opaque outputs are treated as the same alpha type as the source input.
// TODO: we'd really like to have a good way of explaining why we think this is useful.
if (dstAT == kOpaque_SkAlphaType) {

View File

@ -33,8 +33,8 @@ struct SkColorSpaceXformSteps {
}
};
SkColorSpaceXformSteps(SkColorSpace* src, SkAlphaType srcAT,
SkColorSpace* dst, SkAlphaType dstAT);
SkColorSpaceXformSteps(const SkColorSpace* src, SkAlphaType srcAT,
const SkColorSpace* dst, SkAlphaType dstAT);
template <typename S, typename D>
SkColorSpaceXformSteps(const S& src, const D& dst)

View File

@ -11,6 +11,7 @@
#include "include/core/SkColor.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkTileMode.h"
#include "include/core/SkTypes.h"
#include "include/private/SkNx.h"
@ -19,6 +20,8 @@
#include <functional>
#include <vector> // TODO: unused
class SkData;
/**
* SkRasterPipeline provides a cheap way to chain together a pixel processing pipeline.
*
@ -170,7 +173,7 @@ struct SkRasterPipeline_InterpreterCtx {
const SkSL::ByteCodeFunction* fn;
SkColor4f paintColor;
const void* inputs;
sk_sp<SkData> inputs;
int ninputs;
bool shaderConvention; // if false, we're a colorfilter
};

View File

@ -11,6 +11,8 @@
#include "include/private/SkChecksum.h"
#include "include/private/SkMutex.h"
#include "src/core/SkCanvasPriv.h"
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkColorSpaceXformSteps.h"
#include "src/core/SkMatrixProvider.h"
#include "src/core/SkRasterPipeline.h"
#include "src/core/SkReadBuffer.h"
@ -685,7 +687,7 @@ public:
bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
auto ctx = rec.fAlloc->make<SkRasterPipeline_InterpreterCtx>();
// don't need to set ctx->paintColor
ctx->inputs = fInputs->data();
ctx->inputs = fInputs;
ctx->ninputs = fEffect->uniformSize() / 4;
ctx->shaderConvention = false;
@ -792,31 +794,27 @@ public:
bool isOpaque() const override { return fIsOpaque; }
#if SK_SUPPORT_GPU
std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs& args) const override {
SkMatrix matrix;
if (!this->totalLocalMatrix(args.fPreLocalMatrix)->invert(&matrix)) {
return nullptr;
}
// If any of our uniforms are late-bound (eg, layout(marker)), we need to clone the blob
sk_sp<SkData> inputs = fInputs;
auto copyOnWrite = [&]() {
if (inputs == fInputs) {
inputs = SkData::MakeWithCopy(fInputs->data(), fInputs->size());
}
};
sk_sp<SkData> getUniforms(const SkMatrixProvider& matrixProvider,
const SkColorSpace* dstCS) const {
using Flags = SkRuntimeEffect::Variable::Flags;
using Type = SkRuntimeEffect::Variable::Type;
SkColorSpaceXformSteps steps(sk_srgb_singleton(), kUnpremul_SkAlphaType,
dstCS, kUnpremul_SkAlphaType);
sk_sp<SkData> inputs = nullptr;
auto writableData = [&]() {
if (!inputs) {
inputs = SkData::MakeWithCopy(fInputs->data(), fInputs->size());
}
return inputs->writable_data();
};
for (const auto& v : fEffect->inputs()) {
if (v.fFlags & Flags::kMarker_Flag) {
copyOnWrite();
SkASSERT(v.fType == Type::kFloat4x4);
SkM44* localToMarker = SkTAddOffset<SkM44>(inputs->writable_data(), v.fOffset);
if (!args.fMatrixProvider.getLocalToMarker(v.fMarker, localToMarker)) {
SkM44* localToMarker = SkTAddOffset<SkM44>(writableData(), v.fOffset);
if (!matrixProvider.getLocalToMarker(v.fMarker, localToMarker)) {
// We couldn't provide a matrix that was requested by the SkSL
SkDebugf("Failed to get marked matrix %u\n", v.fMarker);
return nullptr;
}
if (v.fFlags & Flags::kMarkerNormals_Flag) {
@ -831,11 +829,8 @@ public:
}
} else if (v.fFlags & Flags::kSRGBUnpremul_Flag) {
SkASSERT(v.fType == Type::kFloat3 || v.fType == Type::kFloat4);
if (auto xform = args.fDstColorInfo->colorSpaceXformFromSRGB()) {
copyOnWrite();
const SkColorSpaceXformSteps& steps(xform->steps());
float* color = SkTAddOffset<float>(inputs->writable_data(), v.fOffset);
if (steps.flags.mask()) {
float* color = SkTAddOffset<float>(writableData(), v.fOffset);
if (v.fType == Type::kFloat4) {
// RGBA, easy case
for (int i = 0; i < v.fCount; ++i) {
@ -858,6 +853,21 @@ public:
}
}
}
return inputs ? inputs : fInputs;
}
#if SK_SUPPORT_GPU
std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs& args) const override {
SkMatrix matrix;
if (!this->totalLocalMatrix(args.fPreLocalMatrix)->invert(&matrix)) {
return nullptr;
}
sk_sp<SkData> inputs =
this->getUniforms(args.fMatrixProvider, args.fDstColorInfo->colorSpace());
if (!inputs) {
return nullptr;
}
auto fp = GrSkSLFP::Make(args.fContext, fEffect, "runtime_shader", std::move(inputs));
for (const auto& child : fChildren) {
@ -894,7 +904,6 @@ public:
}
bool onAppendStages(const SkStageRec& rec) const override {
// TODO: Populate dynamic uniforms!
SkMatrix inverse;
if (!this->computeTotalInverse(rec.fMatrixProvider.localToDevice(), rec.fLocalM,
&inverse)) {
@ -903,7 +912,10 @@ public:
auto ctx = rec.fAlloc->make<SkRasterPipeline_InterpreterCtx>();
ctx->paintColor = rec.fPaint.getColor4f();
ctx->inputs = fInputs->data();
ctx->inputs = this->getUniforms(rec.fMatrixProvider, rec.fDstCS);
if (!ctx->inputs) {
return false;
}
ctx->ninputs = fEffect->uniformSize() / 4;
ctx->shaderConvention = true;
@ -920,7 +932,7 @@ public:
skvm::Color onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint,
const SkMatrix& ctm, const SkMatrix* localM,
SkFilterQuality, const SkColorInfo& /*dst*/,
SkFilterQuality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc*) const override {
const SkSL::ByteCode* bc = this->byteCode();
if (!bc) {
@ -932,10 +944,19 @@ public:
return {};
}
// TODO: Eventually, plumb SkMatrixProvider here (instead of just ctm). For now, we will
// simply fail if our effect requires any marked matrices (SkSimpleMatrixProvider always
// returns false in getLocalToMarker).
SkSimpleMatrixProvider matrixProvider(SkMatrix::I());
sk_sp<SkData> inputs = this->getUniforms(matrixProvider, dst.colorSpace());
if (!inputs) {
return {};
}
std::vector<skvm::F32> uniform;
for (int i = 0; i < (int)fEffect->uniformSize() / 4; i++) {
float f;
memcpy(&f, (const char*)fInputs->data() + 4*i, 4);
memcpy(&f, (const char*)inputs->data() + 4*i, 4);
uniform.push_back(p->uniformF(uniforms->pushF(f)));
}

View File

@ -8,6 +8,7 @@
#ifndef SkRasterPipeline_opts_DEFINED
#define SkRasterPipeline_opts_DEFINED
#include "include/core/SkData.h"
#include "include/core/SkTypes.h"
#include "src/core/SkUtils.h" // unaligned_{load,store}
#include "src/sksl/SkSLByteCode.h"
@ -2737,8 +2738,8 @@ STAGE(interpreter, SkRasterPipeline_InterpreterCtx* c) {
sk_unaligned_store(aa, a);
}
SkAssertResult(c->byteCode->runStriped(c->fn, tail ? tail : N, in_args, in_count,
nullptr, 0, (const float*)c->inputs, c->ninputs));
SkAssertResult(c->byteCode->runStriped(c->fn, tail ? tail : N, in_args, in_count, nullptr, 0,
(const float*)c->inputs->data(), c->ninputs));
r = sk_unaligned_load<F>(rr);
g = sk_unaligned_load<F>(gg);