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 27using namespace skgpu; 28 29/* 30 * This is to test the various pieces of the CommandBuffer interface. 31 */ 32DEF_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