Flutter Engine
The Flutter Engine
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
189 void onPrepareDraws(GrMeshDrawTarget* target) override {
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
Definition: FontMgrTest.cpp:39
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrGpuBufferTransferTest, reporter, ctxInfo, CtsEnforcement::kApiLevel_U)
#define DEFINE_OP_CLASS_ID
Definition: GrOp.h:64
GrClampType
Definition: GrTypesPriv.h:228
std::function< void(GrSurfaceProxy *, skgpu::Mipmapped)> GrVisitProxyFunc
Definition: GrTypesPriv.h:943
@ kDynamic_GrAccessPattern
Definition: GrTypesPriv.h:426
@ kStatic_GrAccessPattern
Definition: GrTypesPriv.h:428
GrLoadOp
Definition: GrTypesPriv.h:155
@ kFloat2_GrVertexAttribType
Definition: GrTypesPriv.h:314
GrXferBarrierFlags
static const int points[]
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:3892
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
#define ERRORF(r,...)
Definition: Test.h:293
Definition: GrCaps.h:57
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)
Definition: GrMeshDrawOp.h:39
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
Definition: GrProgramInfo.h:39
const GrGeometryProcessor & geomProc() const
Definition: GrProgramInfo.h:40
void visitFPProxies(const GrVisitProxyFunc &func) const
Definition: GrProgramInfo.h:64
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)
const char * name() const override
GrProcessorSet::Analysis finalize(const GrCaps &caps, const GrAppliedClip *clip, GrClampType clampType) 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 &)
DlColor color
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint32_t * target
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: GpuTools.h:21
Definition: ref_ptr.h:256
SeparatedVector2 offset
void set(sk_sp< const GrBuffer > vertexBuffer, int vertexCount, int baseVertex)
Definition: GrSimpleMesh.h:47
static const GrUserStencilSettings & kUnused