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 "src/gpu/GrBackendUtils.h" 11#include "src/gpu/GrFragmentProcessor.h" 12#include "src/gpu/GrGeometryProcessor.h" 13#include "src/gpu/GrRenderTarget.h" 14#include "src/gpu/GrTexture.h" 15#include "src/gpu/GrXferProcessor.h" 16#include "src/gpu/effects/GrTextureEffect.h" 17#include "src/gpu/mtl/GrMtlBuffer.h" 18#include "src/gpu/mtl/GrMtlFramebuffer.h" 19#include "src/gpu/mtl/GrMtlGpu.h" 20#include "src/gpu/mtl/GrMtlRenderCommandEncoder.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 27GR_NORETAIN_BEGIN 28 29GrMtlPipelineState::SamplerBindings::SamplerBindings(GrSamplerState state, 30 GrTexture* texture, 31 GrMtlGpu* gpu) 32 : fTexture(static_cast<GrMtlTexture*>(texture)->mtlTexture()) { 33 fSampler = gpu->resourceProvider().findOrCreateCompatibleSampler(state); 34 gpu->commandBuffer()->addResource(sk_ref_sp<GrManagedResource>(fSampler)); 35 gpu->commandBuffer()->addGrSurface( 36 sk_ref_sp<GrSurface>(static_cast<GrMtlTexture*>(texture)->attachment())); 37} 38 39GrMtlPipelineState::GrMtlPipelineState( 40 GrMtlGpu* gpu, 41 sk_sp<GrMtlRenderPipeline> pipeline, 42 MTLPixelFormat pixelFormat, 43 const GrGLSLBuiltinUniformHandles& builtinUniformHandles, 44 const UniformInfoArray& uniforms, 45 uint32_t uniformBufferSize, 46 uint32_t numSamplers, 47 std::unique_ptr<GrGeometryProcessor::ProgramImpl> gpImpl, 48 std::unique_ptr<GrXferProcessor::ProgramImpl> xpImpl, 49 std::vector<std::unique_ptr<GrFragmentProcessor::ProgramImpl>> fpImpls) 50 : fGpu(gpu) 51 , fPipeline(std::move(pipeline)) 52 , fPixelFormat(pixelFormat) 53 , fBuiltinUniformHandles(builtinUniformHandles) 54 , fNumSamplers(numSamplers) 55 , fGPImpl(std::move(gpImpl)) 56 , fXPImpl(std::move(xpImpl)) 57 , fFPImpls(std::move(fpImpls)) 58 , fDataManager(uniforms, uniformBufferSize) { 59 (void) fPixelFormat; // Suppress unused-var warning. 60} 61 62void GrMtlPipelineState::setData(GrMtlFramebuffer* framebuffer, 63 const GrProgramInfo& programInfo) { 64 SkISize colorAttachmentDimensions = framebuffer->colorAttachment()->dimensions(); 65 66 this->setRenderTargetState(colorAttachmentDimensions, programInfo.origin()); 67 fGPImpl->setData(fDataManager, *fGpu->caps()->shaderCaps(), programInfo.geomProc()); 68 69 for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) { 70 const auto& fp = programInfo.pipeline().getFragmentProcessor(i); 71 fp.visitWithImpls([&](const GrFragmentProcessor& fp, 72 GrFragmentProcessor::ProgramImpl& impl) { 73 impl.setData(fDataManager, fp); 74 }, *fFPImpls[i]); 75 } 76 77 programInfo.pipeline().setDstTextureUniforms(fDataManager, &fBuiltinUniformHandles); 78 fXPImpl->setData(fDataManager, programInfo.pipeline().getXferProcessor()); 79 80 fDataManager.resetDirtyBits(); 81 82#ifdef SK_DEBUG 83 if (programInfo.isStencilEnabled()) { 84 SkDEBUGCODE(const GrAttachment* stencil = framebuffer->stencilAttachment()); 85 SkASSERT(stencil); 86 SkASSERT(GrBackendFormatStencilBits(stencil->backendFormat()) == 8); 87 } 88#endif 89 90 fStencil = programInfo.nonGLStencilSettings(); 91 fGpu->commandBuffer()->addResource(fPipeline); 92} 93 94void GrMtlPipelineState::setTextures(const GrGeometryProcessor& geomProc, 95 const GrPipeline& pipeline, 96 const GrSurfaceProxy* const geomProcTextures[]) { 97 fSamplerBindings.reset(); 98 for (int i = 0; i < geomProc.numTextureSamplers(); ++i) { 99 SkASSERT(geomProcTextures[i]->asTextureProxy()); 100 const auto& sampler = geomProc.textureSampler(i); 101 auto texture = static_cast<GrMtlTexture*>(geomProcTextures[i]->peekTexture()); 102 fSamplerBindings.emplace_back(sampler.samplerState(), texture, fGpu); 103 } 104 105 if (GrTextureProxy* dstTextureProxy = pipeline.dstProxyView().asTextureProxy()) { 106 fSamplerBindings.emplace_back( 107 GrSamplerState::Filter::kNearest, dstTextureProxy->peekTexture(), fGpu); 108 } 109 110 pipeline.visitTextureEffects([&](const GrTextureEffect& te) { 111 fSamplerBindings.emplace_back(te.samplerState(), te.texture(), fGpu); 112 }); 113 114 SkASSERT(fNumSamplers == fSamplerBindings.count()); 115} 116 117void GrMtlPipelineState::setDrawState(GrMtlRenderCommandEncoder* renderCmdEncoder, 118 const GrSwizzle& writeSwizzle, 119 const GrXferProcessor& xferProcessor) { 120 this->bindUniforms(renderCmdEncoder); 121 this->setBlendConstants(renderCmdEncoder, writeSwizzle, xferProcessor); 122 this->setDepthStencilState(renderCmdEncoder); 123} 124 125void GrMtlPipelineState::bindUniforms(GrMtlRenderCommandEncoder* renderCmdEncoder) { 126 fDataManager.uploadAndBindUniformBuffers(fGpu, renderCmdEncoder); 127} 128 129void GrMtlPipelineState::bindTextures(GrMtlRenderCommandEncoder* renderCmdEncoder) { 130 SkASSERT(fNumSamplers == fSamplerBindings.count()); 131 for (int index = 0; index < fNumSamplers; ++index) { 132 renderCmdEncoder->setFragmentTexture(fSamplerBindings[index].fTexture, index); 133 renderCmdEncoder->setFragmentSamplerState(fSamplerBindings[index].fSampler, index); 134 } 135} 136 137void GrMtlPipelineState::setRenderTargetState(SkISize colorAttachmentDimensions, 138 GrSurfaceOrigin origin) { 139 SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid()); 140 if (fRenderTargetState.fRenderTargetOrigin != origin || 141 fRenderTargetState.fRenderTargetSize != colorAttachmentDimensions) { 142 fRenderTargetState.fRenderTargetSize = colorAttachmentDimensions; 143 fRenderTargetState.fRenderTargetOrigin = origin; 144 145 // The client will mark a swap buffer as kTopLeft when making a SkSurface because 146 // Metal's framebuffer space has (0, 0) at the top left. This agrees with Skia's device 147 // coords. However, in NDC (-1, -1) is the bottom left. So we flip when origin is kTopLeft. 148 bool flip = (origin == kTopLeft_GrSurfaceOrigin); 149 std::array<float, 4> v = SkSL::Compiler::GetRTAdjustVector(colorAttachmentDimensions, flip); 150 fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, v.data()); 151 if (fBuiltinUniformHandles.fRTFlipUni.isValid()) { 152 // Note above that framebuffer space has origin top left. So we need !flip here. 153 std::array<float, 2> d = 154 SkSL::Compiler::GetRTFlipVector(colorAttachmentDimensions.height(), !flip); 155 fDataManager.set2fv(fBuiltinUniformHandles.fRTFlipUni, 1, d.data()); 156 } 157 } 158} 159 160void GrMtlPipelineState::setBlendConstants(GrMtlRenderCommandEncoder* renderCmdEncoder, 161 const GrSwizzle& swizzle, 162 const GrXferProcessor& xferProcessor) { 163 if (!renderCmdEncoder) { 164 return; 165 } 166 167 const GrXferProcessor::BlendInfo& blendInfo = xferProcessor.getBlendInfo(); 168 GrBlendCoeff srcCoeff = blendInfo.fSrcBlend; 169 GrBlendCoeff dstCoeff = blendInfo.fDstBlend; 170 if (GrBlendCoeffRefsConstant(srcCoeff) || GrBlendCoeffRefsConstant(dstCoeff)) { 171 // Swizzle the blend to match what the shader will output. 172 SkPMColor4f blendConst = swizzle.applyTo(blendInfo.fBlendConstant); 173 174 renderCmdEncoder->setBlendColor(blendConst); 175 } 176} 177 178void GrMtlPipelineState::setDepthStencilState(GrMtlRenderCommandEncoder* renderCmdEncoder) { 179 const GrSurfaceOrigin& origin = fRenderTargetState.fRenderTargetOrigin; 180 GrMtlDepthStencil* state = 181 fGpu->resourceProvider().findOrCreateCompatibleDepthStencilState(fStencil, origin); 182 if (!fStencil.isDisabled()) { 183 if (fStencil.isTwoSided()) { 184 if (@available(macOS 10.11, iOS 9.0, *)) { 185 renderCmdEncoder->setStencilFrontBackReferenceValues( 186 fStencil.postOriginCCWFace(origin).fRef, 187 fStencil.postOriginCWFace(origin).fRef); 188 } else { 189 // Two-sided stencil not supported on older versions of iOS 190 // TODO: Find a way to recover from this 191 SkASSERT(false); 192 } 193 } else { 194 renderCmdEncoder->setStencilReferenceValue(fStencil.singleSidedFace().fRef); 195 } 196 } 197 renderCmdEncoder->setDepthStencilState(state->mtlDepthStencil()); 198 fGpu->commandBuffer()->addResource(sk_ref_sp<GrManagedResource>(state)); 199} 200 201void GrMtlPipelineState::SetDynamicScissorRectState(GrMtlRenderCommandEncoder* renderCmdEncoder, 202 SkISize colorAttachmentDimensions, 203 GrSurfaceOrigin rtOrigin, 204 SkIRect scissorRect) { 205 if (!scissorRect.intersect(SkIRect::MakeWH(colorAttachmentDimensions.width(), 206 colorAttachmentDimensions.height()))) { 207 scissorRect.setEmpty(); 208 } 209 210 MTLScissorRect scissor; 211 scissor.x = scissorRect.fLeft; 212 scissor.width = scissorRect.width(); 213 if (kTopLeft_GrSurfaceOrigin == rtOrigin) { 214 scissor.y = scissorRect.fTop; 215 } else { 216 SkASSERT(kBottomLeft_GrSurfaceOrigin == rtOrigin); 217 scissor.y = colorAttachmentDimensions.height() - scissorRect.fBottom; 218 } 219 scissor.height = scissorRect.height(); 220 221 SkASSERT(scissor.x >= 0); 222 SkASSERT(scissor.y >= 0); 223 224 renderCmdEncoder->setScissorRect(scissor); 225} 226 227bool GrMtlPipelineState::doesntSampleAttachment( 228 const MTLRenderPassAttachmentDescriptor* attachment) const { 229 for (int i = 0; i < fSamplerBindings.count(); ++i) { 230 if (attachment.texture == fSamplerBindings[i].fTexture || 231 attachment.resolveTexture == fSamplerBindings[i].fTexture) { 232 return false; 233 } 234 } 235 return true; 236} 237 238GR_NORETAIN_END 239