blob: 62b847faa9d76f833f4a56ac96329c9d89e318a4 [file] [log] [blame]
Timothy Liang057c3902018-08-08 10:48:45 -04001/*
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 "GrMtlPipelineState.h"
9
Timothy Liang6ed63962018-08-10 09:49:44 -040010#include "GrContext.h"
11#include "GrContextPriv.h"
12#include "GrPipeline.h"
13#include "GrRenderTarget.h"
Ethan Nicholas01063512018-10-08 16:58:25 -040014#include "GrRenderTargetPriv.h"
Timothy Liang6ed63962018-08-10 09:49:44 -040015#include "GrTexturePriv.h"
Timothy Liang057c3902018-08-08 10:48:45 -040016#include "GrMtlBuffer.h"
17#include "GrMtlGpu.h"
Timothy Liang6ed63962018-08-10 09:49:44 -040018#include "GrMtlSampler.h"
19#include "GrMtlTexture.h"
20#include "glsl/GrGLSLFragmentProcessor.h"
21#include "glsl/GrGLSLGeometryProcessor.h"
22#include "glsl/GrGLSLXferProcessor.h"
Timothy Liang057c3902018-08-08 10:48:45 -040023
Timothy Liang6ed63962018-08-10 09:49:44 -040024GrMtlPipelineState::SamplerBindings::SamplerBindings(const GrSamplerState& state,
25 GrTexture* texture,
Timothy Liang6ed63962018-08-10 09:49:44 -040026 GrMtlGpu* gpu)
Greg Daniel0f70be82018-10-08 17:35:08 +000027 : fTexture(static_cast<GrMtlTexture*>(texture)->mtlTexture()) {
Timothy Liang6ed63962018-08-10 09:49:44 -040028 // TODO: use resource provider to get sampler.
29 std::unique_ptr<GrMtlSampler> sampler(
30 GrMtlSampler::Create(gpu, state, texture->texturePriv().maxMipMapLevel()));
31 fSampler = sampler->mtlSamplerState();
32}
33
34GrMtlPipelineState::GrMtlPipelineState(
35 GrMtlGpu* gpu,
36 id<MTLRenderPipelineState> pipelineState,
37 MTLPixelFormat pixelFormat,
38 const GrGLSLBuiltinUniformHandles& builtinUniformHandles,
39 const UniformInfoArray& uniforms,
Brian Salomon12d22642019-01-29 14:38:50 -050040 sk_sp<GrMtlBuffer> geometryUniformBuffer,
41 sk_sp<GrMtlBuffer> fragmentUniformBuffer,
Timothy Liang6ed63962018-08-10 09:49:44 -040042 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)
Timothy Liang057c3902018-08-08 10:48:45 -040047 : fGpu(gpu)
48 , fPipelineState(pipelineState)
49 , fPixelFormat(pixelFormat)
Timothy Liang6ed63962018-08-10 09:49:44 -040050 , fBuiltinUniformHandles(builtinUniformHandles)
Brian Salomon12d22642019-01-29 14:38:50 -050051 , fGeometryUniformBuffer(std::move(geometryUniformBuffer))
52 , fFragmentUniformBuffer(std::move(fragmentUniformBuffer))
Timothy Liang6ed63962018-08-10 09:49:44 -040053 , fNumSamplers(numSamplers)
54 , fGeometryProcessor(std::move(geometryProcessor))
55 , fXferProcessor(std::move(xferProcessor))
56 , fFragmentProcessors(std::move(fragmentProcessors))
57 , fFragmentProcessorCnt(fragmentProcessorCnt)
Brian Salomondbf70722019-02-07 11:31:24 -050058 , fDataManager(uniforms, fGeometryUniformBuffer->size(),
59 fFragmentUniformBuffer->size()) {
Timothy Liang057c3902018-08-08 10:48:45 -040060 (void) fPixelFormat; // Suppress unused-var warning.
61}
Timothy Liang6ed63962018-08-10 09:49:44 -040062
Robert Phillipsd0fe8752019-01-31 14:13:59 -050063void GrMtlPipelineState::setData(const GrRenderTarget* renderTarget,
64 GrSurfaceOrigin origin,
65 const GrPrimitiveProcessor& primProc,
Timothy Liang6ed63962018-08-10 09:49:44 -040066 const GrPipeline& pipeline,
67 const GrTextureProxy* const primProcTextures[]) {
68 SkASSERT(primProcTextures || !primProc.numTextureSamplers());
69
Robert Phillipsd0fe8752019-01-31 14:13:59 -050070 this->setRenderTargetState(renderTarget, origin);
Timothy Liang6ed63962018-08-10 09:49:44 -040071 fGeometryProcessor->setData(fDataManager, primProc,
72 GrFragmentProcessor::CoordTransformIter(pipeline));
73 fSamplerBindings.reset();
74 for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
75 const auto& sampler = primProc.textureSampler(i);
76 auto texture = static_cast<GrMtlTexture*>(primProcTextures[i]->peekTexture());
Greg Daniel0f70be82018-10-08 17:35:08 +000077 fSamplerBindings.emplace_back(sampler.samplerState(), texture, fGpu);
Timothy Liang6ed63962018-08-10 09:49:44 -040078 }
79
80 GrFragmentProcessor::Iter iter(pipeline);
81 GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
82 const GrFragmentProcessor* fp = iter.next();
83 GrGLSLFragmentProcessor* glslFP = glslIter.next();
84 while (fp && glslFP) {
Michael Ludwigd3a357d2018-09-27 17:31:08 -040085 glslFP->setData(fDataManager, *fp);
Timothy Liang6ed63962018-08-10 09:49:44 -040086 for (int i = 0; i < fp->numTextureSamplers(); ++i) {
87 const auto& sampler = fp->textureSampler(i);
Greg Daniel0f70be82018-10-08 17:35:08 +000088 fSamplerBindings.emplace_back(sampler.samplerState(), sampler.peekTexture(), fGpu);
Timothy Liang6ed63962018-08-10 09:49:44 -040089 }
90 fp = iter.next();
91 glslFP = glslIter.next();
92 }
93 SkASSERT(!fp && !glslFP);
94
95 {
96 SkIPoint offset;
97 GrTexture* dstTexture = pipeline.peekDstTexture(&offset);
98
99 fXferProcessor->setData(fDataManager, pipeline.getXferProcessor(), dstTexture, offset);
100 }
101
102 if (GrTextureProxy* dstTextureProxy = pipeline.dstTextureProxy()) {
103 fSamplerBindings.emplace_back(GrSamplerState::ClampNearest(),
104 dstTextureProxy->peekTexture(),
Timothy Liang6ed63962018-08-10 09:49:44 -0400105 fGpu);
106 }
107
108 SkASSERT(fNumSamplers == fSamplerBindings.count());
109 if (fGeometryUniformBuffer || fFragmentUniformBuffer) {
110 fDataManager.uploadUniformBuffers(fGpu, fGeometryUniformBuffer.get(),
111 fFragmentUniformBuffer.get());
112 }
Ethan Nicholas01063512018-10-08 16:58:25 -0400113
114 if (pipeline.isStencilEnabled()) {
Robert Phillipsd0fe8752019-01-31 14:13:59 -0500115 SkASSERT(renderTarget->renderTargetPriv().getStencilAttachment());
Ethan Nicholas01063512018-10-08 16:58:25 -0400116 fStencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(),
Robert Phillipsd0fe8752019-01-31 14:13:59 -0500117 renderTarget->renderTargetPriv().numStencilBits());
Ethan Nicholas01063512018-10-08 16:58:25 -0400118 }
Timothy Liang6ed63962018-08-10 09:49:44 -0400119}
120
121void GrMtlPipelineState::bind(id<MTLRenderCommandEncoder> renderCmdEncoder) {
122 if (fGeometryUniformBuffer) {
123 [renderCmdEncoder setVertexBuffer: fGeometryUniformBuffer->mtlBuffer()
124 offset: 0
125 atIndex: GrMtlUniformHandler::kGeometryBinding];
126 }
127 if (fFragmentUniformBuffer) {
128 [renderCmdEncoder setFragmentBuffer: fFragmentUniformBuffer->mtlBuffer()
129 offset: 0
130 atIndex: GrMtlUniformHandler::kFragBinding];
131 }
132 SkASSERT(fNumSamplers == fSamplerBindings.count());
133 for (int index = 0; index < fNumSamplers; ++index) {
Greg Daniel0f70be82018-10-08 17:35:08 +0000134 [renderCmdEncoder setFragmentTexture: fSamplerBindings[index].fTexture
135 atIndex: index];
136 [renderCmdEncoder setFragmentSamplerState: fSamplerBindings[index].fSampler
137 atIndex: index];
Timothy Liang6ed63962018-08-10 09:49:44 -0400138 }
139}
140
Robert Phillipsd0fe8752019-01-31 14:13:59 -0500141void GrMtlPipelineState::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) {
Timothy Liang6ed63962018-08-10 09:49:44 -0400142 // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
Greg Daniele6ab9982018-08-22 13:56:32 +0000143 if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
144 fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) {
145 fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height()));
Timothy Liang6ed63962018-08-10 09:49:44 -0400146 }
147
148 // set RT adjustment
149 SkISize size;
150 size.set(rt->width(), rt->height());
151 SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
Robert Phillipsd0fe8752019-01-31 14:13:59 -0500152 if (fRenderTargetState.fRenderTargetOrigin != origin ||
Timothy Liang6ed63962018-08-10 09:49:44 -0400153 fRenderTargetState.fRenderTargetSize != size) {
154 fRenderTargetState.fRenderTargetSize = size;
Robert Phillipsd0fe8752019-01-31 14:13:59 -0500155 fRenderTargetState.fRenderTargetOrigin = origin;
Timothy Liang6ed63962018-08-10 09:49:44 -0400156
157 float rtAdjustmentVec[4];
158 fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
159 fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
160 }
161}
Timothy Liangde0be802018-08-10 13:48:08 -0400162
163static bool blend_coeff_refs_constant(GrBlendCoeff coeff) {
164 switch (coeff) {
165 case kConstC_GrBlendCoeff:
166 case kIConstC_GrBlendCoeff:
167 case kConstA_GrBlendCoeff:
168 case kIConstA_GrBlendCoeff:
169 return true;
170 default:
171 return false;
172 }
173}
174
175void GrMtlPipelineState::setBlendConstants(id<MTLRenderCommandEncoder> renderCmdEncoder,
176 GrPixelConfig config,
177 const GrXferProcessor& xferProcessor) {
178 if (!renderCmdEncoder) {
179 return;
180 }
181
182 GrXferProcessor::BlendInfo blendInfo;
183 xferProcessor.getBlendInfo(&blendInfo);
184 GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
185 GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
186 if (blend_coeff_refs_constant(srcCoeff) || blend_coeff_refs_constant(dstCoeff)) {
Timothy Liangde0be802018-08-10 13:48:08 -0400187 // Swizzle the blend to match what the shader will output.
188 const GrSwizzle& swizzle = fGpu->caps()->shaderCaps()->configOutputSwizzle(config);
Brian Osman422f95b2018-11-05 16:49:04 -0500189 SkPMColor4f blendConst = swizzle.applyTo(blendInfo.fBlendConstant);
Timothy Liangde0be802018-08-10 13:48:08 -0400190
Brian Osman422f95b2018-11-05 16:49:04 -0500191 [renderCmdEncoder setBlendColorRed: blendConst.fR
192 green: blendConst.fG
193 blue: blendConst.fB
194 alpha: blendConst.fA];
Timothy Liangde0be802018-08-10 13:48:08 -0400195 }
196}
Ethan Nicholas01063512018-10-08 16:58:25 -0400197
198MTLStencilOperation skia_stencil_op_to_mtl(GrStencilOp op) {
199 switch (op) {
200 case GrStencilOp::kKeep:
201 return MTLStencilOperationKeep;
202 case GrStencilOp::kZero:
203 return MTLStencilOperationZero;
204 case GrStencilOp::kReplace:
205 return MTLStencilOperationReplace;
206 case GrStencilOp::kInvert:
207 return MTLStencilOperationInvert;
208 case GrStencilOp::kIncWrap:
209 return MTLStencilOperationIncrementWrap;
210 case GrStencilOp::kDecWrap:
211 return MTLStencilOperationDecrementWrap;
212 case GrStencilOp::kIncClamp:
213 return MTLStencilOperationIncrementClamp;
214 case GrStencilOp::kDecClamp:
215 return MTLStencilOperationDecrementClamp;
216 }
217}
218
219MTLStencilDescriptor* skia_stencil_to_mtl(GrStencilSettings::Face face) {
220 MTLStencilDescriptor* result = [[MTLStencilDescriptor alloc] init];
221 switch (face.fTest) {
222 case GrStencilTest::kAlways:
223 result.stencilCompareFunction = MTLCompareFunctionAlways;
224 break;
225 case GrStencilTest::kNever:
226 result.stencilCompareFunction = MTLCompareFunctionNever;
227 break;
228 case GrStencilTest::kGreater:
229 result.stencilCompareFunction = MTLCompareFunctionGreater;
230 break;
231 case GrStencilTest::kGEqual:
232 result.stencilCompareFunction = MTLCompareFunctionGreaterEqual;
233 break;
234 case GrStencilTest::kLess:
235 result.stencilCompareFunction = MTLCompareFunctionLess;
236 break;
237 case GrStencilTest::kLEqual:
238 result.stencilCompareFunction = MTLCompareFunctionLessEqual;
239 break;
240 case GrStencilTest::kEqual:
241 result.stencilCompareFunction = MTLCompareFunctionEqual;
242 break;
243 case GrStencilTest::kNotEqual:
244 result.stencilCompareFunction = MTLCompareFunctionNotEqual;
245 break;
246 }
247 result.readMask = face.fTestMask;
248 result.writeMask = face.fWriteMask;
249 result.depthStencilPassOperation = skia_stencil_op_to_mtl(face.fPassOp);
250 result.stencilFailureOperation = skia_stencil_op_to_mtl(face.fFailOp);
251 return result;
252}
253
254void GrMtlPipelineState::setDepthStencilState(id<MTLRenderCommandEncoder> renderCmdEncoder) {
255 if (fStencil.isDisabled()) {
256 MTLDepthStencilDescriptor* desc = [[MTLDepthStencilDescriptor alloc] init];
257 id<MTLDepthStencilState> state = [fGpu->device() newDepthStencilStateWithDescriptor:desc];
258 [renderCmdEncoder setDepthStencilState:state];
259 }
260 else {
261 MTLDepthStencilDescriptor* desc = [[MTLDepthStencilDescriptor alloc] init];
262 desc.frontFaceStencil = skia_stencil_to_mtl(fStencil.front());
263 if (fStencil.isTwoSided()) {
264 desc.backFaceStencil = skia_stencil_to_mtl(fStencil.back());
265 [renderCmdEncoder setStencilFrontReferenceValue:fStencil.front().fRef
266 backReferenceValue:fStencil.back().fRef];
267 }
268 else {
269 desc.backFaceStencil = desc.frontFaceStencil;
270 [renderCmdEncoder setStencilReferenceValue:fStencil.front().fRef];
271 }
272 id<MTLDepthStencilState> state = [fGpu->device() newDepthStencilStateWithDescriptor:desc];
273 [renderCmdEncoder setDepthStencilState:state];
274 }
275}