blob: 1027d27ade3048c72e1c9464bfd459f761d4e8db [file] [log] [blame]
/*
* Copyright 2021 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "tests/Test.h"
#include "experimental/graphite/include/Context.h"
#include "experimental/graphite/src/ContextPriv.h"
#include "experimental/graphite/include/mtl/MtlTypes.h"
#include "experimental/graphite/src/Buffer.h"
#include "experimental/graphite/src/CommandBuffer.h"
#include "experimental/graphite/src/DrawBufferManager.h"
#include "experimental/graphite/src/DrawWriter.h"
#include "experimental/graphite/src/Gpu.h"
#include "experimental/graphite/src/GraphicsPipeline.h"
#include "experimental/graphite/src/ResourceProvider.h"
#include "experimental/graphite/src/Texture.h"
#include "experimental/graphite/src/TextureProxy.h"
#if GRAPHITE_TEST_UTILS
// set to 1 if you want to do GPU capture of the commandBuffer
#define CAPTURE_COMMANDBUFFER 0
#endif
using namespace skgpu;
/*
* This is to test the various pieces of the CommandBuffer interface.
*/
DEF_GRAPHITE_TEST_FOR_CONTEXTS(CommandBufferTest, reporter, context) {
constexpr int kTextureWidth = 1024;
constexpr int kTextureHeight = 768;
auto gpu = context->priv().gpu();
REPORTER_ASSERT(reporter, gpu);
#if GRAPHITE_TEST_UTILS && CAPTURE_COMMANDBUFFER
gpu->testingOnly_startCapture();
#endif
auto commandBuffer = gpu->resourceProvider()->createCommandBuffer();
SkISize textureSize = { kTextureWidth, kTextureHeight };
#ifdef SK_METAL
skgpu::mtl::TextureInfo mtlTextureInfo = {
1,
1,
70, // MTLPixelFormatRGBA8Unorm
0x0005, // MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead
2, // MTLStorageModePrivate
false, // framebufferOnly
};
TextureInfo textureInfo(mtlTextureInfo);
#else
TextureInfo textureInfo;
#endif
auto target = sk_sp<TextureProxy>(new TextureProxy(textureSize, textureInfo));
REPORTER_ASSERT(reporter, target);
RenderPassDesc renderPassDesc = {};
renderPassDesc.fColorAttachment.fTextureProxy = target;
renderPassDesc.fColorAttachment.fLoadOp = LoadOp::kClear;
renderPassDesc.fColorAttachment.fStoreOp = StoreOp::kStore;
renderPassDesc.fClearColor = { 1, 0, 0, 1 }; // red
target->instantiate(gpu->resourceProvider());
DrawBufferManager bufferMgr(gpu->resourceProvider(), 4);
commandBuffer->beginRenderPass(renderPassDesc);
DrawWriter drawWriter(commandBuffer->asDrawDispatcher(), &bufferMgr);
// Shared uniform buffer
struct UniformData {
SkPoint fScale;
SkPoint fTranslate;
SkColor4f fColor;
};
sk_sp<Buffer> uniformBuffer = gpu->resourceProvider()->findOrCreateBuffer(
2*sizeof(UniformData), BufferType::kUniform, PrioritizeGpuReads::kNo);
size_t uniformOffset = 0;
// Draw blue rectangle over entire rendertarget (which was red)
GraphicsPipelineDesc pipelineDesc;
pipelineDesc.setTestingOnlyShaderIndex(0);
auto graphicsPipeline = gpu->resourceProvider()->findOrCreateGraphicsPipeline(pipelineDesc);
drawWriter.newPipelineState(PrimitiveType::kTriangleStrip,
pipelineDesc.vertexStride(),
pipelineDesc.instanceStride());
commandBuffer->bindGraphicsPipeline(std::move(graphicsPipeline));
drawWriter.draw({}, {}, 4);
// Draw inset yellow rectangle using uniforms
pipelineDesc.setTestingOnlyShaderIndex(1);
graphicsPipeline = gpu->resourceProvider()->findOrCreateGraphicsPipeline(pipelineDesc);
drawWriter.newPipelineState(PrimitiveType::kTriangleStrip,
pipelineDesc.vertexStride(),
pipelineDesc.instanceStride());
commandBuffer->bindGraphicsPipeline(std::move(graphicsPipeline));
UniformData* uniforms = (UniformData*)uniformBuffer->map();
uniforms->fScale = SkPoint({1.8, 1.8});
uniforms->fTranslate = SkPoint({-0.9, -0.9});
uniforms->fColor = SkColors::kYellow;
commandBuffer->bindUniformBuffer(UniformSlot::kRenderStep, uniformBuffer, uniformOffset);
drawWriter.draw({}, {}, 4);
uniformOffset += sizeof(UniformData);
++uniforms;
// Draw inset magenta rectangle with triangles in vertex buffer
pipelineDesc.setTestingOnlyShaderIndex(2);
Attribute vertexAttributes[1] = {
{ "position", VertexAttribType::kFloat2, SLType::kFloat2 }
};
pipelineDesc.setVertexAttributes(vertexAttributes, 1);
graphicsPipeline = gpu->resourceProvider()->findOrCreateGraphicsPipeline(pipelineDesc);
drawWriter.newPipelineState(PrimitiveType::kTriangles,
pipelineDesc.vertexStride(),
pipelineDesc.instanceStride());
commandBuffer->bindGraphicsPipeline(std::move(graphicsPipeline));
auto [vertexWriter, vertices] = bufferMgr.getVertexWriter(4 * pipelineDesc.vertexStride());
vertexWriter << SkPoint{0.25f, 0.25f}
<< SkPoint{0.25f, 0.75f}
<< SkPoint{0.75f, 0.25f}
<< SkPoint{0.75f, 0.75f};
auto [indexWriter, indices] = bufferMgr.getIndexWriter(6 * sizeof(uint16_t));
indexWriter << 0 << 1 << 2
<< 2 << 1 << 3;
uniforms->fScale = SkPoint({2, 2});
uniforms->fTranslate = SkPoint({-1, -1});
uniforms->fColor = SkColors::kMagenta;
commandBuffer->bindUniformBuffer(UniformSlot::kRenderStep, uniformBuffer, uniformOffset);
drawWriter.draw(vertices, indices, 6);
// draw rects using instance buffer
pipelineDesc.setTestingOnlyShaderIndex(3);
Attribute instanceAttributes[3] = {
{ "position", VertexAttribType::kFloat2, SLType::kFloat2 },
{ "dims", VertexAttribType::kFloat2, SLType::kFloat2 },
{ "color", VertexAttribType::kFloat4, SLType::kFloat4 }
};
pipelineDesc.setVertexAttributes(nullptr, 0);
pipelineDesc.setInstanceAttributes(instanceAttributes, 3);
graphicsPipeline = gpu->resourceProvider()->findOrCreateGraphicsPipeline(pipelineDesc);
drawWriter.newPipelineState(PrimitiveType::kTriangles,
pipelineDesc.vertexStride(),
pipelineDesc.instanceStride());
commandBuffer->bindGraphicsPipeline(std::move(graphicsPipeline));
drawWriter.setInstanceTemplate({}, indices, 6);
auto instanceWriter = drawWriter.appendInstances(2);
instanceWriter << SkPoint{-0.4f, -0.4f} << SkPoint{0.4f, 0.4f} << SkColors::kGreen
<< SkPoint{0.f, 0.f} << SkPoint{0.25f, 0.25f} << SkColors::kCyan;
drawWriter.flush();
uniformBuffer->unmap();
bufferMgr.transferToCommandBuffer(commandBuffer.get());
commandBuffer->endRenderPass();
// Do readback
// TODO: add 4-byte transfer buffer alignment for Mac to Caps
// add bpp to Caps
size_t rowBytes = 4*kTextureWidth;
size_t bufferSize = rowBytes*kTextureHeight;
sk_sp<Buffer> copyBuffer = gpu->resourceProvider()->findOrCreateBuffer(
bufferSize, BufferType::kXferGpuToCpu, PrioritizeGpuReads::kNo);
REPORTER_ASSERT(reporter, copyBuffer);
SkIRect srcRect = { 0, 0, kTextureWidth, kTextureHeight };
commandBuffer->copyTextureToBuffer(target->refTexture(), srcRect, copyBuffer, 0, rowBytes);
bool result = gpu->submit(commandBuffer);
REPORTER_ASSERT(reporter, result);
gpu->checkForFinishedWork(skgpu::SyncToCpu::kYes);
uint32_t* pixels = (uint32_t*)(copyBuffer->map());
REPORTER_ASSERT(reporter, pixels[0] == 0xffff0000);
REPORTER_ASSERT(reporter, pixels[51 + 38*kTextureWidth] == 0xff00ffff);
REPORTER_ASSERT(reporter, pixels[256 + 192*kTextureWidth] == 0xffff00ff);
copyBuffer->unmap();
#if GRAPHITE_TEST_UTILS && CAPTURE_COMMANDBUFFER
gpu->testingOnly_endCapture();
#endif
}