1/* 2 * Copyright 2018 Google Inc. 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 "src/gpu/mtl/GrMtlPipelineState.h" 9 10#include "include/gpu/GrContext.h" 11#include "src/gpu/GrContextPriv.h" 12#include "src/gpu/GrPipeline.h" 13#include "src/gpu/GrRenderTarget.h" 14#include "src/gpu/GrRenderTargetPriv.h" 15#include "src/gpu/GrTexturePriv.h" 16#include "src/gpu/glsl/GrGLSLFragmentProcessor.h" 17#include "src/gpu/glsl/GrGLSLGeometryProcessor.h" 18#include "src/gpu/glsl/GrGLSLXferProcessor.h" 19#include "src/gpu/mtl/GrMtlBuffer.h" 20#include "src/gpu/mtl/GrMtlGpu.h" 21#include "src/gpu/mtl/GrMtlTexture.h" 22 23#if !__has_feature(objc_arc) 24#error This file must be compiled with Arc. Use -fobjc-arc flag 25#endif 26 27GrMtlPipelineState::SamplerBindings::SamplerBindings(const GrSamplerState& state, 28 GrTexture* texture, 29 GrMtlGpu* gpu) 30 : fTexture(static_cast<GrMtlTexture*>(texture)->mtlTexture()) { 31 fSampler = gpu->resourceProvider().findOrCreateCompatibleSampler(state); 32} 33 34GrMtlPipelineState::GrMtlPipelineState( 35 GrMtlGpu* gpu, 36 id<MTLRenderPipelineState> pipelineState, 37 MTLPixelFormat pixelFormat, 38 const GrGLSLBuiltinUniformHandles& builtinUniformHandles, 39 const UniformInfoArray& uniforms, 40 uint32_t uniformBufferSize, 41 uint32_t numSamplers, 42 std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor, 43 std::unique_ptr<GrGLSLXferProcessor> xferProcessor, 44 std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors, 45 int fragmentProcessorCnt) 46 : fGpu(gpu) 47 , fPipelineState(pipelineState) 48 , fPixelFormat(pixelFormat) 49 , fBuiltinUniformHandles(builtinUniformHandles) 50 , fNumSamplers(numSamplers) 51 , fGeometryProcessor(std::move(geometryProcessor)) 52 , fXferProcessor(std::move(xferProcessor)) 53 , fFragmentProcessors(std::move(fragmentProcessors)) 54 , fFragmentProcessorCnt(fragmentProcessorCnt) 55 , fDataManager(uniforms, uniformBufferSize) { 56 (void) fPixelFormat; // Suppress unused-var warning. 57} 58 59void GrMtlPipelineState::setData(const GrRenderTarget* renderTarget, 60 const GrProgramInfo& programInfo) { 61 62 // Note: the Metal backend currently only supports fixed primProc textures 63 SkASSERT(!programInfo.hasDynamicPrimProcTextures()); 64 auto proxies = programInfo.hasFixedPrimProcTextures() ? programInfo.fixedPrimProcTextures() 65 : nullptr; 66 67 this->setRenderTargetState(renderTarget, programInfo.origin()); 68 fGeometryProcessor->setData(fDataManager, programInfo.primProc(), 69 GrFragmentProcessor::CoordTransformIter(programInfo.pipeline())); 70 fSamplerBindings.reset(); 71 for (int i = 0; i < programInfo.primProc().numTextureSamplers(); ++i) { 72 const auto& sampler = programInfo.primProc().textureSampler(i); 73 auto texture = static_cast<GrMtlTexture*>(proxies[i]->peekTexture()); 74 fSamplerBindings.emplace_back(sampler.samplerState(), texture, fGpu); 75 } 76 77 GrFragmentProcessor::Iter iter(programInfo.pipeline()); 78 GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt); 79 const GrFragmentProcessor* fp = iter.next(); 80 GrGLSLFragmentProcessor* glslFP = glslIter.next(); 81 while (fp && glslFP) { 82 glslFP->setData(fDataManager, *fp); 83 for (int i = 0; i < fp->numTextureSamplers(); ++i) { 84 const auto& sampler = fp->textureSampler(i); 85 fSamplerBindings.emplace_back(sampler.samplerState(), sampler.peekTexture(), fGpu); 86 } 87 fp = iter.next(); 88 glslFP = glslIter.next(); 89 } 90 SkASSERT(!fp && !glslFP); 91 92 { 93 SkIPoint offset; 94 GrTexture* dstTexture = programInfo.pipeline().peekDstTexture(&offset); 95 96 fXferProcessor->setData(fDataManager, programInfo.pipeline().getXferProcessor(), 97 dstTexture, offset); 98 } 99 100 if (GrTextureProxy* dstTextureProxy = programInfo.pipeline().dstTextureProxy()) { 101 fSamplerBindings.emplace_back(GrSamplerState::ClampNearest(), 102 dstTextureProxy->peekTexture(), 103 fGpu); 104 } 105 106 SkASSERT(fNumSamplers == fSamplerBindings.count()); 107 fDataManager.resetDirtyBits(); 108 109 if (programInfo.pipeline().isStencilEnabled()) { 110 SkASSERT(renderTarget->renderTargetPriv().getStencilAttachment()); 111 fStencil.reset(*programInfo.pipeline().getUserStencil(), 112 programInfo.pipeline().hasStencilClip(), 113 renderTarget->renderTargetPriv().numStencilBits()); 114 } 115} 116 117void GrMtlPipelineState::setDrawState(id<MTLRenderCommandEncoder> renderCmdEncoder, 118 const GrSwizzle& outputSwizzle, 119 const GrXferProcessor& xferProcessor) { 120 [renderCmdEncoder pushDebugGroup:@"setDrawState"]; 121 this->bind(renderCmdEncoder); 122 this->setBlendConstants(renderCmdEncoder, outputSwizzle, xferProcessor); 123 this->setDepthStencilState(renderCmdEncoder); 124 [renderCmdEncoder popDebugGroup]; 125} 126 127void GrMtlPipelineState::bind(id<MTLRenderCommandEncoder> renderCmdEncoder) { 128 fDataManager.uploadAndBindUniformBuffers(fGpu, renderCmdEncoder); 129 130 SkASSERT(fNumSamplers == fSamplerBindings.count()); 131 for (int index = 0; index < fNumSamplers; ++index) { 132 [renderCmdEncoder setFragmentTexture: fSamplerBindings[index].fTexture 133 atIndex: index]; 134 [renderCmdEncoder setFragmentSamplerState: fSamplerBindings[index].fSampler->mtlSampler() 135 atIndex: index]; 136 } 137} 138 139void GrMtlPipelineState::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) { 140 // Load the RT height uniform if it is needed to y-flip gl_FragCoord. 141 if (fBuiltinUniformHandles.fRTHeightUni.isValid() && 142 fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) { 143 fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height())); 144 } 145 146 // set RT adjustment 147 SkISize size; 148 size.set(rt->width(), rt->height()); 149 SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid()); 150 if (fRenderTargetState.fRenderTargetOrigin != origin || 151 fRenderTargetState.fRenderTargetSize != size) { 152 fRenderTargetState.fRenderTargetSize = size; 153 fRenderTargetState.fRenderTargetOrigin = origin; 154 155 float rtAdjustmentVec[4]; 156 fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec); 157 fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec); 158 } 159} 160 161static bool blend_coeff_refs_constant(GrBlendCoeff coeff) { 162 switch (coeff) { 163 case kConstC_GrBlendCoeff: 164 case kIConstC_GrBlendCoeff: 165 case kConstA_GrBlendCoeff: 166 case kIConstA_GrBlendCoeff: 167 return true; 168 default: 169 return false; 170 } 171} 172 173void GrMtlPipelineState::setBlendConstants(id<MTLRenderCommandEncoder> renderCmdEncoder, 174 const GrSwizzle& swizzle, 175 const GrXferProcessor& xferProcessor) { 176 if (!renderCmdEncoder) { 177 return; 178 } 179 180 const GrXferProcessor::BlendInfo& blendInfo = xferProcessor.getBlendInfo(); 181 GrBlendCoeff srcCoeff = blendInfo.fSrcBlend; 182 GrBlendCoeff dstCoeff = blendInfo.fDstBlend; 183 if (blend_coeff_refs_constant(srcCoeff) || blend_coeff_refs_constant(dstCoeff)) { 184 // Swizzle the blend to match what the shader will output. 185 SkPMColor4f blendConst = swizzle.applyTo(blendInfo.fBlendConstant); 186 187 [renderCmdEncoder setBlendColorRed: blendConst.fR 188 green: blendConst.fG 189 blue: blendConst.fB 190 alpha: blendConst.fA]; 191 } 192} 193 194void GrMtlPipelineState::setDepthStencilState(id<MTLRenderCommandEncoder> renderCmdEncoder) { 195 const GrSurfaceOrigin& origin = fRenderTargetState.fRenderTargetOrigin; 196 GrMtlDepthStencil* state = 197 fGpu->resourceProvider().findOrCreateCompatibleDepthStencilState(fStencil, origin); 198 if (!fStencil.isDisabled()) { 199 if (fStencil.isTwoSided()) { 200 if (@available(macOS 10.11, iOS 9.0, *)) { 201 [renderCmdEncoder setStencilFrontReferenceValue:fStencil.front(origin).fRef 202 backReferenceValue:fStencil.back(origin).fRef]; 203 } else { 204 // Two-sided stencil not supported on older versions of iOS 205 // TODO: Find a way to recover from this 206 SkASSERT(false); 207 } 208 } else { 209 [renderCmdEncoder setStencilReferenceValue:fStencil.frontAndBack().fRef]; 210 } 211 } 212 [renderCmdEncoder setDepthStencilState:state->mtlDepthStencil()]; 213} 214 215void GrMtlPipelineState::SetDynamicScissorRectState(id<MTLRenderCommandEncoder> renderCmdEncoder, 216 const GrRenderTarget* renderTarget, 217 GrSurfaceOrigin rtOrigin, 218 SkIRect scissorRect) { 219 if (!scissorRect.intersect(SkIRect::MakeWH(renderTarget->width(), renderTarget->height()))) { 220 scissorRect.setEmpty(); 221 } 222 223 MTLScissorRect scissor; 224 scissor.x = scissorRect.fLeft; 225 scissor.width = scissorRect.width(); 226 if (kTopLeft_GrSurfaceOrigin == rtOrigin) { 227 scissor.y = scissorRect.fTop; 228 } else { 229 SkASSERT(kBottomLeft_GrSurfaceOrigin == rtOrigin); 230 scissor.y = renderTarget->height() - scissorRect.fBottom; 231 } 232 scissor.height = scissorRect.height(); 233 234 SkASSERT(scissor.x >= 0); 235 SkASSERT(scissor.y >= 0); 236 237 [renderCmdEncoder setScissorRect: scissor]; 238} 239 240bool GrMtlPipelineState::doesntSampleAttachment( 241 const MTLRenderPassAttachmentDescriptor* attachment) const { 242 for (int i = 0; i < fSamplerBindings.count(); ++i) { 243 if (attachment.texture == fSamplerBindings[i].fTexture) { 244 return false; 245 } 246 } 247 return true; 248} 249