• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 "include/gpu/GrDirectContext.h"
9 #include "include/gpu/GrRecordingContext.h"
10 #include "src/gpu/GrDirectContextPriv.h"
11 #include "src/gpu/GrProxyProvider.h"
12 #include "src/gpu/GrRecordingContextPriv.h"
13 #include "src/gpu/ops/GrTextureOp.h"
14 #include "src/gpu/ops/GrTextureOp.h"
15 #include "tests/Test.h"
16 
17 class OpsTaskTestingAccess {
18 public:
19     typedef GrOpsTask::OpChain OpChain;
20 };
21 
check_chain(OpsTaskTestingAccess::OpChain * chain,SkRect firstRect,SkRect lastRect,int expectedNumOps)22 static void check_chain(OpsTaskTestingAccess::OpChain* chain, SkRect firstRect, SkRect lastRect,
23                         int expectedNumOps) {
24     int actualNumOps = 0;
25     for (const auto& op : GrOp::ChainRange<>(chain->head())) {
26         ++actualNumOps;
27 
28         if (actualNumOps == 1) {
29             SkAssertResult(op.bounds() == firstRect.makeOutset(0.5f, 0.5f));
30         } else if (actualNumOps == expectedNumOps) {
31             SkAssertResult(op.bounds() == lastRect.makeOutset(0.5f, 0.5f));
32         }
33     }
34 
35     SkAssertResult(actualNumOps == expectedNumOps);
36 }
37 
create_proxy(GrRecordingContext * rContext)38 static sk_sp<GrSurfaceProxy> create_proxy(GrRecordingContext* rContext) {
39     const GrCaps* caps = rContext->priv().caps();
40 
41     static constexpr SkISize kDimensions = {16, 16};
42 
43     const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
44                                                                  GrRenderable::kYes);
45     return rContext->priv().proxyProvider()->createProxy(
46             format, kDimensions, GrRenderable::kYes, 1, GrMipmapped::kNo, SkBackingFit::kExact,
47             SkBudgeted::kNo, GrProtected::kNo, GrInternalSurfaceFlags::kNone);
48 }
49 
create_op(GrDirectContext * dContext,SkRect rect,const GrSurfaceProxyView & proxyView,bool isAA)50 static GrOp::Owner create_op(GrDirectContext* dContext, SkRect rect,
51                              const GrSurfaceProxyView& proxyView, bool isAA) {
52     DrawQuad quad;
53 
54     quad.fDevice = GrQuad::MakeFromRect(rect.makeOutset(0.5f, 0.5f),  SkMatrix::I());
55     quad.fLocal = GrQuad(rect);
56     quad.fEdgeFlags = isAA ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
57 
58     return GrTextureOp::Make(dContext,
59                              proxyView,
60                              kPremul_SkAlphaType,
61                              nullptr,
62                              GrSamplerState::Filter::kNearest,
63                              GrSamplerState::MipmapMode::kNone,
64                              {1.f, 1.f, 1.f, 1.f},
65                              GrTextureOp::Saturate::kYes,
66                              SkBlendMode::kSrcOver,
67                              isAA ? GrAAType::kCoverage
68                                   : GrAAType::kNone,
69                              &quad,
70                              nullptr);
71 }
72 
73 // This unit test exercises the crbug.com/1112259 case.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextureOpTest,reporter,ctxInfo)74 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextureOpTest, reporter, ctxInfo) {
75 
76     GrDirectContext* dContext = ctxInfo.directContext();
77     const GrCaps* caps = dContext->priv().caps();
78     SkArenaAlloc arena{nullptr, 0, 1024};
79     auto auditTrail = dContext->priv().auditTrail();
80 
81     if (!caps->dynamicStateArrayGeometryProcessorTextureSupport()) {
82         // This test requires chaining
83         return;
84     }
85 
86     GrSurfaceProxyView proxyViewA(create_proxy(dContext),
87                                   kTopLeft_GrSurfaceOrigin,
88                                   GrSwizzle::RGBA());
89     GrSurfaceProxyView proxyViewB(create_proxy(dContext),
90                                   kTopLeft_GrSurfaceOrigin,
91                                   GrSwizzle::RGBA());
92     GrSurfaceProxyView proxyViewC(create_proxy(dContext),
93                                   kTopLeft_GrSurfaceOrigin,
94                                   GrSwizzle::RGBA());
95 
96     static const SkRect kOpARect{  0,  0, 16, 16 };
97     static const SkRect kOpBRect{ 32,  0, 48, 16 };
98     static const SkRect kOpCRect{  0, 32, 16, 48 };
99     static const SkRect kOpDRect{ 32, 32, 48, 48 };
100 
101     // opA & opB can chain together but can't merge bc they have different proxies
102     GrOp::Owner opA = create_op(dContext, kOpARect, proxyViewA, false);
103     GrOp::Owner opB = create_op(dContext, kOpBRect, proxyViewB, false);
104 
105     GrAppliedClip noClip = GrAppliedClip::Disabled();
106     OpsTaskTestingAccess::OpChain chain1(std::move(opA), GrProcessorSet::EmptySetAnalysis(),
107                                          &noClip, nullptr);
108     chain1.appendOp(std::move(opB), GrProcessorSet::EmptySetAnalysis(), nullptr, &noClip, *caps,
109                     &arena, dContext->priv().auditTrail());
110     check_chain(&chain1, kOpARect, kOpBRect, 2);
111 
112     // opC & opD can also chain together but can't merge (bc, again, they have different
113     // proxies). Note, however, that opA and opD do share a proxy so can be merged if opA's
114     // anti-aliasing is upgraded to coverage.
115     GrOp::Owner opC = create_op(dContext, kOpCRect, proxyViewC, true);
116     GrOp::Owner opD = create_op(dContext, kOpDRect, proxyViewA, true);
117 
118     OpsTaskTestingAccess::OpChain chain2(std::move(opC), GrProcessorSet::EmptySetAnalysis(),
119                                          &noClip, nullptr);
120     chain2.appendOp(std::move(opD), GrProcessorSet::EmptySetAnalysis(), nullptr, &noClip, *caps,
121                     &arena, auditTrail);
122     check_chain(&chain2, kOpCRect, kOpDRect, 2);
123 
124     // opA and opD, now in separate chains, can merge when the two chains are combined while
125     // opB and opC can still only chain.
126     chain1.prependChain(&chain2, *caps, &arena, auditTrail);
127 
128     // We should end up with the chain
129     //   opC - opD/opA - opB
130     check_chain(&chain1, kOpCRect, kOpBRect, 3);
131 
132     chain1.deleteOps();
133 }
134