Flutter Engine
The Flutter Engine
Classes | Public Member Functions | Static Public Member Functions | List of all members
skgpu::graphite::DrawPass Class Reference

#include <DrawPass.h>

Classes

class  SortKey
 

Public Member Functions

 ~DrawPass ()
 
const SkIRectbounds () const
 
TextureProxytarget () const
 
std::pair< LoadOp, StoreOpops () const
 
std::array< float, 4 > clearColor () const
 
bool requiresDstTexture () const
 
bool requiresMSAA () const
 
SkEnumBitMask< DepthStencilFlagsdepthStencilFlags () const
 
size_t vertexBufferSize () const
 
size_t uniformBufferSize () const
 
bool prepareResources (ResourceProvider *, const RuntimeEffectDictionary *, const RenderPassDesc &)
 
DrawPassCommands::List::Iter commands () const
 
const GraphicsPipelinegetPipeline (size_t index) const
 
const TexturegetTexture (size_t index) const
 
const SamplergetSampler (size_t index) const
 
skia_private::TArray< sk_sp< TextureProxy > > sampledTextures () const
 
void addResourceRefs (CommandBuffer *) const
 

Static Public Member Functions

static std::unique_ptr< DrawPassMake (Recorder *, std::unique_ptr< DrawList >, sk_sp< TextureProxy > target, const SkImageInfo &targetInfo, std::pair< LoadOp, StoreOp >, std::array< float, 4 > clearColor, sk_sp< TextureProxy > dstCopy, SkIPoint dstCopyOffset)
 

Detailed Description

DrawPass is analogous to a subpass, storing the drawing operations in the order they are stored in the eventual command buffer, as well as the surface proxy the operations are intended for. DrawPasses are grouped into a RenderPassTask for execution within a single render pass if the subpasses are compatible with each other.

Unlike DrawList, DrawPasses are immutable and represent as closely as possible what will be stored in the command buffer while being flexible as to how the pass is incorporated. Depending on the backend, it may even be able to write accumulated vertex and uniform data directly to mapped GPU memory, although that is the extent of the CPU->GPU work they perform before they are executed by a RenderPassTask.

Definition at line 53 of file DrawPass.h.

Constructor & Destructor Documentation

◆ ~DrawPass()

skgpu::graphite::DrawPass::~DrawPass ( )
default

Member Function Documentation

◆ addResourceRefs()

void skgpu::graphite::DrawPass::addResourceRefs ( CommandBuffer commandBuffer) const

Definition at line 747 of file DrawPass.cpp.

747 {
748 for (int i = 0; i < fFullPipelines.size(); ++i) {
749 commandBuffer->trackResource(fFullPipelines[i]);
750 }
751 for (int i = 0; i < fSampledTextures.size(); ++i) {
752 commandBuffer->trackCommandBufferResource(fSampledTextures[i]->refTexture());
753 }
754 for (int i = 0; i < fSamplers.size(); ++i) {
755 commandBuffer->trackResource(fSamplers[i]);
756 }
757}

◆ bounds()

const SkIRect & skgpu::graphite::DrawPass::bounds ( ) const
inline

Definition at line 72 of file DrawPass.h.

72{ return fBounds; }

◆ clearColor()

std::array< float, 4 > skgpu::graphite::DrawPass::clearColor ( ) const
inline

Definition at line 75 of file DrawPass.h.

75{ return fClearColor; }

◆ commands()

DrawPassCommands::List::Iter skgpu::graphite::DrawPass::commands ( ) const
inline

Definition at line 92 of file DrawPass.h.

92 {
93 return fCommandList.commands();
94 }

◆ depthStencilFlags()

SkEnumBitMask< DepthStencilFlags > skgpu::graphite::DrawPass::depthStencilFlags ( ) const
inline

Definition at line 80 of file DrawPass.h.

80{ return fDepthStencilFlags; }

◆ getPipeline()

const GraphicsPipeline * skgpu::graphite::DrawPass::getPipeline ( size_t  index) const
inline

Definition at line 96 of file DrawPass.h.

96 {
97 return fFullPipelines[index].get();
98 }

