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