xref: /aosp_15_r20/external/skia/src/gpu/graphite/DrawPass.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2021 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawPass.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/GraphiteTypes.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Recorder.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAlign.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTraceEvent.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Buffer.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/BufferManager.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Caps.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ContextPriv.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ContextUtils.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawContext.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawList.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawWriter.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/GlobalCache.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/GraphicsPipeline.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/GraphicsPipelineDesc.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Log.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PaintParamsKey.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PipelineData.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RecorderPriv.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Renderer.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ResourceProvider.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Sampler.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Texture.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/UniformManager.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/BoundsManager.h"
35*c8dee2aaSAndroid Build Coastguard Worker 
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkMathPriv.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTBlockList.h"
38*c8dee2aaSAndroid Build Coastguard Worker 
39*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
40*c8dee2aaSAndroid Build Coastguard Worker 
41*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
42*c8dee2aaSAndroid Build Coastguard Worker 
43*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker namespace {
46*c8dee2aaSAndroid Build Coastguard Worker 
47*c8dee2aaSAndroid Build Coastguard Worker // Helper to manage packed fields within a uint64_t
48*c8dee2aaSAndroid Build Coastguard Worker template <uint64_t Bits, uint64_t Offset>
49*c8dee2aaSAndroid Build Coastguard Worker struct Bitfield {
50*c8dee2aaSAndroid Build Coastguard Worker     static constexpr uint64_t kMask = ((uint64_t) 1 << Bits) - 1;
51*c8dee2aaSAndroid Build Coastguard Worker     static constexpr uint64_t kOffset = Offset;
52*c8dee2aaSAndroid Build Coastguard Worker     static constexpr uint64_t kBits = Bits;
53*c8dee2aaSAndroid Build Coastguard Worker 
getskgpu::graphite::__anon6929da090111::Bitfield54*c8dee2aaSAndroid Build Coastguard Worker     static uint32_t get(uint64_t v) { return static_cast<uint32_t>((v >> kOffset) & kMask); }
setskgpu::graphite::__anon6929da090111::Bitfield55*c8dee2aaSAndroid Build Coastguard Worker     static uint64_t set(uint32_t v) { return (v & kMask) << kOffset; }
56*c8dee2aaSAndroid Build Coastguard Worker };
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker // This class maps objects to a dense index which can then be used to look them up later
59*c8dee2aaSAndroid Build Coastguard Worker template <typename T, typename V = T, typename C = V>
60*c8dee2aaSAndroid Build Coastguard Worker class DenseBiMap {
61*c8dee2aaSAndroid Build Coastguard Worker public:
62*c8dee2aaSAndroid Build Coastguard Worker     using Index = uint32_t;
63*c8dee2aaSAndroid Build Coastguard Worker 
64*c8dee2aaSAndroid Build Coastguard Worker     // See note below in GeometryUniformField. This value can be round-tripped within the SortKey
65*c8dee2aaSAndroid Build Coastguard Worker     // packing for all fields but will not be produced when recording actual draw data.
66*c8dee2aaSAndroid Build Coastguard Worker     static constexpr Index kInvalidIndex{1 << SkNextLog2_portable(DrawList::kMaxRenderSteps)};
67*c8dee2aaSAndroid Build Coastguard Worker 
empty() const68*c8dee2aaSAndroid Build Coastguard Worker     bool empty() const { return fIndexToData.empty(); }
size() const69*c8dee2aaSAndroid Build Coastguard Worker     size_t size() const { return fIndexToData.size(); }
70*c8dee2aaSAndroid Build Coastguard Worker 
insert(const T & data)71*c8dee2aaSAndroid Build Coastguard Worker     Index insert(const T& data) {
72*c8dee2aaSAndroid Build Coastguard Worker         Index* index = fDataToIndex.find(data);
73*c8dee2aaSAndroid Build Coastguard Worker         if (!index) {
74*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(SkToU32(fIndexToData.size()) < kInvalidIndex);
75*c8dee2aaSAndroid Build Coastguard Worker             index = fDataToIndex.set(data, (Index) fIndexToData.size());
76*c8dee2aaSAndroid Build Coastguard Worker             fIndexToData.push_back(C{data});
77*c8dee2aaSAndroid Build Coastguard Worker         }
78*c8dee2aaSAndroid Build Coastguard Worker         return *index;
79*c8dee2aaSAndroid Build Coastguard Worker     }
80*c8dee2aaSAndroid Build Coastguard Worker 
lookup(Index index)81*c8dee2aaSAndroid Build Coastguard Worker     const V& lookup(Index index) {
82*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(index < kInvalidIndex);
83*c8dee2aaSAndroid Build Coastguard Worker         return fIndexToData[index];
84*c8dee2aaSAndroid Build Coastguard Worker     }
85*c8dee2aaSAndroid Build Coastguard Worker 
data()86*c8dee2aaSAndroid Build Coastguard Worker     SkSpan<V> data() { return {fIndexToData.data(), fIndexToData.size()}; }
87*c8dee2aaSAndroid Build Coastguard Worker 
detach()88*c8dee2aaSAndroid Build Coastguard Worker     TArray<V>&& detach() { return std::move(fIndexToData); }
89*c8dee2aaSAndroid Build Coastguard Worker 
90*c8dee2aaSAndroid Build Coastguard Worker private:
91*c8dee2aaSAndroid Build Coastguard Worker     THashMap<T, Index> fDataToIndex;
92*c8dee2aaSAndroid Build Coastguard Worker     TArray<V> fIndexToData;
93*c8dee2aaSAndroid Build Coastguard Worker };
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker // NOTE: TextureBinding's use as a key type in DenseBiMap relies on the fact that the underlying
96*c8dee2aaSAndroid Build Coastguard Worker // data has been de-duplicated by a PipelineDataCache earlier, so that the bit identity of the data
97*c8dee2aaSAndroid Build Coastguard Worker // blocks (e.g. address+size) is equivalent to the content equality of the texture lists.
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker // Tracks the combination of textures from the paint and from the RenderStep to describe the full
100*c8dee2aaSAndroid Build Coastguard Worker // binding that needs to be in the command list.
101*c8dee2aaSAndroid Build Coastguard Worker struct TextureBinding {
102*c8dee2aaSAndroid Build Coastguard Worker     TextureDataBlock fPaintTextures;
103*c8dee2aaSAndroid Build Coastguard Worker     TextureDataBlock fStepTextures;
104*c8dee2aaSAndroid Build Coastguard Worker 
operator ==skgpu::graphite::__anon6929da090111::TextureBinding105*c8dee2aaSAndroid Build Coastguard Worker     bool operator==(const TextureBinding& other) const {
106*c8dee2aaSAndroid Build Coastguard Worker         return fPaintTextures == other.fPaintTextures &&
107*c8dee2aaSAndroid Build Coastguard Worker                fStepTextures == other.fStepTextures;
108*c8dee2aaSAndroid Build Coastguard Worker     }
operator !=skgpu::graphite::__anon6929da090111::TextureBinding109*c8dee2aaSAndroid Build Coastguard Worker     bool operator!=(const TextureBinding& other) const { return !(*this == other); }
110*c8dee2aaSAndroid Build Coastguard Worker 
numTexturesskgpu::graphite::__anon6929da090111::TextureBinding111*c8dee2aaSAndroid Build Coastguard Worker     int numTextures() const {
112*c8dee2aaSAndroid Build Coastguard Worker         return (fPaintTextures ? fPaintTextures.numTextures() : 0) +
113*c8dee2aaSAndroid Build Coastguard Worker                (fStepTextures ? fStepTextures.numTextures() : 0);
114*c8dee2aaSAndroid Build Coastguard Worker     }
115*c8dee2aaSAndroid Build Coastguard Worker };
116*c8dee2aaSAndroid Build Coastguard Worker 
117*c8dee2aaSAndroid Build Coastguard Worker using TextureBindingCache = DenseBiMap<TextureBinding>;
118*c8dee2aaSAndroid Build Coastguard Worker using GraphicsPipelineCache = DenseBiMap<GraphicsPipelineDesc>;
119*c8dee2aaSAndroid Build Coastguard Worker 
120*c8dee2aaSAndroid Build Coastguard Worker // Writes uniform data either to uniform buffers or to shared storage buffers, and tracks when
121*c8dee2aaSAndroid Build Coastguard Worker // bindings need to change between draws.
122*c8dee2aaSAndroid Build Coastguard Worker class UniformTracker {
123*c8dee2aaSAndroid Build Coastguard Worker public:
UniformTracker(bool useStorageBuffers)124*c8dee2aaSAndroid Build Coastguard Worker     UniformTracker(bool useStorageBuffers) : fUseStorageBuffers(useStorageBuffers) {}
125*c8dee2aaSAndroid Build Coastguard Worker 
writeUniforms(UniformDataCache & uniformCache,DrawBufferManager * bufferMgr,UniformDataCache::Index index)126*c8dee2aaSAndroid Build Coastguard Worker     bool writeUniforms(UniformDataCache& uniformCache,
127*c8dee2aaSAndroid Build Coastguard Worker                        DrawBufferManager* bufferMgr,
128*c8dee2aaSAndroid Build Coastguard Worker                        UniformDataCache::Index index) {
129*c8dee2aaSAndroid Build Coastguard Worker         if (index >= UniformDataCache::kInvalidIndex) {
130*c8dee2aaSAndroid Build Coastguard Worker             return false;
131*c8dee2aaSAndroid Build Coastguard Worker         }
132*c8dee2aaSAndroid Build Coastguard Worker 
133*c8dee2aaSAndroid Build Coastguard Worker         if (index == fLastIndex) {
134*c8dee2aaSAndroid Build Coastguard Worker             return false;
135*c8dee2aaSAndroid Build Coastguard Worker         }
136*c8dee2aaSAndroid Build Coastguard Worker         fLastIndex = index;
137*c8dee2aaSAndroid Build Coastguard Worker 
138*c8dee2aaSAndroid Build Coastguard Worker         UniformDataCache::Entry& uniformData = uniformCache.lookup(index);
139*c8dee2aaSAndroid Build Coastguard Worker         const size_t uniformDataSize = uniformData.fCpuData.size();
140*c8dee2aaSAndroid Build Coastguard Worker 
141*c8dee2aaSAndroid Build Coastguard Worker         // Upload the uniform data if we haven't already.
142*c8dee2aaSAndroid Build Coastguard Worker         // Alternatively, re-upload the uniform data to avoid a rebind if we're using storage
143*c8dee2aaSAndroid Build Coastguard Worker         // buffers. This will result in more data uploaded, but the tradeoff seems worthwhile.
144*c8dee2aaSAndroid Build Coastguard Worker         if (!uniformData.fBufferBinding.fBuffer ||
145*c8dee2aaSAndroid Build Coastguard Worker             (fUseStorageBuffers && uniformData.fBufferBinding.fBuffer != fLastBinding.fBuffer)) {
146*c8dee2aaSAndroid Build Coastguard Worker             UniformWriter writer;
147*c8dee2aaSAndroid Build Coastguard Worker             std::tie(writer, uniformData.fBufferBinding) =
148*c8dee2aaSAndroid Build Coastguard Worker                     fUseStorageBuffers ? bufferMgr->getAlignedSsboWriter(1, uniformDataSize)
149*c8dee2aaSAndroid Build Coastguard Worker                                        : bufferMgr->getUniformWriter(1, uniformDataSize);
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker             // Early out if buffer mapping failed.
152*c8dee2aaSAndroid Build Coastguard Worker             if (!writer) {
153*c8dee2aaSAndroid Build Coastguard Worker                 return {};
154*c8dee2aaSAndroid Build Coastguard Worker             }
155*c8dee2aaSAndroid Build Coastguard Worker 
156*c8dee2aaSAndroid Build Coastguard Worker             writer.write(uniformData.fCpuData.data(), uniformDataSize);
157*c8dee2aaSAndroid Build Coastguard Worker 
158*c8dee2aaSAndroid Build Coastguard Worker             if (fUseStorageBuffers) {
159*c8dee2aaSAndroid Build Coastguard Worker                 // When using storage buffers, store the SSBO index in the binding's offset field
160*c8dee2aaSAndroid Build Coastguard Worker                 // and always use the entire buffer's size in the size field.
161*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(uniformData.fBufferBinding.fOffset % uniformDataSize == 0);
162*c8dee2aaSAndroid Build Coastguard Worker                 uniformData.fBufferBinding.fOffset /= uniformDataSize;
163*c8dee2aaSAndroid Build Coastguard Worker                 uniformData.fBufferBinding.fSize = uniformData.fBufferBinding.fBuffer->size();
164*c8dee2aaSAndroid Build Coastguard Worker             }
165*c8dee2aaSAndroid Build Coastguard Worker         }
166*c8dee2aaSAndroid Build Coastguard Worker 
167*c8dee2aaSAndroid Build Coastguard Worker         const bool needsRebind =
168*c8dee2aaSAndroid Build Coastguard Worker                 uniformData.fBufferBinding.fBuffer != fLastBinding.fBuffer ||
169*c8dee2aaSAndroid Build Coastguard Worker                 (!fUseStorageBuffers && uniformData.fBufferBinding.fOffset != fLastBinding.fOffset);
170*c8dee2aaSAndroid Build Coastguard Worker 
171*c8dee2aaSAndroid Build Coastguard Worker         fLastBinding = uniformData.fBufferBinding;
172*c8dee2aaSAndroid Build Coastguard Worker 
173*c8dee2aaSAndroid Build Coastguard Worker         return needsRebind;
174*c8dee2aaSAndroid Build Coastguard Worker     }
175*c8dee2aaSAndroid Build Coastguard Worker 
bindUniforms(UniformSlot slot,DrawPassCommands::List * commandList)176*c8dee2aaSAndroid Build Coastguard Worker     void bindUniforms(UniformSlot slot, DrawPassCommands::List* commandList) {
177*c8dee2aaSAndroid Build Coastguard Worker         BindBufferInfo binding = fLastBinding;
178*c8dee2aaSAndroid Build Coastguard Worker         if (fUseStorageBuffers) {
179*c8dee2aaSAndroid Build Coastguard Worker             // Track the SSBO index in fLastBinding, but set offset = 0 in the actual used binding.
180*c8dee2aaSAndroid Build Coastguard Worker             binding.fOffset = 0;
181*c8dee2aaSAndroid Build Coastguard Worker         }
182*c8dee2aaSAndroid Build Coastguard Worker         commandList->bindUniformBuffer(binding, slot);
183*c8dee2aaSAndroid Build Coastguard Worker     }
184*c8dee2aaSAndroid Build Coastguard Worker 
ssboIndex() const185*c8dee2aaSAndroid Build Coastguard Worker     uint32_t ssboIndex() const {
186*c8dee2aaSAndroid Build Coastguard Worker         // The SSBO index for the last-bound storage buffer is stored in the binding's offset field.
187*c8dee2aaSAndroid Build Coastguard Worker         return fLastBinding.fOffset;
188*c8dee2aaSAndroid Build Coastguard Worker     }
189*c8dee2aaSAndroid Build Coastguard Worker 
190*c8dee2aaSAndroid Build Coastguard Worker private:
191*c8dee2aaSAndroid Build Coastguard Worker     // Internally track the last binding returned, so that we know whether new uploads or rebindings
192*c8dee2aaSAndroid Build Coastguard Worker     // are necessary. If we're using SSBOs, this is treated specially -- the fOffset field holds the
193*c8dee2aaSAndroid Build Coastguard Worker     // index in the storage buffer of the last-written uniforms, and the offsets used for actual
194*c8dee2aaSAndroid Build Coastguard Worker     // bindings are always zero.
195*c8dee2aaSAndroid Build Coastguard Worker     BindBufferInfo fLastBinding;
196*c8dee2aaSAndroid Build Coastguard Worker 
197*c8dee2aaSAndroid Build Coastguard Worker     // This keeps track of the last index used for writing uniforms from a provided uniform cache.
198*c8dee2aaSAndroid Build Coastguard Worker     // If a provided index matches the last index, the uniforms are assumed to already be written
199*c8dee2aaSAndroid Build Coastguard Worker     // and no additional uploading is performed. This assumes a UniformTracker will always be
200*c8dee2aaSAndroid Build Coastguard Worker     // provided with the same uniform cache.
201*c8dee2aaSAndroid Build Coastguard Worker     UniformDataCache::Index fLastIndex = UniformDataCache::kInvalidIndex;
202*c8dee2aaSAndroid Build Coastguard Worker 
203*c8dee2aaSAndroid Build Coastguard Worker     const bool fUseStorageBuffers;
204*c8dee2aaSAndroid Build Coastguard Worker };
205*c8dee2aaSAndroid Build Coastguard Worker 
206*c8dee2aaSAndroid Build Coastguard Worker // Automatically merges and manages texture bindings and uniform bindings sourced from either the
207*c8dee2aaSAndroid Build Coastguard Worker // paint or the RenderStep. Tracks the bound state based on last-provided unique index to write
208*c8dee2aaSAndroid Build Coastguard Worker // Bind commands to a CommandList when necessary.
209*c8dee2aaSAndroid Build Coastguard Worker class TextureBindingTracker {
210*c8dee2aaSAndroid Build Coastguard Worker public:
trackTextures(TextureDataBlock paintTextures,TextureDataBlock stepTextures)211*c8dee2aaSAndroid Build Coastguard Worker     TextureBindingCache::Index trackTextures(TextureDataBlock paintTextures,
212*c8dee2aaSAndroid Build Coastguard Worker                                              TextureDataBlock stepTextures) {
213*c8dee2aaSAndroid Build Coastguard Worker         if (!paintTextures && !stepTextures) {
214*c8dee2aaSAndroid Build Coastguard Worker             return TextureBindingCache::kInvalidIndex;
215*c8dee2aaSAndroid Build Coastguard Worker         }
216*c8dee2aaSAndroid Build Coastguard Worker         return fBindingCache.insert({paintTextures, stepTextures});
217*c8dee2aaSAndroid Build Coastguard Worker     }
218*c8dee2aaSAndroid Build Coastguard Worker 
setCurrentTextureBindings(TextureBindingCache::Index bindingIndex)219*c8dee2aaSAndroid Build Coastguard Worker     bool setCurrentTextureBindings(TextureBindingCache::Index bindingIndex) {
220*c8dee2aaSAndroid Build Coastguard Worker         if (bindingIndex < TextureBindingCache::kInvalidIndex && fLastIndex != bindingIndex) {
221*c8dee2aaSAndroid Build Coastguard Worker             fLastIndex = bindingIndex;
222*c8dee2aaSAndroid Build Coastguard Worker             return true;
223*c8dee2aaSAndroid Build Coastguard Worker         }
224*c8dee2aaSAndroid Build Coastguard Worker         // No binding change
225*c8dee2aaSAndroid Build Coastguard Worker         return false;
226*c8dee2aaSAndroid Build Coastguard Worker     }
227*c8dee2aaSAndroid Build Coastguard Worker 
bindTextures(DrawPassCommands::List * commandList)228*c8dee2aaSAndroid Build Coastguard Worker     void bindTextures(DrawPassCommands::List* commandList) {
229*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fLastIndex < TextureBindingCache::kInvalidIndex);
230*c8dee2aaSAndroid Build Coastguard Worker         const TextureBinding& binding = fBindingCache.lookup(fLastIndex);
231*c8dee2aaSAndroid Build Coastguard Worker 
232*c8dee2aaSAndroid Build Coastguard Worker         auto [texIndices, samplerIndices] =
233*c8dee2aaSAndroid Build Coastguard Worker                 commandList->bindDeferredTexturesAndSamplers(binding.numTextures());
234*c8dee2aaSAndroid Build Coastguard Worker 
235*c8dee2aaSAndroid Build Coastguard Worker         if (binding.fPaintTextures) {
236*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < binding.fPaintTextures.numTextures(); ++i) {
237*c8dee2aaSAndroid Build Coastguard Worker                 auto [tex, sampler] = binding.fPaintTextures.texture(i);
238*c8dee2aaSAndroid Build Coastguard Worker                 *texIndices++     = fProxyCache.insert(tex.get());
239*c8dee2aaSAndroid Build Coastguard Worker                 *samplerIndices++ = fSamplerCache.insert(sampler);
240*c8dee2aaSAndroid Build Coastguard Worker             }
241*c8dee2aaSAndroid Build Coastguard Worker         }
242*c8dee2aaSAndroid Build Coastguard Worker         if (binding.fStepTextures) {
243*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < binding.fStepTextures.numTextures(); ++i) {
244*c8dee2aaSAndroid Build Coastguard Worker                 auto [tex, sampler] = binding.fStepTextures.texture(i);
245*c8dee2aaSAndroid Build Coastguard Worker                 *texIndices++     = fProxyCache.insert(tex.get());
246*c8dee2aaSAndroid Build Coastguard Worker                 *samplerIndices++ = fSamplerCache.insert(sampler);
247*c8dee2aaSAndroid Build Coastguard Worker             }
248*c8dee2aaSAndroid Build Coastguard Worker         }
249*c8dee2aaSAndroid Build Coastguard Worker     }
250*c8dee2aaSAndroid Build Coastguard Worker 
detachTextures()251*c8dee2aaSAndroid Build Coastguard Worker     TArray<sk_sp<TextureProxy>>&& detachTextures() { return fProxyCache.detach(); }
detachSamplers()252*c8dee2aaSAndroid Build Coastguard Worker     TArray<SamplerDesc>&& detachSamplers() { return fSamplerCache.detach(); }
253*c8dee2aaSAndroid Build Coastguard Worker 
254*c8dee2aaSAndroid Build Coastguard Worker private:
255*c8dee2aaSAndroid Build Coastguard Worker     struct ProxyRef {
256*c8dee2aaSAndroid Build Coastguard Worker         const TextureProxy* fProxy;
operator sk_sp<TextureProxy>skgpu::graphite::__anon6929da090111::TextureBindingTracker::ProxyRef257*c8dee2aaSAndroid Build Coastguard Worker         operator sk_sp<TextureProxy>() const { return sk_ref_sp(fProxy); }
258*c8dee2aaSAndroid Build Coastguard Worker     };
259*c8dee2aaSAndroid Build Coastguard Worker     using TextureProxyCache = DenseBiMap<const TextureProxy*, sk_sp<TextureProxy>, ProxyRef>;
260*c8dee2aaSAndroid Build Coastguard Worker     using SamplerDescCache = DenseBiMap<SamplerDesc>;
261*c8dee2aaSAndroid Build Coastguard Worker 
262*c8dee2aaSAndroid Build Coastguard Worker     TextureBindingCache fBindingCache;
263*c8dee2aaSAndroid Build Coastguard Worker 
264*c8dee2aaSAndroid Build Coastguard Worker     TextureProxyCache fProxyCache;
265*c8dee2aaSAndroid Build Coastguard Worker     SamplerDescCache fSamplerCache;
266*c8dee2aaSAndroid Build Coastguard Worker 
267*c8dee2aaSAndroid Build Coastguard Worker     TextureBindingCache::Index fLastIndex = TextureBindingCache::kInvalidIndex;
268*c8dee2aaSAndroid Build Coastguard Worker };
269*c8dee2aaSAndroid Build Coastguard Worker 
270*c8dee2aaSAndroid Build Coastguard Worker class GradientBufferTracker {
271*c8dee2aaSAndroid Build Coastguard Worker public:
writeData(SkSpan<const float> gradData,DrawBufferManager * bufferMgr)272*c8dee2aaSAndroid Build Coastguard Worker     bool writeData(SkSpan<const float> gradData, DrawBufferManager* bufferMgr) {
273*c8dee2aaSAndroid Build Coastguard Worker         if (gradData.empty()) {
274*c8dee2aaSAndroid Build Coastguard Worker             return true;
275*c8dee2aaSAndroid Build Coastguard Worker         }
276*c8dee2aaSAndroid Build Coastguard Worker 
277*c8dee2aaSAndroid Build Coastguard Worker         auto [writer, bufferInfo] = bufferMgr->getSsboWriter(gradData.size(), sizeof(float));
278*c8dee2aaSAndroid Build Coastguard Worker 
279*c8dee2aaSAndroid Build Coastguard Worker         if (!writer) {
280*c8dee2aaSAndroid Build Coastguard Worker             return false;
281*c8dee2aaSAndroid Build Coastguard Worker         }
282*c8dee2aaSAndroid Build Coastguard Worker 
283*c8dee2aaSAndroid Build Coastguard Worker         writer.write(gradData.data(), gradData.size_bytes());
284*c8dee2aaSAndroid Build Coastguard Worker         fBufferInfo = bufferInfo;
285*c8dee2aaSAndroid Build Coastguard Worker         fHasData = true;
286*c8dee2aaSAndroid Build Coastguard Worker 
287*c8dee2aaSAndroid Build Coastguard Worker         return true;
288*c8dee2aaSAndroid Build Coastguard Worker     }
289*c8dee2aaSAndroid Build Coastguard Worker 
bindIfNeeded(DrawPassCommands::List * commandList) const290*c8dee2aaSAndroid Build Coastguard Worker     void bindIfNeeded(DrawPassCommands::List* commandList) const {
291*c8dee2aaSAndroid Build Coastguard Worker         if (fHasData) {
292*c8dee2aaSAndroid Build Coastguard Worker             commandList->bindUniformBuffer(fBufferInfo, UniformSlot::kGradient);
293*c8dee2aaSAndroid Build Coastguard Worker         }
294*c8dee2aaSAndroid Build Coastguard Worker     }
295*c8dee2aaSAndroid Build Coastguard Worker 
296*c8dee2aaSAndroid Build Coastguard Worker private:
297*c8dee2aaSAndroid Build Coastguard Worker     BindBufferInfo fBufferInfo;
298*c8dee2aaSAndroid Build Coastguard Worker     bool fHasData = false;
299*c8dee2aaSAndroid Build Coastguard Worker };
300*c8dee2aaSAndroid Build Coastguard Worker 
301*c8dee2aaSAndroid Build Coastguard Worker } // namespace
302*c8dee2aaSAndroid Build Coastguard Worker 
303*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
304*c8dee2aaSAndroid Build Coastguard Worker 
305*c8dee2aaSAndroid Build Coastguard Worker /**
306*c8dee2aaSAndroid Build Coastguard Worker  * Each Draw in a DrawList might be processed by multiple RenderSteps (determined by the Draw's
307*c8dee2aaSAndroid Build Coastguard Worker  * Renderer), which can be sorted independently. Each (step, draw) pair produces its own SortKey.
308*c8dee2aaSAndroid Build Coastguard Worker  *
309*c8dee2aaSAndroid Build Coastguard Worker  * The goal of sorting draws for the DrawPass is to minimize pipeline transitions and dynamic binds
310*c8dee2aaSAndroid Build Coastguard Worker  * within a pipeline, while still respecting the overall painter's order. This decreases the number
311*c8dee2aaSAndroid Build Coastguard Worker  * of low-level draw commands in a command buffer and increases the size of those, allowing the GPU
312*c8dee2aaSAndroid Build Coastguard Worker  * to operate more efficiently and have fewer bubbles within its own instruction stream.
313*c8dee2aaSAndroid Build Coastguard Worker  *
314*c8dee2aaSAndroid Build Coastguard Worker  * The Draw's CompresssedPaintersOrder and DisjointStencilINdex represent the most significant bits
315*c8dee2aaSAndroid Build Coastguard Worker  * of the key, and are shared by all SortKeys produced by the same draw. Next, the pipeline
316*c8dee2aaSAndroid Build Coastguard Worker  * description is encoded in two steps:
317*c8dee2aaSAndroid Build Coastguard Worker  *  1. The index of the RenderStep packed in the high bits to ensure each step for a draw is
318*c8dee2aaSAndroid Build Coastguard Worker  *     ordered correctly.
319*c8dee2aaSAndroid Build Coastguard Worker  *  2. An index into a cache of pipeline descriptions is used to encode the identity of the
320*c8dee2aaSAndroid Build Coastguard Worker  *     pipeline (SortKeys that differ in the bits from #1 necessarily would have different
321*c8dee2aaSAndroid Build Coastguard Worker  *     descriptions, but then the specific ordering of the RenderSteps isn't enforced).
322*c8dee2aaSAndroid Build Coastguard Worker  * Last, the SortKey encodes an index into the set of uniform bindings accumulated for a DrawPass.
323*c8dee2aaSAndroid Build Coastguard Worker  * This allows the SortKey to cluster draw steps that have both a compatible pipeline and do not
324*c8dee2aaSAndroid Build Coastguard Worker  * require rebinding uniform data or other state (e.g. scissor). Since the uniform data index and
325*c8dee2aaSAndroid Build Coastguard Worker  * the pipeline description index are packed into indices and not actual pointers, a given SortKey
326*c8dee2aaSAndroid Build Coastguard Worker  * is only valid for the a specific DrawList->DrawPass conversion.
327*c8dee2aaSAndroid Build Coastguard Worker  */
328*c8dee2aaSAndroid Build Coastguard Worker class DrawPass::SortKey {
329*c8dee2aaSAndroid Build Coastguard Worker public:
SortKey(const DrawList::Draw * draw,int renderStep,GraphicsPipelineCache::Index pipelineIndex,UniformDataCache::Index geomUniformIndex,UniformDataCache::Index shadingUniformIndex,TextureBindingCache::Index textureBindingIndex)330*c8dee2aaSAndroid Build Coastguard Worker     SortKey(const DrawList::Draw* draw,
331*c8dee2aaSAndroid Build Coastguard Worker             int renderStep,
332*c8dee2aaSAndroid Build Coastguard Worker             GraphicsPipelineCache::Index pipelineIndex,
333*c8dee2aaSAndroid Build Coastguard Worker             UniformDataCache::Index geomUniformIndex,
334*c8dee2aaSAndroid Build Coastguard Worker             UniformDataCache::Index shadingUniformIndex,
335*c8dee2aaSAndroid Build Coastguard Worker             TextureBindingCache::Index textureBindingIndex)
336*c8dee2aaSAndroid Build Coastguard Worker         : fPipelineKey(ColorDepthOrderField::set(draw->fDrawParams.order().paintOrder().bits()) |
337*c8dee2aaSAndroid Build Coastguard Worker                        StencilIndexField::set(draw->fDrawParams.order().stencilIndex().bits())  |
338*c8dee2aaSAndroid Build Coastguard Worker                        RenderStepField::set(static_cast<uint32_t>(renderStep))                  |
339*c8dee2aaSAndroid Build Coastguard Worker                        PipelineField::set(pipelineIndex))
340*c8dee2aaSAndroid Build Coastguard Worker         , fUniformKey(GeometryUniformField::set(geomUniformIndex)   |
341*c8dee2aaSAndroid Build Coastguard Worker                       ShadingUniformField::set(shadingUniformIndex) |
342*c8dee2aaSAndroid Build Coastguard Worker                       TextureBindingsField::set(textureBindingIndex))
343*c8dee2aaSAndroid Build Coastguard Worker         , fDraw(draw) {
344*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(pipelineIndex < GraphicsPipelineCache::kInvalidIndex);
345*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(renderStep <= draw->fRenderer->numRenderSteps());
346*c8dee2aaSAndroid Build Coastguard Worker     }
347*c8dee2aaSAndroid Build Coastguard Worker 
operator <(const SortKey & k) const348*c8dee2aaSAndroid Build Coastguard Worker     bool operator<(const SortKey& k) const {
349*c8dee2aaSAndroid Build Coastguard Worker         return fPipelineKey < k.fPipelineKey ||
350*c8dee2aaSAndroid Build Coastguard Worker                (fPipelineKey == k.fPipelineKey && fUniformKey < k.fUniformKey);
351*c8dee2aaSAndroid Build Coastguard Worker     }
352*c8dee2aaSAndroid Build Coastguard Worker 
renderStep() const353*c8dee2aaSAndroid Build Coastguard Worker     const RenderStep& renderStep() const {
354*c8dee2aaSAndroid Build Coastguard Worker         return fDraw->fRenderer->step(RenderStepField::get(fPipelineKey));
355*c8dee2aaSAndroid Build Coastguard Worker     }
356*c8dee2aaSAndroid Build Coastguard Worker 
draw() const357*c8dee2aaSAndroid Build Coastguard Worker     const DrawList::Draw& draw() const { return *fDraw; }
358*c8dee2aaSAndroid Build Coastguard Worker 
pipelineIndex() const359*c8dee2aaSAndroid Build Coastguard Worker     GraphicsPipelineCache::Index pipelineIndex() const {
360*c8dee2aaSAndroid Build Coastguard Worker         return PipelineField::get(fPipelineKey);
361*c8dee2aaSAndroid Build Coastguard Worker     }
geometryUniformIndex() const362*c8dee2aaSAndroid Build Coastguard Worker     UniformDataCache::Index geometryUniformIndex() const {
363*c8dee2aaSAndroid Build Coastguard Worker         return GeometryUniformField::get(fUniformKey);
364*c8dee2aaSAndroid Build Coastguard Worker     }
shadingUniformIndex() const365*c8dee2aaSAndroid Build Coastguard Worker     UniformDataCache::Index shadingUniformIndex() const {
366*c8dee2aaSAndroid Build Coastguard Worker         return ShadingUniformField::get(fUniformKey);
367*c8dee2aaSAndroid Build Coastguard Worker     }
textureBindingIndex() const368*c8dee2aaSAndroid Build Coastguard Worker     TextureBindingCache::Index textureBindingIndex() const {
369*c8dee2aaSAndroid Build Coastguard Worker         return TextureBindingsField::get(fUniformKey);
370*c8dee2aaSAndroid Build Coastguard Worker     }
371*c8dee2aaSAndroid Build Coastguard Worker 
372*c8dee2aaSAndroid Build Coastguard Worker private:
373*c8dee2aaSAndroid Build Coastguard Worker     // Fields are ordered from most-significant to least when sorting by 128-bit value.
374*c8dee2aaSAndroid Build Coastguard Worker     // NOTE: We don't use C++ bit fields because field ordering is implementation defined and we
375*c8dee2aaSAndroid Build Coastguard Worker     // need to sort consistently.
376*c8dee2aaSAndroid Build Coastguard Worker     using ColorDepthOrderField = Bitfield<16, 48>; // sizeof(CompressedPaintersOrder)
377*c8dee2aaSAndroid Build Coastguard Worker     using StencilIndexField    = Bitfield<16, 32>; // sizeof(DisjointStencilIndex)
378*c8dee2aaSAndroid Build Coastguard Worker     using RenderStepField      = Bitfield<2,  30>; // bits >= log2(Renderer::kMaxRenderSteps)
379*c8dee2aaSAndroid Build Coastguard Worker     using PipelineField        = Bitfield<30, 0>;  // bits >= log2(max total steps in draw list)
380*c8dee2aaSAndroid Build Coastguard Worker     uint64_t fPipelineKey;
381*c8dee2aaSAndroid Build Coastguard Worker 
382*c8dee2aaSAndroid Build Coastguard Worker     // The uniform/texture index fields need 1 extra bit to encode "no-data". Values that are
383*c8dee2aaSAndroid Build Coastguard Worker     // greater than or equal to 2^(bits-1) represent "no-data", while values between
384*c8dee2aaSAndroid Build Coastguard Worker     // [0, 2^(bits-1)-1] can access data arrays without extra logic.
385*c8dee2aaSAndroid Build Coastguard Worker     using GeometryUniformField = Bitfield<17, 47>; // bits >= 1+log2(max total steps)
386*c8dee2aaSAndroid Build Coastguard Worker     using ShadingUniformField  = Bitfield<17, 30>; // bits >= 1+log2(max total steps)
387*c8dee2aaSAndroid Build Coastguard Worker     using TextureBindingsField = Bitfield<30, 0>;  // bits >= 1+log2(max total steps)
388*c8dee2aaSAndroid Build Coastguard Worker     uint64_t fUniformKey;
389*c8dee2aaSAndroid Build Coastguard Worker 
390*c8dee2aaSAndroid Build Coastguard Worker     // Backpointer to the draw that produced the sort key
391*c8dee2aaSAndroid Build Coastguard Worker     const DrawList::Draw* fDraw;
392*c8dee2aaSAndroid Build Coastguard Worker 
393*c8dee2aaSAndroid Build Coastguard Worker     static_assert(ColorDepthOrderField::kBits >= sizeof(CompressedPaintersOrder));
394*c8dee2aaSAndroid Build Coastguard Worker     static_assert(StencilIndexField::kBits    >= sizeof(DisjointStencilIndex));
395*c8dee2aaSAndroid Build Coastguard Worker     static_assert(RenderStepField::kBits      >= SkNextLog2_portable(Renderer::kMaxRenderSteps));
396*c8dee2aaSAndroid Build Coastguard Worker     static_assert(PipelineField::kBits        >= SkNextLog2_portable(DrawList::kMaxRenderSteps));
397*c8dee2aaSAndroid Build Coastguard Worker     static_assert(GeometryUniformField::kBits >= 1+SkNextLog2_portable(DrawList::kMaxRenderSteps));
398*c8dee2aaSAndroid Build Coastguard Worker     static_assert(ShadingUniformField::kBits  >= 1+SkNextLog2_portable(DrawList::kMaxRenderSteps));
399*c8dee2aaSAndroid Build Coastguard Worker     static_assert(TextureBindingsField::kBits >= 1+SkNextLog2_portable(DrawList::kMaxRenderSteps));
400*c8dee2aaSAndroid Build Coastguard Worker };
401*c8dee2aaSAndroid Build Coastguard Worker 
402*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
403*c8dee2aaSAndroid Build Coastguard Worker 
DrawPass(sk_sp<TextureProxy> target,std::pair<LoadOp,StoreOp> ops,std::array<float,4> clearColor)404*c8dee2aaSAndroid Build Coastguard Worker DrawPass::DrawPass(sk_sp<TextureProxy> target,
405*c8dee2aaSAndroid Build Coastguard Worker                    std::pair<LoadOp, StoreOp> ops,
406*c8dee2aaSAndroid Build Coastguard Worker                    std::array<float, 4> clearColor)
407*c8dee2aaSAndroid Build Coastguard Worker         : fTarget(std::move(target))
408*c8dee2aaSAndroid Build Coastguard Worker         , fBounds(SkIRect::MakeEmpty())
409*c8dee2aaSAndroid Build Coastguard Worker         , fOps(ops)
410*c8dee2aaSAndroid Build Coastguard Worker         , fClearColor(clearColor) {}
411*c8dee2aaSAndroid Build Coastguard Worker 
412*c8dee2aaSAndroid Build Coastguard Worker DrawPass::~DrawPass() = default;
413*c8dee2aaSAndroid Build Coastguard Worker 
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)414*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<DrawPass> DrawPass::Make(Recorder* recorder,
415*c8dee2aaSAndroid Build Coastguard Worker                                          std::unique_ptr<DrawList> draws,
416*c8dee2aaSAndroid Build Coastguard Worker                                          sk_sp<TextureProxy> target,
417*c8dee2aaSAndroid Build Coastguard Worker                                          const SkImageInfo& targetInfo,
418*c8dee2aaSAndroid Build Coastguard Worker                                          std::pair<LoadOp, StoreOp> ops,
419*c8dee2aaSAndroid Build Coastguard Worker                                          std::array<float, 4> clearColor) {
420*c8dee2aaSAndroid Build Coastguard Worker     // NOTE: This assert is here to ensure SortKey is as tightly packed as possible. Any change to
421*c8dee2aaSAndroid Build Coastguard Worker     // its size should be done with care and good reason. The performance of sorting the keys is
422*c8dee2aaSAndroid Build Coastguard Worker     // heavily tied to the total size.
423*c8dee2aaSAndroid Build Coastguard Worker     //
424*c8dee2aaSAndroid Build Coastguard Worker     // At 24 bytes (current), sorting is about 30% slower than if SortKey could be packed into just
425*c8dee2aaSAndroid Build Coastguard Worker     // 16 bytes. There are several ways this could be done if necessary:
426*c8dee2aaSAndroid Build Coastguard Worker     //  - Restricting the max draw count to 16k (14-bits) and only using a single index to refer to
427*c8dee2aaSAndroid Build Coastguard Worker     //    the uniform data => 8 bytes of key, 8 bytes of pointer.
428*c8dee2aaSAndroid Build Coastguard Worker     //  - Restrict the max draw count to 32k (15-bits), use a single uniform index, and steal the
429*c8dee2aaSAndroid Build Coastguard Worker     //    4 low bits from the Draw* pointer since it's 16 byte aligned.
430*c8dee2aaSAndroid Build Coastguard Worker     //  - Compact the Draw* to an index into the original collection, although that has extra
431*c8dee2aaSAndroid Build Coastguard Worker     //    indirection and does not work as well with SkTBlockList.
432*c8dee2aaSAndroid Build Coastguard Worker     // In pseudo tests, manipulating the pointer or having to mask out indices was about 15% slower
433*c8dee2aaSAndroid Build Coastguard Worker     // than an 8 byte key and unmodified pointer.
434*c8dee2aaSAndroid Build Coastguard Worker     static_assert(sizeof(DrawPass::SortKey) ==
435*c8dee2aaSAndroid Build Coastguard Worker                   SkAlignTo(16 + sizeof(void*), alignof(DrawPass::SortKey)));
436*c8dee2aaSAndroid Build Coastguard Worker 
437*c8dee2aaSAndroid Build Coastguard Worker     TRACE_EVENT1("skia.gpu", TRACE_FUNC, "draw count", draws->fDraws.count());
438*c8dee2aaSAndroid Build Coastguard Worker 
439*c8dee2aaSAndroid Build Coastguard Worker     // The DrawList is converted directly into the DrawPass' data structures, but once the DrawPass
440*c8dee2aaSAndroid Build Coastguard Worker     // is returned from Make(), it is considered immutable.
441*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<DrawPass> drawPass(new DrawPass(target, ops, clearColor));
442*c8dee2aaSAndroid Build Coastguard Worker 
443*c8dee2aaSAndroid Build Coastguard Worker     Rect passBounds = Rect::InfiniteInverted();
444*c8dee2aaSAndroid Build Coastguard Worker 
445*c8dee2aaSAndroid Build Coastguard Worker     UniformDataCache geometryUniformDataCache;
446*c8dee2aaSAndroid Build Coastguard Worker     UniformDataCache shadingUniformDataCache;
447*c8dee2aaSAndroid Build Coastguard Worker     TextureDataCache* textureDataCache = recorder->priv().textureDataCache();
448*c8dee2aaSAndroid Build Coastguard Worker     DrawBufferManager* bufferMgr = recorder->priv().drawBufferManager();
449*c8dee2aaSAndroid Build Coastguard Worker     if (bufferMgr->hasMappingFailed()) {
450*c8dee2aaSAndroid Build Coastguard Worker         SKGPU_LOG_W("Buffer mapping has already failed; dropping draw pass!");
451*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
452*c8dee2aaSAndroid Build Coastguard Worker     }
453*c8dee2aaSAndroid Build Coastguard Worker 
454*c8dee2aaSAndroid Build Coastguard Worker     GraphicsPipelineCache pipelineCache;
455*c8dee2aaSAndroid Build Coastguard Worker 
456*c8dee2aaSAndroid Build Coastguard Worker     // Geometry uniforms are currently always UBO-backed.
457*c8dee2aaSAndroid Build Coastguard Worker     const bool useStorageBuffers = recorder->priv().caps()->storageBufferSupport();
458*c8dee2aaSAndroid Build Coastguard Worker     const ResourceBindingRequirements& bindingReqs =
459*c8dee2aaSAndroid Build Coastguard Worker             recorder->priv().caps()->resourceBindingRequirements();
460*c8dee2aaSAndroid Build Coastguard Worker     Layout uniformLayout =
461*c8dee2aaSAndroid Build Coastguard Worker             useStorageBuffers ? bindingReqs.fStorageBufferLayout : bindingReqs.fUniformBufferLayout;
462*c8dee2aaSAndroid Build Coastguard Worker 
463*c8dee2aaSAndroid Build Coastguard Worker     TextureBindingTracker textureBindingTracker;
464*c8dee2aaSAndroid Build Coastguard Worker     GradientBufferTracker gradientBufferTracker;
465*c8dee2aaSAndroid Build Coastguard Worker 
466*c8dee2aaSAndroid Build Coastguard Worker     ShaderCodeDictionary* dict = recorder->priv().shaderCodeDictionary();
467*c8dee2aaSAndroid Build Coastguard Worker     PaintParamsKeyBuilder builder(dict);
468*c8dee2aaSAndroid Build Coastguard Worker 
469*c8dee2aaSAndroid Build Coastguard Worker     // The initial layout we pass here is not important as it will be re-assigned when writing
470*c8dee2aaSAndroid Build Coastguard Worker     // shading and geometry uniforms below.
471*c8dee2aaSAndroid Build Coastguard Worker     PipelineDataGatherer gatherer(uniformLayout);
472*c8dee2aaSAndroid Build Coastguard Worker 
473*c8dee2aaSAndroid Build Coastguard Worker     std::vector<SortKey> keys;
474*c8dee2aaSAndroid Build Coastguard Worker     keys.reserve(draws->renderStepCount());
475*c8dee2aaSAndroid Build Coastguard Worker 
476*c8dee2aaSAndroid Build Coastguard Worker     for (const DrawList::Draw& draw : draws->fDraws.items()) {
477*c8dee2aaSAndroid Build Coastguard Worker         // If we have two different descriptors, such that the uniforms from the PaintParams can be
478*c8dee2aaSAndroid Build Coastguard Worker         // bound independently of those used by the rest of the RenderStep, then we can upload now
479*c8dee2aaSAndroid Build Coastguard Worker         // and remember the location for re-use on any RenderStep that does shading.
480*c8dee2aaSAndroid Build Coastguard Worker         UniquePaintParamsID shaderID;
481*c8dee2aaSAndroid Build Coastguard Worker         UniformDataCache::Index shadingUniformIndex = UniformDataCache::kInvalidIndex;
482*c8dee2aaSAndroid Build Coastguard Worker         TextureDataBlock paintTextures;
483*c8dee2aaSAndroid Build Coastguard Worker 
484*c8dee2aaSAndroid Build Coastguard Worker         if (draw.fPaintParams.has_value()) {
485*c8dee2aaSAndroid Build Coastguard Worker             shaderID = ExtractPaintData(recorder,
486*c8dee2aaSAndroid Build Coastguard Worker                                         &gatherer,
487*c8dee2aaSAndroid Build Coastguard Worker                                         &builder,
488*c8dee2aaSAndroid Build Coastguard Worker                                         uniformLayout,
489*c8dee2aaSAndroid Build Coastguard Worker                                         draw.fDrawParams.transform(),
490*c8dee2aaSAndroid Build Coastguard Worker                                         draw.fPaintParams.value(),
491*c8dee2aaSAndroid Build Coastguard Worker                                         draw.fDrawParams.geometry(),
492*c8dee2aaSAndroid Build Coastguard Worker                                         targetInfo.colorInfo());
493*c8dee2aaSAndroid Build Coastguard Worker 
494*c8dee2aaSAndroid Build Coastguard Worker             if (shaderID.isValid()) {
495*c8dee2aaSAndroid Build Coastguard Worker                 if (gatherer.hasUniforms()) {
496*c8dee2aaSAndroid Build Coastguard Worker                     shadingUniformIndex =
497*c8dee2aaSAndroid Build Coastguard Worker                             shadingUniformDataCache.insert(gatherer.finishUniformDataBlock());
498*c8dee2aaSAndroid Build Coastguard Worker                 }
499*c8dee2aaSAndroid Build Coastguard Worker                 if (gatherer.hasTextures()) {
500*c8dee2aaSAndroid Build Coastguard Worker                     paintTextures = textureDataCache->insert(gatherer.textureDataBlock());
501*c8dee2aaSAndroid Build Coastguard Worker                 }
502*c8dee2aaSAndroid Build Coastguard Worker             }
503*c8dee2aaSAndroid Build Coastguard Worker         } // else depth-only
504*c8dee2aaSAndroid Build Coastguard Worker 
505*c8dee2aaSAndroid Build Coastguard Worker         // Create a sort key for every render step in this draw, extracting out any
506*c8dee2aaSAndroid Build Coastguard Worker         // RenderStep-specific data.
507*c8dee2aaSAndroid Build Coastguard Worker         for (int stepIndex = 0; stepIndex < draw.fRenderer->numRenderSteps(); ++stepIndex) {
508*c8dee2aaSAndroid Build Coastguard Worker             const RenderStep* const step = draw.fRenderer->steps()[stepIndex];
509*c8dee2aaSAndroid Build Coastguard Worker             const bool performsShading = draw.fPaintParams.has_value() && step->performsShading();
510*c8dee2aaSAndroid Build Coastguard Worker 
511*c8dee2aaSAndroid Build Coastguard Worker             GraphicsPipelineCache::Index pipelineIndex = pipelineCache.insert(
512*c8dee2aaSAndroid Build Coastguard Worker                     {step, performsShading ? shaderID : UniquePaintParamsID::InvalidID()});
513*c8dee2aaSAndroid Build Coastguard Worker 
514*c8dee2aaSAndroid Build Coastguard Worker             gatherer.resetWithNewLayout(uniformLayout);
515*c8dee2aaSAndroid Build Coastguard Worker             step->writeUniformsAndTextures(draw.fDrawParams, &gatherer);
516*c8dee2aaSAndroid Build Coastguard Worker 
517*c8dee2aaSAndroid Build Coastguard Worker             UniformDataCache::Index geomUniformIndex =
518*c8dee2aaSAndroid Build Coastguard Worker                     gatherer.hasUniforms()
519*c8dee2aaSAndroid Build Coastguard Worker                             ? geometryUniformDataCache.insert(gatherer.finishUniformDataBlock())
520*c8dee2aaSAndroid Build Coastguard Worker                             : UniformDataCache::kInvalidIndex;
521*c8dee2aaSAndroid Build Coastguard Worker 
522*c8dee2aaSAndroid Build Coastguard Worker             TextureDataBlock stepTextures =
523*c8dee2aaSAndroid Build Coastguard Worker                     gatherer.hasTextures() ? textureDataCache->insert(gatherer.textureDataBlock())
524*c8dee2aaSAndroid Build Coastguard Worker                                            : TextureDataBlock();
525*c8dee2aaSAndroid Build Coastguard Worker             TextureBindingCache::Index textureIndex = textureBindingTracker.trackTextures(
526*c8dee2aaSAndroid Build Coastguard Worker                     performsShading ? paintTextures : TextureDataBlock(), stepTextures);
527*c8dee2aaSAndroid Build Coastguard Worker 
528*c8dee2aaSAndroid Build Coastguard Worker             keys.push_back({&draw, stepIndex, pipelineIndex,
529*c8dee2aaSAndroid Build Coastguard Worker                             geomUniformIndex, shadingUniformIndex, textureIndex});
530*c8dee2aaSAndroid Build Coastguard Worker         }
531*c8dee2aaSAndroid Build Coastguard Worker 
532*c8dee2aaSAndroid Build Coastguard Worker         passBounds.join(draw.fDrawParams.clip().drawBounds());
533*c8dee2aaSAndroid Build Coastguard Worker         drawPass->fDepthStencilFlags |= draw.fRenderer->depthStencilFlags();
534*c8dee2aaSAndroid Build Coastguard Worker         drawPass->fRequiresMSAA |= draw.fRenderer->requiresMSAA();
535*c8dee2aaSAndroid Build Coastguard Worker     }
536*c8dee2aaSAndroid Build Coastguard Worker 
537*c8dee2aaSAndroid Build Coastguard Worker     if (!gradientBufferTracker.writeData(gatherer.gradientBufferData(), bufferMgr)) {
538*c8dee2aaSAndroid Build Coastguard Worker         // The necessary uniform data couldn't be written to the GPU, so the DrawPass is invalid.
539*c8dee2aaSAndroid Build Coastguard Worker         // Early out now since the next Recording snap will fail.
540*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
541*c8dee2aaSAndroid Build Coastguard Worker     }
542*c8dee2aaSAndroid Build Coastguard Worker 
543*c8dee2aaSAndroid Build Coastguard Worker     // TODO: Explore sorting algorithms; in all likelihood this will be mostly sorted already, so
544*c8dee2aaSAndroid Build Coastguard Worker     // algorithms that approach O(n) in that condition may be favorable. Alternatively, could
545*c8dee2aaSAndroid Build Coastguard Worker     // explore radix sort that is always O(n). Brief testing suggested std::sort was faster than
546*c8dee2aaSAndroid Build Coastguard Worker     // std::stable_sort and SkTQSort on my [ml]'s Windows desktop. Also worth considering in-place
547*c8dee2aaSAndroid Build Coastguard Worker     // vs. algorithms that require an extra O(n) storage.
548*c8dee2aaSAndroid Build Coastguard Worker     // TODO: It's not strictly necessary, but would a stable sort be useful or just end up hiding
549*c8dee2aaSAndroid Build Coastguard Worker     // bugs in the DrawOrder determination code?
550*c8dee2aaSAndroid Build Coastguard Worker     std::sort(keys.begin(), keys.end());
551*c8dee2aaSAndroid Build Coastguard Worker 
552*c8dee2aaSAndroid Build Coastguard Worker     // Used to record vertex/instance data, buffer binds, and draw calls
553*c8dee2aaSAndroid Build Coastguard Worker     DrawWriter drawWriter(&drawPass->fCommandList, bufferMgr);
554*c8dee2aaSAndroid Build Coastguard Worker     GraphicsPipelineCache::Index lastPipeline = GraphicsPipelineCache::kInvalidIndex;
555*c8dee2aaSAndroid Build Coastguard Worker     SkIRect lastScissor = SkIRect::MakeSize(targetInfo.dimensions());
556*c8dee2aaSAndroid Build Coastguard Worker 
557*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(drawPass->fTarget->isFullyLazy() ||
558*c8dee2aaSAndroid Build Coastguard Worker              SkIRect::MakeSize(drawPass->fTarget->dimensions()).contains(lastScissor));
559*c8dee2aaSAndroid Build Coastguard Worker     drawPass->fCommandList.setScissor(lastScissor);
560*c8dee2aaSAndroid Build Coastguard Worker 
561*c8dee2aaSAndroid Build Coastguard Worker     // All large gradients pack their data into a single buffer throughout the draw pass,
562*c8dee2aaSAndroid Build Coastguard Worker     // therefore the gradient buffer only needs to be bound once.
563*c8dee2aaSAndroid Build Coastguard Worker     gradientBufferTracker.bindIfNeeded(&drawPass->fCommandList);
564*c8dee2aaSAndroid Build Coastguard Worker 
565*c8dee2aaSAndroid Build Coastguard Worker     UniformTracker geometryUniformTracker(useStorageBuffers);
566*c8dee2aaSAndroid Build Coastguard Worker     UniformTracker shadingUniformTracker(useStorageBuffers);
567*c8dee2aaSAndroid Build Coastguard Worker 
568*c8dee2aaSAndroid Build Coastguard Worker     // TODO(b/372953722): Remove this forced binding command behavior once dst copies are always
569*c8dee2aaSAndroid Build Coastguard Worker     // bound separately from the rest of the textures.
570*c8dee2aaSAndroid Build Coastguard Worker     const bool rebindTexturesOnPipelineChange =
571*c8dee2aaSAndroid Build Coastguard Worker             recorder->priv().caps()->getDstReadRequirement() == DstReadRequirement::kTextureCopy;
572*c8dee2aaSAndroid Build Coastguard Worker 
573*c8dee2aaSAndroid Build Coastguard Worker     for (const SortKey& key : keys) {
574*c8dee2aaSAndroid Build Coastguard Worker         const DrawList::Draw& draw = key.draw();
575*c8dee2aaSAndroid Build Coastguard Worker         const RenderStep& renderStep = key.renderStep();
576*c8dee2aaSAndroid Build Coastguard Worker 
577*c8dee2aaSAndroid Build Coastguard Worker         const bool pipelineChange = key.pipelineIndex() != lastPipeline;
578*c8dee2aaSAndroid Build Coastguard Worker 
579*c8dee2aaSAndroid Build Coastguard Worker         const bool geomBindingChange = geometryUniformTracker.writeUniforms(
580*c8dee2aaSAndroid Build Coastguard Worker                 geometryUniformDataCache, bufferMgr, key.geometryUniformIndex());
581*c8dee2aaSAndroid Build Coastguard Worker         const bool shadingBindingChange = shadingUniformTracker.writeUniforms(
582*c8dee2aaSAndroid Build Coastguard Worker                 shadingUniformDataCache, bufferMgr, key.shadingUniformIndex());
583*c8dee2aaSAndroid Build Coastguard Worker 
584*c8dee2aaSAndroid Build Coastguard Worker         // TODO(b/372953722): The Dawn and Vulkan CommandBuffer implementations currently append any
585*c8dee2aaSAndroid Build Coastguard Worker         // dst copy to the texture bind group/descriptor set automatically when processing a
586*c8dee2aaSAndroid Build Coastguard Worker         // BindTexturesAndSamplers call because they use a single group to contain all textures.
587*c8dee2aaSAndroid Build Coastguard Worker         // However, from the DrawPass POV, we can run into the scenario where two pipelines have the
588*c8dee2aaSAndroid Build Coastguard Worker         // same textures+samplers except one requires a dst-copy and the other does not. In this
589*c8dee2aaSAndroid Build Coastguard Worker         // case we wouldn't necessarily insert a new command when the pipeline changed and then
590*c8dee2aaSAndroid Build Coastguard Worker         // end up with layout validation errors.
591*c8dee2aaSAndroid Build Coastguard Worker         const bool textureBindingsChange = textureBindingTracker.setCurrentTextureBindings(
592*c8dee2aaSAndroid Build Coastguard Worker                 key.textureBindingIndex()) ||
593*c8dee2aaSAndroid Build Coastguard Worker                 (rebindTexturesOnPipelineChange && pipelineChange &&
594*c8dee2aaSAndroid Build Coastguard Worker                  key.textureBindingIndex() != TextureBindingCache::kInvalidIndex);
595*c8dee2aaSAndroid Build Coastguard Worker         const SkIRect* newScissor        = draw.fDrawParams.clip().scissor() != lastScissor ?
596*c8dee2aaSAndroid Build Coastguard Worker                 &draw.fDrawParams.clip().scissor() : nullptr;
597*c8dee2aaSAndroid Build Coastguard Worker 
598*c8dee2aaSAndroid Build Coastguard Worker         const bool stateChange = geomBindingChange ||
599*c8dee2aaSAndroid Build Coastguard Worker                                  shadingBindingChange ||
600*c8dee2aaSAndroid Build Coastguard Worker                                  textureBindingsChange ||
601*c8dee2aaSAndroid Build Coastguard Worker                                  SkToBool(newScissor);
602*c8dee2aaSAndroid Build Coastguard Worker 
603*c8dee2aaSAndroid Build Coastguard Worker         // Update DrawWriter *before* we actually change any state so that accumulated draws from
604*c8dee2aaSAndroid Build Coastguard Worker         // the previous state use the proper state.
605*c8dee2aaSAndroid Build Coastguard Worker         if (pipelineChange) {
606*c8dee2aaSAndroid Build Coastguard Worker             drawWriter.newPipelineState(renderStep.primitiveType(),
607*c8dee2aaSAndroid Build Coastguard Worker                                         renderStep.vertexStride(),
608*c8dee2aaSAndroid Build Coastguard Worker                                         renderStep.instanceStride());
609*c8dee2aaSAndroid Build Coastguard Worker         } else if (stateChange) {
610*c8dee2aaSAndroid Build Coastguard Worker             drawWriter.newDynamicState();
611*c8dee2aaSAndroid Build Coastguard Worker         }
612*c8dee2aaSAndroid Build Coastguard Worker 
613*c8dee2aaSAndroid Build Coastguard Worker         // Make state changes before accumulating new draw data
614*c8dee2aaSAndroid Build Coastguard Worker         if (pipelineChange) {
615*c8dee2aaSAndroid Build Coastguard Worker             drawPass->fCommandList.bindGraphicsPipeline(key.pipelineIndex());
616*c8dee2aaSAndroid Build Coastguard Worker             lastPipeline = key.pipelineIndex();
617*c8dee2aaSAndroid Build Coastguard Worker         }
618*c8dee2aaSAndroid Build Coastguard Worker         if (stateChange) {
619*c8dee2aaSAndroid Build Coastguard Worker             if (geomBindingChange) {
620*c8dee2aaSAndroid Build Coastguard Worker                 geometryUniformTracker.bindUniforms(UniformSlot::kRenderStep,
621*c8dee2aaSAndroid Build Coastguard Worker                                                     &drawPass->fCommandList);
622*c8dee2aaSAndroid Build Coastguard Worker             }
623*c8dee2aaSAndroid Build Coastguard Worker             if (shadingBindingChange) {
624*c8dee2aaSAndroid Build Coastguard Worker                 shadingUniformTracker.bindUniforms(UniformSlot::kPaint, &drawPass->fCommandList);
625*c8dee2aaSAndroid Build Coastguard Worker             }
626*c8dee2aaSAndroid Build Coastguard Worker             if (textureBindingsChange) {
627*c8dee2aaSAndroid Build Coastguard Worker                 textureBindingTracker.bindTextures(&drawPass->fCommandList);
628*c8dee2aaSAndroid Build Coastguard Worker             }
629*c8dee2aaSAndroid Build Coastguard Worker             if (newScissor) {
630*c8dee2aaSAndroid Build Coastguard Worker                 drawPass->fCommandList.setScissor(*newScissor);
631*c8dee2aaSAndroid Build Coastguard Worker                 lastScissor = *newScissor;
632*c8dee2aaSAndroid Build Coastguard Worker             }
633*c8dee2aaSAndroid Build Coastguard Worker         }
634*c8dee2aaSAndroid Build Coastguard Worker 
635*c8dee2aaSAndroid Build Coastguard Worker         uint32_t geometrySsboIndex = useStorageBuffers ? geometryUniformTracker.ssboIndex() : 0;
636*c8dee2aaSAndroid Build Coastguard Worker         uint32_t shadingSsboIndex = useStorageBuffers ? shadingUniformTracker.ssboIndex() : 0;
637*c8dee2aaSAndroid Build Coastguard Worker         skvx::uint2 ssboIndices = {geometrySsboIndex, shadingSsboIndex};
638*c8dee2aaSAndroid Build Coastguard Worker         renderStep.writeVertices(&drawWriter, draw.fDrawParams, ssboIndices);
639*c8dee2aaSAndroid Build Coastguard Worker 
640*c8dee2aaSAndroid Build Coastguard Worker         if (bufferMgr->hasMappingFailed()) {
641*c8dee2aaSAndroid Build Coastguard Worker             SKGPU_LOG_W("Failed to write necessary vertex/instance data for DrawPass, dropping!");
642*c8dee2aaSAndroid Build Coastguard Worker             return nullptr;
643*c8dee2aaSAndroid Build Coastguard Worker         }
644*c8dee2aaSAndroid Build Coastguard Worker     }
645*c8dee2aaSAndroid Build Coastguard Worker     // Finish recording draw calls for any collected data at the end of the loop
646*c8dee2aaSAndroid Build Coastguard Worker     drawWriter.flush();
647*c8dee2aaSAndroid Build Coastguard Worker 
648*c8dee2aaSAndroid Build Coastguard Worker     drawPass->fBounds = passBounds.roundOut().asSkIRect();
649*c8dee2aaSAndroid Build Coastguard Worker 
650*c8dee2aaSAndroid Build Coastguard Worker     drawPass->fPipelineDescs   = pipelineCache.detach();
651*c8dee2aaSAndroid Build Coastguard Worker     drawPass->fSamplerDescs    = textureBindingTracker.detachSamplers();
652*c8dee2aaSAndroid Build Coastguard Worker     drawPass->fSampledTextures = textureBindingTracker.detachTextures();
653*c8dee2aaSAndroid Build Coastguard Worker 
654*c8dee2aaSAndroid Build Coastguard Worker     TRACE_COUNTER1("skia.gpu", "# pipelines", drawPass->fPipelineDescs.size());
655*c8dee2aaSAndroid Build Coastguard Worker     TRACE_COUNTER1("skia.gpu", "# textures", drawPass->fSampledTextures.size());
656*c8dee2aaSAndroid Build Coastguard Worker     TRACE_COUNTER1("skia.gpu", "# commands", drawPass->fCommandList.count());
657*c8dee2aaSAndroid Build Coastguard Worker 
658*c8dee2aaSAndroid Build Coastguard Worker     return drawPass;
659*c8dee2aaSAndroid Build Coastguard Worker }
660*c8dee2aaSAndroid Build Coastguard Worker 
prepareResources(ResourceProvider * resourceProvider,const RuntimeEffectDictionary * runtimeDict,const RenderPassDesc & renderPassDesc)661*c8dee2aaSAndroid Build Coastguard Worker bool DrawPass::prepareResources(ResourceProvider* resourceProvider,
662*c8dee2aaSAndroid Build Coastguard Worker                                 const RuntimeEffectDictionary* runtimeDict,
663*c8dee2aaSAndroid Build Coastguard Worker                                 const RenderPassDesc& renderPassDesc) {
664*c8dee2aaSAndroid Build Coastguard Worker     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
665*c8dee2aaSAndroid Build Coastguard Worker 
666*c8dee2aaSAndroid Build Coastguard Worker     fFullPipelines.reserve(fFullPipelines.size() + fPipelineDescs.size());
667*c8dee2aaSAndroid Build Coastguard Worker     for (const GraphicsPipelineDesc& pipelineDesc : fPipelineDescs) {
668*c8dee2aaSAndroid Build Coastguard Worker         auto pipeline = resourceProvider->findOrCreateGraphicsPipeline(runtimeDict,
669*c8dee2aaSAndroid Build Coastguard Worker                                                                        pipelineDesc,
670*c8dee2aaSAndroid Build Coastguard Worker                                                                        renderPassDesc);
671*c8dee2aaSAndroid Build Coastguard Worker         if (!pipeline) {
672*c8dee2aaSAndroid Build Coastguard Worker             SKGPU_LOG_W("Failed to create GraphicsPipeline for draw in RenderPass. Dropping pass!");
673*c8dee2aaSAndroid Build Coastguard Worker             return false;
674*c8dee2aaSAndroid Build Coastguard Worker         }
675*c8dee2aaSAndroid Build Coastguard Worker         fFullPipelines.push_back(std::move(pipeline));
676*c8dee2aaSAndroid Build Coastguard Worker     }
677*c8dee2aaSAndroid Build Coastguard Worker     // The DrawPass may be long lived on a Recording and we no longer need the GraphicPipelineDescs
678*c8dee2aaSAndroid Build Coastguard Worker     // once we've created pipelines, so we drop the storage for them here.
679*c8dee2aaSAndroid Build Coastguard Worker     fPipelineDescs.clear();
680*c8dee2aaSAndroid Build Coastguard Worker 
681*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG)
682*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < fSampledTextures.size(); ++i) {
683*c8dee2aaSAndroid Build Coastguard Worker         // It should not have been possible to draw an Image that has an invalid texture info
684*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fSampledTextures[i]->textureInfo().isValid());
685*c8dee2aaSAndroid Build Coastguard Worker         // Tasks should have been ordered to instantiate any scratch textures already, or any
686*c8dee2aaSAndroid Build Coastguard Worker         // client-owned image will have been instantiated at creation.
687*c8dee2aaSAndroid Build Coastguard Worker         SkASSERTF(fSampledTextures[i]->isInstantiated() ||
688*c8dee2aaSAndroid Build Coastguard Worker                   fSampledTextures[i]->isLazy(),
689*c8dee2aaSAndroid Build Coastguard Worker                   "proxy label = %s", fSampledTextures[i]->label());
690*c8dee2aaSAndroid Build Coastguard Worker     }
691*c8dee2aaSAndroid Build Coastguard Worker #endif
692*c8dee2aaSAndroid Build Coastguard Worker 
693*c8dee2aaSAndroid Build Coastguard Worker     fSamplers.reserve(fSamplers.size() + fSamplerDescs.size());
694*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < fSamplerDescs.size(); ++i) {
695*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<Sampler> sampler = resourceProvider->findOrCreateCompatibleSampler(fSamplerDescs[i]);
696*c8dee2aaSAndroid Build Coastguard Worker         if (!sampler) {
697*c8dee2aaSAndroid Build Coastguard Worker             SKGPU_LOG_W("Failed to create sampler. Will not create renderpass!");
698*c8dee2aaSAndroid Build Coastguard Worker             return false;
699*c8dee2aaSAndroid Build Coastguard Worker         }
700*c8dee2aaSAndroid Build Coastguard Worker         fSamplers.push_back(std::move(sampler));
701*c8dee2aaSAndroid Build Coastguard Worker     }
702*c8dee2aaSAndroid Build Coastguard Worker     // The DrawPass may be long lived on a Recording and we no longer need the SamplerDescs
703*c8dee2aaSAndroid Build Coastguard Worker     // once we've created Samplers, so we drop the storage for them here.
704*c8dee2aaSAndroid Build Coastguard Worker     fSamplerDescs.clear();
705*c8dee2aaSAndroid Build Coastguard Worker 
706*c8dee2aaSAndroid Build Coastguard Worker     return true;
707*c8dee2aaSAndroid Build Coastguard Worker }
708*c8dee2aaSAndroid Build Coastguard Worker 
addResourceRefs(CommandBuffer * commandBuffer) const709*c8dee2aaSAndroid Build Coastguard Worker void DrawPass::addResourceRefs(CommandBuffer* commandBuffer) const {
710*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < fFullPipelines.size(); ++i) {
711*c8dee2aaSAndroid Build Coastguard Worker         commandBuffer->trackResource(fFullPipelines[i]);
712*c8dee2aaSAndroid Build Coastguard Worker     }
713*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < fSampledTextures.size(); ++i) {
714*c8dee2aaSAndroid Build Coastguard Worker         commandBuffer->trackCommandBufferResource(fSampledTextures[i]->refTexture());
715*c8dee2aaSAndroid Build Coastguard Worker     }
716*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < fSamplers.size(); ++i) {
717*c8dee2aaSAndroid Build Coastguard Worker         commandBuffer->trackResource(fSamplers[i]);
718*c8dee2aaSAndroid Build Coastguard Worker     }
719*c8dee2aaSAndroid Build Coastguard Worker }
720*c8dee2aaSAndroid Build Coastguard Worker 
getTexture(size_t index) const721*c8dee2aaSAndroid Build Coastguard Worker const Texture* DrawPass::getTexture(size_t index) const {
722*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(index < SkToSizeT(fSampledTextures.size()));
723*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fSampledTextures[index]);
724*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fSampledTextures[index]->texture());
725*c8dee2aaSAndroid Build Coastguard Worker     return fSampledTextures[index]->texture();
726*c8dee2aaSAndroid Build Coastguard Worker }
getSampler(size_t index) const727*c8dee2aaSAndroid Build Coastguard Worker const Sampler* DrawPass::getSampler(size_t index) const {
728*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(index < SkToSizeT(fSamplers.size()));
729*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fSamplers[index]);
730*c8dee2aaSAndroid Build Coastguard Worker     return fSamplers[index].get();
731*c8dee2aaSAndroid Build Coastguard Worker }
732*c8dee2aaSAndroid Build Coastguard Worker 
733*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
734