254 {
257
260
262
263 ShaderErrorHandler* errorHandler = caps.shaderErrorHandler();
264
266 const bool useStorageBuffers = caps.storageBufferPreferred();
267
268 std::string vsCode, fsCode;
269 wgpu::ShaderModule fsModule, vsModule;
270
271
272
273 UniquePaintParamsID paintID = pipelineDesc.paintParamsID();
276 runtimeDict,
278 paintID,
279 useStorageBuffers,
280 renderPassDesc.fWriteSwizzle);
281 std::string& fsSkSL = fsSkSLInfo.fSkSL;
282 const BlendInfo& blendInfo = fsSkSLInfo.fBlendInfo;
283 const bool localCoordsNeeded = fsSkSLInfo.fRequiresLocalCoords;
285
286 bool hasFragmentSkSL = !fsSkSL.empty();
287 if (hasFragmentSkSL) {
289 fsSkSL,
291 settings,
292 &fsCode,
293 &fsInterface,
294 errorHandler)) {
295 return {};
296 }
298 &fsModule, errorHandler)) {
299 return {};
300 }
301 }
302
303 VertSkSLInfo vsSkSLInfo =
BuildVertexSkSL(caps.resourceBindingRequirements(),
305 useStorageBuffers,
306 localCoordsNeeded);
307 const std::string& vsSkSL = vsSkSLInfo.fSkSL;
309 vsSkSL,
311 settings,
312 &vsCode,
313 &vsInterface,
314 errorHandler)) {
315 return {};
316 }
318 &vsModule, errorHandler)) {
319 return {};
320 }
321
322 std::string pipelineLabel =
324 wgpu::RenderPipelineDescriptor descriptor;
325 descriptor.label = pipelineLabel.c_str();
326
327
332
333 wgpu::BlendState
blend;
334 if (blendOn) {
335 blend.color.operation = blend_equation_to_dawn_blend_op(equation);
336 blend.color.srcFactor = blend_coeff_to_dawn_blend(caps, srcCoeff);
337 blend.color.dstFactor = blend_coeff_to_dawn_blend(caps, dstCoeff);
338 blend.alpha.operation = blend_equation_to_dawn_blend_op(equation);
339 blend.alpha.srcFactor = blend_coeff_to_dawn_blend_for_alpha(caps, srcCoeff);
340 blend.alpha.dstFactor = blend_coeff_to_dawn_blend_for_alpha(caps, dstCoeff);
341 }
342
343 wgpu::ColorTargetState colorTarget;
344 colorTarget.format =
345 renderPassDesc.fColorAttachment.fTextureInfo.dawnTextureSpec().getViewFormat();
346 colorTarget.blend = blendOn ? &
blend :
nullptr;
347 colorTarget.writeMask = blendInfo.fWritesColor && hasFragmentSkSL ? wgpu::ColorWriteMask::All
348 : wgpu::ColorWriteMask::None;
349
350 wgpu::FragmentState fragment;
351
352
353 fragment.module = hasFragmentSkSL ? std::move(fsModule) :
sharedContext->noopFragment();
354 fragment.entryPoint = "main";
355 fragment.targetCount = 1;
356 fragment.targets = &colorTarget;
357 descriptor.fragment = &fragment;
358
359
360 const auto& depthStencilSettings =
step->depthStencilSettings();
361 SkASSERT(depthStencilSettings.fDepthTestEnabled ||
363 wgpu::DepthStencilState depthStencil;
364 if (renderPassDesc.fDepthStencilAttachment.fTextureInfo.isValid()) {
365 wgpu::TextureFormat dsFormat =
366 renderPassDesc.fDepthStencilAttachment.fTextureInfo.dawnTextureSpec()
367 .getViewFormat();
368 depthStencil.format =
370 if (depthStencilSettings.fDepthTestEnabled) {
371 depthStencil.depthWriteEnabled = depthStencilSettings.fDepthWriteEnabled;
372 }
373 depthStencil.depthCompare = compare_op_to_dawn(depthStencilSettings.fDepthCompareOp);
374
375
376
378 depthStencil.stencilFront = stencil_face_to_dawn(depthStencilSettings.fFrontStencil);
379 depthStencil.stencilBack = stencil_face_to_dawn(depthStencilSettings.fBackStencil);
380 depthStencil.stencilReadMask = depthStencilSettings.fFrontStencil.fReadMask;
381 depthStencil.stencilWriteMask = depthStencilSettings.fFrontStencil.fWriteMask;
382 }
383
384 descriptor.depthStencil = &depthStencil;
385 }
386
387
389 {
390 groupLayouts[0] = resourceProvider->getOrCreateUniformBuffersBindGroupLayout();
391 if (!groupLayouts[0]) {
392 return {};
393 }
394
396 if (hasFragmentSamplers) {
398
399 groupLayouts[1] =
400 resourceProvider->getOrCreateSingleTextureSamplerBindGroupLayout();
401 } else {
404 entries[i].binding = static_cast<uint32_t>(i);
405 entries[i].visibility = wgpu::ShaderStage::Fragment;
406 entries[i].sampler.type = wgpu::SamplerBindingType::Filtering;
407 ++i;
408 entries[i].binding = i;
409 entries[i].visibility = wgpu::ShaderStage::Fragment;
410 entries[i].texture.sampleType = wgpu::TextureSampleType::Float;
411 entries[i].texture.viewDimension = wgpu::TextureViewDimension::e2D;
412 entries[i].texture.multisampled = false;
413 ++i;
414 }
415
416 wgpu::BindGroupLayoutDescriptor groupLayoutDesc;
417#if defined(SK_DEBUG)
418 groupLayoutDesc.label = vsSkSLInfo.fLabel.c_str();
419#endif
420 groupLayoutDesc.entryCount = entries.size();
421 groupLayoutDesc.entries = entries.data();
422 groupLayouts[1] =
device.CreateBindGroupLayout(&groupLayoutDesc);
423 }
424 if (!groupLayouts[1]) {
425 return {};
426 }
427 }
428
429 wgpu::PipelineLayoutDescriptor layoutDesc;
430#if defined(SK_DEBUG)
431 layoutDesc.label = fsSkSLInfo.fLabel.c_str();
432#endif
433 layoutDesc.bindGroupLayoutCount =
434 hasFragmentSamplers ? groupLayouts.size() : groupLayouts.size() - 1;
435 layoutDesc.bindGroupLayouts = groupLayouts.data();
436 auto layout =
device.CreatePipelineLayout(&layoutDesc);
437 if (!layout) {
438 return {};
439 }
440 descriptor.layout = std::move(layout);
441 }
442
443
444 std::array<wgpu::VertexBufferLayout, kNumVertexBuffers> vertexBufferLayouts;
445
446 std::vector<wgpu::VertexAttribute> vertexAttributes;
447 {
448 auto arrayStride = create_vertex_attributes(
step->vertexAttributes(),
449 0,
450 &vertexAttributes);
452 if (arrayStride) {
453 layout.arrayStride = arrayStride;
454 layout.stepMode = wgpu::VertexStepMode::Vertex;
455 layout.attributeCount = vertexAttributes.size();
456 layout.attributes = vertexAttributes.data();
457 } else {
458 layout.arrayStride = 0;
459 layout.stepMode = wgpu::VertexStepMode::VertexBufferNotUsed;
460 layout.attributeCount = 0;
461 layout.attributes = nullptr;
462 }
463 }
464
465
466 std::vector<wgpu::VertexAttribute> instanceAttributes;
467 {
468 auto arrayStride = create_vertex_attributes(
step->instanceAttributes(),
469 step->vertexAttributes().size(),
470 &instanceAttributes);
472 if (arrayStride) {
473 layout.arrayStride = arrayStride;
474 layout.stepMode = wgpu::VertexStepMode::Instance;
475 layout.attributeCount = instanceAttributes.size();
476 layout.attributes = instanceAttributes.data();
477 } else {
478 layout.arrayStride = 0;
479 layout.stepMode = wgpu::VertexStepMode::VertexBufferNotUsed;
480 layout.attributeCount = 0;
481 layout.attributes = nullptr;
482 }
483 }
484
485 auto& vertex = descriptor.vertex;
486 vertex.module = std::move(vsModule);
487 vertex.entryPoint = "main";
488 vertex.constantCount = 0;
489 vertex.constants = nullptr;
490 vertex.bufferCount = vertexBufferLayouts.size();
491 vertex.buffers = vertexBufferLayouts.data();
492
493
494 descriptor.primitive.frontFace = wgpu::FrontFace::CCW;
495 descriptor.primitive.cullMode = wgpu::CullMode::None;
496 switch(
step->primitiveType()) {
498 descriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
499 break;
501 descriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleStrip;
502 descriptor.primitive.stripIndexFormat = wgpu::IndexFormat::Uint16;
503 break;
505 descriptor.primitive.topology = wgpu::PrimitiveTopology::PointList;
506 break;
507 }
508
509
510 descriptor.multisample.count = renderPassDesc.fSampleCount;
511 [[maybe_unused]] bool isMSAARenderToSingleSampled =
512 renderPassDesc.fSampleCount > 1 &&
513 renderPassDesc.fColorAttachment.fTextureInfo.isValid() &&
514 renderPassDesc.fColorAttachment.fTextureInfo.numSamples() == 1;
515#if defined(__EMSCRIPTEN__)
516 SkASSERT(!isMSAARenderToSingleSampled);
517#else
518 wgpu::DawnMultisampleStateRenderToSingleSampled pipelineMSAARenderToSingleSampledDesc;
519 if (isMSAARenderToSingleSampled) {
520
521
522 SkASSERT(
device.HasFeature(wgpu::FeatureName::MSAARenderToSingleSampled));
523
524 descriptor.multisample.nextInChain = &pipelineMSAARenderToSingleSampledDesc;
525 pipelineMSAARenderToSingleSampledDesc.enabled = true;
526 }
527#endif
528
529 descriptor.multisample.mask = 0xFFFFFFFF;
530 descriptor.multisample.alphaToCoverageEnabled = false;
531
532 auto asyncCreation = std::make_unique<AsyncPipelineCreation>(
sharedContext);
533
534 if (caps.useAsyncPipelineCreation()) {
535 device.CreateRenderPipelineAsync(
536 &descriptor,
537 [](WGPUCreatePipelineAsyncStatus status,
538 WGPURenderPipeline pipeline,
540 void* userdata) {
541 AsyncPipelineCreation* arg = static_cast<AsyncPipelineCreation*>(userdata);
542
543 if (status != WGPUCreatePipelineAsyncStatus_Success) {
545 arg->set(nullptr);
546 } else {
547 arg->set(wgpu::RenderPipeline::Acquire(pipeline));
548 }
549 },
550 asyncCreation.get());
551 } else {
552 asyncCreation->set(
device.CreateRenderPipeline(&descriptor));
553 }
554#if defined(GRAPHITE_TEST_UTILS)
555 GraphicsPipeline::PipelineInfo pipelineInfo = {pipelineDesc.renderStepID(),
556 pipelineDesc.paintParamsID(),
557 std::move(vsSkSL),
558 std::move(fsSkSL),
559 std::move(vsCode),
560 std::move(fsCode)};
561 GraphicsPipeline::PipelineInfo* pipelineInfoPtr = &pipelineInfo;
562#else
563 GraphicsPipeline::PipelineInfo* pipelineInfoPtr = nullptr;
564#endif
565
568 pipelineInfoPtr,
569 std::move(asyncCreation),
570 std::move(groupLayouts),
571 step->primitiveType(),
572 depthStencilSettings.fStencilReferenceValue,
573 !
step->uniforms().empty(),
574 fsSkSLInfo.fNumPaintUniforms > 0,
576}
static int step(int x, SkScalar min, SkScalar max)
#define SKGPU_LOG_E(fmt,...)
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 SharedContext * sharedContext() 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)