◆ getSampler()

const Sampler * skgpu::graphite::DrawPass::getSampler ( size_t  index) const

Definition at line 765 of file DrawPass.cpp.

765 {
766 SkASSERT(index < SkToSizeT(fSamplers.size()));
767 SkASSERT(fSamplers[index]);
768 return fSamplers[index].get();
769}
#define SkASSERT(cond)
Definition: SkAssert.h:116
constexpr size_t SkToSizeT(S x)
Definition: SkTo.h:31

◆ getTexture()

const Texture * skgpu::graphite::DrawPass::getTexture ( size_t  index) const

Definition at line 759 of file DrawPass.cpp.

759 {
760 SkASSERT(index < SkToSizeT(fSampledTextures.size()));
761 SkASSERT(fSampledTextures[index]);
762 SkASSERT(fSampledTextures[index]->texture());
763 return fSampledTextures[index]->texture();
764}
FlTexture * texture

◆ Make()

std::unique_ptr< DrawPass > skgpu::graphite::DrawPass::Make ( Recorder recorder,
std::unique_ptr< DrawList draws,
sk_sp< TextureProxy target,
const SkImageInfo targetInfo,
std::pair< LoadOp, StoreOp ops,
std::array< float, 4 >  clearColor,
sk_sp< TextureProxy dstCopy,
SkIPoint  dstCopyOffset 
)
static

Definition at line 458 of file DrawPass.cpp.

