blob: 3b39cd7a4506c115037c2150ce92ec40753d6ca3 [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>
11#include <vector>
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkBitmap.h"
13#include "include/gpu/GrContext.h"
14#include "include/private/GrResourceKey.h"
15#include "src/core/SkMakeUnique.h"
16#include "src/gpu/GrCaps.h"
17#include "src/gpu/GrContextPriv.h"
18#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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "src/gpu/GrRenderTargetContext.h"
24#include "src/gpu/GrRenderTargetContextPriv.h"
25#include "src/gpu/GrResourceProvider.h"
26#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"
Chris Dalton114a3c02017-05-26 15:17:19 -060030
31GR_DECLARE_STATIC_UNIQUE_KEY(gIndexBufferKey);
32
33static constexpr int kBoxSize = 2;
34static constexpr int kBoxCountY = 8;
35static constexpr int kBoxCountX = 8;
36static constexpr int kBoxCount = kBoxCountY * kBoxCountX;
37
38static constexpr int kImageWidth = kBoxCountY * kBoxSize;
39static constexpr int kImageHeight = kBoxCountX * kBoxSize;
40
41static constexpr int kIndexPatternRepeatCount = 3;
42constexpr uint16_t kIndexPattern[6] = {0, 1, 2, 1, 2, 3};
43
44
45class DrawMeshHelper {
46public:
47 DrawMeshHelper(GrOpFlushState* state) : fState(state) {}
48
49 sk_sp<const GrBuffer> getIndexBuffer();
50
51 template<typename T> sk_sp<const GrBuffer> makeVertexBuffer(const SkTArray<T>& data) {
52 return this->makeVertexBuffer(data.begin(), data.count());
53 }
Chris Dalton1d616352017-05-31 12:51:23 -060054 template<typename T> sk_sp<const GrBuffer> makeVertexBuffer(const std::vector<T>& data) {
55 return this->makeVertexBuffer(data.data(), data.size());
56 }
Chris Dalton114a3c02017-05-26 15:17:19 -060057 template<typename T> sk_sp<const GrBuffer> makeVertexBuffer(const T* data, int count);
58
Greg Danielf793de12019-09-05 13:23:23 -040059 sk_sp<const GrBuffer> fVertBuffer;
60 sk_sp<const GrBuffer> fVertBuffer2;
61 sk_sp<const GrBuffer> fIndexBuffer;
62 sk_sp<const GrBuffer> fInstBuffer;
63
Chris Dalton114a3c02017-05-26 15:17:19 -060064 void drawMesh(const GrMesh& mesh);
65
66private:
67 GrOpFlushState* fState;
68};
69
70struct Box {
71 float fX, fY;
72 GrColor fColor;
73};
74
75////////////////////////////////////////////////////////////////////////////////////////////////////
76
77/**
78 * This is a GPU-backend specific test. It tries to test all possible usecases of GrMesh. The test
79 * works by drawing checkerboards of colored boxes, reading back the pixels, and comparing with
80 * expected results. The boxes are drawn on integer boundaries and the (opaque) colors are chosen
81 * from the set (r,g,b) = (0,255)^3, so the GPU renderings ought to produce exact matches.
82 */
83
Robert Phillips88a32ef2018-06-07 11:05:56 -040084static void run_test(GrContext* context, const char* testName, skiatest::Reporter*,
Brian Salomonbf6b9792019-08-21 09:38:10 -040085 const std::unique_ptr<GrRenderTargetContext>&, const SkBitmap& gold,
Greg Danielf793de12019-09-05 13:23:23 -040086 std::function<void(DrawMeshHelper*)> prepareFn,
87 std::function<void(DrawMeshHelper*)> executeFn);
Chris Dalton114a3c02017-05-26 15:17:19 -060088
89DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrMeshTest, reporter, ctxInfo) {
Robert Phillips88a32ef2018-06-07 11:05:56 -040090 GrContext* context = ctxInfo.grContext();
Chris Dalton114a3c02017-05-26 15:17:19 -060091
Brian Salomonbf6b9792019-08-21 09:38:10 -040092 auto rtc = context->priv().makeDeferredRenderTargetContext(
93 SkBackingFit::kExact, kImageWidth, kImageHeight, GrColorType::kRGBA_8888, nullptr);
Chris Dalton114a3c02017-05-26 15:17:19 -060094 if (!rtc) {
95 ERRORF(reporter, "could not create render target context.");
96 return;
97 }
98
99 SkTArray<Box> boxes;
100 SkTArray<std::array<Box, 4>> vertexData;
101 SkBitmap gold;
102
103 // ---- setup ----------
104
105 SkPaint paint;
106 paint.setBlendMode(SkBlendMode::kSrc);
107 gold.allocN32Pixels(kImageWidth, kImageHeight);
108
109 SkCanvas goldCanvas(gold);
110
111 for (int y = 0; y < kBoxCountY; ++y) {
112 for (int x = 0; x < kBoxCountX; ++x) {
113 int c = y + x;
114 int rgb[3] = {-(c & 1) & 0xff, -((c >> 1) & 1) & 0xff, -((c >> 2) & 1) & 0xff};
115
116 const Box box = boxes.push_back() = {
Brian Salomon23356442018-11-30 15:33:19 -0500117 float(x * kBoxSize),
118 float(y * kBoxSize),
119 GrColorPackRGBA(rgb[0], rgb[1], rgb[2], 255)
Chris Dalton114a3c02017-05-26 15:17:19 -0600120 };
121
122 std::array<Box, 4>& boxVertices = vertexData.push_back();
123 for (int i = 0; i < 4; ++i) {
124 boxVertices[i] = {
Brian Salomon23356442018-11-30 15:33:19 -0500125 box.fX + (i / 2) * kBoxSize,
126 box.fY + (i % 2) * kBoxSize,
127 box.fColor
Chris Dalton114a3c02017-05-26 15:17:19 -0600128 };
129 }
130
131 paint.setARGB(255, rgb[0], rgb[1], rgb[2]);
132 goldCanvas.drawRect(SkRect::MakeXYWH(box.fX, box.fY, kBoxSize, kBoxSize), paint);
133 }
134 }
135
Chris Dalton114a3c02017-05-26 15:17:19 -0600136 // ---- tests ----------
137
Brian Salomon23356442018-11-30 15:33:19 -0500138#define VALIDATE(buff) \
139 do { \
140 if (!buff) { \
141 ERRORF(reporter, #buff " is null."); \
142 return; \
143 } \
144 } while (0)
Chris Dalton114a3c02017-05-26 15:17:19 -0600145
Robert Phillips88a32ef2018-06-07 11:05:56 -0400146 run_test(context, "setNonIndexedNonInstanced", reporter, rtc, gold,
147 [&](DrawMeshHelper* helper) {
148 SkTArray<Box> expandedVertexData;
149 for (int i = 0; i < kBoxCount; ++i) {
150 for (int j = 0; j < 6; ++j) {
151 expandedVertexData.push_back(vertexData[i][kIndexPattern[j]]);
152 }
153 }
Chris Dalton114a3c02017-05-26 15:17:19 -0600154
Robert Phillips88a32ef2018-06-07 11:05:56 -0400155 // Draw boxes one line at a time to exercise base vertex.
Greg Danielf793de12019-09-05 13:23:23 -0400156 helper->fVertBuffer = helper->makeVertexBuffer(expandedVertexData);
157 VALIDATE(helper->fVertBuffer);
158 },
159 [&](DrawMeshHelper* helper) {
Robert Phillips88a32ef2018-06-07 11:05:56 -0400160 for (int y = 0; y < kBoxCountY; ++y) {
161 GrMesh mesh(GrPrimitiveType::kTriangles);
162 mesh.setNonIndexedNonInstanced(kBoxCountX * 6);
Greg Danielf793de12019-09-05 13:23:23 -0400163 mesh.setVertexData(helper->fVertBuffer, y * kBoxCountX * 6);
Robert Phillips88a32ef2018-06-07 11:05:56 -0400164 helper->drawMesh(mesh);
165 }
166 });
Chris Dalton114a3c02017-05-26 15:17:19 -0600167
Greg Danielf793de12019-09-05 13:23:23 -0400168 run_test(context, "setIndexed", reporter, rtc, gold,
169 [&](DrawMeshHelper* helper) {
170 helper->fIndexBuffer = helper->getIndexBuffer();
171 VALIDATE(helper->fIndexBuffer);
172 helper->fVertBuffer = helper->makeVertexBuffer(vertexData);
173 VALIDATE(helper->fVertBuffer);
174 },
175 [&](DrawMeshHelper* helper) {
176 int baseRepetition = 0;
177 int i = 0;
178 // Start at various repetitions within the patterned index buffer to exercise base
179 // index.
180 while (i < kBoxCount) {
181 GR_STATIC_ASSERT(kIndexPatternRepeatCount >= 3);
182 int repetitionCount = SkTMin(3 - baseRepetition, kBoxCount - i);
Chris Dalton114a3c02017-05-26 15:17:19 -0600183
Greg Danielf793de12019-09-05 13:23:23 -0400184 GrMesh mesh(GrPrimitiveType::kTriangles);
185 mesh.setIndexed(helper->fIndexBuffer, repetitionCount * 6, baseRepetition * 6,
186 baseRepetition * 4, (baseRepetition + repetitionCount) * 4 - 1,
187 GrPrimitiveRestart::kNo);
188 mesh.setVertexData(helper->fVertBuffer, (i - baseRepetition) * 4);
189 helper->drawMesh(mesh);
Chris Dalton114a3c02017-05-26 15:17:19 -0600190
Greg Danielf793de12019-09-05 13:23:23 -0400191 baseRepetition = (baseRepetition + 1) % 3;
192 i += repetitionCount;
193 }
194 });
Chris Dalton114a3c02017-05-26 15:17:19 -0600195
Greg Danielf793de12019-09-05 13:23:23 -0400196 run_test(context, "setIndexedPatterned", reporter, rtc, gold,
197 [&](DrawMeshHelper* helper) {
198 helper->fIndexBuffer = helper->getIndexBuffer();
199 VALIDATE(helper->fIndexBuffer);
200 helper->fVertBuffer = helper->makeVertexBuffer(vertexData);
201 VALIDATE(helper->fVertBuffer);
202 },
203 [&](DrawMeshHelper* helper) {
204 // Draw boxes one line at a time to exercise base vertex. setIndexedPatterned does
205 // not support a base index.
206 for (int y = 0; y < kBoxCountY; ++y) {
207 GrMesh mesh(GrPrimitiveType::kTriangles);
208 mesh.setIndexedPatterned(helper->fIndexBuffer, 6, 4, kBoxCountX,
209 kIndexPatternRepeatCount);
210 mesh.setVertexData(helper->fVertBuffer, y * kBoxCountX * 4);
211 helper->drawMesh(mesh);
212 }
213 });
Chris Dalton1d616352017-05-31 12:51:23 -0600214
215 for (bool indexed : {false, true}) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500216 if (!context->priv().caps()->instanceAttribSupport()) {
Chris Dalton1d616352017-05-31 12:51:23 -0600217 break;
218 }
219
Robert Phillips88a32ef2018-06-07 11:05:56 -0400220 run_test(context, indexed ? "setIndexedInstanced" : "setInstanced",
Greg Danielf793de12019-09-05 13:23:23 -0400221 reporter, rtc, gold,
222 [&](DrawMeshHelper* helper) {
223 helper->fIndexBuffer = indexed ? helper->getIndexBuffer() : nullptr;
224 helper->fInstBuffer = helper->makeVertexBuffer(boxes);
225 VALIDATE(helper->fInstBuffer);
226 helper->fVertBuffer =
227 helper->makeVertexBuffer(std::vector<float>{0,0, 0,1, 1,0, 1,1});
228 VALIDATE(helper->fVertBuffer);
229 helper->fVertBuffer2 = helper->makeVertexBuffer( // for testing base vertex.
230 std::vector<float>{-1,-1, -1,-1, 0,0, 0,1, 1,0, 1,1});
231 VALIDATE(helper->fVertBuffer2);
232 },
233 [&](DrawMeshHelper* helper) {
234 // Draw boxes one line at a time to exercise base instance, base vertex, and
235 // null vertex buffer. setIndexedInstanced intentionally does not support a
236 // base index.
237 for (int y = 0; y < kBoxCountY; ++y) {
238 GrMesh mesh(indexed ? GrPrimitiveType::kTriangles
239 : GrPrimitiveType::kTriangleStrip);
240 if (indexed) {
241 VALIDATE(helper->fIndexBuffer);
242 mesh.setIndexedInstanced(helper->fIndexBuffer, 6, helper->fInstBuffer,
243 kBoxCountX, y * kBoxCountX,
244 GrPrimitiveRestart::kNo);
245 } else {
246 mesh.setInstanced(helper->fInstBuffer, kBoxCountX, y * kBoxCountX, 4);
247 }
248 switch (y % 3) {
249 case 0:
250 if (context->priv().caps()->shaderCaps()->vertexIDSupport()) {
251 if (y % 2) {
252 // We don't need this call because it's the initial state
253 // of GrMesh.
254 mesh.setVertexData(nullptr);
255 }
256 break;
257 }
258 // Fallthru.
259 case 1:
260 mesh.setVertexData(helper->fVertBuffer);
261 break;
262 case 2:
263 mesh.setVertexData(helper->fVertBuffer2, 2);
264 break;
265 }
266 helper->drawMesh(mesh);
267 }
268 });
Chris Dalton1d616352017-05-31 12:51:23 -0600269 }
Chris Dalton114a3c02017-05-26 15:17:19 -0600270}
271
272////////////////////////////////////////////////////////////////////////////////////////////////////
273
274class GrMeshTestOp : public GrDrawOp {
275public:
276 DEFINE_OP_CLASS_ID
277
Robert Phillips88a32ef2018-06-07 11:05:56 -0400278 static std::unique_ptr<GrDrawOp> Make(GrContext* context,
Greg Danielf793de12019-09-05 13:23:23 -0400279 std::function<void(DrawMeshHelper*)> prepareFn,
280 std::function<void(DrawMeshHelper*)> executeFn) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500281 GrOpMemoryPool* pool = context->priv().opMemoryPool();
Robert Phillipsc994a932018-06-19 13:09:54 -0400282
Greg Danielf793de12019-09-05 13:23:23 -0400283 return pool->allocate<GrMeshTestOp>(prepareFn, executeFn);
Robert Phillips88a32ef2018-06-07 11:05:56 -0400284 }
285
286private:
Robert Phillips7c525e62018-06-12 10:11:12 -0400287 friend class GrOpMemoryPool; // for ctor
288
Greg Danielf793de12019-09-05 13:23:23 -0400289 GrMeshTestOp(std::function<void(DrawMeshHelper*)> prepareFn,
290 std::function<void(DrawMeshHelper*)> executeFn)
Chris Dalton114a3c02017-05-26 15:17:19 -0600291 : INHERITED(ClassID())
Greg Danielf793de12019-09-05 13:23:23 -0400292 , fPrepareFn(prepareFn)
293 , fExecuteFn(executeFn){
Chris Dalton114a3c02017-05-26 15:17:19 -0600294 this->setBounds(SkRect::MakeIWH(kImageWidth, kImageHeight),
Greg Daniel5faf4742019-10-01 15:14:44 -0400295 HasAABloat::kNo, IsHairline::kNo);
Chris Dalton114a3c02017-05-26 15:17:19 -0600296 }
297
Chris Dalton114a3c02017-05-26 15:17:19 -0600298 const char* name() const override { return "GrMeshTestOp"; }
299 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
Chris Dalton6ce447a2019-06-23 18:07:38 -0600300 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
301 bool hasMixedSampledCoverage, GrClampType) override {
Chris Dalton4b62aed2019-01-15 11:53:00 -0700302 return GrProcessorSet::EmptySetAnalysis();
Brian Salomonf86d37b2017-06-16 10:04:34 -0400303 }
Greg Danielf793de12019-09-05 13:23:23 -0400304 void onPrepare(GrOpFlushState* state) override {
305 fHelper.reset(new DrawMeshHelper(state));
306 fPrepareFn(fHelper.get());
307 }
Brian Salomon588cec72018-11-14 13:56:37 -0500308 void onExecute(GrOpFlushState* state, const SkRect& chainBounds) override {
Greg Danielf793de12019-09-05 13:23:23 -0400309 fExecuteFn(fHelper.get());
Chris Dalton114a3c02017-05-26 15:17:19 -0600310 }
311
Greg Danielf793de12019-09-05 13:23:23 -0400312 std::unique_ptr<DrawMeshHelper> fHelper;
313 std::function<void(DrawMeshHelper*)> fPrepareFn;
314 std::function<void(DrawMeshHelper*)> fExecuteFn;
Chris Dalton114a3c02017-05-26 15:17:19 -0600315
316 typedef GrDrawOp INHERITED;
317};
318
319class GrMeshTestProcessor : public GrGeometryProcessor {
320public:
Chris Dalton1d616352017-05-31 12:51:23 -0600321 GrMeshTestProcessor(bool instanced, bool hasVertexBuffer)
Brian Salomon92be2f72018-06-19 14:33:47 -0400322 : INHERITED(kGrMeshTestProcessor_ClassID) {
Chris Dalton1d616352017-05-31 12:51:23 -0600323 if (instanced) {
Brian Osmand4c29702018-09-14 16:16:55 -0400324 fInstanceLocation = {"location", kFloat2_GrVertexAttribType, kHalf2_GrSLType};
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500325 fInstanceColor = {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
326 this->setInstanceAttributes(&fInstanceLocation, 2);
Chris Dalton1d616352017-05-31 12:51:23 -0600327 if (hasVertexBuffer) {
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500328 fVertexPosition = {"vertex", kFloat2_GrVertexAttribType, kHalf2_GrSLType};
329 this->setVertexAttributes(&fVertexPosition, 1);
Chris Dalton1d616352017-05-31 12:51:23 -0600330 }
Chris Dalton1d616352017-05-31 12:51:23 -0600331 } else {
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500332 fVertexPosition = {"vertex", kFloat2_GrVertexAttribType, kHalf2_GrSLType};
333 fVertexColor = {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
334 this->setVertexAttributes(&fVertexPosition, 2);
Chris Dalton1d616352017-05-31 12:51:23 -0600335 }
Chris Dalton114a3c02017-05-26 15:17:19 -0600336 }
337
338 const char* name() const override { return "GrMeshTest Processor"; }
339
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500340 const Attribute& inColor() const {
341 return fVertexColor.isInitialized() ? fVertexColor : fInstanceColor;
342 }
343
Chris Dalton1d616352017-05-31 12:51:23 -0600344 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
Brian Salomon92be2f72018-06-19 14:33:47 -0400345 b->add32(fInstanceLocation.isInitialized());
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500346 b->add32(fVertexPosition.isInitialized());
Chris Dalton1d616352017-05-31 12:51:23 -0600347 }
Chris Dalton114a3c02017-05-26 15:17:19 -0600348
349 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
350
Brian Salomon92be2f72018-06-19 14:33:47 -0400351private:
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500352 Attribute fVertexPosition;
353 Attribute fVertexColor;
Brian Salomon92be2f72018-06-19 14:33:47 -0400354
355 Attribute fInstanceLocation;
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500356 Attribute fInstanceColor;
Chris Dalton114a3c02017-05-26 15:17:19 -0600357
358 friend class GLSLMeshTestProcessor;
359 typedef GrGeometryProcessor INHERITED;
360};
361
362class GLSLMeshTestProcessor : public GrGLSLGeometryProcessor {
363 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
364 FPCoordTransformIter&& transformIter) final {}
365
366 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final {
367 const GrMeshTestProcessor& mp = args.fGP.cast<GrMeshTestProcessor>();
368
369 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
370 varyingHandler->emitAttributes(mp);
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500371 varyingHandler->addPassThroughAttribute(mp.inColor(), args.fOutputColor);
Chris Dalton114a3c02017-05-26 15:17:19 -0600372
373 GrGLSLVertexBuilder* v = args.fVertBuilder;
Brian Salomon92be2f72018-06-19 14:33:47 -0400374 if (!mp.fInstanceLocation.isInitialized()) {
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500375 v->codeAppendf("float2 vertex = %s;", mp.fVertexPosition.name());
Chris Dalton1d616352017-05-31 12:51:23 -0600376 } else {
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500377 if (mp.fVertexPosition.isInitialized()) {
378 v->codeAppendf("float2 offset = %s;", mp.fVertexPosition.name());
Chris Dalton1d616352017-05-31 12:51:23 -0600379 } else {
Ethan Nicholas8aa45692017-09-20 11:24:15 -0400380 v->codeAppend ("float2 offset = float2(sk_VertexID / 2, sk_VertexID % 2);");
Chris Dalton1d616352017-05-31 12:51:23 -0600381 }
Brian Salomon92be2f72018-06-19 14:33:47 -0400382 v->codeAppendf("float2 vertex = %s + offset * %i;", mp.fInstanceLocation.name(),
Brian Salomon70132d02018-05-29 15:33:06 -0400383 kBoxSize);
Chris Dalton1d616352017-05-31 12:51:23 -0600384 }
Ethan Nicholas8aa45692017-09-20 11:24:15 -0400385 gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex");
Chris Dalton114a3c02017-05-26 15:17:19 -0600386
Chris Dalton60283612018-02-14 13:38:14 -0700387 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400388 f->codeAppendf("%s = half4(1);", args.fOutputCoverage);
Chris Dalton114a3c02017-05-26 15:17:19 -0600389 }
390};
391
392GrGLSLPrimitiveProcessor* GrMeshTestProcessor::createGLSLInstance(const GrShaderCaps&) const {
393 return new GLSLMeshTestProcessor;
394}
395
396////////////////////////////////////////////////////////////////////////////////////////////////////
397
398template<typename T>
399sk_sp<const GrBuffer> DrawMeshHelper::makeVertexBuffer(const T* data, int count) {
Brian Salomonae64c192019-02-05 09:41:37 -0500400 return sk_sp<const GrBuffer>(fState->resourceProvider()->createBuffer(
Brian Salomondbf70722019-02-07 11:31:24 -0500401 count * sizeof(T), GrGpuBufferType::kVertex, kDynamic_GrAccessPattern, data));
Chris Dalton114a3c02017-05-26 15:17:19 -0600402}
403
404sk_sp<const GrBuffer> DrawMeshHelper::getIndexBuffer() {
405 GR_DEFINE_STATIC_UNIQUE_KEY(gIndexBufferKey);
Brian Salomond28a79d2017-10-16 13:01:07 -0400406 return fState->resourceProvider()->findOrCreatePatternedIndexBuffer(
407 kIndexPattern, 6, kIndexPatternRepeatCount, 4, gIndexBufferKey);
Chris Dalton114a3c02017-05-26 15:17:19 -0600408}
409
410void DrawMeshHelper::drawMesh(const GrMesh& mesh) {
Greg Daniel2c3398d2019-06-19 11:58:01 -0400411 GrPipeline pipeline(GrScissorTest::kDisabled, SkBlendMode::kSrc, GrSwizzle::RGBA());
Chris Dalton1d616352017-05-31 12:51:23 -0600412 GrMeshTestProcessor mtp(mesh.isInstanced(), mesh.hasVertexData());
Greg Daniel2d41d0d2019-08-26 11:08:51 -0400413 fState->opsRenderPass()->draw(mtp, pipeline, nullptr, nullptr, &mesh, 1,
414 SkRect::MakeIWH(kImageWidth, kImageHeight));
Chris Dalton114a3c02017-05-26 15:17:19 -0600415}
416
Robert Phillips88a32ef2018-06-07 11:05:56 -0400417static void run_test(GrContext* context, const char* testName, skiatest::Reporter* reporter,
Brian Salomonbf6b9792019-08-21 09:38:10 -0400418 const std::unique_ptr<GrRenderTargetContext>& rtc, const SkBitmap& gold,
Greg Danielf793de12019-09-05 13:23:23 -0400419 std::function<void(DrawMeshHelper*)> prepareFn,
420 std::function<void(DrawMeshHelper*)> executeFn) {
Chris Dalton114a3c02017-05-26 15:17:19 -0600421 const int w = gold.width(), h = gold.height(), rowBytes = gold.rowBytes();
422 const uint32_t* goldPx = reinterpret_cast<const uint32_t*>(gold.getPixels());
423 if (h != rtc->height() || w != rtc->width()) {
424 ERRORF(reporter, "[%s] expectation and rtc not compatible (?).", testName);
425 return;
426 }
427 if (sizeof(uint32_t) * kImageWidth != gold.rowBytes()) {
428 ERRORF(reporter, "unexpected row bytes in gold image.", testName);
429 return;
430 }
431
432 SkAutoSTMalloc<kImageHeight * kImageWidth, uint32_t> resultPx(h * rowBytes);
Brian Osman9a9baae2018-11-05 15:06:26 -0500433 rtc->clear(nullptr, SkPMColor4f::FromBytes_RGBA(0xbaaaaaad),
434 GrRenderTargetContext::CanClearFullscreen::kYes);
Greg Danielf793de12019-09-05 13:23:23 -0400435 rtc->priv().testingOnly_addDrawOp(GrMeshTestOp::Make(context, prepareFn, executeFn));
Brian Salomon1d435302019-07-01 13:05:28 -0400436 rtc->readPixels(gold.info(), resultPx, rowBytes, {0, 0});
Chris Dalton114a3c02017-05-26 15:17:19 -0600437 for (int y = 0; y < h; ++y) {
438 for (int x = 0; x < w; ++x) {
439 uint32_t expected = goldPx[y * kImageWidth + x];
440 uint32_t actual = resultPx[y * kImageWidth + x];
441 if (expected != actual) {
442 ERRORF(reporter, "[%s] pixel (%i,%i): got 0x%x expected 0x%x",
443 testName, x, y, actual, expected);
444 return;
445 }
446 }
447 }
448}