1// 2// Copyright 2020 Pixar 3// 4// Licensed under the Apache License, Version 2.0 (the "Apache License") 5// with the following modification; you may not use this file except in 6// compliance with the Apache License and the following modification to it: 7// Section 6. Trademarks. is deleted and replaced with: 8// 9// 6. Trademarks. This License does not grant permission to use the trade 10// names, trademarks, service marks, or product names of the Licensor 11// and its affiliates, except as required to comply with Section 4(c) of 12// the License and to reproduce the content of the NOTICE file. 13// 14// You may obtain a copy of the Apache License at 15// 16// http://www.apache.org/licenses/LICENSE-2.0 17// 18// Unless required by applicable law or agreed to in writing, software 19// distributed under the Apache License with the above modification is 20// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 21// KIND, either express or implied. See the Apache License for the specific 22// language governing permissions and limitations under the Apache License. 23// 24 25#include "pxr/base/tf/diagnostic.h" 26 27#include "pxr/imaging/hgiMetal/hgi.h" 28#include "pxr/imaging/hgiMetal/conversions.h" 29#include "pxr/imaging/hgiMetal/diagnostic.h" 30#include "pxr/imaging/hgiMetal/graphicsPipeline.h" 31#include "pxr/imaging/hgiMetal/resourceBindings.h" 32#include "pxr/imaging/hgiMetal/shaderProgram.h" 33#include "pxr/imaging/hgiMetal/shaderFunction.h" 34 35PXR_NAMESPACE_OPEN_SCOPE 36 37HgiMetalGraphicsPipeline::HgiMetalGraphicsPipeline( 38 HgiMetal *hgi, 39 HgiGraphicsPipelineDesc const& desc) 40 : HgiGraphicsPipeline(desc) 41 , _vertexDescriptor(nil) 42 , _depthStencilState(nil) 43 , _renderPipelineState(nil) 44{ 45 _CreateVertexDescriptor(); 46 _CreateDepthStencilState(hgi->GetPrimaryDevice()); 47 _CreateRenderPipelineState(hgi->GetPrimaryDevice()); 48} 49 50HgiMetalGraphicsPipeline::~HgiMetalGraphicsPipeline() 51{ 52 if (_renderPipelineState) { 53 [_renderPipelineState release]; 54 } 55 if (_depthStencilState) { 56 [_depthStencilState release]; 57 } 58 if (_vertexDescriptor) { 59 [_vertexDescriptor release]; 60 } 61} 62 63void 64HgiMetalGraphicsPipeline::_CreateVertexDescriptor() 65{ 66 _vertexDescriptor = [[MTLVertexDescriptor alloc] init]; 67 68 int index = 0; 69 for (HgiVertexBufferDesc const& vbo : _descriptor.vertexBuffers) { 70 71 HgiVertexAttributeDescVector const& vas = vbo.vertexAttributes; 72 73 _vertexDescriptor.layouts[index].stepFunction = 74 MTLVertexStepFunctionPerVertex; 75 _vertexDescriptor.layouts[index].stepRate = 1; 76 _vertexDescriptor.layouts[index].stride = vbo.vertexStride; 77 78 // Describe each vertex attribute in the vertex buffer 79 for (size_t loc = 0; loc<vas.size(); loc++) { 80 HgiVertexAttributeDesc const& va = vas[loc]; 81 82 uint32_t idx = va.shaderBindLocation; 83 _vertexDescriptor.attributes[idx].format = 84 HgiMetalConversions::GetVertexFormat(va.format); 85 _vertexDescriptor.attributes[idx].bufferIndex = vbo.bindingIndex; 86 _vertexDescriptor.attributes[idx].offset = va.offset; 87 } 88 index++; 89 } 90} 91 92void 93HgiMetalGraphicsPipeline::_CreateRenderPipelineState(id<MTLDevice> device) 94{ 95 MTLRenderPipelineDescriptor *stateDesc = 96 [[MTLRenderPipelineDescriptor alloc] init]; 97 98 // Create a new render pipeline state object 99 HGIMETAL_DEBUG_LABEL(stateDesc, _descriptor.debugName.c_str()); 100 stateDesc.rasterSampleCount = 1; 101 102 stateDesc.inputPrimitiveTopology = 103 HgiMetalConversions::GetPrimitiveClass(_descriptor.primitiveType); 104 105 HgiMetalShaderProgram const *metalProgram = 106 static_cast<HgiMetalShaderProgram*>(_descriptor.shaderProgram.Get()); 107 108 stateDesc.vertexFunction = metalProgram->GetVertexFunction(); 109 id<MTLFunction> fragFunction = metalProgram->GetFragmentFunction(); 110 if (fragFunction && _descriptor.rasterizationState.rasterizerEnabled) { 111 stateDesc.fragmentFunction = fragFunction; 112 stateDesc.rasterizationEnabled = YES; 113 } 114 else { 115 stateDesc.rasterizationEnabled = NO; 116 } 117 118 // Color attachments 119 for (size_t i=0; i<_descriptor.colorAttachmentDescs.size(); i++) { 120 HgiAttachmentDesc const &hgiColorAttachment = 121 _descriptor.colorAttachmentDescs[i]; 122 MTLRenderPipelineColorAttachmentDescriptor *metalColorAttachment = 123 stateDesc.colorAttachments[i]; 124 125 metalColorAttachment.pixelFormat = HgiMetalConversions::GetPixelFormat( 126 hgiColorAttachment.format); 127 128 if (hgiColorAttachment.blendEnabled) { 129 metalColorAttachment.blendingEnabled = YES; 130 131 metalColorAttachment.sourceRGBBlendFactor = 132 HgiMetalConversions::GetBlendFactor( 133 hgiColorAttachment.srcColorBlendFactor); 134 metalColorAttachment.destinationRGBBlendFactor = 135 HgiMetalConversions::GetBlendFactor( 136 hgiColorAttachment.dstColorBlendFactor); 137 138 metalColorAttachment.sourceAlphaBlendFactor = 139 HgiMetalConversions::GetBlendFactor( 140 hgiColorAttachment.srcAlphaBlendFactor); 141 metalColorAttachment.destinationAlphaBlendFactor = 142 HgiMetalConversions::GetBlendFactor( 143 hgiColorAttachment.dstAlphaBlendFactor); 144 145 metalColorAttachment.rgbBlendOperation = 146 HgiMetalConversions::GetBlendEquation( 147 hgiColorAttachment.colorBlendOp); 148 metalColorAttachment.alphaBlendOperation = 149 HgiMetalConversions::GetBlendEquation( 150 hgiColorAttachment.alphaBlendOp); 151 } 152 else { 153 metalColorAttachment.blendingEnabled = NO; 154 } 155 } 156 157 HgiAttachmentDesc const &hgiDepthAttachment = 158 _descriptor.depthAttachmentDesc; 159 160 stateDesc.depthAttachmentPixelFormat = 161 HgiMetalConversions::GetPixelFormat(hgiDepthAttachment.format); 162 163 stateDesc.sampleCount = _descriptor.multiSampleState.sampleCount; 164 if (_descriptor.multiSampleState.alphaToCoverageEnable) { 165 stateDesc.alphaToCoverageEnabled = YES; 166 } else { 167 stateDesc.alphaToCoverageEnabled = NO; 168 } 169 170 stateDesc.vertexDescriptor = _vertexDescriptor; 171 172 NSError *error = NULL; 173 _renderPipelineState = [device 174 newRenderPipelineStateWithDescriptor:stateDesc 175 error:&error]; 176 [stateDesc release]; 177 178 if (!_renderPipelineState) { 179 NSString *err = [error localizedDescription]; 180 TF_WARN("Failed to created pipeline state, error %s", 181 [err UTF8String]); 182 } 183} 184 185void 186HgiMetalGraphicsPipeline::_CreateDepthStencilState(id<MTLDevice> device) 187{ 188 MTLDepthStencilDescriptor *depthStencilStateDescriptor = 189 [[MTLDepthStencilDescriptor alloc] init]; 190 191 HGIMETAL_DEBUG_LABEL( 192 depthStencilStateDescriptor, _descriptor.debugName.c_str()); 193 194 if (_descriptor.depthState.depthWriteEnabled) { 195 depthStencilStateDescriptor.depthWriteEnabled = YES; 196 } 197 else { 198 depthStencilStateDescriptor.depthWriteEnabled = NO; 199 } 200 if (_descriptor.depthState.depthTestEnabled) { 201 MTLCompareFunction depthFn = HgiMetalConversions::GetDepthCompareFunction( 202 _descriptor.depthState.depthCompareFn); 203 depthStencilStateDescriptor.depthCompareFunction = depthFn; 204 } 205 else { 206 // Even if there is no depth attachment, some drivers may still perform 207 // the depth test. So we pick Always over Never. 208 depthStencilStateDescriptor.depthCompareFunction = 209 MTLCompareFunctionAlways; 210 } 211 212 if (_descriptor.depthState.stencilTestEnabled) { 213 TF_CODING_ERROR("Missing implementation stencil mask enabled"); 214 } else { 215 depthStencilStateDescriptor.backFaceStencil = nil; 216 depthStencilStateDescriptor.frontFaceStencil = nil; 217 } 218 219 _depthStencilState = [device 220 newDepthStencilStateWithDescriptor:depthStencilStateDescriptor]; 221 [depthStencilStateDescriptor release]; 222 223 TF_VERIFY(_depthStencilState, 224 "Failed to created depth stencil state"); 225} 226 227void 228HgiMetalGraphicsPipeline::BindPipeline(id<MTLRenderCommandEncoder> renderEncoder) 229{ 230 [renderEncoder setRenderPipelineState:_renderPipelineState]; 231 232 // 233 // Rasterization state 234 // 235 [renderEncoder setCullMode:HgiMetalConversions::GetCullMode( 236 _descriptor.rasterizationState.cullMode)]; 237 [renderEncoder setTriangleFillMode:HgiMetalConversions::GetPolygonMode( 238 _descriptor.rasterizationState.polygonMode)]; 239 [renderEncoder setFrontFacingWinding:HgiMetalConversions::GetWinding( 240 _descriptor.rasterizationState.winding)]; 241 [renderEncoder setDepthStencilState:_depthStencilState]; 242 243 TF_VERIFY(_descriptor.rasterizationState.lineWidth == 1.0f, 244 "Missing implementation buffers"); 245} 246 247PXR_NAMESPACE_CLOSE_SCOPE 248