465 {
466 // NOTE: This assert is here to ensure SortKey is as tightly packed as possible. Any change to
467 // its size should be done with care and good reason. The performance of sorting the keys is
468 // heavily tied to the total size.
469 //
470 // At 24 bytes (current), sorting is about 30% slower than if SortKey could be packed into just
471 // 16 bytes. There are several ways this could be done if necessary:
472 // - Restricting the max draw count to 16k (14-bits) and only using a single index to refer to
473 // the uniform data => 8 bytes of key, 8 bytes of pointer.
474 // - Restrict the max draw count to 32k (15-bits), use a single uniform index, and steal the
475 // 4 low bits from the Draw* pointer since it's 16 byte aligned.
476 // - Compact the Draw* to an index into the original collection, although that has extra
477 // indirection and does not work as well with SkTBlockList.
478 // In pseudo tests, manipulating the pointer or having to mask out indices was about 15% slower
479 // than an 8 byte key and unmodified pointer.
480 static_assert(sizeof(DrawPass::SortKey) ==
481 SkAlignTo(16 + sizeof(void*), alignof(DrawPass::SortKey)));
482
483 TRACE_EVENT1("skia.gpu", TRACE_FUNC, "draw count", draws->fDraws.count());
484
485 // The DrawList is converted directly into the DrawPass' data structures, but once the DrawPass
486 // is returned from Make(), it is considered immutable.
487 std::unique_ptr<DrawPass> drawPass(new DrawPass(target, ops, clearColor));
488
489 Rect passBounds = Rect::InfiniteInverted();
490
491 // We don't expect the uniforms from the renderSteps to reappear multiple times across a
492 // recorder's lifetime so we only de-dupe them w/in a given DrawPass.
493 UniformDataCache geometryUniformDataCache;
494 TextureDataCache* textureDataCache = recorder->priv().textureDataCache();
495 DrawBufferManager* bufferMgr = recorder->priv().drawBufferManager();
496 if (bufferMgr->hasMappingFailed()) {
497 SKGPU_LOG_W("Buffer mapping has already failed; dropping draw pass!");
498 return nullptr;
499 }
500 // Ensure there's a destination copy if required
501 if (!draws->dstCopyBounds().isEmptyNegativeOrNaN() && !dstCopy) {
502 SKGPU_LOG_W("Failed to copy destination for reading. Dropping draw pass!");
503 return nullptr;
504 }
505
506 GraphicsPipelineCache pipelineCache;
507
508 // Geometry uniforms are currently always UBO-backed.
509 const bool useStorageBuffers = recorder->priv().caps()->storageBufferPreferred();
510 const ResourceBindingRequirements& bindingReqs =
511 recorder->priv().caps()->resourceBindingRequirements();
512 Layout uniformLayout =
513 useStorageBuffers ? bindingReqs.fStorageBufferLayout : bindingReqs.fUniformBufferLayout;
514
515 UniformTracker geometryUniformTracker(useStorageBuffers);
516 UniformTracker shadingUniformTracker(useStorageBuffers);
517 TextureBindingTracker textureBindingTracker;
518 GradientBufferTracker gradientBufferTracker;
519
520 ShaderCodeDictionary* dict = recorder->priv().shaderCodeDictionary();
521 PaintParamsKeyBuilder builder(dict);
522
523 // The initial layout we pass here is not important as it will be re-assigned when writing
524 // shading and geometry uniforms below.
525 PipelineDataGatherer gatherer(uniformLayout);
526
527 std::vector<SortKey> keys;
528 keys.reserve(draws->renderStepCount());
529
530 for (const DrawList::Draw& draw : draws->fDraws.items()) {
531 // If we have two different descriptors, such that the uniforms from the PaintParams can be
532 // bound independently of those used by the rest of the RenderStep, then we can upload now
533 // and remember the location for re-use on any RenderStep that does shading.
534 UniquePaintParamsID shaderID;
535 const UniformDataBlock* shadingUniforms = nullptr;
536 const TextureDataBlock* paintTextures = nullptr;
537
538 if (draw.fPaintParams.has_value()) {
539 sk_sp<TextureProxy> curDst =
540 draw.fPaintParams->dstReadRequirement() == DstReadRequirement::kTextureCopy
541 ? dstCopy
542 : nullptr;
543 std::tie(shaderID, shadingUniforms, paintTextures) =
544 ExtractPaintData(recorder,
545 &gatherer,
546 &builder,
547 uniformLayout,
548 draw.fDrawParams.transform(),
549 draw.fPaintParams.value(),
550 draw.fDrawParams.geometry(),
551 curDst,
552 dstCopyOffset,
553 targetInfo.colorInfo());
554 } // else depth-only
555
556 for (int stepIndex = 0; stepIndex < draw.fRenderer->numRenderSteps(); ++stepIndex) {
557 const RenderStep* const step = draw.fRenderer->steps()[stepIndex];
558 const bool performsShading = draw.fPaintParams.has_value() && step->performsShading();
559
560 GraphicsPipelineCache::Index pipelineIndex = pipelineCache.insert(
561 {step, performsShading ? shaderID : UniquePaintParamsID::InvalidID()});
562 auto [geometryUniforms, stepTextures] = ExtractRenderStepData(&geometryUniformDataCache,
563 textureDataCache,
564 &gatherer,
565 uniformLayout,
566 step,
567 draw.fDrawParams);
568
569 UniformCache::Index geomUniformIndex = geometryUniformTracker.trackUniforms(
570 pipelineIndex, geometryUniforms);
571 UniformCache::Index shadingUniformIndex = shadingUniformTracker.trackUniforms(
572 pipelineIndex, performsShading ? shadingUniforms : nullptr);
573 TextureBindingCache::Index textureIndex = textureBindingTracker.trackTextures(
574 performsShading ? paintTextures : nullptr, stepTextures);
575
576 keys.push_back({&draw, stepIndex, pipelineIndex,
577 geomUniformIndex, shadingUniformIndex, textureIndex});
578 }
579
580 passBounds.join(draw.fDrawParams.clip().drawBounds());
581 drawPass->fDepthStencilFlags |= draw.fRenderer->depthStencilFlags();
582 drawPass->fRequiresMSAA |= draw.fRenderer->requiresMSAA();
583 }
584
585 if (!geometryUniformTracker.writeUniforms(bufferMgr) ||
586 !shadingUniformTracker.writeUniforms(bufferMgr) ||
587 !gradientBufferTracker.writeData(gatherer.gradientBufferData(), bufferMgr)) {
588 // The necessary uniform data couldn't be written to the GPU, so the DrawPass is invalid.
589 // Early out now since the next Recording snap will fail.
590 return nullptr;
591 }
592
593 // TODO: Explore sorting algorithms; in all likelihood this will be mostly sorted already, so
594 // algorithms that approach O(n) in that condition may be favorable. Alternatively, could
595 // explore radix sort that is always O(n). Brief testing suggested std::sort was faster than
596 // std::stable_sort and SkTQSort on my [ml]'s Windows desktop. Also worth considering in-place
597 // vs. algorithms that require an extra O(n) storage.
598 // TODO: It's not strictly necessary, but would a stable sort be useful or just end up hiding
599 // bugs in the DrawOrder determination code?
600 std::sort(keys.begin(), keys.end());
601
602 // Used to record vertex/instance data, buffer binds, and draw calls
603 DrawWriter drawWriter(&drawPass->fCommandList, bufferMgr);
604 GraphicsPipelineCache::Index lastPipeline = GraphicsPipelineCache::kInvalidIndex;
605 SkIRect lastScissor = SkIRect::MakeSize(targetInfo.dimensions());
606
607 SkASSERT(drawPass->fTarget->isFullyLazy() ||
608 SkIRect::MakeSize(drawPass->fTarget->dimensions()).contains(lastScissor));
609 drawPass->fCommandList.setScissor(lastScissor);
610
611 // All large gradients pack their data into a single buffer throughout the draw pass,
612 // therefore the gradient buffer only needs to be bound once.
613 gradientBufferTracker.bindIfNeeded(&drawPass->fCommandList);
614
615 for (const SortKey& key : keys) {
616 const DrawList::Draw& draw = key.draw();
617 const RenderStep& renderStep = key.renderStep();
618
619 const bool pipelineChange = key.pipelineIndex() != lastPipeline;
620
621 const bool geomBindingChange = geometryUniformTracker.setCurrentUniforms(
622 key.pipelineIndex(), key.geometryUniformIndex());
623 const bool shadingBindingChange = shadingUniformTracker.setCurrentUniforms(
624 key.pipelineIndex(), key.shadingUniformIndex());
625 const bool textureBindingsChange = textureBindingTracker.setCurrentTextureBindings(
626 key.textureBindingIndex());
627 const SkIRect* newScissor = draw.fDrawParams.clip().scissor() != lastScissor ?
628 &draw.fDrawParams.clip().scissor() : nullptr;
629
630 const bool stateChange = geomBindingChange ||
631 shadingBindingChange ||
632 textureBindingsChange ||
633 SkToBool(newScissor);
634
635 // Update DrawWriter *before* we actually change any state so that accumulated draws from
636 // the previous state use the proper state.
637 if (pipelineChange) {
638 drawWriter.newPipelineState(renderStep.primitiveType(),
639 renderStep.vertexStride(),
640 renderStep.instanceStride());
641 } else if (stateChange) {
642 drawWriter.newDynamicState();
643 }
644
645 // Make state changes before accumulating new draw data
646 if (pipelineChange) {
647 drawPass->fCommandList.bindGraphicsPipeline(key.pipelineIndex());
648 lastPipeline = key.pipelineIndex();
649 }
650 if (stateChange) {
651 if (geomBindingChange) {
652 geometryUniformTracker.bindUniforms(UniformSlot::kRenderStep,
653 &drawPass->fCommandList);
654 }
655 if (shadingBindingChange) {
656 shadingUniformTracker.bindUniforms(UniformSlot::kPaint, &drawPass->fCommandList);
657 }
658 if (textureBindingsChange) {
659 textureBindingTracker.bindTextures(&drawPass->fCommandList);
660 }
661 if (newScissor) {
662 drawPass->fCommandList.setScissor(*newScissor);
663 lastScissor = *newScissor;
664 }
665 }
666
667 UniformCache::Index geometrySsboIndex =
668 (key.geometryUniformIndex() == UniformCache::kInvalidIndex)
669 ? 0
670 : key.geometryUniformIndex();
671 UniformCache::Index shadingSsboIndex =
672 (key.shadingUniformIndex() == UniformCache::kInvalidIndex)
673 ? 0
674 : key.shadingUniformIndex();
675 skvx::ushort2 ssboIndices = {SkToU16(geometrySsboIndex), SkToU16(shadingSsboIndex)};
676 renderStep.writeVertices(&drawWriter, draw.fDrawParams, ssboIndices);
677
678 if (bufferMgr->hasMappingFailed()) {
679 SKGPU_LOG_W("Failed to write necessary vertex/instance data for DrawPass, dropping!");
680 return nullptr;
681 }
682 }
683 // Finish recording draw calls for any collected data at the end of the loop
684 drawWriter.flush();
685
686 drawPass->fBounds = passBounds.roundOut().asSkIRect();
687
688 drawPass->fPipelineDescs = pipelineCache.detach();
689 drawPass->fSamplerDescs = textureBindingTracker.detachSamplers();
690 drawPass->fSampledTextures = textureBindingTracker.detachTextures();
691
692 TRACE_COUNTER1("skia.gpu", "# pipelines", drawPass->fPipelineDescs.size());
693 TRACE_COUNTER1("skia.gpu", "# textures", drawPass->fSampledTextures.size());
694 TRACE_COUNTER1("skia.gpu", "# commands", drawPass->fCommandList.count());
695
696 return drawPass;
697}
static int step(int x, SkScalar min, SkScalar max)
Definition: BlurTest.cpp:215
static constexpr Index kInvalidIndex
Definition: DrawPass.cpp:68
#define SKGPU_LOG_W(fmt,...)
Definition: Log.h:40
static constexpr size_t SkAlignTo(size_t x, size_t alignment)
Definition: SkAlign.h:33
static std::vector< SkPDFIndirectReference > sort(const THashSet< SkPDFIndirectReference > &src)
constexpr uint16_t SkToU16(S x)
Definition: SkTo.h:24
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
#define TRACE_COUNTER1(category_group, name, value)
#define TRACE_FUNC
Definition: SkTraceEvent.h:30
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
Definition: aaclip.cpp:27
const ResourceBindingRequirements & resourceBindingRequirements() const
Definition: Caps.h:150
bool storageBufferPreferred() const
Definition: Caps.h:239
std::array< float, 4 > clearColor() const
Definition: DrawPass.h:75
std::pair< LoadOp, StoreOp > ops() const
Definition: DrawPass.h:74
TextureProxy * target() const
Definition: DrawPass.h:73
const ShaderCodeDictionary * shaderCodeDictionary() const
Definition: RecorderPriv.h:41
TextureDataCache * textureDataCache()
Definition: RecorderPriv.h:57
const Caps * caps() const
Definition: RecorderPriv.h:31
DrawBufferManager * drawBufferManager()
Definition: RecorderPriv.h:58
static AI Rect InfiniteInverted()
Definition: Rect.h:64
static UniquePaintParamsID InvalidID()
static void Draw(SkCanvas *canvas, const SkRect &rect)
TRect< Scalar > Rect
Definition: rect.h:769
PipelineDataCache< UniformDataBlock > UniformDataCache
Definition: Recorder.h:60
std::tuple< const UniformDataBlock *, const TextureDataBlock * > ExtractRenderStepData(UniformDataCache *uniformDataCache, TextureDataCache *textureDataCache, PipelineDataGatherer *gatherer, const Layout layout, const RenderStep *step, const DrawParams &params)
std::tuple< UniquePaintParamsID, const UniformDataBlock *, const TextureDataBlock * > ExtractPaintData(Recorder *recorder, PipelineDataGatherer *gatherer, PaintParamsKeyBuilder *builder, const Layout layout, const SkM44 &local2Dev, const PaintParams &p, const Geometry &geometry, sk_sp< TextureProxy > dstTexture, SkIPoint dstOffset, const SkColorInfo &targetColorInfo)
PipelineDataCache< TextureDataBlock > TextureDataCache
Definition: Recorder.h:61
Definition: SkRect.h:32
static constexpr SkIRect MakeSize(const SkISize &size)
Definition: SkRect.h:66
bool contains(int32_t x, int32_t y) const
Definition: SkRect.h:463
const SkColorInfo & colorInfo() const
Definition: SkImageInfo.h:404
SkISize dimensions() const
Definition: SkImageInfo.h:421
Definition: SkVx.h:83
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
Definition: trace_event.h:141

