Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 3c35842

Browse files
brianosmanSkia Commit-Bot
authored andcommitted
Support for custom vertex data in SkSL and drawVertices
Adds a 'varying' modifier to the SkSL frontend. Only valid for pipeline stage (runtime effect) SkSL programs, and only on variables that are float, or float[2-4]. Runtime effect SkSL can declare varyings. The effect gathers and reflects them. The GPU backend uses SkShader_Base's new asRuntimeEffect() to get this data. GrDrawVerticesOp and its GP get the shader's effect, if any. They use this to add vertex attributes, varyings, and global variables (in the fragment shader) of the appropriate width. The globals have procedurally generated names, based on their index in the list ("_vtx_attr_%d"). The GP's fragment code copies the varyings to the globals. When PipelineStageCodeGenerator sees a varying reference, it just replaces that with the procedurally generated name that matches the logic in the op. Change-Id: I0effbc4f3425d452cb7d62e51e268f3b48fa3c74 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/275962 Reviewed-by: Brian Salomon <[email protected]> Commit-Queue: Brian Osman <[email protected]>
1 parent f5ff4c2 commit 3c35842

17 files changed

+702
-467
lines changed

gm/vertices.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,13 @@
2222
#include "include/core/SkTypes.h"
2323
#include "include/core/SkVertices.h"
2424
#include "include/effects/SkGradientShader.h"
25+
#include "include/effects/SkRuntimeEffect.h"
2526
#include "include/private/SkTDArray.h"
2627
#include "include/utils/SkRandom.h"
28+
#include "src/core/SkVerticesPriv.h"
2729
#include "src/shaders/SkLocalMatrixShader.h"
30+
#include "src/utils/SkPatchUtils.h"
31+
#include "tools/Resources.h"
2832
#include "tools/ToolUtils.h"
2933

3034
#include <initializer_list>
@@ -335,3 +339,46 @@ DEF_SIMPLE_GM(vertices_perspective, canvas, 256, 256) {
335339
canvas->drawVertices(verts, paint);
336340
canvas->restore();
337341
}
342+
343+
DEF_SIMPLE_GM(vertices_data_lerp, canvas, 256, 256) {
344+
SkPoint pts[12] = {{0, 0}, {85, 0}, {171, 0}, {256, 0}, {256, 85}, {256, 171},
345+
{256, 256}, {171, 256}, {85, 256}, {0, 256}, {0, 171}, {0, 85}};
346+
347+
auto patchVerts = SkPatchUtils::MakeVertices(pts, nullptr, nullptr, 12, 12);
348+
SkVertices::Info info;
349+
patchVerts->getInfo(&info);
350+
351+
SkVertices::CustomLayout customLayout { 1 };
352+
SkVertices::Builder builder(info.fMode, info.fVertexCount, info.fIndexCount, customLayout);
353+
354+
memcpy(builder.positions(), info.fPositions, info.fVertexCount * sizeof(SkPoint));
355+
memcpy(builder.indices(), info.fIndices, info.fIndexCount * sizeof(uint16_t));
356+
357+
SkRandom rnd;
358+
for (int i = 0; i < info.fVertexCount; ++i) {
359+
builder.perVertexData()[i] = rnd.nextBool() ? 1.0f : 0.0f;
360+
}
361+
362+
auto verts = builder.detach();
363+
364+
SkPaint paint;
365+
const char* gProg = R"(
366+
in fragmentProcessor c0;
367+
in fragmentProcessor c1;
368+
varying float vtx_lerp;
369+
void main(float2 p, inout half4 color) {
370+
half4 col0 = sample(c0, p);
371+
half4 col1 = sample(c1, p);
372+
color = mix(col0, col1, half(vtx_lerp));
373+
}
374+
)";
375+
auto [effect, errorText] = SkRuntimeEffect::Make(SkString(gProg));
376+
SkMatrix scale = SkMatrix::MakeScale(2);
377+
sk_sp<SkShader> children[] = {
378+
GetResourceAsImage("images/mandrill_256.png")->makeShader(),
379+
GetResourceAsImage("images/color_wheel.png")->makeShader(scale),
380+
};
381+
paint.setShader(effect->makeShader(nullptr, children, 2, nullptr, false));
382+
383+
canvas->drawVertices(verts, paint);
384+
}

include/effects/SkRuntimeEffect.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ class SK_API SkRuntimeEffect : public SkRefCnt {
7474
size_t sizeInBytes() const;
7575
};
7676

