xref: /aosp_15_r20/external/skia/tests/GrMeshTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2017 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurfaceProps.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkColorData.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAlignedStorage.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkOnce.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkSLTypeShared.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/KeyBuilder.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ResourceKey.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/SkBackingFit.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrBuffer.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrColor.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDirectContextPriv.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDrawIndirectCommand.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGeometryProcessor.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrMeshDrawTarget.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpFlushState.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpsRenderPass.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPipeline.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPixmap.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorAnalysis.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorSet.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProgramInfo.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrResourceProvider.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrShaderCaps.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrShaderVar.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrUserStencilSettings.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SurfaceDrawContext.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLVarying.h"
50*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h"
51*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrDrawOp.h"
52*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrOp.h"
53*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelper.h"
54*c8dee2aaSAndroid Build Coastguard Worker #include "tests/CtsEnforcement.h"
55*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
56*c8dee2aaSAndroid Build Coastguard Worker 
57*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
58*c8dee2aaSAndroid Build Coastguard Worker #include <array>
59*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
60*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
61*c8dee2aaSAndroid Build Coastguard Worker #include <functional>
62*c8dee2aaSAndroid Build Coastguard Worker #include <initializer_list>
63*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
64*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
65*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
66*c8dee2aaSAndroid Build Coastguard Worker 
67*c8dee2aaSAndroid Build Coastguard Worker class GrAppliedClip;
68*c8dee2aaSAndroid Build Coastguard Worker class GrDstProxyView;
69*c8dee2aaSAndroid Build Coastguard Worker class GrGLSLProgramDataManager;
70*c8dee2aaSAndroid Build Coastguard Worker class GrRecordingContext;
71*c8dee2aaSAndroid Build Coastguard Worker class GrSurfaceProxyView;
72*c8dee2aaSAndroid Build Coastguard Worker enum class GrXferBarrierFlags;
73*c8dee2aaSAndroid Build Coastguard Worker struct GrContextOptions;
74*c8dee2aaSAndroid Build Coastguard Worker 
75*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
76*c8dee2aaSAndroid Build Coastguard Worker 
77*c8dee2aaSAndroid Build Coastguard Worker #if 0
78*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
79*c8dee2aaSAndroid Build Coastguard Worker #define WRITE_PNG_CONTEXT_TYPE kANGLE_D3D11_ES3
80*c8dee2aaSAndroid Build Coastguard Worker #endif
81*c8dee2aaSAndroid Build Coastguard Worker 
82*c8dee2aaSAndroid Build Coastguard Worker SKGPU_DECLARE_STATIC_UNIQUE_KEY(gIndexBufferKey);
83*c8dee2aaSAndroid Build Coastguard Worker 
84*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kBoxSize = 2;
85*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kBoxCountY = 8;
86*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kBoxCountX = 8;
87*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kBoxCount = kBoxCountY * kBoxCountX;
88*c8dee2aaSAndroid Build Coastguard Worker 
89*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kImageWidth = kBoxCountY * kBoxSize;
90*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kImageHeight = kBoxCountX * kBoxSize;
91*c8dee2aaSAndroid Build Coastguard Worker 
92*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kIndexPatternRepeatCount = 3;
93*c8dee2aaSAndroid Build Coastguard Worker constexpr uint16_t kIndexPattern[6] = {0, 1, 2, 1, 2, 3};
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker 
96*c8dee2aaSAndroid Build Coastguard Worker class DrawMeshHelper {
97*c8dee2aaSAndroid Build Coastguard Worker public:
DrawMeshHelper(GrOpFlushState * state)98*c8dee2aaSAndroid Build Coastguard Worker     DrawMeshHelper(GrOpFlushState* state) : fState(state) {}
99*c8dee2aaSAndroid Build Coastguard Worker 
100*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const GrBuffer> getIndexBuffer();
101*c8dee2aaSAndroid Build Coastguard Worker 
102*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const GrBuffer> makeIndexBuffer(const uint16_t[], int count);
103*c8dee2aaSAndroid Build Coastguard Worker 
makeVertexBuffer(const TArray<T> & data)104*c8dee2aaSAndroid Build Coastguard Worker     template<typename T> sk_sp<const GrBuffer> makeVertexBuffer(const TArray<T>& data) {
105*c8dee2aaSAndroid Build Coastguard Worker         return this->makeVertexBuffer(data.begin(), data.size());
106*c8dee2aaSAndroid Build Coastguard Worker     }
makeVertexBuffer(const std::vector<T> & data)107*c8dee2aaSAndroid Build Coastguard Worker     template<typename T> sk_sp<const GrBuffer> makeVertexBuffer(const std::vector<T>& data) {
108*c8dee2aaSAndroid Build Coastguard Worker         return this->makeVertexBuffer(data.data(), data.size());
109*c8dee2aaSAndroid Build Coastguard Worker     }
110*c8dee2aaSAndroid Build Coastguard Worker     template<typename T> sk_sp<const GrBuffer> makeVertexBuffer(const T* data, int count);
111*c8dee2aaSAndroid Build Coastguard Worker 
target()112*c8dee2aaSAndroid Build Coastguard Worker     GrMeshDrawTarget* target() { return fState; }
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const GrBuffer> fIndexBuffer;
115*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const GrBuffer> fIndexBuffer2;
116*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const GrBuffer> fInstBuffer;
117*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const GrBuffer> fVertBuffer;
118*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const GrBuffer> fVertBuffer2;
119*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const GrBuffer> fDrawIndirectBuffer;
120*c8dee2aaSAndroid Build Coastguard Worker     size_t fDrawIndirectBufferOffset;
121*c8dee2aaSAndroid Build Coastguard Worker 
122*c8dee2aaSAndroid Build Coastguard Worker     GrOpsRenderPass* bindPipeline(GrPrimitiveType, bool isInstanced, bool hasVertexBuffer);
123*c8dee2aaSAndroid Build Coastguard Worker 
124*c8dee2aaSAndroid Build Coastguard Worker private:
125*c8dee2aaSAndroid Build Coastguard Worker     GrOpFlushState* fState;
126*c8dee2aaSAndroid Build Coastguard Worker };
127*c8dee2aaSAndroid Build Coastguard Worker 
128*c8dee2aaSAndroid Build Coastguard Worker struct Box {
129*c8dee2aaSAndroid Build Coastguard Worker     float fX, fY;
130*c8dee2aaSAndroid Build Coastguard Worker     GrColor fColor;
131*c8dee2aaSAndroid Build Coastguard Worker };
132*c8dee2aaSAndroid Build Coastguard Worker 
133*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////////////////////////
134*c8dee2aaSAndroid Build Coastguard Worker 
135*c8dee2aaSAndroid Build Coastguard Worker /**
136*c8dee2aaSAndroid Build Coastguard Worker  * This is a GPU-backend specific test. It tries to test all possible usecases of
137*c8dee2aaSAndroid Build Coastguard Worker  * GrOpsRenderPass::draw*. The test works by drawing checkerboards of colored boxes, reading back
138*c8dee2aaSAndroid Build Coastguard Worker  * the pixels, and comparing with expected results. The boxes are drawn on integer boundaries and
139*c8dee2aaSAndroid Build Coastguard Worker  * the (opaque) colors are chosen from the set (r,g,b) = (0,255)^3, so the GPU renderings ought to
140*c8dee2aaSAndroid Build Coastguard Worker  * produce exact matches.
141*c8dee2aaSAndroid Build Coastguard Worker  */
142*c8dee2aaSAndroid Build Coastguard Worker 
143*c8dee2aaSAndroid Build Coastguard Worker static void run_test(GrDirectContext*,
144*c8dee2aaSAndroid Build Coastguard Worker                      const char* testName,
145*c8dee2aaSAndroid Build Coastguard Worker                      skiatest::Reporter*,
146*c8dee2aaSAndroid Build Coastguard Worker                      const std::unique_ptr<skgpu::ganesh::SurfaceDrawContext>&,
147*c8dee2aaSAndroid Build Coastguard Worker                      const SkBitmap& gold,
148*c8dee2aaSAndroid Build Coastguard Worker                      std::function<void(DrawMeshHelper*)> prepareFn,
149*c8dee2aaSAndroid Build Coastguard Worker                      std::function<void(DrawMeshHelper*)> executeFn);
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker #ifdef WRITE_PNG_CONTEXT_TYPE
IsContextTypeForOutputPNGs(skgpu::ContextType type)152*c8dee2aaSAndroid Build Coastguard Worker static bool IsContextTypeForOutputPNGs(skgpu::ContextType type) {
153*c8dee2aaSAndroid Build Coastguard Worker     return type == skgpu::ContextType::WRITE_PNG_CONTEXT_TYPE;
154*c8dee2aaSAndroid Build Coastguard Worker }
DEF_GANESH_TEST_FOR_CONTEXTS(GrMeshTest,IsContextTypeForOutputPNGs,reporter,ctxInfo,nullptr)155*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_CONTEXTS(GrMeshTest, IsContextTypeForOutputPNGs, reporter, ctxInfo, nullptr) {
156*c8dee2aaSAndroid Build Coastguard Worker #else
157*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrMeshTest, reporter, ctxInfo, CtsEnforcement::kApiLevel_T) {
158*c8dee2aaSAndroid Build Coastguard Worker #endif
159*c8dee2aaSAndroid Build Coastguard Worker     auto dContext = ctxInfo.directContext();
160*c8dee2aaSAndroid Build Coastguard Worker 
161*c8dee2aaSAndroid Build Coastguard Worker     auto sdc = skgpu::ganesh::SurfaceDrawContext::Make(dContext,
162*c8dee2aaSAndroid Build Coastguard Worker                                                        GrColorType::kRGBA_8888,
163*c8dee2aaSAndroid Build Coastguard Worker                                                        nullptr,
164*c8dee2aaSAndroid Build Coastguard Worker                                                        SkBackingFit::kExact,
165*c8dee2aaSAndroid Build Coastguard Worker                                                        {kImageWidth, kImageHeight},
166*c8dee2aaSAndroid Build Coastguard Worker                                                        SkSurfaceProps(),
167*c8dee2aaSAndroid Build Coastguard Worker                                                        /*label=*/{});
168*c8dee2aaSAndroid Build Coastguard Worker     if (!sdc) {
169*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "could not create render target context.");
170*c8dee2aaSAndroid Build Coastguard Worker         return;
171*c8dee2aaSAndroid Build Coastguard Worker     }
172*c8dee2aaSAndroid Build Coastguard Worker 
173*c8dee2aaSAndroid Build Coastguard Worker     TArray<Box> boxes;
174*c8dee2aaSAndroid Build Coastguard Worker     TArray<std::array<Box, 4>> vertexData;
175*c8dee2aaSAndroid Build Coastguard Worker     SkBitmap gold;
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker     // ---- setup ----------
178*c8dee2aaSAndroid Build Coastguard Worker 
179*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
180*c8dee2aaSAndroid Build Coastguard Worker     paint.setBlendMode(SkBlendMode::kSrc);
181*c8dee2aaSAndroid Build Coastguard Worker     gold.allocN32Pixels(kImageWidth, kImageHeight);
182*c8dee2aaSAndroid Build Coastguard Worker 
183*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas goldCanvas(gold);
184*c8dee2aaSAndroid Build Coastguard Worker 
185*c8dee2aaSAndroid Build Coastguard Worker     for (int y = 0; y < kBoxCountY; ++y) {
186*c8dee2aaSAndroid Build Coastguard Worker         for (int x = 0; x < kBoxCountX; ++x) {
187*c8dee2aaSAndroid Build Coastguard Worker             int c = y + x;
188*c8dee2aaSAndroid Build Coastguard Worker             int rgb[3] = {-(c & 1) & 0xff, -((c >> 1) & 1) & 0xff, -((c >> 2) & 1) & 0xff};
189*c8dee2aaSAndroid Build Coastguard Worker 
190*c8dee2aaSAndroid Build Coastguard Worker             const Box box = boxes.push_back() = {
191*c8dee2aaSAndroid Build Coastguard Worker                     float(x * kBoxSize),
192*c8dee2aaSAndroid Build Coastguard Worker                     float(y * kBoxSize),
193*c8dee2aaSAndroid Build Coastguard Worker                     GrColorPackRGBA(rgb[0], rgb[1], rgb[2], 255)
194*c8dee2aaSAndroid Build Coastguard Worker             };
195*c8dee2aaSAndroid Build Coastguard Worker 
196*c8dee2aaSAndroid Build Coastguard Worker             std::array<Box, 4>& boxVertices = vertexData.push_back();
197*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < 4; ++i) {
198*c8dee2aaSAndroid Build Coastguard Worker                 boxVertices[i] = {
199*c8dee2aaSAndroid Build Coastguard Worker                         box.fX + (i / 2) * kBoxSize,
200*c8dee2aaSAndroid Build Coastguard Worker                         box.fY + (i % 2) * kBoxSize,
201*c8dee2aaSAndroid Build Coastguard Worker                         box.fColor
202*c8dee2aaSAndroid Build Coastguard Worker                 };
203*c8dee2aaSAndroid Build Coastguard Worker             }
204*c8dee2aaSAndroid Build Coastguard Worker 
205*c8dee2aaSAndroid Build Coastguard Worker             paint.setARGB(255, rgb[0], rgb[1], rgb[2]);
206*c8dee2aaSAndroid Build Coastguard Worker             goldCanvas.drawRect(SkRect::MakeXYWH(box.fX, box.fY, kBoxSize, kBoxSize), paint);
207*c8dee2aaSAndroid Build Coastguard Worker         }
208*c8dee2aaSAndroid Build Coastguard Worker     }
209*c8dee2aaSAndroid Build Coastguard Worker 
210*c8dee2aaSAndroid Build Coastguard Worker     // ---- tests ----------
211*c8dee2aaSAndroid Build Coastguard Worker 
212*c8dee2aaSAndroid Build Coastguard Worker #define VALIDATE(buff)                           \
213*c8dee2aaSAndroid Build Coastguard Worker     do {                                         \
214*c8dee2aaSAndroid Build Coastguard Worker         if (!buff) {                             \
215*c8dee2aaSAndroid Build Coastguard Worker             ERRORF(reporter, #buff " is null."); \
216*c8dee2aaSAndroid Build Coastguard Worker             return;                              \
217*c8dee2aaSAndroid Build Coastguard Worker         }                                        \
218*c8dee2aaSAndroid Build Coastguard Worker     } while (0)
219*c8dee2aaSAndroid Build Coastguard Worker 
220*c8dee2aaSAndroid Build Coastguard Worker     run_test(dContext, "draw", reporter, sdc, gold,
221*c8dee2aaSAndroid Build Coastguard Worker              [&](DrawMeshHelper* helper) {
222*c8dee2aaSAndroid Build Coastguard Worker                  TArray<Box> expandedVertexData;
223*c8dee2aaSAndroid Build Coastguard Worker                  for (int i = 0; i < kBoxCount; ++i) {
224*c8dee2aaSAndroid Build Coastguard Worker                      for (int j = 0; j < 6; ++j) {
225*c8dee2aaSAndroid Build Coastguard Worker                          expandedVertexData.push_back(vertexData[i][kIndexPattern[j]]);
226*c8dee2aaSAndroid Build Coastguard Worker                      }
227*c8dee2aaSAndroid Build Coastguard Worker                  }
228*c8dee2aaSAndroid Build Coastguard Worker 
229*c8dee2aaSAndroid Build Coastguard Worker                  // Draw boxes one line at a time to exercise base vertex.
230*c8dee2aaSAndroid Build Coastguard Worker                  helper->fVertBuffer = helper->makeVertexBuffer(expandedVertexData);
231*c8dee2aaSAndroid Build Coastguard Worker                  VALIDATE(helper->fVertBuffer);
232*c8dee2aaSAndroid Build Coastguard Worker              },
233*c8dee2aaSAndroid Build Coastguard Worker              [&](DrawMeshHelper* helper) {
234*c8dee2aaSAndroid Build Coastguard Worker                  for (int y = 0; y < kBoxCountY; ++y) {
235*c8dee2aaSAndroid Build Coastguard Worker                      auto pass = helper->bindPipeline(GrPrimitiveType::kTriangles, false, true);
236*c8dee2aaSAndroid Build Coastguard Worker                      pass->bindBuffers(nullptr, nullptr, helper->fVertBuffer);
237*c8dee2aaSAndroid Build Coastguard Worker                      pass->draw(kBoxCountX * 6, y * kBoxCountX * 6);
238*c8dee2aaSAndroid Build Coastguard Worker                  }
239*c8dee2aaSAndroid Build Coastguard Worker              });
240*c8dee2aaSAndroid Build Coastguard Worker 
241*c8dee2aaSAndroid Build Coastguard Worker     run_test(dContext, "drawIndexed", reporter, sdc, gold,
242*c8dee2aaSAndroid Build Coastguard Worker              [&](DrawMeshHelper* helper) {
243*c8dee2aaSAndroid Build Coastguard Worker                 helper->fIndexBuffer = helper->getIndexBuffer();
244*c8dee2aaSAndroid Build Coastguard Worker                 VALIDATE(helper->fIndexBuffer);
245*c8dee2aaSAndroid Build Coastguard Worker                 helper->fVertBuffer = helper->makeVertexBuffer(vertexData);
246*c8dee2aaSAndroid Build Coastguard Worker                 VALIDATE(helper->fVertBuffer);
247*c8dee2aaSAndroid Build Coastguard Worker              },
248*c8dee2aaSAndroid Build Coastguard Worker              [&](DrawMeshHelper* helper) {
249*c8dee2aaSAndroid Build Coastguard Worker                 int baseRepetition = 0;
250*c8dee2aaSAndroid Build Coastguard Worker                 int i = 0;
251*c8dee2aaSAndroid Build Coastguard Worker                 // Start at various repetitions within the patterned index buffer to exercise base
252*c8dee2aaSAndroid Build Coastguard Worker                 // index.
253*c8dee2aaSAndroid Build Coastguard Worker                 while (i < kBoxCount) {
254*c8dee2aaSAndroid Build Coastguard Worker                     static_assert(kIndexPatternRepeatCount >= 3);
255*c8dee2aaSAndroid Build Coastguard Worker                     int repetitionCount = std::min(3 - baseRepetition, kBoxCount - i);
256*c8dee2aaSAndroid Build Coastguard Worker 
257*c8dee2aaSAndroid Build Coastguard Worker                     auto pass = helper->bindPipeline(GrPrimitiveType::kTriangles, false, true);
258*c8dee2aaSAndroid Build Coastguard Worker                     pass->bindBuffers(helper->fIndexBuffer, nullptr, helper->fVertBuffer);
259*c8dee2aaSAndroid Build Coastguard Worker                     pass->drawIndexed(repetitionCount * 6, baseRepetition * 6, baseRepetition * 4,
260*c8dee2aaSAndroid Build Coastguard Worker                                       (baseRepetition + repetitionCount) * 4 - 1,
261*c8dee2aaSAndroid Build Coastguard Worker                                       (i - baseRepetition) * 4);
262*c8dee2aaSAndroid Build Coastguard Worker 
263*c8dee2aaSAndroid Build Coastguard Worker                     baseRepetition = (baseRepetition + 1) % 3;
264*c8dee2aaSAndroid Build Coastguard Worker                     i += repetitionCount;
265*c8dee2aaSAndroid Build Coastguard Worker                 }
266*c8dee2aaSAndroid Build Coastguard Worker             });
267*c8dee2aaSAndroid Build Coastguard Worker 
268*c8dee2aaSAndroid Build Coastguard Worker     run_test(dContext, "drawIndexPattern", reporter, sdc, gold,
269*c8dee2aaSAndroid Build Coastguard Worker              [&](DrawMeshHelper* helper) {
270*c8dee2aaSAndroid Build Coastguard Worker                  helper->fIndexBuffer = helper->getIndexBuffer();
271*c8dee2aaSAndroid Build Coastguard Worker                  VALIDATE(helper->fIndexBuffer);
272*c8dee2aaSAndroid Build Coastguard Worker                  helper->fVertBuffer = helper->makeVertexBuffer(vertexData);
273*c8dee2aaSAndroid Build Coastguard Worker                  VALIDATE(helper->fVertBuffer);
274*c8dee2aaSAndroid Build Coastguard Worker              },
275*c8dee2aaSAndroid Build Coastguard Worker              [&](DrawMeshHelper* helper) {
276*c8dee2aaSAndroid Build Coastguard Worker                 // Draw boxes one line at a time to exercise base vertex. drawIndexPattern does
277*c8dee2aaSAndroid Build Coastguard Worker                 // not support a base index.
278*c8dee2aaSAndroid Build Coastguard Worker                 for (int y = 0; y < kBoxCountY; ++y) {
279*c8dee2aaSAndroid Build Coastguard Worker                     auto pass = helper->bindPipeline(GrPrimitiveType::kTriangles, false, true);
280*c8dee2aaSAndroid Build Coastguard Worker                     pass->bindBuffers(helper->fIndexBuffer, nullptr, helper->fVertBuffer);
281*c8dee2aaSAndroid Build Coastguard Worker                     pass->drawIndexPattern(6, kBoxCountX, kIndexPatternRepeatCount, 4,
282*c8dee2aaSAndroid Build Coastguard Worker                                            y * kBoxCountX * 4);
283*c8dee2aaSAndroid Build Coastguard Worker 
284*c8dee2aaSAndroid Build Coastguard Worker                 }
285*c8dee2aaSAndroid Build Coastguard Worker              });
286*c8dee2aaSAndroid Build Coastguard Worker 
287*c8dee2aaSAndroid Build Coastguard Worker     for (bool indexed : {false, true}) {
288*c8dee2aaSAndroid Build Coastguard Worker         if (!dContext->priv().caps()->drawInstancedSupport()) {
289*c8dee2aaSAndroid Build Coastguard Worker             break;
290*c8dee2aaSAndroid Build Coastguard Worker         }
291*c8dee2aaSAndroid Build Coastguard Worker 
292*c8dee2aaSAndroid Build Coastguard Worker         run_test(dContext, indexed ? "drawIndexedInstanced" : "drawInstanced",
293*c8dee2aaSAndroid Build Coastguard Worker                  reporter, sdc, gold,
294*c8dee2aaSAndroid Build Coastguard Worker                  [&](DrawMeshHelper* helper) {
295*c8dee2aaSAndroid Build Coastguard Worker                      helper->fIndexBuffer = indexed ? helper->getIndexBuffer() : nullptr;
296*c8dee2aaSAndroid Build Coastguard Worker                      TArray<uint16_t> baseIndexData;
297*c8dee2aaSAndroid Build Coastguard Worker                      baseIndexData.push_back(kBoxCountX/2 * 6); // for testing base index.
298*c8dee2aaSAndroid Build Coastguard Worker                      for (int i = 0; i < 6; ++i) {
299*c8dee2aaSAndroid Build Coastguard Worker                          baseIndexData.push_back(kIndexPattern[i]);
300*c8dee2aaSAndroid Build Coastguard Worker                      }
301*c8dee2aaSAndroid Build Coastguard Worker                      helper->fIndexBuffer2 = helper->makeIndexBuffer(baseIndexData.begin(),
302*c8dee2aaSAndroid Build Coastguard Worker                                                                      baseIndexData.size());
303*c8dee2aaSAndroid Build Coastguard Worker                      helper->fInstBuffer = helper->makeVertexBuffer(boxes);
304*c8dee2aaSAndroid Build Coastguard Worker                      VALIDATE(helper->fInstBuffer);
305*c8dee2aaSAndroid Build Coastguard Worker                      helper->fVertBuffer =
306*c8dee2aaSAndroid Build Coastguard Worker                              helper->makeVertexBuffer(std::vector<float>{0,0, 0,1, 1,0, 1,1});
307*c8dee2aaSAndroid Build Coastguard Worker                      VALIDATE(helper->fVertBuffer);
308*c8dee2aaSAndroid Build Coastguard Worker                      helper->fVertBuffer2 = helper->makeVertexBuffer( // for testing base vertex.
309*c8dee2aaSAndroid Build Coastguard Worker                          std::vector<float>{-1,-1, -1,-1, 0,0, 0,1, 1,0, 1,1});
310*c8dee2aaSAndroid Build Coastguard Worker                      VALIDATE(helper->fVertBuffer2);
311*c8dee2aaSAndroid Build Coastguard Worker                  },
312*c8dee2aaSAndroid Build Coastguard Worker                  [&](DrawMeshHelper* helper) {
313*c8dee2aaSAndroid Build Coastguard Worker                      // Draw boxes one line at a time to exercise base instance, base vertex, and
314*c8dee2aaSAndroid Build Coastguard Worker                      // null vertex buffer.
315*c8dee2aaSAndroid Build Coastguard Worker                      for (int y = 0; y < kBoxCountY; ++y) {
316*c8dee2aaSAndroid Build Coastguard Worker                          sk_sp<const GrBuffer> vertexBuffer;
317*c8dee2aaSAndroid Build Coastguard Worker                          int baseVertex = 0;
318*c8dee2aaSAndroid Build Coastguard Worker                          switch (y % 3) {
319*c8dee2aaSAndroid Build Coastguard Worker                              case 0:
320*c8dee2aaSAndroid Build Coastguard Worker                                  if (dContext->priv().caps()->shaderCaps()->fVertexIDSupport) {
321*c8dee2aaSAndroid Build Coastguard Worker                                      break;
322*c8dee2aaSAndroid Build Coastguard Worker                                  }
323*c8dee2aaSAndroid Build Coastguard Worker                                  [[fallthrough]];
324*c8dee2aaSAndroid Build Coastguard Worker                              case 1:
325*c8dee2aaSAndroid Build Coastguard Worker                                  vertexBuffer = helper->fVertBuffer;
326*c8dee2aaSAndroid Build Coastguard Worker                                  break;
327*c8dee2aaSAndroid Build Coastguard Worker                              case 2:
328*c8dee2aaSAndroid Build Coastguard Worker                                  vertexBuffer = helper->fVertBuffer2;
329*c8dee2aaSAndroid Build Coastguard Worker                                  baseVertex = 2;
330*c8dee2aaSAndroid Build Coastguard Worker                                  break;
331*c8dee2aaSAndroid Build Coastguard Worker                          }
332*c8dee2aaSAndroid Build Coastguard Worker 
333*c8dee2aaSAndroid Build Coastguard Worker                          GrPrimitiveType primitiveType = indexed ? GrPrimitiveType::kTriangles
334*c8dee2aaSAndroid Build Coastguard Worker                                                                  : GrPrimitiveType::kTriangleStrip;
335*c8dee2aaSAndroid Build Coastguard Worker                          auto pass = helper->bindPipeline(primitiveType, true,
336*c8dee2aaSAndroid Build Coastguard Worker                                                           SkToBool(vertexBuffer));
337*c8dee2aaSAndroid Build Coastguard Worker                          if (indexed) {
338*c8dee2aaSAndroid Build Coastguard Worker                              sk_sp<const GrBuffer> indexBuffer = (y % 2) ?
339*c8dee2aaSAndroid Build Coastguard Worker                                      helper->fIndexBuffer2 : helper->fIndexBuffer;
340*c8dee2aaSAndroid Build Coastguard Worker                              VALIDATE(indexBuffer);
341*c8dee2aaSAndroid Build Coastguard Worker                              int baseIndex = (y % 2);
342*c8dee2aaSAndroid Build Coastguard Worker                              pass->bindBuffers(std::move(indexBuffer), helper->fInstBuffer,
343*c8dee2aaSAndroid Build Coastguard Worker                                                std::move(vertexBuffer));
344*c8dee2aaSAndroid Build Coastguard Worker                              pass->drawIndexedInstanced(6, baseIndex, kBoxCountX, y * kBoxCountX,
345*c8dee2aaSAndroid Build Coastguard Worker                                                         baseVertex);
346*c8dee2aaSAndroid Build Coastguard Worker                          } else {
347*c8dee2aaSAndroid Build Coastguard Worker                              pass->bindBuffers(nullptr, helper->fInstBuffer,
348*c8dee2aaSAndroid Build Coastguard Worker                                                std::move(vertexBuffer));
349*c8dee2aaSAndroid Build Coastguard Worker                              pass->drawInstanced(kBoxCountX, y * kBoxCountY, 4, baseVertex);
350*c8dee2aaSAndroid Build Coastguard Worker                          }
351*c8dee2aaSAndroid Build Coastguard Worker                      }
352*c8dee2aaSAndroid Build Coastguard Worker                  });
353*c8dee2aaSAndroid Build Coastguard Worker     }
354*c8dee2aaSAndroid Build Coastguard Worker 
355*c8dee2aaSAndroid Build Coastguard Worker     for (bool indexed : {false, true}) {
356*c8dee2aaSAndroid Build Coastguard Worker         if (!dContext->priv().caps()->drawInstancedSupport()) {
357*c8dee2aaSAndroid Build Coastguard Worker             break;
358*c8dee2aaSAndroid Build Coastguard Worker         }
359*c8dee2aaSAndroid Build Coastguard Worker 
360*c8dee2aaSAndroid Build Coastguard Worker         run_test(dContext, (indexed) ? "drawIndexedIndirect" : "drawIndirect",
361*c8dee2aaSAndroid Build Coastguard Worker                  reporter, sdc, gold,
362*c8dee2aaSAndroid Build Coastguard Worker                  [&](DrawMeshHelper* helper) {
363*c8dee2aaSAndroid Build Coastguard Worker                      TArray<uint16_t> baseIndexData;
364*c8dee2aaSAndroid Build Coastguard Worker                      baseIndexData.push_back(kBoxCountX/2 * 6); // for testing base index.
365*c8dee2aaSAndroid Build Coastguard Worker                      for (int j = 0; j < kBoxCountY; ++j) {
366*c8dee2aaSAndroid Build Coastguard Worker                          for (int i = 0; i < 6; ++i) {
367*c8dee2aaSAndroid Build Coastguard Worker                              baseIndexData.push_back(kIndexPattern[i]);
368*c8dee2aaSAndroid Build Coastguard Worker                          }
369*c8dee2aaSAndroid Build Coastguard Worker                      }
370*c8dee2aaSAndroid Build Coastguard Worker                      helper->fIndexBuffer2 = helper->makeIndexBuffer(baseIndexData.begin(),
371*c8dee2aaSAndroid Build Coastguard Worker                                                                      baseIndexData.size());
372*c8dee2aaSAndroid Build Coastguard Worker                      VALIDATE(helper->fIndexBuffer2);
373*c8dee2aaSAndroid Build Coastguard Worker                      helper->fInstBuffer = helper->makeVertexBuffer(boxes);
374*c8dee2aaSAndroid Build Coastguard Worker                      VALIDATE(helper->fInstBuffer);
375*c8dee2aaSAndroid Build Coastguard Worker                      helper->fVertBuffer = helper->makeVertexBuffer(std::vector<float>{
376*c8dee2aaSAndroid Build Coastguard Worker                              -1,-1, 0,0, 0,1, 1,0, 1,1, -1,-1, 0,0, 1,0, 0,1, 1,1});
377*c8dee2aaSAndroid Build Coastguard Worker                      VALIDATE(helper->fVertBuffer);
378*c8dee2aaSAndroid Build Coastguard Worker 
379*c8dee2aaSAndroid Build Coastguard Worker                      GrDrawIndirectWriter indirectWriter;
380*c8dee2aaSAndroid Build Coastguard Worker                      GrDrawIndexedIndirectWriter indexedIndirectWriter;
381*c8dee2aaSAndroid Build Coastguard Worker                      if (indexed) {
382*c8dee2aaSAndroid Build Coastguard Worker                          // Make helper->fDrawIndirectBufferOffset nonzero.
383*c8dee2aaSAndroid Build Coastguard Worker                          sk_sp<const GrBuffer> ignoredBuff;
384*c8dee2aaSAndroid Build Coastguard Worker                          size_t ignoredOffset;
385*c8dee2aaSAndroid Build Coastguard Worker                          // Make a superfluous call to makeDrawIndirectSpace in order to test
386*c8dee2aaSAndroid Build Coastguard Worker                          // "offsetInBytes!=0" for the actual call to makeDrawIndexedIndirectSpace.
387*c8dee2aaSAndroid Build Coastguard Worker                          helper->target()->makeDrawIndirectSpace(29, &ignoredBuff, &ignoredOffset);
388*c8dee2aaSAndroid Build Coastguard Worker                          indexedIndirectWriter = helper->target()->makeDrawIndexedIndirectSpace(
389*c8dee2aaSAndroid Build Coastguard Worker                                  kBoxCountY, &helper->fDrawIndirectBuffer,
390*c8dee2aaSAndroid Build Coastguard Worker                                  &helper->fDrawIndirectBufferOffset);
391*c8dee2aaSAndroid Build Coastguard Worker                      } else {
392*c8dee2aaSAndroid Build Coastguard Worker                          // Make helper->fDrawIndirectBufferOffset nonzero.
393*c8dee2aaSAndroid Build Coastguard Worker                          sk_sp<const GrBuffer> ignoredBuff;
394*c8dee2aaSAndroid Build Coastguard Worker                          size_t ignoredOffset;
395*c8dee2aaSAndroid Build Coastguard Worker                          // Make a superfluous call to makeDrawIndexedIndirectSpace in order to test
396*c8dee2aaSAndroid Build Coastguard Worker                          // "offsetInBytes!=0" for the actual call to makeDrawIndirectSpace.
397*c8dee2aaSAndroid Build Coastguard Worker                          helper->target()->makeDrawIndexedIndirectSpace(7, &ignoredBuff,
398*c8dee2aaSAndroid Build Coastguard Worker                                                                         &ignoredOffset);
399*c8dee2aaSAndroid Build Coastguard Worker                          indirectWriter = helper->target()->makeDrawIndirectSpace(
400*c8dee2aaSAndroid Build Coastguard Worker                                  kBoxCountY, &helper->fDrawIndirectBuffer,
401*c8dee2aaSAndroid Build Coastguard Worker                                  &helper->fDrawIndirectBufferOffset);
402*c8dee2aaSAndroid Build Coastguard Worker                      }
403*c8dee2aaSAndroid Build Coastguard Worker 
404*c8dee2aaSAndroid Build Coastguard Worker                      // Draw boxes one line at a time to exercise multiple draws.
405*c8dee2aaSAndroid Build Coastguard Worker                      for (int y = 0; y < kBoxCountY; ++y) {
406*c8dee2aaSAndroid Build Coastguard Worker                          int baseVertex = (y % 2) ? 1 : 6;
407*c8dee2aaSAndroid Build Coastguard Worker                          if (indexed) {
408*c8dee2aaSAndroid Build Coastguard Worker                              int baseIndex = 1 + y * 6;
409*c8dee2aaSAndroid Build Coastguard Worker                              indexedIndirectWriter.writeIndexed(6, baseIndex, kBoxCountX,
410*c8dee2aaSAndroid Build Coastguard Worker                                                                 y * kBoxCountX, baseVertex);
411*c8dee2aaSAndroid Build Coastguard Worker                          } else {
412*c8dee2aaSAndroid Build Coastguard Worker                              indirectWriter.write(kBoxCountX, y * kBoxCountX, 4, baseVertex);
413*c8dee2aaSAndroid Build Coastguard Worker                          }
414*c8dee2aaSAndroid Build Coastguard Worker                      }
415*c8dee2aaSAndroid Build Coastguard Worker                  },
416*c8dee2aaSAndroid Build Coastguard Worker                  [&](DrawMeshHelper* helper) {
417*c8dee2aaSAndroid Build Coastguard Worker                      GrOpsRenderPass* pass;
418*c8dee2aaSAndroid Build Coastguard Worker                      if (indexed) {
419*c8dee2aaSAndroid Build Coastguard Worker                          pass = helper->bindPipeline(GrPrimitiveType::kTriangles, true, true);
420*c8dee2aaSAndroid Build Coastguard Worker                          pass->bindBuffers(helper->fIndexBuffer2, helper->fInstBuffer,
421*c8dee2aaSAndroid Build Coastguard Worker                                            helper->fVertBuffer);
422*c8dee2aaSAndroid Build Coastguard Worker                          for (int i = 0; i < 3; ++i) {
423*c8dee2aaSAndroid Build Coastguard Worker                              int start = kBoxCountY * i / 3;
424*c8dee2aaSAndroid Build Coastguard Worker                              int end = kBoxCountY * (i + 1) / 3;
425*c8dee2aaSAndroid Build Coastguard Worker                              size_t offset = helper->fDrawIndirectBufferOffset + start *
426*c8dee2aaSAndroid Build Coastguard Worker                                              sizeof(GrDrawIndexedIndirectCommand);
427*c8dee2aaSAndroid Build Coastguard Worker                              pass->drawIndexedIndirect(helper->fDrawIndirectBuffer.get(), offset,
428*c8dee2aaSAndroid Build Coastguard Worker                                                        end - start);
429*c8dee2aaSAndroid Build Coastguard Worker                          }
430*c8dee2aaSAndroid Build Coastguard Worker                      } else {
431*c8dee2aaSAndroid Build Coastguard Worker                          pass = helper->bindPipeline(GrPrimitiveType::kTriangleStrip, true, true);
432*c8dee2aaSAndroid Build Coastguard Worker                          pass->bindBuffers(nullptr, helper->fInstBuffer, helper->fVertBuffer);
433*c8dee2aaSAndroid Build Coastguard Worker                          for (int i = 0; i < 2; ++i) {
434*c8dee2aaSAndroid Build Coastguard Worker                              int start = kBoxCountY * i / 2;
435*c8dee2aaSAndroid Build Coastguard Worker                              int end = kBoxCountY * (i + 1) / 2;
436*c8dee2aaSAndroid Build Coastguard Worker                              size_t offset = helper->fDrawIndirectBufferOffset + start *
437*c8dee2aaSAndroid Build Coastguard Worker                                              sizeof(GrDrawIndirectCommand);
438*c8dee2aaSAndroid Build Coastguard Worker                              pass->drawIndirect(helper->fDrawIndirectBuffer.get(), offset,
439*c8dee2aaSAndroid Build Coastguard Worker                                                 end - start);
440*c8dee2aaSAndroid Build Coastguard Worker                          }
441*c8dee2aaSAndroid Build Coastguard Worker                      }
442*c8dee2aaSAndroid Build Coastguard Worker                  });
443*c8dee2aaSAndroid Build Coastguard Worker     }
444*c8dee2aaSAndroid Build Coastguard Worker }
445*c8dee2aaSAndroid Build Coastguard Worker 
446*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////////////////////////
447*c8dee2aaSAndroid Build Coastguard Worker 
448*c8dee2aaSAndroid Build Coastguard Worker namespace {
449*c8dee2aaSAndroid Build Coastguard Worker class MeshTestOp : public GrDrawOp {
450*c8dee2aaSAndroid Build Coastguard Worker public:
451*c8dee2aaSAndroid Build Coastguard Worker     DEFINE_OP_CLASS_ID
452*c8dee2aaSAndroid Build Coastguard Worker 
453*c8dee2aaSAndroid Build Coastguard Worker     static GrOp::Owner Make(GrRecordingContext* rContext,
454*c8dee2aaSAndroid Build Coastguard Worker                             std::function<void(DrawMeshHelper*)> prepareFn,
455*c8dee2aaSAndroid Build Coastguard Worker                             std::function<void(DrawMeshHelper*)> executeFn) {
456*c8dee2aaSAndroid Build Coastguard Worker         return GrOp::Make<MeshTestOp>(rContext, prepareFn, executeFn);
457*c8dee2aaSAndroid Build Coastguard Worker     }
458*c8dee2aaSAndroid Build Coastguard Worker 
459*c8dee2aaSAndroid Build Coastguard Worker private:
460*c8dee2aaSAndroid Build Coastguard Worker     friend class GrOp;  // for ctor
461*c8dee2aaSAndroid Build Coastguard Worker 
462*c8dee2aaSAndroid Build Coastguard Worker     MeshTestOp(std::function<void(DrawMeshHelper*)> prepareFn,
463*c8dee2aaSAndroid Build Coastguard Worker                std::function<void(DrawMeshHelper*)> executeFn)
464*c8dee2aaSAndroid Build Coastguard Worker             : INHERITED(ClassID()), fPrepareFn(prepareFn), fExecuteFn(executeFn) {
465*c8dee2aaSAndroid Build Coastguard Worker         this->setBounds(
466*c8dee2aaSAndroid Build Coastguard Worker                 SkRect::MakeIWH(kImageWidth, kImageHeight), HasAABloat::kNo, IsHairline::kNo);
467*c8dee2aaSAndroid Build Coastguard Worker     }
468*c8dee2aaSAndroid Build Coastguard Worker 
469*c8dee2aaSAndroid Build Coastguard Worker     const char* name() const override { return "GrMeshTestOp"; }
470*c8dee2aaSAndroid Build Coastguard Worker     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
471*c8dee2aaSAndroid Build Coastguard Worker     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
472*c8dee2aaSAndroid Build Coastguard Worker         return GrProcessorSet::EmptySetAnalysis();
473*c8dee2aaSAndroid Build Coastguard Worker     }
474*c8dee2aaSAndroid Build Coastguard Worker 
475*c8dee2aaSAndroid Build Coastguard Worker     void onPrePrepare(GrRecordingContext*,
476*c8dee2aaSAndroid Build Coastguard Worker                       const GrSurfaceProxyView& writeView,
477*c8dee2aaSAndroid Build Coastguard Worker                       GrAppliedClip*,
478*c8dee2aaSAndroid Build Coastguard Worker                       const GrDstProxyView&,
479*c8dee2aaSAndroid Build Coastguard Worker                       GrXferBarrierFlags renderPassXferBarriers,
480*c8dee2aaSAndroid Build Coastguard Worker                       GrLoadOp colorLoadOp) override {}
481*c8dee2aaSAndroid Build Coastguard Worker     void onPrepare(GrOpFlushState* state) override {
482*c8dee2aaSAndroid Build Coastguard Worker         fHelper = std::make_unique<DrawMeshHelper>(state);
483*c8dee2aaSAndroid Build Coastguard Worker         fPrepareFn(fHelper.get());
484*c8dee2aaSAndroid Build Coastguard Worker     }
485*c8dee2aaSAndroid Build Coastguard Worker     void onExecute(GrOpFlushState* state, const SkRect& chainBounds) override {
486*c8dee2aaSAndroid Build Coastguard Worker         fExecuteFn(fHelper.get());
487*c8dee2aaSAndroid Build Coastguard Worker     }
488*c8dee2aaSAndroid Build Coastguard Worker 
489*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<DrawMeshHelper> fHelper;
490*c8dee2aaSAndroid Build Coastguard Worker     std::function<void(DrawMeshHelper*)> fPrepareFn;
491*c8dee2aaSAndroid Build Coastguard Worker     std::function<void(DrawMeshHelper*)> fExecuteFn;
492*c8dee2aaSAndroid Build Coastguard Worker 
493*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GrDrawOp;
494*c8dee2aaSAndroid Build Coastguard Worker };
495*c8dee2aaSAndroid Build Coastguard Worker 
496*c8dee2aaSAndroid Build Coastguard Worker class MeshTestProcessor : public GrGeometryProcessor {
497*c8dee2aaSAndroid Build Coastguard Worker public:
498*c8dee2aaSAndroid Build Coastguard Worker     static GrGeometryProcessor* Make(SkArenaAlloc* arena, bool instanced, bool hasVertexBuffer) {
499*c8dee2aaSAndroid Build Coastguard Worker         return arena->make([&](void* ptr) {
500*c8dee2aaSAndroid Build Coastguard Worker             return new (ptr) MeshTestProcessor(instanced, hasVertexBuffer);
501*c8dee2aaSAndroid Build Coastguard Worker         });
502*c8dee2aaSAndroid Build Coastguard Worker     }
503*c8dee2aaSAndroid Build Coastguard Worker 
504*c8dee2aaSAndroid Build Coastguard Worker     const char* name() const override { return "GrMeshTestProcessor"; }
505*c8dee2aaSAndroid Build Coastguard Worker 
506*c8dee2aaSAndroid Build Coastguard Worker     void addToKey(const GrShaderCaps&, skgpu::KeyBuilder* b) const final {
507*c8dee2aaSAndroid Build Coastguard Worker         b->add32(fInstanceLocation.isInitialized());
508*c8dee2aaSAndroid Build Coastguard Worker         b->add32(fVertexPosition.isInitialized());
509*c8dee2aaSAndroid Build Coastguard Worker     }
510*c8dee2aaSAndroid Build Coastguard Worker 
511*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const final;
512*c8dee2aaSAndroid Build Coastguard Worker 
513*c8dee2aaSAndroid Build Coastguard Worker private:
514*c8dee2aaSAndroid Build Coastguard Worker     class Impl;
515*c8dee2aaSAndroid Build Coastguard Worker 
516*c8dee2aaSAndroid Build Coastguard Worker     const Attribute& inColor() const {
517*c8dee2aaSAndroid Build Coastguard Worker         return fVertexColor.isInitialized() ? fVertexColor : fInstanceColor;
518*c8dee2aaSAndroid Build Coastguard Worker     }
519*c8dee2aaSAndroid Build Coastguard Worker 
520*c8dee2aaSAndroid Build Coastguard Worker     MeshTestProcessor(bool instanced, bool hasVertexBuffer)
521*c8dee2aaSAndroid Build Coastguard Worker             : INHERITED(kGrMeshTestProcessor_ClassID) {
522*c8dee2aaSAndroid Build Coastguard Worker         if (instanced) {
523*c8dee2aaSAndroid Build Coastguard Worker             fInstanceLocation = {"location", kFloat2_GrVertexAttribType, SkSLType::kHalf2};
524*c8dee2aaSAndroid Build Coastguard Worker             fInstanceColor = {"color", kUByte4_norm_GrVertexAttribType, SkSLType::kHalf4};
525*c8dee2aaSAndroid Build Coastguard Worker             this->setInstanceAttributesWithImplicitOffsets(&fInstanceLocation, 2);
526*c8dee2aaSAndroid Build Coastguard Worker             if (hasVertexBuffer) {
527*c8dee2aaSAndroid Build Coastguard Worker                 fVertexPosition = {"vertex", kFloat2_GrVertexAttribType, SkSLType::kHalf2};
528*c8dee2aaSAndroid Build Coastguard Worker                 this->setVertexAttributesWithImplicitOffsets(&fVertexPosition, 1);
529*c8dee2aaSAndroid Build Coastguard Worker             }
530*c8dee2aaSAndroid Build Coastguard Worker         } else {
531*c8dee2aaSAndroid Build Coastguard Worker             fVertexPosition = {"vertex", kFloat2_GrVertexAttribType, SkSLType::kHalf2};
532*c8dee2aaSAndroid Build Coastguard Worker             fVertexColor = {"color", kUByte4_norm_GrVertexAttribType, SkSLType::kHalf4};
533*c8dee2aaSAndroid Build Coastguard Worker             this->setVertexAttributesWithImplicitOffsets(&fVertexPosition, 2);
534*c8dee2aaSAndroid Build Coastguard Worker         }
535*c8dee2aaSAndroid Build Coastguard Worker     }
536*c8dee2aaSAndroid Build Coastguard Worker 
537*c8dee2aaSAndroid Build Coastguard Worker     Attribute fVertexPosition;
538*c8dee2aaSAndroid Build Coastguard Worker     Attribute fVertexColor;
539*c8dee2aaSAndroid Build Coastguard Worker 
540*c8dee2aaSAndroid Build Coastguard Worker     Attribute fInstanceLocation;
541*c8dee2aaSAndroid Build Coastguard Worker     Attribute fInstanceColor;
542*c8dee2aaSAndroid Build Coastguard Worker 
543*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GrGeometryProcessor;
544*c8dee2aaSAndroid Build Coastguard Worker };
545*c8dee2aaSAndroid Build Coastguard Worker }  // anonymous namespace
546*c8dee2aaSAndroid Build Coastguard Worker 
547*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrGeometryProcessor::ProgramImpl> MeshTestProcessor::makeProgramImpl(
548*c8dee2aaSAndroid Build Coastguard Worker         const GrShaderCaps&) const {
549*c8dee2aaSAndroid Build Coastguard Worker     class Impl : public ProgramImpl {
550*c8dee2aaSAndroid Build Coastguard Worker     public:
551*c8dee2aaSAndroid Build Coastguard Worker         void setData(const GrGLSLProgramDataManager&,
552*c8dee2aaSAndroid Build Coastguard Worker                      const GrShaderCaps&,
553*c8dee2aaSAndroid Build Coastguard Worker                      const GrGeometryProcessor&) final {}
554*c8dee2aaSAndroid Build Coastguard Worker 
555*c8dee2aaSAndroid Build Coastguard Worker     private:
556*c8dee2aaSAndroid Build Coastguard Worker         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final {
557*c8dee2aaSAndroid Build Coastguard Worker             const MeshTestProcessor& mp = args.fGeomProc.cast<MeshTestProcessor>();
558*c8dee2aaSAndroid Build Coastguard Worker             GrGLSLVertexBuilder* v = args.fVertBuilder;
559*c8dee2aaSAndroid Build Coastguard Worker             GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
560*c8dee2aaSAndroid Build Coastguard Worker 
561*c8dee2aaSAndroid Build Coastguard Worker             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
562*c8dee2aaSAndroid Build Coastguard Worker             varyingHandler->emitAttributes(mp);
563*c8dee2aaSAndroid Build Coastguard Worker             f->codeAppendf("half4 %s;", args.fOutputColor);
564*c8dee2aaSAndroid Build Coastguard Worker             varyingHandler->addPassThroughAttribute(mp.inColor().asShaderVar(), args.fOutputColor);
565*c8dee2aaSAndroid Build Coastguard Worker 
566*c8dee2aaSAndroid Build Coastguard Worker             if (!mp.fInstanceLocation.isInitialized()) {
567*c8dee2aaSAndroid Build Coastguard Worker                 v->codeAppendf("float2 vertex = %s;", mp.fVertexPosition.name());
568*c8dee2aaSAndroid Build Coastguard Worker             } else {
569*c8dee2aaSAndroid Build Coastguard Worker                 if (mp.fVertexPosition.isInitialized()) {
570*c8dee2aaSAndroid Build Coastguard Worker                     v->codeAppendf("float2 offset = %s;", mp.fVertexPosition.name());
571*c8dee2aaSAndroid Build Coastguard Worker                 } else {
572*c8dee2aaSAndroid Build Coastguard Worker                     v->codeAppend("float2 offset = float2(sk_VertexID / 2, sk_VertexID % 2);");
573*c8dee2aaSAndroid Build Coastguard Worker                 }
574*c8dee2aaSAndroid Build Coastguard Worker                 v->codeAppendf("float2 vertex = %s + offset * %i;", mp.fInstanceLocation.name(),
575*c8dee2aaSAndroid Build Coastguard Worker                                kBoxSize);
576*c8dee2aaSAndroid Build Coastguard Worker             }
577*c8dee2aaSAndroid Build Coastguard Worker             gpArgs->fPositionVar.set(SkSLType::kFloat2, "vertex");
578*c8dee2aaSAndroid Build Coastguard Worker 
579*c8dee2aaSAndroid Build Coastguard Worker             f->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
580*c8dee2aaSAndroid Build Coastguard Worker         }
581*c8dee2aaSAndroid Build Coastguard Worker     };
582*c8dee2aaSAndroid Build Coastguard Worker 
583*c8dee2aaSAndroid Build Coastguard Worker     return std::make_unique<Impl>();
584*c8dee2aaSAndroid Build Coastguard Worker }
585*c8dee2aaSAndroid Build Coastguard Worker 
586*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////////////////////////
587*c8dee2aaSAndroid Build Coastguard Worker 
588*c8dee2aaSAndroid Build Coastguard Worker sk_sp<const GrBuffer> DrawMeshHelper::makeIndexBuffer(const uint16_t indices[], int count) {
589*c8dee2aaSAndroid Build Coastguard Worker     return fState->resourceProvider()->createBuffer(indices,
590*c8dee2aaSAndroid Build Coastguard Worker                                                     count*sizeof(uint16_t),
591*c8dee2aaSAndroid Build Coastguard Worker                                                     GrGpuBufferType::kIndex,
592*c8dee2aaSAndroid Build Coastguard Worker                                                     kDynamic_GrAccessPattern);
593*c8dee2aaSAndroid Build Coastguard Worker }
594*c8dee2aaSAndroid Build Coastguard Worker 
595*c8dee2aaSAndroid Build Coastguard Worker template<typename T>
596*c8dee2aaSAndroid Build Coastguard Worker sk_sp<const GrBuffer> DrawMeshHelper::makeVertexBuffer(const T* data, int count) {
597*c8dee2aaSAndroid Build Coastguard Worker     return fState->resourceProvider()->createBuffer(data,
598*c8dee2aaSAndroid Build Coastguard Worker                                                     count*sizeof(T),
599*c8dee2aaSAndroid Build Coastguard Worker                                                     GrGpuBufferType::kVertex,
600*c8dee2aaSAndroid Build Coastguard Worker                                                     kDynamic_GrAccessPattern);
601*c8dee2aaSAndroid Build Coastguard Worker }
602*c8dee2aaSAndroid Build Coastguard Worker 
603*c8dee2aaSAndroid Build Coastguard Worker sk_sp<const GrBuffer> DrawMeshHelper::getIndexBuffer() {
604*c8dee2aaSAndroid Build Coastguard Worker     SKGPU_DEFINE_STATIC_UNIQUE_KEY(gIndexBufferKey);
605*c8dee2aaSAndroid Build Coastguard Worker     return fState->resourceProvider()->findOrCreatePatternedIndexBuffer(
606*c8dee2aaSAndroid Build Coastguard Worker             kIndexPattern, 6, kIndexPatternRepeatCount, 4, gIndexBufferKey);
607*c8dee2aaSAndroid Build Coastguard Worker }
608*c8dee2aaSAndroid Build Coastguard Worker 
609*c8dee2aaSAndroid Build Coastguard Worker GrOpsRenderPass* DrawMeshHelper::bindPipeline(GrPrimitiveType primitiveType, bool isInstanced,
610*c8dee2aaSAndroid Build Coastguard Worker                                               bool hasVertexBuffer) {
611*c8dee2aaSAndroid Build Coastguard Worker     GrProcessorSet processorSet(SkBlendMode::kSrc);
612*c8dee2aaSAndroid Build Coastguard Worker 
613*c8dee2aaSAndroid Build Coastguard Worker     // TODO: add a GrProcessorSet testing helper to make this easier
614*c8dee2aaSAndroid Build Coastguard Worker     SkPMColor4f overrideColor;
615*c8dee2aaSAndroid Build Coastguard Worker     processorSet.finalize(GrProcessorAnalysisColor(),
616*c8dee2aaSAndroid Build Coastguard Worker                           GrProcessorAnalysisCoverage::kNone,
617*c8dee2aaSAndroid Build Coastguard Worker                           fState->appliedClip(),
618*c8dee2aaSAndroid Build Coastguard Worker                           nullptr,
619*c8dee2aaSAndroid Build Coastguard Worker                           fState->caps(),
620*c8dee2aaSAndroid Build Coastguard Worker                           GrClampType::kAuto,
621*c8dee2aaSAndroid Build Coastguard Worker                           &overrideColor);
622*c8dee2aaSAndroid Build Coastguard Worker 
623*c8dee2aaSAndroid Build Coastguard Worker     auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(fState,
624*c8dee2aaSAndroid Build Coastguard Worker                                                              std::move(processorSet),
625*c8dee2aaSAndroid Build Coastguard Worker                                                              GrPipeline::InputFlags::kNone);
626*c8dee2aaSAndroid Build Coastguard Worker 
627*c8dee2aaSAndroid Build Coastguard Worker     GrGeometryProcessor* mtp = MeshTestProcessor::Make(fState->allocator(), isInstanced,
628*c8dee2aaSAndroid Build Coastguard Worker                                                        hasVertexBuffer);
629*c8dee2aaSAndroid Build Coastguard Worker 
630*c8dee2aaSAndroid Build Coastguard Worker     GrProgramInfo programInfo(fState->caps(), fState->writeView(), fState->usesMSAASurface(),
631*c8dee2aaSAndroid Build Coastguard Worker                               pipeline, &GrUserStencilSettings::kUnused, mtp, primitiveType,
632*c8dee2aaSAndroid Build Coastguard Worker                               fState->renderPassBarriers(), fState->colorLoadOp());
633*c8dee2aaSAndroid Build Coastguard Worker 
634*c8dee2aaSAndroid Build Coastguard Worker     fState->opsRenderPass()->bindPipeline(programInfo, SkRect::MakeIWH(kImageWidth, kImageHeight));
635*c8dee2aaSAndroid Build Coastguard Worker     return fState->opsRenderPass();
636*c8dee2aaSAndroid Build Coastguard Worker }
637*c8dee2aaSAndroid Build Coastguard Worker 
638*c8dee2aaSAndroid Build Coastguard Worker static void run_test(GrDirectContext* dContext,
639*c8dee2aaSAndroid Build Coastguard Worker                      const char* testName,
640*c8dee2aaSAndroid Build Coastguard Worker                      skiatest::Reporter* reporter,
641*c8dee2aaSAndroid Build Coastguard Worker                      const std::unique_ptr<skgpu::ganesh::SurfaceDrawContext>& sdc,
642*c8dee2aaSAndroid Build Coastguard Worker                      const SkBitmap& gold,
643*c8dee2aaSAndroid Build Coastguard Worker                      std::function<void(DrawMeshHelper*)> prepareFn,
644*c8dee2aaSAndroid Build Coastguard Worker                      std::function<void(DrawMeshHelper*)> executeFn) {
645*c8dee2aaSAndroid Build Coastguard Worker     const int w = gold.width(), h = gold.height();
646*c8dee2aaSAndroid Build Coastguard Worker     const uint32_t* goldPx = reinterpret_cast<const uint32_t*>(gold.getPixels());
647*c8dee2aaSAndroid Build Coastguard Worker     if (h != sdc->height() || w != sdc->width()) {
648*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "[%s] expectation and rtc not compatible (?).", testName);
649*c8dee2aaSAndroid Build Coastguard Worker         return;
650*c8dee2aaSAndroid Build Coastguard Worker     }
651*c8dee2aaSAndroid Build Coastguard Worker     if (sizeof(uint32_t) * kImageWidth != gold.rowBytes()) {
652*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "[%s] unexpected row bytes in gold image", testName);
653*c8dee2aaSAndroid Build Coastguard Worker         return;
654*c8dee2aaSAndroid Build Coastguard Worker     }
655*c8dee2aaSAndroid Build Coastguard Worker 
656*c8dee2aaSAndroid Build Coastguard Worker     GrPixmap resultPM = GrPixmap::Allocate(gold.info());
657*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(SkPMColor4f::FromBytes_RGBA(0xbaaaaaad));
658*c8dee2aaSAndroid Build Coastguard Worker     sdc->addDrawOp(MeshTestOp::Make(dContext, prepareFn, executeFn));
659*c8dee2aaSAndroid Build Coastguard Worker 
660*c8dee2aaSAndroid Build Coastguard Worker     sdc->readPixels(dContext, resultPM, {0, 0});
661*c8dee2aaSAndroid Build Coastguard Worker 
662*c8dee2aaSAndroid Build Coastguard Worker #ifdef WRITE_PNG_CONTEXT_TYPE
663*c8dee2aaSAndroid Build Coastguard Worker #define STRINGIFY(X) #X
664*c8dee2aaSAndroid Build Coastguard Worker #define TOSTRING(X) STRINGIFY(X)
665*c8dee2aaSAndroid Build Coastguard Worker     SkString filename;
666*c8dee2aaSAndroid Build Coastguard Worker     filename.printf("GrMeshTest_%s_%s.png", TOSTRING(WRITE_PNG_CONTEXT_TYPE), testName);
667*c8dee2aaSAndroid Build Coastguard Worker     SkDebugf("writing %s...\n", filename.c_str());
668*c8dee2aaSAndroid Build Coastguard Worker     ToolUtils::EncodeImageToPngFile(filename.c_str(), resultPM);
669*c8dee2aaSAndroid Build Coastguard Worker #endif
670*c8dee2aaSAndroid Build Coastguard Worker 
671*c8dee2aaSAndroid Build Coastguard Worker     for (int y = 0; y < h; ++y) {
672*c8dee2aaSAndroid Build Coastguard Worker         for (int x = 0; x < w; ++x) {
673*c8dee2aaSAndroid Build Coastguard Worker             uint32_t expected = goldPx[y * kImageWidth + x];
674*c8dee2aaSAndroid Build Coastguard Worker             uint32_t actual = static_cast<uint32_t*>(resultPM.addr())[y * kImageWidth + x];
675*c8dee2aaSAndroid Build Coastguard Worker             if (expected != actual) {
676*c8dee2aaSAndroid Build Coastguard Worker                 ERRORF(reporter, "[%s] pixel (%i,%i): got 0x%x expected 0x%x",
677*c8dee2aaSAndroid Build Coastguard Worker                        testName, x, y, actual, expected);
678*c8dee2aaSAndroid Build Coastguard Worker                 return;
679*c8dee2aaSAndroid Build Coastguard Worker             }
680*c8dee2aaSAndroid Build Coastguard Worker         }
681*c8dee2aaSAndroid Build Coastguard Worker     }
682*c8dee2aaSAndroid Build Coastguard Worker }
683