blob: ba370484dc3c1b3801e3ac524cf65c02282ffced [file] [log] [blame]
Brian Salomon34169692017-08-28 15:32:01 -04001/*
2 * Copyright 2017 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 "GrTextureOp.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -04009
Brian Salomon34169692017-08-28 15:32:01 -040010#include "GrAppliedClip.h"
Brian Salomon336ce7b2017-09-08 08:23:58 -040011#include "GrCaps.h"
Robert Phillips7c525e62018-06-12 10:11:12 -040012#include "GrContext.h"
13#include "GrContextPriv.h"
Brian Salomon34169692017-08-28 15:32:01 -040014#include "GrDrawOpTest.h"
15#include "GrGeometryProcessor.h"
Robert Phillips7c525e62018-06-12 10:11:12 -040016#include "GrMemoryPool.h"
Brian Salomon34169692017-08-28 15:32:01 -040017#include "GrMeshDrawOp.h"
18#include "GrOpFlushState.h"
19#include "GrQuad.h"
20#include "GrResourceProvider.h"
21#include "GrShaderCaps.h"
22#include "GrTexture.h"
Brian Salomon336ce7b2017-09-08 08:23:58 -040023#include "GrTexturePriv.h"
Brian Salomon34169692017-08-28 15:32:01 -040024#include "GrTextureProxy.h"
25#include "SkGr.h"
Brian Salomon336ce7b2017-09-08 08:23:58 -040026#include "SkMathPriv.h"
Brian Salomona33b67c2018-05-17 10:42:14 -040027#include "SkMatrixPriv.h"
Brian Salomonb5ef1f92018-01-11 11:46:21 -050028#include "SkPoint.h"
29#include "SkPoint3.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040030#include "SkTo.h"
Brian Salomon34169692017-08-28 15:32:01 -040031#include "glsl/GrGLSLColorSpaceXformHelper.h"
Brian Salomonb5ef1f92018-01-11 11:46:21 -050032#include "glsl/GrGLSLFragmentShaderBuilder.h"
Brian Salomon34169692017-08-28 15:32:01 -040033#include "glsl/GrGLSLGeometryProcessor.h"
34#include "glsl/GrGLSLVarying.h"
Brian Salomonb5ef1f92018-01-11 11:46:21 -050035#include "glsl/GrGLSLVertexGeoBuilder.h"
Mike Klein79aea6a2018-06-11 10:45:26 -040036#include <new>
Brian Salomon34169692017-08-28 15:32:01 -040037
38namespace {
39
Brian Salomonb80ffee2018-05-23 16:39:39 -040040enum class Domain : bool { kNo = false, kYes = true };
41
Brian Salomon34169692017-08-28 15:32:01 -040042/**
43 * Geometry Processor that draws a texture modulated by a vertex color (though, this is meant to be
44 * the same value across all vertices of a quad and uses flat interpolation when available). This is
45 * used by TextureOp below.
46 */
47class TextureGeometryProcessor : public GrGeometryProcessor {
48public:
Brian Salomon17031a72018-05-22 14:14:07 -040049 template <typename Pos> struct VertexCommon {
50 using Position = Pos;
51 Position fPosition;
Brian Salomon34169692017-08-28 15:32:01 -040052 GrColor fColor;
Brian Salomon17031a72018-05-22 14:14:07 -040053 SkPoint fTextureCoords;
Brian Salomon34169692017-08-28 15:32:01 -040054 };
Brian Salomon17031a72018-05-22 14:14:07 -040055
Brian Salomon7eae3e02018-08-07 14:02:38 +000056 template <typename Pos, Domain D> struct OptionalDomainVertex;
Brian Salomon17031a72018-05-22 14:14:07 -040057 template <typename Pos>
Brian Salomon7eae3e02018-08-07 14:02:38 +000058 struct OptionalDomainVertex<Pos, Domain::kNo> : VertexCommon<Pos> {
Brian Salomonfdf05f42018-08-06 17:51:35 -040059 static constexpr Domain kDomain = Domain::kNo;
60 };
Brian Salomon7eae3e02018-08-07 14:02:38 +000061 template <typename Pos>
62 struct OptionalDomainVertex<Pos, Domain::kYes> : VertexCommon<Pos> {
Brian Salomonb80ffee2018-05-23 16:39:39 -040063 static constexpr Domain kDomain = Domain::kYes;
64 SkRect fTextureDomain;
65 };
66
Brian Salomon7eae3e02018-08-07 14:02:38 +000067 template <typename Pos, Domain D, GrAA> struct OptionalAAVertex;
68 template <typename Pos, Domain D>
69 struct OptionalAAVertex<Pos, D, GrAA::kNo> : OptionalDomainVertex<Pos, D> {
Brian Salomonb80ffee2018-05-23 16:39:39 -040070 static constexpr GrAA kAA = GrAA::kNo;
71 };
Brian Salomon7eae3e02018-08-07 14:02:38 +000072 template <typename Pos, Domain D>
73 struct OptionalAAVertex<Pos, D, GrAA::kYes> : OptionalDomainVertex<Pos, D> {
Brian Salomonbe3c1d22018-05-21 12:54:39 -040074 static constexpr GrAA kAA = GrAA::kYes;
Brian Salomonb5ef1f92018-01-11 11:46:21 -050075 SkPoint3 fEdges[4];
Brian Salomonb5ef1f92018-01-11 11:46:21 -050076 };
Brian Salomon336ce7b2017-09-08 08:23:58 -040077
Brian Salomon7eae3e02018-08-07 14:02:38 +000078 template <typename Pos, Domain D, GrAA AA>
79 using Vertex = OptionalAAVertex<Pos, D, AA>;
Brian Salomon336ce7b2017-09-08 08:23:58 -040080
Brian Salomon7eae3e02018-08-07 14:02:38 +000081 static sk_sp<GrGeometryProcessor> Make(GrTextureType textureType, GrPixelConfig textureConfig,
82 const GrSamplerState::Filter filter,
Brian Osman3ebd3542018-07-30 14:36:53 -040083 sk_sp<GrColorSpaceXform> textureColorSpaceXform,
84 sk_sp<GrColorSpaceXform> paintColorSpaceXform,
Brian Salomon7eae3e02018-08-07 14:02:38 +000085 bool coverageAA, bool perspective, Domain domain,
Brian Salomon336ce7b2017-09-08 08:23:58 -040086 const GrShaderCaps& caps) {
Brian Salomon7eae3e02018-08-07 14:02:38 +000087 return sk_sp<TextureGeometryProcessor>(new TextureGeometryProcessor(
88 textureType, textureConfig, filter, std::move(textureColorSpaceXform),
89 std::move(paintColorSpaceXform), coverageAA, perspective, domain, caps));
Brian Salomon34169692017-08-28 15:32:01 -040090 }
91
92 const char* name() const override { return "TextureGeometryProcessor"; }
93
94 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
Brian Osman3ebd3542018-07-30 14:36:53 -040095 b->add32(GrColorSpaceXform::XformKey(fTextureColorSpaceXform.get()));
96 b->add32(GrColorSpaceXform::XformKey(fPaintColorSpaceXform.get()));
Brian Salomonbe3c1d22018-05-21 12:54:39 -040097 uint32_t x = this->usesCoverageEdgeAA() ? 0 : 1;
Brian Osmand4c29702018-09-14 16:16:55 -040098 x |= kFloat3_GrVertexAttribType == fPositions.cpuType() ? 0 : 2;
Brian Salomonb80ffee2018-05-23 16:39:39 -040099 x |= fDomain.isInitialized() ? 4 : 0;
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400100 b->add32(x);
Brian Salomon34169692017-08-28 15:32:01 -0400101 }
102
103 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override {
104 class GLSLProcessor : public GrGLSLGeometryProcessor {
105 public:
106 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc,
107 FPCoordTransformIter&& transformIter) override {
108 const auto& textureGP = proc.cast<TextureGeometryProcessor>();
109 this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
Brian Osman3ebd3542018-07-30 14:36:53 -0400110 fTextureColorSpaceXformHelper.setData(
111 pdman, textureGP.fTextureColorSpaceXform.get());
112 fPaintColorSpaceXformHelper.setData(pdman, textureGP.fPaintColorSpaceXform.get());
Brian Salomon34169692017-08-28 15:32:01 -0400113 }
114
115 private:
116 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
Chris Dalton7b046312018-02-02 11:06:30 -0700117 using Interpolation = GrGLSLVaryingHandler::Interpolation;
Brian Salomon34169692017-08-28 15:32:01 -0400118 const auto& textureGP = args.fGP.cast<TextureGeometryProcessor>();
Brian Osman3ebd3542018-07-30 14:36:53 -0400119 fTextureColorSpaceXformHelper.emitCode(
120 args.fUniformHandler, textureGP.fTextureColorSpaceXform.get());
121 fPaintColorSpaceXformHelper.emitCode(
122 args.fUniformHandler, textureGP.fPaintColorSpaceXform.get(),
123 kVertex_GrShaderFlag);
Brian Osmand4c29702018-09-14 16:16:55 -0400124 if (kFloat2_GrVertexAttribType == textureGP.fPositions.cpuType()) {
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400125 args.fVaryingHandler->setNoPerspective();
126 }
Brian Salomon34169692017-08-28 15:32:01 -0400127 args.fVaryingHandler->emitAttributes(textureGP);
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400128 gpArgs->fPositionVar = textureGP.fPositions.asShaderVar();
129
Brian Salomon34169692017-08-28 15:32:01 -0400130 this->emitTransforms(args.fVertBuilder,
131 args.fVaryingHandler,
132 args.fUniformHandler,
Brian Salomon04460cc2017-12-06 14:47:42 -0500133 textureGP.fTextureCoords.asShaderVar(),
Brian Salomon34169692017-08-28 15:32:01 -0400134 args.fFPCoordTransformHandler);
Brian Osman3ebd3542018-07-30 14:36:53 -0400135 if (fPaintColorSpaceXformHelper.isNoop()) {
136 args.fVaryingHandler->addPassThroughAttribute(
137 textureGP.fColors, args.fOutputColor, Interpolation::kCanBeFlat);
138 } else {
139 GrGLSLVarying varying(kHalf4_GrSLType);
140 args.fVaryingHandler->addVarying("color", &varying);
141 args.fVertBuilder->codeAppend("half4 color = ");
142 args.fVertBuilder->appendColorGamutXform(textureGP.fColors.name(),
143 &fPaintColorSpaceXformHelper);
144 args.fVertBuilder->codeAppend(";");
145 args.fVertBuilder->codeAppendf("%s = half4(color.rgb * color.a, color.a);",
146 varying.vsOut());
147 args.fFragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn());
148 }
Ethan Nicholas8aa45692017-09-20 11:24:15 -0400149 args.fFragBuilder->codeAppend("float2 texCoord;");
Brian Salomon92be2f72018-06-19 14:33:47 -0400150 args.fVaryingHandler->addPassThroughAttribute(textureGP.fTextureCoords, "texCoord");
Brian Salomonb80ffee2018-05-23 16:39:39 -0400151 if (textureGP.fDomain.isInitialized()) {
152 args.fFragBuilder->codeAppend("float4 domain;");
153 args.fVaryingHandler->addPassThroughAttribute(
Brian Salomon92be2f72018-06-19 14:33:47 -0400154 textureGP.fDomain, "domain",
Brian Salomonb80ffee2018-05-23 16:39:39 -0400155 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
156 args.fFragBuilder->codeAppend(
157 "texCoord = clamp(texCoord, domain.xy, domain.zw);");
158 }
Brian Salomon7eae3e02018-08-07 14:02:38 +0000159 args.fFragBuilder->codeAppendf("%s = ", args.fOutputColor);
160 args.fFragBuilder->appendTextureLookupAndModulate(
161 args.fOutputColor, args.fTexSamplers[0], "texCoord", kFloat2_GrSLType,
162 &fTextureColorSpaceXformHelper);
Brian Salomon34169692017-08-28 15:32:01 -0400163 args.fFragBuilder->codeAppend(";");
Brian Salomon485b8c62018-01-12 15:11:06 -0500164 if (textureGP.usesCoverageEdgeAA()) {
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400165 bool mulByFragCoordW = false;
Brian Salomon9b4bd592018-07-10 09:23:40 -0400166 GrGLSLVarying aaDistVarying(kFloat4_GrSLType,
167 GrGLSLVarying::Scope::kVertToFrag);
Brian Osmand4c29702018-09-14 16:16:55 -0400168 if (kFloat3_GrVertexAttribType == textureGP.fPositions.cpuType()) {
Brian Salomon9b4bd592018-07-10 09:23:40 -0400169 args.fVaryingHandler->addVarying("aaDists", &aaDistVarying);
170 // The distance from edge equation e to homogenous point p=sk_Position
171 // is e.x*p.x/p.wx + e.y*p.y/p.w + e.z. However, we want screen space
172 // interpolation of this distance. We can do this by multiplying the
173 // varying in the VS by p.w and then multiplying by sk_FragCoord.w in
174 // the FS. So we output e.x*p.x + e.y*p.y + e.z * p.w
175 args.fVertBuilder->codeAppendf(
176 R"(%s = float4(dot(aaEdge0, %s), dot(aaEdge1, %s),
177 dot(aaEdge2, %s), dot(aaEdge3, %s));)",
178 aaDistVarying.vsOut(), textureGP.fPositions.name(),
179 textureGP.fPositions.name(), textureGP.fPositions.name(),
180 textureGP.fPositions.name());
181 mulByFragCoordW = true;
Brian Salomondba65f92018-01-22 08:43:38 -0500182 } else {
Brian Salomon9b4bd592018-07-10 09:23:40 -0400183 args.fVaryingHandler->addVarying("aaDists", &aaDistVarying);
184 args.fVertBuilder->codeAppendf(
185 R"(%s = float4(dot(aaEdge0.xy, %s.xy) + aaEdge0.z,
186 dot(aaEdge1.xy, %s.xy) + aaEdge1.z,
187 dot(aaEdge2.xy, %s.xy) + aaEdge2.z,
188 dot(aaEdge3.xy, %s.xy) + aaEdge3.z);)",
189 aaDistVarying.vsOut(), textureGP.fPositions.name(),
190 textureGP.fPositions.name(), textureGP.fPositions.name(),
191 textureGP.fPositions.name());
Brian Salomondba65f92018-01-22 08:43:38 -0500192 }
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500193 args.fFragBuilder->codeAppendf(
194 "float mindist = min(min(%s.x, %s.y), min(%s.z, %s.w));",
Brian Salomon9b4bd592018-07-10 09:23:40 -0400195 aaDistVarying.fsIn(), aaDistVarying.fsIn(), aaDistVarying.fsIn(),
196 aaDistVarying.fsIn());
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400197 if (mulByFragCoordW) {
198 args.fFragBuilder->codeAppend("mindist *= sk_FragCoord.w;");
199 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400200 args.fFragBuilder->codeAppendf("%s = float4(saturate(mindist));",
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500201 args.fOutputCoverage);
202 } else {
203 args.fFragBuilder->codeAppendf("%s = float4(1);", args.fOutputCoverage);
204 }
Brian Salomon34169692017-08-28 15:32:01 -0400205 }
Brian Osman3ebd3542018-07-30 14:36:53 -0400206 GrGLSLColorSpaceXformHelper fTextureColorSpaceXformHelper;
207 GrGLSLColorSpaceXformHelper fPaintColorSpaceXformHelper;
Brian Salomon34169692017-08-28 15:32:01 -0400208 };
209 return new GLSLProcessor;
210 }
211
Brian Salomon485b8c62018-01-12 15:11:06 -0500212 bool usesCoverageEdgeAA() const { return SkToBool(fAAEdges[0].isInitialized()); }
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500213
Brian Salomon34169692017-08-28 15:32:01 -0400214private:
Brian Salomon7eae3e02018-08-07 14:02:38 +0000215 TextureGeometryProcessor(GrTextureType textureType, GrPixelConfig textureConfig,
216 GrSamplerState::Filter filter,
Brian Salomon986f64c2018-08-06 15:25:15 -0400217 sk_sp<GrColorSpaceXform> textureColorSpaceXform,
Brian Salomon7eae3e02018-08-07 14:02:38 +0000218 sk_sp<GrColorSpaceXform> paintColorSpaceXform, bool coverageAA,
219 bool perspective, Domain domain, const GrShaderCaps& caps)
Brian Osman3ebd3542018-07-30 14:36:53 -0400220 : INHERITED(kTextureGeometryProcessor_ClassID)
221 , fTextureColorSpaceXform(std::move(textureColorSpaceXform))
Brian Salomon7eae3e02018-08-07 14:02:38 +0000222 , fPaintColorSpaceXform(std::move(paintColorSpaceXform))
223 , fSampler(textureType, textureConfig, filter) {
224 this->setTextureSamplerCnt(1);
Brian Salomon30e1a5e2018-05-18 12:32:32 -0400225
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400226 if (perspective) {
Brian Osmand4c29702018-09-14 16:16:55 -0400227 fPositions = {"position", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400228 } else {
Brian Osmand4c29702018-09-14 16:16:55 -0400229 fPositions = {"position", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400230 }
Brian Osmand4c29702018-09-14 16:16:55 -0400231 fColors = {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
232 fTextureCoords = {"textureCoords", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
Brian Salomon92be2f72018-06-19 14:33:47 -0400233 int vertexAttributeCnt = 3;
Brian Salomon30e1a5e2018-05-18 12:32:32 -0400234
Brian Salomonb80ffee2018-05-23 16:39:39 -0400235 if (domain == Domain::kYes) {
Brian Osmand4c29702018-09-14 16:16:55 -0400236 fDomain = {"domain", kFloat4_GrVertexAttribType, kFloat4_GrSLType};
Brian Salomon92be2f72018-06-19 14:33:47 -0400237 ++vertexAttributeCnt;
Brian Salomonb80ffee2018-05-23 16:39:39 -0400238 }
Brian Salomon485b8c62018-01-12 15:11:06 -0500239 if (coverageAA) {
Brian Osmand4c29702018-09-14 16:16:55 -0400240 fAAEdges[0] = {"aaEdge0", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
241 fAAEdges[1] = {"aaEdge1", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
242 fAAEdges[2] = {"aaEdge2", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
243 fAAEdges[3] = {"aaEdge3", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
Brian Salomon92be2f72018-06-19 14:33:47 -0400244 vertexAttributeCnt += 4;
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500245 }
Brian Salomon92be2f72018-06-19 14:33:47 -0400246 this->setVertexAttributeCnt(vertexAttributeCnt);
247 }
248
249 const Attribute& onVertexAttribute(int i) const override {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000250 return IthInitializedAttribute(i, fPositions, fColors, fTextureCoords, fDomain, fAAEdges[0],
251 fAAEdges[1], fAAEdges[2], fAAEdges[3]);
Brian Salomon34169692017-08-28 15:32:01 -0400252 }
253
Brian Salomon7eae3e02018-08-07 14:02:38 +0000254 const TextureSampler& onTextureSampler(int) const override { return fSampler; }
Brian Salomonf7dcd762018-07-30 14:48:15 -0400255
Brian Salomon34169692017-08-28 15:32:01 -0400256 Attribute fPositions;
Brian Salomon34169692017-08-28 15:32:01 -0400257 Attribute fColors;
Brian Salomon30e1a5e2018-05-18 12:32:32 -0400258 Attribute fTextureCoords;
Brian Salomonb80ffee2018-05-23 16:39:39 -0400259 Attribute fDomain;
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500260 Attribute fAAEdges[4];
Brian Osman3ebd3542018-07-30 14:36:53 -0400261 sk_sp<GrColorSpaceXform> fTextureColorSpaceXform;
262 sk_sp<GrColorSpaceXform> fPaintColorSpaceXform;
Brian Salomon7eae3e02018-08-07 14:02:38 +0000263 TextureSampler fSampler;
Ethan Nicholasabff9562017-10-09 10:54:08 -0400264
265 typedef GrGeometryProcessor INHERITED;
Brian Salomon34169692017-08-28 15:32:01 -0400266};
267
Brian Salomon6872e942018-05-18 10:29:54 -0400268// This computes the four edge equations for a quad, then outsets them and computes a new quad
269// as the intersection points of the outset edges. 'x' and 'y' contain the original points as input
270// and the outset points as output. 'a', 'b', and 'c' are the edge equation coefficients on output.
271static void compute_quad_edges_and_outset_vertices(Sk4f* x, Sk4f* y, Sk4f* a, Sk4f* b, Sk4f* c) {
272 static constexpr auto fma = SkNx_fma<4, float>;
273 // These rotate the points/edge values either clockwise or counterclockwise assuming tri strip
274 // order.
275 auto nextCW = [](const Sk4f& v) { return SkNx_shuffle<2, 0, 3, 1>(v); };
276 auto nextCCW = [](const Sk4f& v) { return SkNx_shuffle<1, 3, 0, 2>(v); };
277
278 auto xnext = nextCCW(*x);
279 auto ynext = nextCCW(*y);
280 *a = ynext - *y;
281 *b = *x - xnext;
282 *c = fma(xnext, *y, -ynext * *x);
283 Sk4f invNormLengths = (*a * *a + *b * *b).rsqrt();
284 // Make sure the edge equations have their normals facing into the quad in device space.
285 auto test = fma(*a, nextCW(*x), fma(*b, nextCW(*y), *c));
286 if ((test < Sk4f(0)).anyTrue()) {
287 invNormLengths = -invNormLengths;
288 }
289 *a *= invNormLengths;
290 *b *= invNormLengths;
291 *c *= invNormLengths;
292
293 // Here is the outset. This makes our edge equations compute coverage without requiring a
294 // half pixel offset and is also used to compute the bloated quad that will cover all
295 // pixels.
296 *c += Sk4f(0.5f);
297
298 // Reverse the process to compute the points of the bloated quad from the edge equations.
299 // This time the inputs don't have 1s as their third coord and we want to homogenize rather
300 // than normalize.
301 auto anext = nextCW(*a);
302 auto bnext = nextCW(*b);
303 auto cnext = nextCW(*c);
304 *x = fma(bnext, *c, -*b * cnext);
305 *y = fma(*a, cnext, -anext * *c);
306 auto ic = (fma(anext, *b, -bnext * *a)).invert();
307 *x *= ic;
308 *y *= ic;
309}
310
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500311namespace {
312// This is a class soley so it can be partially specialized (functions cannot be).
Brian Salomon86c40012018-05-22 10:48:49 -0400313template <typename V, GrAA AA = V::kAA, typename Position = typename V::Position>
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400314class VertexAAHandler;
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500315
Brian Salomon86c40012018-05-22 10:48:49 -0400316template<typename V> class VertexAAHandler<V, GrAA::kNo, SkPoint> {
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500317public:
Brian Salomon86c40012018-05-22 10:48:49 -0400318 static void AssignPositionsAndTexCoords(V* vertices, const GrPerspQuad& quad,
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500319 const SkRect& texRect) {
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400320 SkASSERT((quad.w4f() == Sk4f(1.f)).allTrue());
Brian Salomon86c40012018-05-22 10:48:49 -0400321 SkPointPriv::SetRectTriStrip(&vertices[0].fTextureCoords, texRect, sizeof(V));
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400322 for (int i = 0; i < 4; ++i) {
323 vertices[i].fPosition = {quad.x(i), quad.y(i)};
324 }
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500325 }
326};
327
Brian Salomon86c40012018-05-22 10:48:49 -0400328template<typename V> class VertexAAHandler<V, GrAA::kNo, SkPoint3> {
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500329public:
Brian Salomon86c40012018-05-22 10:48:49 -0400330 static void AssignPositionsAndTexCoords(V* vertices, const GrPerspQuad& quad,
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500331 const SkRect& texRect) {
Brian Salomon86c40012018-05-22 10:48:49 -0400332 SkPointPriv::SetRectTriStrip(&vertices[0].fTextureCoords, texRect, sizeof(V));
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400333 for (int i = 0; i < 4; ++i) {
334 vertices[i].fPosition = quad.point(i);
335 }
336 }
337};
338
Brian Salomon86c40012018-05-22 10:48:49 -0400339template<typename V> class VertexAAHandler<V, GrAA::kYes, SkPoint> {
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400340public:
Brian Salomon86c40012018-05-22 10:48:49 -0400341 static void AssignPositionsAndTexCoords(V* vertices, const GrPerspQuad& quad,
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400342 const SkRect& texRect) {
343 SkASSERT((quad.w4f() == Sk4f(1.f)).allTrue());
Brian Salomon6872e942018-05-18 10:29:54 -0400344 auto x = quad.x4f();
345 auto y = quad.y4f();
346 Sk4f a, b, c;
347 compute_quad_edges_and_outset_vertices(&x, &y, &a, &b, &c);
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500348
349 for (int i = 0; i < 4; ++i) {
Brian Salomon6872e942018-05-18 10:29:54 -0400350 vertices[i].fPosition = {x[i], y[i]};
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500351 for (int j = 0; j < 4; ++j) {
Brian Salomon6872e942018-05-18 10:29:54 -0400352 vertices[i].fEdges[j] = {a[j], b[j], c[j]};
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500353 }
354 }
355
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500356 AssignTexCoords(vertices, quad, texRect);
357 }
358
359private:
Brian Salomon86c40012018-05-22 10:48:49 -0400360 static void AssignTexCoords(V* vertices, const GrPerspQuad& quad, const SkRect& tex) {
Brian Salomona33b67c2018-05-17 10:42:14 -0400361 SkMatrix q = SkMatrix::MakeAll(quad.x(0), quad.x(1), quad.x(2),
362 quad.y(0), quad.y(1), quad.y(2),
363 1.f, 1.f, 1.f);
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500364 SkMatrix qinv;
365 if (!q.invert(&qinv)) {
366 return;
367 }
368 SkMatrix t = SkMatrix::MakeAll(tex.fLeft, tex.fLeft, tex.fRight,
369 tex.fTop, tex.fBottom, tex.fTop,
370 1.f, 1.f, 1.f);
371 SkMatrix map;
372 map.setConcat(t, qinv);
Brian Salomon86c40012018-05-22 10:48:49 -0400373 SkMatrixPriv::MapPointsWithStride(map, &vertices[0].fTextureCoords, sizeof(V),
374 &vertices[0].fPosition, sizeof(V), 4);
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500375 }
376};
377
Brian Salomon86c40012018-05-22 10:48:49 -0400378template<typename V> class VertexAAHandler<V, GrAA::kYes, SkPoint3> {
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400379public:
Brian Salomon86c40012018-05-22 10:48:49 -0400380 static void AssignPositionsAndTexCoords(V* vertices, const GrPerspQuad& quad,
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400381 const SkRect& texRect) {
382 auto x = quad.x4f();
383 auto y = quad.y4f();
384 auto iw = quad.iw4f();
385 x *= iw;
386 y *= iw;
387
388 // Get an equation for w from device space coords.
389 SkMatrix P;
390 P.setAll(x[0], y[0], 1, x[1], y[1], 1, x[2], y[2], 1);
391 SkAssertResult(P.invert(&P));
392 SkPoint3 weq{quad.w(0), quad.w(1), quad.w(2)};
393 P.mapHomogeneousPoints(&weq, &weq, 1);
394
395 Sk4f a, b, c;
396 compute_quad_edges_and_outset_vertices(&x, &y, &a, &b, &c);
397
398 // Compute new w values for the output vertices;
399 auto w = Sk4f(weq.fX) * x + Sk4f(weq.fY) * y + Sk4f(weq.fZ);
400 x *= w;
401 y *= w;
402
403 for (int i = 0; i < 4; ++i) {
404 vertices[i].fPosition = {x[i], y[i], w[i]};
405 for (int j = 0; j < 4; ++j) {
406 vertices[i].fEdges[j] = {a[j], b[j], c[j]};
407 }
408 }
409
410 AssignTexCoords(vertices, quad, texRect);
411 }
412
413private:
Brian Salomon86c40012018-05-22 10:48:49 -0400414 static void AssignTexCoords(V* vertices, const GrPerspQuad& quad, const SkRect& tex) {
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400415 SkMatrix q = SkMatrix::MakeAll(quad.x(0), quad.x(1), quad.x(2),
416 quad.y(0), quad.y(1), quad.y(2),
417 quad.w(0), quad.w(1), quad.w(2));
418 SkMatrix qinv;
419 if (!q.invert(&qinv)) {
420 return;
421 }
422 SkMatrix t = SkMatrix::MakeAll(tex.fLeft, tex.fLeft, tex.fRight,
423 tex.fTop, tex.fBottom, tex.fTop,
424 1.f, 1.f, 1.f);
425 SkMatrix map;
426 map.setConcat(t, qinv);
427 SkPoint3 tempTexCoords[4];
428 SkMatrixPriv::MapHomogeneousPointsWithStride(map, tempTexCoords, sizeof(SkPoint3),
Brian Salomon86c40012018-05-22 10:48:49 -0400429 &vertices[0].fPosition, sizeof(V), 4);
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400430 for (int i = 0; i < 4; ++i) {
431 auto invW = 1.f / tempTexCoords[i].fZ;
432 vertices[i].fTextureCoords.fX = tempTexCoords[i].fX * invW;
433 vertices[i].fTextureCoords.fY = tempTexCoords[i].fY * invW;
434 }
435 }
436};
437
Brian Salomonb80ffee2018-05-23 16:39:39 -0400438template <typename V, Domain D = V::kDomain> struct DomainAssigner;
439
440template <typename V> struct DomainAssigner<V, Domain::kYes> {
441 static void Assign(V* vertices, Domain domain, GrSamplerState::Filter filter,
442 const SkRect& srcRect, GrSurfaceOrigin origin, float iw, float ih) {
443 static constexpr SkRect kLargeRect = {-2, -2, 2, 2};
444 SkRect domainRect;
445 if (domain == Domain::kYes) {
446 auto ltrb = Sk4f::Load(&srcRect);
447 if (filter == GrSamplerState::Filter::kBilerp) {
448 auto rblt = SkNx_shuffle<2, 3, 0, 1>(ltrb);
449 auto whwh = (rblt - ltrb).abs();
450 auto c = (rblt + ltrb) * 0.5f;
451 static const Sk4f kOffsets = {0.5f, 0.5f, -0.5f, -0.5f};
452 ltrb = (whwh < 1.f).thenElse(c, ltrb + kOffsets);
453 }
454 ltrb *= Sk4f(iw, ih, iw, ih);
455 if (origin == kBottomLeft_GrSurfaceOrigin) {
456 static const Sk4f kMul = {1.f, -1.f, 1.f, -1.f};
457 static const Sk4f kAdd = {0.f, 1.f, 0.f, 1.f};
458 ltrb = SkNx_shuffle<0, 3, 2, 1>(kMul * ltrb + kAdd);
459 }
460 ltrb.store(&domainRect);
461 } else {
462 domainRect = kLargeRect;
463 }
464 for (int i = 0; i < 4; ++i) {
465 vertices[i].fTextureDomain = domainRect;
466 }
467 }
468};
469
470template <typename V> struct DomainAssigner<V, Domain::kNo> {
471 static void Assign(V*, Domain domain, GrSamplerState::Filter, const SkRect&, GrSurfaceOrigin,
472 float iw, float ih) {
473 SkASSERT(domain == Domain::kNo);
474 }
475};
476
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500477} // anonymous namespace
478
Brian Salomon86c40012018-05-22 10:48:49 -0400479template <typename V>
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400480static void tessellate_quad(const GrPerspQuad& devQuad, const SkRect& srcRect, GrColor color,
Brian Salomonb80ffee2018-05-23 16:39:39 -0400481 GrSurfaceOrigin origin, GrSamplerState::Filter filter, V* vertices,
Brian Salomon7eae3e02018-08-07 14:02:38 +0000482 SkScalar iw, SkScalar ih, Domain domain) {
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500483 SkRect texRect = {
484 iw * srcRect.fLeft,
485 ih * srcRect.fTop,
486 iw * srcRect.fRight,
487 ih * srcRect.fBottom
488 };
489 if (origin == kBottomLeft_GrSurfaceOrigin) {
490 texRect.fTop = 1.f - texRect.fTop;
491 texRect.fBottom = 1.f - texRect.fBottom;
492 }
Brian Salomon86c40012018-05-22 10:48:49 -0400493 VertexAAHandler<V>::AssignPositionsAndTexCoords(vertices, devQuad, texRect);
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500494 vertices[0].fColor = color;
495 vertices[1].fColor = color;
496 vertices[2].fColor = color;
497 vertices[3].fColor = color;
Brian Salomonb80ffee2018-05-23 16:39:39 -0400498 DomainAssigner<V>::Assign(vertices, domain, filter, srcRect, origin, iw, ih);
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500499}
Brian Salomon17031a72018-05-22 14:14:07 -0400500
Brian Salomon34169692017-08-28 15:32:01 -0400501/**
502 * Op that implements GrTextureOp::Make. It draws textured quads. Each quad can modulate against a
503 * the texture by color. The blend with the destination is always src-over. The edges are non-AA.
504 */
505class TextureOp final : public GrMeshDrawOp {
506public:
Robert Phillips7c525e62018-06-12 10:11:12 -0400507 static std::unique_ptr<GrDrawOp> Make(GrContext* context,
508 sk_sp<GrTextureProxy> proxy,
509 GrSamplerState::Filter filter,
510 GrColor color,
511 const SkRect& srcRect,
512 const SkRect& dstRect,
513 GrAAType aaType,
514 SkCanvas::SrcRectConstraint constraint,
Brian Osman2b23c4b2018-06-01 12:25:08 -0400515 const SkMatrix& viewMatrix,
Brian Osman3ebd3542018-07-30 14:36:53 -0400516 sk_sp<GrColorSpaceXform> textureColorSpaceXform,
517 sk_sp<GrColorSpaceXform> paintColorSpaceXform) {
Robert Phillipsc994a932018-06-19 13:09:54 -0400518 GrOpMemoryPool* pool = context->contextPriv().opMemoryPool();
519
520 return pool->allocate<TextureOp>(std::move(proxy), filter, color,
521 srcRect, dstRect, aaType, constraint,
Brian Osman3ebd3542018-07-30 14:36:53 -0400522 viewMatrix, std::move(textureColorSpaceXform),
523 std::move(paintColorSpaceXform));
Brian Salomon34169692017-08-28 15:32:01 -0400524 }
525
Brian Salomon336ce7b2017-09-08 08:23:58 -0400526 ~TextureOp() override {
527 if (fFinalized) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000528 fProxy->completedRead();
Brian Salomon336ce7b2017-09-08 08:23:58 -0400529 } else {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000530 fProxy->unref();
Brian Salomon336ce7b2017-09-08 08:23:58 -0400531 }
532 }
Brian Salomon34169692017-08-28 15:32:01 -0400533
534 const char* name() const override { return "TextureOp"; }
535
Brian Salomon7eae3e02018-08-07 14:02:38 +0000536 void visitProxies(const VisitProxyFunc& func) const override { func(fProxy); }
Robert Phillipsb493eeb2017-09-13 13:10:52 -0400537
Brian Salomon34169692017-08-28 15:32:01 -0400538 SkString dumpInfo() const override {
539 SkString str;
Brian Salomon34169692017-08-28 15:32:01 -0400540 str.appendf("# draws: %d\n", fDraws.count());
Brian Salomon7eae3e02018-08-07 14:02:38 +0000541 str.appendf("Proxy ID: %d, Filter: %d\n", fProxy->uniqueID().asUInt(),
542 static_cast<int>(fFilter));
Brian Salomon34169692017-08-28 15:32:01 -0400543 for (int i = 0; i < fDraws.count(); ++i) {
544 const Draw& draw = fDraws[i];
545 str.appendf(
Brian Salomon7eae3e02018-08-07 14:02:38 +0000546 "%d: Color: 0x%08x, TexRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f] "
Brian Salomon336ce7b2017-09-08 08:23:58 -0400547 "Quad [(%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f)]\n",
Brian Salomon7eae3e02018-08-07 14:02:38 +0000548 i, draw.color(), draw.srcRect().fLeft, draw.srcRect().fTop,
Brian Salomonb80ffee2018-05-23 16:39:39 -0400549 draw.srcRect().fRight, draw.srcRect().fBottom, draw.quad().point(0).fX,
550 draw.quad().point(0).fY, draw.quad().point(1).fX, draw.quad().point(1).fY,
551 draw.quad().point(2).fX, draw.quad().point(2).fY, draw.quad().point(3).fX,
552 draw.quad().point(3).fY);
Brian Salomon34169692017-08-28 15:32:01 -0400553 }
554 str += INHERITED::dumpInfo();
555 return str;
556 }
557
Brian Osman532b3f92018-07-11 10:02:07 -0400558 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
Brian Salomon34169692017-08-28 15:32:01 -0400559 SkASSERT(!fFinalized);
560 fFinalized = true;
Brian Salomon7eae3e02018-08-07 14:02:38 +0000561 fProxy->addPendingRead();
562 fProxy->unref();
Brian Salomon34169692017-08-28 15:32:01 -0400563 return RequiresDstTexture::kNo;
564 }
565
Brian Salomon485b8c62018-01-12 15:11:06 -0500566 FixedFunctionFlags fixedFunctionFlags() const override {
567 return this->aaType() == GrAAType::kMSAA ? FixedFunctionFlags::kUsesHWAA
568 : FixedFunctionFlags::kNone;
569 }
Brian Salomon34169692017-08-28 15:32:01 -0400570
571 DEFINE_OP_CLASS_ID
572
573private:
Robert Phillips7c525e62018-06-12 10:11:12 -0400574 friend class ::GrOpMemoryPool;
Brian Salomon762d5e72017-12-01 10:25:08 -0500575
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400576 TextureOp(sk_sp<GrTextureProxy> proxy, GrSamplerState::Filter filter, GrColor color,
Brian Salomon485b8c62018-01-12 15:11:06 -0500577 const SkRect& srcRect, const SkRect& dstRect, GrAAType aaType,
Brian Salomonb80ffee2018-05-23 16:39:39 -0400578 SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix,
Brian Osman3ebd3542018-07-30 14:36:53 -0400579 sk_sp<GrColorSpaceXform> textureColorSpaceXform,
580 sk_sp<GrColorSpaceXform> paintColorSpaceXform)
Brian Salomon34169692017-08-28 15:32:01 -0400581 : INHERITED(ClassID())
Brian Osman3ebd3542018-07-30 14:36:53 -0400582 , fTextureColorSpaceXform(std::move(textureColorSpaceXform))
583 , fPaintColorSpaceXform(std::move(paintColorSpaceXform))
Brian Salomon7eae3e02018-08-07 14:02:38 +0000584 , fProxy(proxy.release())
585 , fFilter(filter)
Brian Salomon485b8c62018-01-12 15:11:06 -0500586 , fAAType(static_cast<unsigned>(aaType))
Brian Osman2b23c4b2018-06-01 12:25:08 -0400587 , fFinalized(0) {
Brian Salomon485b8c62018-01-12 15:11:06 -0500588 SkASSERT(aaType != GrAAType::kMixedSamples);
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400589 fPerspective = viewMatrix.hasPerspective();
Brian Salomon594b64c2018-05-29 12:47:57 -0400590 auto quad = GrPerspQuad(dstRect, viewMatrix);
591 auto bounds = quad.bounds();
592#ifndef SK_DONT_DROP_UNNECESSARY_AA_IN_TEXTURE_OP
593 if (GrAAType::kCoverage == this->aaType() && viewMatrix.rectStaysRect()) {
594 // Disable coverage AA when rect falls on integers in device space.
595 auto is_int = [](float f) { return f == sk_float_floor(f); };
596 if (is_int(bounds.fLeft) && is_int(bounds.fTop) && is_int(bounds.fRight) &&
597 is_int(bounds.fBottom)) {
598 fAAType = static_cast<unsigned>(GrAAType::kNone);
599 // We may have had a strict constraint with nearest filter soley due to possible AA
600 // bloat. In that case it's no longer necessary.
601 if (constraint == SkCanvas::kStrict_SrcRectConstraint &&
602 filter == GrSamplerState::Filter::kNearest) {
603 constraint = SkCanvas::kFast_SrcRectConstraint;
604 }
605 }
606 }
607#endif
Brian Salomon7eae3e02018-08-07 14:02:38 +0000608 const auto& draw = fDraws.emplace_back(srcRect, quad, constraint, color);
Brian Salomon34169692017-08-28 15:32:01 -0400609 this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
Brian Salomon594b64c2018-05-29 12:47:57 -0400610 fDomain = static_cast<bool>(draw.domain());
Brian Salomon34169692017-08-28 15:32:01 -0400611 }
612
Brian Salomon7eae3e02018-08-07 14:02:38 +0000613 template <typename Pos, Domain D, GrAA AA>
Brian Salomoncd7907b2018-08-30 08:36:18 -0400614 void tess(void* v, const GrGeometryProcessor* gp) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000615 using Vertex = TextureGeometryProcessor::Vertex<Pos, D, AA>;
Brian Salomon92be2f72018-06-19 14:33:47 -0400616 SkASSERT(gp->debugOnly_vertexStride() == sizeof(Vertex));
Brian Salomon17031a72018-05-22 14:14:07 -0400617 auto vertices = static_cast<Vertex*>(v);
Brian Salomon7eae3e02018-08-07 14:02:38 +0000618 auto origin = fProxy->origin();
619 const auto* texture = fProxy->peekTexture();
620 float iw = 1.f / texture->width();
621 float ih = 1.f / texture->height();
622
Brian Salomon17031a72018-05-22 14:14:07 -0400623 for (const auto& draw : fDraws) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000624 tessellate_quad<Vertex>(draw.quad(), draw.srcRect(), draw.color(), origin, fFilter,
625 vertices, iw, ih, draw.domain());
Brian Salomon17031a72018-05-22 14:14:07 -0400626 vertices += 4;
627 }
628 }
629
Brian Salomon34169692017-08-28 15:32:01 -0400630 void onPrepareDraws(Target* target) override {
Brian Salomoncd7907b2018-08-30 08:36:18 -0400631 if (!fProxy->instantiate(target->resourceProvider())) {
632 return;
Brian Salomon34169692017-08-28 15:32:01 -0400633 }
Brian Salomon336ce7b2017-09-08 08:23:58 -0400634
Brian Salomoncd7907b2018-08-30 08:36:18 -0400635 Domain domain = fDomain ? Domain::kYes : Domain::kNo;
Brian Salomon485b8c62018-01-12 15:11:06 -0500636 bool coverageAA = GrAAType::kCoverage == this->aaType();
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400637 sk_sp<GrGeometryProcessor> gp = TextureGeometryProcessor::Make(
Brian Salomon7eae3e02018-08-07 14:02:38 +0000638 fProxy->textureType(), fProxy->config(), fFilter,
639 std::move(fTextureColorSpaceXform), std::move(fPaintColorSpaceXform), coverageAA,
Brian Salomoncd7907b2018-08-30 08:36:18 -0400640 fPerspective, domain, *target->caps().shaderCaps());
Brian Salomon34169692017-08-28 15:32:01 -0400641 GrPipeline::InitArgs args;
642 args.fProxy = target->proxy();
643 args.fCaps = &target->caps();
644 args.fResourceProvider = target->resourceProvider();
Brian Salomon485b8c62018-01-12 15:11:06 -0500645 args.fFlags = 0;
Brian Salomon485b8c62018-01-12 15:11:06 -0500646 if (GrAAType::kMSAA == this->aaType()) {
647 args.fFlags |= GrPipeline::kHWAntialias_Flag;
648 }
649
Brian Salomon49348902018-06-26 09:12:38 -0400650 auto clip = target->detachAppliedClip();
Brian Salomoncd7907b2018-08-30 08:36:18 -0400651 auto* fixedDynamicState = target->allocFixedDynamicState(clip.scissorState().rect(), 1);
652 fixedDynamicState->fPrimitiveProcessorTextures[0] = fProxy;
Brian Salomon49348902018-06-26 09:12:38 -0400653 const auto* pipeline =
654 target->allocPipeline(args, GrProcessorSet::MakeEmptySet(), std::move(clip));
Brian Salomon7eae3e02018-08-07 14:02:38 +0000655 using TessFn = decltype(&TextureOp::tess<SkPoint, Domain::kNo, GrAA::kNo>);
656#define TESS_FN_AND_VERTEX_SIZE(Point, Domain, AA) \
657 { \
658 &TextureOp::tess<Point, Domain, AA>, \
659 sizeof(TextureGeometryProcessor::Vertex<Point, Domain, AA>) \
Brian Salomon92be2f72018-06-19 14:33:47 -0400660 }
661 static constexpr struct {
662 TessFn fTessFn;
663 size_t fVertexSize;
664 } kTessFnsAndVertexSizes[] = {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000665 TESS_FN_AND_VERTEX_SIZE(SkPoint, Domain::kNo, GrAA::kNo),
666 TESS_FN_AND_VERTEX_SIZE(SkPoint, Domain::kNo, GrAA::kYes),
667 TESS_FN_AND_VERTEX_SIZE(SkPoint, Domain::kYes, GrAA::kNo),
668 TESS_FN_AND_VERTEX_SIZE(SkPoint, Domain::kYes, GrAA::kYes),
669 TESS_FN_AND_VERTEX_SIZE(SkPoint3, Domain::kNo, GrAA::kNo),
670 TESS_FN_AND_VERTEX_SIZE(SkPoint3, Domain::kNo, GrAA::kYes),
671 TESS_FN_AND_VERTEX_SIZE(SkPoint3, Domain::kYes, GrAA::kNo),
672 TESS_FN_AND_VERTEX_SIZE(SkPoint3, Domain::kYes, GrAA::kYes),
Brian Salomon92be2f72018-06-19 14:33:47 -0400673 };
674#undef TESS_FN_AND_VERTEX_SIZE
675 int tessFnIdx = 0;
Brian Salomoncd7907b2018-08-30 08:36:18 -0400676 tessFnIdx |= coverageAA ? 0x1 : 0x0;
677 tessFnIdx |= fDomain ? 0x2 : 0x0;
678 tessFnIdx |= fPerspective ? 0x4 : 0x0;
Brian Salomon92be2f72018-06-19 14:33:47 -0400679
680 SkASSERT(kTessFnsAndVertexSizes[tessFnIdx].fVertexSize == gp->debugOnly_vertexStride());
681
Brian Salomoncd7907b2018-08-30 08:36:18 -0400682 int vstart;
683 const GrBuffer* vbuffer;
684 void* vdata = target->makeVertexSpace(kTessFnsAndVertexSizes[tessFnIdx].fVertexSize,
685 4 * fDraws.count(), &vbuffer, &vstart);
686 if (!vdata) {
687 SkDebugf("Could not allocate vertices\n");
688 return;
689 }
Brian Salomon2d0a6a12018-08-22 15:22:24 +0000690
Brian Salomoncd7907b2018-08-30 08:36:18 -0400691 (this->*(kTessFnsAndVertexSizes[tessFnIdx].fTessFn))(vdata, gp.get());
Brian Salomon2d0a6a12018-08-22 15:22:24 +0000692
Brian Salomoncd7907b2018-08-30 08:36:18 -0400693 GrPrimitiveType primitiveType =
694 fDraws.count() > 1 ? GrPrimitiveType::kTriangles : GrPrimitiveType::kTriangleStrip;
695 GrMesh* mesh = target->allocMesh(primitiveType);
696 if (fDraws.count() > 1) {
Brian Salomon5e81a122018-08-23 16:46:07 -0400697 sk_sp<const GrBuffer> ibuffer = target->resourceProvider()->refQuadIndexBuffer();
698 if (!ibuffer) {
699 SkDebugf("Could not allocate quad indices\n");
700 return;
Brian Salomon2d0a6a12018-08-22 15:22:24 +0000701 }
Brian Salomoncd7907b2018-08-30 08:36:18 -0400702 mesh->setIndexedPatterned(ibuffer.get(), 6, 4, fDraws.count(),
703 GrResourceProvider::QuadCountOfQuadBuffer());
704 } else {
705 mesh->setNonIndexedNonInstanced(4);
Brian Salomon34169692017-08-28 15:32:01 -0400706 }
Brian Salomoncd7907b2018-08-30 08:36:18 -0400707 mesh->setVertexData(vbuffer, vstart);
708 target->draw(std::move(gp), pipeline, fixedDynamicState, mesh);
Brian Salomon34169692017-08-28 15:32:01 -0400709 }
710
Brian Salomoncd7907b2018-08-30 08:36:18 -0400711 CombineResult onCombineIfPossible(GrOp* t, const GrCaps&) override {
Brian Salomon34169692017-08-28 15:32:01 -0400712 const auto* that = t->cast<TextureOp>();
Brian Osman3ebd3542018-07-30 14:36:53 -0400713 if (!GrColorSpaceXform::Equals(fTextureColorSpaceXform.get(),
714 that->fTextureColorSpaceXform.get())) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000715 return CombineResult::kCannotCombine;
Brian Osman3ebd3542018-07-30 14:36:53 -0400716 }
717 if (!GrColorSpaceXform::Equals(fPaintColorSpaceXform.get(),
718 that->fPaintColorSpaceXform.get())) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000719 return CombineResult::kCannotCombine;
Brian Salomon34169692017-08-28 15:32:01 -0400720 }
Brian Salomon485b8c62018-01-12 15:11:06 -0500721 if (this->aaType() != that->aaType()) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000722 return CombineResult::kCannotCombine;
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500723 }
Brian Salomoncd7907b2018-08-30 08:36:18 -0400724 if (fProxy->uniqueID() != that->fProxy->uniqueID() || fFilter != that->fFilter) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000725 return CombineResult::kCannotCombine;
Brian Salomon336ce7b2017-09-08 08:23:58 -0400726 }
Brian Salomon7eae3e02018-08-07 14:02:38 +0000727 fDraws.push_back_n(that->fDraws.count(), that->fDraws.begin());
Brian Salomon34169692017-08-28 15:32:01 -0400728 this->joinBounds(*that);
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400729 fPerspective |= that->fPerspective;
Brian Salomonb80ffee2018-05-23 16:39:39 -0400730 fDomain |= that->fDomain;
Brian Salomon7eae3e02018-08-07 14:02:38 +0000731 return CombineResult::kMerged;
Brian Salomon34169692017-08-28 15:32:01 -0400732 }
733
Brian Salomon485b8c62018-01-12 15:11:06 -0500734 GrAAType aaType() const { return static_cast<GrAAType>(fAAType); }
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500735
Brian Salomonb80ffee2018-05-23 16:39:39 -0400736 class Draw {
737 public:
Brian Salomon7eae3e02018-08-07 14:02:38 +0000738 Draw(const SkRect& srcRect, const GrPerspQuad& quad, SkCanvas::SrcRectConstraint constraint,
739 GrColor color)
Brian Salomonb80ffee2018-05-23 16:39:39 -0400740 : fSrcRect(srcRect)
Brian Salomonb80ffee2018-05-23 16:39:39 -0400741 , fQuad(quad)
Brian Salomon7eae3e02018-08-07 14:02:38 +0000742 , fColor(color)
743 , fHasDomain(constraint == SkCanvas::kStrict_SrcRectConstraint) {}
Brian Salomonb80ffee2018-05-23 16:39:39 -0400744 const GrPerspQuad& quad() const { return fQuad; }
Brian Salomonb80ffee2018-05-23 16:39:39 -0400745 const SkRect& srcRect() const { return fSrcRect; }
746 GrColor color() const { return fColor; }
747 Domain domain() const { return Domain(fHasDomain); }
Brian Salomonb80ffee2018-05-23 16:39:39 -0400748
749 private:
Brian Salomon34169692017-08-28 15:32:01 -0400750 SkRect fSrcRect;
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400751 GrPerspQuad fQuad;
Brian Salomon34169692017-08-28 15:32:01 -0400752 GrColor fColor;
Brian Salomon7eae3e02018-08-07 14:02:38 +0000753 bool fHasDomain;
Brian Salomon34169692017-08-28 15:32:01 -0400754 };
755 SkSTArray<1, Draw, true> fDraws;
Brian Osman3ebd3542018-07-30 14:36:53 -0400756 sk_sp<GrColorSpaceXform> fTextureColorSpaceXform;
757 sk_sp<GrColorSpaceXform> fPaintColorSpaceXform;
Brian Salomon7eae3e02018-08-07 14:02:38 +0000758 GrTextureProxy* fProxy;
759 GrSamplerState::Filter fFilter;
Brian Salomon485b8c62018-01-12 15:11:06 -0500760 unsigned fAAType : 2;
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400761 unsigned fPerspective : 1;
Brian Salomonb80ffee2018-05-23 16:39:39 -0400762 unsigned fDomain : 1;
Brian Salomon34169692017-08-28 15:32:01 -0400763 // Used to track whether fProxy is ref'ed or has a pending IO after finalize() is called.
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500764 unsigned fFinalized : 1;
Brian Salomon336ce7b2017-09-08 08:23:58 -0400765
Brian Salomon34169692017-08-28 15:32:01 -0400766 typedef GrMeshDrawOp INHERITED;
767};
768
769} // anonymous namespace
770
771namespace GrTextureOp {
772
Robert Phillips7c525e62018-06-12 10:11:12 -0400773std::unique_ptr<GrDrawOp> Make(GrContext* context,
774 sk_sp<GrTextureProxy> proxy,
775 GrSamplerState::Filter filter,
776 GrColor color,
777 const SkRect& srcRect,
778 const SkRect& dstRect,
779 GrAAType aaType,
780 SkCanvas::SrcRectConstraint constraint,
781 const SkMatrix& viewMatrix,
Brian Osman3ebd3542018-07-30 14:36:53 -0400782 sk_sp<GrColorSpaceXform> textureColorSpaceXform,
783 sk_sp<GrColorSpaceXform> paintColorSpaceXform) {
Robert Phillips7c525e62018-06-12 10:11:12 -0400784 return TextureOp::Make(context, std::move(proxy), filter, color, srcRect, dstRect, aaType,
Brian Osman3ebd3542018-07-30 14:36:53 -0400785 constraint, viewMatrix, std::move(textureColorSpaceXform),
786 std::move(paintColorSpaceXform));
Brian Salomon34169692017-08-28 15:32:01 -0400787}
788
789} // namespace GrTextureOp
790
791#if GR_TEST_UTILS
792#include "GrContext.h"
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500793#include "GrContextPriv.h"
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500794#include "GrProxyProvider.h"
Brian Salomon34169692017-08-28 15:32:01 -0400795
796GR_DRAW_OP_TEST_DEFINE(TextureOp) {
797 GrSurfaceDesc desc;
798 desc.fConfig = kRGBA_8888_GrPixelConfig;
799 desc.fHeight = random->nextULessThan(90) + 10;
800 desc.fWidth = random->nextULessThan(90) + 10;
Brian Salomon2a4f9832018-03-03 22:43:43 -0500801 auto origin = random->nextBool() ? kTopLeft_GrSurfaceOrigin : kBottomLeft_GrSurfaceOrigin;
Greg Daniel09c94002018-06-08 22:11:51 +0000802 GrMipMapped mipMapped = random->nextBool() ? GrMipMapped::kYes : GrMipMapped::kNo;
803 SkBackingFit fit = SkBackingFit::kExact;
804 if (mipMapped == GrMipMapped::kNo) {
805 fit = random->nextBool() ? SkBackingFit::kApprox : SkBackingFit::kExact;
806 }
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500807
808 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
Greg Daniel09c94002018-06-08 22:11:51 +0000809 sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(desc, origin, mipMapped, fit,
810 SkBudgeted::kNo,
811 GrInternalSurfaceFlags::kNone);
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500812
Brian Salomon34169692017-08-28 15:32:01 -0400813 SkRect rect = GrTest::TestRect(random);
814 SkRect srcRect;
815 srcRect.fLeft = random->nextRangeScalar(0.f, proxy->width() / 2.f);
816 srcRect.fRight = random->nextRangeScalar(0.f, proxy->width()) + proxy->width() / 2.f;
817 srcRect.fTop = random->nextRangeScalar(0.f, proxy->height() / 2.f);
818 srcRect.fBottom = random->nextRangeScalar(0.f, proxy->height()) + proxy->height() / 2.f;
819 SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random);
820 GrColor color = SkColorToPremulGrColor(random->nextU());
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400821 GrSamplerState::Filter filter = (GrSamplerState::Filter)random->nextULessThan(
822 static_cast<uint32_t>(GrSamplerState::Filter::kMipMap) + 1);
Greg Daniel09c94002018-06-08 22:11:51 +0000823 while (mipMapped == GrMipMapped::kNo && filter == GrSamplerState::Filter::kMipMap) {
824 filter = (GrSamplerState::Filter)random->nextULessThan(
825 static_cast<uint32_t>(GrSamplerState::Filter::kMipMap) + 1);
826 }
Brian Osman3ebd3542018-07-30 14:36:53 -0400827 auto texXform = GrTest::TestColorXform(random);
828 auto paintXform = GrTest::TestColorXform(random);
Brian Salomon485b8c62018-01-12 15:11:06 -0500829 GrAAType aaType = GrAAType::kNone;
830 if (random->nextBool()) {
831 aaType = (fsaaType == GrFSAAType::kUnifiedMSAA) ? GrAAType::kMSAA : GrAAType::kCoverage;
832 }
Brian Salomonb80ffee2018-05-23 16:39:39 -0400833 auto constraint = random->nextBool() ? SkCanvas::kStrict_SrcRectConstraint
834 : SkCanvas::kFast_SrcRectConstraint;
Robert Phillips7c525e62018-06-12 10:11:12 -0400835 return GrTextureOp::Make(context, std::move(proxy), filter, color, srcRect, rect, aaType,
Brian Osman3ebd3542018-07-30 14:36:53 -0400836 constraint, viewMatrix, std::move(texXform), std::move(paintXform));
Brian Salomon34169692017-08-28 15:32:01 -0400837}
838
839#endif