41#include <unordered_map>
50template <u
int64_t Bits, u
int64_t Offset>
52 static constexpr uint64_t kMask = ((uint64_t) 1 <<
Bits) - 1;
53 static constexpr uint64_t
kOffset = Offset;
56 static uint32_t
get(uint64_t v) {
return static_cast<uint32_t
>((v >>
kOffset) & kMask); }
57 static uint64_t
set(uint32_t v) {
return (v & kMask) <<
kOffset; }
61template <
typename T,
typename V = T,
typename C = V>
64 using Index = uint32_t;
70 bool empty()
const {
return fIndexToData.empty(); }
71 size_t size()
const {
return fIndexToData.size(); }
73 Index insert(
const T&
data) {
74 Index* index = fDataToIndex.find(
data);
77 index = fDataToIndex.set(
data, (Index) fIndexToData.size());
78 fIndexToData.push_back(
C{
data});
83 const V& lookup(Index index) {
85 return fIndexToData[index];
88 SkSpan<V> data() {
return {fIndexToData.data(), fIndexToData.size()}; }
90 TArray<V>&& detach() {
return std::move(fIndexToData); }
105 CpuOrGpuData(
const UniformDataBlock* cpuData) :
fCpuData(cpuData) {}
110struct TextureBinding {
114 bool operator==(
const TextureBinding& other)
const {
118 bool operator!=(
const TextureBinding& other)
const {
return !(*
this == other); }
120 int numTextures()
const {
126using UniformCache = DenseBiMap<const UniformDataBlock*, CpuOrGpuData>;
127using TextureBindingCache = DenseBiMap<TextureBinding>;
128using GraphicsPipelineCache = DenseBiMap<GraphicsPipelineDesc>;
133class TextureBindingTracker {
135 TextureBindingCache::Index trackTextures(
const TextureDataBlock* paintTextures,
136 const TextureDataBlock* stepTextures) {
137 if (!paintTextures && !stepTextures) {
140 return fBindingCache.insert({paintTextures, stepTextures});
143 bool setCurrentTextureBindings(TextureBindingCache::Index bindingIndex) {
145 fLastIndex = bindingIndex;
154 const TextureBinding& binding = fBindingCache.lookup(fLastIndex);
156 auto [texIndices, samplerIndices] =
157 commandList->bindDeferredTexturesAndSamplers(binding.numTextures());
159 if (binding.fPaintTextures) {
160 for (
int i = 0;
i < binding.fPaintTextures->numTextures(); ++
i) {
161 auto [tex, sampler] = binding.fPaintTextures->texture(
i);
162 *texIndices++ = fProxyCache.insert(tex.get());
163 *samplerIndices++ = fSamplerCache.insert(sampler);
166 if (binding.fStepTextures) {
167 for (
int i = 0;
i < binding.fStepTextures->numTextures(); ++
i) {
168 auto [tex, sampler] = binding.fStepTextures->texture(
i);
169 *texIndices++ = fProxyCache.insert(tex.get());
170 *samplerIndices++ = fSamplerCache.insert(sampler);
183 using TextureProxyCache = DenseBiMap<const TextureProxy*, sk_sp<TextureProxy>, ProxyRef>;
184 using SamplerDescCache = DenseBiMap<SamplerDesc>;
186 TextureBindingCache fBindingCache;
188 TextureProxyCache fProxyCache;
189 SamplerDescCache fSamplerCache;
196class UniformTracker {
198 UniformTracker(
bool useStorageBuffers) : fUseStorageBuffers(useStorageBuffers) {}
202 UniformCache::Index trackUniforms(GraphicsPipelineCache::Index pipelineIndex,
203 const UniformDataBlock* cpuData) {
208 if (pipelineIndex >=
SkToU32(fPerPipelineCaches.size())) {
209 fPerPipelineCaches.resize(pipelineIndex + 1);
212 return fPerPipelineCaches[pipelineIndex].insert(cpuData);
219 bool writeUniforms(DrawBufferManager* bufferMgr) {
220 for (UniformCache&
cache : fPerPipelineCaches) {
226 size_t udbSize =
cache.lookup(0).fCpuData->size();
227 size_t udbDataSize = udbSize;
228 if (!fUseStorageBuffers) {
229 udbSize = bufferMgr->alignUniformBlockSize(udbSize);
231 auto [writer, bufferInfo] =
232 fUseStorageBuffers ? bufferMgr->getSsboWriter(udbSize *
cache.size())
233 : bufferMgr->getUniformWriter(udbSize *
cache.size());
238 uint32_t bindingSize;
239 if (fUseStorageBuffers) {
241 bindingSize =
static_cast<uint32_t
>(udbSize *
cache.size());
245 bindingSize =
static_cast<uint32_t
>(udbSize);
248 for (CpuOrGpuData& dataBlock :
cache.data()) {
249 SkASSERT(dataBlock.fCpuData->size() == udbDataSize);
250 writer.write(dataBlock.fCpuData->data(), udbDataSize);
252 dataBlock.fGpuData.fBuffer = bufferInfo.fBuffer;
253 dataBlock.fGpuData.fOffset = bufferInfo.fOffset;
254 dataBlock.fGpuData.fBindingSize = bindingSize;
256 if (!fUseStorageBuffers) {
257 bufferInfo.fOffset += bindingSize;
258 writer.skipBytes(bindingSize - udbDataSize);
268 bool setCurrentUniforms(GraphicsPipelineCache::Index pipelineIndex,
269 UniformCache::Index uniformIndex) {
274 uniformIndex < fPerPipelineCaches[pipelineIndex].size());
276 if (fUseStorageBuffers) {
279 if (fLastPipeline != pipelineIndex || fLastIndex != uniformIndex) {
280 fLastPipeline = pipelineIndex;
281 fLastIndex = uniformIndex;
293 SkASSERT(!fUseStorageBuffers || fLastIndex == 0);
294 const BindUniformBufferInfo& binding =
295 fPerPipelineCaches[fLastPipeline].lookup(fLastIndex).fGpuData;
296 commandList->bindUniformBuffer(binding, slot);
305 const bool fUseStorageBuffers;
311class GradientBufferTracker {
314 if (gradData.
empty()) {
318 auto [writer, bufferInfo] = bufferMgr->getSsboWriter(gradData.
size_bytes());
326 fBufferInfo.fBuffer = bufferInfo.fBuffer;
327 fBufferInfo.fOffset = bufferInfo.fOffset;
328 fBufferInfo.fBindingSize = gradData.
size_bytes();
341 BindUniformBufferInfo fBufferInfo;
342 bool fHasData =
false;
377 UniformCache::Index geomUniformIndex,
380 : fPipelineKey(ColorDepthOrderField::
set(
draw->fDrawParams.order().paintOrder().
bits()) |
381 StencilIndexField::
set(
draw->fDrawParams.order().stencilIndex().
bits()) |
384 , fUniformKey(GeometryUniformField::
set(geomUniformIndex) |
389 SkASSERT(renderStep <= draw->fRenderer->numRenderSteps());
393 return fPipelineKey < k.fPipelineKey ||
394 (fPipelineKey == k.fPipelineKey && fUniformKey < k.fUniformKey);
420 using ColorDepthOrderField = Bitfield<16, 48>;
421 using StencilIndexField = Bitfield<16, 32>;
422 using RenderStepField = Bitfield<2, 30>;
423 using PipelineField = Bitfield<30, 0>;
424 uint64_t fPipelineKey;
429 using GeometryUniformField = Bitfield<17, 47>;
430 using ShadingUniformField = Bitfield<17, 30>;
431 using TextureBindingsField = Bitfield<30, 0>;
432 uint64_t fUniformKey;
449 std::pair<LoadOp, StoreOp>
ops,
450 std::array<float, 4> clearColor)
454 , fClearColor(clearColor) {}
459 std::unique_ptr<DrawList> draws,
462 std::pair<LoadOp, StoreOp>
ops,
497 SKGPU_LOG_W(
"Buffer mapping has already failed; dropping draw pass!");
501 if (!draws->dstCopyBounds().isEmptyNegativeOrNaN() && !dstCopy) {
502 SKGPU_LOG_W(
"Failed to copy destination for reading. Dropping draw pass!");
506 GraphicsPipelineCache pipelineCache;
515 UniformTracker geometryUniformTracker(useStorageBuffers);
516 UniformTracker shadingUniformTracker(useStorageBuffers);
517 TextureBindingTracker textureBindingTracker;
518 GradientBufferTracker gradientBufferTracker;
527 std::vector<SortKey> keys;
528 keys.reserve(draws->renderStepCount());
538 if (
draw.fPaintParams.has_value()) {
543 std::tie(shaderID, shadingUniforms, paintTextures) =
548 draw.fDrawParams.transform(),
549 draw.fPaintParams.value(),
550 draw.fDrawParams.geometry(),
556 for (
int stepIndex = 0; stepIndex <
draw.fRenderer->numRenderSteps(); ++stepIndex) {
558 const bool performsShading =
draw.fPaintParams.has_value() &&
step->performsShading();
560 GraphicsPipelineCache::Index pipelineIndex = pipelineCache.insert(
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);
576 keys.push_back({&
draw, stepIndex, pipelineIndex,
577 geomUniformIndex, shadingUniformIndex, textureIndex});
580 passBounds.
join(
draw.fDrawParams.clip().drawBounds());
581 drawPass->fDepthStencilFlags |=
draw.fRenderer->depthStencilFlags();
582 drawPass->fRequiresMSAA |=
draw.fRenderer->requiresMSAA();
585 if (!geometryUniformTracker.writeUniforms(bufferMgr) ||
586 !shadingUniformTracker.writeUniforms(bufferMgr) ||
603 DrawWriter drawWriter(&drawPass->fCommandList, bufferMgr);
607 SkASSERT(drawPass->fTarget->isFullyLazy() ||
609 drawPass->fCommandList.setScissor(lastScissor);
613 gradientBufferTracker.bindIfNeeded(&drawPass->fCommandList);
619 const bool pipelineChange =
key.pipelineIndex() != lastPipeline;
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;
630 const bool stateChange = geomBindingChange ||
631 shadingBindingChange ||
632 textureBindingsChange ||
637 if (pipelineChange) {
641 }
else if (stateChange) {
646 if (pipelineChange) {
647 drawPass->fCommandList.bindGraphicsPipeline(
key.pipelineIndex());
648 lastPipeline =
key.pipelineIndex();
651 if (geomBindingChange) {
653 &drawPass->fCommandList);
655 if (shadingBindingChange) {
658 if (textureBindingsChange) {
659 textureBindingTracker.bindTextures(&drawPass->fCommandList);
662 drawPass->fCommandList.setScissor(*newScissor);
663 lastScissor = *newScissor;
667 UniformCache::Index geometrySsboIndex =
670 :
key.geometryUniformIndex();
671 UniformCache::Index shadingSsboIndex =
674 :
key.shadingUniformIndex();
679 SKGPU_LOG_W(
"Failed to write necessary vertex/instance data for DrawPass, dropping!");
688 drawPass->fPipelineDescs = pipelineCache.detach();
689 drawPass->fSamplerDescs = textureBindingTracker.detachSamplers();
690 drawPass->fSampledTextures = textureBindingTracker.detachTextures();
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());
704 fFullPipelines.reserve(fFullPipelines.size() + fPipelineDescs.size());
710 SKGPU_LOG_W(
"Failed to create GraphicsPipeline for draw in RenderPass. Dropping pass!");
713 fFullPipelines.push_back(std::move(pipeline));
717 fPipelineDescs.clear();
720 for (
int i = 0;
i < fSampledTextures.size(); ++
i) {
722 SkASSERT(fSampledTextures[
i]->textureInfo().isValid());
725 SkASSERTF(fSampledTextures[
i]->isInstantiated() ||
726 fSampledTextures[
i]->isLazy(),
727 "proxy label = %s", fSampledTextures[
i]->label());
731 fSamplers.reserve(fSamplers.size() + fSamplerDescs.size());
732 for (
int i = 0;
i < fSamplerDescs.size(); ++
i) {
735 SKGPU_LOG_W(
"Failed to create sampler. Will not create renderpass!");
738 fSamplers.push_back(std::move(sampler));
742 fSamplerDescs.clear();
748 for (
int i = 0;
i < fFullPipelines.size(); ++
i) {
751 for (
int i = 0;
i < fSampledTextures.size(); ++
i) {
754 for (
int i = 0;
i < fSamplers.size(); ++
i) {
763 return fSampledTextures[index]->texture();
768 return fSamplers[index].get();
static int step(int x, SkScalar min, SkScalar max)
const TextureProxy * fProxy
static constexpr uint64_t kBits
const TextureDataBlock * fPaintTextures
const UniformDataBlock * fCpuData
BindUniformBufferInfo fGpuData
static constexpr Index kInvalidIndex
static constexpr uint64_t kOffset
const TextureDataBlock * fStepTextures
#define SKGPU_LOG_W(fmt,...)
static constexpr size_t SkAlignTo(size_t x, size_t alignment)
#define SkASSERTF(cond, fmt,...)
SkIDChangeListener::List List
constexpr int SkNextLog2_portable(uint32_t value)
static std::vector< SkPDFIndirectReference > sort(const THashSet< SkPDFIndirectReference > &src)
sk_sp< T > sk_ref_sp(T *obj)
constexpr size_t SkToSizeT(S x)
constexpr uint16_t SkToU16(S x)
static constexpr bool SkToBool(const T &x)
constexpr uint32_t SkToU32(S x)
#define TRACE_COUNTER1(category_group, name, value)
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
constexpr T * data() const
constexpr bool empty() const
constexpr size_t size_bytes() const
const ResourceBindingRequirements & resourceBindingRequirements() const
bool storageBufferPreferred() const
void trackResource(sk_sp< Resource > resource)
void trackCommandBufferResource(sk_sp< Resource > resource)
bool hasMappingFailed() const
static constexpr int kMaxRenderSteps
UniformCache::Index shadingUniformIndex() const
UniformCache::Index geometryUniformIndex() const
SortKey(const DrawList::Draw *draw, int renderStep, GraphicsPipelineCache::Index pipelineIndex, UniformCache::Index geomUniformIndex, UniformCache::Index shadingUniformIndex, TextureBindingCache::Index textureBindingIndex)
const DrawList::Draw & draw() const
const RenderStep & renderStep() const
bool operator<(const SortKey &k) const
TextureBindingCache::Index textureBindingIndex() const
GraphicsPipelineCache::Index pipelineIndex() const
const Texture * getTexture(size_t index) const
std::array< float, 4 > clearColor() const
bool prepareResources(ResourceProvider *, const RuntimeEffectDictionary *, const RenderPassDesc &)
const Sampler * getSampler(size_t index) const
std::pair< LoadOp, StoreOp > ops() const
TextureProxy * target() const
void addResourceRefs(CommandBuffer *) const
static std::unique_ptr< DrawPass > Make(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)
void newPipelineState(PrimitiveType type, size_t vertexStride, size_t instanceStride)
SkSpan< const float > gradientBufferData() const
const ShaderCodeDictionary * shaderCodeDictionary() const
TextureDataCache * textureDataCache()
const Caps * caps() const
DrawBufferManager * drawBufferManager()
static AI Rect InfiniteInverted()
AI Rect & join(Rect rect)
AI SkIRect asSkIRect() const
size_t vertexStride() const
PrimitiveType primitiveType() const
virtual void writeVertices(DrawWriter *, const DrawParams &, skvx::ushort2 ssboIndices) const =0
size_t instanceStride() const
static constexpr int kMaxRenderSteps
const RenderStep & step(int i) const
sk_sp< GraphicsPipeline > findOrCreateGraphicsPipeline(const RuntimeEffectDictionary *, const GraphicsPipelineDesc &, const RenderPassDesc &)
sk_sp< Sampler > findOrCreateCompatibleSampler(const SamplerDesc &)
static UniquePaintParamsID InvalidID()
EMSCRIPTEN_KEEPALIVE void empty()
T __attribute__((ext_vector_type(N))) V
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
bool operator==(C p1, const scoped_nsprotocol< C > &p2)
bool operator!=(C p1, const scoped_nsprotocol< C > &p2)
const myers::Point & get(const myers::Segment &)
MonotonicValue< DisjointStencilIndexSequence > DisjointStencilIndex
std::tuple< const UniformDataBlock *, const TextureDataBlock * > ExtractRenderStepData(UniformDataCache *uniformDataCache, TextureDataCache *textureDataCache, PipelineDataGatherer *gatherer, const Layout layout, const RenderStep *step, const DrawParams ¶ms)
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)
MonotonicValue< CompressedPaintersOrderSequence > CompressedPaintersOrder
static constexpr SkIRect MakeSize(const SkISize &size)
bool contains(int32_t x, int32_t y) const
const SkColorInfo & colorInfo() const
SkISize dimensions() const
const Renderer * fRenderer
Layout fUniformBufferLayout
Layout fStorageBufferLayout
std::shared_ptr< const fml::Mapping > data
#define TRACE_EVENT0(category_group, name)
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)