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