xref: /aosp_15_r20/external/skia/src/gpu/graphite/task/UploadTask.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2022 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/task/UploadTask.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.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/SkAutoPixmapStorage.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkCompressedDataUtils.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMipmap.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTraceEvent.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/DataUtils.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Buffer.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Caps.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/CommandBuffer.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Log.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RecorderPriv.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ResourceProvider.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Texture.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/TextureProxy.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/UploadBufferManager.h"
27*c8dee2aaSAndroid Build Coastguard Worker 
28*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
29*c8dee2aaSAndroid Build Coastguard Worker 
30*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker UploadInstance::UploadInstance() = default;
33*c8dee2aaSAndroid Build Coastguard Worker UploadInstance::UploadInstance(UploadInstance&&) = default;
34*c8dee2aaSAndroid Build Coastguard Worker UploadInstance& UploadInstance::operator=(UploadInstance&&) = default;
35*c8dee2aaSAndroid Build Coastguard Worker UploadInstance::~UploadInstance() = default;
36*c8dee2aaSAndroid Build Coastguard Worker 
UploadInstance(const Buffer * buffer,size_t bytesPerPixel,sk_sp<TextureProxy> textureProxy,std::unique_ptr<ConditionalUploadContext> condContext)37*c8dee2aaSAndroid Build Coastguard Worker UploadInstance::UploadInstance(const Buffer* buffer,
38*c8dee2aaSAndroid Build Coastguard Worker                                size_t bytesPerPixel,
39*c8dee2aaSAndroid Build Coastguard Worker                                sk_sp<TextureProxy> textureProxy,
40*c8dee2aaSAndroid Build Coastguard Worker                                std::unique_ptr<ConditionalUploadContext> condContext)
41*c8dee2aaSAndroid Build Coastguard Worker         : fBuffer(buffer)
42*c8dee2aaSAndroid Build Coastguard Worker         , fBytesPerPixel(bytesPerPixel)
43*c8dee2aaSAndroid Build Coastguard Worker         , fTextureProxy(textureProxy)
44*c8dee2aaSAndroid Build Coastguard Worker         , fConditionalContext(std::move(condContext)) {}
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker // Returns total buffer size to allocate, and required offset alignment of that allocation.
47*c8dee2aaSAndroid Build Coastguard Worker // Updates 'levelOffsetsAndRowBytes' with offsets relative to start of the allocation, as well as
48*c8dee2aaSAndroid Build Coastguard Worker // the aligned destination rowBytes for each level.
compute_combined_buffer_size(const Caps * caps,int mipLevelCount,size_t bytesPerBlock,const SkISize & baseDimensions,SkTextureCompressionType compressionType,TArray<std::pair<size_t,size_t>> * levelOffsetsAndRowBytes)49*c8dee2aaSAndroid Build Coastguard Worker std::pair<size_t, size_t> compute_combined_buffer_size(
50*c8dee2aaSAndroid Build Coastguard Worker         const Caps* caps,
51*c8dee2aaSAndroid Build Coastguard Worker         int mipLevelCount,
52*c8dee2aaSAndroid Build Coastguard Worker         size_t bytesPerBlock,
53*c8dee2aaSAndroid Build Coastguard Worker         const SkISize& baseDimensions,
54*c8dee2aaSAndroid Build Coastguard Worker         SkTextureCompressionType compressionType,
55*c8dee2aaSAndroid Build Coastguard Worker         TArray<std::pair<size_t, size_t>>* levelOffsetsAndRowBytes) {
56*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(levelOffsetsAndRowBytes && levelOffsetsAndRowBytes->empty());
57*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(mipLevelCount >= 1);
58*c8dee2aaSAndroid Build Coastguard Worker 
59*c8dee2aaSAndroid Build Coastguard Worker     SkISize compressedBlockDimensions = CompressedDimensionsInBlocks(compressionType,
60*c8dee2aaSAndroid Build Coastguard Worker                                                                      baseDimensions);
61*c8dee2aaSAndroid Build Coastguard Worker 
62*c8dee2aaSAndroid Build Coastguard Worker     size_t minTransferBufferAlignment =
63*c8dee2aaSAndroid Build Coastguard Worker             std::max(bytesPerBlock, caps->requiredTransferBufferAlignment());
64*c8dee2aaSAndroid Build Coastguard Worker     size_t alignedBytesPerRow =
65*c8dee2aaSAndroid Build Coastguard Worker             caps->getAlignedTextureDataRowBytes(compressedBlockDimensions.width() * bytesPerBlock);
66*c8dee2aaSAndroid Build Coastguard Worker 
67*c8dee2aaSAndroid Build Coastguard Worker     levelOffsetsAndRowBytes->push_back({0, alignedBytesPerRow});
68*c8dee2aaSAndroid Build Coastguard Worker     size_t combinedBufferSize = SkAlignTo(alignedBytesPerRow * baseDimensions.height(),
69*c8dee2aaSAndroid Build Coastguard Worker                                           minTransferBufferAlignment);
70*c8dee2aaSAndroid Build Coastguard Worker     SkISize levelDimensions = baseDimensions;
71*c8dee2aaSAndroid Build Coastguard Worker 
72*c8dee2aaSAndroid Build Coastguard Worker     for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; ++currentMipLevel) {
73*c8dee2aaSAndroid Build Coastguard Worker         levelDimensions = {std::max(1, levelDimensions.width() / 2),
74*c8dee2aaSAndroid Build Coastguard Worker                            std::max(1, levelDimensions.height() / 2)};
75*c8dee2aaSAndroid Build Coastguard Worker         compressedBlockDimensions = CompressedDimensionsInBlocks(compressionType, levelDimensions);
76*c8dee2aaSAndroid Build Coastguard Worker         alignedBytesPerRow = caps->getAlignedTextureDataRowBytes(
77*c8dee2aaSAndroid Build Coastguard Worker                 compressedBlockDimensions.width() * bytesPerBlock);
78*c8dee2aaSAndroid Build Coastguard Worker         size_t alignedSize = SkAlignTo(alignedBytesPerRow * compressedBlockDimensions.height(),
79*c8dee2aaSAndroid Build Coastguard Worker                                        minTransferBufferAlignment);
80*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(combinedBufferSize % minTransferBufferAlignment == 0);
81*c8dee2aaSAndroid Build Coastguard Worker 
82*c8dee2aaSAndroid Build Coastguard Worker         levelOffsetsAndRowBytes->push_back({combinedBufferSize, alignedBytesPerRow});
83*c8dee2aaSAndroid Build Coastguard Worker         combinedBufferSize += alignedSize;
84*c8dee2aaSAndroid Build Coastguard Worker     }
85*c8dee2aaSAndroid Build Coastguard Worker 
86*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(levelOffsetsAndRowBytes->size() == mipLevelCount);
87*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(combinedBufferSize % minTransferBufferAlignment == 0);
88*c8dee2aaSAndroid Build Coastguard Worker     return {combinedBufferSize, minTransferBufferAlignment};
89*c8dee2aaSAndroid Build Coastguard Worker }
90*c8dee2aaSAndroid Build Coastguard Worker 
Make(Recorder * recorder,sk_sp<TextureProxy> textureProxy,const SkColorInfo & srcColorInfo,const SkColorInfo & dstColorInfo,SkSpan<const MipLevel> levels,const SkIRect & dstRect,std::unique_ptr<ConditionalUploadContext> condContext)91*c8dee2aaSAndroid Build Coastguard Worker UploadInstance UploadInstance::Make(Recorder* recorder,
92*c8dee2aaSAndroid Build Coastguard Worker                                     sk_sp<TextureProxy> textureProxy,
93*c8dee2aaSAndroid Build Coastguard Worker                                     const SkColorInfo& srcColorInfo,
94*c8dee2aaSAndroid Build Coastguard Worker                                     const SkColorInfo& dstColorInfo,
95*c8dee2aaSAndroid Build Coastguard Worker                                     SkSpan<const MipLevel> levels,
96*c8dee2aaSAndroid Build Coastguard Worker                                     const SkIRect& dstRect,
97*c8dee2aaSAndroid Build Coastguard Worker                                     std::unique_ptr<ConditionalUploadContext> condContext) {
98*c8dee2aaSAndroid Build Coastguard Worker     const Caps* caps = recorder->priv().caps();
99*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(caps->isTexturable(textureProxy->textureInfo()));
100*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(caps->areColorTypeAndTextureInfoCompatible(dstColorInfo.colorType(),
101*c8dee2aaSAndroid Build Coastguard Worker                                                         textureProxy->textureInfo()));
102*c8dee2aaSAndroid Build Coastguard Worker 
103*c8dee2aaSAndroid Build Coastguard Worker     unsigned int mipLevelCount = levels.size();
104*c8dee2aaSAndroid Build Coastguard Worker     // The assumption is either that we have no mipmaps, or that our rect is the entire texture
105*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(mipLevelCount == 1 || dstRect == SkIRect::MakeSize(textureProxy->dimensions()));
106*c8dee2aaSAndroid Build Coastguard Worker 
107*c8dee2aaSAndroid Build Coastguard Worker     // We assume that if the texture has mip levels, we either upload to all the levels or just the
108*c8dee2aaSAndroid Build Coastguard Worker     // first.
109*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
110*c8dee2aaSAndroid Build Coastguard Worker     unsigned int numExpectedLevels = 1;
111*c8dee2aaSAndroid Build Coastguard Worker     if (textureProxy->textureInfo().mipmapped() == Mipmapped::kYes) {
112*c8dee2aaSAndroid Build Coastguard Worker         numExpectedLevels = SkMipmap::ComputeLevelCount(textureProxy->dimensions().width(),
113*c8dee2aaSAndroid Build Coastguard Worker                                                         textureProxy->dimensions().height()) + 1;
114*c8dee2aaSAndroid Build Coastguard Worker     }
115*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(mipLevelCount == 1 || mipLevelCount == numExpectedLevels);
116*c8dee2aaSAndroid Build Coastguard Worker #endif
117*c8dee2aaSAndroid Build Coastguard Worker 
118*c8dee2aaSAndroid Build Coastguard Worker     if (dstRect.isEmpty()) {
119*c8dee2aaSAndroid Build Coastguard Worker         return Invalid();
120*c8dee2aaSAndroid Build Coastguard Worker     }
121*c8dee2aaSAndroid Build Coastguard Worker 
122*c8dee2aaSAndroid Build Coastguard Worker     if (mipLevelCount == 1 && !levels[0].fPixels) {
123*c8dee2aaSAndroid Build Coastguard Worker         return Invalid();   // no data to upload
124*c8dee2aaSAndroid Build Coastguard Worker     }
125*c8dee2aaSAndroid Build Coastguard Worker 
126*c8dee2aaSAndroid Build Coastguard Worker     for (unsigned int i = 0; i < mipLevelCount; ++i) {
127*c8dee2aaSAndroid Build Coastguard Worker         // We do not allow any gaps in the mip data
128*c8dee2aaSAndroid Build Coastguard Worker         if (!levels[i].fPixels) {
129*c8dee2aaSAndroid Build Coastguard Worker             return Invalid();
130*c8dee2aaSAndroid Build Coastguard Worker         }
131*c8dee2aaSAndroid Build Coastguard Worker     }
132*c8dee2aaSAndroid Build Coastguard Worker 
133*c8dee2aaSAndroid Build Coastguard Worker     SkColorType supportedColorType;
134*c8dee2aaSAndroid Build Coastguard Worker     bool isRGB888Format;
135*c8dee2aaSAndroid Build Coastguard Worker     std::tie(supportedColorType, isRGB888Format) =
136*c8dee2aaSAndroid Build Coastguard Worker             caps->supportedWritePixelsColorType(dstColorInfo.colorType(),
137*c8dee2aaSAndroid Build Coastguard Worker                                                 textureProxy->textureInfo(),
138*c8dee2aaSAndroid Build Coastguard Worker                                                 srcColorInfo.colorType());
139*c8dee2aaSAndroid Build Coastguard Worker     if (supportedColorType == kUnknown_SkColorType) {
140*c8dee2aaSAndroid Build Coastguard Worker         return Invalid();
141*c8dee2aaSAndroid Build Coastguard Worker     }
142*c8dee2aaSAndroid Build Coastguard Worker 
143*c8dee2aaSAndroid Build Coastguard Worker     const size_t bpp = isRGB888Format ? 3 : SkColorTypeBytesPerPixel(supportedColorType);
144*c8dee2aaSAndroid Build Coastguard Worker     TArray<std::pair<size_t, size_t>> levelOffsetsAndRowBytes(mipLevelCount);
145*c8dee2aaSAndroid Build Coastguard Worker 
146*c8dee2aaSAndroid Build Coastguard Worker     auto [combinedBufferSize, minAlignment] = compute_combined_buffer_size(
147*c8dee2aaSAndroid Build Coastguard Worker             caps,
148*c8dee2aaSAndroid Build Coastguard Worker             mipLevelCount,
149*c8dee2aaSAndroid Build Coastguard Worker             bpp,
150*c8dee2aaSAndroid Build Coastguard Worker             dstRect.size(),
151*c8dee2aaSAndroid Build Coastguard Worker             SkTextureCompressionType::kNone,
152*c8dee2aaSAndroid Build Coastguard Worker             &levelOffsetsAndRowBytes);
153*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(combinedBufferSize);
154*c8dee2aaSAndroid Build Coastguard Worker 
155*c8dee2aaSAndroid Build Coastguard Worker     UploadBufferManager* bufferMgr = recorder->priv().uploadBufferManager();
156*c8dee2aaSAndroid Build Coastguard Worker     auto [writer, bufferInfo] = bufferMgr->getTextureUploadWriter(combinedBufferSize, minAlignment);
157*c8dee2aaSAndroid Build Coastguard Worker     if (!writer) {
158*c8dee2aaSAndroid Build Coastguard Worker         SKGPU_LOG_W("Failed to get write-mapped buffer for texture upload of size %zu",
159*c8dee2aaSAndroid Build Coastguard Worker                     combinedBufferSize);
160*c8dee2aaSAndroid Build Coastguard Worker         return Invalid();
161*c8dee2aaSAndroid Build Coastguard Worker     }
162*c8dee2aaSAndroid Build Coastguard Worker 
163*c8dee2aaSAndroid Build Coastguard Worker     UploadInstance upload{bufferInfo.fBuffer, bpp, std::move(textureProxy), std::move(condContext)};
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker     // Fill in copy data
166*c8dee2aaSAndroid Build Coastguard Worker     int32_t currentWidth = dstRect.width();
167*c8dee2aaSAndroid Build Coastguard Worker     int32_t currentHeight = dstRect.height();
168*c8dee2aaSAndroid Build Coastguard Worker     bool needsConversion = (srcColorInfo != dstColorInfo);
169*c8dee2aaSAndroid Build Coastguard Worker     for (unsigned int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
170*c8dee2aaSAndroid Build Coastguard Worker         const size_t trimRowBytes = currentWidth * bpp;
171*c8dee2aaSAndroid Build Coastguard Worker         const size_t srcRowBytes = levels[currentMipLevel].fRowBytes;
172*c8dee2aaSAndroid Build Coastguard Worker         const auto [mipOffset, dstRowBytes] = levelOffsetsAndRowBytes[currentMipLevel];
173*c8dee2aaSAndroid Build Coastguard Worker 
174*c8dee2aaSAndroid Build Coastguard Worker         // copy data into the buffer, skipping any trailing bytes
175*c8dee2aaSAndroid Build Coastguard Worker         const char* src = (const char*)levels[currentMipLevel].fPixels;
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker         if (isRGB888Format) {
178*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(supportedColorType == kRGB_888x_SkColorType &&
179*c8dee2aaSAndroid Build Coastguard Worker                      dstColorInfo.colorType() == kRGB_888x_SkColorType);
180*c8dee2aaSAndroid Build Coastguard Worker             SkISize dims = {currentWidth, currentHeight};
181*c8dee2aaSAndroid Build Coastguard Worker             SkImageInfo srcImageInfo = SkImageInfo::Make(dims, srcColorInfo);
182*c8dee2aaSAndroid Build Coastguard Worker             SkImageInfo dstImageInfo = SkImageInfo::Make(dims, dstColorInfo);
183*c8dee2aaSAndroid Build Coastguard Worker 
184*c8dee2aaSAndroid Build Coastguard Worker             const void* rgbConvertSrc = src;
185*c8dee2aaSAndroid Build Coastguard Worker             size_t rgbSrcRowBytes = srcRowBytes;
186*c8dee2aaSAndroid Build Coastguard Worker             SkAutoPixmapStorage temp;
187*c8dee2aaSAndroid Build Coastguard Worker             if (needsConversion) {
188*c8dee2aaSAndroid Build Coastguard Worker                 temp.alloc(dstImageInfo);
189*c8dee2aaSAndroid Build Coastguard Worker                 SkAssertResult(SkConvertPixels(dstImageInfo,
190*c8dee2aaSAndroid Build Coastguard Worker                                                temp.writable_addr(),
191*c8dee2aaSAndroid Build Coastguard Worker                                                temp.rowBytes(),
192*c8dee2aaSAndroid Build Coastguard Worker                                                srcImageInfo,
193*c8dee2aaSAndroid Build Coastguard Worker                                                src,
194*c8dee2aaSAndroid Build Coastguard Worker                                                srcRowBytes));
195*c8dee2aaSAndroid Build Coastguard Worker                 rgbConvertSrc = temp.addr();
196*c8dee2aaSAndroid Build Coastguard Worker                 rgbSrcRowBytes = temp.rowBytes();
197*c8dee2aaSAndroid Build Coastguard Worker             }
198*c8dee2aaSAndroid Build Coastguard Worker             writer.writeRGBFromRGBx(mipOffset,
199*c8dee2aaSAndroid Build Coastguard Worker                                     rgbConvertSrc,
200*c8dee2aaSAndroid Build Coastguard Worker                                     rgbSrcRowBytes,
201*c8dee2aaSAndroid Build Coastguard Worker                                     dstRowBytes,
202*c8dee2aaSAndroid Build Coastguard Worker                                     currentWidth,
203*c8dee2aaSAndroid Build Coastguard Worker                                     currentHeight);
204*c8dee2aaSAndroid Build Coastguard Worker         } else if (needsConversion) {
205*c8dee2aaSAndroid Build Coastguard Worker             SkISize dims = {currentWidth, currentHeight};
206*c8dee2aaSAndroid Build Coastguard Worker             SkImageInfo srcImageInfo = SkImageInfo::Make(dims, srcColorInfo);
207*c8dee2aaSAndroid Build Coastguard Worker             SkImageInfo dstImageInfo = SkImageInfo::Make(dims, dstColorInfo);
208*c8dee2aaSAndroid Build Coastguard Worker 
209*c8dee2aaSAndroid Build Coastguard Worker             writer.convertAndWrite(
210*c8dee2aaSAndroid Build Coastguard Worker                     mipOffset, srcImageInfo, src, srcRowBytes, dstImageInfo, dstRowBytes);
211*c8dee2aaSAndroid Build Coastguard Worker         } else {
212*c8dee2aaSAndroid Build Coastguard Worker             writer.write(mipOffset, src, srcRowBytes, dstRowBytes, trimRowBytes, currentHeight);
213*c8dee2aaSAndroid Build Coastguard Worker         }
214*c8dee2aaSAndroid Build Coastguard Worker 
215*c8dee2aaSAndroid Build Coastguard Worker         // For mipped data, the dstRect is always the full texture so we don't need to worry about
216*c8dee2aaSAndroid Build Coastguard Worker         // modifying the TL coord as it will always be 0,0,for all levels.
217*c8dee2aaSAndroid Build Coastguard Worker         upload.fCopyData.push_back({
218*c8dee2aaSAndroid Build Coastguard Worker             /*fBufferOffset=*/bufferInfo.fOffset + mipOffset,
219*c8dee2aaSAndroid Build Coastguard Worker             /*fBufferRowBytes=*/dstRowBytes,
220*c8dee2aaSAndroid Build Coastguard Worker             /*fRect=*/SkIRect::MakeXYWH(dstRect.left(), dstRect.top(), currentWidth, currentHeight),
221*c8dee2aaSAndroid Build Coastguard Worker             /*fMipmapLevel=*/currentMipLevel
222*c8dee2aaSAndroid Build Coastguard Worker         });
223*c8dee2aaSAndroid Build Coastguard Worker 
224*c8dee2aaSAndroid Build Coastguard Worker         currentWidth = std::max(1, currentWidth / 2);
225*c8dee2aaSAndroid Build Coastguard Worker         currentHeight = std::max(1, currentHeight / 2);
226*c8dee2aaSAndroid Build Coastguard Worker     }
227*c8dee2aaSAndroid Build Coastguard Worker 
228*c8dee2aaSAndroid Build Coastguard Worker     ATRACE_ANDROID_FRAMEWORK("Upload %sTexture [%dx%d]",
229*c8dee2aaSAndroid Build Coastguard Worker                              mipLevelCount > 1 ? "MipMap " : "",
230*c8dee2aaSAndroid Build Coastguard Worker                              dstRect.width(), dstRect.height());
231*c8dee2aaSAndroid Build Coastguard Worker 
232*c8dee2aaSAndroid Build Coastguard Worker     return upload;
233*c8dee2aaSAndroid Build Coastguard Worker }
234*c8dee2aaSAndroid Build Coastguard Worker 
MakeCompressed(Recorder * recorder,sk_sp<TextureProxy> textureProxy,const void * data,size_t dataSize)235*c8dee2aaSAndroid Build Coastguard Worker UploadInstance UploadInstance::MakeCompressed(Recorder* recorder,
236*c8dee2aaSAndroid Build Coastguard Worker                                               sk_sp<TextureProxy> textureProxy,
237*c8dee2aaSAndroid Build Coastguard Worker                                               const void* data,
238*c8dee2aaSAndroid Build Coastguard Worker                                               size_t dataSize) {
239*c8dee2aaSAndroid Build Coastguard Worker     if (!data) {
240*c8dee2aaSAndroid Build Coastguard Worker         return Invalid();   // no data to upload
241*c8dee2aaSAndroid Build Coastguard Worker     }
242*c8dee2aaSAndroid Build Coastguard Worker 
243*c8dee2aaSAndroid Build Coastguard Worker     const TextureInfo& texInfo = textureProxy->textureInfo();
244*c8dee2aaSAndroid Build Coastguard Worker 
245*c8dee2aaSAndroid Build Coastguard Worker     const Caps* caps = recorder->priv().caps();
246*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(caps->isTexturable(texInfo));
247*c8dee2aaSAndroid Build Coastguard Worker 
248*c8dee2aaSAndroid Build Coastguard Worker     SkTextureCompressionType compression = texInfo.compressionType();
249*c8dee2aaSAndroid Build Coastguard Worker     if (compression == SkTextureCompressionType::kNone) {
250*c8dee2aaSAndroid Build Coastguard Worker         return Invalid();
251*c8dee2aaSAndroid Build Coastguard Worker     }
252*c8dee2aaSAndroid Build Coastguard Worker 
253*c8dee2aaSAndroid Build Coastguard Worker     // Create a transfer buffer and fill with data.
254*c8dee2aaSAndroid Build Coastguard Worker     const SkISize dimensions = textureProxy->dimensions();
255*c8dee2aaSAndroid Build Coastguard Worker     skia_private::STArray<16, size_t> srcMipOffsets;
256*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(size_t computedSize =) SkCompressedDataSize(compression,
257*c8dee2aaSAndroid Build Coastguard Worker                                                             dimensions,
258*c8dee2aaSAndroid Build Coastguard Worker                                                             &srcMipOffsets,
259*c8dee2aaSAndroid Build Coastguard Worker                                                             texInfo.mipmapped() == Mipmapped::kYes);
260*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(computedSize == dataSize);
261*c8dee2aaSAndroid Build Coastguard Worker 
262*c8dee2aaSAndroid Build Coastguard Worker     unsigned int mipLevelCount = srcMipOffsets.size();
263*c8dee2aaSAndroid Build Coastguard Worker     size_t bytesPerBlock = SkCompressedBlockSize(compression);
264*c8dee2aaSAndroid Build Coastguard Worker     TArray<std::pair<size_t, size_t>> levelOffsetsAndRowBytes(mipLevelCount);
265*c8dee2aaSAndroid Build Coastguard Worker     auto [combinedBufferSize, minAlignment] = compute_combined_buffer_size(
266*c8dee2aaSAndroid Build Coastguard Worker             caps,
267*c8dee2aaSAndroid Build Coastguard Worker             mipLevelCount,
268*c8dee2aaSAndroid Build Coastguard Worker             bytesPerBlock,
269*c8dee2aaSAndroid Build Coastguard Worker             dimensions,
270*c8dee2aaSAndroid Build Coastguard Worker             compression,
271*c8dee2aaSAndroid Build Coastguard Worker             &levelOffsetsAndRowBytes);
272*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(combinedBufferSize);
273*c8dee2aaSAndroid Build Coastguard Worker 
274*c8dee2aaSAndroid Build Coastguard Worker     UploadBufferManager* bufferMgr = recorder->priv().uploadBufferManager();
275*c8dee2aaSAndroid Build Coastguard Worker     auto [writer, bufferInfo] = bufferMgr->getTextureUploadWriter(combinedBufferSize, minAlignment);
276*c8dee2aaSAndroid Build Coastguard Worker 
277*c8dee2aaSAndroid Build Coastguard Worker     std::vector<BufferTextureCopyData> copyData(mipLevelCount);
278*c8dee2aaSAndroid Build Coastguard Worker 
279*c8dee2aaSAndroid Build Coastguard Worker     if (!bufferInfo.fBuffer) {
280*c8dee2aaSAndroid Build Coastguard Worker         SKGPU_LOG_W("Failed to get write-mapped buffer for texture upload of size %zu",
281*c8dee2aaSAndroid Build Coastguard Worker                     combinedBufferSize);
282*c8dee2aaSAndroid Build Coastguard Worker         return Invalid();
283*c8dee2aaSAndroid Build Coastguard Worker     }
284*c8dee2aaSAndroid Build Coastguard Worker 
285*c8dee2aaSAndroid Build Coastguard Worker     UploadInstance upload{bufferInfo.fBuffer, bytesPerBlock, std::move(textureProxy)};
286*c8dee2aaSAndroid Build Coastguard Worker 
287*c8dee2aaSAndroid Build Coastguard Worker     // Fill in copy data
288*c8dee2aaSAndroid Build Coastguard Worker     int32_t currentWidth = dimensions.width();
289*c8dee2aaSAndroid Build Coastguard Worker     int32_t currentHeight = dimensions.height();
290*c8dee2aaSAndroid Build Coastguard Worker     for (unsigned int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
291*c8dee2aaSAndroid Build Coastguard Worker         SkISize blockDimensions = CompressedDimensionsInBlocks(compression,
292*c8dee2aaSAndroid Build Coastguard Worker                                                                {currentWidth, currentHeight});
293*c8dee2aaSAndroid Build Coastguard Worker         int32_t blockHeight = blockDimensions.height();
294*c8dee2aaSAndroid Build Coastguard Worker 
295*c8dee2aaSAndroid Build Coastguard Worker         const size_t trimRowBytes = CompressedRowBytes(compression, currentWidth);
296*c8dee2aaSAndroid Build Coastguard Worker         const size_t srcRowBytes = trimRowBytes;
297*c8dee2aaSAndroid Build Coastguard Worker         const auto [dstMipOffset, dstRowBytes] = levelOffsetsAndRowBytes[currentMipLevel];
298*c8dee2aaSAndroid Build Coastguard Worker 
299*c8dee2aaSAndroid Build Coastguard Worker         // copy data into the buffer, skipping any trailing bytes
300*c8dee2aaSAndroid Build Coastguard Worker         const void* src = SkTAddOffset<const void>(data, srcMipOffsets[currentMipLevel]);
301*c8dee2aaSAndroid Build Coastguard Worker 
302*c8dee2aaSAndroid Build Coastguard Worker         writer.write(dstMipOffset, src, srcRowBytes, dstRowBytes, trimRowBytes, blockHeight);
303*c8dee2aaSAndroid Build Coastguard Worker 
304*c8dee2aaSAndroid Build Coastguard Worker         int32_t copyWidth = currentWidth;
305*c8dee2aaSAndroid Build Coastguard Worker         int32_t copyHeight = currentHeight;
306*c8dee2aaSAndroid Build Coastguard Worker         if (caps->fullCompressedUploadSizeMustAlignToBlockDims()) {
307*c8dee2aaSAndroid Build Coastguard Worker             SkISize oneBlockDims = CompressedDimensions(compression, {1, 1});
308*c8dee2aaSAndroid Build Coastguard Worker             copyWidth = SkAlignTo(copyWidth, oneBlockDims.fWidth);
309*c8dee2aaSAndroid Build Coastguard Worker             copyHeight = SkAlignTo(copyHeight, oneBlockDims.fHeight);
310*c8dee2aaSAndroid Build Coastguard Worker         }
311*c8dee2aaSAndroid Build Coastguard Worker 
312*c8dee2aaSAndroid Build Coastguard Worker         upload.fCopyData.push_back({
313*c8dee2aaSAndroid Build Coastguard Worker             /*fBufferOffset=*/bufferInfo.fOffset + dstMipOffset,
314*c8dee2aaSAndroid Build Coastguard Worker             /*fBufferRowBytes=*/dstRowBytes,
315*c8dee2aaSAndroid Build Coastguard Worker             /*fRect=*/SkIRect::MakeXYWH(0, 0, copyWidth, copyHeight),
316*c8dee2aaSAndroid Build Coastguard Worker             /*fMipLevel=*/currentMipLevel
317*c8dee2aaSAndroid Build Coastguard Worker         });
318*c8dee2aaSAndroid Build Coastguard Worker 
319*c8dee2aaSAndroid Build Coastguard Worker         currentWidth = std::max(1, currentWidth / 2);
320*c8dee2aaSAndroid Build Coastguard Worker         currentHeight = std::max(1, currentHeight / 2);
321*c8dee2aaSAndroid Build Coastguard Worker     }
322*c8dee2aaSAndroid Build Coastguard Worker 
323*c8dee2aaSAndroid Build Coastguard Worker     ATRACE_ANDROID_FRAMEWORK("Upload Compressed %sTexture [%dx%d]",
324*c8dee2aaSAndroid Build Coastguard Worker                              mipLevelCount > 1 ? "MipMap " : "",
325*c8dee2aaSAndroid Build Coastguard Worker                              dimensions.width(),
326*c8dee2aaSAndroid Build Coastguard Worker                              dimensions.height());
327*c8dee2aaSAndroid Build Coastguard Worker 
328*c8dee2aaSAndroid Build Coastguard Worker     return upload;
329*c8dee2aaSAndroid Build Coastguard Worker }
330*c8dee2aaSAndroid Build Coastguard Worker 
prepareResources(ResourceProvider * resourceProvider)331*c8dee2aaSAndroid Build Coastguard Worker bool UploadInstance::prepareResources(ResourceProvider* resourceProvider) {
332*c8dee2aaSAndroid Build Coastguard Worker     // While most uploads are to already instantiated proxies (e.g. for client-created texture
333*c8dee2aaSAndroid Build Coastguard Worker     // images) it is possible that writePixels() was issued as the first operation on a scratch
334*c8dee2aaSAndroid Build Coastguard Worker     // Device, or that this is the first upload to the raster or text atlas proxies.
335*c8dee2aaSAndroid Build Coastguard Worker     // TODO: Determine how to instantatiate textues in this case; atlas proxies shouldn't really be
336*c8dee2aaSAndroid Build Coastguard Worker     // "scratch" because they aren't going to be reused for anything else in a Recording. At the
337*c8dee2aaSAndroid Build Coastguard Worker     // same time, it could still go through the ScratchResourceManager and just never return them,
338*c8dee2aaSAndroid Build Coastguard Worker     // which is no different from instantiating them directly with the ResourceProvider.
339*c8dee2aaSAndroid Build Coastguard Worker     if (!TextureProxy::InstantiateIfNotLazy(resourceProvider, fTextureProxy.get())) {
340*c8dee2aaSAndroid Build Coastguard Worker         SKGPU_LOG_E("Could not instantiate texture proxy for UploadTask!");
341*c8dee2aaSAndroid Build Coastguard Worker         return false;
342*c8dee2aaSAndroid Build Coastguard Worker     }
343*c8dee2aaSAndroid Build Coastguard Worker     return true;
344*c8dee2aaSAndroid Build Coastguard Worker }
345*c8dee2aaSAndroid Build Coastguard Worker 
addCommand(Context * context,CommandBuffer * commandBuffer,Task::ReplayTargetData replayData) const346*c8dee2aaSAndroid Build Coastguard Worker Task::Status UploadInstance::addCommand(Context* context,
347*c8dee2aaSAndroid Build Coastguard Worker                                         CommandBuffer* commandBuffer,
348*c8dee2aaSAndroid Build Coastguard Worker                                         Task::ReplayTargetData replayData) const {
349*c8dee2aaSAndroid Build Coastguard Worker     using Status = Task::Status;
350*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fTextureProxy && fTextureProxy->isInstantiated());
351*c8dee2aaSAndroid Build Coastguard Worker 
352*c8dee2aaSAndroid Build Coastguard Worker     if (fConditionalContext && !fConditionalContext->needsUpload(context)) {
353*c8dee2aaSAndroid Build Coastguard Worker         // Assume that if a conditional context says to dynamically not upload that another
354*c8dee2aaSAndroid Build Coastguard Worker         // time through the tasks should try to upload again.
355*c8dee2aaSAndroid Build Coastguard Worker         return Status::kSuccess;
356*c8dee2aaSAndroid Build Coastguard Worker     }
357*c8dee2aaSAndroid Build Coastguard Worker 
358*c8dee2aaSAndroid Build Coastguard Worker     if (fTextureProxy->texture() != replayData.fTarget) {
359*c8dee2aaSAndroid Build Coastguard Worker         // The CommandBuffer doesn't take ownership of the upload buffer here; it's owned by
360*c8dee2aaSAndroid Build Coastguard Worker         // UploadBufferManager, which will transfer ownership in transferToCommandBuffer.
361*c8dee2aaSAndroid Build Coastguard Worker         if (!commandBuffer->copyBufferToTexture(fBuffer,
362*c8dee2aaSAndroid Build Coastguard Worker                                                 fTextureProxy->refTexture(),
363*c8dee2aaSAndroid Build Coastguard Worker                                                 fCopyData.data(),
364*c8dee2aaSAndroid Build Coastguard Worker                                                 fCopyData.size())) {
365*c8dee2aaSAndroid Build Coastguard Worker             return Status::kFail;
366*c8dee2aaSAndroid Build Coastguard Worker         }
367*c8dee2aaSAndroid Build Coastguard Worker     } else {
368*c8dee2aaSAndroid Build Coastguard Worker         // Here we assume that multiple copies in a single UploadInstance are always used for
369*c8dee2aaSAndroid Build Coastguard Worker         // mipmaps of a single image, and that we won't ever upload to a replay target's mipmaps
370*c8dee2aaSAndroid Build Coastguard Worker         // directly.
371*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fCopyData.size() == 1);
372*c8dee2aaSAndroid Build Coastguard Worker         const BufferTextureCopyData& copyData = fCopyData[0];
373*c8dee2aaSAndroid Build Coastguard Worker         SkIRect dstRect = copyData.fRect;
374*c8dee2aaSAndroid Build Coastguard Worker         dstRect.offset(replayData.fTranslation);
375*c8dee2aaSAndroid Build Coastguard Worker         SkIRect croppedDstRect = dstRect;
376*c8dee2aaSAndroid Build Coastguard Worker 
377*c8dee2aaSAndroid Build Coastguard Worker         if (!replayData.fClip.isEmpty()) {
378*c8dee2aaSAndroid Build Coastguard Worker             SkIRect dstClip = replayData.fClip;
379*c8dee2aaSAndroid Build Coastguard Worker             dstClip.offset(replayData.fTranslation);
380*c8dee2aaSAndroid Build Coastguard Worker             if (!croppedDstRect.intersect(dstClip)) {
381*c8dee2aaSAndroid Build Coastguard Worker                 // The replay clip can change on each insert, so subsequent replays may actually
382*c8dee2aaSAndroid Build Coastguard Worker                 // intersect the copy rect.
383*c8dee2aaSAndroid Build Coastguard Worker                 return Status::kSuccess;
384*c8dee2aaSAndroid Build Coastguard Worker             }
385*c8dee2aaSAndroid Build Coastguard Worker         }
386*c8dee2aaSAndroid Build Coastguard Worker 
387*c8dee2aaSAndroid Build Coastguard Worker         if (!croppedDstRect.intersect(SkIRect::MakeSize(fTextureProxy->dimensions()))) {
388*c8dee2aaSAndroid Build Coastguard Worker             // The replay translation can change on each insert, so subsequent replays may
389*c8dee2aaSAndroid Build Coastguard Worker             // actually intersect the copy rect.
390*c8dee2aaSAndroid Build Coastguard Worker             return Status::kSuccess;
391*c8dee2aaSAndroid Build Coastguard Worker         }
392*c8dee2aaSAndroid Build Coastguard Worker 
393*c8dee2aaSAndroid Build Coastguard Worker         BufferTextureCopyData transformedCopyData = copyData;
394*c8dee2aaSAndroid Build Coastguard Worker         transformedCopyData.fBufferOffset +=
395*c8dee2aaSAndroid Build Coastguard Worker                 (croppedDstRect.y() - dstRect.y()) * copyData.fBufferRowBytes +
396*c8dee2aaSAndroid Build Coastguard Worker                 (croppedDstRect.x() - dstRect.x()) * fBytesPerPixel;
397*c8dee2aaSAndroid Build Coastguard Worker         transformedCopyData.fRect = croppedDstRect;
398*c8dee2aaSAndroid Build Coastguard Worker 
399*c8dee2aaSAndroid Build Coastguard Worker         if (!commandBuffer->copyBufferToTexture(fBuffer,
400*c8dee2aaSAndroid Build Coastguard Worker                                                 fTextureProxy->refTexture(),
401*c8dee2aaSAndroid Build Coastguard Worker                                                 &transformedCopyData, 1)) {
402*c8dee2aaSAndroid Build Coastguard Worker             return Status::kFail;
403*c8dee2aaSAndroid Build Coastguard Worker         }
404*c8dee2aaSAndroid Build Coastguard Worker     }
405*c8dee2aaSAndroid Build Coastguard Worker 
406*c8dee2aaSAndroid Build Coastguard Worker     // The conditional context will return false if the upload should not happen anymore. If there's
407*c8dee2aaSAndroid Build Coastguard Worker     // no context assume that the upload should always be executed on replay.
408*c8dee2aaSAndroid Build Coastguard Worker     if (!fConditionalContext || fConditionalContext->uploadSubmitted()) {
409*c8dee2aaSAndroid Build Coastguard Worker         return Status::kSuccess;
410*c8dee2aaSAndroid Build Coastguard Worker     } else {
411*c8dee2aaSAndroid Build Coastguard Worker         return Status::kDiscard;
412*c8dee2aaSAndroid Build Coastguard Worker     }
413*c8dee2aaSAndroid Build Coastguard Worker }
414*c8dee2aaSAndroid Build Coastguard Worker 
415*c8dee2aaSAndroid Build Coastguard Worker //---------------------------------------------------------------------------
416*c8dee2aaSAndroid Build Coastguard Worker 
recordUpload(Recorder * recorder,sk_sp<TextureProxy> textureProxy,const SkColorInfo & srcColorInfo,const SkColorInfo & dstColorInfo,SkSpan<const MipLevel> levels,const SkIRect & dstRect,std::unique_ptr<ConditionalUploadContext> condContext)417*c8dee2aaSAndroid Build Coastguard Worker bool UploadList::recordUpload(Recorder* recorder,
418*c8dee2aaSAndroid Build Coastguard Worker                               sk_sp<TextureProxy> textureProxy,
419*c8dee2aaSAndroid Build Coastguard Worker                               const SkColorInfo& srcColorInfo,
420*c8dee2aaSAndroid Build Coastguard Worker                               const SkColorInfo& dstColorInfo,
421*c8dee2aaSAndroid Build Coastguard Worker                               SkSpan<const MipLevel> levels,
422*c8dee2aaSAndroid Build Coastguard Worker                               const SkIRect& dstRect,
423*c8dee2aaSAndroid Build Coastguard Worker                               std::unique_ptr<ConditionalUploadContext> condContext) {
424*c8dee2aaSAndroid Build Coastguard Worker     UploadInstance instance = UploadInstance::Make(recorder, std::move(textureProxy),
425*c8dee2aaSAndroid Build Coastguard Worker                                                    srcColorInfo, dstColorInfo,
426*c8dee2aaSAndroid Build Coastguard Worker                                                    levels, dstRect, std::move(condContext));
427*c8dee2aaSAndroid Build Coastguard Worker     if (!instance.isValid()) {
428*c8dee2aaSAndroid Build Coastguard Worker         return false;
429*c8dee2aaSAndroid Build Coastguard Worker     }
430*c8dee2aaSAndroid Build Coastguard Worker 
431*c8dee2aaSAndroid Build Coastguard Worker     fInstances.emplace_back(std::move(instance));
432*c8dee2aaSAndroid Build Coastguard Worker     return true;
433*c8dee2aaSAndroid Build Coastguard Worker }
434*c8dee2aaSAndroid Build Coastguard Worker 
435*c8dee2aaSAndroid Build Coastguard Worker //---------------------------------------------------------------------------
436*c8dee2aaSAndroid Build Coastguard Worker 
Make(UploadList * uploadList)437*c8dee2aaSAndroid Build Coastguard Worker sk_sp<UploadTask> UploadTask::Make(UploadList* uploadList) {
438*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(uploadList);
439*c8dee2aaSAndroid Build Coastguard Worker     if (!uploadList->size()) {
440*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
441*c8dee2aaSAndroid Build Coastguard Worker     }
442*c8dee2aaSAndroid Build Coastguard Worker     return sk_sp<UploadTask>(new UploadTask(std::move(uploadList->fInstances)));
443*c8dee2aaSAndroid Build Coastguard Worker }
444*c8dee2aaSAndroid Build Coastguard Worker 
Make(UploadInstance instance)445*c8dee2aaSAndroid Build Coastguard Worker sk_sp<UploadTask> UploadTask::Make(UploadInstance instance) {
446*c8dee2aaSAndroid Build Coastguard Worker     if (!instance.isValid()) {
447*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
448*c8dee2aaSAndroid Build Coastguard Worker     }
449*c8dee2aaSAndroid Build Coastguard Worker     return sk_sp<UploadTask>(new UploadTask(std::move(instance)));
450*c8dee2aaSAndroid Build Coastguard Worker }
451*c8dee2aaSAndroid Build Coastguard Worker 
UploadTask(skia_private::TArray<UploadInstance> && instances)452*c8dee2aaSAndroid Build Coastguard Worker UploadTask::UploadTask(skia_private::TArray<UploadInstance>&& instances)
453*c8dee2aaSAndroid Build Coastguard Worker         : fInstances(std::move(instances)) {}
454*c8dee2aaSAndroid Build Coastguard Worker 
UploadTask(UploadInstance instance)455*c8dee2aaSAndroid Build Coastguard Worker UploadTask::UploadTask(UploadInstance instance) {
456*c8dee2aaSAndroid Build Coastguard Worker     fInstances.emplace_back(std::move(instance));
457*c8dee2aaSAndroid Build Coastguard Worker }
458*c8dee2aaSAndroid Build Coastguard Worker 
~UploadTask()459*c8dee2aaSAndroid Build Coastguard Worker UploadTask::~UploadTask() {}
460*c8dee2aaSAndroid Build Coastguard Worker 
prepareResources(ResourceProvider * resourceProvider,ScratchResourceManager *,const RuntimeEffectDictionary *)461*c8dee2aaSAndroid Build Coastguard Worker Task::Status UploadTask::prepareResources(ResourceProvider* resourceProvider,
462*c8dee2aaSAndroid Build Coastguard Worker                                           ScratchResourceManager*,
463*c8dee2aaSAndroid Build Coastguard Worker                                           const RuntimeEffectDictionary*) {
464*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < fInstances.size(); ++i) {
465*c8dee2aaSAndroid Build Coastguard Worker         // No upload should be invalidated before prepareResources() is called.
466*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fInstances[i].isValid());
467*c8dee2aaSAndroid Build Coastguard Worker         if (!fInstances[i].prepareResources(resourceProvider)) {
468*c8dee2aaSAndroid Build Coastguard Worker             return Status::kFail;
469*c8dee2aaSAndroid Build Coastguard Worker         }
470*c8dee2aaSAndroid Build Coastguard Worker     }
471*c8dee2aaSAndroid Build Coastguard Worker 
472*c8dee2aaSAndroid Build Coastguard Worker     return Status::kSuccess;
473*c8dee2aaSAndroid Build Coastguard Worker }
474*c8dee2aaSAndroid Build Coastguard Worker 
addCommands(Context * context,CommandBuffer * commandBuffer,ReplayTargetData replayData)475*c8dee2aaSAndroid Build Coastguard Worker Task::Status UploadTask::addCommands(Context* context,
476*c8dee2aaSAndroid Build Coastguard Worker                                      CommandBuffer* commandBuffer,
477*c8dee2aaSAndroid Build Coastguard Worker                                      ReplayTargetData replayData) {
478*c8dee2aaSAndroid Build Coastguard Worker     int discardCount = 0;
479*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < fInstances.size(); ++i) {
480*c8dee2aaSAndroid Build Coastguard Worker         if (!fInstances[i].isValid()) {
481*c8dee2aaSAndroid Build Coastguard Worker             discardCount++;
482*c8dee2aaSAndroid Build Coastguard Worker             continue;
483*c8dee2aaSAndroid Build Coastguard Worker         }
484*c8dee2aaSAndroid Build Coastguard Worker         Status status = fInstances[i].addCommand(context, commandBuffer, replayData);
485*c8dee2aaSAndroid Build Coastguard Worker         if (status == Status::kFail) {
486*c8dee2aaSAndroid Build Coastguard Worker             return Status::kFail;
487*c8dee2aaSAndroid Build Coastguard Worker         } else if (status == Status::kDiscard) {
488*c8dee2aaSAndroid Build Coastguard Worker             fInstances[i] = UploadInstance::Invalid();
489*c8dee2aaSAndroid Build Coastguard Worker             discardCount++;
490*c8dee2aaSAndroid Build Coastguard Worker         }
491*c8dee2aaSAndroid Build Coastguard Worker     }
492*c8dee2aaSAndroid Build Coastguard Worker 
493*c8dee2aaSAndroid Build Coastguard Worker     if (discardCount == fInstances.size()) {
494*c8dee2aaSAndroid Build Coastguard Worker         return Status::kDiscard;
495*c8dee2aaSAndroid Build Coastguard Worker     } else {
496*c8dee2aaSAndroid Build Coastguard Worker         return Status::kSuccess;
497*c8dee2aaSAndroid Build Coastguard Worker     }
498*c8dee2aaSAndroid Build Coastguard Worker }
499*c8dee2aaSAndroid Build Coastguard Worker 
500*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
501