• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 "src/gpu/GrAutoLocaleSetter.h"
11 #include "src/gpu/GrRenderTarget.h"
12 #include "src/gpu/GrShaderUtils.h"
13 #include "src/gpu/GrStencilSettings.h"
14 #include "src/gpu/dawn/GrDawnGpu.h"
15 #include "src/gpu/dawn/GrDawnTexture.h"
16 #include "src/gpu/effects/GrTextureEffect.h"
17 
to_dawn_blend_factor(GrBlendCoeff coeff)18 static wgpu::BlendFactor to_dawn_blend_factor(GrBlendCoeff coeff) {
19     switch (coeff) {
20         case kZero_GrBlendCoeff:
21             return wgpu::BlendFactor::Zero;
22         case kOne_GrBlendCoeff:
23             return wgpu::BlendFactor::One;
24         case kSC_GrBlendCoeff:
25             return wgpu::BlendFactor::Src;
26         case kISC_GrBlendCoeff:
27             return wgpu::BlendFactor::OneMinusSrc;
28         case kDC_GrBlendCoeff:
29             return wgpu::BlendFactor::Dst;
30         case kIDC_GrBlendCoeff:
31             return wgpu::BlendFactor::OneMinusDst;
32         case kSA_GrBlendCoeff:
33             return wgpu::BlendFactor::SrcAlpha;
34         case kISA_GrBlendCoeff:
35             return wgpu::BlendFactor::OneMinusSrcAlpha;
36         case kDA_GrBlendCoeff:
37             return wgpu::BlendFactor::DstAlpha;
38         case kIDA_GrBlendCoeff:
39             return wgpu::BlendFactor::OneMinusDstAlpha;
40         case kConstC_GrBlendCoeff:
41             return wgpu::BlendFactor::Constant;
42         case kIConstC_GrBlendCoeff:
43             return wgpu::BlendFactor::OneMinusConstant;
44         case kS2C_GrBlendCoeff:
45         case kIS2C_GrBlendCoeff:
46         case kS2A_GrBlendCoeff:
47         case kIS2A_GrBlendCoeff:
48         default:
49             SkASSERT(!"unsupported blend coefficient");
50             return wgpu::BlendFactor::One;
51         }
52 }
53 
to_dawn_blend_factor_for_alpha(GrBlendCoeff coeff)54 static wgpu::BlendFactor to_dawn_blend_factor_for_alpha(GrBlendCoeff coeff) {
55     switch (coeff) {
56     // Force all srcColor used in alpha slot to alpha version.
57     case kSC_GrBlendCoeff:
58         return wgpu::BlendFactor::SrcAlpha;
59     case kISC_GrBlendCoeff:
60         return wgpu::BlendFactor::OneMinusSrcAlpha;
61     case kDC_GrBlendCoeff:
62         return wgpu::BlendFactor::DstAlpha;
63     case kIDC_GrBlendCoeff:
64         return wgpu::BlendFactor::OneMinusDstAlpha;
65     default:
66         return to_dawn_blend_factor(coeff);
67     }
68 }
69 
to_dawn_blend_operation(GrBlendEquation equation)70 static wgpu::BlendOperation to_dawn_blend_operation(GrBlendEquation equation) {
71     switch (equation) {
72     case kAdd_GrBlendEquation:
73         return wgpu::BlendOperation::Add;
74     case kSubtract_GrBlendEquation:
75         return wgpu::BlendOperation::Subtract;
76     case kReverseSubtract_GrBlendEquation:
77         return wgpu::BlendOperation::ReverseSubtract;
78     default:
79         SkASSERT(!"unsupported blend equation");
80         return wgpu::BlendOperation::Add;
81     }
82 }
83 
to_dawn_compare_function(GrStencilTest test)84 static wgpu::CompareFunction to_dawn_compare_function(GrStencilTest test) {
85     switch (test) {
86         case GrStencilTest::kAlways:
87             return wgpu::CompareFunction::Always;
88         case GrStencilTest::kNever:
89             return wgpu::CompareFunction::Never;
90         case GrStencilTest::kGreater:
91             return wgpu::CompareFunction::Greater;
92         case GrStencilTest::kGEqual:
93             return wgpu::CompareFunction::GreaterEqual;
94         case GrStencilTest::kLess:
95             return wgpu::CompareFunction::Less;
96         case GrStencilTest::kLEqual:
97             return wgpu::CompareFunction::LessEqual;
98         case GrStencilTest::kEqual:
99             return wgpu::CompareFunction::Equal;
100         case GrStencilTest::kNotEqual:
101             return wgpu::CompareFunction::NotEqual;
102         default:
103             SkASSERT(!"unsupported stencil test");
104             return wgpu::CompareFunction::Always;
105     }
106 }
107 
to_dawn_stencil_operation(GrStencilOp op)108 static wgpu::StencilOperation to_dawn_stencil_operation(GrStencilOp op) {
109     switch (op) {
110         case GrStencilOp::kKeep:
111             return wgpu::StencilOperation::Keep;
112         case GrStencilOp::kZero:
113             return wgpu::StencilOperation::Zero;
114         case GrStencilOp::kReplace:
115             return wgpu::StencilOperation::Replace;
116         case GrStencilOp::kInvert:
117             return wgpu::StencilOperation::Invert;
118         case GrStencilOp::kIncClamp:
119             return wgpu::StencilOperation::IncrementClamp;
120         case GrStencilOp::kDecClamp:
121             return wgpu::StencilOperation::DecrementClamp;
122         case GrStencilOp::kIncWrap:
123             return wgpu::StencilOperation::IncrementWrap;
124         case GrStencilOp::kDecWrap:
125             return wgpu::StencilOperation::DecrementWrap;
126         default:
127             SkASSERT(!"unsupported stencil function");
128             return wgpu::StencilOperation::Keep;
129     }
130 }
131 
to_dawn_primitive_topology(GrPrimitiveType primitiveType)132 static wgpu::PrimitiveTopology to_dawn_primitive_topology(GrPrimitiveType primitiveType) {
133     switch (primitiveType) {
134         case GrPrimitiveType::kTriangles:
135             return wgpu::PrimitiveTopology::TriangleList;
136         case GrPrimitiveType::kTriangleStrip:
137             return wgpu::PrimitiveTopology::TriangleStrip;
138         case GrPrimitiveType::kPoints:
139             return wgpu::PrimitiveTopology::PointList;
140         case GrPrimitiveType::kLines:
141             return wgpu::PrimitiveTopology::LineList;
142         case GrPrimitiveType::kLineStrip:
143             return wgpu::PrimitiveTopology::LineStrip;
144         case GrPrimitiveType::kPath:
145         default:
146             SkASSERT(!"unsupported primitive topology");
147             return wgpu::PrimitiveTopology::TriangleList;
148     }
149 }
150 
to_dawn_vertex_format(GrVertexAttribType type)151 static wgpu::VertexFormat to_dawn_vertex_format(GrVertexAttribType type) {
152     switch (type) {
153     case kFloat_GrVertexAttribType:
154     case kHalf_GrVertexAttribType:
155         return wgpu::VertexFormat::Float32;
156     case kFloat2_GrVertexAttribType:
157     case kHalf2_GrVertexAttribType:
158         return wgpu::VertexFormat::Float32x2;
159     case kFloat3_GrVertexAttribType:
160         return wgpu::VertexFormat::Float32x3;
161     case kFloat4_GrVertexAttribType:
162     case kHalf4_GrVertexAttribType:
163         return wgpu::VertexFormat::Float32x4;
164     case kUShort2_GrVertexAttribType:
165         return wgpu::VertexFormat::Uint16x2;
166     case kInt_GrVertexAttribType:
167         return wgpu::VertexFormat::Sint32;
168     case kUByte4_norm_GrVertexAttribType:
169         return wgpu::VertexFormat::Unorm8x4;
170     default:
171         SkASSERT(!"unsupported vertex format");
172         return wgpu::VertexFormat::Float32x4;
173     }
174 }
175 
create_blend_state(const GrDawnGpu * gpu,const GrPipeline & pipeline)176 static wgpu::BlendState create_blend_state(const GrDawnGpu* gpu, const GrPipeline& pipeline) {
177     GrXferProcessor::BlendInfo blendInfo = pipeline.getXferProcessor().getBlendInfo();
178     GrBlendEquation equation = blendInfo.fEquation;
179     GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
180     GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
181 
182     wgpu::BlendFactor srcFactor = to_dawn_blend_factor(srcCoeff);
183     wgpu::BlendFactor dstFactor = to_dawn_blend_factor(dstCoeff);
184     wgpu::BlendFactor srcFactorAlpha = to_dawn_blend_factor_for_alpha(srcCoeff);
185     wgpu::BlendFactor dstFactorAlpha = to_dawn_blend_factor_for_alpha(dstCoeff);
186     wgpu::BlendOperation operation = to_dawn_blend_operation(equation);
187 
188     wgpu::BlendState blendState;
189     blendState.color = {operation, srcFactor, dstFactor};
190     blendState.alpha = {operation, srcFactorAlpha, dstFactorAlpha};
191 
192     return blendState;
193 }
194 
to_stencil_state_face(const GrStencilSettings::Face & face)195 static wgpu::StencilFaceState to_stencil_state_face(const GrStencilSettings::Face& face) {
196      wgpu::StencilFaceState desc;
197      desc.compare = to_dawn_compare_function(face.fTest);
198      desc.failOp = desc.depthFailOp = to_dawn_stencil_operation(face.fFailOp);
199      desc.passOp = to_dawn_stencil_operation(face.fPassOp);
200      return desc;
201 }
202 
create_depth_stencil_state(const GrProgramInfo & programInfo,wgpu::TextureFormat depthStencilFormat)203 static wgpu::DepthStencilState create_depth_stencil_state(
204         const GrProgramInfo& programInfo,
205         wgpu::TextureFormat depthStencilFormat) {
206     GrStencilSettings stencilSettings = programInfo.nonGLStencilSettings();
207     GrSurfaceOrigin origin = programInfo.origin();
208 
209     wgpu::DepthStencilState state;
210     state.format = depthStencilFormat;
211     if (!stencilSettings.isDisabled()) {
212         if (stencilSettings.isTwoSided()) {
213             auto front = stencilSettings.postOriginCCWFace(origin);
214             auto back = stencilSettings.postOriginCWFace(origin);
215             state.stencilFront = to_stencil_state_face(front);
216             state.stencilBack = to_stencil_state_face(back);
217             state.stencilReadMask = front.fTestMask;
218             state.stencilWriteMask = front.fWriteMask;
219         } else {
220             auto frontAndBack = stencilSettings.singleSidedFace();
221             state.stencilBack = state.stencilFront = to_stencil_state_face(frontAndBack);
222             state.stencilReadMask = frontAndBack.fTestMask;
223             state.stencilWriteMask = frontAndBack.fWriteMask;
224         }
225     }
226     return state;
227 }
228 
make_bind_group_entry(uint32_t binding,const wgpu::Sampler & sampler,const wgpu::TextureView & textureView)229 static wgpu::BindGroupEntry make_bind_group_entry(uint32_t binding,
230                                                   const wgpu::Sampler& sampler,
231                                                   const wgpu::TextureView& textureView) {
232     wgpu::BindGroupEntry result;
233     result.binding = binding;
234     result.buffer = nullptr;
235     result.offset = 0;
236     result.size = 0;
237     result.sampler = sampler;
238     result.textureView = textureView;
239     return result;
240 }
241 
make_bind_group_entry(uint32_t binding,const wgpu::Sampler & sampler)242 static wgpu::BindGroupEntry make_bind_group_entry(uint32_t binding,
243                                                   const wgpu::Sampler& sampler) {
244     return make_bind_group_entry(binding, sampler, nullptr);
245 }
246 
make_bind_group_entry(uint32_t binding,const wgpu::TextureView & textureView)247 static wgpu::BindGroupEntry make_bind_group_entry(uint32_t binding,
248                                                   const wgpu::TextureView& textureView) {
249     return make_bind_group_entry(binding, nullptr, textureView);
250 }
251 
Build(GrDawnGpu * gpu,GrRenderTarget * renderTarget,const GrProgramInfo & programInfo,wgpu::TextureFormat colorFormat,bool hasDepthStencil,wgpu::TextureFormat depthStencilFormat,GrProgramDesc * desc)252 sk_sp<GrDawnProgram> GrDawnProgramBuilder::Build(GrDawnGpu* gpu,
253                                                  GrRenderTarget* renderTarget,
254                                                  const GrProgramInfo& programInfo,
255                                                  wgpu::TextureFormat colorFormat,
256                                                  bool hasDepthStencil,
257                                                  wgpu::TextureFormat depthStencilFormat,
258                                                  GrProgramDesc* desc) {
259     GrAutoLocaleSetter als("C");
260 
261     GrDawnProgramBuilder builder(gpu, programInfo, desc);
262     if (!builder.emitAndInstallProcs()) {
263         return nullptr;
264     }
265 
266     builder.finalizeShaders();
267 
268     SkSL::Program::Inputs vertInputs, fragInputs;
269     bool flipY = programInfo.origin() != kTopLeft_GrSurfaceOrigin;
270     auto vsModule = builder.createShaderModule(builder.fVS, SkSL::ProgramKind::kVertex, flipY,
271                                                &vertInputs);
272     auto fsModule = builder.createShaderModule(builder.fFS, SkSL::ProgramKind::kFragment, flipY,
273                                                &fragInputs);
274     GrSPIRVUniformHandler::UniformInfoArray& uniforms = builder.fUniformHandler.fUniforms;
275     uint32_t uniformBufferSize = builder.fUniformHandler.fCurrentUBOOffset;
276     sk_sp<GrDawnProgram> result(new GrDawnProgram(uniforms, uniformBufferSize));
277     result->fGPImpl = std::move(builder.fGPImpl);
278     result->fXPImpl = std::move(builder.fXPImpl);
279     result->fFPImpls = std::move(builder.fFPImpls);
280     std::vector<wgpu::BindGroupLayoutEntry> uniformLayoutEntries;
281     if (0 != uniformBufferSize) {
282         wgpu::BindGroupLayoutEntry entry;
283         entry.binding = GrSPIRVUniformHandler::kUniformBinding;
284         entry.visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment;
285         entry.buffer.type = wgpu::BufferBindingType::Uniform;
286         uniformLayoutEntries.push_back(std::move(entry));
287     }
288     wgpu::BindGroupLayoutDescriptor uniformBindGroupLayoutDesc;
289     uniformBindGroupLayoutDesc.entryCount = uniformLayoutEntries.size();
290     uniformBindGroupLayoutDesc.entries = uniformLayoutEntries.data();
291     result->fBindGroupLayouts.push_back(
292         gpu->device().CreateBindGroupLayout(&uniformBindGroupLayoutDesc));
293     uint32_t binding = 0;
294     std::vector<wgpu::BindGroupLayoutEntry> textureLayoutEntries;
295     int textureCount = builder.fUniformHandler.fSamplers.count();
296     if (textureCount > 0) {
297         for (int i = 0; i < textureCount; ++i)  {
298             {
299                 wgpu::BindGroupLayoutEntry entry;
300                 entry.binding = binding++;
301                 entry.visibility = wgpu::ShaderStage::Fragment;
302                 entry.sampler.type = wgpu::SamplerBindingType::Filtering;
303                 textureLayoutEntries.push_back(std::move(entry));
304             }
305             {
306                 wgpu::BindGroupLayoutEntry entry;
307                 entry.binding = binding++;
308                 entry.visibility = wgpu::ShaderStage::Fragment;
309                 entry.texture.sampleType = wgpu::TextureSampleType::Float;
310                 entry.texture.viewDimension = wgpu::TextureViewDimension::e2D;
311                 textureLayoutEntries.push_back(std::move(entry));
312             }
313         }
314         wgpu::BindGroupLayoutDescriptor textureBindGroupLayoutDesc;
315         textureBindGroupLayoutDesc.entryCount = textureLayoutEntries.size();
316         textureBindGroupLayoutDesc.entries = textureLayoutEntries.data();
317         result->fBindGroupLayouts.push_back(
318             gpu->device().CreateBindGroupLayout(&textureBindGroupLayoutDesc));
319     }
320     wgpu::PipelineLayoutDescriptor pipelineLayoutDesc;
321     pipelineLayoutDesc.bindGroupLayoutCount = result->fBindGroupLayouts.size();
322     pipelineLayoutDesc.bindGroupLayouts = result->fBindGroupLayouts.data();
323     auto pipelineLayout = gpu->device().CreatePipelineLayout(&pipelineLayoutDesc);
324     result->fBuiltinUniformHandles = builder.fUniformHandles;
325     const GrPipeline& pipeline = programInfo.pipeline();
326     wgpu::DepthStencilState depthStencilState;
327 
328 #ifdef SK_DEBUG
329     if (programInfo.isStencilEnabled()) {
330         SkASSERT(renderTarget->numStencilBits(renderTarget->numSamples() > 1) == 8);
331     }
332 #endif
333     depthStencilState = create_depth_stencil_state(programInfo, depthStencilFormat);
334 
335     std::vector<wgpu::VertexBufferLayout> inputs;
336 
337     std::vector<wgpu::VertexAttribute> vertexAttributes;
338     const GrGeometryProcessor& geomProc = programInfo.geomProc();
339     int i = 0;
340     if (geomProc.numVertexAttributes() > 0) {
341         size_t offset = 0;
342         for (const auto& attrib : geomProc.vertexAttributes()) {
343             wgpu::VertexAttribute attribute;
344             attribute.shaderLocation = i;
345             attribute.offset = offset;
346             attribute.format = to_dawn_vertex_format(attrib.cpuType());
347             vertexAttributes.push_back(attribute);
348             offset += attrib.sizeAlign4();
349             i++;
350         }
351         wgpu::VertexBufferLayout input;
352         input.arrayStride = offset;
353         input.stepMode = wgpu::VertexStepMode::Vertex;
354         input.attributeCount = vertexAttributes.size();
355         input.attributes = &vertexAttributes.front();
356         inputs.push_back(input);
357     }
358     std::vector<wgpu::VertexAttribute> instanceAttributes;
359     if (geomProc.numInstanceAttributes() > 0) {
360         size_t offset = 0;
361         for (const auto& attrib : geomProc.instanceAttributes()) {
362             wgpu::VertexAttribute attribute;
363             attribute.shaderLocation = i;
364             attribute.offset = offset;
365             attribute.format = to_dawn_vertex_format(attrib.cpuType());
366             instanceAttributes.push_back(attribute);
367             offset += attrib.sizeAlign4();
368             i++;
369         }
370         wgpu::VertexBufferLayout input;
371         input.arrayStride = offset;
372         input.stepMode = wgpu::VertexStepMode::Instance;
373         input.attributeCount = instanceAttributes.size();
374         input.attributes = &instanceAttributes.front();
375         inputs.push_back(input);
376     }
377     wgpu::VertexState vertexState;
378     vertexState.module = vsModule;
379     vertexState.entryPoint = "main";
380     vertexState.bufferCount = inputs.size();
381     vertexState.buffers = &inputs.front();
382 
383     wgpu::BlendState blendState = create_blend_state(gpu, pipeline);
384 
385     wgpu::ColorTargetState colorTargetState;
386     colorTargetState.format = colorFormat;
387     colorTargetState.blend = &blendState;
388 
389     bool writeColor = pipeline.getXferProcessor().getBlendInfo().fWriteColor;
390     colorTargetState.writeMask = writeColor ? wgpu::ColorWriteMask::All
391                                             : wgpu::ColorWriteMask::None;
392 
393     wgpu::FragmentState fragmentState;
394     fragmentState.module = fsModule;
395     fragmentState.entryPoint = "main";
396     fragmentState.targetCount = 1;
397     fragmentState.targets = &colorTargetState;
398 
399     wgpu::RenderPipelineDescriptor rpDesc;
400     rpDesc.layout = pipelineLayout;
401     rpDesc.vertex = vertexState;
402     rpDesc.primitive.topology = to_dawn_primitive_topology(programInfo.primitiveType());
403     GrPrimitiveType primitiveType = programInfo.primitiveType();
404     if (primitiveType == GrPrimitiveType::kTriangleStrip ||
405         primitiveType == GrPrimitiveType::kLineStrip) {
406         rpDesc.primitive.stripIndexFormat = wgpu::IndexFormat::Uint16;
407     }
408     if (hasDepthStencil) {
409         rpDesc.depthStencil = &depthStencilState;
410     }
411     rpDesc.fragment = &fragmentState;
412     result->fRenderPipeline = gpu->device().CreateRenderPipeline(&rpDesc);
413     return result;
414 }
415 
GrDawnProgramBuilder(GrDawnGpu * gpu,const GrProgramInfo & programInfo,GrProgramDesc * desc)416 GrDawnProgramBuilder::GrDawnProgramBuilder(GrDawnGpu* gpu,
417                                            const GrProgramInfo& programInfo,
418                                            GrProgramDesc* desc)
419     : INHERITED(*desc, programInfo)
420     , fGpu(gpu)
421     , fVaryingHandler(this)
422     , fUniformHandler(this) {
423 }
424 
createShaderModule(const GrGLSLShaderBuilder & builder,SkSL::ProgramKind kind,bool flipY,SkSL::Program::Inputs * inputs)425 wgpu::ShaderModule GrDawnProgramBuilder::createShaderModule(const GrGLSLShaderBuilder& builder,
426                                                             SkSL::ProgramKind kind,
427                                                             bool flipY,
428                                                             SkSL::Program::Inputs* inputs) {
429     wgpu::Device device = fGpu->device();
430     SkString source(builder.fCompilerString.c_str());
431 
432 #if 0
433     SkSL::String sksl = GrShaderUtils::PrettyPrint(builder.fCompilerString);
434     printf("converting program:\n%s\n", sksl.c_str());
435 #endif
436 
437     SkSL::String spirvSource = fGpu->SkSLToSPIRV(source.c_str(),
438                                                  kind,
439                                                  fUniformHandler.getRTFlipOffset(),
440                                                  inputs);
441     if (inputs->fUseFlipRTUniform) {
442         this->addRTFlipUniform(SKSL_RTFLIP_NAME);
443     }
444 
445     return fGpu->createShaderModule(spirvSource);
446 };
447 
caps() const448 const GrCaps* GrDawnProgramBuilder::caps() const {
449     return fGpu->caps();
450 }
451 
shaderCompiler() const452 SkSL::Compiler* GrDawnProgramBuilder::shaderCompiler() const {
453     return fGpu->shaderCompiler();
454 }
455 
setRenderTargetState(const GrRenderTarget * rt,GrSurfaceOrigin origin)456 void GrDawnProgram::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) {
457     // Set RT adjustment and RT flip
458     SkISize dimensions = rt->dimensions();
459     SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
460     if (fRenderTargetState.fRenderTargetOrigin != origin ||
461         fRenderTargetState.fRenderTargetSize != dimensions) {
462         fRenderTargetState.fRenderTargetSize = dimensions;
463         fRenderTargetState.fRenderTargetOrigin = origin;
464 
465         // The client will mark a swap buffer as kTopLeft when making a SkSurface because
466         // Dawn's framebuffer space has (0, 0) at the top left. This agrees with Skia's device
467         // coords. However, in NDC (-1, -1) is the bottom left. So we flip when origin is kTopLeft.
468         bool flip = (origin == kTopLeft_GrSurfaceOrigin);
469         std::array<float, 4> v = SkSL::Compiler::GetRTAdjustVector(dimensions, flip);
470         fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, v.data());
471         if (fBuiltinUniformHandles.fRTFlipUni.isValid()) {
472             // Note above that framebuffer space has origin top left. So we need !flip here.
473             std::array<float, 2> d = SkSL::Compiler::GetRTFlipVector(rt->height(), !flip);
474             fDataManager.set2fv(fBuiltinUniformHandles.fRTFlipUni, 1, d.data());
475         }
476     }
477 }
478 
set_texture(GrDawnGpu * gpu,GrSamplerState state,GrTexture * texture,std::vector<wgpu::BindGroupEntry> * bindings,int * binding)479 static void set_texture(GrDawnGpu* gpu, GrSamplerState state, GrTexture* texture,
480                         std::vector<wgpu::BindGroupEntry>* bindings, int* binding) {
481     // FIXME: could probably cache samplers in GrDawnProgram
482     wgpu::Sampler sampler = gpu->getOrCreateSampler(state);
483     bindings->push_back(make_bind_group_entry((*binding)++, sampler));
484     GrDawnTexture* tex = static_cast<GrDawnTexture*>(texture);
485     wgpu::TextureViewDescriptor viewDesc;
486     // Note that a mipLevelCount == WGPU_MIP_LEVEL_COUNT_UNDEFINED here means to expose all
487     // available levels.
488     viewDesc.mipLevelCount = GrSamplerState::MipmapMode::kNone == state.mipmapMode()
489                                      ? 1
490                                      : WGPU_MIP_LEVEL_COUNT_UNDEFINED;
491     wgpu::TextureView textureView = tex->texture().CreateView(&viewDesc);
492     bindings->push_back(make_bind_group_entry((*binding)++, textureView));
493 }
494 
setUniformData(GrDawnGpu * gpu,const GrRenderTarget * renderTarget,const GrProgramInfo & programInfo)495 wgpu::BindGroup GrDawnProgram::setUniformData(GrDawnGpu* gpu, const GrRenderTarget* renderTarget,
496                                               const GrProgramInfo& programInfo) {
497     if (0 == fDataManager.uniformBufferSize()) {
498         return nullptr;
499     }
500     this->setRenderTargetState(renderTarget, programInfo.origin());
501     const GrPipeline& pipeline = programInfo.pipeline();
502     const GrGeometryProcessor& geomProc = programInfo.geomProc();
503     fGPImpl->setData(fDataManager, *gpu->caps()->shaderCaps(), geomProc);
504 
505     for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) {
506         const auto& fp = programInfo.pipeline().getFragmentProcessor(i);
507         fp.visitWithImpls([&](const GrFragmentProcessor& fp,
508                               GrFragmentProcessor::ProgramImpl& impl) {
509             impl.setData(fDataManager, fp);
510         }, *fFPImpls[i]);
511     }
512 
513     programInfo.pipeline().setDstTextureUniforms(fDataManager, &fBuiltinUniformHandles);
514     fXPImpl->setData(fDataManager, pipeline.getXferProcessor());
515 
516     return fDataManager.uploadUniformBuffers(gpu, fBindGroupLayouts[0]);
517 }
518 
setTextures(GrDawnGpu * gpu,const GrGeometryProcessor & geomProc,const GrPipeline & pipeline,const GrSurfaceProxy * const geomProcTextures[])519 wgpu::BindGroup GrDawnProgram::setTextures(GrDawnGpu* gpu,
520                                            const GrGeometryProcessor& geomProc,
521                                            const GrPipeline& pipeline,
522                                            const GrSurfaceProxy* const geomProcTextures[]) {
523     if (fBindGroupLayouts.size() < 2) {
524         return nullptr;
525     }
526     std::vector<wgpu::BindGroupEntry> bindings;
527     int binding = 0;
528     if (geomProcTextures) {
529         for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
530             SkASSERT(geomProcTextures[i]->asTextureProxy());
531             auto& sampler = geomProc.textureSampler(i);
532             set_texture(gpu, sampler.samplerState(), geomProcTextures[i]->peekTexture(), &bindings,
533                         &binding);
534         }
535     }
536 
537     if (GrTexture* dstTexture = pipeline.peekDstTexture()) {
538         set_texture(gpu, GrSamplerState::Filter::kNearest, dstTexture, &bindings, &binding);
539     }
540 
541     pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
542         set_texture(gpu, te.samplerState(), te.texture(), &bindings, &binding);
543     });
544 
545     wgpu::BindGroupDescriptor descriptor;
546     descriptor.layout = fBindGroupLayouts[1];
547     descriptor.entryCount = bindings.size();
548     descriptor.entries = bindings.data();
549     return gpu->device().CreateBindGroup(&descriptor);
550 }
551