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(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 this->setRenderTargetState(renderTarget, programInfo.origin()); 62 GrFragmentProcessor::PipelineCoordTransformRange transformRange(programInfo.pipeline()); 63 fGeometryProcessor->setData(fDataManager, programInfo.primProc(), transformRange); 64 65 if (!programInfo.hasDynamicPrimProcTextures()) { 66 auto proxies = programInfo.hasFixedPrimProcTextures() ? programInfo.fixedPrimProcTextures() 67 : nullptr; 68 this->setTextures(programInfo, proxies); 69 } 70 fDataManager.resetDirtyBits(); 71 72#ifdef SK_DEBUG 73 if (programInfo.pipeline().isStencilEnabled()) { 74 SkASSERT(renderTarget->renderTargetPriv().getStencilAttachment()); 75 SkASSERT(renderTarget->renderTargetPriv().numStencilBits() == 8); 76 } 77#endif 78 79 fStencil = programInfo.nonGLStencilSettings(); 80} 81 82void GrMtlPipelineState::setTextures(const GrProgramInfo& programInfo, 83 const GrSurfaceProxy* const primProcTextures[]) { 84 fSamplerBindings.reset(); 85 for (int i = 0; i < programInfo.primProc().numTextureSamplers(); ++i) { 86 SkASSERT(primProcTextures[i]->asTextureProxy()); 87 const auto& sampler = programInfo.primProc().textureSampler(i); 88 auto texture = static_cast<GrMtlTexture*>(primProcTextures[i]->peekTexture()); 89 fSamplerBindings.emplace_back(sampler.samplerState(), texture, fGpu); 90 } 91 92 GrFragmentProcessor::CIter fpIter(programInfo.pipeline()); 93 GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt); 94 for (; fpIter && glslIter; ++fpIter, ++glslIter) { 95 glslIter->setData(fDataManager, *fpIter); 96 for (int i = 0; i < fpIter->numTextureSamplers(); ++i) { 97 const auto& sampler = fpIter->textureSampler(i); 98 fSamplerBindings.emplace_back(sampler.samplerState(), sampler.peekTexture(), fGpu); 99 } 100 } 101 SkASSERT(!fpIter && !glslIter); 102 103 { 104 SkIPoint offset; 105 GrTexture* dstTexture = programInfo.pipeline().peekDstTexture(&offset); 106 107 fXferProcessor->setData(fDataManager, programInfo.pipeline().getXferProcessor(), 108 dstTexture, offset); 109 } 110 111 if (GrTextureProxy* dstTextureProxy = programInfo.pipeline().dstProxyView().asTextureProxy()) { 112 fSamplerBindings.emplace_back( 113 GrSamplerState::Filter::kNearest, dstTextureProxy->peekTexture(), fGpu); 114 } 115 116 SkASSERT(fNumSamplers == fSamplerBindings.count()); 117} 118 119void GrMtlPipelineState::setDrawState(id<MTLRenderCommandEncoder> renderCmdEncoder, 120 const GrSwizzle& outputSwizzle, 121 const GrXferProcessor& xferProcessor) { 122 [renderCmdEncoder pushDebugGroup:@"setDrawState"]; 123 this->bindUniforms(renderCmdEncoder); 124 this->setBlendConstants(renderCmdEncoder, outputSwizzle, xferProcessor); 125 this->setDepthStencilState(renderCmdEncoder); 126 [renderCmdEncoder popDebugGroup]; 127} 128 129void GrMtlPipelineState::bindUniforms(id<MTLRenderCommandEncoder> renderCmdEncoder) { 130 fDataManager.uploadAndBindUniformBuffers(fGpu, renderCmdEncoder); 131} 132 133void GrMtlPipelineState::bindTextures(id<MTLRenderCommandEncoder> renderCmdEncoder) { 134 SkASSERT(fNumSamplers == fSamplerBindings.count()); 135 for (int index = 0; index < fNumSamplers; ++index) { 136 [renderCmdEncoder setFragmentTexture: fSamplerBindings[index].fTexture 137 atIndex: index]; 138 [renderCmdEncoder setFragmentSamplerState: fSamplerBindings[index].fSampler->mtlSampler() 139 atIndex: index]; 140 } 141} 142 143void GrMtlPipelineState::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) { 144 // Load the RT height uniform if it is needed to y-flip gl_FragCoord. 145 if (fBuiltinUniformHandles.fRTHeightUni.isValid() && 146 fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) { 147 fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height())); 148 } 149 150 // set RT adjustment 151 SkISize dimensions = rt->dimensions(); 152 SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid()); 153 if (fRenderTargetState.fRenderTargetOrigin != origin || 154 fRenderTargetState.fRenderTargetSize != dimensions) { 155 fRenderTargetState.fRenderTargetSize = dimensions; 156 fRenderTargetState.fRenderTargetOrigin = origin; 157 158 float rtAdjustmentVec[4]; 159 fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec); 160 fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec); 161 } 162} 163 164static bool blend_coeff_refs_constant(GrBlendCoeff coeff) { 165 switch (coeff) { 166 case kConstC_GrBlendCoeff: 167 case kIConstC_GrBlendCoeff: 168 case kConstA_GrBlendCoeff: 169 case kIConstA_GrBlendCoeff: 170 return true; 171 default: 172 return false; 173 } 174} 175 176void GrMtlPipelineState::setBlendConstants(id<MTLRenderCommandEncoder> renderCmdEncoder, 177 const GrSwizzle& swizzle, 178 const GrXferProcessor& xferProcessor) { 179 if (!renderCmdEncoder) { 180 return; 181 } 182 183 const GrXferProcessor::BlendInfo& blendInfo = xferProcessor.getBlendInfo(); 184 GrBlendCoeff srcCoeff = blendInfo.fSrcBlend; 185 GrBlendCoeff dstCoeff = blendInfo.fDstBlend; 186 if (blend_coeff_refs_constant(srcCoeff) || blend_coeff_refs_constant(dstCoeff)) { 187 // Swizzle the blend to match what the shader will output. 188 SkPMColor4f blendConst = swizzle.applyTo(blendInfo.fBlendConstant); 189 190 [renderCmdEncoder setBlendColorRed: blendConst.fR 191 green: blendConst.fG 192 blue: blendConst.fB 193 alpha: blendConst.fA]; 194 } 195} 196 197void GrMtlPipelineState::setDepthStencilState(id<MTLRenderCommandEncoder> renderCmdEncoder) { 198 const GrSurfaceOrigin& origin = fRenderTargetState.fRenderTargetOrigin; 199 GrMtlDepthStencil* state = 200 fGpu->resourceProvider().findOrCreateCompatibleDepthStencilState(fStencil, origin); 201 if (!fStencil.isDisabled()) { 202 if (fStencil.isTwoSided()) { 203 if (@available(macOS 10.11, iOS 9.0, *)) { 204 [renderCmdEncoder 205 setStencilFrontReferenceValue:fStencil.postOriginCCWFace(origin).fRef 206 backReferenceValue:fStencil.postOriginCWFace(origin).fRef]; 207 } else { 208 // Two-sided stencil not supported on older versions of iOS 209 // TODO: Find a way to recover from this 210 SkASSERT(false); 211 } 212 } else { 213 [renderCmdEncoder setStencilReferenceValue:fStencil.singleSidedFace().fRef]; 214 } 215 } 216 [renderCmdEncoder setDepthStencilState:state->mtlDepthStencil()]; 217} 218 219void GrMtlPipelineState::SetDynamicScissorRectState(id<MTLRenderCommandEncoder> renderCmdEncoder, 220 const GrRenderTarget* renderTarget, 221 GrSurfaceOrigin rtOrigin, 222 SkIRect scissorRect) { 223 if (!scissorRect.intersect(SkIRect::MakeWH(renderTarget->width(), renderTarget->height()))) { 224 scissorRect.setEmpty(); 225 } 226 227 MTLScissorRect scissor; 228 scissor.x = scissorRect.fLeft; 229 scissor.width = scissorRect.width(); 230 if (kTopLeft_GrSurfaceOrigin == rtOrigin) { 231 scissor.y = scissorRect.fTop; 232 } else { 233 SkASSERT(kBottomLeft_GrSurfaceOrigin == rtOrigin); 234 scissor.y = renderTarget->height() - scissorRect.fBottom; 235 } 236 scissor.height = scissorRect.height(); 237 238 SkASSERT(scissor.x >= 0); 239 SkASSERT(scissor.y >= 0); 240 241 [renderCmdEncoder setScissorRect: scissor]; 242} 243 244bool GrMtlPipelineState::doesntSampleAttachment( 245 const MTLRenderPassAttachmentDescriptor* attachment) const { 246 for (int i = 0; i < fSamplerBindings.count(); ++i) { 247 if (attachment.texture == fSamplerBindings[i].fTexture) { 248 return false; 249 } 250 } 251 return true; 252} 253