blob: 255f937fe9744d2a8d99e51b9d0316ba069ee692 [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"
Brian Salomond7065e72018-10-12 11:42:02 -04009#include <new>
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"
Greg Daniel7a82edf2018-12-04 10:54:34 -050016#include "GrGpu.h"
Robert Phillips7c525e62018-06-12 10:11:12 -040017#include "GrMemoryPool.h"
Brian Salomon34169692017-08-28 15:32:01 -040018#include "GrMeshDrawOp.h"
19#include "GrOpFlushState.h"
20#include "GrQuad.h"
Michael Ludwig460eb5e2018-10-29 11:09:29 -040021#include "GrQuadPerEdgeAA.h"
Brian Salomon34169692017-08-28 15:32:01 -040022#include "GrResourceProvider.h"
Greg Daniel7a82edf2018-12-04 10:54:34 -050023#include "GrResourceProviderPriv.h"
Brian Salomon34169692017-08-28 15:32:01 -040024#include "GrShaderCaps.h"
25#include "GrTexture.h"
Brian Salomon336ce7b2017-09-08 08:23:58 -040026#include "GrTexturePriv.h"
Brian Salomon34169692017-08-28 15:32:01 -040027#include "GrTextureProxy.h"
28#include "SkGr.h"
Brian Salomon336ce7b2017-09-08 08:23:58 -040029#include "SkMathPriv.h"
Brian Salomona33b67c2018-05-17 10:42:14 -040030#include "SkMatrixPriv.h"
Brian Salomonb5ef1f92018-01-11 11:46:21 -050031#include "SkPoint.h"
32#include "SkPoint3.h"
Brian Salomond7065e72018-10-12 11:42:02 -040033#include "SkRectPriv.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040034#include "SkTo.h"
Brian Salomon34169692017-08-28 15:32:01 -040035#include "glsl/GrGLSLVarying.h"
36
37namespace {
38
Michael Ludwig460eb5e2018-10-29 11:09:29 -040039using Domain = GrQuadPerEdgeAA::Domain;
Michael Ludwigc182b942018-11-16 10:27:51 -050040using VertexSpec = GrQuadPerEdgeAA::VertexSpec;
Brian Osman3d139a42018-11-19 10:42:10 -050041using ColorType = GrQuadPerEdgeAA::ColorType;
Brian Salomonb80ffee2018-05-23 16:39:39 -040042
Brian Salomon0087c832018-10-15 14:48:20 -040043static bool filter_has_effect_for_rect_stays_rect(const GrPerspQuad& quad, const SkRect& srcRect) {
Michael Ludwigc182b942018-11-16 10:27:51 -050044 SkASSERT(quad.quadType() == GrQuadType::kRect);
Brian Salomon0087c832018-10-15 14:48:20 -040045 float ql = quad.x(0);
46 float qt = quad.y(0);
47 float qr = quad.x(3);
48 float qb = quad.y(3);
49 // Disable filtering when there is no scaling of the src rect and the src rect and dst rect
50 // align fractionally. If we allow inverted src rects this logic needs to consider that.
51 SkASSERT(srcRect.isSorted());
52 return (qr - ql) != srcRect.width() || (qb - qt) != srcRect.height() ||
53 SkScalarFraction(ql) != SkScalarFraction(srcRect.fLeft) ||
54 SkScalarFraction(qt) != SkScalarFraction(srcRect.fTop);
55}
56
Michael Ludwig460eb5e2018-10-29 11:09:29 -040057static SkRect compute_domain(Domain domain, GrSamplerState::Filter filter,
58 GrSurfaceOrigin origin, const SkRect& srcRect, float iw, float ih) {
59 static constexpr SkRect kLargeRect = {-2, -2, 2, 2};
60 if (domain == Domain::kNo) {
61 // Either the quad has no domain constraint and is batched with a domain constrained op
62 // (in which case we want a domain that doesn't restrict normalized tex coords), or the
63 // entire op doesn't use the domain, in which case the returned value is ignored.
64 return kLargeRect;
65 }
66
67 auto ltrb = Sk4f::Load(&srcRect);
68 if (filter == GrSamplerState::Filter::kBilerp) {
69 auto rblt = SkNx_shuffle<2, 3, 0, 1>(ltrb);
70 auto whwh = (rblt - ltrb).abs();
71 auto c = (rblt + ltrb) * 0.5f;
72 static const Sk4f kOffsets = {0.5f, 0.5f, -0.5f, -0.5f};
73 ltrb = (whwh < 1.f).thenElse(c, ltrb + kOffsets);
74 }
75 ltrb *= Sk4f(iw, ih, iw, ih);
76 if (origin == kBottomLeft_GrSurfaceOrigin) {
77 static const Sk4f kMul = {1.f, -1.f, 1.f, -1.f};
78 static const Sk4f kAdd = {0.f, 1.f, 0.f, 1.f};
79 ltrb = SkNx_shuffle<0, 3, 2, 1>(kMul * ltrb + kAdd);
80 }
81
82 SkRect domainRect;
83 ltrb.store(&domainRect);
84 return domainRect;
85}
86
87static GrPerspQuad compute_src_quad(GrSurfaceOrigin origin, const SkRect& srcRect,
88 float iw, float ih) {
89 // Convert the pixel-space src rectangle into normalized texture coordinates
90 SkRect texRect = {
91 iw * srcRect.fLeft,
92 ih * srcRect.fTop,
93 iw * srcRect.fRight,
94 ih * srcRect.fBottom
95 };
96 if (origin == kBottomLeft_GrSurfaceOrigin) {
97 texRect.fTop = 1.f - texRect.fTop;
98 texRect.fBottom = 1.f - texRect.fBottom;
99 }
100 return GrPerspQuad(texRect, SkMatrix::I());
101}
102
Brian Salomon34169692017-08-28 15:32:01 -0400103/**
104 * Op that implements GrTextureOp::Make. It draws textured quads. Each quad can modulate against a
105 * the texture by color. The blend with the destination is always src-over. The edges are non-AA.
106 */
107class TextureOp final : public GrMeshDrawOp {
108public:
Robert Phillips7c525e62018-06-12 10:11:12 -0400109 static std::unique_ptr<GrDrawOp> Make(GrContext* context,
110 sk_sp<GrTextureProxy> proxy,
111 GrSamplerState::Filter filter,
Brian Osman3d139a42018-11-19 10:42:10 -0500112 const SkPMColor4f& color,
Robert Phillips7c525e62018-06-12 10:11:12 -0400113 const SkRect& srcRect,
114 const SkRect& dstRect,
115 GrAAType aaType,
Brian Salomon2213ee92018-10-02 10:44:21 -0400116 GrQuadAAFlags aaFlags,
Robert Phillips7c525e62018-06-12 10:11:12 -0400117 SkCanvas::SrcRectConstraint constraint,
Brian Osman2b23c4b2018-06-01 12:25:08 -0400118 const SkMatrix& viewMatrix,
Brian Osman3d139a42018-11-19 10:42:10 -0500119 sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
Robert Phillipsc994a932018-06-19 13:09:54 -0400120 GrOpMemoryPool* pool = context->contextPriv().opMemoryPool();
121
Brian Salomon2213ee92018-10-02 10:44:21 -0400122 return pool->allocate<TextureOp>(
123 std::move(proxy), filter, color, srcRect, dstRect, aaType, aaFlags, constraint,
Brian Osman3d139a42018-11-19 10:42:10 -0500124 viewMatrix, std::move(textureColorSpaceXform));
Brian Salomon34169692017-08-28 15:32:01 -0400125 }
Brian Salomond7065e72018-10-12 11:42:02 -0400126 static std::unique_ptr<GrDrawOp> Make(GrContext* context,
127 const GrRenderTargetContext::TextureSetEntry set[],
Brian Salomond003d222018-11-26 13:25:05 -0500128 int cnt, GrSamplerState::Filter filter, GrAAType aaType,
129 const SkMatrix& viewMatrix,
Brian Osman3d139a42018-11-19 10:42:10 -0500130 sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
Brian Salomond7065e72018-10-12 11:42:02 -0400131 size_t size = sizeof(TextureOp) + sizeof(Proxy) * (cnt - 1);
132 GrOpMemoryPool* pool = context->contextPriv().opMemoryPool();
133 void* mem = pool->allocate(size);
Brian Salomond003d222018-11-26 13:25:05 -0500134 return std::unique_ptr<GrDrawOp>(new (mem) TextureOp(set, cnt, filter, aaType, viewMatrix,
135 std::move(textureColorSpaceXform)));
Brian Salomond7065e72018-10-12 11:42:02 -0400136 }
Brian Salomon34169692017-08-28 15:32:01 -0400137
Brian Salomon336ce7b2017-09-08 08:23:58 -0400138 ~TextureOp() override {
Brian Salomond7065e72018-10-12 11:42:02 -0400139 for (unsigned p = 0; p < fProxyCnt; ++p) {
140 if (fFinalized) {
141 fProxies[p].fProxy->completedRead();
142 } else {
143 fProxies[p].fProxy->unref();
144 }
Brian Salomon336ce7b2017-09-08 08:23:58 -0400145 }
146 }
Brian Salomon34169692017-08-28 15:32:01 -0400147
148 const char* name() const override { return "TextureOp"; }
149
Brian Salomon7d94bb52018-10-12 14:37:19 -0400150 void visitProxies(const VisitProxyFunc& func, VisitorType visitor) const override {
151 if (visitor == VisitorType::kAllocatorGather && fCanSkipAllocatorGather) {
152 return;
153 }
Brian Salomond7065e72018-10-12 11:42:02 -0400154 for (unsigned p = 0; p < fProxyCnt; ++p) {
155 func(fProxies[p].fProxy);
156 }
157 }
Robert Phillipsb493eeb2017-09-13 13:10:52 -0400158
Brian Osman9a390ac2018-11-12 09:47:48 -0500159#ifdef SK_DEBUG
Brian Salomon34169692017-08-28 15:32:01 -0400160 SkString dumpInfo() const override {
161 SkString str;
Brian Salomond7065e72018-10-12 11:42:02 -0400162 str.appendf("# draws: %d\n", fQuads.count());
163 int q = 0;
164 for (unsigned p = 0; p < fProxyCnt; ++p) {
165 str.appendf("Proxy ID: %d, Filter: %d\n", fProxies[p].fProxy->uniqueID().asUInt(),
166 static_cast<int>(fFilter));
167 for (int i = 0; i < fProxies[p].fQuadCnt; ++i, ++q) {
168 const Quad& quad = fQuads[q];
169 str.appendf(
170 "%d: Color: 0x%08x, TexRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f] "
171 "Quad [(%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f)]\n",
Brian Osman3d139a42018-11-19 10:42:10 -0500172 i, quad.color().toBytes_RGBA(), quad.srcRect().fLeft, quad.srcRect().fTop,
Brian Salomond7065e72018-10-12 11:42:02 -0400173 quad.srcRect().fRight, quad.srcRect().fBottom, quad.quad().point(0).fX,
174 quad.quad().point(0).fY, quad.quad().point(1).fX, quad.quad().point(1).fY,
175 quad.quad().point(2).fX, quad.quad().point(2).fY, quad.quad().point(3).fX,
176 quad.quad().point(3).fY);
177 }
Brian Salomon34169692017-08-28 15:32:01 -0400178 }
179 str += INHERITED::dumpInfo();
180 return str;
181 }
Brian Osman9a390ac2018-11-12 09:47:48 -0500182#endif
Brian Salomon34169692017-08-28 15:32:01 -0400183
Brian Osman532b3f92018-07-11 10:02:07 -0400184 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
Brian Salomon34169692017-08-28 15:32:01 -0400185 SkASSERT(!fFinalized);
186 fFinalized = true;
Brian Salomond7065e72018-10-12 11:42:02 -0400187 for (unsigned p = 0; p < fProxyCnt; ++p) {
188 fProxies[p].fProxy->addPendingRead();
189 fProxies[p].fProxy->unref();
190 }
Brian Salomon34169692017-08-28 15:32:01 -0400191 return RequiresDstTexture::kNo;
192 }
193
Brian Salomon485b8c62018-01-12 15:11:06 -0500194 FixedFunctionFlags fixedFunctionFlags() const override {
195 return this->aaType() == GrAAType::kMSAA ? FixedFunctionFlags::kUsesHWAA
196 : FixedFunctionFlags::kNone;
197 }
Brian Salomon34169692017-08-28 15:32:01 -0400198
199 DEFINE_OP_CLASS_ID
200
201private:
Robert Phillips7c525e62018-06-12 10:11:12 -0400202 friend class ::GrOpMemoryPool;
Brian Salomon762d5e72017-12-01 10:25:08 -0500203
Brian Osman3d139a42018-11-19 10:42:10 -0500204 TextureOp(sk_sp<GrTextureProxy> proxy, GrSamplerState::Filter filter, const SkPMColor4f& color,
Brian Salomon2213ee92018-10-02 10:44:21 -0400205 const SkRect& srcRect, const SkRect& dstRect, GrAAType aaType, GrQuadAAFlags aaFlags,
Brian Salomonb80ffee2018-05-23 16:39:39 -0400206 SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix,
Brian Osman3d139a42018-11-19 10:42:10 -0500207 sk_sp<GrColorSpaceXform> textureColorSpaceXform)
Brian Salomon34169692017-08-28 15:32:01 -0400208 : INHERITED(ClassID())
Brian Osman3ebd3542018-07-30 14:36:53 -0400209 , fTextureColorSpaceXform(std::move(textureColorSpaceXform))
Brian Salomon0087c832018-10-15 14:48:20 -0400210 , fFilter(static_cast<unsigned>(filter))
Brian Osman2b23c4b2018-06-01 12:25:08 -0400211 , fFinalized(0) {
Michael Ludwig6bee7762018-10-19 09:50:36 -0400212 GrQuadType quadType = GrQuadTypeForTransformedRect(viewMatrix);
Brian Salomon594b64c2018-05-29 12:47:57 -0400213 auto quad = GrPerspQuad(dstRect, viewMatrix);
Michael Ludwig6bee7762018-10-19 09:50:36 -0400214
215 // Clean up disparities between the overall aa type and edge configuration and apply
216 // optimizations based on the rect and matrix when appropriate
217 GrResolveAATypeForQuad(aaType, aaFlags, quad, quadType, &aaType, &aaFlags);
218 fAAType = static_cast<unsigned>(aaType);
219
Michael Ludwigf995c052018-11-26 15:24:29 -0500220 fQuadType = static_cast<unsigned>(quadType);
Brian Salomonf1709042018-10-03 11:57:00 -0400221 // We expect our caller to have already caught this optimization.
Brian Salomond7065e72018-10-12 11:42:02 -0400222 SkASSERT(!srcRect.contains(proxy->getWorstCaseBoundsRect()) ||
Brian Salomonf1709042018-10-03 11:57:00 -0400223 constraint == SkCanvas::kFast_SrcRectConstraint);
Michael Ludwigc182b942018-11-16 10:27:51 -0500224 if (quadType == GrQuadType::kRect) {
Michael Ludwig6bee7762018-10-19 09:50:36 -0400225 // Disable filtering if possible (note AA optimizations for rects are automatically
226 // handled above in GrResolveAATypeForQuad).
Brian Salomon0087c832018-10-15 14:48:20 -0400227 if (this->filter() != GrSamplerState::Filter::kNearest &&
228 !filter_has_effect_for_rect_stays_rect(quad, srcRect)) {
229 fFilter = static_cast<unsigned>(GrSamplerState::Filter::kNearest);
Brian Salomon594b64c2018-05-29 12:47:57 -0400230 }
231 }
Brian Salomonf09abc52018-10-03 15:59:04 -0400232 // We may have had a strict constraint with nearest filter solely due to possible AA bloat.
233 // If we don't have (or determined we don't need) coverage AA then we can skip using a
234 // domain.
235 if (constraint == SkCanvas::kStrict_SrcRectConstraint &&
Brian Salomon0087c832018-10-15 14:48:20 -0400236 this->filter() == GrSamplerState::Filter::kNearest &&
Michael Ludwig6bee7762018-10-19 09:50:36 -0400237 aaType != GrAAType::kCoverage) {
Brian Salomonf09abc52018-10-03 15:59:04 -0400238 constraint = SkCanvas::kFast_SrcRectConstraint;
239 }
Brian Salomond7065e72018-10-12 11:42:02 -0400240 const auto& draw = fQuads.emplace_back(srcRect, quad, aaFlags, constraint, color);
241 fProxyCnt = 1;
242 fProxies[0] = {proxy.release(), 1};
Brian Salomon0087c832018-10-15 14:48:20 -0400243 auto bounds = quad.bounds();
Michael Ludwig6bee7762018-10-19 09:50:36 -0400244 this->setBounds(bounds, HasAABloat(aaType == GrAAType::kCoverage), IsZeroArea::kNo);
Brian Salomond7065e72018-10-12 11:42:02 -0400245 fDomain = static_cast<unsigned>(draw.domain());
Brian Osman3d139a42018-11-19 10:42:10 -0500246 fWideColor = !SkPMColor4fFitsInBytes(color);
Brian Salomon7d94bb52018-10-12 14:37:19 -0400247 fCanSkipAllocatorGather =
248 static_cast<unsigned>(fProxies[0].fProxy->canSkipResourceAllocator());
Brian Salomond7065e72018-10-12 11:42:02 -0400249 }
250 TextureOp(const GrRenderTargetContext::TextureSetEntry set[], int cnt,
Brian Salomond003d222018-11-26 13:25:05 -0500251 GrSamplerState::Filter filter, GrAAType aaType, const SkMatrix& viewMatrix,
252 sk_sp<GrColorSpaceXform> textureColorSpaceXform)
Brian Salomond7065e72018-10-12 11:42:02 -0400253 : INHERITED(ClassID())
254 , fTextureColorSpaceXform(std::move(textureColorSpaceXform))
Brian Salomon0087c832018-10-15 14:48:20 -0400255 , fFilter(static_cast<unsigned>(filter))
Brian Salomond7065e72018-10-12 11:42:02 -0400256 , fFinalized(0) {
257 fQuads.reserve(cnt);
258 fProxyCnt = SkToUInt(cnt);
259 SkRect bounds = SkRectPriv::MakeLargestInverted();
Michael Ludwig6bee7762018-10-19 09:50:36 -0400260 GrAAType overallAAType = GrAAType::kNone; // aa type maximally compatible with all dst rects
Brian Salomon0087c832018-10-15 14:48:20 -0400261 bool mustFilter = false;
Brian Salomon7d94bb52018-10-12 14:37:19 -0400262 fCanSkipAllocatorGather = static_cast<unsigned>(true);
Michael Ludwig6bee7762018-10-19 09:50:36 -0400263 // All dst rects are transformed by the same view matrix, so their quad types are identical
264 GrQuadType quadType = GrQuadTypeForTransformedRect(viewMatrix);
Brian Salomond7065e72018-10-12 11:42:02 -0400265 for (unsigned p = 0; p < fProxyCnt; ++p) {
266 fProxies[p].fProxy = SkRef(set[p].fProxy.get());
267 fProxies[p].fQuadCnt = 1;
268 SkASSERT(fProxies[p].fProxy->textureType() == fProxies[0].fProxy->textureType());
269 SkASSERT(fProxies[p].fProxy->config() == fProxies[0].fProxy->config());
Brian Salomon7d94bb52018-10-12 14:37:19 -0400270 if (!fProxies[p].fProxy->canSkipResourceAllocator()) {
271 fCanSkipAllocatorGather = static_cast<unsigned>(false);
272 }
Brian Salomond7065e72018-10-12 11:42:02 -0400273 auto quad = GrPerspQuad(set[p].fDstRect, viewMatrix);
274 bounds.joinPossiblyEmptyRect(quad.bounds());
Michael Ludwig6bee7762018-10-19 09:50:36 -0400275 GrQuadAAFlags aaFlags;
276 // Don't update the overall aaType, might be inappropriate for some of the quads
277 GrAAType aaForQuad;
278 GrResolveAATypeForQuad(aaType, set[p].fAAFlags, quad, quadType, &aaForQuad, &aaFlags);
279 // Resolve sets aaForQuad to aaType or None, there is never a change between aa methods
280 SkASSERT(aaForQuad == GrAAType::kNone || aaForQuad == aaType);
281 if (overallAAType == GrAAType::kNone && aaForQuad != GrAAType::kNone) {
282 overallAAType = aaType;
Brian Salomond7065e72018-10-12 11:42:02 -0400283 }
Brian Salomon0087c832018-10-15 14:48:20 -0400284 if (!mustFilter && this->filter() != GrSamplerState::Filter::kNearest) {
Michael Ludwigc182b942018-11-16 10:27:51 -0500285 mustFilter = quadType != GrQuadType::kRect ||
Brian Salomon0087c832018-10-15 14:48:20 -0400286 filter_has_effect_for_rect_stays_rect(quad, set[p].fSrcRect);
287 }
Brian Salomond003d222018-11-26 13:25:05 -0500288 float alpha = SkTPin(set[p].fAlpha, 0.f, 1.f);
289 SkPMColor4f color{alpha, alpha, alpha, alpha};
Brian Salomond7065e72018-10-12 11:42:02 -0400290 fQuads.emplace_back(set[p].fSrcRect, quad, aaFlags, SkCanvas::kFast_SrcRectConstraint,
291 color);
292 }
Michael Ludwig6bee7762018-10-19 09:50:36 -0400293 fAAType = static_cast<unsigned>(overallAAType);
Brian Salomon0087c832018-10-15 14:48:20 -0400294 if (!mustFilter) {
295 fFilter = static_cast<unsigned>(GrSamplerState::Filter::kNearest);
296 }
Brian Salomond7065e72018-10-12 11:42:02 -0400297 this->setBounds(bounds, HasAABloat(this->aaType() == GrAAType::kCoverage), IsZeroArea::kNo);
Michael Ludwigf995c052018-11-26 15:24:29 -0500298 fQuadType = static_cast<unsigned>(quadType);
Brian Salomond7065e72018-10-12 11:42:02 -0400299 fDomain = static_cast<unsigned>(false);
Brian Salomon574d6162018-11-19 16:57:25 -0500300 fWideColor = static_cast<unsigned>(false);
Brian Salomon34169692017-08-28 15:32:01 -0400301 }
302
Brian Salomon574d6162018-11-19 16:57:25 -0500303 void tess(void* v, const VertexSpec& spec, const GrTextureProxy* proxy, int start,
304 int cnt) const {
Brian Salomond7065e72018-10-12 11:42:02 -0400305 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomond7065e72018-10-12 11:42:02 -0400306 auto origin = proxy->origin();
307 const auto* texture = proxy->peekTexture();
Brian Salomon7eae3e02018-08-07 14:02:38 +0000308 float iw = 1.f / texture->width();
309 float ih = 1.f / texture->height();
310
Brian Salomond7065e72018-10-12 11:42:02 -0400311 for (int i = start; i < start + cnt; ++i) {
312 const auto q = fQuads[i];
Michael Ludwig460eb5e2018-10-29 11:09:29 -0400313 GrPerspQuad srcQuad = compute_src_quad(origin, q.srcRect(), iw, ih);
314 SkRect domain = compute_domain(q.domain(), this->filter(), origin, q.srcRect(), iw, ih);
Michael Ludwigc182b942018-11-16 10:27:51 -0500315 v = GrQuadPerEdgeAA::Tessellate(v, spec, q.quad(), q.color(), srcQuad, domain,
316 q.aaFlags());
Brian Salomon17031a72018-05-22 14:14:07 -0400317 }
318 }
319
Brian Salomon34169692017-08-28 15:32:01 -0400320 void onPrepareDraws(Target* target) override {
Brian Salomond7065e72018-10-12 11:42:02 -0400321 TRACE_EVENT0("skia", TRACE_FUNC);
Michael Ludwigf995c052018-11-26 15:24:29 -0500322 GrQuadType quadType = GrQuadType::kRect;
Brian Salomonf7232642018-09-19 08:58:08 -0400323 Domain domain = Domain::kNo;
Brian Osman3d139a42018-11-19 10:42:10 -0500324 bool wideColor = false;
Brian Salomond7065e72018-10-12 11:42:02 -0400325 int numProxies = 0;
Brian Salomon4b8178f2018-10-12 13:18:27 -0400326 int numTotalQuads = 0;
Brian Salomond7065e72018-10-12 11:42:02 -0400327 auto textureType = fProxies[0].fProxy->textureType();
328 auto config = fProxies[0].fProxy->config();
Brian Salomonae7d7702018-10-14 15:05:45 -0400329 GrAAType aaType = this->aaType();
Brian Salomonf7232642018-09-19 08:58:08 -0400330 for (const auto& op : ChainRange<TextureOp>(this)) {
Michael Ludwigf995c052018-11-26 15:24:29 -0500331 if (op.quadType() > quadType) {
332 quadType = op.quadType();
333 }
Brian Salomonf7232642018-09-19 08:58:08 -0400334 if (op.fDomain) {
335 domain = Domain::kYes;
336 }
Brian Osman3d139a42018-11-19 10:42:10 -0500337 wideColor |= op.fWideColor;
Brian Salomond7065e72018-10-12 11:42:02 -0400338 numProxies += op.fProxyCnt;
339 for (unsigned p = 0; p < op.fProxyCnt; ++p) {
Brian Salomon4b8178f2018-10-12 13:18:27 -0400340 numTotalQuads += op.fProxies[p].fQuadCnt;
Brian Salomond7065e72018-10-12 11:42:02 -0400341 auto* proxy = op.fProxies[p].fProxy;
342 if (!proxy->instantiate(target->resourceProvider())) {
343 return;
344 }
345 SkASSERT(proxy->config() == config);
346 SkASSERT(proxy->textureType() == textureType);
Brian Salomonf7232642018-09-19 08:58:08 -0400347 }
Brian Salomonae7d7702018-10-14 15:05:45 -0400348 if (op.aaType() == GrAAType::kCoverage) {
349 SkASSERT(aaType == GrAAType::kCoverage || aaType == GrAAType::kNone);
350 aaType = GrAAType::kCoverage;
351 }
Brian Salomon34169692017-08-28 15:32:01 -0400352 }
Brian Salomon336ce7b2017-09-08 08:23:58 -0400353
Michael Ludwigf995c052018-11-26 15:24:29 -0500354 VertexSpec vertexSpec(quadType, wideColor ? ColorType::kHalf : ColorType::kByte,
355 GrQuadType::kRect, /* hasLocal */ true, domain, aaType);
Michael Ludwigc182b942018-11-16 10:27:51 -0500356
Greg Daniel7a82edf2018-12-04 10:54:34 -0500357 GrSamplerState samplerState = GrSamplerState(GrSamplerState::WrapMode::kClamp,
358 this->filter());
359 GrGpu* gpu = target->resourceProvider()->priv().gpu();
360 uint32_t extraSamplerKey = gpu->getExtraSamplerKeyForProgram(
361 samplerState, fProxies[0].fProxy->backendFormat());
362
Michael Ludwig467994d2018-12-03 14:58:31 +0000363 sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeTexturedProcessor(
364 vertexSpec, *target->caps().shaderCaps(),
Greg Daniel7a82edf2018-12-04 10:54:34 -0500365 textureType, config, samplerState, extraSamplerKey,
366 std::move(fTextureColorSpaceXform));
367
Brian Salomon34169692017-08-28 15:32:01 -0400368 GrPipeline::InitArgs args;
369 args.fProxy = target->proxy();
370 args.fCaps = &target->caps();
371 args.fResourceProvider = target->resourceProvider();
Brian Salomon485b8c62018-01-12 15:11:06 -0500372 args.fFlags = 0;
Brian Salomonae7d7702018-10-14 15:05:45 -0400373 if (aaType == GrAAType::kMSAA) {
Brian Salomon485b8c62018-01-12 15:11:06 -0500374 args.fFlags |= GrPipeline::kHWAntialias_Flag;
375 }
376
Brian Salomon49348902018-06-26 09:12:38 -0400377 auto clip = target->detachAppliedClip();
Brian Salomonf7232642018-09-19 08:58:08 -0400378 // We'll use a dynamic state array for the GP textures when there are multiple ops.
379 // Otherwise, we use fixed dynamic state to specify the single op's proxy.
380 GrPipeline::DynamicStateArrays* dynamicStateArrays = nullptr;
381 GrPipeline::FixedDynamicState* fixedDynamicState;
Brian Salomond7065e72018-10-12 11:42:02 -0400382 if (numProxies > 1) {
383 dynamicStateArrays = target->allocDynamicStateArrays(numProxies, 1, false);
Brian Salomonf7232642018-09-19 08:58:08 -0400384 fixedDynamicState = target->allocFixedDynamicState(clip.scissorState().rect(), 0);
385 } else {
386 fixedDynamicState = target->allocFixedDynamicState(clip.scissorState().rect(), 1);
Brian Salomond7065e72018-10-12 11:42:02 -0400387 fixedDynamicState->fPrimitiveProcessorTextures[0] = fProxies[0].fProxy;
Brian Salomonf7232642018-09-19 08:58:08 -0400388 }
Brian Salomon49348902018-06-26 09:12:38 -0400389 const auto* pipeline =
390 target->allocPipeline(args, GrProcessorSet::MakeEmptySet(), std::move(clip));
Brian Salomon92be2f72018-06-19 14:33:47 -0400391
Michael Ludwigc182b942018-11-16 10:27:51 -0500392 size_t vertexSize = gp->vertexStride();
Brian Salomon92be2f72018-06-19 14:33:47 -0400393
Brian Salomond7065e72018-10-12 11:42:02 -0400394 GrMesh* meshes = target->allocMeshes(numProxies);
Brian Salomon4b8178f2018-10-12 13:18:27 -0400395 const GrBuffer* vbuffer;
396 int vertexOffsetInBuffer = 0;
397 int numQuadVerticesLeft = numTotalQuads * 4;
398 int numAllocatedVertices = 0;
399 void* vdata = nullptr;
400
Brian Salomond7065e72018-10-12 11:42:02 -0400401 int m = 0;
Brian Salomonf7232642018-09-19 08:58:08 -0400402 for (const auto& op : ChainRange<TextureOp>(this)) {
Brian Salomond7065e72018-10-12 11:42:02 -0400403 int q = 0;
404 for (unsigned p = 0; p < op.fProxyCnt; ++p) {
405 int quadCnt = op.fProxies[p].fQuadCnt;
406 auto* proxy = op.fProxies[p].fProxy;
Brian Salomon4b8178f2018-10-12 13:18:27 -0400407 int meshVertexCnt = quadCnt * 4;
408 if (numAllocatedVertices < meshVertexCnt) {
409 vdata = target->makeVertexSpaceAtLeast(
410 vertexSize, meshVertexCnt, numQuadVerticesLeft, &vbuffer,
411 &vertexOffsetInBuffer, &numAllocatedVertices);
412 SkASSERT(numAllocatedVertices <= numQuadVerticesLeft);
413 if (!vdata) {
414 SkDebugf("Could not allocate vertices\n");
415 return;
416 }
Brian Salomonf7232642018-09-19 08:58:08 -0400417 }
Brian Salomon4b8178f2018-10-12 13:18:27 -0400418 SkASSERT(numAllocatedVertices >= meshVertexCnt);
Brian Salomond7065e72018-10-12 11:42:02 -0400419
Michael Ludwigc182b942018-11-16 10:27:51 -0500420 op.tess(vdata, vertexSpec, proxy, q, quadCnt);
Brian Salomond7065e72018-10-12 11:42:02 -0400421
422 if (quadCnt > 1) {
423 meshes[m].setPrimitiveType(GrPrimitiveType::kTriangles);
424 sk_sp<const GrBuffer> ibuffer =
425 target->resourceProvider()->refQuadIndexBuffer();
426 if (!ibuffer) {
427 SkDebugf("Could not allocate quad indices\n");
428 return;
429 }
430 meshes[m].setIndexedPatterned(ibuffer.get(), 6, 4, quadCnt,
431 GrResourceProvider::QuadCountOfQuadBuffer());
432 } else {
433 meshes[m].setPrimitiveType(GrPrimitiveType::kTriangleStrip);
434 meshes[m].setNonIndexedNonInstanced(4);
435 }
Brian Salomon4b8178f2018-10-12 13:18:27 -0400436 meshes[m].setVertexData(vbuffer, vertexOffsetInBuffer);
Brian Salomond7065e72018-10-12 11:42:02 -0400437 if (dynamicStateArrays) {
438 dynamicStateArrays->fPrimitiveProcessorTextures[m] = proxy;
439 }
440 ++m;
Brian Salomon4b8178f2018-10-12 13:18:27 -0400441 numAllocatedVertices -= meshVertexCnt;
442 numQuadVerticesLeft -= meshVertexCnt;
443 vertexOffsetInBuffer += meshVertexCnt;
444 vdata = reinterpret_cast<char*>(vdata) + vertexSize * meshVertexCnt;
Brian Salomond7065e72018-10-12 11:42:02 -0400445 q += quadCnt;
Brian Salomonf7232642018-09-19 08:58:08 -0400446 }
Brian Salomon34169692017-08-28 15:32:01 -0400447 }
Brian Salomon4b8178f2018-10-12 13:18:27 -0400448 SkASSERT(!numQuadVerticesLeft);
449 SkASSERT(!numAllocatedVertices);
Brian Salomonf7232642018-09-19 08:58:08 -0400450 target->draw(std::move(gp), pipeline, fixedDynamicState, dynamicStateArrays, meshes,
Brian Salomond7065e72018-10-12 11:42:02 -0400451 numProxies);
Brian Salomon34169692017-08-28 15:32:01 -0400452 }
453
Brian Salomonf7232642018-09-19 08:58:08 -0400454 CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
Brian Salomond7065e72018-10-12 11:42:02 -0400455 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon34169692017-08-28 15:32:01 -0400456 const auto* that = t->cast<TextureOp>();
Brian Osman3ebd3542018-07-30 14:36:53 -0400457 if (!GrColorSpaceXform::Equals(fTextureColorSpaceXform.get(),
458 that->fTextureColorSpaceXform.get())) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000459 return CombineResult::kCannotCombine;
Brian Osman3ebd3542018-07-30 14:36:53 -0400460 }
Brian Salomonae7d7702018-10-14 15:05:45 -0400461 bool upgradeToCoverageAAOnMerge = false;
Brian Salomon485b8c62018-01-12 15:11:06 -0500462 if (this->aaType() != that->aaType()) {
Brian Salomonae7d7702018-10-14 15:05:45 -0400463 if (!((this->aaType() == GrAAType::kCoverage && that->aaType() == GrAAType::kNone) ||
464 (that->aaType() == GrAAType::kCoverage && this->aaType() == GrAAType::kNone))) {
465 return CombineResult::kCannotCombine;
466 }
467 upgradeToCoverageAAOnMerge = true;
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500468 }
Brian Salomonf7232642018-09-19 08:58:08 -0400469 if (fFilter != that->fFilter) {
470 return CombineResult::kCannotCombine;
471 }
Brian Salomond7065e72018-10-12 11:42:02 -0400472 auto thisProxy = fProxies[0].fProxy;
473 auto thatProxy = that->fProxies[0].fProxy;
474 if (fProxyCnt > 1 || that->fProxyCnt > 1 ||
Brian Salomon588cec72018-11-14 13:56:37 -0500475 thisProxy->uniqueID() != thatProxy->uniqueID()) {
476 // We can't merge across different proxies. Check if 'this' can be chained with 'that'.
Greg Daniel45723ac2018-11-30 10:12:43 -0500477 if (GrTextureProxy::ProxiesAreCompatibleAsDynamicState(thisProxy, thatProxy) &&
Brian Salomonf7232642018-09-19 08:58:08 -0400478 caps.dynamicStateArrayGeometryProcessorTextureSupport()) {
479 return CombineResult::kMayChain;
480 }
Brian Salomon7eae3e02018-08-07 14:02:38 +0000481 return CombineResult::kCannotCombine;
Brian Salomon336ce7b2017-09-08 08:23:58 -0400482 }
Brian Salomond7065e72018-10-12 11:42:02 -0400483 fProxies[0].fQuadCnt += that->fQuads.count();
484 fQuads.push_back_n(that->fQuads.count(), that->fQuads.begin());
Michael Ludwigf995c052018-11-26 15:24:29 -0500485 if (that->fQuadType > fQuadType) {
486 fQuadType = that->fQuadType;
487 }
Brian Salomonb80ffee2018-05-23 16:39:39 -0400488 fDomain |= that->fDomain;
Brian Osman3d139a42018-11-19 10:42:10 -0500489 fWideColor |= that->fWideColor;
Brian Salomonae7d7702018-10-14 15:05:45 -0400490 if (upgradeToCoverageAAOnMerge) {
491 fAAType = static_cast<unsigned>(GrAAType::kCoverage);
492 }
Brian Salomon7eae3e02018-08-07 14:02:38 +0000493 return CombineResult::kMerged;
Brian Salomon34169692017-08-28 15:32:01 -0400494 }
495
Brian Salomon485b8c62018-01-12 15:11:06 -0500496 GrAAType aaType() const { return static_cast<GrAAType>(fAAType); }
Brian Salomon0087c832018-10-15 14:48:20 -0400497 GrSamplerState::Filter filter() const { return static_cast<GrSamplerState::Filter>(fFilter); }
Michael Ludwigf995c052018-11-26 15:24:29 -0500498 GrQuadType quadType() const { return static_cast<GrQuadType>(fQuadType); }
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500499
Brian Salomond7065e72018-10-12 11:42:02 -0400500 class Quad {
Brian Salomonb80ffee2018-05-23 16:39:39 -0400501 public:
Brian Salomond7065e72018-10-12 11:42:02 -0400502 Quad(const SkRect& srcRect, const GrPerspQuad& quad, GrQuadAAFlags aaFlags,
Brian Osman3d139a42018-11-19 10:42:10 -0500503 SkCanvas::SrcRectConstraint constraint, const SkPMColor4f& color)
Brian Salomonb80ffee2018-05-23 16:39:39 -0400504 : fSrcRect(srcRect)
Brian Salomonb80ffee2018-05-23 16:39:39 -0400505 , fQuad(quad)
Brian Salomon7eae3e02018-08-07 14:02:38 +0000506 , fColor(color)
Brian Salomon2213ee92018-10-02 10:44:21 -0400507 , fHasDomain(constraint == SkCanvas::kStrict_SrcRectConstraint)
508 , fAAFlags(static_cast<unsigned>(aaFlags)) {
509 SkASSERT(fAAFlags == static_cast<unsigned>(aaFlags));
510 }
Brian Salomonb80ffee2018-05-23 16:39:39 -0400511 const GrPerspQuad& quad() const { return fQuad; }
Brian Salomonb80ffee2018-05-23 16:39:39 -0400512 const SkRect& srcRect() const { return fSrcRect; }
Brian Osman3d139a42018-11-19 10:42:10 -0500513 SkPMColor4f color() const { return fColor; }
Brian Salomonb80ffee2018-05-23 16:39:39 -0400514 Domain domain() const { return Domain(fHasDomain); }
Brian Salomon2213ee92018-10-02 10:44:21 -0400515 GrQuadAAFlags aaFlags() const { return static_cast<GrQuadAAFlags>(fAAFlags); }
Brian Salomonb80ffee2018-05-23 16:39:39 -0400516
517 private:
Brian Salomon34169692017-08-28 15:32:01 -0400518 SkRect fSrcRect;
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400519 GrPerspQuad fQuad;
Brian Osman3d139a42018-11-19 10:42:10 -0500520 SkPMColor4f fColor;
Brian Salomon2213ee92018-10-02 10:44:21 -0400521 unsigned fHasDomain : 1;
522 unsigned fAAFlags : 4;
Brian Salomon34169692017-08-28 15:32:01 -0400523 };
Brian Salomond7065e72018-10-12 11:42:02 -0400524 struct Proxy {
525 GrTextureProxy* fProxy;
526 int fQuadCnt;
527 };
528 SkSTArray<1, Quad, true> fQuads;
Brian Osman3ebd3542018-07-30 14:36:53 -0400529 sk_sp<GrColorSpaceXform> fTextureColorSpaceXform;
Brian Salomon0087c832018-10-15 14:48:20 -0400530 unsigned fFilter : 2;
Brian Salomon485b8c62018-01-12 15:11:06 -0500531 unsigned fAAType : 2;
Michael Ludwigf995c052018-11-26 15:24:29 -0500532 unsigned fQuadType : 2; // Device quad, src quad is always trivial
Brian Salomonb80ffee2018-05-23 16:39:39 -0400533 unsigned fDomain : 1;
Brian Osman3d139a42018-11-19 10:42:10 -0500534 unsigned fWideColor : 1;
Brian Salomon34169692017-08-28 15:32:01 -0400535 // Used to track whether fProxy is ref'ed or has a pending IO after finalize() is called.
Brian Salomonb5ef1f92018-01-11 11:46:21 -0500536 unsigned fFinalized : 1;
Brian Salomon7d94bb52018-10-12 14:37:19 -0400537 unsigned fCanSkipAllocatorGather : 1;
Michael Ludwigf995c052018-11-26 15:24:29 -0500538 unsigned fProxyCnt : 32 - 10;
Brian Salomond7065e72018-10-12 11:42:02 -0400539 Proxy fProxies[1];
Brian Salomon336ce7b2017-09-08 08:23:58 -0400540
Michael Ludwigf995c052018-11-26 15:24:29 -0500541 static_assert(kGrQuadTypeCount <= 4, "GrQuadType does not fit in 2 bits");
542
Brian Salomon34169692017-08-28 15:32:01 -0400543 typedef GrMeshDrawOp INHERITED;
544};
545
546} // anonymous namespace
547
548namespace GrTextureOp {
549
Robert Phillips7c525e62018-06-12 10:11:12 -0400550std::unique_ptr<GrDrawOp> Make(GrContext* context,
551 sk_sp<GrTextureProxy> proxy,
552 GrSamplerState::Filter filter,
Brian Osman3d139a42018-11-19 10:42:10 -0500553 const SkPMColor4f& color,
Robert Phillips7c525e62018-06-12 10:11:12 -0400554 const SkRect& srcRect,
555 const SkRect& dstRect,
556 GrAAType aaType,
Brian Salomon2213ee92018-10-02 10:44:21 -0400557 GrQuadAAFlags aaFlags,
Robert Phillips7c525e62018-06-12 10:11:12 -0400558 SkCanvas::SrcRectConstraint constraint,
559 const SkMatrix& viewMatrix,
Brian Osman3d139a42018-11-19 10:42:10 -0500560 sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
Robert Phillips7c525e62018-06-12 10:11:12 -0400561 return TextureOp::Make(context, std::move(proxy), filter, color, srcRect, dstRect, aaType,
Brian Osman3d139a42018-11-19 10:42:10 -0500562 aaFlags, constraint, viewMatrix, std::move(textureColorSpaceXform));
Brian Salomon34169692017-08-28 15:32:01 -0400563}
564
Brian Salomond7065e72018-10-12 11:42:02 -0400565std::unique_ptr<GrDrawOp> Make(GrContext* context,
566 const GrRenderTargetContext::TextureSetEntry set[],
567 int cnt,
568 GrSamplerState::Filter filter,
Brian Salomond7065e72018-10-12 11:42:02 -0400569 GrAAType aaType,
570 const SkMatrix& viewMatrix,
Brian Osman3d139a42018-11-19 10:42:10 -0500571 sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
Brian Salomond003d222018-11-26 13:25:05 -0500572 return TextureOp::Make(context, set, cnt, filter, aaType, viewMatrix,
Brian Osman3d139a42018-11-19 10:42:10 -0500573 std::move(textureColorSpaceXform));
Brian Salomond7065e72018-10-12 11:42:02 -0400574}
575
Brian Salomon34169692017-08-28 15:32:01 -0400576} // namespace GrTextureOp
577
578#if GR_TEST_UTILS
579#include "GrContext.h"
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500580#include "GrContextPriv.h"
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500581#include "GrProxyProvider.h"
Brian Salomon34169692017-08-28 15:32:01 -0400582
583GR_DRAW_OP_TEST_DEFINE(TextureOp) {
584 GrSurfaceDesc desc;
585 desc.fConfig = kRGBA_8888_GrPixelConfig;
586 desc.fHeight = random->nextULessThan(90) + 10;
587 desc.fWidth = random->nextULessThan(90) + 10;
Brian Salomon2a4f9832018-03-03 22:43:43 -0500588 auto origin = random->nextBool() ? kTopLeft_GrSurfaceOrigin : kBottomLeft_GrSurfaceOrigin;
Greg Daniel09c94002018-06-08 22:11:51 +0000589 GrMipMapped mipMapped = random->nextBool() ? GrMipMapped::kYes : GrMipMapped::kNo;
590 SkBackingFit fit = SkBackingFit::kExact;
591 if (mipMapped == GrMipMapped::kNo) {
592 fit = random->nextBool() ? SkBackingFit::kApprox : SkBackingFit::kExact;
593 }
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500594
Greg Daniel4065d452018-11-16 15:43:41 -0500595 const GrBackendFormat format =
596 context->contextPriv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
597
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500598 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
Greg Daniel4065d452018-11-16 15:43:41 -0500599 sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(format, desc, origin, mipMapped, fit,
Greg Daniel09c94002018-06-08 22:11:51 +0000600 SkBudgeted::kNo,
601 GrInternalSurfaceFlags::kNone);
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500602
Brian Salomon34169692017-08-28 15:32:01 -0400603 SkRect rect = GrTest::TestRect(random);
604 SkRect srcRect;
605 srcRect.fLeft = random->nextRangeScalar(0.f, proxy->width() / 2.f);
606 srcRect.fRight = random->nextRangeScalar(0.f, proxy->width()) + proxy->width() / 2.f;
607 srcRect.fTop = random->nextRangeScalar(0.f, proxy->height() / 2.f);
608 srcRect.fBottom = random->nextRangeScalar(0.f, proxy->height()) + proxy->height() / 2.f;
609 SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random);
Brian Osman3d139a42018-11-19 10:42:10 -0500610 SkPMColor4f color = SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU()));
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400611 GrSamplerState::Filter filter = (GrSamplerState::Filter)random->nextULessThan(
612 static_cast<uint32_t>(GrSamplerState::Filter::kMipMap) + 1);
Greg Daniel09c94002018-06-08 22:11:51 +0000613 while (mipMapped == GrMipMapped::kNo && filter == GrSamplerState::Filter::kMipMap) {
614 filter = (GrSamplerState::Filter)random->nextULessThan(
615 static_cast<uint32_t>(GrSamplerState::Filter::kMipMap) + 1);
616 }
Brian Osman3ebd3542018-07-30 14:36:53 -0400617 auto texXform = GrTest::TestColorXform(random);
Brian Salomon485b8c62018-01-12 15:11:06 -0500618 GrAAType aaType = GrAAType::kNone;
619 if (random->nextBool()) {
620 aaType = (fsaaType == GrFSAAType::kUnifiedMSAA) ? GrAAType::kMSAA : GrAAType::kCoverage;
621 }
Brian Salomon2213ee92018-10-02 10:44:21 -0400622 GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
623 aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
624 aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
625 aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
626 aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
Brian Salomonb80ffee2018-05-23 16:39:39 -0400627 auto constraint = random->nextBool() ? SkCanvas::kStrict_SrcRectConstraint
628 : SkCanvas::kFast_SrcRectConstraint;
Robert Phillips7c525e62018-06-12 10:11:12 -0400629 return GrTextureOp::Make(context, std::move(proxy), filter, color, srcRect, rect, aaType,
Brian Osman3d139a42018-11-19 10:42:10 -0500630 aaFlags, constraint, viewMatrix, std::move(texXform));
Brian Salomon34169692017-08-28 15:32:01 -0400631}
632
633#endif