77+
struct Varying {
78+
SkString fName;
79+
int fWidth; // 1 - 4 (floats)
80+
};
81+
7782
// [Effect, ErrorText]
7883
// If successful, Effect != nullptr, otherwise, ErrorText contains the reason for failure.
7984
using EffectResult = std::tuple<sk_sp<SkRuntimeEffect>, SkString>;
@@ -112,8 +117,12 @@ class SK_API SkRuntimeEffect : public SkRefCnt {
112117
// Combined size of just the 'uniform' variables.
113118
size_t uniformSize() const { return fUniformSize; }
114119

120+
// Total number of channels across all varyings, combined.
121+
int varyingCount() const;
122+
115123
ConstIterable<Variable> inputs() const { return ConstIterable<Variable>(fInAndUniformVars); }
116124
ConstIterable<SkString> children() const { return ConstIterable<SkString>(fChildren); }
125+
ConstIterable<Varying> varyings() const { return ConstIterable<Varying>(fVaryings); }
117126

118127
#if SK_SUPPORT_GPU
119128
// This re-compiles the program from scratch, using the supplied shader caps.
@@ -136,7 +145,7 @@ class SK_API SkRuntimeEffect : public SkRefCnt {
136145
private:
137146
SkRuntimeEffect(SkString sksl, std::unique_ptr<SkSL::Program> baseProgram,
138147
std::vector<Variable>&& inAndUniformVars, std::vector<SkString>&& children,
139-
size_t uniformSize);
148+
std::vector<Varying>&& varyings, size_t uniformSize);
140149

141150
using SpecializeResult = std::tuple<std::unique_ptr<SkSL::Program>, SkString>;
142151
SpecializeResult specialize(SkSL::Program& baseProgram, const void* inputs,
@@ -148,6 +157,7 @@ class SK_API SkRuntimeEffect : public SkRefCnt {
148157
std::unique_ptr<SkSL::Program> fBaseProgram;
149158
std::vector<Variable> fInAndUniformVars;
150159
std::vector<SkString> fChildren;
160+
std::vector<Varying> fVaryings;
151161

152162
size_t fUniformSize;
153163
};

src/core/SkRuntimeEffect.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "src/sksl/SkSLByteCode.h"
1717
#include "src/sksl/SkSLCompiler.h"
1818
#include "src/sksl/SkSLInterpreter.h"
19+
#include "src/sksl/ir/SkSLFunctionDefinition.h"
1920
#include "src/sksl/ir/SkSLVarDeclarations.h"
2021

2122
#if SK_SUPPORT_GPU
@@ -66,8 +67,25 @@ SkRuntimeEffect::EffectResult SkRuntimeEffect::Make(SkString sksl) {
6667
size_t offset = 0, uniformSize = 0;
6768
std::vector<Variable> inAndUniformVars;
6869
std::vector<SkString> children;
70+
std::vector<Varying> varyings;
6971
const SkSL::Context& ctx(compiler->context());
7072

73+
// Scrape the varyings
74+
for (const auto& e : *program) {
75+
if (e.fKind == SkSL::ProgramElement::kVar_Kind) {
76+
SkSL::VarDeclarations& v = (SkSL::VarDeclarations&) e;
77+
for (const auto& varStatement : v.fVars) {
78+
const SkSL::Variable& var = *((SkSL::VarDeclaration&) *varStatement).fVar;
79+
80+
if (var.fModifiers.fFlags & SkSL::Modifiers::kVarying_Flag) {
81+
varyings.push_back({var.fName, var.fType.kind() == SkSL::Type::kVector_Kind
82+
? var.fType.columns()
83+
: 1});
84+
}
85+
}
86+
}
87+
}
88+
7189
// Gather the inputs in two passes, to de-interleave them in our input layout.
7290
// We put the uniforms *first*, so that the CPU backend can alias the combined input block as
7391
// the uniform block when calling the interpreter.
@@ -200,6 +218,7 @@ SkRuntimeEffect::EffectResult SkRuntimeEffect::Make(SkString sksl) {
200218
std::move(program),
201219
std::move(inAndUniformVars),
202220
std::move(children),
221+
std::move(varyings),
203222
uniformSize));
204223
return std::make_pair(std::move(effect), SkString());
205224
}
@@ -227,12 +246,14 @@ SkRuntimeEffect::SkRuntimeEffect(SkString sksl,
227246
std::unique_ptr<SkSL::Program> baseProgram,
228247
std::vector<Variable>&& inAndUniformVars,
229248
std::vector<SkString>&& children,
249+
std::vector<Varying>&& varyings,
230250
size_t uniformSize)
231251
: fHash(SkGoodHash()(sksl))
232252
, fSkSL(std::move(sksl))
233253
, fBaseProgram(std::move(baseProgram))
234254
, fInAndUniformVars(std::move(inAndUniformVars))
235255
, fChildren(std::move(children))
256+
, fVaryings(std::move(varyings))
236257
, fUniformSize(uniformSize) {
237258
SkASSERT(fBaseProgram);
238259
SkASSERT(SkIsAlign4(fUniformSize));
@@ -247,6 +268,14 @@ size_t SkRuntimeEffect::inputSize() const {
247268
fInAndUniformVars.back().sizeInBytes());
248269
}
249270

271+
int SkRuntimeEffect::varyingCount() const {
272+
int count = 0;
273+
for (const auto& v : fVaryings) {
274+
count += v.fWidth;
275+
}
276+
return count;
277+
}
278+
250279
SkRuntimeEffect::SpecializeResult SkRuntimeEffect::specialize(SkSL::Program& baseProgram,
251280
const void* inputs,
252281
const SkSL::SharedCompiler& compiler) {
@@ -528,6 +557,8 @@ class SkRTShader : public SkShaderBase {
528557
}
529558
}
530559

560+
SkRuntimeEffect* asRuntimeEffect() const override { return fEffect.get(); }
561+
531562
SK_FLATTENABLE_HOOKS(SkRTShader)
532563

533564
private:

src/gpu/GrRenderTargetContext.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,7 +1064,8 @@ void GrRenderTargetContext::drawVertices(const GrClip& clip,
10641064
GrPaint&& paint,
10651065
const SkMatrix& viewMatrix,
10661066
sk_sp<SkVertices> vertices,
1067-
GrPrimitiveType* overridePrimType) {
1067+
GrPrimitiveType* overridePrimType,
1068+
const SkRuntimeEffect* effect) {
10681069
ASSERT_SINGLE_OWNER
10691070
RETURN_IF_ABANDONED
10701071
SkDEBUGCODE(this->validate();)
@@ -1076,7 +1077,7 @@ void GrRenderTargetContext::drawVertices(const GrClip& clip,
10761077
GrAAType aaType = this->chooseAAType(GrAA::kNo);
10771078
std::unique_ptr<GrDrawOp> op = GrDrawVerticesOp::Make(
10781079
fContext, std::move(paint), std::move(vertices), viewMatrix, aaType,
1079-
this->colorInfo().refColorSpaceXformFromSRGB(), overridePrimType);
1080+
this->colorInfo().refColorSpaceXformFromSRGB(), overridePrimType, effect);
10801081
this->addDrawOp(clip, std::move(op));
10811082
}
10821083

src/gpu/GrRenderTargetContext.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct SkRect;
4949
class SkRegion;
5050
class SkRRect;
5151
struct SkRSXform;
52+
class SkRuntimeEffect;
5253
class SkTextBlob;
5354
class SkVertices;
5455

@@ -411,12 +412,14 @@ class GrRenderTargetContext : public GrSurfaceContext {
411412
* @param viewMatrix transformation matrix
412413
* @param vertices specifies the mesh to draw.
413414
* @param overridePrimType primitive type to draw. If NULL, derive prim type from vertices.
415+
* @param effect runtime effect that will handle custom vertex attributes.
414416
*/
415417
void drawVertices(const GrClip&,
416418
GrPaint&& paint,
417419
const SkMatrix& viewMatrix,
418420
sk_sp<SkVertices> vertices,
419-
GrPrimitiveType* overridePrimType = nullptr);
421+
GrPrimitiveType* overridePrimType = nullptr,
422+
const SkRuntimeEffect* effect = nullptr);
420423

421424
/**
422425
* Draws textured sprites from an atlas with a paint. This currently does not support AA for the

src/gpu/SkGpuDevice.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "include/core/SkPicture.h"
1313
#include "include/core/SkSurface.h"
1414
#include "include/core/SkVertices.h"
15+
#include "include/effects/SkRuntimeEffect.h"
1516
#include "include/gpu/GrContext.h"
1617
#include "include/private/SkShadowFlags.h"
1718
#include "include/private/SkTo.h"
@@ -1031,14 +1032,25 @@ void SkGpuDevice::wireframeVertices(SkVertices::VertexMode vmode, int vertexCoun
10311032
void SkGpuDevice::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
10321033
ASSERT_SINGLE_OWNER
10331034
GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext.get());
1035+
SkASSERT(vertices);
10341036

10351037
SkVertices::Info info;
10361038
vertices->getInfo(&info);
10371039

1038-
SkASSERT(vertices);
1040+
const SkRuntimeEffect* effect =
1041+
paint.getShader() ? as_SB(paint.getShader())->asRuntimeEffect() : nullptr;
1042+
int shaderVaryingCount = effect ? effect->varyingCount() : 0;
1043+
1044+
// TODO: Hoist this check up to SkCanvas
1045+
if (shaderVaryingCount != info.fPerVertexDataCount) {
1046+
return;
1047+
}
1048+
1049+
// Pretend that we have tex coords when using custom per-vertex data. The shader is going to
1050+
// use those (rather than local coords), but our paint conversion remains the same.
10391051
GrPaint grPaint;
10401052
bool hasColors = info.hasColors();
1041-
bool hasTexs = info.hasTexCoords();
1053+
bool hasTexs = info.hasTexCoords() || info.hasPerVertexData();
10421054
if ((!hasTexs || !paint.getShader()) && !hasColors) {
10431055
// The dreaded wireframe mode. Fallback to drawVertices and go so slooooooow.
10441056
this->wireframeVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(),
@@ -1051,7 +1063,8 @@ void SkGpuDevice::drawVertices(const SkVertices* vertices, SkBlendMode mode, con
10511063
return;
10521064
}
10531065
fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), this->localToDevice(),
1054-
sk_ref_sp(const_cast<SkVertices*>(vertices)));
1066+
sk_ref_sp(const_cast<SkVertices*>(vertices)), nullptr,
1067+
effect);
10551068
}
10561069

10571070
///////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)