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