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 uint32_t maxMipMapLevel = texture->texturePriv().maxMipMapLevel(); 32 fSampler = gpu->resourceProvider().findOrCreateCompatibleSampler(state, maxMipMapLevel); 33} 34 35GrMtlPipelineState::GrMtlPipelineState( 36 GrMtlGpu* gpu, 37 id<MTLRenderPipelineState> pipelineState, 38 MTLPixelFormat pixelFormat, 39 const GrGLSLBuiltinUniformHandles& builtinUniformHandles, 40 const UniformInfoArray& uniforms, 41 uint32_t uniformBufferSize, 42 uint32_t numSamplers, 43 std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor, 44 std::unique_ptr<GrGLSLXferProcessor> xferProcessor, 45 std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors, 46 int fragmentProcessorCnt) 47 : fGpu(gpu) 48 , fPipelineState(pipelineState) 49 , fPixelFormat(pixelFormat) 50 , fBuiltinUniformHandles(builtinUniformHandles) 51 , fNumSamplers(numSamplers) 52 , fGeometryProcessor(std::move(geometryProcessor)) 53 , fXferProcessor(std::move(xferProcessor)) 54 , fFragmentProcessors(std::move(fragmentProcessors)) 55 , fFragmentProcessorCnt(fragmentProcessorCnt) 56 , fDataManager(uniforms, uniformBufferSize) { 57 (void) fPixelFormat; // Suppress unused-var warning. 58} 59 60void GrMtlPipelineState::setData(const GrRenderTarget* renderTarget, 61 GrSurfaceOrigin origin, 62 const GrPrimitiveProcessor& primProc, 63 const GrPipeline& pipeline, 64 const GrTextureProxy* const primProcTextures[]) { 65 SkASSERT(primProcTextures || !primProc.numTextureSamplers()); 66 67 this->setRenderTargetState(renderTarget, origin); 68 fGeometryProcessor->setData(fDataManager, primProc, 69 GrFragmentProcessor::CoordTransformIter(pipeline)); 70 fSamplerBindings.reset(); 71 for (int i = 0; i < primProc.numTextureSamplers(); ++i) { 72 const auto& sampler = primProc.textureSampler(i); 73 auto texture = static_cast<GrMtlTexture*>(primProcTextures[i]->peekTexture()); 74 fSamplerBindings.emplace_back(sampler.samplerState(), texture, fGpu); 75 } 76 77 GrFragmentProcessor::Iter iter(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 = pipeline.peekDstTexture(&offset); 95 96 fXferProcessor->setData(fDataManager, pipeline.getXferProcessor(), dstTexture, offset); 97 } 98 99 if (GrTextureProxy* dstTextureProxy = pipeline.dstTextureProxy()) { 100 fSamplerBindings.emplace_back(GrSamplerState::ClampNearest(), 101 dstTextureProxy->peekTexture(), 102 fGpu); 103 } 104 105 SkASSERT(fNumSamplers == fSamplerBindings.count()); 106 fDataManager.resetDirtyBits(); 107 108 if (pipeline.isStencilEnabled()) { 109 SkASSERT(renderTarget->renderTargetPriv().getStencilAttachment()); 110 fStencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(), 111 renderTarget->renderTargetPriv().numStencilBits()); 112 } 113} 114 115void GrMtlPipelineState::setDrawState(id<MTLRenderCommandEncoder> renderCmdEncoder, 116 const GrSwizzle& outputSwizzle, 117 const GrXferProcessor& xferProcessor) { 118 [renderCmdEncoder pushDebugGroup:@"setDrawState"]; 119 this->bind(renderCmdEncoder); 120 this->setBlendConstants(renderCmdEncoder, outputSwizzle, xferProcessor); 121 this->setDepthStencilState(renderCmdEncoder); 122 [renderCmdEncoder popDebugGroup]; 123} 124 125void GrMtlPipelineState::bind(id<MTLRenderCommandEncoder> renderCmdEncoder) { 126 fDataManager.uploadAndBindUniformBuffers(fGpu, renderCmdEncoder); 127 128 SkASSERT(fNumSamplers == fSamplerBindings.count()); 129 for (int index = 0; index < fNumSamplers; ++index) { 130 [renderCmdEncoder setFragmentTexture: fSamplerBindings[index].fTexture 131 atIndex: index]; 132 [renderCmdEncoder setFragmentSamplerState: fSamplerBindings[index].fSampler->mtlSampler() 133 atIndex: index]; 134 } 135} 136 137void GrMtlPipelineState::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) { 138 // Load the RT height uniform if it is needed to y-flip gl_FragCoord. 139 if (fBuiltinUniformHandles.fRTHeightUni.isValid() && 140 fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) { 141 fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height())); 142 } 143 144 // set RT adjustment 145 SkISize size; 146 size.set(rt->width(), rt->height()); 147 SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid()); 148 if (fRenderTargetState.fRenderTargetOrigin != origin || 149 fRenderTargetState.fRenderTargetSize != size) { 150 fRenderTargetState.fRenderTargetSize = size; 151 fRenderTargetState.fRenderTargetOrigin = origin; 152 153 float rtAdjustmentVec[4]; 154 fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec); 155 fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec); 156 } 157} 158 159static bool blend_coeff_refs_constant(GrBlendCoeff coeff) { 160 switch (coeff) { 161 case kConstC_GrBlendCoeff: 162 case kIConstC_GrBlendCoeff: 163 case kConstA_GrBlendCoeff: 164 case kIConstA_GrBlendCoeff: 165 return true; 166 default: 167 return false; 168 } 169} 170 171void GrMtlPipelineState::setBlendConstants(id<MTLRenderCommandEncoder> renderCmdEncoder, 172 const GrSwizzle& swizzle, 173 const GrXferProcessor& xferProcessor) { 174 if (!renderCmdEncoder) { 175 return; 176 } 177 178 const GrXferProcessor::BlendInfo& blendInfo = xferProcessor.getBlendInfo(); 179 GrBlendCoeff srcCoeff = blendInfo.fSrcBlend; 180 GrBlendCoeff dstCoeff = blendInfo.fDstBlend; 181 if (blend_coeff_refs_constant(srcCoeff) || blend_coeff_refs_constant(dstCoeff)) { 182 // Swizzle the blend to match what the shader will output. 183 SkPMColor4f blendConst = swizzle.applyTo(blendInfo.fBlendConstant); 184 185 [renderCmdEncoder setBlendColorRed: blendConst.fR 186 green: blendConst.fG 187 blue: blendConst.fB 188 alpha: blendConst.fA]; 189 } 190} 191 192void GrMtlPipelineState::setDepthStencilState(id<MTLRenderCommandEncoder> renderCmdEncoder) { 193 const GrSurfaceOrigin& origin = fRenderTargetState.fRenderTargetOrigin; 194 GrMtlDepthStencil* state = 195 fGpu->resourceProvider().findOrCreateCompatibleDepthStencilState(fStencil, origin); 196 if (!fStencil.isDisabled()) { 197 if (fStencil.isTwoSided()) { 198 [renderCmdEncoder setStencilFrontReferenceValue:fStencil.front(origin).fRef 199 backReferenceValue:fStencil.back(origin).fRef]; 200 } 201 else { 202 [renderCmdEncoder setStencilReferenceValue:fStencil.frontAndBack().fRef]; 203 } 204 } 205 [renderCmdEncoder setDepthStencilState:state->mtlDepthStencil()]; 206} 207 208void GrMtlPipelineState::SetDynamicScissorRectState(id<MTLRenderCommandEncoder> renderCmdEncoder, 209 const GrRenderTarget* renderTarget, 210 GrSurfaceOrigin rtOrigin, 211 SkIRect scissorRect) { 212 if (!scissorRect.intersect(SkIRect::MakeWH(renderTarget->width(), renderTarget->height()))) { 213 scissorRect.setEmpty(); 214 } 215 216 MTLScissorRect scissor; 217 scissor.x = scissorRect.fLeft; 218 scissor.width = scissorRect.width(); 219 if (kTopLeft_GrSurfaceOrigin == rtOrigin) { 220 scissor.y = scissorRect.fTop; 221 } else { 222 SkASSERT(kBottomLeft_GrSurfaceOrigin == rtOrigin); 223 scissor.y = renderTarget->height() - scissorRect.fBottom; 224 } 225 scissor.height = scissorRect.height(); 226 227 SkASSERT(scissor.x >= 0); 228 SkASSERT(scissor.y >= 0); 229 230 [renderCmdEncoder setScissorRect: scissor]; 231} 232 233bool GrMtlPipelineState::doesntSampleAttachment( 234 const MTLRenderPassAttachmentDescriptor* attachment) const { 235 for (int i = 0; i < fSamplerBindings.count(); ++i) { 236 if (attachment.texture == fSamplerBindings[i].fTexture) { 237 return false; 238 } 239 } 240 return true; 241} 242