Supply device and local coords to SkShader_Base::onProgram

Use that to add support for sk_FragCoord in SkRuntimeEffect.

Change-Id: I587ad97057c13ec8a4052c7c20f655eae88786ba
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/298504
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
Brian Osman 2020-06-22 14:26:03 -04:00 committed by Skia Commit-Bot
parent fe02dd1ee6
commit 5aaaeea4da
33 changed files with 173 additions and 97 deletions

View File

@ -415,7 +415,7 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p,
std::vector<skvm::F32> stack,
/*these parameters are used to call program() on children*/
const std::vector<sk_sp<SkShader>>& children,
skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Coord device, skvm::Color paint,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) {
auto push = [&](skvm::F32 x) { stack.push_back(x); };
@ -483,7 +483,7 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p,
x = pop();
SkOverrideDeviceMatrixProvider mats{matrices, SkMatrix::I()};
skvm::Color c = as_SB(children[ix])->program(p, x,y,paint,
skvm::Color c = as_SB(children[ix])->program(p, device, {x,y},paint,
mats, nullptr,
quality, dst,
uniforms, alloc);
@ -548,6 +548,14 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p,
push(uniform[ix + 3]);
} break;
case Inst::kLoadFragCoord: {
// TODO: Actually supply Z and 1/W from the rasterizer?
push(device.x);
push(device.y);
push(p->splat(0.0f)); // Z
push(p->splat(1.0f)); // 1/W
} break;
case Inst::kStore: {
int ix = u8();
stack[ix + 0] = pop();
@ -828,7 +836,7 @@ public:
std::vector<skvm::F32> stack =
program_fn(p, *fn, uniform, SkSimpleMatrixProvider{SkMatrix::I()}, {c.r, c.g, c.b, c.a},
/* the remaining parameters are for shaders only and won't be used here */
{},{},{},{},{},{},{},{});
{},{},{},{},{},{},{});
if (stack.size() == 4) {
return {stack[0], stack[1], stack[2], stack[3]};
@ -1017,7 +1025,8 @@ public:
return true;
}
skvm::Color onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color onProgram(skvm::Builder* p,
skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider& matrices, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override {
@ -1047,12 +1056,13 @@ public:
if (!this->computeTotalInverse(matrices.localToDevice(), localM, &inv)) {
return {};
}
SkShaderBase::ApplyMatrix(p,inv, &x,&y,uniforms);
SkShaderBase::ApplyMatrix(p,inv, &local,uniforms);
std::vector<skvm::F32> stack =
program_fn(p, *fn, uniform, matrices, {x,y, paint.r, paint.g, paint.b, paint.a},
program_fn(p, *fn, uniform, matrices,
{local.x,local.y, paint.r, paint.g, paint.b, paint.a},
/*parameters for calling program() on children*/
fChildren, x,y,paint, quality,dst, uniforms,alloc);
fChildren, device,paint, quality,dst, uniforms,alloc);
if (stack.size() == 6) {
return {stack[2], stack[3], stack[4], stack[5]};

View File

@ -476,6 +476,12 @@ namespace skvm {
Builder* operator->() const { return a.operator->(); }
};
struct Coord {
F32 x,y;
explicit operator bool() const { return x && y; }
Builder* operator->() const { return x.operator->(); }
};
struct Uniform {
Arg ptr;
int offset;

View File

@ -117,8 +117,9 @@ namespace {
skvm::I32 dx = p.uniform32(uniforms->base, offsetof(BlitterUniforms, right))
- p.index(),
dy = p.uniform32(uniforms->base, offsetof(BlitterUniforms, y));
skvm::F32 x = to_f32(dx) + 0.5f,
y = to_f32(dy) + 0.5f;
skvm::Coord device = {to_f32(dx) + 0.5f,
to_f32(dy) + 0.5f},
local = device;
skvm::Color paint = {
p.uniformF(uniforms->base, offsetof(BlitterUniforms, paint.fR)),
@ -129,7 +130,7 @@ namespace {
uint64_t hash = 0;
if (auto c = sb->program(&p,
x,y, paint,
device,local, paint,
params.matrices, /*localM=*/nullptr,
params.quality, params.dst,
uniforms,alloc)) {
@ -197,8 +198,9 @@ namespace {
skvm::I32 dx = p->uniform32(uniforms->base, offsetof(BlitterUniforms, right))
- p->index(),
dy = p->uniform32(uniforms->base, offsetof(BlitterUniforms, y));
skvm::F32 x = to_f32(dx) + 0.5f,
y = to_f32(dy) + 0.5f;
skvm::Coord device = {to_f32(dx) + 0.5f,
to_f32(dy) + 0.5f},
local = device;
skvm::Color paint = {
p->uniformF(uniforms->base, offsetof(BlitterUniforms, paint.fR)),
@ -207,7 +209,7 @@ namespace {
p->uniformF(uniforms->base, offsetof(BlitterUniforms, paint.fA)),
};
skvm::Color src = as_SB(params.shader)->program(p, x,y, paint,
skvm::Color src = as_SB(params.shader)->program(p, device,local, paint,
params.matrices, /*localM=*/nullptr,
params.quality, params.dst,
uniforms, alloc);
@ -274,7 +276,7 @@ namespace {
}
if (params.clip) {
skvm::Color clip = as_SB(params.clip)->program(p, x,y, paint,
skvm::Color clip = as_SB(params.clip)->program(p, device,local, paint,
params.matrices, /*localM=*/nullptr,
params.quality, params.dst,
uniforms, alloc);
@ -428,12 +430,13 @@ namespace {
bool isOpaque() const override { return fShader->isOpaque(); }
skvm::Color onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color onProgram(skvm::Builder* p,
skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider& matrices, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override {
// Run our wrapped shader.
skvm::Color c = as_SB(fShader)->program(p, x,y, paint,
skvm::Color c = as_SB(fShader)->program(p, device,local, paint,
matrices,localM, quality,dst, uniforms,alloc);
if (!c) {
return {};
@ -467,8 +470,10 @@ namespace {
// See SkRasterPipeline dither stage.
// This is 8x8 ordered dithering. From here we'll only need dx and dx^dy.
skvm::I32 X = trunc(x - 0.5f),
Y = X ^ trunc(y - 0.5f);
SkASSERT(local.x.id == device.x.id);
SkASSERT(local.y.id == device.y.id);
skvm::I32 X = trunc(device.x - 0.5f),
Y = X ^ trunc(device.y - 0.5f);
// If X's low bits are abc and Y's def, M is fcebda,
// 6 bits producing all values [0,63] shuffled over an 8x8 grid.

View File

@ -16,6 +16,7 @@ namespace skvm {
struct I32;
struct F32;
struct Color;
struct Coord;
struct Uniforms;
}

View File

@ -62,12 +62,12 @@ bool SkColorFilterShader::onAppendStages(const SkStageRec& rec) const {
}
skvm::Color SkColorFilterShader::onProgram(skvm::Builder* p,
skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider& matrices, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
// Run the shader.
skvm::Color c = as_SB(fShader)->program(p, x,y, paint,
skvm::Color c = as_SB(fShader)->program(p, device,local, paint,
matrices,localM,
quality,dst,
uniforms,alloc);

View File

@ -26,7 +26,7 @@ private:
void flatten(SkWriteBuffer&) const override;
bool onAppendStages(const SkStageRec&) const override;
skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider&, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc*) const override;

View File

@ -92,7 +92,8 @@ bool SkColor4Shader::onAppendStages(const SkStageRec& rec) const {
}
skvm::Color SkColorShader::onProgram(skvm::Builder* p,
skvm::F32 /*x*/, skvm::F32 /*y*/, skvm::Color /*paint*/,
skvm::Coord /*device*/, skvm::Coord /*local*/,
skvm::Color /*paint*/,
const SkMatrixProvider&, const SkMatrix* /*localM*/,
SkFilterQuality /*quality*/, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc*) const {
@ -100,7 +101,8 @@ skvm::Color SkColorShader::onProgram(skvm::Builder* p,
uniforms, dst.colorSpace());
}
skvm::Color SkColor4Shader::onProgram(skvm::Builder* p,
skvm::F32 /*x*/, skvm::F32 /*y*/, skvm::Color /*paint*/,
skvm::Coord /*device*/, skvm::Coord /*local*/,
skvm::Color /*paint*/,
const SkMatrixProvider&, const SkMatrix* /*localM*/,
SkFilterQuality /*quality*/, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc*) const {

View File

@ -44,7 +44,7 @@ private:
bool onAppendStages(const SkStageRec&) const override;
skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider&, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc*) const override;
@ -69,7 +69,7 @@ private:
void flatten(SkWriteBuffer&) const override;
bool onAppendStages(const SkStageRec&) const override;
skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider&, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc*) const override;

View File

@ -127,13 +127,14 @@ bool SkShader_Blend::onAppendStages(const SkStageRec& orig_rec) const {
return true;
}
skvm::Color SkShader_Blend::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint,
const SkMatrixProvider& matrices, const SkMatrix* localM,
skvm::Color SkShader_Blend::onProgram(skvm::Builder* p,
skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider& mats, const SkMatrix* localM,
SkFilterQuality q, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
skvm::Color d,s;
if ((d = as_SB(fDst)->program(p, x,y, paint, matrices,localM, q, dst, uniforms, alloc)) &&
(s = as_SB(fSrc)->program(p, x,y, paint, matrices,localM, q, dst, uniforms, alloc)))
if ((d = as_SB(fDst)->program(p, device,local, paint, mats,localM, q,dst, uniforms,alloc)) &&
(s = as_SB(fSrc)->program(p, device,local, paint, mats,localM, q,dst, uniforms,alloc)))
{
return p->blend(fMode, s,d);
}
@ -167,13 +168,14 @@ bool SkShader_Lerp::onAppendStages(const SkStageRec& orig_rec) const {
return true;
}
skvm::Color SkShader_Lerp::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint,
const SkMatrixProvider& matrices, const SkMatrix* localM,
skvm::Color SkShader_Lerp::onProgram(skvm::Builder* p,
skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider& mats, const SkMatrix* localM,
SkFilterQuality q, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
skvm::Color d,s;
if ((d = as_SB(fDst)->program(p, x,y, paint, matrices,localM, q, dst, uniforms, alloc)) &&
(s = as_SB(fSrc)->program(p, x,y, paint, matrices,localM, q, dst, uniforms, alloc)))
if ((d = as_SB(fDst)->program(p, device,local, paint, mats,localM, q,dst, uniforms,alloc)) &&
(s = as_SB(fSrc)->program(p, device,local, paint, mats,localM, q,dst, uniforms,alloc)))
{
auto t = p->uniformF(uniforms->pushF(fWeight));
return {

View File

@ -27,7 +27,7 @@ protected:
SkShader_Blend(SkReadBuffer&);
void flatten(SkWriteBuffer&) const override;
bool onAppendStages(const SkStageRec&) const override;
skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider&, const SkMatrix* localM,
SkFilterQuality, const SkColorInfo& dst,
skvm::Uniforms*, SkArenaAlloc*) const override;
@ -60,7 +60,7 @@ protected:
SkShader_Lerp(SkReadBuffer&);
void flatten(SkWriteBuffer&) const override;
bool onAppendStages(const SkStageRec&) const override;
skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider&, const SkMatrix* localM,
SkFilterQuality, const SkColorInfo& dst,
skvm::Uniforms*, SkArenaAlloc*) const override;

View File

@ -37,7 +37,7 @@ protected:
return false;
}
skvm::Color onProgram(skvm::Builder*, skvm::F32, skvm::F32, skvm::Color,
skvm::Color onProgram(skvm::Builder*, skvm::Coord, skvm::Coord, skvm::Color,
const SkMatrixProvider&, const SkMatrix*,
SkFilterQuality, const SkColorInfo&,
skvm::Uniforms*, SkArenaAlloc*) const override;

View File

@ -639,7 +639,8 @@ SkStageUpdater* SkImageShader::onAppendUpdatableStages(const SkStageRec& rec) co
return this->doStages(rec, updater) ? updater : nullptr;
}
skvm::Color SkImageShader::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color SkImageShader::onProgram(skvm::Builder* p,
skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider& matrices, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
@ -663,7 +664,7 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y,
inv.normalizePerspective();
// Apply matrix to convert dst coords to sample center coords.
SkShaderBase::ApplyMatrix(p, inv, &x,&y,uniforms);
SkShaderBase::ApplyMatrix(p, inv, &local, uniforms);
// Bail out if sample() can't yet handle our image's color type.
switch (pm.colorType()) {
@ -788,14 +789,14 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y,
skvm::Color c;
if (quality == kNone_SkFilterQuality) {
c = sample(x,y);
c = sample(local.x,local.y);
} else if (quality == kLow_SkFilterQuality) {
// Our four sample points are the corners of a logical 1x1 pixel
// box surrounding (x,y) at (0.5,0.5) off-center.
skvm::F32 left = x - 0.5f,
top = y - 0.5f,
right = x + 0.5f,
bottom = y + 0.5f;
skvm::F32 left = local.x - 0.5f,
top = local.y - 0.5f,
right = local.x + 0.5f,
bottom = local.y + 0.5f;
// The fractional parts of right and bottom are our lerp factors in x and y respectively.
skvm::F32 fx = fract(right ),
@ -808,8 +809,8 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y,
// All bicubic samples have the same fractional offset (fx,fy) from the center.
// They're either the 16 corners of a 3x3 grid/ surrounding (x,y) at (0.5,0.5) off-center.
skvm::F32 fx = fract(x + 0.5f),
fy = fract(y + 0.5f);
skvm::F32 fx = fract(local.x + 0.5f),
fy = fract(local.y + 0.5f);
// See GrCubicEffect for details of these weights.
// TODO: these maybe don't seem right looking at gm/bicubic and GrBicubicEffect.
@ -836,9 +837,9 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y,
c.r = c.g = c.b = c.a = p->splat(0.0f);
skvm::F32 sy = y - 1.5f;
skvm::F32 sy = local.y - 1.5f;
for (int j = 0; j < 4; j++, sy += 1.0f) {
skvm::F32 sx = x - 1.5f;
skvm::F32 sx = local.x - 1.5f;
for (int i = 0; i < 4; i++, sx += 1.0f) {
skvm::Color s = sample(sx,sy);
skvm::F32 w = wx[i] * wy[j];

View File

@ -58,7 +58,7 @@ private:
bool onAppendStages(const SkStageRec&) const override;
SkStageUpdater* onAppendUpdatableStages(const SkStageRec&) const override;
skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider&, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc*) const override;

View File

@ -78,7 +78,7 @@ bool SkLocalMatrixShader::onAppendStages(const SkStageRec& rec) const {
skvm::Color SkLocalMatrixShader::onProgram(skvm::Builder* p,
skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider& matrices, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
@ -86,7 +86,7 @@ skvm::Color SkLocalMatrixShader::onProgram(skvm::Builder* p,
if (localM) {
lm.writable()->preConcat(*localM);
}
return as_SB(fProxyShader)->program(p, x,y, paint,
return as_SB(fProxyShader)->program(p, device,local, paint,
matrices,lm.get(),
quality,dst,
uniforms,alloc);
@ -156,12 +156,13 @@ protected:
return as_SB(fProxyShader)->appendStages(newRec);
}
skvm::Color onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color onProgram(skvm::Builder* p,
skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider& matrices, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override {
SkOverrideDeviceMatrixProvider matrixProvider(matrices, fCTM);
return as_SB(fProxyShader)->program(p, x,y,paint,
return as_SB(fProxyShader)->program(p, device,local, paint,
matrixProvider,localM,
quality,dst,
uniforms,alloc);

View File

@ -48,7 +48,7 @@ protected:
bool onAppendStages(const SkStageRec&) const override;
skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider&, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc*) const override;

View File

@ -275,7 +275,7 @@ bool SkPictureShader::onAppendStages(const SkStageRec& rec) const {
}
skvm::Color SkPictureShader::onProgram(skvm::Builder* p,
skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider& matrices, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
@ -289,7 +289,10 @@ skvm::Color SkPictureShader::onProgram(skvm::Builder* p,
return {};
}
return as_SB(bitmapShader)->program(p, x,y, paint, matrices, lm, quality, dst, uniforms, alloc);
return as_SB(bitmapShader)->program(p, device,local, paint,
matrices,lm,
quality,dst,
uniforms,alloc);
}
/////////////////////////////////////////////////////////////////////////////////////////

View File

@ -37,7 +37,7 @@ protected:
SkPictureShader(SkReadBuffer&);
void flatten(SkWriteBuffer&) const override;
bool onAppendStages(const SkStageRec&) const override;
skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider&, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override;

View File

@ -195,7 +195,8 @@ bool SkShaderBase::onAppendStages(const SkStageRec& rec) const {
return false;
}
skvm::Color SkShaderBase::program(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color SkShaderBase::program(skvm::Builder* p,
skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider& matrices, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
@ -211,7 +212,8 @@ skvm::Color SkShaderBase::program(skvm::Builder* p, skvm::F32 x, skvm::F32 y, sk
// shader program hash and blitter Key. This makes it safe for us to use
// that bit to make decisions when constructing an SkVMBlitter, like doing
// SrcOver -> Src strength reduction.
if (auto color = this->onProgram(p, x,y, paint, matrices,localM, quality,dst, uniforms,alloc)) {
if (auto color = this->onProgram(p, device,local, paint, matrices,localM, quality,dst,
uniforms,alloc)) {
if (this->isOpaque()) {
color.a = p->splat(1.0f);
}
@ -220,11 +222,12 @@ skvm::Color SkShaderBase::program(skvm::Builder* p, skvm::F32 x, skvm::F32 y, sk
return {};
}
skvm::Color SkShaderBase::onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color SkShaderBase::onProgram(skvm::Builder*,
skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider&, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
//SkDebugf("cannot onProgram %s\n", this->getTypeName());
// SkDebugf("cannot onProgram %s\n", this->getTypeName());
return {};
}
@ -235,7 +238,9 @@ sk_sp<SkShader> SkShaderBase::makeInvertAlpha() const {
void SkShaderBase::ApplyMatrix(skvm::Builder* p, const SkMatrix& m,
skvm::F32* x, skvm::F32* y, skvm::Uniforms* uniforms) {
skvm::Coord* coord, skvm::Uniforms* uniforms) {
skvm::F32 *x = &coord->x,
*y = &coord->y;
if (m.isIdentity()) {
// That was easy.
} else if (m.isTranslate()) {
@ -261,7 +266,7 @@ void SkShaderBase::ApplyMatrix(skvm::Builder* p, const SkMatrix& m,
///////////////////////////////////////////////////////////////////////////////////////////////////
skvm::Color SkEmptyShader::onProgram(skvm::Builder*, skvm::F32, skvm::F32, skvm::Color,
skvm::Color SkEmptyShader::onProgram(skvm::Builder*, skvm::Coord, skvm::Coord, skvm::Color,
const SkMatrixProvider&, const SkMatrix*,
SkFilterQuality, const SkColorInfo&,
skvm::Uniforms*, SkArenaAlloc*) const {

View File

@ -211,7 +211,7 @@ public:
return this->onAppendUpdatableStages(rec);
}
skvm::Color program(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color program(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider&, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const;
@ -241,13 +241,14 @@ protected:
virtual SkStageUpdater* onAppendUpdatableStages(const SkStageRec&) const { return nullptr; }
protected:
static void ApplyMatrix(skvm::Builder*, const SkMatrix&, skvm::F32* x, skvm::F32* y, skvm::Uniforms*);
static void ApplyMatrix(skvm::Builder*, const SkMatrix&, skvm::Coord*, skvm::Uniforms*);
private:
// This is essentially const, but not officially so it can be modified in constructors.
SkMatrix fLocalMatrix;
virtual skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint,
virtual skvm::Color onProgram(skvm::Builder*,
skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider&, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const;

View File

@ -420,7 +420,8 @@ bool SkGradientShaderBase::onAppendStages(const SkStageRec& rec) const {
}
skvm::Color SkGradientShaderBase::onProgram(skvm::Builder* p,
skvm::F32 x, skvm::F32 y, skvm::Color /*paint*/,
skvm::Coord device, skvm::Coord local,
skvm::Color /*paint*/,
const SkMatrixProvider& mats, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dstInfo,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
@ -431,10 +432,10 @@ skvm::Color SkGradientShaderBase::onProgram(skvm::Builder* p,
inv.postConcat(fPtsToUnit);
inv.normalizePerspective();
SkShaderBase::ApplyMatrix(p, inv, &x,&y,uniforms);
SkShaderBase::ApplyMatrix(p, inv, &local, uniforms);
skvm::I32 mask = p->splat(~0);
skvm::F32 t = this->transformT(p,uniforms, x,y, &mask);
skvm::F32 t = this->transformT(p,uniforms, local, &mask);
// Perhaps unexpectedly, clamping is handled naturally by our search, so we
// don't explicitly clamp t to [0,1]. That clamp would break hard stops

View File

@ -79,7 +79,7 @@ protected:
bool onAppendStages(const SkStageRec&) const override;
skvm::Color onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint,
skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint,
const SkMatrixProvider&, const SkMatrix* localM,
SkFilterQuality quality, const SkColorInfo& dstCS,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override;
@ -89,7 +89,7 @@ protected:
// Produce t from (x,y), modifying mask if it should be anything other than ~0.
virtual skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*,
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const = 0;
skvm::Coord coord, skvm::I32* mask) const = 0;
template <typename T, typename... Args>
static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {

View File

@ -76,9 +76,9 @@ void SkLinearGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline*,
}
skvm::F32 SkLinearGradient::transformT(skvm::Builder* p, skvm::Uniforms*,
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const {
skvm::Coord coord, skvm::I32* mask) const {
// We've baked getting t in x into the matrix, so this is pretty trivial.
return x;
return coord.x;
}
SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const {

View File

@ -30,7 +30,7 @@ protected:
SkRasterPipeline* postPipeline) const final;
skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*,
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const final;
skvm::Coord coord, skvm::I32* mask) const final;
private:
SK_FLATTENABLE_HOOKS(SkLinearGradient)

View File

@ -64,8 +64,8 @@ void SkRadialGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline* p,
}
skvm::F32 SkRadialGradient::transformT(skvm::Builder* p, skvm::Uniforms*,
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const {
return sqrt(x*x + y*y);
skvm::Coord coord, skvm::I32* mask) const {
return sqrt(coord.x*coord.x + coord.y*coord.y);
}
/////////////////////////////////////////////////////////////////////

View File

@ -27,7 +27,7 @@ protected:
SkRasterPipeline* postPipeline) const override;
skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*,
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const final;
skvm::Coord coord, skvm::I32* mask) const final;
private:
SK_FLATTENABLE_HOOKS(SkRadialGradient)

View File

@ -68,9 +68,9 @@ void SkSweepGradient::appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline
}
skvm::F32 SkSweepGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms,
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const {
skvm::F32 xabs = abs(x),
yabs = abs(y),
skvm::Coord coord, skvm::I32* mask) const {
skvm::F32 xabs = abs(coord.x),
yabs = abs(coord.y),
slope = min(xabs, yabs) / max(xabs, yabs);
skvm::F32 s = slope * slope;
@ -82,9 +82,9 @@ skvm::F32 SkSweepGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms
+2.476101927459239959716796875e-2f,
-5.185396969318389892578125e-2f,
+0.15912117063999176025390625f);
phi = select(xabs < yabs, (1/4.0f) - phi, phi);
phi = select( x < 0.0f, (1/2.0f) - phi, phi);
phi = select( y < 0.0f, (1/1.0f) - phi, phi);
phi = select( xabs < yabs, (1/4.0f) - phi, phi);
phi = select(coord.x < 0.0f, (1/2.0f) - phi, phi);
phi = select(coord.y < 0.0f, (1/1.0f) - phi, phi);
skvm::F32 t = select(is_NaN(phi), p->splat(0.0f)
, phi);

View File

@ -31,7 +31,7 @@ protected:
SkRasterPipeline* postPipeline) const override;
skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*,
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const final;
skvm::Coord coord, skvm::I32* mask) const final;
private:
SK_FLATTENABLE_HOOKS(SkSweepGradient)

View File

@ -234,11 +234,13 @@ void SkTwoPointConicalGradient::appendGradientStages(SkArenaAlloc* alloc, SkRast
}
skvm::F32 SkTwoPointConicalGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms,
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const {
skvm::Coord coord, skvm::I32* mask) const {
// See https://skia.org/dev/design/conical, and onAppendStages() above.
// There's a lot going on here, and I'm not really sure what's independent
// or disjoint, what can be reordered, simplified, etc. Tweak carefully.
const skvm::F32 x = coord.x,
y = coord.y;
if (fType == Type::kRadial) {
float denom = 1.0f / (fRadius2 - fRadius1),
scale = std::max(fRadius1, fRadius2) * denom,

View File

@ -70,7 +70,7 @@ protected:
SkRasterPipeline* postPipeline) const override;
skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*,
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const final;
skvm::Coord coord, skvm::I32* mask) const final;
private:
SK_FLATTENABLE_HOOKS(SkTwoPointConicalGradient)

View File

@ -110,6 +110,7 @@ static const uint8_t* DisassembleInstruction(const uint8_t* ip) {
break;
case ByteCodeInstruction::kLoadExtendedUniform: printf("loadextendeduniform %d", READ8());
break;
case ByteCodeInstruction::kLoadFragCoord: printf("loadfragcoord"); break;
case ByteCodeInstruction::kMatrixToMatrix: {
int srcCols = READ8();
int srcRows = READ8();
@ -926,11 +927,6 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue
}
}
case ByteCodeInstruction::kSampleExplicit:
case ByteCodeInstruction::kSampleMatrix:
// TODO: Support these?
return false;
case ByteCodeInstruction::kScalarToMatrix: {
int cols = READ8();
int rows = READ8();
@ -1105,6 +1101,14 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue
*loopPtr &= ~m;
continue;
}
case ByteCodeInstruction::kLoadFragCoord:
case ByteCodeInstruction::kSampleExplicit:
case ByteCodeInstruction::kSampleMatrix:
default:
// TODO: Support these?
SkASSERT(false);
return false;
}
}
}

View File

@ -78,6 +78,8 @@ enum class ByteCodeInstruction : uint16_t {
kLoadExtended,
kLoadExtendedGlobal,
kLoadExtendedUniform,
// Loads "sk_FragCoord" [X, Y, Z, 1/W]
kLoadFragCoord,
// Followed by four bytes: srcCols, srcRows, dstCols, dstRows. Consumes the src matrix from the
// stack, and replaces it with the dst matrix. Per GLSL rules, there are no restrictions on
// dimensions. Any overlapping values are copied, and any other values are filled in with the
@ -275,7 +277,7 @@ public:
* Some byte code programs can't be executed by the interpreter, due to unsupported features.
* They may still be used to convert to other formats, or for reflection of uniforms.
*/
bool canRun() const { return fChildFPCount == 0; }
bool canRun() const { return fChildFPCount == 0 && !fUsesFragCoord; }
private:
ByteCode(const ByteCode&) = delete;
@ -287,6 +289,7 @@ private:
int fGlobalSlotCount = 0;
int fUniformSlotCount = 0;
int fChildFPCount = 0;
bool fUsesFragCoord = false;
std::vector<Uniform> fUniforms;
std::vector<std::unique_ptr<ByteCodeFunction>> fFunctions;

View File

@ -207,10 +207,27 @@ std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const Functio
return result;
}
// If the expression is a reference to a builtin global variable, return the builtin ID.
// Otherwise, return -1.
static int expression_as_builtin(const Expression& e) {
if (e.fKind == Expression::kVariableReference_Kind) {
const Variable& var(((VariableReference&)e).fVariable);
if (var.fStorage == Variable::kGlobal_Storage) {
return var.fModifiers.fLayout.fBuiltin;
}
}
return -1;
}
// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
// that references consecutive values, such that it can be implemented using normal load/store ops
// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
static bool swizzle_is_simple(const Swizzle& s) {
// Builtin variables use dedicated instructions that don't allow subset loads
if (expression_as_builtin(*s.fBase) >= 0) {
return false;
}
switch (s.fBase->fKind) {
case Expression::kFieldAccess_Kind:
case Expression::kIndex_Kind:
@ -366,6 +383,7 @@ int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
case ByteCodeInstruction::kLoadGlobal4:
case ByteCodeInstruction::kLoadUniform4:
case ByteCodeInstruction::kReadExternal4:
case ByteCodeInstruction::kLoadFragCoord:
return 4;
case ByteCodeInstruction::kDupN:
@ -1015,6 +1033,19 @@ void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
}
void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
if (int builtin = expression_as_builtin(expr); builtin >= 0) {
switch (builtin) {
case SK_FRAGCOORD_BUILTIN:
this->write(ByteCodeInstruction::kLoadFragCoord);
fOutput->fUsesFragCoord = true;
break;
default:
fErrors.error(expr.fOffset, "Unsupported builtin");
break;
}
return;
}
Location location = this->getLocation(expr);
int count = SlotCount(expr.fType);
if (count == 0) {

View File

@ -76,7 +76,7 @@ public:
}
void test(skiatest::Reporter* r, sk_sp<SkSurface> surface,
uint32_t TL, uint32_t TR, uint32_t BL, uint32_t BR) {
uint32_t TL, uint32_t TR, uint32_t BL, uint32_t BR, SkScalar rotate = 0.0f) {
auto shader = fBuilder->makeShader(nullptr, false);
if (!shader) {
REPORT_FAILURE(r, "shader", SkString("Effect didn't produce a shader"));
@ -86,6 +86,7 @@ public:
SkPaint paint;
paint.setShader(std::move(shader));
paint.setBlendMode(SkBlendMode::kSrc);
surface->getCanvas()->rotate(rotate);
surface->getCanvas()->drawPaint(paint);
uint32_t actual[4];
@ -153,11 +154,8 @@ static void test_RuntimeEffect_Shaders(skiatest::Reporter* r, GrContext* context
// Test sk_FragCoord, which we output to color. Since the surface is 2x2, we should see
// (0,0), (1,0), (0,1), (1,1), multiply by 0.498 to make sure we're not saturating unexpectedly.
// TODO: Remove this when sk_FragCoord is supported by interpreter.
if (context) {
TestEffect fragCoord(r, "", "color = half4(0.498 * (half2(sk_FragCoord.xy) - 0.5), 0, 1);");
fragCoord.test(r, surface, 0xFF000000, 0xFF00007F, 0xFF007F00, 0xFF007F7F);
}
TestEffect fragCoord(r, "", "color = half4(0.498 * (half2(sk_FragCoord.xy) - 0.5), 0, 1);");
fragCoord.test(r, surface, 0xFF000000, 0xFF00007F, 0xFF007F00, 0xFF007F7F, 45.0f);
}
DEF_TEST(SkRuntimeEffectSimple, r) {