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/src/ContextPriv.h"
12
13 #include "experimental/graphite/include/mtl/MtlTypes.h"
14 #include "experimental/graphite/src/Buffer.h"
15 #include "experimental/graphite/src/CommandBuffer.h"
16 #include "experimental/graphite/src/Gpu.h"
17 #include "experimental/graphite/src/GraphicsPipeline.h"
18 #include "experimental/graphite/src/ResourceProvider.h"
19 #include "experimental/graphite/src/Texture.h"
20 #include "experimental/graphite/src/TextureProxy.h"
21
22 #if GRAPHITE_TEST_UTILS
23 // set to 1 if you want to do GPU capture of the commandBuffer
24 #define CAPTURE_COMMANDBUFFER 0
25 #endif
26
27 using namespace skgpu;
28
29 /*
30 * This is to test the various pieces of the CommandBuffer interface.
31 */
DEF_GRAPHITE_TEST_FOR_CONTEXTS(CommandBufferTest,reporter,context)32 DEF_GRAPHITE_TEST_FOR_CONTEXTS(CommandBufferTest, reporter, context) {
33 constexpr int kTextureWidth = 1024;
34 constexpr int kTextureHeight = 768;
35
36 auto gpu = context->priv().gpu();
37 REPORTER_ASSERT(reporter, gpu);
38
39 #if GRAPHITE_TEST_UTILS && CAPTURE_COMMANDBUFFER
40 gpu->testingOnly_startCapture();
41 #endif
42 auto commandBuffer = gpu->resourceProvider()->createCommandBuffer();
43
44 SkISize textureSize = { kTextureWidth, kTextureHeight };
45 #ifdef SK_METAL
46 skgpu::mtl::TextureInfo mtlTextureInfo = {
47 1,
48 1,
49 70, // MTLPixelFormatRGBA8Unorm
50 0x0005, // MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead
51 2, // MTLStorageModePrivate
52 false, // framebufferOnly
53 };
54 TextureInfo textureInfo(mtlTextureInfo);
55 #else
56 TextureInfo textureInfo;
57 #endif
58
59 auto target = sk_sp<TextureProxy>(new TextureProxy(textureSize, textureInfo));
60 REPORTER_ASSERT(reporter, target);
61
62 RenderPassDesc renderPassDesc = {};
63 renderPassDesc.fColorAttachment.fTextureProxy = target;
64 renderPassDesc.fColorAttachment.fLoadOp = LoadOp::kClear;
65 renderPassDesc.fColorAttachment.fStoreOp = StoreOp::kStore;
66 renderPassDesc.fClearColor = { 1, 0, 0, 1 }; // red
67
68 target->instantiate(gpu->resourceProvider());
69 commandBuffer->beginRenderPass(renderPassDesc);
70
71 // Shared uniform buffer
72 struct UniformData {
73 SkPoint fScale;
74 SkPoint fTranslate;
75 SkColor4f fColor;
76 };
77 sk_sp<Buffer> uniformBuffer = gpu->resourceProvider()->findOrCreateBuffer(
78 2*sizeof(UniformData), BufferType::kUniform, PrioritizeGpuReads::kNo);
79 size_t uniformOffset = 0;
80
81 // Draw blue rectangle over entire rendertarget (which was red)
82 GraphicsPipelineDesc pipelineDesc;
83 pipelineDesc.setTestingOnlyShaderIndex(0);
84 auto graphicsPipeline = gpu->resourceProvider()->findOrCreateGraphicsPipeline(pipelineDesc);
85 commandBuffer->bindGraphicsPipeline(std::move(graphicsPipeline));
86 commandBuffer->draw(PrimitiveType::kTriangleStrip, 0, 4);
87
88 // Draw inset yellow rectangle using uniforms
89 pipelineDesc.setTestingOnlyShaderIndex(1);
90 graphicsPipeline = gpu->resourceProvider()->findOrCreateGraphicsPipeline(pipelineDesc);
91 commandBuffer->bindGraphicsPipeline(std::move(graphicsPipeline));
92 UniformData* uniforms = (UniformData*)uniformBuffer->map();
93 uniforms->fScale = SkPoint({1.8, 1.8});
94 uniforms->fTranslate = SkPoint({-0.9, -0.9});
95 uniforms->fColor = SkColors::kYellow;
96 commandBuffer->bindUniformBuffer(uniformBuffer, uniformOffset);
97 commandBuffer->draw(PrimitiveType::kTriangleStrip, 0, 4);
98 uniformOffset += sizeof(UniformData);
99 ++uniforms;
100
101 // Draw inset magenta rectangle with triangles in vertex buffer
102 pipelineDesc.setTestingOnlyShaderIndex(2);
103 skgpu::GraphicsPipelineDesc::Attribute vertexAttributes[1] = {
104 { "position", VertexAttribType::kFloat2, SLType::kFloat2 }
105 };
106 pipelineDesc.setVertexAttributes(vertexAttributes, 1);
107 graphicsPipeline = gpu->resourceProvider()->findOrCreateGraphicsPipeline(pipelineDesc);
108 commandBuffer->bindGraphicsPipeline(std::move(graphicsPipeline));
109
110 struct VertexData {
111 SkPoint fPosition;
112 };
113 sk_sp<Buffer> vertexBuffer = gpu->resourceProvider()->findOrCreateBuffer(
114 4*sizeof(VertexData), BufferType::kVertex, PrioritizeGpuReads::kNo);
115 sk_sp<Buffer> indexBuffer = gpu->resourceProvider()->findOrCreateBuffer(
116 6*sizeof(uint16_t), BufferType::kIndex, PrioritizeGpuReads::kNo);
117 auto vertices = (VertexData*)vertexBuffer->map();
118 vertices[0].fPosition = SkPoint({0.25f, 0.25f});
119 vertices[1].fPosition = SkPoint({0.25f, 0.75f});
120 vertices[2].fPosition = SkPoint({0.75f, 0.25f});
121 vertices[3].fPosition = SkPoint({0.75f, 0.75f});
122 vertexBuffer->unmap();
123 auto indices = (uint16_t*)indexBuffer->map();
124 indices[0] = 0;
125 indices[1] = 1;
126 indices[2] = 2;
127 indices[3] = 2;
128 indices[4] = 1;
129 indices[5] = 3;
130 indexBuffer->unmap();
131 commandBuffer->bindVertexBuffers(vertexBuffer, 0, nullptr, 0);
132 commandBuffer->bindIndexBuffer(indexBuffer, 0);
133 uniforms->fScale = SkPoint({2, 2});
134 uniforms->fTranslate = SkPoint({-1, -1});
135 uniforms->fColor = SkColors::kMagenta;
136 commandBuffer->bindUniformBuffer(uniformBuffer, uniformOffset);
137 commandBuffer->drawIndexed(PrimitiveType::kTriangles, 0, 6, 0);
138
139 // draw rects using instance buffer
140 pipelineDesc.setTestingOnlyShaderIndex(3);
141 skgpu::GraphicsPipelineDesc::Attribute instanceAttributes[3] = {
142 { "position", VertexAttribType::kFloat2, SLType::kFloat2 },
143 { "dims", VertexAttribType::kFloat2, SLType::kFloat2 },
144 { "color", VertexAttribType::kFloat4, SLType::kFloat4 }
145 };
146 pipelineDesc.setVertexAttributes(nullptr, 0);
147 pipelineDesc.setInstanceAttributes(instanceAttributes, 3);
148 graphicsPipeline = gpu->resourceProvider()->findOrCreateGraphicsPipeline(pipelineDesc);
149 commandBuffer->bindGraphicsPipeline(std::move(graphicsPipeline));
150
151 struct InstanceData {
152 SkPoint fPosition;
153 SkPoint fDims;
154 SkColor4f fColor;
155 };
156 sk_sp<Buffer> instanceBuffer = gpu->resourceProvider()->findOrCreateBuffer(
157 2*sizeof(InstanceData), BufferType::kVertex, PrioritizeGpuReads::kNo);
158 auto instances = (InstanceData*)instanceBuffer->map();
159 instances[0].fPosition = SkPoint({-0.4, -0.4});
160 instances[0].fDims = SkPoint({0.4, 0.4});
161 instances[0].fColor = SkColors::kGreen;
162 instances[1].fPosition = SkPoint({0, 0});
163 instances[1].fDims = SkPoint({0.25, 0.25});
164 instances[1].fColor = SkColors::kCyan;
165 instanceBuffer->unmap();
166 commandBuffer->bindVertexBuffers(nullptr, 0, instanceBuffer, 0);
167 // commandBuffer->drawInstanced(PrimitiveType::kTriangleStrip, 0, 4, 0, 2);
168 commandBuffer->drawIndexedInstanced(PrimitiveType::kTriangles, 0, 6, 0, 0, 2);
169
170 commandBuffer->endRenderPass();
171
172 uniformBuffer->unmap();
173
174 // Do readback
175
176 // TODO: add 4-byte transfer buffer alignment for Mac to Caps
177 // add bpp to Caps
178 size_t rowBytes = 4*kTextureWidth;
179 size_t bufferSize = rowBytes*kTextureHeight;
180 sk_sp<Buffer> copyBuffer = gpu->resourceProvider()->findOrCreateBuffer(
181 bufferSize, BufferType::kXferGpuToCpu, PrioritizeGpuReads::kNo);
182 REPORTER_ASSERT(reporter, copyBuffer);
183 SkIRect srcRect = { 0, 0, kTextureWidth, kTextureHeight };
184 commandBuffer->copyTextureToBuffer(target->refTexture(), srcRect, copyBuffer, 0, rowBytes);
185
186 bool result = gpu->submit(commandBuffer);
187 REPORTER_ASSERT(reporter, result);
188
189 gpu->checkForFinishedWork(skgpu::SyncToCpu::kYes);
190 uint32_t* pixels = (uint32_t*)(copyBuffer->map());
191 REPORTER_ASSERT(reporter, pixels[0] == 0xffff0000);
192 REPORTER_ASSERT(reporter, pixels[51 + 38*kTextureWidth] == 0xff00ffff);
193 REPORTER_ASSERT(reporter, pixels[256 + 192*kTextureWidth] == 0xffff00ff);
194 copyBuffer->unmap();
195
196 #if GRAPHITE_TEST_UTILS && CAPTURE_COMMANDBUFFER
197 gpu->testingOnly_endCapture();
198 #endif
199 }
200