◆ ops()

std::pair< LoadOp, StoreOp > skgpu::graphite::DrawPass::ops ( ) const
inline

Definition at line 74 of file DrawPass.h.

74{ return fOps; }

◆ prepareResources()

bool skgpu::graphite::DrawPass::prepareResources ( ResourceProvider resourceProvider,
const RuntimeEffectDictionary runtimeDict,
const RenderPassDesc renderPassDesc 
)

Definition at line 699 of file DrawPass.cpp.

701 {
702 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
703
704 fFullPipelines.reserve(fFullPipelines.size() + fPipelineDescs.size());
705 for (const GraphicsPipelineDesc& pipelineDesc : fPipelineDescs) {
706 auto pipeline = resourceProvider->findOrCreateGraphicsPipeline(runtimeDict,
707 pipelineDesc,
708 renderPassDesc);
709 if (!pipeline) {
710 SKGPU_LOG_W("Failed to create GraphicsPipeline for draw in RenderPass. Dropping pass!");
711 return false;
712 }
713 fFullPipelines.push_back(std::move(pipeline));
714 }
715 // The DrawPass may be long lived on a Recording and we no longer need the GraphicPipelineDescs
716 // once we've created pipelines, so we drop the storage for them here.
717 fPipelineDescs.clear();
718
719#if defined(SK_DEBUG)
720 for (int i = 0; i < fSampledTextures.size(); ++i) {
721 // It should not have been possible to draw an Image that has an invalid texture info
722 SkASSERT(fSampledTextures[i]->textureInfo().isValid());
723 // Tasks should have been ordered to instantiate any scratch textures already, or any
724 // client-owned image will have been instantiated at creation.
725 SkASSERTF(fSampledTextures[i]->isInstantiated() ||
726 fSampledTextures[i]->isLazy(),
727 "proxy label = %s", fSampledTextures[i]->label());
728 }
729#endif
730
731 fSamplers.reserve(fSamplers.size() + fSamplerDescs.size());
732 for (int i = 0; i < fSamplerDescs.size(); ++i) {
733 sk_sp<Sampler> sampler = resourceProvider->findOrCreateCompatibleSampler(fSamplerDescs[i]);
734 if (!sampler) {
735 SKGPU_LOG_W("Failed to create sampler. Will not create renderpass!");
736 return false;
737 }
738 fSamplers.push_back(std::move(sampler));
739 }
740 // The DrawPass may be long lived on a Recording and we no longer need the SamplerDescs
741 // once we've created Samplers, so we drop the storage for them here.
742 fSamplerDescs.clear();
743
744 return true;
745}
#define SkASSERTF(cond, fmt,...)
Definition: SkAssert.h:117
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131

◆ requiresDstTexture()

bool skgpu::graphite::DrawPass::requiresDstTexture ( ) const
inline

Definition at line 77 of file DrawPass.h.

77{ return false; }

◆ requiresMSAA()

bool skgpu::graphite::DrawPass::requiresMSAA ( ) const
inline

Definition at line 78 of file DrawPass.h.

78{ return fRequiresMSAA; }

◆ sampledTextures()

skia_private::TArray< sk_sp< TextureProxy > > skgpu::graphite::DrawPass::sampledTextures ( ) const
inline

Definition at line 102 of file DrawPass.h.

102{ return fSampledTextures; }

◆ target()

TextureProxy * skgpu::graphite::DrawPass::target ( ) const
inline

Definition at line 73 of file DrawPass.h.

73{ return fTarget.get(); }

◆ uniformBufferSize()

size_t skgpu::graphite::DrawPass::uniformBufferSize ( ) const
inline

Definition at line 83 of file DrawPass.h.

83{ return 0; }

◆ vertexBufferSize()

size_t skgpu::graphite::DrawPass::vertexBufferSize ( ) const
inline

Definition at line 82 of file DrawPass.h.

82{ return 0; }

The documentation for this class was generated from the following files: