| /* |
| * 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/Gpu.h" |
| #include "experimental/graphite/src/RenderPipeline.h" |
| #include "experimental/graphite/src/ResourceProvider.h" |
| #include "experimental/graphite/src/Texture.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 |
| }; |
| TextureInfo textureInfo(mtlTextureInfo); |
| #else |
| TextureInfo textureInfo; |
| #endif |
| |
| sk_sp<Texture> texture = gpu->resourceProvider()->findOrCreateTexture(textureSize, |
| textureInfo); |
| REPORTER_ASSERT(reporter, texture); |
| |
| RenderPassDesc renderPassDesc = {}; |
| renderPassDesc.fColorAttachment.fTexture = texture; |
| renderPassDesc.fColorAttachment.fLoadOp = LoadOp::kClear; |
| renderPassDesc.fColorAttachment.fStoreOp = StoreOp::kStore; |
| renderPassDesc.fClearColor = { 1, 0, 0, 1 }; // red |
| |
| commandBuffer->beginRenderPass(renderPassDesc); |
| |
| // 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) |
| RenderPipelineDesc pipelineDesc; |
| pipelineDesc.setTestingOnlyShaderIndex(0); |
| auto renderPipeline = gpu->resourceProvider()->findOrCreateRenderPipeline(pipelineDesc); |
| commandBuffer->bindRenderPipeline(std::move(renderPipeline)); |
| commandBuffer->draw(PrimitiveType::kTriangleStrip, 0, 4); |
| |
| // Draw inset yellow rectangle using uniforms |
| pipelineDesc.setTestingOnlyShaderIndex(1); |
| renderPipeline = gpu->resourceProvider()->findOrCreateRenderPipeline(pipelineDesc); |
| commandBuffer->bindRenderPipeline(std::move(renderPipeline)); |
| 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(uniformBuffer, uniformOffset); |
| commandBuffer->draw(PrimitiveType::kTriangleStrip, 0, 4); |
| uniformOffset += sizeof(UniformData); |
| ++uniforms; |
| |
| // Draw inset magenta rectangle with triangles in vertex buffer |
| pipelineDesc.setTestingOnlyShaderIndex(2); |
| skgpu::RenderPipelineDesc::Attribute vertexAttributes[1] = { |
| { "position", VertexAttribType::kFloat2, SLType::kFloat2 } |
| }; |
| pipelineDesc.setVertexAttributes(vertexAttributes, 1); |
| renderPipeline = gpu->resourceProvider()->findOrCreateRenderPipeline(pipelineDesc); |
| commandBuffer->bindRenderPipeline(std::move(renderPipeline)); |
| |
| struct VertexData { |
| SkPoint fPosition; |
| }; |
| sk_sp<Buffer> vertexBuffer = gpu->resourceProvider()->findOrCreateBuffer( |
| 4*sizeof(VertexData), BufferType::kVertex, PrioritizeGpuReads::kNo); |
| sk_sp<Buffer> indexBuffer = gpu->resourceProvider()->findOrCreateBuffer( |
| 6*sizeof(uint16_t), BufferType::kIndex, PrioritizeGpuReads::kNo); |
| auto vertices = (VertexData*)vertexBuffer->map(); |
| vertices[0].fPosition = SkPoint({0.25f, 0.25f}); |
| vertices[1].fPosition = SkPoint({0.25f, 0.75f}); |
| vertices[2].fPosition = SkPoint({0.75f, 0.25f}); |
| vertices[3].fPosition = SkPoint({0.75f, 0.75f}); |
| vertexBuffer->unmap(); |
| auto indices = (uint16_t*)indexBuffer->map(); |
| indices[0] = 0; |
| indices[1] = 1; |
| indices[2] = 2; |
| indices[3] = 2; |
| indices[4] = 1; |
| indices[5] = 3; |
| indexBuffer->unmap(); |
| commandBuffer->bindVertexBuffers(vertexBuffer, nullptr); |
| commandBuffer->bindIndexBuffer(indexBuffer, 0); |
| uniforms->fScale = SkPoint({2, 2}); |
| uniforms->fTranslate = SkPoint({-1, -1}); |
| uniforms->fColor = SkColors::kMagenta; |
| commandBuffer->bindUniformBuffer(uniformBuffer, uniformOffset); |
| commandBuffer->drawIndexed(PrimitiveType::kTriangles, 0, 6, 0); |
| |
| // draw rects using instance buffer |
| pipelineDesc.setTestingOnlyShaderIndex(3); |
| skgpu::RenderPipelineDesc::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); |
| renderPipeline = gpu->resourceProvider()->findOrCreateRenderPipeline(pipelineDesc); |
| commandBuffer->bindRenderPipeline(std::move(renderPipeline)); |
| |
| struct InstanceData { |
| SkPoint fPosition; |
| SkPoint fDims; |
| SkColor4f fColor; |
| }; |
| sk_sp<Buffer> instanceBuffer = gpu->resourceProvider()->findOrCreateBuffer( |
| 2*sizeof(InstanceData), BufferType::kVertex, PrioritizeGpuReads::kNo); |
| auto instances = (InstanceData*)instanceBuffer->map(); |
| instances[0].fPosition = SkPoint({-0.4, -0.4}); |
| instances[0].fDims = SkPoint({0.4, 0.4}); |
| instances[0].fColor = SkColors::kGreen; |
| instances[1].fPosition = SkPoint({0, 0}); |
| instances[1].fDims = SkPoint({0.25, 0.25}); |
| instances[1].fColor = SkColors::kCyan; |
| instanceBuffer->unmap(); |
| commandBuffer->bindVertexBuffers(nullptr, instanceBuffer); |
| // commandBuffer->drawInstanced(PrimitiveType::kTriangleStrip, 0, 4, 0, 2); |
| commandBuffer->drawIndexedInstanced(PrimitiveType::kTriangles, 0, 6, 0, 0, 2); |
| |
| commandBuffer->endRenderPass(); |
| |
| uniformBuffer->unmap(); |
| |
| // 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(texture, 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 |
| } |