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