1 /*
2 * Copyright 2021 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/core/SkMatrixProvider.h"
9 #include "src/core/SkRasterPipeline.h"
10 #include "src/shaders/SkTransformShader.h"
11
SkTransformShader(const SkShaderBase & shader)12 SkTransformShader::SkTransformShader(const SkShaderBase& shader) : fShader{shader} {}
13
onProgram(skvm::Builder * b,skvm::Coord device,skvm::Coord local,skvm::Color color,const SkMatrixProvider & matrices,const SkMatrix * localM,const SkColorInfo & dst,skvm::Uniforms * uniforms,SkArenaAlloc * alloc) const14 skvm::Color SkTransformShader::onProgram(skvm::Builder* b,
15 skvm::Coord device, skvm::Coord local, skvm::Color color,
16 const SkMatrixProvider& matrices, const SkMatrix* localM,
17 const SkColorInfo& dst,
18 skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
19 skvm::Coord newLocal = this->applyMatrix(b, matrices.localToDevice(), local, uniforms);
20 SkSimpleMatrixProvider matrixProvider{SkMatrix::I()};
21 return fShader.program(
22 b, device, newLocal, color, matrixProvider, localM, dst, uniforms, alloc);
23 }
24
applyMatrix(skvm::Builder * b,const SkMatrix & matrix,skvm::Coord local,skvm::Uniforms * uniforms) const25 skvm::Coord SkTransformShader::applyMatrix(
26 skvm::Builder* b, const SkMatrix& matrix, skvm::Coord local,
27 skvm::Uniforms* uniforms) const {
28 fMatrix = uniforms->pushPtr(&fMatrixStorage);
29
30 skvm::F32 x = local.x,
31 y = local.y;
32
33 auto dot = [&,x,y](int row) {
34 return b->mad(x, b->arrayF(fMatrix, 3*row+0),
35 b->mad(y, b->arrayF(fMatrix, 3*row+1),
36 b->arrayF(fMatrix, 3*row+2)));
37 };
38
39 x = dot(0);
40 y = dot(1);
41 fProcessingAsPerspective = matrix.hasPerspective() || fShader.getLocalMatrix().hasPerspective();
42 if (fProcessingAsPerspective) {
43 x = x * (1.0f / dot(2));
44 y = y * (1.0f / dot(2));
45 }
46
47 return {x, y};
48 }
49
appendMatrix(const SkMatrix & matrix,SkRasterPipeline * p) const50 void SkTransformShader::appendMatrix(const SkMatrix& matrix, SkRasterPipeline* p) const {
51 fProcessingAsPerspective = matrix.hasPerspective() || fShader.getLocalMatrix().hasPerspective();
52 if (fProcessingAsPerspective) {
53 p->append(SkRasterPipeline::matrix_perspective, fMatrixStorage);
54 } else {
55 p->append(SkRasterPipeline::matrix_2x3, fMatrixStorage);
56 }
57 }
58
update(const SkMatrix & ctm) const59 bool SkTransformShader::update(const SkMatrix& ctm) const {
60 if (SkMatrix matrix; this->computeTotalInverse(ctm, nullptr, &matrix)) {
61 if (!fProcessingAsPerspective) {
62 SkASSERT(!matrix.hasPerspective());
63 if (matrix.hasPerspective()) {
64 return false;
65 }
66 }
67
68 matrix.get9(fMatrixStorage);
69 return true;
70 }
71 return false;
72 }
73
onAppendStages(const SkStageRec & rec) const74 bool SkTransformShader::onAppendStages(const SkStageRec& rec) const {
75 // TODO
76 return false;
77 }
78