• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google LLC
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 
8 #include "tests/Test.h"
9 
10 #include "experimental/graphite/include/Context.h"
11 #include "experimental/graphite/include/Recorder.h"
12 #include "experimental/graphite/include/mtl/MtlTypes.h"
13 #include "experimental/graphite/src/Buffer.h"
14 #include "experimental/graphite/src/Caps.h"
15 #include "experimental/graphite/src/CommandBuffer.h"
16 #include "experimental/graphite/src/ContextPriv.h"
17 #include "experimental/graphite/src/DrawBufferManager.h"
18 #include "experimental/graphite/src/DrawWriter.h"
19 #include "experimental/graphite/src/GlobalCache.h"
20 #include "experimental/graphite/src/Gpu.h"
21 #include "experimental/graphite/src/GraphicsPipeline.h"
22 #include "experimental/graphite/src/RecorderPriv.h"
23 #include "experimental/graphite/src/Renderer.h"
24 #include "experimental/graphite/src/ResourceProvider.h"
25 #include "experimental/graphite/src/Sampler.h"
26 #include "experimental/graphite/src/Texture.h"
27 #include "experimental/graphite/src/TextureProxy.h"
28 #include "experimental/graphite/src/UniformManager.h"
29 #include "experimental/graphite/src/geom/Shape.h"
30 #include "experimental/graphite/src/geom/Transform_graphite.h"
31 #include "src/core/SkKeyHelpers.h"
32 #include "src/core/SkShaderCodeDictionary.h"
33 #include "src/core/SkUniformData.h"
34 
35 #if GRAPHITE_TEST_UTILS
36 // set to 1 if you want to do GPU capture of the commandBuffer
37 #define CAPTURE_COMMANDBUFFER 0
38 #endif
39 
40 using namespace skgpu;
41 
42 namespace {
43 
44 const DepthStencilSettings kTestDepthStencilSettings = {
45     // stencil
46     {},
47     {},
48     0,
49     true,
50     // depth
51     CompareOp::kAlways,
52     true,
53     false,
54 };
55 
56 class UniformRectDraw final : public RenderStep {
57 public:
~UniformRectDraw()58     ~UniformRectDraw() override {}
59 
Singleton()60     static const RenderStep* Singleton() {
61         static const UniformRectDraw kSingleton;
62         return &kSingleton;
63     }
64 
name() const65     const char* name() const override { return "uniform-rect"; }
66 
vertexSkSL() const67     const char* vertexSkSL() const override {
68         return "float2 tmpPosition = float2(float(sk_VertexID >> 1), float(sk_VertexID & 1));\n"
69                "float4 devPosition = float4(tmpPosition * scale + translate, 0.0, 1.0);\n";
70     }
71 
writeVertices(DrawWriter * writer,const SkIRect &,const Transform &,const Shape &) const72     void writeVertices(DrawWriter* writer,
73                        const SkIRect&,
74                        const Transform&,
75                        const Shape&) const override {
76         // The shape is upload via uniforms, so this just needs to record 4 data-less vertices
77         writer->draw({}, 4);
78     }
79 
writeUniforms(Layout layout,const SkIRect &,const Transform &,const Shape & shape) const80     sk_sp<SkUniformData> writeUniforms(Layout layout,
81                                        const SkIRect&,
82                                        const Transform&,
83                                        const Shape& shape) const override {
84         SkASSERT(shape.isRect());
85         // TODO: A << API for uniforms would be nice, particularly if it could take pre-computed
86         // offsets for each uniform.
87         auto uniforms = SkUniformData::Make(this->uniforms(), sizeof(float) * 4);
88         float2 scale = shape.rect().size();
89         float2 translate = shape.rect().topLeft();
90         memcpy(uniforms->data(), &scale, sizeof(float2));
91         memcpy(uniforms->data() + sizeof(float2), &translate, sizeof(float2));
92         return uniforms;
93     }
94 
95 private:
UniformRectDraw()96     UniformRectDraw() : RenderStep(Flags::kPerformsShading,
97                                    /*uniforms=*/{{"scale",     SkSLType::kFloat2},
98                                                  {"translate", SkSLType::kFloat2}},
99                                    PrimitiveType::kTriangleStrip,
100                                    {{},
101                                     {},
102                                     0,
103                                     true,
104                                     CompareOp::kAlways,
105                                     false,
106                                     false},
107                                    /*vertexAttrs=*/{},
108                                    /*instanceAttrs=*/{}) {}
109 };
110 
111 class TriangleRectDraw final : public RenderStep {
112 public:
~TriangleRectDraw()113     ~TriangleRectDraw() override {}
114 
Singleton()115     static const RenderStep* Singleton() {
116         static const TriangleRectDraw kSingleton;
117         return &kSingleton;
118     }
119 
name() const120     const char* name() const override { return "triangle-rect"; }
121 
vertexSkSL() const122     const char* vertexSkSL() const override {
123         return "float4 devPosition = float4(position * scale + translate, 0.0, 1.0);\n";
124     }
125 
writeVertices(DrawWriter * writer,const SkIRect &,const Transform &,const Shape & shape) const126     void writeVertices(DrawWriter* writer,
127                        const SkIRect&,
128                        const Transform&,
129                        const Shape& shape) const override {
130         DrawBufferManager* bufferMgr = writer->bufferManager();
131         auto [vertexWriter, vertices] = bufferMgr->getVertexWriter(4 * this->vertexStride());
132         vertexWriter << 0.5f * (shape.rect().left() + 1.f)  << 0.5f * (shape.rect().top() + 1.f)
133                      << 0.5f * (shape.rect().left() + 1.f)  << 0.5f * (shape.rect().bot() + 1.f)
134                      << 0.5f * (shape.rect().right() + 1.f) << 0.5f * (shape.rect().top() + 1.f)
135                      << 0.5f * (shape.rect().right() + 1.f) << 0.5f * (shape.rect().bot() + 1.f);
136 
137         // TODO: Would be nice to re-use this
138         auto [indexWriter, indices] = bufferMgr->getIndexWriter(6 * sizeof(uint16_t));
139         indexWriter << 0 << 1 << 2
140                     << 2 << 1 << 3;
141 
142         writer->drawIndexed(vertices, indices, 6);
143     }
144 
writeUniforms(Layout layout,const SkIRect &,const Transform &,const Shape &) const145     sk_sp<SkUniformData> writeUniforms(Layout layout,
146                                        const SkIRect&,
147                                        const Transform&,
148                                        const Shape&) const override {
149         auto uniforms = SkUniformData::Make(this->uniforms(), sizeof(float) * 4);
150         float data[4] = {2.f, 2.f, -1.f, -1.f};
151         memcpy(uniforms->data(), data, 4 * sizeof(float));
152         return uniforms;
153     }
154 
155 private:
TriangleRectDraw()156     TriangleRectDraw()
157             : RenderStep(Flags::kPerformsShading,
158                          /*uniforms=*/{{"scale",     SkSLType::kFloat2},
159                                        {"translate", SkSLType::kFloat2}},
160                          PrimitiveType::kTriangles,
161                          kTestDepthStencilSettings,
162                          /*vertexAttrs=*/{{"position",
163                                            VertexAttribType::kFloat2,
164                                            SkSLType::kFloat2}},
165                          /*instanceAttrs=*/{}) {}
166 };
167 
168 class InstanceRectDraw final : public RenderStep {
169 public:
~InstanceRectDraw()170     ~InstanceRectDraw() override {}
171 
Singleton()172     static const RenderStep* Singleton() {
173         static const InstanceRectDraw kSingleton;
174         return &kSingleton;
175     }
176 
name() const177     const char* name() const override { return "instance-rect"; }
178 
vertexSkSL() const179     const char* vertexSkSL() const override {
180         return "float2 tmpPosition = float2(float(sk_VertexID >> 1), float(sk_VertexID & 1));\n"
181                "float4 devPosition = float4(tmpPosition * dims + position, 0.0, 1.0);\n";
182     }
183 
writeVertices(DrawWriter * writer,const SkIRect &,const Transform &,const Shape & shape) const184     void writeVertices(DrawWriter* writer,
185                        const SkIRect&,
186                        const Transform&,
187                        const Shape& shape) const override {
188         SkASSERT(shape.isRect());
189 
190         DrawBufferManager* bufferMgr = writer->bufferManager();
191 
192         // TODO: To truly test draw merging, this index buffer needs to remembered across
193         // writeVertices calls
194         auto [indexWriter, indices] = bufferMgr->getIndexWriter(6 * sizeof(uint16_t));
195         indexWriter << 0 << 1 << 2
196                     << 2 << 1 << 3;
197 
198         DrawWriter::Instances instances{*writer, {}, indices, 6};
199         instances.append(1) << shape.rect().topLeft() << shape.rect().size();
200     }
201 
writeUniforms(Layout,const SkIRect &,const Transform &,const Shape &) const202     sk_sp<SkUniformData> writeUniforms(Layout,
203                                        const SkIRect&,
204                                        const Transform&,
205                                        const Shape&) const override {
206         return nullptr;
207     }
208 
209 private:
InstanceRectDraw()210     InstanceRectDraw()
211             : RenderStep(Flags::kPerformsShading,
212                          /*uniforms=*/{},
213                          PrimitiveType::kTriangles,
214                          kTestDepthStencilSettings,
215                          /*vertexAttrs=*/{},
216                          /*instanceAttrs=*/ {
217                                 { "position", VertexAttribType::kFloat2, SkSLType::kFloat2 },
218                                 { "dims",     VertexAttribType::kFloat2, SkSLType::kFloat2 }
219                          }) {}
220 };
221 
222 } // anonymous namespace
223 
224 /*
225  * This is to test the various pieces of the CommandBuffer interface.
226  */
DEF_GRAPHITE_TEST_FOR_CONTEXTS(CommandBufferTest,reporter,context)227 DEF_GRAPHITE_TEST_FOR_CONTEXTS(CommandBufferTest, reporter, context) {
228     constexpr int kTextureWidth = 1024;
229     constexpr int kTextureHeight = 768;
230 
231     auto gpu = context->priv().gpu();
232     REPORTER_ASSERT(reporter, gpu);
233 
234 #if GRAPHITE_TEST_UTILS && CAPTURE_COMMANDBUFFER
235     gpu->testingOnly_startCapture();
236 #endif
237     auto recorder = context->makeRecorder();
238     auto resourceProvider = recorder->priv().resourceProvider();
239     auto dict = resourceProvider->shaderCodeDictionary();
240     auto commandBuffer = resourceProvider->createCommandBuffer();
241 
242     SkISize textureSize = { kTextureWidth, kTextureHeight };
243 #ifdef SK_METAL
244     skgpu::mtl::TextureInfo mtlTextureInfo = {
245         1,
246         1,
247         70,     // MTLPixelFormatRGBA8Unorm
248         0x0005, // MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead
249         2,      // MTLStorageModePrivate
250         false,  // framebufferOnly
251     };
252     TextureInfo textureInfo(mtlTextureInfo);
253 #else
254     TextureInfo textureInfo;
255 #endif
256 
257     std::unique_ptr<SkPaintParamsKey> key = CreateKey(dict,
258                                                       SkBackend::kGraphite,
259                                                       ShaderCombo::ShaderType::kSolidColor,
260                                                       SkTileMode::kClamp,
261                                                       SkBlendMode::kSrc);
262 
263     auto entry = dict->findOrCreate(std::move(key));
264 
265     auto target = sk_sp<TextureProxy>(new TextureProxy(textureSize, textureInfo));
266     REPORTER_ASSERT(reporter, target);
267 
268     RenderPassDesc renderPassDesc = {};
269     renderPassDesc.fColorAttachment.fTextureInfo = target->textureInfo();
270     renderPassDesc.fColorAttachment.fLoadOp = LoadOp::kClear;
271     renderPassDesc.fColorAttachment.fStoreOp = StoreOp::kStore;
272     renderPassDesc.fClearColor = { 1, 0, 0, 1 }; // red
273 
274     target->instantiate(resourceProvider);
275     DrawBufferManager bufferMgr(resourceProvider, 4);
276 
277     TextureInfo depthStencilInfo =
278             gpu->caps()->getDefaultDepthStencilTextureInfo(DepthStencilFlags::kDepthStencil,
279                                                            1,
280                                                            Protected::kNo);
281     renderPassDesc.fDepthStencilAttachment.fTextureInfo = depthStencilInfo;
282     renderPassDesc.fDepthStencilAttachment.fLoadOp = LoadOp::kDiscard;
283     renderPassDesc.fDepthStencilAttachment.fStoreOp = StoreOp::kDiscard;
284     sk_sp<Texture> depthStencilTexture =
285             resourceProvider->findOrCreateTexture(textureSize, depthStencilInfo);
286 
287     // Create Sampler -- for now, just to test creation
288     sk_sp<Sampler> sampler = resourceProvider->findOrCreateCompatibleSampler(
289             SkSamplingOptions(SkFilterMode::kLinear), SkTileMode::kClamp, SkTileMode::kDecal);
290     REPORTER_ASSERT(reporter, sampler);
291 
292     commandBuffer->beginRenderPass(renderPassDesc, target->refTexture(), nullptr,
293                                    depthStencilTexture);
294 
295     commandBuffer->setViewport(0.f, 0.f, kTextureWidth, kTextureHeight);
296 
297     DrawWriter drawWriter(commandBuffer->asDrawDispatcher(), &bufferMgr);
298 
299     struct RectAndColor {
300         SkRect    fRect;
301         SkColor4f fColor;
302     };
303 
304     auto draw = [&](const RenderStep* step, std::vector<RectAndColor> draws) {
305         GraphicsPipelineDesc pipelineDesc;
306         pipelineDesc.setProgram(step, entry->uniqueID());
307         drawWriter.newPipelineState(step->primitiveType(),
308                                     step->vertexStride(),
309                                     step->instanceStride());
310         auto pipeline = resourceProvider->findOrCreateGraphicsPipeline(pipelineDesc,
311                                                                        renderPassDesc);
312         commandBuffer->bindGraphicsPipeline(std::move(pipeline));
313 
314         // All of the test RenderSteps ignore the transform, so just use the identity
315         static const Transform kIdentity{SkM44()};
316         // No set scissor, so use entire render target dimensions
317         static const SkIRect kBounds = SkIRect::MakeWH(kTextureWidth, kTextureHeight);
318 
319         for (auto d : draws) {
320             drawWriter.newDynamicState();
321             Shape shape(d.fRect);
322 
323             auto renderStepUniforms =
324                     step->writeUniforms(Layout::kMetal, kBounds, kIdentity, shape);
325             if (renderStepUniforms) {
326                 auto [writer, bindInfo] =
327                         bufferMgr.getUniformWriter(renderStepUniforms->dataSize());
328                 writer.write(renderStepUniforms->data(), renderStepUniforms->dataSize());
329                 commandBuffer->bindUniformBuffer(UniformSlot::kRenderStep,
330                                                  sk_ref_sp(bindInfo.fBuffer),
331                                                  bindInfo.fOffset);
332             }
333 
334             // TODO: Rely on uniform writer and GetUniforms(kSolidColor).
335             auto [writer, bindInfo] = bufferMgr.getUniformWriter(sizeof(SkColor4f));
336             writer.write(&d.fColor, sizeof(SkColor4f));
337             commandBuffer->bindUniformBuffer(UniformSlot::kPaint,
338                                              sk_ref_sp(bindInfo.fBuffer),
339                                              bindInfo.fOffset);
340 
341             step->writeVertices(&drawWriter, kBounds, kIdentity, shape);
342         }
343     };
344 
345     SkRect fullRect = SkRect::MakeIWH(kTextureWidth, kTextureHeight);
346     // Draw blue rectangle over entire rendertarget (which was red)
347     draw(UniformRectDraw::Singleton(), {{fullRect, SkColors::kBlue}});
348 
349     // Draw inset yellow rectangle using uniforms
350     draw(UniformRectDraw::Singleton(),
351          {{fullRect.makeInset(kTextureWidth/20.f, kTextureHeight/20.f), SkColors::kYellow}});
352 
353     // Draw inset magenta rectangle with triangles in vertex buffer
354     draw(TriangleRectDraw::Singleton(),
355          {{fullRect.makeInset(kTextureWidth/4.f, kTextureHeight/4.f), SkColors::kMagenta}});
356 
357     // Draw green and cyan rects using instance buffer
358     draw(InstanceRectDraw::Singleton(),
359          { {{kTextureWidth/3.f, kTextureHeight/3.f,
360              kTextureWidth/2.f, kTextureHeight/2.f}, SkColors::kGreen},
361            {{kTextureWidth/2.f, kTextureHeight/2.f,
362              5.f*kTextureWidth/8.f, 5.f*kTextureHeight/8.f}, SkColors::kCyan} });
363 
364     drawWriter.flush();
365     bufferMgr.transferToCommandBuffer(commandBuffer.get());
366     commandBuffer->endRenderPass();
367 
368     // Do readback
369 
370     // TODO: add 4-byte transfer buffer alignment for Mac to Caps
371     //       add bpp to Caps
372     size_t rowBytes = 4*kTextureWidth;
373     size_t bufferSize = rowBytes*kTextureHeight;
374     sk_sp<Buffer> copyBuffer = resourceProvider->findOrCreateBuffer(
375             bufferSize, BufferType::kXferGpuToCpu, PrioritizeGpuReads::kNo);
376     REPORTER_ASSERT(reporter, copyBuffer);
377     SkIRect srcRect = { 0, 0, kTextureWidth, kTextureHeight };
378     commandBuffer->copyTextureToBuffer(target->refTexture(), srcRect, copyBuffer, 0, rowBytes);
379 
380     bool result = gpu->submit(commandBuffer);
381     REPORTER_ASSERT(reporter, result);
382 
383     gpu->checkForFinishedWork(skgpu::SyncToCpu::kYes);
384     uint32_t* pixels = (uint32_t*)(copyBuffer->map());
385     REPORTER_ASSERT(reporter, pixels[0] == 0xffff0000);
386     REPORTER_ASSERT(reporter, pixels[51 + 38*kTextureWidth] == 0xff00ffff);
387     REPORTER_ASSERT(reporter, pixels[256 + 192*kTextureWidth] == 0xffff00ff);
388     copyBuffer->unmap();
389 
390 #if GRAPHITE_TEST_UTILS && CAPTURE_COMMANDBUFFER
391     gpu->testingOnly_endCapture();
392 #endif
393 }
394