blob: 850b3888199536b0a31c9d89bfe416bc20fa556d [file] [log] [blame]
Stephen Whitebb6bed12019-08-02 09:57:55 -04001/*
2 * Copyright 2019 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/dawn/GrDawnProgramBuilder.h"
9
10#include "include/gpu/GrRenderTarget.h"
11#include "src/gpu/dawn/GrDawnGpu.h"
12#include "src/sksl/SkSLCompiler.h"
13
14#include "src/gpu/GrShaderUtils.h"
15
16static SkSL::String sksl_to_spirv(const GrDawnGpu* gpu, const char* shaderString,
17 SkSL::Program::Kind kind, SkSL::Program::Inputs* inputs) {
18 SkSL::Program::Settings settings;
19 std::unique_ptr<SkSL::Program> program = gpu->shaderCompiler()->convertProgram(
20 kind,
21 shaderString,
22 settings);
23 if (!program) {
24 SkDebugf("SkSL error:\n%s\n", gpu->shaderCompiler()->errorText().c_str());
25 SkASSERT(false);
26 return "";
27 }
28 *inputs = program->fInputs;
29 SkSL::String code;
30 if (!gpu->shaderCompiler()->toSPIRV(*program, &code)) {
31 return "";
32 }
33 return code;
34}
35
36static dawn::BlendFactor to_dawn_blend_factor(GrBlendCoeff coeff) {
37 switch (coeff) {
38 case kZero_GrBlendCoeff:
39 return dawn::BlendFactor::Zero;
40 case kOne_GrBlendCoeff:
41 return dawn::BlendFactor::One;
42 case kSC_GrBlendCoeff:
43 return dawn::BlendFactor::SrcColor;
44 case kISC_GrBlendCoeff:
45 return dawn::BlendFactor::OneMinusSrcColor;
46 case kDC_GrBlendCoeff:
47 return dawn::BlendFactor::DstColor;
48 case kIDC_GrBlendCoeff:
49 return dawn::BlendFactor::OneMinusDstColor;
50 case kSA_GrBlendCoeff:
51 return dawn::BlendFactor::SrcAlpha;
52 case kISA_GrBlendCoeff:
53 return dawn::BlendFactor::OneMinusSrcAlpha;
54 case kDA_GrBlendCoeff:
55 return dawn::BlendFactor::DstAlpha;
56 case kIDA_GrBlendCoeff:
57 return dawn::BlendFactor::OneMinusDstAlpha;
58 case kConstC_GrBlendCoeff:
59 return dawn::BlendFactor::BlendColor;
60 case kIConstC_GrBlendCoeff:
61 return dawn::BlendFactor::OneMinusBlendColor;
62 case kConstA_GrBlendCoeff:
63 case kIConstA_GrBlendCoeff:
64 case kS2C_GrBlendCoeff:
65 case kIS2C_GrBlendCoeff:
66 case kS2A_GrBlendCoeff:
67 case kIS2A_GrBlendCoeff:
68 default:
69 SkASSERT(!"unsupported blend coefficient");
70 return dawn::BlendFactor::One;
71 }
72}
73
74static dawn::BlendOperation to_dawn_blend_operation(GrBlendEquation equation) {
75 switch (equation) {
76 case kAdd_GrBlendEquation:
77 return dawn::BlendOperation::Add;
78 case kSubtract_GrBlendEquation:
79 return dawn::BlendOperation::Subtract;
80 default:
81 SkASSERT(!"unsupported blend equation");
82 return dawn::BlendOperation::Add;
83 }
84}
85
86static dawn::ColorStateDescriptor create_color_state(const GrDawnGpu* gpu,
87 const GrPipeline& pipeline,
88 dawn::TextureFormat colorFormat) {
89 GrXferProcessor::BlendInfo blendInfo = pipeline.getXferProcessor().getBlendInfo();
90 GrBlendEquation equation = blendInfo.fEquation;
91 GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
92 GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
93
94 dawn::BlendFactor srcFactor = to_dawn_blend_factor(srcCoeff);
95 dawn::BlendFactor dstFactor = to_dawn_blend_factor(dstCoeff);
96 dawn::BlendOperation operation = to_dawn_blend_operation(equation);
97 auto mask = blendInfo.fWriteColor ? dawn::ColorWriteMask::All : dawn::ColorWriteMask::None;
98
99 dawn::BlendDescriptor colorDesc = {operation, srcFactor, dstFactor};
100 dawn::BlendDescriptor alphaDesc = {operation, srcFactor, dstFactor};
101
102 dawn::ColorStateDescriptor descriptor;
103 descriptor.format = colorFormat;
104 descriptor.alphaBlend = alphaDesc;
105 descriptor.colorBlend = colorDesc;
106 descriptor.nextInChain = nullptr;
107 descriptor.writeMask = mask;
108
109 return descriptor;
110}
111
112static dawn::BindGroupBinding make_bind_group_binding(uint32_t binding, const dawn::Buffer& buffer,
113 uint32_t offset, uint32_t size, const
114 dawn::Sampler& sampler,
115 const dawn::TextureView& textureView) {
116 dawn::BindGroupBinding result;
117 result.binding = binding;
118 result.buffer = buffer;
119 result.offset = offset;
120 result.size = size;
121 result.sampler = sampler;
122 result.textureView = textureView;
123 return result;
124}
125
126static dawn::BindGroupBinding make_bind_group_binding(uint32_t binding, const dawn::Buffer& buffer,
127 uint32_t offset, uint32_t size) {
128 return make_bind_group_binding(binding, buffer, offset, size, nullptr, nullptr);
129}
130
131sk_sp<GrDawnProgram> GrDawnProgramBuilder::Build(GrDawnGpu* gpu,
132 GrRenderTarget* renderTarget,
133 GrSurfaceOrigin origin,
134 const GrPipeline& pipeline,
135 const GrPrimitiveProcessor& primProc,
136 const GrTextureProxy* const primProcProxies[],
137 dawn::TextureFormat colorFormat,
138 GrProgramDesc* desc) {
139 GrDawnProgramBuilder builder(gpu, renderTarget, origin, primProc, primProcProxies, pipeline,
140 desc);
141 if (!builder.emitAndInstallProcs()) {
142 return nullptr;
143 }
144
145 builder.fVS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n");
146 builder.fFS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n");
147 builder.fVS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n");
148 builder.fFS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n");
149
150 builder.finalizeShaders();
151
152 SkSL::Program::Inputs vertInputs, fragInputs;
153 GrDawnUniformHandler::UniformInfoArray& uniforms = builder.fUniformHandler.fUniforms;
154 uint32_t geometryUniformSize = builder.fUniformHandler.fCurrentGeometryUBOOffset;
155 uint32_t fragmentUniformSize = builder.fUniformHandler.fCurrentFragmentUBOOffset;
156 sk_sp<GrDawnProgram> result(
157 new GrDawnProgram(uniforms, geometryUniformSize, fragmentUniformSize));
158 result->fVSModule = builder.createShaderModule(builder.fVS, SkSL::Program::kVertex_Kind,
159 &vertInputs);
160 result->fFSModule = builder.createShaderModule(builder.fFS, SkSL::Program::kFragment_Kind,
161 &fragInputs);
162 result->fGeometryProcessor = std::move(builder.fGeometryProcessor);
163 result->fXferProcessor = std::move(builder.fXferProcessor);
164 result->fFragmentProcessors = std::move(builder.fFragmentProcessors);
165 result->fFragmentProcessorCnt = builder.fFragmentProcessorCnt;
166 std::vector<dawn::BindGroupLayoutBinding> layoutBindings;
167 std::vector<dawn::BindGroupBinding> bindings;
168
169 if (0 != geometryUniformSize) {
170 dawn::BufferDescriptor desc;
171 desc.usage = dawn::BufferUsageBit::Uniform | dawn::BufferUsageBit::CopyDst;
172 desc.size = geometryUniformSize;
173 result->fGeometryUniformBuffer = gpu->device().CreateBuffer(&desc);
174 bindings.push_back(make_bind_group_binding(0, result->fGeometryUniformBuffer, 0,
175 geometryUniformSize));
176 layoutBindings.push_back({ 0, dawn::ShaderStageBit::Vertex,
177 dawn::BindingType::UniformBuffer});
178 }
179 if (0 != fragmentUniformSize) {
180 dawn::BufferDescriptor desc;
181 desc.usage = dawn::BufferUsageBit::Uniform | dawn::BufferUsageBit::CopyDst;
182 desc.size = fragmentUniformSize;
183 result->fFragmentUniformBuffer = gpu->device().CreateBuffer(&desc);
184 bindings.push_back(make_bind_group_binding(1, result->fFragmentUniformBuffer, 0,
185 fragmentUniformSize));
186 layoutBindings.push_back({ 1, dawn::ShaderStageBit::Fragment,
187 dawn::BindingType::UniformBuffer});
188 }
189 dawn::BindGroupLayoutDescriptor bindGroupLayoutDesc;
190 bindGroupLayoutDesc.bindingCount = layoutBindings.size();
191 bindGroupLayoutDesc.bindings = layoutBindings.data();
192 auto bindGroupLayout = gpu->device().CreateBindGroupLayout(&bindGroupLayoutDesc);
193 dawn::BindGroupDescriptor descriptor;
194 descriptor.layout = bindGroupLayout;
195 descriptor.bindingCount = bindings.size();
196 descriptor.bindings = bindings.data();
197 result->fUniformBindGroup = gpu->device().CreateBindGroup(&descriptor);
198 dawn::PipelineLayoutDescriptor pipelineLayoutDesc;
199 pipelineLayoutDesc.bindGroupLayoutCount = 1;
200 pipelineLayoutDesc.bindGroupLayouts = &bindGroupLayout;
201 result->fPipelineLayout = gpu->device().CreatePipelineLayout(&pipelineLayoutDesc);
202 result->fBuiltinUniformHandles = builder.fUniformHandles;
203 result->fColorState = create_color_state(gpu, pipeline, colorFormat);
204 return result;
205}
206
207GrDawnProgramBuilder::GrDawnProgramBuilder(GrDawnGpu* gpu,
208 GrRenderTarget* renderTarget,
209 GrSurfaceOrigin origin,
210 const GrPrimitiveProcessor& primProc,
211 const GrTextureProxy* const primProcProxies[],
212 const GrPipeline& pipeline,
213 GrProgramDesc* desc)
214 : INHERITED(renderTarget, origin, primProc, primProcProxies, pipeline, desc)
215 , fGpu(gpu)
216 , fVaryingHandler(this)
217 , fUniformHandler(this) {
218}
219
220dawn::ShaderModule GrDawnProgramBuilder::createShaderModule(const GrGLSLShaderBuilder& builder,
221 SkSL::Program::Kind kind,
222 SkSL::Program::Inputs* inputs) {
223 dawn::Device device = fGpu->device();
224 SkString source(builder.fCompilerString.c_str());
225
226#if 0
227 SkSL::String sksl = GrShaderUtils::PrettyPrint(builder.fCompilerString);
228 printf("converting program:\n%s\n", sksl.c_str());
229#endif
230
231 SkSL::String spirvSource = sksl_to_spirv(fGpu, source.c_str(), kind, inputs);
232
233 dawn::ShaderModuleDescriptor desc;
234 desc.codeSize = spirvSource.size() / 4;
235 desc.code = reinterpret_cast<const uint32_t*>(spirvSource.c_str());
236
237 return device.CreateShaderModule(&desc);
238};
239
240const GrCaps* GrDawnProgramBuilder::caps() const {
241 return fGpu->caps();
242}
243
244void GrDawnProgram::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) {
245 // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
246 if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
247 fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) {
248 fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height()));
249 }
250
251 // set RT adjustment
252 SkISize size;
253 size.set(rt->width(), rt->height());
254 SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
255 if (fRenderTargetState.fRenderTargetOrigin != origin ||
256 fRenderTargetState.fRenderTargetSize != size) {
257 fRenderTargetState.fRenderTargetSize = size;
258 fRenderTargetState.fRenderTargetOrigin = origin;
259
260 float rtAdjustmentVec[4];
261 fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
262 fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
263 }
264}
265
266void GrDawnProgram::setData(const GrPrimitiveProcessor& primProc,
267 const GrRenderTarget* renderTarget,
268 GrSurfaceOrigin origin,
269 const GrPipeline& pipeline) {
270 this->setRenderTargetState(renderTarget, origin);
271 fGeometryProcessor->setData(fDataManager, primProc,
272 GrFragmentProcessor::CoordTransformIter(pipeline));
273 GrFragmentProcessor::Iter iter(pipeline);
274 GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
275 const GrFragmentProcessor* fp = iter.next();
276 GrGLSLFragmentProcessor* glslFP = glslIter.next();
277 while (fp && glslFP) {
278 glslFP->setData(fDataManager, *fp);
279 fp = iter.next();
280 glslFP = glslIter.next();
281 }
282 fDataManager.uploadUniformBuffers(fGeometryUniformBuffer,
283 fFragmentUniformBuffer);
284}