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
18static 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
54static 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
70static 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
84static 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
108static 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
132static 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
151static 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
176static 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
195static 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
203static 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
229static 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
242static 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
247static 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
252sk_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
416GrDawnProgramBuilder::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
425wgpu::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
448const GrCaps* GrDawnProgramBuilder::caps() const {
449    return fGpu->caps();
450}
451
452SkSL::Compiler* GrDawnProgramBuilder::shaderCompiler() const {
453    return fGpu->shaderCompiler();
454}
455
456void 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
479static 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
495wgpu::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
519wgpu::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