blob: 11c5c1399ec0d8ca9e08713a681dcafa18f0a964 [file] [log] [blame]
Chris Dalton4328e922020-01-29 13:16:14 -07001/*
2 * Copyright 2020 Google LLC.
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/gpu/tessellate/GrFillPathShader.h"
9
10#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
11#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
12#include "src/gpu/glsl/GrGLSLVarying.h"
13#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
14
15class GrFillPathShader::Impl : public GrGLSLGeometryProcessor {
16public:
17 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
18 auto& shader = args.fGP.cast<GrFillPathShader>();
19
20 const char* viewMatrix;
21 fViewMatrixUniform = args.fUniformHandler->addUniform(
Ethan Nicholas16464c32020-04-06 13:53:05 -040022 nullptr, kVertex_GrShaderFlag, kFloat3x3_GrSLType, "view_matrix", &viewMatrix);
Chris Dalton4328e922020-01-29 13:16:14 -070023
24 args.fVaryingHandler->emitAttributes(shader);
25
26 args.fVertBuilder->codeAppend("float2 localcoord, vertexpos;");
27 shader.emitVertexCode(this, args.fVertBuilder, viewMatrix, args.fUniformHandler);
28
Chris Dalton4328e922020-01-29 13:16:14 -070029 gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
Michael Ludwig553db622020-06-19 10:47:30 -040030 gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
Chris Dalton4328e922020-01-29 13:16:14 -070031
32 const char* color;
33 fColorUniform = args.fUniformHandler->addUniform(
Ethan Nicholas16464c32020-04-06 13:53:05 -040034 nullptr, kFragment_GrShaderFlag, kHalf4_GrSLType, "color", &color);
Chris Dalton4328e922020-01-29 13:16:14 -070035
36 args.fFragBuilder->codeAppendf("%s = %s;", args.fOutputColor, color);
37 args.fFragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
38 }
39
Brian Osman609f1592020-07-01 15:14:39 -040040 void setData(const GrGLSLProgramDataManager& pdman,
41 const GrPrimitiveProcessor& primProc) override {
Chris Dalton4328e922020-01-29 13:16:14 -070042 const GrFillPathShader& shader = primProc.cast<GrFillPathShader>();
43 pdman.setSkMatrix(fViewMatrixUniform, shader.viewMatrix());
44
45 const SkPMColor4f& color = shader.fColor;
46 pdman.set4f(fColorUniform, color.fR, color.fG, color.fB, color.fA);
47
48 if (fPathBoundsUniform.isValid()) {
49 const SkRect& b = primProc.cast<GrFillBoundingBoxShader>().pathBounds();
50 pdman.set4f(fPathBoundsUniform, b.left(), b.top(), b.right(), b.bottom());
51 }
Chris Dalton4328e922020-01-29 13:16:14 -070052 }
53
54 GrGLSLUniformHandler::UniformHandle fViewMatrixUniform;
55 GrGLSLUniformHandler::UniformHandle fColorUniform;
56 GrGLSLUniformHandler::UniformHandle fPathBoundsUniform;
57};
58
59GrGLSLPrimitiveProcessor* GrFillPathShader::createGLSLInstance(const GrShaderCaps&) const {
60 return new Impl;
61}
62
63void GrFillTriangleShader::emitVertexCode(Impl*, GrGLSLVertexBuilder* v, const char* viewMatrix,
64 GrGLSLUniformHandler* uniformHandler) const {
65 v->codeAppendf(R"(
Chris Daltonb27f39c2020-11-23 09:30:24 -070066 localcoord = input_point;
67 vertexpos = (%s * float3(localcoord, 1)).xy;)", viewMatrix);
Chris Dalton4328e922020-01-29 13:16:14 -070068}
69
70void GrFillCubicHullShader::emitVertexCode(Impl*, GrGLSLVertexBuilder* v, const char* viewMatrix,
71 GrGLSLUniformHandler* uniformHandler) const {
72 v->codeAppend(R"(
Chris Daltonb27f39c2020-11-23 09:30:24 -070073 float4x2 P = float4x2(input_points_0_1, input_points_2_3);
Chris Dalton011a7732020-12-04 16:27:50 -070074 if (isinf(P[3].y)) {
Chris Daltonb27f39c2020-11-23 09:30:24 -070075 // This curve is actually a conic. Convert the control points to a trapeziodal hull
76 // that circumcscribes the conic.
77 float w = P[3].x;
78 float2 p1w = P[1] * w;
79 float T = .51; // Bias outward a bit to ensure we cover the outermost samples.
80 float2 c1 = mix(P[0], p1w, T);
81 float2 c2 = mix(P[2], p1w, T);
82 float iw = 1 / mix(1, w, T);
83 P = float4x2(P[0], c1 * iw, c2 * iw, P[2]);
84 }
Chris Dalton4328e922020-01-29 13:16:14 -070085
Chris Daltonb27f39c2020-11-23 09:30:24 -070086 // Translate the points to v0..3 where v0=0.
87 float2 v1 = P[1] - P[0], v2 = P[2] - P[0], v3 = P[3] - P[0];
Chris Dalton4328e922020-01-29 13:16:14 -070088
Chris Daltonb27f39c2020-11-23 09:30:24 -070089 // Reorder the points so v2 bisects v1 and v3.
90 if (sign(determinant(float2x2(v2,v1))) == sign(determinant(float2x2(v2,v3)))) {
91 float2 tmp = P[2];
92 if (sign(determinant(float2x2(v1,v2))) != sign(determinant(float2x2(v1,v3)))) {
93 P[2] = P[1]; // swap(P2, P1)
94 P[1] = tmp;
95 } else {
96 P[2] = P[3]; // swap(P2, P3)
97 P[3] = tmp;
98 }
99 }
Chris Dalton4328e922020-01-29 13:16:14 -0700100
Chris Daltonb27f39c2020-11-23 09:30:24 -0700101 // sk_VertexID comes in fan order. Convert to strip order.
102 int vertexidx = sk_VertexID;
103 vertexidx ^= vertexidx >> 1;
Chris Dalton4328e922020-01-29 13:16:14 -0700104
Chris Daltoneae5c162020-12-29 10:18:21 -0700105 // Find the "turn direction" of each corner and net turn direction.
106 float vertexdir = 0;
107 float netdir = 0;
108 for (int i = 0; i < 4; ++i) {
109 float2 prev = P[i] - P[(i + 3) & 3], next = P[(i + 1) & 3] - P[i];
110 float dir = sign(determinant(float2x2(prev, next)));
111 if (i == vertexidx) {
112 vertexdir = dir;
113 }
114 netdir += dir;
115 }
116
Chris Daltonb27f39c2020-11-23 09:30:24 -0700117 // Remove the non-convex vertex, if any.
Chris Daltoneae5c162020-12-29 10:18:21 -0700118 if (vertexdir != sign(netdir)) {
Chris Daltonb27f39c2020-11-23 09:30:24 -0700119 vertexidx = (vertexidx + 1) & 3;
120 }
Chris Dalton4328e922020-01-29 13:16:14 -0700121
Chris Daltonb27f39c2020-11-23 09:30:24 -0700122 localcoord = P[vertexidx];)");
Chris Dalton4328e922020-01-29 13:16:14 -0700123
124 v->codeAppendf("vertexpos = (%s * float3(localcoord, 1)).xy;", viewMatrix);
125}
126
127void GrFillBoundingBoxShader::emitVertexCode(Impl* impl, GrGLSLVertexBuilder* v,
128 const char* viewMatrix,
129 GrGLSLUniformHandler* uniformHandler) const {
130 const char* pathBounds;
131 impl->fPathBoundsUniform = uniformHandler->addUniform(
Ethan Nicholas16464c32020-04-06 13:53:05 -0400132 nullptr, kVertex_GrShaderFlag, kFloat4_GrSLType, "path_bounds", &pathBounds);
Chris Dalton4328e922020-01-29 13:16:14 -0700133
134 v->codeAppendf(R"(
Chris Daltonb27f39c2020-11-23 09:30:24 -0700135 // Use sk_VertexID and uniforms (instead of vertex data) to find vertex positions.
136 float2 T = float2(sk_VertexID & 1, sk_VertexID >> 1);
137 localcoord = mix(%s.xy, %s.zw, T);
138 vertexpos = (%s * float3(localcoord, 1)).xy;
Chris Dalton4328e922020-01-29 13:16:14 -0700139
Chris Daltonb27f39c2020-11-23 09:30:24 -0700140 // Outset to avoid possible T-junctions with extreme edges of the path.
141 float2x2 M2 = float2x2(%s);
142 float2 devoutset = .25 * sign(M2 * (T - .5));
143 localcoord += inverse(M2) * devoutset;
144 vertexpos += devoutset;)", pathBounds, pathBounds, viewMatrix, viewMatrix);
Chris Dalton4328e922020-01-29 13:16:14 -0700145}