Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
GrGpuBufferTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2022 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
12#include "include/core/SkRect.h"
49#include "tests/Test.h"
50
51#include <algorithm>
52#include <cstring>
53#include <initializer_list>
54#include <memory>
55#include <string_view>
56#include <utility>
57
58class GrDstProxyView;
62class SkArenaAlloc;
63enum class GrXferBarrierFlags;
64namespace skgpu { class KeyBuilder; }
65struct GrContextOptions;
66struct GrShaderCaps;
67
68// Simple op that draws a vertex buffer with float2 positions as green triangles. We use this to
69// draw GrGpuBuffers to test that the buffer contains the expected values as not all contexts will
70// support buffer mapping.
71class TestVertexOp final : public GrMeshDrawOp {
72public:
75 int baseVertex,
76 int vertexCount,
77 const SkRect& bounds) {
78 return GrOp::Make<TestVertexOp>(context,
79 std::move(buffer),
80 baseVertex,
81 vertexCount,
82 bounds);
83 }
84
85 const char* name() const override { return "TestVertexOp"; }
86
88
90 const GrAppliedClip* clip,
91 GrClampType clampType) override {
92 static constexpr SkPMColor4f kGreen{0, 1, 0, 1};
94 auto analysis = fProcessorSet.finalize(GrProcessorAnalysisColor::Opaque::kYes,
96 clip,
98 caps,
99 clampType,
100 &color);
102 return analysis;
103 }
104
105 void visitProxies(const GrVisitProxyFunc& func) const override {
106 if (fProgramInfo) {
107 fProgramInfo->visitFPProxies(func);
108 }
109 }
110
111private:
113
115 int baseVertex,
116 int vertexCount,
117 const SkRect& bounds)
118 : GrMeshDrawOp(ClassID())
119 , fBuffer(std::move(buffer))
120 , fProcessorSet(SkBlendMode::kSrc)
121 , fBaseVertex(baseVertex)
122 , fVertexCount(vertexCount) {
124 }
125
126 GrProgramInfo* programInfo() override { return fProgramInfo; }
127
128 void onCreateProgramInfo(const GrCaps* caps,
129 SkArenaAlloc* arena,
130 const GrSurfaceProxyView& writeView,
131 bool usesMSAASurface,
132 GrAppliedClip&& appliedClip,
133 const GrDstProxyView& dstProxyView,
134 GrXferBarrierFlags renderPassXferBarriers,
135 GrLoadOp colorLoadOp) override {
137 caps,
138 arena,
139 writeView,
140 usesMSAASurface,
141 std::move(appliedClip),
142 dstProxyView,
143 &fGP,
144 std::move(fProcessorSet),
146 renderPassXferBarriers,
147 colorLoadOp,
149 }
150
151 class GP : public GrGeometryProcessor {
152 public:
155 }
156
157 const char* name() const override { return "TestVertexOp::GP"; }
158
159 std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override {
160 class Impl : public ProgramImpl {
161 public:
162 void setData(const GrGLSLProgramDataManager&,
163 const GrShaderCaps&,
164 const GrGeometryProcessor&) override {}
165
166 private:
167 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
168 const auto& gp = args.fGeomProc.cast<GP>();
169 args.fVaryingHandler->emitAttributes(gp);
170 args.fFragBuilder->codeAppendf("half4 %s = half4(0, 1, 0, 1);",
171 args.fOutputColor);
172 args.fFragBuilder->codeAppendf("const half4 %s = half4(1);",
173 args.fOutputCoverage);
174 WriteOutputPosition(args.fVertBuilder, gpArgs, kPos.name());
175 }
176
177 UniformHandle fLocalMatrixUni;
178 };
179
180 return std::make_unique<Impl>();
181 }
182
183 void addToKey(const GrShaderCaps &caps, skgpu::KeyBuilder *builder) const override {}
184
185 private:
186 static constexpr Attribute kPos = {"pos", kFloat2_GrVertexAttribType, SkSLType::kFloat2};
187 };
188
190 fMesh = target->allocMesh();
191 fMesh->set(fBuffer, fVertexCount, fBaseVertex);
192 }
193
194 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
195 if (!fProgramInfo) {
196 this->createProgramInfo(flushState);
197 }
198
199 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
200 flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
201 flushState->drawMesh(*fMesh);
202 }
203
204 sk_sp<GrGpuBuffer> fBuffer;
205
206 GP fGP;
207
208 GrProcessorSet fProcessorSet;
209
210 int fBaseVertex;
211 int fVertexCount;
212
213 GrProgramInfo* fProgramInfo = nullptr;
214 GrSimpleMesh* fMesh = nullptr;
215
216 friend class ::GrOp;
217};
218
220 reporter,
221 ctxInfo,
223 if (!ctxInfo.directContext()->priv().caps()->transferFromBufferToBufferSupport()) {
224 return;
225 }
226
227 GrDirectContext* dc = ctxInfo.directContext();
228
230
231 GrResourceProvider* rp = ctxInfo.directContext()->priv().resourceProvider();
232
233 GrGpu* gpu = ctxInfo.directContext()->priv().getGpu();
234
235 auto create_cpu_to_gpu_buffer = [&](int baseVertex) {
236 // Ensure any extra vertices are offscreen
237 int totalVertices = baseVertex + 6;
238 auto points = std::make_unique<SkPoint[]>(totalVertices);
239 SkPoint offscreenPt{-10000, -10000};
240 std::fill_n(points.get(), totalVertices, offscreenPt);
241
242 // set the quad at the desired base vertex
243 static constexpr SkPoint kUnitQuad[] {{0, 0}, {0, 1}, {1, 0},
244 {1, 0}, {0, 1}, {1, 1}};
245 std::copy_n(kUnitQuad, 6, points.get() + baseVertex);
246
247 return rp->createBuffer(points.get(),
248 totalVertices*sizeof(SkPoint),
251 };
252
253 auto create_vertex_buffer = [&](sk_sp<GrGpuBuffer> srcBuffer,
254 int srcBaseVertex,
255 int vbBaseVertex,
256 bool useTask,
257 bool minSizedTransfers) {
258 // make initialization data of offscreen points.
259 int dstVertexCount = vbBaseVertex + 6;
260 auto points = std::make_unique<SkPoint[]>(dstVertexCount);
261 SkPoint offscreenPt{-10000, -10000};
262 std::fill_n(points.get(), dstVertexCount, offscreenPt);
263
265 dstVertexCount*sizeof(SkPoint),
268
269 // copy actual quad data from the source buffer to our new vb.
270
271 static constexpr size_t kTotalSize = 6*sizeof(SkPoint);
272
273 size_t srcOffset = srcBaseVertex*sizeof(SkPoint);
274 size_t vbOffset = vbBaseVertex*sizeof(SkPoint);
275
276 size_t alignment = gpu->caps()->transferFromBufferToBufferAlignment();
277 SkASSERT(kTotalSize % alignment == 0);
278 SkASSERT(sizeof(SkPoint) % alignment == 0);
279
280 if (minSizedTransfers) {
281 for (size_t n = kTotalSize/alignment, i = 0; i < n; ++i) {
282 if (useTask) {
283 dm->newBufferTransferTask(srcBuffer,
284 srcOffset + i*alignment,
285 vb,
286 vbOffset + i*alignment,
287 alignment);
288 } else {
289 gpu->transferFromBufferToBuffer(srcBuffer,
290 srcOffset + i*alignment,
291 vb,
292 vbOffset + i*alignment,
293 alignment);
294 }
295 }
296 } else if (useTask) {
297 dm->newBufferTransferTask(srcBuffer, srcOffset, vb, vbOffset, kTotalSize);
298 } else {
299 gpu->transferFromBufferToBuffer(srcBuffer, srcOffset, vb, vbOffset, kTotalSize);
300 }
301 return vb;
302 };
303
306 nullptr,
308 {1, 1},
310 std::string_view{});
311 if (!sdc) {
312 ERRORF(reporter, "Could not create draw context");
313 return;
314 }
315
316 auto pm = GrPixmap::Allocate(sdc->imageInfo().makeColorType(GrColorType::kRGBA_F32));
317
318 for (bool useTask : {false, true}) {
319 for (bool minSizedTransfers : {false, true}) {
320 for (int srcBaseVertex : {0, 5}) {
321 auto src = create_cpu_to_gpu_buffer(srcBaseVertex);
322 if (!src) {
323 ERRORF(reporter, "Could not create src buffer");
324 return;
325 }
326 for (int vbBaseVertex : {0, 2}) {
327 auto vb = create_vertex_buffer(src,
328 srcBaseVertex,
329 vbBaseVertex,
330 useTask,
331 minSizedTransfers);
332 if (!vb) {
333 ERRORF(reporter, "Could not create vertex buffer");
334 return;
335 }
336
337 static constexpr SkColor4f kRed{1, 0, 0, 1};
338
339 static constexpr SkRect kBounds{0, 0, 1, 1};
340
341 sdc->clear(kRed);
342
343 sdc->addDrawOp(nullptr, TestVertexOp::Make(dc,
344 vb,
345 vbBaseVertex,
346 /*vertexCount=*/6,
347 kBounds));
348
349 auto color = static_cast<SkPMColor4f*>(pm.addr());
350 *color = kRed.premul();
351 if (!sdc->readPixels(dc, pm, {0, 0})) {
352 ERRORF(reporter, "Read back failed.");
353 return;
354 }
355
356 static constexpr SkPMColor4f kGreen{0, 1, 0, 1};
357
358 REPORTER_ASSERT(reporter, *color == kGreen, "src base vertex: %d, "
359 "vb base vertex: %d, "
360 "use task: %d, "
361 "minSizedTransfers: %d",
362 srcBaseVertex,
363 vbBaseVertex,
364 useTask,
365 minSizedTransfers);
366 }
367 }
368 }
369 }
370}
371
373 reporter,
374 ctxInfo,
376 GrDirectContext* dc = ctxInfo.directContext();
377
378 GrGpu* gpu = ctxInfo.directContext()->priv().getGpu();
379
380 static constexpr SkPoint kUnitQuad[] {{0, 0}, {0, 1}, {1, 0},
381 {1, 0}, {0, 1}, {1, 1}};
382
385 nullptr,
387 {1, 1},
389 std::string_view{});
390 if (!sdc) {
391 ERRORF(reporter, "Could not create draw context");
392 return;
393 }
394
395 auto pm = GrPixmap::Allocate(sdc->imageInfo().makeColorType(GrColorType::kRGBA_F32));
396
397 for (bool piecewise : {false, true}) {
398 size_t alignment = piecewise ? gpu->caps()->bufferUpdateDataPreserveAlignment() : 1;
399 for (size_t offset : {size_t{0}, 4*sizeof(SkPoint), size_t{1}, size_t{27}}) {
400 // For non-discarding updates we may not be able to actually put the data at an
401 // arbitrary offset.
402 if (alignment > 1) {
403 offset = SkAlignTo(offset, alignment);
404 }
405 for (auto accessPattern : {kStatic_GrAccessPattern,
406 // kStream_GrAccessPattern, GrVkGpu asserts on this for VBs.
408 // Go direct to GrGpu to avoid caching/size adjustments at GrResourceProvider level.
409 // We add an extra size(SkPoint) to ensure that everything fits when we align the
410 // first point's location in the vb below.
411 auto vb = gpu->createBuffer(sizeof(kUnitQuad) + offset + sizeof(SkPoint),
413 accessPattern);
414 if (!vb) {
415 ERRORF(reporter, "Could not create vertex buffer");
416 return;
417 }
418
419 const void* src = kUnitQuad;
420 size_t updateSize = sizeof(kUnitQuad);
421 // The vertices in the VB must be aligned to the size of a vertex (because our draw
422 // call takes a base vertex index rather than a byte offset). So if we want our
423 // upload to begin at a non-aligned byte we shift the data in the src buffer so that
424 // it falls at a vertex alignment in the vb.
425 std::unique_ptr<char[]> tempSrc;
426 size_t baseVertex = offset/sizeof(SkPoint);
427 if (size_t r = offset%sizeof(SkPoint); r != 0) {
428 size_t pad = sizeof(SkPoint) - r;
429 updateSize += pad;
430 if (alignment > 1) {
431 updateSize = SkAlignTo(updateSize, alignment);
432 }
433 ++baseVertex;
434 tempSrc.reset(new char[updateSize]);
435 std::memcpy(tempSrc.get() + pad, kUnitQuad, sizeof(kUnitQuad));
436 src = tempSrc.get();
437 }
438 if (piecewise) {
439 // This is the minimum size we can transfer at once.
440 size_t pieceSize = alignment;
441
442 // Upload each piece from a buffer where the byte before and after the uploaded
443 // bytes are not the same values as want adjacent to the piece in the buffer.
444 // Thus, if updateData() transfers extra bytes around the source we should get a
445 // bad buffer.
446 auto piece = std::make_unique<unsigned char[]>(pieceSize + 2);
447 piece[0] = piece[pieceSize + 1] = 0xFF;
448
449 for (size_t o = 0; o < updateSize; o += pieceSize) {
450 memcpy(&piece[1], SkTAddOffset<const void>(src, o), pieceSize);
451 if (!vb->updateData(&piece[1], offset + o, pieceSize, /*preserve=*/true)) {
452 ERRORF(reporter, "GrGpuBuffer::updateData returned false.");
453 return;
454 }
455 }
456 } else if (!vb->updateData(src, offset, updateSize, /*preserve=*/false)) {
457 ERRORF(reporter, "GrGpuBuffer::updateData returned false.");
458 return;
459 }
460
461 static constexpr SkColor4f kRed{1, 0, 0, 1};
462
463 static constexpr SkRect kBounds{0, 0, 1, 1};
464
465 sdc->clear(kRed);
466
467 sdc->addDrawOp(nullptr, TestVertexOp::Make(dc,
468 vb,
469 baseVertex,
470 std::size(kUnitQuad),
471 kBounds));
472
473 auto color = static_cast<SkPMColor4f*>(pm.addr());
474 *color = kRed.premul();
475 if (!sdc->readPixels(dc, pm, {0, 0})) {
476 ERRORF(reporter, "Read back failed.");
477 return;
478 }
479
480 static constexpr SkPMColor4f kGreen{0, 1, 0, 1};
481
482 REPORTER_ASSERT(reporter, *color == kGreen, "piecewise: %d, offset: %zu",
483 piecewise, offset);
484 }
485 }
486 }
487}
reporter
#define DEFINE_OP_CLASS_ID
Definition GrOp.h:64
GrClampType
std::function< void(GrSurfaceProxy *, skgpu::Mipmapped)> GrVisitProxyFunc
@ kDynamic_GrAccessPattern
@ kStatic_GrAccessPattern
GrLoadOp
@ kFloat2_GrVertexAttribType
GrXferBarrierFlags
static const int points[]
SkColor4f color
static const uint64_t kGreen
static const uint64_t kRed
static constexpr size_t SkAlignTo(size_t x, size_t alignment)
Definition SkAlign.h:33
#define SkASSERT(cond)
Definition SkAssert.h:116
SkBlendMode
Definition SkBlendMode.h:38
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
#define ERRORF(r,...)
Definition Test.h:293
#define DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(name, reporter, context_info, ctsEnforcement)
Definition Test.h:434
size_t bufferUpdateDataPreserveAlignment() const
Definition GrCaps.h:250
size_t transferFromBufferToBufferAlignment() const
Definition GrCaps.h:244
GrDirectContextPriv priv()
FixedFunctionFlags
Definition GrDrawOp.h:104
void newBufferTransferTask(sk_sp< GrGpuBuffer > src, size_t srcOffset, sk_sp< GrGpuBuffer > dst, size_t dstOffset, size_t size)
void setVertexAttributesWithImplicitOffsets(const Attribute *attrs, int attrCount)
Definition GrGpu.h:62
const GrCaps * caps() const
Definition GrGpu.h:73
bool transferFromBufferToBuffer(sk_sp< GrGpuBuffer > src, size_t srcOffset, sk_sp< GrGpuBuffer > dst, size_t dstOffset, size_t size)
Definition GrGpu.cpp:511
sk_sp< GrGpuBuffer > createBuffer(size_t size, GrGpuBufferType intendedType, GrAccessPattern accessPattern)
Definition GrGpu.cpp:393
void createProgramInfo(const GrCaps *caps, SkArenaAlloc *arena, const GrSurfaceProxyView &writeView, bool usesMSAASurface, GrAppliedClip &&appliedClip, const GrDstProxyView &dstProxyView, GrXferBarrierFlags renderPassXferBarriers, GrLoadOp colorLoadOp)
void drawMesh(const GrSimpleMesh &mesh)
void bindPipelineAndScissorClip(const GrProgramInfo &programInfo, const SkRect &drawBounds)
void bindTextures(const GrGeometryProcessor &geomProc, const GrSurfaceProxy &singleGeomProcTexture, const GrPipeline &pipeline)
std::unique_ptr< GrOp > Owner
Definition GrOp.h:72
const SkRect & bounds() const
Definition GrOp.h:122
void setBounds(const SkRect &newBounds, HasAABloat aabloat, IsHairline zeroArea)
Definition GrOp.h:279
static GrPixmap Allocate(const GrImageInfo &info)
Definition GrPixmap.h:101
Analysis finalize(const GrProcessorAnalysisColor &, const GrProcessorAnalysisCoverage, const GrAppliedClip *, const GrUserStencilSettings *, const GrCaps &, GrClampType, SkPMColor4f *inputColorOverride)
const GrPipeline & pipeline() const
const GrGeometryProcessor & geomProc() const
void visitFPProxies(const GrVisitProxyFunc &func) const
GrDrawingManager * drawingManager()
sk_sp< GrGpuBuffer > createBuffer(size_t size, GrGpuBufferType, GrAccessPattern, ZeroInit)
GrResourceProviderPriv priv()
static GrProgramInfo * CreateProgramInfo(const GrCaps *, SkArenaAlloc *, const GrPipeline *, const GrSurfaceProxyView &writeView, bool usesMSAASurface, GrGeometryProcessor *, GrPrimitiveType, GrXferBarrierFlags renderPassXferBarriers, GrLoadOp colorLoadOp, const GrUserStencilSettings *=&GrUserStencilSettings::kUnused)
void onExecute(GrOpFlushState *flushState, const SkRect &chainBounds) override
GrProgramInfo * programInfo() override
const char * name() const override
GrProcessorSet::Analysis finalize(const GrCaps &caps, const GrAppliedClip *clip, GrClampType clampType) override
void onPrepareDraws(GrMeshDrawTarget *target) override
void onCreateProgramInfo(const GrCaps *caps, SkArenaAlloc *arena, const GrSurfaceProxyView &writeView, bool usesMSAASurface, GrAppliedClip &&appliedClip, const GrDstProxyView &dstProxyView, GrXferBarrierFlags renderPassXferBarriers, GrLoadOp colorLoadOp) override
FixedFunctionFlags fixedFunctionFlags() const override
void visitProxies(const GrVisitProxyFunc &func) const override
static GrOp::Owner Make(GrRecordingContext *context, sk_sp< GrGpuBuffer > buffer, int baseVertex, int vertexCount, const SkRect &bounds)
static std::unique_ptr< SurfaceDrawContext > Make(GrRecordingContext *, GrColorType, sk_sp< GrSurfaceProxy >, sk_sp< SkColorSpace >, GrSurfaceOrigin, const SkSurfaceProps &)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static const uint8_t buffer[]
uint32_t * target
DEF_SWITCHES_START aot vmservice shared library name
Definition switches.h:32
Definition ref_ptr.h:256
Point offset
void set(sk_sp< const GrBuffer > vertexBuffer, int vertexCount, int baseVertex)
static const GrUserStencilSettings & kUnused