264 {
267
270
272
273 ShaderErrorHandler* errorHandler = caps.shaderErrorHandler();
274
276 const bool useStorageBuffers = caps.storageBufferPreferred();
277
278 std::string vsCode, fsCode;
279 wgpu::ShaderModule fsModule, vsModule;
280
281
282
283 UniquePaintParamsID paintID = pipelineDesc.paintParamsID();
286 runtimeDict,
288 paintID,
289 useStorageBuffers,
290 renderPassDesc.fWriteSwizzle);
291 std::string& fsSkSL = fsSkSLInfo.fSkSL;
292 const BlendInfo& blendInfo = fsSkSLInfo.fBlendInfo;
293 const bool localCoordsNeeded = fsSkSLInfo.fRequiresLocalCoords;
295
296 bool hasFragmentSkSL = !fsSkSL.empty();
297 if (hasFragmentSkSL) {
299 fsSkSL,
302 &fsCode,
303 &fsInterface,
304 errorHandler)) {
305 return {};
306 }
308 &fsModule, errorHandler)) {
309 return {};
310 }
311 }
312
313 VertSkSLInfo vsSkSLInfo =
BuildVertexSkSL(caps.resourceBindingRequirements(),
315 useStorageBuffers,
316 localCoordsNeeded);
317 const std::string& vsSkSL = vsSkSLInfo.fSkSL;
319 vsSkSL,
322 &vsCode,
323 &vsInterface,
324 errorHandler)) {
325 return {};
326 }
328 &vsModule, errorHandler)) {
329 return {};
330 }
331
332 std::string pipelineLabel =
334 wgpu::RenderPipelineDescriptor descriptor;
335
336 descriptor.label = pipelineLabel.c_str();
337
338
343
344 wgpu::BlendState
blend;
345 if (blendOn) {
346 blend.color.operation = blend_equation_to_dawn_blend_op(equation);
347 blend.color.srcFactor = blend_coeff_to_dawn_blend(caps, srcCoeff);
348 blend.color.dstFactor = blend_coeff_to_dawn_blend(caps, dstCoeff);
349 blend.alpha.operation = blend_equation_to_dawn_blend_op(equation);
350 blend.alpha.srcFactor = blend_coeff_to_dawn_blend_for_alpha(caps, srcCoeff);
351 blend.alpha.dstFactor = blend_coeff_to_dawn_blend_for_alpha(caps, dstCoeff);
352 }
353
354 wgpu::ColorTargetState colorTarget;
355 colorTarget.format =
356 renderPassDesc.fColorAttachment.fTextureInfo.dawnTextureSpec().getViewFormat();
357 colorTarget.blend = blendOn ? &
blend :
nullptr;
358 colorTarget.writeMask = blendInfo.fWritesColor && hasFragmentSkSL ? wgpu::ColorWriteMask::All
359 : wgpu::ColorWriteMask::None;
360
361#if !defined(__EMSCRIPTEN__)
362 const bool loadMsaaFromResolve =
363 renderPassDesc.fColorResolveAttachment.fTextureInfo.isValid() &&
364 renderPassDesc.fColorResolveAttachment.fLoadOp ==
LoadOp::kLoad;
365
366
367 wgpu::ColorTargetStateExpandResolveTextureDawn pipelineMSAALoadResolveTextureDesc;
368 if (loadMsaaFromResolve &&
sharedContext->dawnCaps()->resolveTextureLoadOp().has_value()) {
369 SkASSERT(
device.HasFeature(wgpu::FeatureName::DawnLoadResolveTexture));
370 colorTarget.nextInChain = &pipelineMSAALoadResolveTextureDesc;
371 pipelineMSAALoadResolveTextureDesc.enabled = true;
372 }
373#endif
374
375 wgpu::FragmentState fragment;
376
377
378 fragment.module = hasFragmentSkSL ? std::move(fsModule) :
sharedContext->noopFragment();
379 fragment.entryPoint = "main";
380 fragment.targetCount = 1;
381 fragment.targets = &colorTarget;
382 descriptor.fragment = &fragment;
383
384
385 const auto& depthStencilSettings =
step->depthStencilSettings();
386 SkASSERT(depthStencilSettings.fDepthTestEnabled ||
388 wgpu::DepthStencilState depthStencil;
389 if (renderPassDesc.fDepthStencilAttachment.fTextureInfo.isValid()) {
390 wgpu::TextureFormat dsFormat =
391 renderPassDesc.fDepthStencilAttachment.fTextureInfo.dawnTextureSpec()
392 .getViewFormat();
393 depthStencil.format =
395 if (depthStencilSettings.fDepthTestEnabled) {
396 depthStencil.depthWriteEnabled = depthStencilSettings.fDepthWriteEnabled;
397 }
398 depthStencil.depthCompare = compare_op_to_dawn(depthStencilSettings.fDepthCompareOp);
399
400
401
403 depthStencil.stencilFront = stencil_face_to_dawn(depthStencilSettings.fFrontStencil);
404 depthStencil.stencilBack = stencil_face_to_dawn(depthStencilSettings.fBackStencil);
405 depthStencil.stencilReadMask = depthStencilSettings.fFrontStencil.fReadMask;
406 depthStencil.stencilWriteMask = depthStencilSettings.fFrontStencil.fWriteMask;
407 }
408
409 descriptor.depthStencil = &depthStencil;
410 }
411
412
414 {
415 groupLayouts[0] = resourceProvider->getOrCreateUniformBuffersBindGroupLayout();
416 if (!groupLayouts[0]) {
417 return {};
418 }
419
421 if (hasFragmentSamplers) {
423
424 groupLayouts[1] =
425 resourceProvider->getOrCreateSingleTextureSamplerBindGroupLayout();
426 } else {
429 entries[
i].binding =
static_cast<uint32_t
>(
i);
430 entries[
i].visibility = wgpu::ShaderStage::Fragment;
431 entries[
i].sampler.type = wgpu::SamplerBindingType::Filtering;
433 entries[
i].binding =
i;
434 entries[
i].visibility = wgpu::ShaderStage::Fragment;
435 entries[
i].texture.sampleType = wgpu::TextureSampleType::Float;
436 entries[
i].texture.viewDimension = wgpu::TextureViewDimension::e2D;
437 entries[
i].texture.multisampled =
false;
439 }
440
441 wgpu::BindGroupLayoutDescriptor groupLayoutDesc;
443 groupLayoutDesc.label = vsSkSLInfo.fLabel.c_str();
444 }
445 groupLayoutDesc.entryCount = entries.size();
446 groupLayoutDesc.entries = entries.data();
447 groupLayouts[1] =
device.CreateBindGroupLayout(&groupLayoutDesc);
448 }
449 if (!groupLayouts[1]) {
450 return {};
451 }
452 }
453
454 wgpu::PipelineLayoutDescriptor layoutDesc;
456 layoutDesc.label = fsSkSLInfo.fLabel.c_str();
457 }
458 layoutDesc.bindGroupLayoutCount =
459 hasFragmentSamplers ? groupLayouts.size() : groupLayouts.size() - 1;
460 layoutDesc.bindGroupLayouts = groupLayouts.data();
461 auto layout =
device.CreatePipelineLayout(&layoutDesc);
462 if (!layout) {
463 return {};
464 }
465 descriptor.layout = std::move(layout);
466 }
467
468
469 std::array<wgpu::VertexBufferLayout, kNumVertexBuffers> vertexBufferLayouts;
470
471 std::vector<wgpu::VertexAttribute> vertexAttributes;
472 {
473 auto arrayStride = create_vertex_attributes(
step->vertexAttributes(),
474 0,
475 &vertexAttributes);
477 if (arrayStride) {
478 layout.arrayStride = arrayStride;
480 layout.attributeCount = vertexAttributes.size();
481 layout.attributes = vertexAttributes.data();
482 } else {
483 layout.arrayStride = 0;
484 layout.stepMode = wgpu::VertexStepMode::VertexBufferNotUsed;
485 layout.attributeCount = 0;
486 layout.attributes = nullptr;
487 }
488 }
489
490
491 std::vector<wgpu::VertexAttribute> instanceAttributes;
492 {
493 auto arrayStride = create_vertex_attributes(
step->instanceAttributes(),
494 step->vertexAttributes().size(),
495 &instanceAttributes);
497 if (arrayStride) {
498 layout.arrayStride = arrayStride;
499 layout.stepMode = wgpu::VertexStepMode::Instance;
500 layout.attributeCount = instanceAttributes.size();
501 layout.attributes = instanceAttributes.data();
502 } else {
503 layout.arrayStride = 0;
504 layout.stepMode = wgpu::VertexStepMode::VertexBufferNotUsed;
505 layout.attributeCount = 0;
506 layout.attributes = nullptr;
507 }
508 }
509
510 auto& vertex = descriptor.vertex;
511 vertex.module = std::move(vsModule);
512 vertex.entryPoint = "main";
513 vertex.constantCount = 0;
514 vertex.constants = nullptr;
515 vertex.bufferCount = vertexBufferLayouts.size();
516 vertex.buffers = vertexBufferLayouts.data();
517
518
519 descriptor.primitive.frontFace = wgpu::FrontFace::CCW;
520 descriptor.primitive.cullMode = wgpu::CullMode::None;
521 switch (
step->primitiveType()) {
523 descriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
524 break;
526 descriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleStrip;
527 descriptor.primitive.stripIndexFormat = wgpu::IndexFormat::Uint16;
528 break;
530 descriptor.primitive.topology = wgpu::PrimitiveTopology::PointList;
531 break;
532 }
533
534
535 descriptor.multisample.count = renderPassDesc.fSampleCount;
536 descriptor.multisample.mask = 0xFFFFFFFF;
537 descriptor.multisample.alphaToCoverageEnabled = false;
538
539 auto asyncCreation = std::make_unique<AsyncPipelineCreation>();
540
541 if (caps.useAsyncPipelineCreation()) {
542#if defined(__EMSCRIPTEN__)
543
544 SKGPU_LOG_F(
"CreateRenderPipelineAsync shouldn't be used in WASM");
545#else
546 asyncCreation->fFuture =
device.CreateRenderPipelineAsync(
547 &descriptor,
548 wgpu::CallbackMode::WaitAnyOnly,
549 [asyncCreationPtr = asyncCreation.get()](wgpu::CreatePipelineAsyncStatus status,
550 wgpu::RenderPipeline pipeline,
552 if (status != wgpu::CreatePipelineAsyncStatus::Success) {
553 SKGPU_LOG_E("Failed to create render pipeline (%d): %s",
554 static_cast<int>(status),
555 message);
556
557
558 asyncCreationPtr->fRenderPipeline = nullptr;
559 } else {
560 asyncCreationPtr->fRenderPipeline = std::move(pipeline);
561 }
562
563 asyncCreationPtr->fFinished = true;
564 });
565#endif
566 } else {
567 std::optional<DawnErrorChecker> errorChecker;
570 }
571 asyncCreation->fRenderPipeline =
device.CreateRenderPipeline(&descriptor);
572 asyncCreation->fFinished = true;
573
575 asyncCreation->fRenderPipeline = nullptr;
576 }
577 }
578#if defined(GRAPHITE_TEST_UTILS)
579 GraphicsPipeline::PipelineInfo pipelineInfo = {pipelineDesc.renderStepID(),
580 pipelineDesc.paintParamsID(),
581 std::move(vsSkSL),
582 std::move(fsSkSL),
583 std::move(vsCode),
584 std::move(fsCode)};
585 GraphicsPipeline::PipelineInfo* pipelineInfoPtr = &pipelineInfo;
586#else
587 GraphicsPipeline::PipelineInfo* pipelineInfoPtr = nullptr;
588#endif
589
592 pipelineInfoPtr,
593 std::move(asyncCreation),
594 std::move(groupLayouts),
595 step->primitiveType(),
596 depthStencilSettings.fStencilReferenceValue,
597 !
step->uniforms().empty(),
598 fsSkSLInfo.fNumPaintUniforms > 0,
599 fsSkSLInfo.fHasGradientBuffer,
601}
static int step(int x, SkScalar min, SkScalar max)
GrTriangulator::Vertex Vertex
bool setBackendLabels() const
std::array< wgpu::BindGroupLayout, kBindGroupCount > BindGroupLayouts
int numTexturesAndSamplers() const
static constexpr unsigned int kInstanceBufferIndex
static constexpr unsigned int kVertexBufferIndex
const RenderStep * lookup(uint32_t uniqueID) const
const Caps * caps() const
ShaderCodeDictionary * shaderCodeDictionary()
const RendererProvider * rendererProvider() const
static SkColor blend(SkColor dst, SkColor src, void(*mode)(float, float, float, float *, float *, float *))
VertSkSLInfo BuildVertexSkSL(const ResourceBindingRequirements &bindingReqs, const RenderStep *step, bool useStorageBuffers, bool defineLocalCoordsVarying)
bool DawnFormatIsDepthOrStencil(wgpu::TextureFormat format)
FragSkSLInfo BuildFragmentSkSL(const Caps *caps, const ShaderCodeDictionary *dict, const RuntimeEffectDictionary *rteDict, const RenderStep *step, UniquePaintParamsID paintID, bool useStorageBuffers, skgpu::Swizzle writeSwizzle)
std::string GetPipelineLabel(const ShaderCodeDictionary *dict, const RenderPassDesc &renderPassDesc, const RenderStep *renderStep, UniquePaintParamsID paintID)
bool DawnCompileWGSLShaderModule(const DawnSharedContext *sharedContext, const char *label, const std::string &wgsl, wgpu::ShaderModule *module, ShaderErrorHandler *errorHandler)
bool DawnFormatIsStencil(wgpu::TextureFormat format)
static constexpr bool BlendShouldDisable(BlendEquation equation, BlendCoeff srcCoeff, BlendCoeff dstCoeff)
bool SkSLToWGSL(const SkSL::ShaderCaps *caps, const std::string &sksl, SkSL::ProgramKind programKind, const SkSL::ProgramSettings &settings, std::string *wgsl, SkSL::ProgramInterface *outInterface, ShaderErrorHandler *errorHandler)