optimize verts
Take advantage of the new virtual on SkShaderBase : appendStagesWithUpdater
If our shader supports that, we can draw each triangle without having to
recreate the entire pipeline/blitter.
This change produces 3 different loops:
tricolor only : uses private backdoor to update colors per triangle
has updater : uses updater to update ctm per triangle
general : rebuilds pipeline/blitter on each triangle
In a follow-up, we may be able to plumb updater through to other shaders
(other than image), which would have us land in the updater case more
often.
Before
728.09 verts_textures_colors 8888
167.48 ? verts_colors 8888
510.17 verts_textures 8888
After
729.61 verts_textures_colors 8888
168.80 verts_colors 8888
219.58 verts_textures 8888
Change-Id: I87a6e6dc23dfba3377d6f9a54818fe6b8d349018
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/235801
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/src/core/SkDraw_vertices.cpp b/src/core/SkDraw_vertices.cpp
index 624011c..ec3904e 100644
--- a/src/core/SkDraw_vertices.cpp
+++ b/src/core/SkDraw_vertices.cpp
@@ -71,10 +71,8 @@
public:
SkTriColorShader(bool isOpaque) : fIsOpaque(isOpaque) {}
- Matrix43* getMatrix43() { return &fM43; }
-
- bool isOpaque() const override { return fIsOpaque; }
-
+ bool update(const SkMatrix& ctmInv, const SkPoint pts[], const SkPMColor4f colors[],
+ int index0, int index1, int index2);
protected:
#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
@@ -89,19 +87,19 @@
}
private:
+ bool isOpaque() const override { return fIsOpaque; }
// For serialization. This will never be called.
Factory getFactory() const override { return nullptr; }
const char* getTypeName() const override { return nullptr; }
- Matrix43 fM43;
+ Matrix43 fM43; // we overwrite this for each triangle
const bool fIsOpaque;
typedef SkShaderBase INHERITED;
};
-static bool SK_WARN_UNUSED_RESULT
-update_tricolor_matrix(const SkMatrix& ctmInv, const SkPoint pts[], const SkPMColor4f colors[],
- int index0, int index1, int index2, Matrix43* result) {
+bool SkTriColorShader::update(const SkMatrix& ctmInv, const SkPoint pts[],
+ const SkPMColor4f colors[], int index0, int index1, int index2) {
SkMatrix m, im;
m.reset();
m.set(0, pts[index1].fX - pts[index0].fX);
@@ -125,7 +123,7 @@
(c1 - c0).store(&colorm.fMat[0]);
(c2 - c0).store(&colorm.fMat[4]);
c0.store(&colorm.fMat[8]);
- result->setConcat(colorm, dstToUnit);
+ fM43.setConcat(colorm, dstToUnit);
return true;
}
@@ -265,73 +263,7 @@
VertState state(vertexCount, indices, indexCount);
VertState::Proc vertProc = state.chooseProc(vmode);
- if (colors || textures) {
- SkPMColor4f* dstColors = nullptr;
- Matrix43* matrix43 = nullptr;
-
- if (colors) {
- dstColors = convert_colors(colors, vertexCount, fDst.colorSpace(), &outerAlloc);
-
- SkTriColorShader* triShader = outerAlloc.make<SkTriColorShader>(
- compute_is_opaque(colors,
- vertexCount));
- matrix43 = triShader->getMatrix43();
- if (shader) {
- shader = outerAlloc.make<SkShader_Blend>(bmode,
- sk_ref_sp(triShader), sk_ref_sp(shader),
- nullptr);
- } else {
- shader = triShader;
- }
- }
-
- SkPaint p(paint);
- p.setShader(sk_ref_sp(shader));
-
- if (!textures) { // only tricolor shader
- SkASSERT(matrix43);
- auto blitter = SkCreateRasterPipelineBlitter(fDst, p, *fMatrix, &outerAlloc);
- while (vertProc(&state)) {
- if (!update_tricolor_matrix(ctmInv, vertices, dstColors,
- state.f0, state.f1, state.f2,
- matrix43)) {
- continue;
- }
-
- SkPoint tmp[] = {
- devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
- };
- SkScan::FillTriangle(tmp, *fRC, blitter);
- }
- } else {
- while (vertProc(&state)) {
- SkSTArenaAlloc<2048> innerAlloc;
-
- const SkMatrix* ctm = fMatrix;
- SkMatrix tmpCtm;
- if (textures) {
- SkMatrix localM;
- if (!texture_to_matrix(state, vertices, textures, &localM)) {
- continue;
- }
- tmpCtm = SkMatrix::Concat(*fMatrix, localM);
- ctm = &tmpCtm;
- }
-
- if (matrix43 && !update_tricolor_matrix(ctmInv, vertices, dstColors,
- state.f0, state.f1, state.f2,
- matrix43)) {
- continue;
- }
-
- SkPoint tmp[] = {
- devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
- };
- auto blitter = SkCreateRasterPipelineBlitter(fDst, p, *ctm, &innerAlloc);
- SkScan::FillTriangle(tmp, *fRC, blitter);
- }
- }
- } else {
+ if (!(colors || textures)) {
// no colors[] and no texture, stroke hairlines with paint's color.
SkPaint p;
p.setStyle(SkPaint::kStroke_Style);
@@ -348,5 +280,97 @@
};
hairProc(array, 4, clip, blitter.get());
}
+ return;
+ }
+
+ SkTriColorShader* triShader = nullptr;
+ SkPMColor4f* dstColors = nullptr;
+
+ if (colors) {
+ dstColors = convert_colors(colors, vertexCount, fDst.colorSpace(), &outerAlloc);
+ triShader = outerAlloc.make<SkTriColorShader>(compute_is_opaque(colors, vertexCount));
+ if (shader) {
+ shader = outerAlloc.make<SkShader_Blend>(bmode,
+ sk_ref_sp(triShader), sk_ref_sp(shader),
+ nullptr);
+ } else {
+ shader = triShader;
+ }
+ }
+
+ SkPaint p(paint);
+ p.setShader(sk_ref_sp(shader));
+
+ if (!textures) { // only tricolor shader
+ auto blitter = SkCreateRasterPipelineBlitter(fDst, p, *fMatrix, &outerAlloc);
+ while (vertProc(&state)) {
+ if (!triShader->update(ctmInv, vertices, dstColors, state.f0, state.f1, state.f2)) {
+ continue;
+ }
+
+ SkPoint tmp[] = {
+ devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
+ };
+ SkScan::FillTriangle(tmp, *fRC, blitter);
+ }
+ return;
+ }
+
+ SkRasterPipeline pipeline(&outerAlloc);
+ SkStageRec rec = {
+ &pipeline, &outerAlloc, fDst.colorType(), fDst.colorSpace(), p, nullptr, *fMatrix
+ };
+ if (auto updater = as_SB(shader)->appendUpdatableStages(rec)) {
+ bool isOpaque = shader->isOpaque();
+ if (triShader) {
+ isOpaque = false; // unless we want to walk all the colors, and see if they are
+ // all opaque (and the blendmode will keep them that way
+ }
+
+ auto blitter = SkCreateRasterPipelineBlitter(fDst, p, pipeline, isOpaque, &outerAlloc);
+ while (vertProc(&state)) {
+ if (triShader && !triShader->update(ctmInv, vertices, dstColors,
+ state.f0, state.f1, state.f2)) {
+ continue;
+ }
+
+ SkMatrix localM;
+ if (!texture_to_matrix(state, vertices, textures, &localM) ||
+ !updater->update(*fMatrix, &localM)) {
+ continue;
+ }
+
+ SkPoint tmp[] = {
+ devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
+ };
+ SkScan::FillTriangle(tmp, *fRC, blitter);
+ }
+ } else {
+ // must rebuild pipeline for each triangle, to pass in the computed ctm
+ while (vertProc(&state)) {
+ if (triShader && !triShader->update(ctmInv, vertices, dstColors,
+ state.f0, state.f1, state.f2)) {
+ continue;
+ }
+
+ SkSTArenaAlloc<2048> innerAlloc;
+
+ const SkMatrix* ctm = fMatrix;
+ SkMatrix tmpCtm;
+ if (textures) {
+ SkMatrix localM;
+ if (!texture_to_matrix(state, vertices, textures, &localM)) {
+ continue;
+ }
+ tmpCtm = SkMatrix::Concat(*fMatrix, localM);
+ ctm = &tmpCtm;
+ }
+
+ SkPoint tmp[] = {
+ devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
+ };
+ auto blitter = SkCreateRasterPipelineBlitter(fDst, p, *ctm, &innerAlloc);
+ SkScan::FillTriangle(tmp, *fRC, blitter);
+ }
}
}