blob: ae78c3bd6262494da4b7e124cd985a797613faf2 [file] [log] [blame]
Chris Dalton114a3c02017-05-26 15:17:19 -06001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "tests/Test.h"
Chris Dalton114a3c02017-05-26 15:17:19 -06009
Brian Salomonc7fe0f72018-05-11 10:14:21 -040010#include <array>
John Stilesfbd050b2020-08-03 13:21:46 -040011#include <memory>
Brian Salomonc7fe0f72018-05-11 10:14:21 -040012#include <vector>
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkBitmap.h"
Robert Phillips6d344c32020-07-06 10:56:46 -040014#include "include/gpu/GrDirectContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "include/private/GrResourceKey.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/gpu/GrCaps.h"
Adlai Hollera0693042020-10-14 11:23:11 -040017#include "src/gpu/GrDirectContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/gpu/GrGeometryProcessor.h"
Brian Salomonf2ebdd92019-09-30 12:15:30 -040019#include "src/gpu/GrImageInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/gpu/GrMemoryPool.h"
21#include "src/gpu/GrOpFlushState.h"
Greg Daniel2d41d0d2019-08-26 11:08:51 -040022#include "src/gpu/GrOpsRenderPass.h"
Robert Phillips901aff02019-10-08 12:32:56 -040023#include "src/gpu/GrProgramInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/gpu/GrResourceProvider.h"
Brian Salomoneebe7352020-12-09 16:37:04 -050025#include "src/gpu/GrSurfaceDrawContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050026#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
27#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
28#include "src/gpu/glsl/GrGLSLVarying.h"
29#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
Robert Phillips3968fcb2019-12-05 16:40:31 -050030#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
Chris Dalton114a3c02017-05-26 15:17:19 -060031
Chris Daltond4dec972020-04-03 11:01:30 -060032#if 0
33#include "tools/ToolUtils.h"
34#define WRITE_PNG_CONTEXT_TYPE kANGLE_D3D11_ES3_ContextType
35#endif
36
Chris Dalton114a3c02017-05-26 15:17:19 -060037GR_DECLARE_STATIC_UNIQUE_KEY(gIndexBufferKey);
38
39static constexpr int kBoxSize = 2;
40static constexpr int kBoxCountY = 8;
41static constexpr int kBoxCountX = 8;
42static constexpr int kBoxCount = kBoxCountY * kBoxCountX;
43
44static constexpr int kImageWidth = kBoxCountY * kBoxSize;
45static constexpr int kImageHeight = kBoxCountX * kBoxSize;
46
47static constexpr int kIndexPatternRepeatCount = 3;
48constexpr uint16_t kIndexPattern[6] = {0, 1, 2, 1, 2, 3};
49
50
51class DrawMeshHelper {
52public:
53 DrawMeshHelper(GrOpFlushState* state) : fState(state) {}
54
55 sk_sp<const GrBuffer> getIndexBuffer();
56
Chris Daltonbb768422020-03-12 12:13:29 -060057 sk_sp<const GrBuffer> makeIndexBuffer(const uint16_t[], int count);
58
Chris Dalton114a3c02017-05-26 15:17:19 -060059 template<typename T> sk_sp<const GrBuffer> makeVertexBuffer(const SkTArray<T>& data) {
60 return this->makeVertexBuffer(data.begin(), data.count());
61 }
Chris Dalton1d616352017-05-31 12:51:23 -060062 template<typename T> sk_sp<const GrBuffer> makeVertexBuffer(const std::vector<T>& data) {
63 return this->makeVertexBuffer(data.data(), data.size());
64 }
Chris Dalton114a3c02017-05-26 15:17:19 -060065 template<typename T> sk_sp<const GrBuffer> makeVertexBuffer(const T* data, int count);
66
Chris Daltonb8d7e002020-05-13 11:02:10 -060067 GrMeshDrawOp::Target* target() { return fState; }
Chris Dalton03fdf6a2020-04-07 12:31:59 -060068
Chris Daltonbb768422020-03-12 12:13:29 -060069 sk_sp<const GrBuffer> fIndexBuffer;
70 sk_sp<const GrBuffer> fIndexBuffer2;
71 sk_sp<const GrBuffer> fInstBuffer;
Greg Danielf793de12019-09-05 13:23:23 -040072 sk_sp<const GrBuffer> fVertBuffer;
73 sk_sp<const GrBuffer> fVertBuffer2;
Chris Dalton03fdf6a2020-04-07 12:31:59 -060074 sk_sp<const GrBuffer> fDrawIndirectBuffer;
75 size_t fDrawIndirectBufferOffset;
Greg Danielf793de12019-09-05 13:23:23 -040076
Chris Daltonbb768422020-03-12 12:13:29 -060077 GrOpsRenderPass* bindPipeline(GrPrimitiveType, bool isInstanced, bool hasVertexBuffer);
Chris Dalton114a3c02017-05-26 15:17:19 -060078
79private:
80 GrOpFlushState* fState;
81};
82
83struct Box {
84 float fX, fY;
85 GrColor fColor;
86};
87
88////////////////////////////////////////////////////////////////////////////////////////////////////
89
90/**
Chris Daltoneb694b72020-03-16 09:25:50 -060091 * This is a GPU-backend specific test. It tries to test all possible usecases of
92 * GrOpsRenderPass::draw*. The test works by drawing checkerboards of colored boxes, reading back
93 * the pixels, and comparing with expected results. The boxes are drawn on integer boundaries and
94 * the (opaque) colors are chosen from the set (r,g,b) = (0,255)^3, so the GPU renderings ought to
95 * produce exact matches.
Chris Dalton114a3c02017-05-26 15:17:19 -060096 */
97
Adlai Hollerc95b5892020-08-11 12:02:22 -040098static void run_test(GrDirectContext*, const char* testName, skiatest::Reporter*,
Brian Salomoneebe7352020-12-09 16:37:04 -050099 const std::unique_ptr<GrSurfaceDrawContext>&, const SkBitmap& gold,
Greg Danielf793de12019-09-05 13:23:23 -0400100 std::function<void(DrawMeshHelper*)> prepareFn,
101 std::function<void(DrawMeshHelper*)> executeFn);
Chris Dalton114a3c02017-05-26 15:17:19 -0600102
Chris Daltond4dec972020-04-03 11:01:30 -0600103#ifdef WRITE_PNG_CONTEXT_TYPE
104static bool IsContextTypeForOutputPNGs(skiatest::GrContextFactoryContextType type) {
105 return type == skiatest::GrContextFactoryContextType::WRITE_PNG_CONTEXT_TYPE;
106}
107DEF_GPUTEST_FOR_CONTEXTS(GrMeshTest, IsContextTypeForOutputPNGs, reporter, ctxInfo, nullptr) {
108#else
Chris Dalton114a3c02017-05-26 15:17:19 -0600109DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrMeshTest, reporter, ctxInfo) {
Chris Daltond4dec972020-04-03 11:01:30 -0600110#endif
Robert Phillipseffd13f2020-07-20 15:00:36 -0400111 auto dContext = ctxInfo.directContext();
Chris Dalton114a3c02017-05-26 15:17:19 -0600112
Brian Salomoneebe7352020-12-09 16:37:04 -0500113 auto rtc = GrSurfaceDrawContext::Make(
Robert Phillipseffd13f2020-07-20 15:00:36 -0400114 dContext, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kExact,
Greg Daniele20fcad2020-01-08 11:52:34 -0500115 {kImageWidth, kImageHeight});
Chris Dalton114a3c02017-05-26 15:17:19 -0600116 if (!rtc) {
117 ERRORF(reporter, "could not create render target context.");
118 return;
119 }
120
121 SkTArray<Box> boxes;
122 SkTArray<std::array<Box, 4>> vertexData;
123 SkBitmap gold;
124
125 // ---- setup ----------
126
127 SkPaint paint;
128 paint.setBlendMode(SkBlendMode::kSrc);
129 gold.allocN32Pixels(kImageWidth, kImageHeight);
130
131 SkCanvas goldCanvas(gold);
132
133 for (int y = 0; y < kBoxCountY; ++y) {
134 for (int x = 0; x < kBoxCountX; ++x) {
135 int c = y + x;
136 int rgb[3] = {-(c & 1) & 0xff, -((c >> 1) & 1) & 0xff, -((c >> 2) & 1) & 0xff};
137
138 const Box box = boxes.push_back() = {
Brian Salomon23356442018-11-30 15:33:19 -0500139 float(x * kBoxSize),
140 float(y * kBoxSize),
141 GrColorPackRGBA(rgb[0], rgb[1], rgb[2], 255)
Chris Dalton114a3c02017-05-26 15:17:19 -0600142 };
143
144 std::array<Box, 4>& boxVertices = vertexData.push_back();
145 for (int i = 0; i < 4; ++i) {
146 boxVertices[i] = {
Brian Salomon23356442018-11-30 15:33:19 -0500147 box.fX + (i / 2) * kBoxSize,
148 box.fY + (i % 2) * kBoxSize,
149 box.fColor
Chris Dalton114a3c02017-05-26 15:17:19 -0600150 };
151 }
152
153 paint.setARGB(255, rgb[0], rgb[1], rgb[2]);
154 goldCanvas.drawRect(SkRect::MakeXYWH(box.fX, box.fY, kBoxSize, kBoxSize), paint);
155 }
156 }
157
Chris Dalton114a3c02017-05-26 15:17:19 -0600158 // ---- tests ----------
159
Brian Salomon23356442018-11-30 15:33:19 -0500160#define VALIDATE(buff) \
161 do { \
162 if (!buff) { \
163 ERRORF(reporter, #buff " is null."); \
164 return; \
165 } \
166 } while (0)
Chris Dalton114a3c02017-05-26 15:17:19 -0600167
Robert Phillipseffd13f2020-07-20 15:00:36 -0400168 run_test(dContext, "draw", reporter, rtc, gold,
Robert Phillips88a32ef2018-06-07 11:05:56 -0400169 [&](DrawMeshHelper* helper) {
170 SkTArray<Box> expandedVertexData;
171 for (int i = 0; i < kBoxCount; ++i) {
172 for (int j = 0; j < 6; ++j) {
173 expandedVertexData.push_back(vertexData[i][kIndexPattern[j]]);
174 }
175 }
Chris Dalton114a3c02017-05-26 15:17:19 -0600176
Robert Phillips88a32ef2018-06-07 11:05:56 -0400177 // Draw boxes one line at a time to exercise base vertex.
Greg Danielf793de12019-09-05 13:23:23 -0400178 helper->fVertBuffer = helper->makeVertexBuffer(expandedVertexData);
179 VALIDATE(helper->fVertBuffer);
180 },
181 [&](DrawMeshHelper* helper) {
Robert Phillips88a32ef2018-06-07 11:05:56 -0400182 for (int y = 0; y < kBoxCountY; ++y) {
Chris Daltonbb768422020-03-12 12:13:29 -0600183 auto pass = helper->bindPipeline(GrPrimitiveType::kTriangles, false, true);
Greg Daniel426274b2020-07-20 11:37:38 -0400184 pass->bindBuffers(nullptr, nullptr, helper->fVertBuffer);
Chris Daltonbb768422020-03-12 12:13:29 -0600185 pass->draw(kBoxCountX * 6, y * kBoxCountX * 6);
Robert Phillips88a32ef2018-06-07 11:05:56 -0400186 }
187 });
Chris Dalton114a3c02017-05-26 15:17:19 -0600188
Robert Phillipseffd13f2020-07-20 15:00:36 -0400189 run_test(dContext, "drawIndexed", reporter, rtc, gold,
Greg Danielf793de12019-09-05 13:23:23 -0400190 [&](DrawMeshHelper* helper) {
191 helper->fIndexBuffer = helper->getIndexBuffer();
192 VALIDATE(helper->fIndexBuffer);
193 helper->fVertBuffer = helper->makeVertexBuffer(vertexData);
194 VALIDATE(helper->fVertBuffer);
195 },
196 [&](DrawMeshHelper* helper) {
197 int baseRepetition = 0;
198 int i = 0;
199 // Start at various repetitions within the patterned index buffer to exercise base
200 // index.
201 while (i < kBoxCount) {
Brian Salomon4dea72a2019-12-18 10:43:10 -0500202 static_assert(kIndexPatternRepeatCount >= 3);
Brian Osman788b9162020-02-07 10:36:46 -0500203 int repetitionCount = std::min(3 - baseRepetition, kBoxCount - i);
Chris Dalton114a3c02017-05-26 15:17:19 -0600204
Chris Daltonbb768422020-03-12 12:13:29 -0600205 auto pass = helper->bindPipeline(GrPrimitiveType::kTriangles, false, true);
Greg Daniel426274b2020-07-20 11:37:38 -0400206 pass->bindBuffers(helper->fIndexBuffer, nullptr, helper->fVertBuffer);
Chris Daltonbb768422020-03-12 12:13:29 -0600207 pass->drawIndexed(repetitionCount * 6, baseRepetition * 6, baseRepetition * 4,
208 (baseRepetition + repetitionCount) * 4 - 1,
209 (i - baseRepetition) * 4);
Chris Dalton114a3c02017-05-26 15:17:19 -0600210
Greg Danielf793de12019-09-05 13:23:23 -0400211 baseRepetition = (baseRepetition + 1) % 3;
212 i += repetitionCount;
213 }
214 });
Chris Dalton114a3c02017-05-26 15:17:19 -0600215
Robert Phillipseffd13f2020-07-20 15:00:36 -0400216 run_test(dContext, "drawIndexPattern", reporter, rtc, gold,
Greg Danielf793de12019-09-05 13:23:23 -0400217 [&](DrawMeshHelper* helper) {
218 helper->fIndexBuffer = helper->getIndexBuffer();
219 VALIDATE(helper->fIndexBuffer);
220 helper->fVertBuffer = helper->makeVertexBuffer(vertexData);
221 VALIDATE(helper->fVertBuffer);
222 },
223 [&](DrawMeshHelper* helper) {
Chris Daltonbb768422020-03-12 12:13:29 -0600224 // Draw boxes one line at a time to exercise base vertex. drawIndexPattern does
Greg Danielf793de12019-09-05 13:23:23 -0400225 // not support a base index.
226 for (int y = 0; y < kBoxCountY; ++y) {
Chris Daltonbb768422020-03-12 12:13:29 -0600227 auto pass = helper->bindPipeline(GrPrimitiveType::kTriangles, false, true);
Greg Daniel426274b2020-07-20 11:37:38 -0400228 pass->bindBuffers(helper->fIndexBuffer, nullptr, helper->fVertBuffer);
Chris Daltonbb768422020-03-12 12:13:29 -0600229 pass->drawIndexPattern(6, kBoxCountX, kIndexPatternRepeatCount, 4,
230 y * kBoxCountX * 4);
231
Greg Danielf793de12019-09-05 13:23:23 -0400232 }
233 });
Chris Dalton1d616352017-05-31 12:51:23 -0600234
235 for (bool indexed : {false, true}) {
Robert Phillipseffd13f2020-07-20 15:00:36 -0400236 if (!dContext->priv().caps()->drawInstancedSupport()) {
Chris Dalton1d616352017-05-31 12:51:23 -0600237 break;
238 }
239
Robert Phillipseffd13f2020-07-20 15:00:36 -0400240 run_test(dContext, indexed ? "drawIndexedInstanced" : "drawInstanced",
Greg Danielf793de12019-09-05 13:23:23 -0400241 reporter, rtc, gold,
242 [&](DrawMeshHelper* helper) {
243 helper->fIndexBuffer = indexed ? helper->getIndexBuffer() : nullptr;
Chris Daltonbb768422020-03-12 12:13:29 -0600244 SkTArray<uint16_t> baseIndexData;
245 baseIndexData.push_back(kBoxCountX/2 * 6); // for testing base index.
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600246 for (int i = 0; i < 6; ++i) {
247 baseIndexData.push_back(kIndexPattern[i]);
Chris Daltonbb768422020-03-12 12:13:29 -0600248 }
249 helper->fIndexBuffer2 = helper->makeIndexBuffer(baseIndexData.begin(),
250 baseIndexData.count());
Greg Danielf793de12019-09-05 13:23:23 -0400251 helper->fInstBuffer = helper->makeVertexBuffer(boxes);
252 VALIDATE(helper->fInstBuffer);
253 helper->fVertBuffer =
254 helper->makeVertexBuffer(std::vector<float>{0,0, 0,1, 1,0, 1,1});
255 VALIDATE(helper->fVertBuffer);
256 helper->fVertBuffer2 = helper->makeVertexBuffer( // for testing base vertex.
257 std::vector<float>{-1,-1, -1,-1, 0,0, 0,1, 1,0, 1,1});
258 VALIDATE(helper->fVertBuffer2);
259 },
260 [&](DrawMeshHelper* helper) {
261 // Draw boxes one line at a time to exercise base instance, base vertex, and
Chris Daltonbb768422020-03-12 12:13:29 -0600262 // null vertex buffer.
Greg Danielf793de12019-09-05 13:23:23 -0400263 for (int y = 0; y < kBoxCountY; ++y) {
Greg Daniel426274b2020-07-20 11:37:38 -0400264 sk_sp<const GrBuffer> vertexBuffer;
Chris Daltonbb768422020-03-12 12:13:29 -0600265 int baseVertex = 0;
Greg Danielf793de12019-09-05 13:23:23 -0400266 switch (y % 3) {
267 case 0:
Robert Phillipseffd13f2020-07-20 15:00:36 -0400268 if (dContext->priv().caps()->shaderCaps()->vertexIDSupport()) {
Greg Danielf793de12019-09-05 13:23:23 -0400269 break;
270 }
John Stiles30212b72020-06-11 17:55:07 -0400271 [[fallthrough]];
Greg Danielf793de12019-09-05 13:23:23 -0400272 case 1:
Greg Daniel426274b2020-07-20 11:37:38 -0400273 vertexBuffer = helper->fVertBuffer;
Greg Danielf793de12019-09-05 13:23:23 -0400274 break;
275 case 2:
Greg Daniel426274b2020-07-20 11:37:38 -0400276 vertexBuffer = helper->fVertBuffer2;
Chris Daltonbb768422020-03-12 12:13:29 -0600277 baseVertex = 2;
Greg Danielf793de12019-09-05 13:23:23 -0400278 break;
279 }
Chris Daltonbb768422020-03-12 12:13:29 -0600280
281 GrPrimitiveType primitiveType = indexed ? GrPrimitiveType::kTriangles
282 : GrPrimitiveType::kTriangleStrip;
283 auto pass = helper->bindPipeline(primitiveType, true,
284 SkToBool(vertexBuffer));
285 if (indexed) {
Greg Daniel426274b2020-07-20 11:37:38 -0400286 sk_sp<const GrBuffer> indexBuffer = (y % 2) ?
287 helper->fIndexBuffer2 : helper->fIndexBuffer;
Chris Daltonbb768422020-03-12 12:13:29 -0600288 VALIDATE(indexBuffer);
289 int baseIndex = (y % 2);
Greg Daniel426274b2020-07-20 11:37:38 -0400290 pass->bindBuffers(std::move(indexBuffer), helper->fInstBuffer,
291 std::move(vertexBuffer));
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600292 pass->drawIndexedInstanced(6, baseIndex, kBoxCountX, y * kBoxCountX,
Chris Daltonbb768422020-03-12 12:13:29 -0600293 baseVertex);
294 } else {
Greg Daniel426274b2020-07-20 11:37:38 -0400295 pass->bindBuffers(nullptr, helper->fInstBuffer,
296 std::move(vertexBuffer));
Chris Daltonbb768422020-03-12 12:13:29 -0600297 pass->drawInstanced(kBoxCountX, y * kBoxCountY, 4, baseVertex);
298 }
Greg Danielf793de12019-09-05 13:23:23 -0400299 }
300 });
Chris Dalton1d616352017-05-31 12:51:23 -0600301 }
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600302
303 for (bool indexed : {false, true}) {
Robert Phillipseffd13f2020-07-20 15:00:36 -0400304 if (!dContext->priv().caps()->drawInstancedSupport()) {
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600305 break;
306 }
307
Robert Phillipseffd13f2020-07-20 15:00:36 -0400308 run_test(dContext, (indexed) ? "drawIndexedIndirect" : "drawIndirect",
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600309 reporter, rtc, gold,
310 [&](DrawMeshHelper* helper) {
311 SkTArray<uint16_t> baseIndexData;
312 baseIndexData.push_back(kBoxCountX/2 * 6); // for testing base index.
313 for (int j = 0; j < kBoxCountY; ++j) {
314 for (int i = 0; i < 6; ++i) {
315 baseIndexData.push_back(kIndexPattern[i]);
316 }
317 }
318 helper->fIndexBuffer2 = helper->makeIndexBuffer(baseIndexData.begin(),
319 baseIndexData.count());
320 VALIDATE(helper->fIndexBuffer2);
321 helper->fInstBuffer = helper->makeVertexBuffer(boxes);
322 VALIDATE(helper->fInstBuffer);
323 helper->fVertBuffer = helper->makeVertexBuffer(std::vector<float>{
324 -1,-1, 0,0, 0,1, 1,0, 1,1, -1,-1, 0,0, 1,0, 0,1, 1,1});
325 VALIDATE(helper->fVertBuffer);
326
Chris Daltona6a3d052021-02-07 20:56:36 -0700327 GrDrawIndirectWriter indirectWriter;
328 GrDrawIndexedIndirectWriter indexedIndirectWriter;
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600329 if (indexed) {
330 // Make helper->fDrawIndirectBufferOffset nonzero.
331 sk_sp<const GrBuffer> dummyBuff;
332 size_t dummyOffset;
Chris Daltonb8d7e002020-05-13 11:02:10 -0600333 // Make a superfluous call to makeDrawIndirectSpace in order to test
334 // "offsetInBytes!=0" for the actual call to makeDrawIndexedIndirectSpace.
335 helper->target()->makeDrawIndirectSpace(29, &dummyBuff, &dummyOffset);
Chris Daltona6a3d052021-02-07 20:56:36 -0700336 indexedIndirectWriter = helper->target()->makeDrawIndexedIndirectSpace(
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600337 kBoxCountY, &helper->fDrawIndirectBuffer,
338 &helper->fDrawIndirectBufferOffset);
339 } else {
340 // Make helper->fDrawIndirectBufferOffset nonzero.
341 sk_sp<const GrBuffer> dummyBuff;
342 size_t dummyOffset;
Chris Daltonb8d7e002020-05-13 11:02:10 -0600343 // Make a superfluous call to makeDrawIndexedIndirectSpace in order to test
344 // "offsetInBytes!=0" for the actual call to makeDrawIndirectSpace.
Chris Daltona6a3d052021-02-07 20:56:36 -0700345 helper->target()->makeDrawIndexedIndirectSpace(7, &dummyBuff,
346 &dummyOffset);
347 indirectWriter = helper->target()->makeDrawIndirectSpace(
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600348 kBoxCountY, &helper->fDrawIndirectBuffer,
349 &helper->fDrawIndirectBufferOffset);
350 }
351
352 // Draw boxes one line at a time to exercise multiple draws.
353 for (int y = 0; y < kBoxCountY; ++y) {
354 int baseVertex = (y % 2) ? 1 : 6;
355 if (indexed) {
356 int baseIndex = 1 + y * 6;
Chris Daltona6a3d052021-02-07 20:56:36 -0700357 indexedIndirectWriter.writeIndexed(6, baseIndex, kBoxCountX,
Chris Daltonb849f7a2021-02-10 12:55:48 -0700358 y * kBoxCountX, baseVertex);
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600359 } else {
Chris Daltonb849f7a2021-02-10 12:55:48 -0700360 indirectWriter.write(kBoxCountX, y * kBoxCountX, 4, baseVertex);
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600361 }
362 }
363 },
364 [&](DrawMeshHelper* helper) {
365 GrOpsRenderPass* pass;
366 if (indexed) {
367 pass = helper->bindPipeline(GrPrimitiveType::kTriangles, true, true);
Greg Daniel426274b2020-07-20 11:37:38 -0400368 pass->bindBuffers(helper->fIndexBuffer2, helper->fInstBuffer,
369 helper->fVertBuffer);
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600370 for (int i = 0; i < 3; ++i) {
371 int start = kBoxCountY * i / 3;
372 int end = kBoxCountY * (i + 1) / 3;
373 size_t offset = helper->fDrawIndirectBufferOffset + start *
374 sizeof(GrDrawIndexedIndirectCommand);
375 pass->drawIndexedIndirect(helper->fDrawIndirectBuffer.get(), offset,
376 end - start);
377 }
378 } else {
379 pass = helper->bindPipeline(GrPrimitiveType::kTriangleStrip, true, true);
Greg Daniel426274b2020-07-20 11:37:38 -0400380 pass->bindBuffers(nullptr, helper->fInstBuffer, helper->fVertBuffer);
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600381 for (int i = 0; i < 2; ++i) {
382 int start = kBoxCountY * i / 2;
383 int end = kBoxCountY * (i + 1) / 2;
384 size_t offset = helper->fDrawIndirectBufferOffset + start *
385 sizeof(GrDrawIndirectCommand);
386 pass->drawIndirect(helper->fDrawIndirectBuffer.get(), offset,
387 end - start);
388 }
389 }
390 });
391 }
Chris Dalton114a3c02017-05-26 15:17:19 -0600392}
393
394////////////////////////////////////////////////////////////////////////////////////////////////////
395
396class GrMeshTestOp : public GrDrawOp {
397public:
398 DEFINE_OP_CLASS_ID
399
Herb Derbyc76d4092020-10-07 16:46:15 -0400400 static GrOp::Owner Make(GrRecordingContext* rContext,
401 std::function<void(DrawMeshHelper*)> prepareFn,
402 std::function<void(DrawMeshHelper*)> executeFn) {
403 return GrOp::Make<GrMeshTestOp>(rContext, prepareFn, executeFn);
Robert Phillips88a32ef2018-06-07 11:05:56 -0400404 }
405
406private:
Herb Derbyc76d4092020-10-07 16:46:15 -0400407 friend class GrOp; // for ctor
Robert Phillips7c525e62018-06-12 10:11:12 -0400408
Greg Danielf793de12019-09-05 13:23:23 -0400409 GrMeshTestOp(std::function<void(DrawMeshHelper*)> prepareFn,
410 std::function<void(DrawMeshHelper*)> executeFn)
Chris Dalton114a3c02017-05-26 15:17:19 -0600411 : INHERITED(ClassID())
Greg Danielf793de12019-09-05 13:23:23 -0400412 , fPrepareFn(prepareFn)
413 , fExecuteFn(executeFn){
Chris Dalton114a3c02017-05-26 15:17:19 -0600414 this->setBounds(SkRect::MakeIWH(kImageWidth, kImageHeight),
Greg Daniel5faf4742019-10-01 15:14:44 -0400415 HasAABloat::kNo, IsHairline::kNo);
Chris Dalton114a3c02017-05-26 15:17:19 -0600416 }
417
Chris Dalton114a3c02017-05-26 15:17:19 -0600418 const char* name() const override { return "GrMeshTestOp"; }
419 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
Chris Dalton6ce447a2019-06-23 18:07:38 -0600420 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
421 bool hasMixedSampledCoverage, GrClampType) override {
Chris Dalton4b62aed2019-01-15 11:53:00 -0700422 return GrProcessorSet::EmptySetAnalysis();
Brian Salomonf86d37b2017-06-16 10:04:34 -0400423 }
Robert Phillipsc655c3a2020-03-18 13:23:45 -0400424
425 void onPrePrepare(GrRecordingContext*,
Adlai Hollere2296f72020-11-19 13:41:26 -0500426 const GrSurfaceProxyView& writeView,
Robert Phillipsc655c3a2020-03-18 13:23:45 -0400427 GrAppliedClip*,
Greg Danield358cbe2020-09-11 09:33:54 -0400428 const GrXferProcessor::DstProxyView&,
Greg Daniel42dbca52020-11-20 10:22:43 -0500429 GrXferBarrierFlags renderPassXferBarriers,
430 GrLoadOp colorLoadOp) override {}
Greg Danielf793de12019-09-05 13:23:23 -0400431 void onPrepare(GrOpFlushState* state) override {
John Stilesfbd050b2020-08-03 13:21:46 -0400432 fHelper = std::make_unique<DrawMeshHelper>(state);
Greg Danielf793de12019-09-05 13:23:23 -0400433 fPrepareFn(fHelper.get());
434 }
Brian Salomon588cec72018-11-14 13:56:37 -0500435 void onExecute(GrOpFlushState* state, const SkRect& chainBounds) override {
Greg Danielf793de12019-09-05 13:23:23 -0400436 fExecuteFn(fHelper.get());
Chris Dalton114a3c02017-05-26 15:17:19 -0600437 }
438
Greg Danielf793de12019-09-05 13:23:23 -0400439 std::unique_ptr<DrawMeshHelper> fHelper;
440 std::function<void(DrawMeshHelper*)> fPrepareFn;
441 std::function<void(DrawMeshHelper*)> fExecuteFn;
Chris Dalton114a3c02017-05-26 15:17:19 -0600442
John Stiles7571f9e2020-09-02 22:42:33 -0400443 using INHERITED = GrDrawOp;
Chris Dalton114a3c02017-05-26 15:17:19 -0600444};
445
446class GrMeshTestProcessor : public GrGeometryProcessor {
447public:
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500448 static GrGeometryProcessor* Make(SkArenaAlloc* arena, bool instanced, bool hasVertexBuffer) {
Mike Kleinf1241082020-12-14 15:59:09 -0600449 return arena->make([&](void* ptr) {
450 return new (ptr) GrMeshTestProcessor(instanced, hasVertexBuffer);
451 });
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500452 }
453
454 const char* name() const override { return "GrMeshTestProcessor"; }
455
456 const Attribute& inColor() const {
457 return fVertexColor.isInitialized() ? fVertexColor : fInstanceColor;
458 }
459
460 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
461 b->add32(fInstanceLocation.isInitialized());
462 b->add32(fVertexPosition.isInitialized());
463 }
464
465 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
466
467private:
468 friend class GLSLMeshTestProcessor;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500469
Chris Dalton1d616352017-05-31 12:51:23 -0600470 GrMeshTestProcessor(bool instanced, bool hasVertexBuffer)
Brian Salomon92be2f72018-06-19 14:33:47 -0400471 : INHERITED(kGrMeshTestProcessor_ClassID) {
Chris Dalton1d616352017-05-31 12:51:23 -0600472 if (instanced) {
Brian Osmand4c29702018-09-14 16:16:55 -0400473 fInstanceLocation = {"location", kFloat2_GrVertexAttribType, kHalf2_GrSLType};
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500474 fInstanceColor = {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
475 this->setInstanceAttributes(&fInstanceLocation, 2);
Chris Dalton1d616352017-05-31 12:51:23 -0600476 if (hasVertexBuffer) {
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500477 fVertexPosition = {"vertex", kFloat2_GrVertexAttribType, kHalf2_GrSLType};
478 this->setVertexAttributes(&fVertexPosition, 1);
Chris Dalton1d616352017-05-31 12:51:23 -0600479 }
Chris Dalton1d616352017-05-31 12:51:23 -0600480 } else {
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500481 fVertexPosition = {"vertex", kFloat2_GrVertexAttribType, kHalf2_GrSLType};
482 fVertexColor = {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
483 this->setVertexAttributes(&fVertexPosition, 2);
Chris Dalton1d616352017-05-31 12:51:23 -0600484 }
Chris Dalton114a3c02017-05-26 15:17:19 -0600485 }
486
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500487 Attribute fVertexPosition;
488 Attribute fVertexColor;
Brian Salomon92be2f72018-06-19 14:33:47 -0400489
490 Attribute fInstanceLocation;
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500491 Attribute fInstanceColor;
Chris Dalton114a3c02017-05-26 15:17:19 -0600492
John Stiles7571f9e2020-09-02 22:42:33 -0400493 using INHERITED = GrGeometryProcessor;
Chris Dalton114a3c02017-05-26 15:17:19 -0600494};
495
496class GLSLMeshTestProcessor : public GrGLSLGeometryProcessor {
Brian Osman609f1592020-07-01 15:14:39 -0400497 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&) final {}
Chris Dalton114a3c02017-05-26 15:17:19 -0600498
499 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final {
500 const GrMeshTestProcessor& mp = args.fGP.cast<GrMeshTestProcessor>();
501
502 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
503 varyingHandler->emitAttributes(mp);
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500504 varyingHandler->addPassThroughAttribute(mp.inColor(), args.fOutputColor);
Chris Dalton114a3c02017-05-26 15:17:19 -0600505
506 GrGLSLVertexBuilder* v = args.fVertBuilder;
Brian Salomon92be2f72018-06-19 14:33:47 -0400507 if (!mp.fInstanceLocation.isInitialized()) {
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500508 v->codeAppendf("float2 vertex = %s;", mp.fVertexPosition.name());
Chris Dalton1d616352017-05-31 12:51:23 -0600509 } else {
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500510 if (mp.fVertexPosition.isInitialized()) {
511 v->codeAppendf("float2 offset = %s;", mp.fVertexPosition.name());
Chris Dalton1d616352017-05-31 12:51:23 -0600512 } else {
John Stilesaf9b58e2021-01-13 17:48:36 -0500513 v->codeAppend("float2 offset = float2(sk_VertexID / 2, sk_VertexID % 2);");
Chris Dalton1d616352017-05-31 12:51:23 -0600514 }
Brian Salomon92be2f72018-06-19 14:33:47 -0400515 v->codeAppendf("float2 vertex = %s + offset * %i;", mp.fInstanceLocation.name(),
Brian Salomon70132d02018-05-29 15:33:06 -0400516 kBoxSize);
Chris Dalton1d616352017-05-31 12:51:23 -0600517 }
Ethan Nicholas8aa45692017-09-20 11:24:15 -0400518 gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex");
Chris Dalton114a3c02017-05-26 15:17:19 -0600519
Chris Dalton60283612018-02-14 13:38:14 -0700520 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400521 f->codeAppendf("%s = half4(1);", args.fOutputCoverage);
Chris Dalton114a3c02017-05-26 15:17:19 -0600522 }
523};
524
525GrGLSLPrimitiveProcessor* GrMeshTestProcessor::createGLSLInstance(const GrShaderCaps&) const {
526 return new GLSLMeshTestProcessor;
527}
528
529////////////////////////////////////////////////////////////////////////////////////////////////////
530
Chris Daltonbb768422020-03-12 12:13:29 -0600531sk_sp<const GrBuffer> DrawMeshHelper::makeIndexBuffer(const uint16_t indices[], int count) {
532 return sk_sp<const GrBuffer>(fState->resourceProvider()->createBuffer(
533 count * sizeof(uint16_t), GrGpuBufferType::kIndex, kDynamic_GrAccessPattern, indices));
534}
535
Chris Dalton114a3c02017-05-26 15:17:19 -0600536template<typename T>
537sk_sp<const GrBuffer> DrawMeshHelper::makeVertexBuffer(const T* data, int count) {
Brian Salomonae64c192019-02-05 09:41:37 -0500538 return sk_sp<const GrBuffer>(fState->resourceProvider()->createBuffer(
Brian Salomondbf70722019-02-07 11:31:24 -0500539 count * sizeof(T), GrGpuBufferType::kVertex, kDynamic_GrAccessPattern, data));
Chris Dalton114a3c02017-05-26 15:17:19 -0600540}
541
542sk_sp<const GrBuffer> DrawMeshHelper::getIndexBuffer() {
543 GR_DEFINE_STATIC_UNIQUE_KEY(gIndexBufferKey);
Brian Salomond28a79d2017-10-16 13:01:07 -0400544 return fState->resourceProvider()->findOrCreatePatternedIndexBuffer(
545 kIndexPattern, 6, kIndexPatternRepeatCount, 4, gIndexBufferKey);
Chris Dalton114a3c02017-05-26 15:17:19 -0600546}
547
Chris Daltonbb768422020-03-12 12:13:29 -0600548GrOpsRenderPass* DrawMeshHelper::bindPipeline(GrPrimitiveType primitiveType, bool isInstanced,
549 bool hasVertexBuffer) {
Robert Phillips3968fcb2019-12-05 16:40:31 -0500550 GrProcessorSet processorSet(SkBlendMode::kSrc);
551
552 // TODO: add a GrProcessorSet testing helper to make this easier
553 SkPMColor4f overrideColor;
554 processorSet.finalize(GrProcessorAnalysisColor(),
555 GrProcessorAnalysisCoverage::kNone,
556 fState->appliedClip(),
557 nullptr,
558 false,
559 fState->caps(),
560 GrClampType::kAuto,
561 &overrideColor);
562
563 auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(fState,
564 std::move(processorSet),
565 GrPipeline::InputFlags::kNone);
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500566
Chris Daltonbb768422020-03-12 12:13:29 -0600567 GrGeometryProcessor* mtp = GrMeshTestProcessor::Make(fState->allocator(), isInstanced,
568 hasVertexBuffer);
Robert Phillips901aff02019-10-08 12:32:56 -0400569
Robert Phillips5c809642020-11-20 12:28:45 -0500570 GrProgramInfo programInfo(fState->writeView(), pipeline, &GrUserStencilSettings::kUnused,
571 mtp, primitiveType, 0, fState->renderPassBarriers(),
572 fState->colorLoadOp());
Robert Phillips901aff02019-10-08 12:32:56 -0400573
Chris Dalton4386ad12020-02-19 16:42:06 -0700574 fState->opsRenderPass()->bindPipeline(programInfo, SkRect::MakeIWH(kImageWidth, kImageHeight));
Chris Daltonbb768422020-03-12 12:13:29 -0600575 return fState->opsRenderPass();
Chris Dalton114a3c02017-05-26 15:17:19 -0600576}
577
Adlai Hollerc95b5892020-08-11 12:02:22 -0400578static void run_test(GrDirectContext* dContext, const char* testName,
Robert Phillipseffd13f2020-07-20 15:00:36 -0400579 skiatest::Reporter* reporter,
Brian Salomoneebe7352020-12-09 16:37:04 -0500580 const std::unique_ptr<GrSurfaceDrawContext>& rtc, const SkBitmap& gold,
Greg Danielf793de12019-09-05 13:23:23 -0400581 std::function<void(DrawMeshHelper*)> prepareFn,
582 std::function<void(DrawMeshHelper*)> executeFn) {
Brian Salomondd4087d2020-12-23 20:36:44 -0500583 const int w = gold.width(), h = gold.height();
Chris Dalton114a3c02017-05-26 15:17:19 -0600584 const uint32_t* goldPx = reinterpret_cast<const uint32_t*>(gold.getPixels());
585 if (h != rtc->height() || w != rtc->width()) {
586 ERRORF(reporter, "[%s] expectation and rtc not compatible (?).", testName);
587 return;
588 }
589 if (sizeof(uint32_t) * kImageWidth != gold.rowBytes()) {
Adlai Holler684838f2020-05-12 10:41:04 -0400590 ERRORF(reporter, "[%s] unexpected row bytes in gold image", testName);
Chris Dalton114a3c02017-05-26 15:17:19 -0600591 return;
592 }
593
Brian Salomonbe1084b2021-01-26 13:29:30 -0500594 GrPixmap resultPM = GrPixmap::Allocate(gold.info());
Michael Ludwig81d41722020-05-26 16:57:38 -0400595 rtc->clear(SkPMColor4f::FromBytes_RGBA(0xbaaaaaad));
Brian Salomon70fe17e2020-11-30 14:33:58 -0500596 rtc->addDrawOp(GrMeshTestOp::Make(dContext, prepareFn, executeFn));
Chris Daltond4dec972020-04-03 11:01:30 -0600597
Brian Salomondd4087d2020-12-23 20:36:44 -0500598 rtc->readPixels(dContext, resultPM, {0, 0});
Chris Daltond4dec972020-04-03 11:01:30 -0600599
600#ifdef WRITE_PNG_CONTEXT_TYPE
601#define STRINGIFY(X) #X
602#define TOSTRING(X) STRINGIFY(X)
603 SkString filename;
604 filename.printf("GrMeshTest_%s_%s.png", TOSTRING(WRITE_PNG_CONTEXT_TYPE), testName);
605 SkDebugf("writing %s...\n", filename.c_str());
Brian Salomondd4087d2020-12-23 20:36:44 -0500606 ToolUtils::EncodeImageToFile(filename.c_str(), resultPM, SkEncodedImageFormat::kPNG, 100);
Chris Daltond4dec972020-04-03 11:01:30 -0600607#endif
608
Chris Dalton114a3c02017-05-26 15:17:19 -0600609 for (int y = 0; y < h; ++y) {
610 for (int x = 0; x < w; ++x) {
611 uint32_t expected = goldPx[y * kImageWidth + x];
Brian Salomondd4087d2020-12-23 20:36:44 -0500612 uint32_t actual = static_cast<uint32_t*>(resultPM.addr())[y * kImageWidth + x];
Chris Dalton114a3c02017-05-26 15:17:19 -0600613 if (expected != actual) {
614 ERRORF(reporter, "[%s] pixel (%i,%i): got 0x%x expected 0x%x",
615 testName, x, y, actual, expected);
616 return;
617 }
618 }
619 }
620}