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 "experimental/graphite/src/mtl/MtlGraphicsPipeline.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "experimental/graphite/src/GraphicsPipelineDesc.h" 11cb93a386Sopenharmony_ci#include "experimental/graphite/src/mtl/MtlGpu.h" 12cb93a386Sopenharmony_ci#include "experimental/graphite/src/mtl/MtlUtils.h" 13cb93a386Sopenharmony_ci#include "include/private/SkSLString.h" 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_cinamespace skgpu::mtl { 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_cistatic const char* kTestingOnlyShaders[] = { 18cb93a386Sopenharmony_ci // clear viewport to blue 19cb93a386Sopenharmony_ci "#include <metal_stdlib>\n" 20cb93a386Sopenharmony_ci "#include <simd/simd.h>\n" 21cb93a386Sopenharmony_ci "using namespace metal;\n" 22cb93a386Sopenharmony_ci "\n" 23cb93a386Sopenharmony_ci "typedef struct {\n" 24cb93a386Sopenharmony_ci " float4 position [[position]];\n" 25cb93a386Sopenharmony_ci "} VertexOutput;\n" 26cb93a386Sopenharmony_ci "\n" 27cb93a386Sopenharmony_ci "vertex VertexOutput vertexMain(uint vertexID [[vertex_id]]) {\n" 28cb93a386Sopenharmony_ci " VertexOutput out;\n" 29cb93a386Sopenharmony_ci " float2 position = float2(float(vertexID >> 1), float(vertexID & 1));\n" 30cb93a386Sopenharmony_ci " out.position.xy = position * 2 - 1;\n" 31cb93a386Sopenharmony_ci " out.position.zw = float2(0.0, 1.0);\n" 32cb93a386Sopenharmony_ci " return out;\n" 33cb93a386Sopenharmony_ci "}\n" 34cb93a386Sopenharmony_ci "\n" 35cb93a386Sopenharmony_ci "fragment float4 fragmentMain(VertexOutput in [[stage_in]]) {\n" 36cb93a386Sopenharmony_ci " return float4(0.0, 0.0, 1.0, 1.0);\n" 37cb93a386Sopenharmony_ci "}", 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci // clear subarea to given color, using uniform buffer 40cb93a386Sopenharmony_ci "#include <metal_stdlib>\n" 41cb93a386Sopenharmony_ci "#include <simd/simd.h>\n" 42cb93a386Sopenharmony_ci "using namespace metal;\n" 43cb93a386Sopenharmony_ci "\n" 44cb93a386Sopenharmony_ci "typedef struct {\n" 45cb93a386Sopenharmony_ci " float4 position [[position]];\n" 46cb93a386Sopenharmony_ci "} VertexOutput;\n" 47cb93a386Sopenharmony_ci "\n" 48cb93a386Sopenharmony_ci "typedef struct {\n" 49cb93a386Sopenharmony_ci " float4 uPosXform;\n" 50cb93a386Sopenharmony_ci " float4 uColor;\n" 51cb93a386Sopenharmony_ci "} UniformData;\n" 52cb93a386Sopenharmony_ci "\n" 53cb93a386Sopenharmony_ci "vertex VertexOutput vertexMain(constant UniformData& uniforms [[buffer(0)]],\n" 54cb93a386Sopenharmony_ci " uint vertexID [[vertex_id]]) {\n" 55cb93a386Sopenharmony_ci " VertexOutput out;\n" 56cb93a386Sopenharmony_ci " float2 position = float2(float(vertexID >> 1), float(vertexID & 1));\n" 57cb93a386Sopenharmony_ci " out.position.xy = position * uniforms.uPosXform.xy + uniforms.uPosXform.zw;\n" 58cb93a386Sopenharmony_ci " out.position.zw = float2(0.0, 1.0);\n" 59cb93a386Sopenharmony_ci " return out;\n" 60cb93a386Sopenharmony_ci "}\n" 61cb93a386Sopenharmony_ci "\n" 62cb93a386Sopenharmony_ci "fragment float4 fragmentMain(constant UniformData& uniforms [[buffer(0)]],\n" 63cb93a386Sopenharmony_ci " VertexOutput in [[stage_in]]) {\n" 64cb93a386Sopenharmony_ci " return uniforms.uColor;\n" 65cb93a386Sopenharmony_ci "}", 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci // draw triangles with given color, using uniform buffer and vertex data 68cb93a386Sopenharmony_ci "#include <metal_stdlib>\n" 69cb93a386Sopenharmony_ci "#include <simd/simd.h>\n" 70cb93a386Sopenharmony_ci "using namespace metal;\n" 71cb93a386Sopenharmony_ci "\n" 72cb93a386Sopenharmony_ci "typedef struct {\n" 73cb93a386Sopenharmony_ci " float2 position [[attribute(0)]];\n" 74cb93a386Sopenharmony_ci "} VertexInput;\n" 75cb93a386Sopenharmony_ci "\n" 76cb93a386Sopenharmony_ci "typedef struct {\n" 77cb93a386Sopenharmony_ci " float4 position [[position]];\n" 78cb93a386Sopenharmony_ci "} VertexOutput;\n" 79cb93a386Sopenharmony_ci "\n" 80cb93a386Sopenharmony_ci "typedef struct {\n" 81cb93a386Sopenharmony_ci " float4 uPosXform;\n" 82cb93a386Sopenharmony_ci " float4 uColor;\n" 83cb93a386Sopenharmony_ci "} UniformData;\n" 84cb93a386Sopenharmony_ci "\n" 85cb93a386Sopenharmony_ci "vertex VertexOutput vertexMain(VertexInput in [[stage_in]],\n" 86cb93a386Sopenharmony_ci " constant UniformData& uniforms [[buffer(0)]],\n" 87cb93a386Sopenharmony_ci " uint vertexID [[vertex_id]]) {\n" 88cb93a386Sopenharmony_ci " VertexOutput out;\n" 89cb93a386Sopenharmony_ci " float2 position = in.position;\n" 90cb93a386Sopenharmony_ci " out.position.xy = position * uniforms.uPosXform.xy + uniforms.uPosXform.zw;\n" 91cb93a386Sopenharmony_ci " out.position.zw = float2(0.0, 1.0);\n" 92cb93a386Sopenharmony_ci " return out;\n" 93cb93a386Sopenharmony_ci "}\n" 94cb93a386Sopenharmony_ci "\n" 95cb93a386Sopenharmony_ci "fragment float4 fragmentMain(constant UniformData& uniforms [[buffer(0)]],\n" 96cb93a386Sopenharmony_ci " VertexOutput in [[stage_in]]) {\n" 97cb93a386Sopenharmony_ci " return uniforms.uColor;\n" 98cb93a386Sopenharmony_ci "}", 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_ci // draw triangles with vertex ID and instance buffer 101cb93a386Sopenharmony_ci "#include <metal_stdlib>\n" 102cb93a386Sopenharmony_ci "#include <simd/simd.h>\n" 103cb93a386Sopenharmony_ci "using namespace metal;\n" 104cb93a386Sopenharmony_ci "\n" 105cb93a386Sopenharmony_ci "typedef struct {\n" 106cb93a386Sopenharmony_ci " float2 position [[attribute(0)]];\n" 107cb93a386Sopenharmony_ci " float2 dims [[attribute(1)]];\n" 108cb93a386Sopenharmony_ci " float4 color [[attribute(2)]];\n" 109cb93a386Sopenharmony_ci "} InstanceInput;\n" 110cb93a386Sopenharmony_ci "\n" 111cb93a386Sopenharmony_ci "typedef struct {\n" 112cb93a386Sopenharmony_ci " float4 position [[position]];\n" 113cb93a386Sopenharmony_ci " float4 color;\n" 114cb93a386Sopenharmony_ci "} VertexOutput;\n" 115cb93a386Sopenharmony_ci "\n" 116cb93a386Sopenharmony_ci "vertex VertexOutput vertexMain(InstanceInput in [[stage_in]],\n" 117cb93a386Sopenharmony_ci " uint vertexID [[vertex_id]]) {\n" 118cb93a386Sopenharmony_ci " VertexOutput out;\n" 119cb93a386Sopenharmony_ci " float2 position = float2(float(vertexID >> 1), float(vertexID & 1));\n" 120cb93a386Sopenharmony_ci " out.position.xy = position * in.dims + in.position;\n" 121cb93a386Sopenharmony_ci " out.position.zw = float2(0.0, 1.0);\n" 122cb93a386Sopenharmony_ci " out.color = in.color;" 123cb93a386Sopenharmony_ci " return out;\n" 124cb93a386Sopenharmony_ci "}\n" 125cb93a386Sopenharmony_ci "\n" 126cb93a386Sopenharmony_ci "fragment float4 fragmentMain(VertexOutput in [[stage_in]]) {\n" 127cb93a386Sopenharmony_ci " return in.color;\n" 128cb93a386Sopenharmony_ci "}", 129cb93a386Sopenharmony_ci}; 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_cistatic constexpr NSString* kTestingOnlyShaderLabels[] = { 132cb93a386Sopenharmony_ci @"Clear viewport to blue", 133cb93a386Sopenharmony_ci @"Clear rect with uniforms", 134cb93a386Sopenharmony_ci @"Draw triangles with uniform color", 135cb93a386Sopenharmony_ci @"Draw triangles with instance buffer" 136cb93a386Sopenharmony_ci}; 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_cistatic inline MTLVertexFormat attribute_type_to_mtlformat(VertexAttribType type) { 139cb93a386Sopenharmony_ci switch (type) { 140cb93a386Sopenharmony_ci case VertexAttribType::kFloat: 141cb93a386Sopenharmony_ci return MTLVertexFormatFloat; 142cb93a386Sopenharmony_ci case VertexAttribType::kFloat2: 143cb93a386Sopenharmony_ci return MTLVertexFormatFloat2; 144cb93a386Sopenharmony_ci case VertexAttribType::kFloat3: 145cb93a386Sopenharmony_ci return MTLVertexFormatFloat3; 146cb93a386Sopenharmony_ci case VertexAttribType::kFloat4: 147cb93a386Sopenharmony_ci return MTLVertexFormatFloat4; 148cb93a386Sopenharmony_ci case VertexAttribType::kHalf: 149cb93a386Sopenharmony_ci if (@available(macOS 10.13, iOS 11.0, *)) { 150cb93a386Sopenharmony_ci return MTLVertexFormatHalf; 151cb93a386Sopenharmony_ci } else { 152cb93a386Sopenharmony_ci return MTLVertexFormatInvalid; 153cb93a386Sopenharmony_ci } 154cb93a386Sopenharmony_ci case VertexAttribType::kHalf2: 155cb93a386Sopenharmony_ci return MTLVertexFormatHalf2; 156cb93a386Sopenharmony_ci case VertexAttribType::kHalf4: 157cb93a386Sopenharmony_ci return MTLVertexFormatHalf4; 158cb93a386Sopenharmony_ci case VertexAttribType::kInt2: 159cb93a386Sopenharmony_ci return MTLVertexFormatInt2; 160cb93a386Sopenharmony_ci case VertexAttribType::kInt3: 161cb93a386Sopenharmony_ci return MTLVertexFormatInt3; 162cb93a386Sopenharmony_ci case VertexAttribType::kInt4: 163cb93a386Sopenharmony_ci return MTLVertexFormatInt4; 164cb93a386Sopenharmony_ci case VertexAttribType::kByte: 165cb93a386Sopenharmony_ci if (@available(macOS 10.13, iOS 11.0, *)) { 166cb93a386Sopenharmony_ci return MTLVertexFormatChar; 167cb93a386Sopenharmony_ci } else { 168cb93a386Sopenharmony_ci return MTLVertexFormatInvalid; 169cb93a386Sopenharmony_ci } 170cb93a386Sopenharmony_ci case VertexAttribType::kByte2: 171cb93a386Sopenharmony_ci return MTLVertexFormatChar2; 172cb93a386Sopenharmony_ci case VertexAttribType::kByte4: 173cb93a386Sopenharmony_ci return MTLVertexFormatChar4; 174cb93a386Sopenharmony_ci case VertexAttribType::kUByte: 175cb93a386Sopenharmony_ci if (@available(macOS 10.13, iOS 11.0, *)) { 176cb93a386Sopenharmony_ci return MTLVertexFormatUChar; 177cb93a386Sopenharmony_ci } else { 178cb93a386Sopenharmony_ci return MTLVertexFormatInvalid; 179cb93a386Sopenharmony_ci } 180cb93a386Sopenharmony_ci case VertexAttribType::kUByte2: 181cb93a386Sopenharmony_ci return MTLVertexFormatUChar2; 182cb93a386Sopenharmony_ci case VertexAttribType::kUByte4: 183cb93a386Sopenharmony_ci return MTLVertexFormatUChar4; 184cb93a386Sopenharmony_ci case VertexAttribType::kUByte_norm: 185cb93a386Sopenharmony_ci if (@available(macOS 10.13, iOS 11.0, *)) { 186cb93a386Sopenharmony_ci return MTLVertexFormatUCharNormalized; 187cb93a386Sopenharmony_ci } else { 188cb93a386Sopenharmony_ci return MTLVertexFormatInvalid; 189cb93a386Sopenharmony_ci } 190cb93a386Sopenharmony_ci case VertexAttribType::kUByte4_norm: 191cb93a386Sopenharmony_ci return MTLVertexFormatUChar4Normalized; 192cb93a386Sopenharmony_ci case VertexAttribType::kShort2: 193cb93a386Sopenharmony_ci return MTLVertexFormatShort2; 194cb93a386Sopenharmony_ci case VertexAttribType::kShort4: 195cb93a386Sopenharmony_ci return MTLVertexFormatShort4; 196cb93a386Sopenharmony_ci case VertexAttribType::kUShort2: 197cb93a386Sopenharmony_ci return MTLVertexFormatUShort2; 198cb93a386Sopenharmony_ci case VertexAttribType::kUShort2_norm: 199cb93a386Sopenharmony_ci return MTLVertexFormatUShort2Normalized; 200cb93a386Sopenharmony_ci case VertexAttribType::kInt: 201cb93a386Sopenharmony_ci return MTLVertexFormatInt; 202cb93a386Sopenharmony_ci case VertexAttribType::kUInt: 203cb93a386Sopenharmony_ci return MTLVertexFormatUInt; 204cb93a386Sopenharmony_ci case VertexAttribType::kUShort_norm: 205cb93a386Sopenharmony_ci if (@available(macOS 10.13, iOS 11.0, *)) { 206cb93a386Sopenharmony_ci return MTLVertexFormatUShortNormalized; 207cb93a386Sopenharmony_ci } else { 208cb93a386Sopenharmony_ci return MTLVertexFormatInvalid; 209cb93a386Sopenharmony_ci } 210cb93a386Sopenharmony_ci case VertexAttribType::kUShort4_norm: 211cb93a386Sopenharmony_ci return MTLVertexFormatUShort4Normalized; 212cb93a386Sopenharmony_ci } 213cb93a386Sopenharmony_ci SK_ABORT("Unknown vertex attribute type"); 214cb93a386Sopenharmony_ci} 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_cistatic MTLVertexDescriptor* create_vertex_descriptor(const GraphicsPipelineDesc& desc) { 217cb93a386Sopenharmony_ci auto vertexDescriptor = [[MTLVertexDescriptor alloc] init]; 218cb93a386Sopenharmony_ci int attributeIndex = 0; 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci int vertexAttributeCount = desc.numVertexAttributes(); 221cb93a386Sopenharmony_ci size_t vertexAttributeOffset = 0; 222cb93a386Sopenharmony_ci for (const auto& attribute : desc.vertexAttributes()) { 223cb93a386Sopenharmony_ci MTLVertexAttributeDescriptor* mtlAttribute = vertexDescriptor.attributes[attributeIndex]; 224cb93a386Sopenharmony_ci MTLVertexFormat format = attribute_type_to_mtlformat(attribute.cpuType()); 225cb93a386Sopenharmony_ci SkASSERT(MTLVertexFormatInvalid != format); 226cb93a386Sopenharmony_ci mtlAttribute.format = format; 227cb93a386Sopenharmony_ci mtlAttribute.offset = vertexAttributeOffset; 228cb93a386Sopenharmony_ci mtlAttribute.bufferIndex = GraphicsPipeline::kVertexBufferIndex; 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_ci vertexAttributeOffset += attribute.sizeAlign4(); 231cb93a386Sopenharmony_ci attributeIndex++; 232cb93a386Sopenharmony_ci } 233cb93a386Sopenharmony_ci SkASSERT(vertexAttributeOffset == desc.vertexStride()); 234cb93a386Sopenharmony_ci 235cb93a386Sopenharmony_ci if (vertexAttributeCount) { 236cb93a386Sopenharmony_ci MTLVertexBufferLayoutDescriptor* vertexBufferLayout = 237cb93a386Sopenharmony_ci vertexDescriptor.layouts[GraphicsPipeline::kVertexBufferIndex]; 238cb93a386Sopenharmony_ci vertexBufferLayout.stepFunction = MTLVertexStepFunctionPerVertex; 239cb93a386Sopenharmony_ci vertexBufferLayout.stepRate = 1; 240cb93a386Sopenharmony_ci vertexBufferLayout.stride = vertexAttributeOffset; 241cb93a386Sopenharmony_ci } 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_ci int instanceAttributeCount = desc.numInstanceAttributes(); 244cb93a386Sopenharmony_ci size_t instanceAttributeOffset = 0; 245cb93a386Sopenharmony_ci for (const auto& attribute : desc.instanceAttributes()) { 246cb93a386Sopenharmony_ci MTLVertexAttributeDescriptor* mtlAttribute = vertexDescriptor.attributes[attributeIndex]; 247cb93a386Sopenharmony_ci MTLVertexFormat format = attribute_type_to_mtlformat(attribute.cpuType()); 248cb93a386Sopenharmony_ci SkASSERT(MTLVertexFormatInvalid != format); 249cb93a386Sopenharmony_ci mtlAttribute.format = format; 250cb93a386Sopenharmony_ci mtlAttribute.offset = instanceAttributeOffset; 251cb93a386Sopenharmony_ci mtlAttribute.bufferIndex = GraphicsPipeline::kInstanceBufferIndex; 252cb93a386Sopenharmony_ci 253cb93a386Sopenharmony_ci instanceAttributeOffset += attribute.sizeAlign4(); 254cb93a386Sopenharmony_ci attributeIndex++; 255cb93a386Sopenharmony_ci } 256cb93a386Sopenharmony_ci SkASSERT(instanceAttributeOffset == desc.instanceStride()); 257cb93a386Sopenharmony_ci 258cb93a386Sopenharmony_ci if (instanceAttributeCount) { 259cb93a386Sopenharmony_ci MTLVertexBufferLayoutDescriptor* instanceBufferLayout = 260cb93a386Sopenharmony_ci vertexDescriptor.layouts[GraphicsPipeline::kInstanceBufferIndex]; 261cb93a386Sopenharmony_ci instanceBufferLayout.stepFunction = MTLVertexStepFunctionPerInstance; 262cb93a386Sopenharmony_ci instanceBufferLayout.stepRate = 1; 263cb93a386Sopenharmony_ci instanceBufferLayout.stride = instanceAttributeOffset; 264cb93a386Sopenharmony_ci } 265cb93a386Sopenharmony_ci return vertexDescriptor; 266cb93a386Sopenharmony_ci} 267cb93a386Sopenharmony_ci 268cb93a386Sopenharmony_cisk_sp<GraphicsPipeline> GraphicsPipeline::Make(const Gpu* gpu, 269cb93a386Sopenharmony_ci const skgpu::GraphicsPipelineDesc& desc) { 270cb93a386Sopenharmony_ci sk_cfp<MTLRenderPipelineDescriptor*> psoDescriptor([[MTLRenderPipelineDescriptor alloc] init]); 271cb93a386Sopenharmony_ci 272cb93a386Sopenharmony_ci // Temp pipeline for now that just fills the viewport with blue 273cb93a386Sopenharmony_ci int shaderIndex = desc.testingOnlyShaderIndex(); 274cb93a386Sopenharmony_ci SkSL::String shaderText; 275cb93a386Sopenharmony_ci shaderText.append(kTestingOnlyShaders[shaderIndex]); 276cb93a386Sopenharmony_ci 277cb93a386Sopenharmony_ci auto metallib = CompileShaderLibrary(gpu, shaderText); 278cb93a386Sopenharmony_ci if (!metallib) { 279cb93a386Sopenharmony_ci return nullptr; 280cb93a386Sopenharmony_ci } 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_ci (*psoDescriptor).label = kTestingOnlyShaderLabels[shaderIndex]; 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_ci (*psoDescriptor).vertexFunction = 285cb93a386Sopenharmony_ci [*metallib newFunctionWithName: @"vertexMain"]; 286cb93a386Sopenharmony_ci (*psoDescriptor).fragmentFunction = 287cb93a386Sopenharmony_ci [*metallib newFunctionWithName: @"fragmentMain"]; 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci // TODO: I *think* this gets cleaned up by the pipelineDescriptor? 290cb93a386Sopenharmony_ci (*psoDescriptor).vertexDescriptor = create_vertex_descriptor(desc); 291cb93a386Sopenharmony_ci 292cb93a386Sopenharmony_ci // TODO: I *think* this gets cleaned up by the pipelineDescriptor as well? 293cb93a386Sopenharmony_ci auto mtlColorAttachment = [[MTLRenderPipelineColorAttachmentDescriptor alloc] init]; 294cb93a386Sopenharmony_ci 295cb93a386Sopenharmony_ci mtlColorAttachment.pixelFormat = MTLPixelFormatRGBA8Unorm; 296cb93a386Sopenharmony_ci mtlColorAttachment.blendingEnabled = FALSE; 297cb93a386Sopenharmony_ci mtlColorAttachment.writeMask = MTLColorWriteMaskAll; 298cb93a386Sopenharmony_ci 299cb93a386Sopenharmony_ci (*psoDescriptor).colorAttachments[0] = mtlColorAttachment; 300cb93a386Sopenharmony_ci (*psoDescriptor).sampleCount = 1; 301cb93a386Sopenharmony_ci 302cb93a386Sopenharmony_ci NSError* error; 303cb93a386Sopenharmony_ci sk_cfp<id<MTLRenderPipelineState>> pso( 304cb93a386Sopenharmony_ci [gpu->device() newRenderPipelineStateWithDescriptor:psoDescriptor.get() 305cb93a386Sopenharmony_ci error:&error]); 306cb93a386Sopenharmony_ci if (!pso) { 307cb93a386Sopenharmony_ci SkDebugf("Pipeline creation failure\n"); 308cb93a386Sopenharmony_ci SkDebugf("Errors:\n%s", error.debugDescription.UTF8String); 309cb93a386Sopenharmony_ci return nullptr; 310cb93a386Sopenharmony_ci } 311cb93a386Sopenharmony_ci return sk_sp<GraphicsPipeline>(new GraphicsPipeline(std::move(pso), desc.vertexStride(), 312cb93a386Sopenharmony_ci desc.instanceStride())); 313cb93a386Sopenharmony_ci} 314cb93a386Sopenharmony_ci 315cb93a386Sopenharmony_ci} // namespace skgpu::mtl 316