Flutter Engine
The Flutter Engine
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Public Member Functions | Static Public Member Functions | List of all members
skgpu::graphite::UploadInstance Class Reference

#include <UploadTask.h>

Public Member Functions

 UploadInstance (UploadInstance &&)
 
UploadInstanceoperator= (UploadInstance &&)
 
 ~UploadInstance ()
 
bool isValid () const
 
bool prepareResources (ResourceProvider *)
 
Task::Status addCommand (Context *, CommandBuffer *, Task::ReplayTargetData) const
 

Static Public Member Functions

static UploadInstance Make (Recorder *, sk_sp< TextureProxy > targetProxy, const SkColorInfo &srcColorInfo, const SkColorInfo &dstColorInfo, SkSpan< const MipLevel > levels, const SkIRect &dstRect, std::unique_ptr< ConditionalUploadContext >)
 
static UploadInstance MakeCompressed (Recorder *, sk_sp< TextureProxy > targetProxy, const void *data, size_t dataSize)
 
static UploadInstance Invalid ()
 

Detailed Description

An UploadInstance represents a single set of uploads from a buffer to texture that can be processed in a single command.

Definition at line 70 of file UploadTask.h.

Constructor & Destructor Documentation

◆ UploadInstance()

skgpu::graphite::UploadInstance::UploadInstance ( UploadInstance &&  )
default

◆ ~UploadInstance()

skgpu::graphite::UploadInstance::~UploadInstance ( )
default

Member Function Documentation

◆ addCommand()

Task::Status skgpu::graphite::UploadInstance::addCommand ( Context context,
CommandBuffer commandBuffer,
Task::ReplayTargetData  replayData 
) const

Definition at line 346 of file UploadTask.cpp.

348 {
349 using Status = Task::Status;
350 SkASSERT(fTextureProxy && fTextureProxy->isInstantiated());
351
352 if (fConditionalContext && !fConditionalContext->needsUpload(context)) {
353 // Assume that if a conditional context says to dynamically not upload that another
354 // time through the tasks should try to upload again.
355 return Status::kSuccess;
356 }
357
358 if (fTextureProxy->texture() != replayData.fTarget) {
359 // The CommandBuffer doesn't take ownership of the upload buffer here; it's owned by
360 // UploadBufferManager, which will transfer ownership in transferToCommandBuffer.
361 if (!commandBuffer->copyBufferToTexture(fBuffer,
362 fTextureProxy->refTexture(),
363 fCopyData.data(),
364 fCopyData.size())) {
365 return Status::kFail;
366 }
367 } else {
368 // Here we assume that multiple copies in a single UploadInstance are always used for
369 // mipmaps of a single image, and that we won't ever copy to a replay target with mipmaps.
370 SkASSERT(fCopyData.size() == 1);
371 const BufferTextureCopyData& copyData = fCopyData[0];
372 SkIRect dstRect = copyData.fRect;
373 dstRect.offset(replayData.fTranslation);
374 SkIRect croppedDstRect = dstRect;
375 if (!croppedDstRect.intersect(SkIRect::MakeSize(fTextureProxy->dimensions()))) {
376 // The replay translation can change on each insert, so subsequent replays may
377 // actually intersect the copy rect.
378 return Status::kSuccess;
379 }
380
381 BufferTextureCopyData transformedCopyData = copyData;
382 transformedCopyData.fBufferOffset +=
383 (croppedDstRect.y() - dstRect.y()) * copyData.fBufferRowBytes +
384 (croppedDstRect.x() - dstRect.x()) * fBytesPerPixel;
385 transformedCopyData.fRect = croppedDstRect;
386
387 if (!commandBuffer->copyBufferToTexture(fBuffer,
388 fTextureProxy->refTexture(),
389 &transformedCopyData, 1)) {
390 return Status::kFail;
391 }
392 }
393
394 // The conditional context will return false if the upload should not happen anymore. If there's
395 // no context assume that the upload should always be executed on replay.
396 if (!fConditionalContext || fConditionalContext->uploadSubmitted()) {
397 return Status::kSuccess;
398 } else {
399 return Status::kDiscard;
400 }
401}
#define SkASSERT(cond)
Definition: SkAssert.h:116
Task::Status Status
Definition: TaskList.cpp:15
Definition: SkRect.h:32
constexpr int32_t x() const
Definition: SkRect.h:141
constexpr int32_t y() const
Definition: SkRect.h:148
bool intersect(const SkIRect &r)
Definition: SkRect.h:513
static constexpr SkIRect MakeSize(const SkISize &size)
Definition: SkRect.h:66
void offset(int32_t dx, int32_t dy)
Definition: SkRect.h:367

◆ Invalid()

static UploadInstance skgpu::graphite::UploadInstance::Invalid ( )
inlinestatic

Definition at line 84 of file UploadTask.h.

84{ return {}; }

◆ isValid()

bool skgpu::graphite::UploadInstance::isValid ( ) const
inline

Definition at line 90 of file UploadTask.h.

90{ return fBuffer != nullptr && fTextureProxy != nullptr; }

◆ Make()

UploadInstance skgpu::graphite::UploadInstance::Make ( Recorder recorder,
sk_sp< TextureProxy targetProxy,
const SkColorInfo srcColorInfo,
const SkColorInfo dstColorInfo,
SkSpan< const MipLevel levels,
const SkIRect dstRect,
std::unique_ptr< ConditionalUploadContext condContext 
)
static

Definition at line 91 of file UploadTask.cpp.

97 {
98 const Caps* caps = recorder->priv().caps();
99 SkASSERT(caps->isTexturable(textureProxy->textureInfo()));
100 SkASSERT(caps->areColorTypeAndTextureInfoCompatible(dstColorInfo.colorType(),
101 textureProxy->textureInfo()));
102
103 unsigned int mipLevelCount = levels.size();
104 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
105 SkASSERT(mipLevelCount == 1 || dstRect == SkIRect::MakeSize(textureProxy->dimensions()));
106
107 // We assume that if the texture has mip levels, we either upload to all the levels or just the
108 // first.
109#ifdef SK_DEBUG
110 unsigned int numExpectedLevels = 1;
111 if (textureProxy->textureInfo().mipmapped() == Mipmapped::kYes) {
112 numExpectedLevels = SkMipmap::ComputeLevelCount(textureProxy->dimensions().width(),
113 textureProxy->dimensions().height()) + 1;
114 }
115 SkASSERT(mipLevelCount == 1 || mipLevelCount == numExpectedLevels);
116#endif
117
118 if (dstRect.isEmpty()) {
119 return Invalid();
120 }
121
122 if (mipLevelCount == 1 && !levels[0].fPixels) {
123 return Invalid(); // no data to upload
124 }
125
126 for (unsigned int i = 0; i < mipLevelCount; ++i) {
127 // We do not allow any gaps in the mip data
128 if (!levels[i].fPixels) {
129 return Invalid();
130 }
131 }
132
133 SkColorType supportedColorType;
134 bool isRGB888Format;
135 std::tie(supportedColorType, isRGB888Format) =
136 caps->supportedWritePixelsColorType(dstColorInfo.colorType(),
137 textureProxy->textureInfo(),
138 srcColorInfo.colorType());
139 if (supportedColorType == kUnknown_SkColorType) {
140 return Invalid();
141 }
142
143 const size_t bpp = isRGB888Format ? 3 : SkColorTypeBytesPerPixel(supportedColorType);
144 TArray<std::pair<size_t, size_t>> levelOffsetsAndRowBytes(mipLevelCount);
145
146 auto [combinedBufferSize, minAlignment] = compute_combined_buffer_size(
147 caps,
148 mipLevelCount,
149 bpp,
150 dstRect.size(),
152 &levelOffsetsAndRowBytes);
153 SkASSERT(combinedBufferSize);
154
155 UploadBufferManager* bufferMgr = recorder->priv().uploadBufferManager();
156 auto [writer, bufferInfo] = bufferMgr->getTextureUploadWriter(combinedBufferSize, minAlignment);
157 if (!writer) {
158 SKGPU_LOG_W("Failed to get write-mapped buffer for texture upload of size %zu",
159 combinedBufferSize);
160 return Invalid();
161 }
162
163 UploadInstance upload{bufferInfo.fBuffer, bpp, std::move(textureProxy), std::move(condContext)};
164
165 // Fill in copy data
166 int32_t currentWidth = dstRect.width();
167 int32_t currentHeight = dstRect.height();
168 bool needsConversion = (srcColorInfo != dstColorInfo);
169 for (unsigned int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
170 const size_t trimRowBytes = currentWidth * bpp;
171 const size_t srcRowBytes = levels[currentMipLevel].fRowBytes;
172 const auto [mipOffset, dstRowBytes] = levelOffsetsAndRowBytes[currentMipLevel];
173
174 // copy data into the buffer, skipping any trailing bytes
175 const char* src = (const char*)levels[currentMipLevel].fPixels;
176
177 if (isRGB888Format) {
178 SkASSERT(supportedColorType == kRGB_888x_SkColorType &&
179 dstColorInfo.colorType() == kRGB_888x_SkColorType);
180 SkISize dims = {currentWidth, currentHeight};
181 SkImageInfo srcImageInfo = SkImageInfo::Make(dims, srcColorInfo);
182 SkImageInfo dstImageInfo = SkImageInfo::Make(dims, dstColorInfo);
183
184 const void* rgbConvertSrc = src;
185 size_t rgbSrcRowBytes = srcRowBytes;
187 if (needsConversion) {
188 temp.alloc(dstImageInfo);
189 SkAssertResult(SkConvertPixels(dstImageInfo,
190 temp.writable_addr(),
191 temp.rowBytes(),
192 srcImageInfo,
193 src,
194 srcRowBytes));
195 rgbConvertSrc = temp.addr();
196 rgbSrcRowBytes = temp.rowBytes();
197 }
198 writer.writeRGBFromRGBx(mipOffset,
199 rgbConvertSrc,
200 rgbSrcRowBytes,
201 dstRowBytes,
202 currentWidth,
203 currentHeight);
204 } else if (needsConversion) {
205 SkISize dims = {currentWidth, currentHeight};
206 SkImageInfo srcImageInfo = SkImageInfo::Make(dims, srcColorInfo);
207 SkImageInfo dstImageInfo = SkImageInfo::Make(dims, dstColorInfo);
208
209 writer.convertAndWrite(
210 mipOffset, srcImageInfo, src, srcRowBytes, dstImageInfo, dstRowBytes);
211 } else {
212 writer.write(mipOffset, src, srcRowBytes, dstRowBytes, trimRowBytes, currentHeight);
213 }
214
215 // For mipped data, the dstRect is always the full texture so we don't need to worry about
216 // modifying the TL coord as it will always be 0,0,for all levels.
217 upload.fCopyData.push_back({
218 /*fBufferOffset=*/bufferInfo.fOffset + mipOffset,
219 /*fBufferRowBytes=*/dstRowBytes,
220 /*fRect=*/SkIRect::MakeXYWH(dstRect.left(), dstRect.top(), currentWidth, currentHeight),
221 /*fMipmapLevel=*/currentMipLevel
222 });
223
224 currentWidth = std::max(1, currentWidth / 2);
225 currentHeight = std::max(1, currentHeight / 2);
226 }
227
228 ATRACE_ANDROID_FRAMEWORK("Upload %sTexture [%dx%d]",
229 mipLevelCount > 1 ? "MipMap " : "",
230 dstRect.width(), dstRect.height());
231
232 return upload;
233}
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
#define SKGPU_LOG_W(fmt,...)
Definition: Log.h:40
SkColorType
Definition: SkColorType.h:19
@ kRGB_888x_SkColorType
pixel with 8 bits each for red, green, blue; in 32-bit word
Definition: SkColorType.h:25
@ kUnknown_SkColorType
uninitialized
Definition: SkColorType.h:20
bool SkConvertPixels(const SkImageInfo &dstInfo, void *dstPixels, size_t dstRB, const SkImageInfo &srcInfo, const void *srcPixels, size_t srcRB)
SK_API int SkColorTypeBytesPerPixel(SkColorType ct)
Definition: SkImageInfo.cpp:16
#define ATRACE_ANDROID_FRAMEWORK(fmt,...)
static sk_sp< SkImage > upload(const sk_sp< SkSurface > &surf, SkColor color)
void alloc(const SkImageInfo &)
SkColorType colorType() const
Definition: SkImageInfo.h:140
static int ComputeLevelCount(int baseWidth, int baseHeight)
Definition: SkMipmap.cpp:134
size_t rowBytes() const
Definition: SkPixmap.h:145
void * writable_addr() const
Definition: SkPixmap.h:483
const void * addr() const
Definition: SkPixmap.h:153
constexpr size_t size() const
Definition: SkSpan_impl.h:95
const Caps * caps() const
Definition: RecorderPriv.h:31
UploadBufferManager * uploadBufferManager()
Definition: RecorderPriv.h:59
std::tuple< TextureUploadWriter, BindBufferInfo > getTextureUploadWriter(size_t requiredBytes, size_t requiredAlignment)
static UploadInstance Invalid()
Definition: UploadTask.h:84
UploadInstance(UploadInstance &&)
static float max(float r, float g, float b)
Definition: hsl.cpp:49
std::pair< size_t, size_t > 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)
Definition: UploadTask.cpp:49
Definition: upload.py:1
constexpr int32_t top() const
Definition: SkRect.h:120
constexpr SkISize size() const
Definition: SkRect.h:172
constexpr int32_t height() const
Definition: SkRect.h:165
constexpr int32_t width() const
Definition: SkRect.h:158
bool isEmpty() const
Definition: SkRect.h:202
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition: SkRect.h:104
constexpr int32_t left() const
Definition: SkRect.h:113
Definition: SkSize.h:16
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)

◆ MakeCompressed()

UploadInstance skgpu::graphite::UploadInstance::MakeCompressed ( Recorder recorder,
sk_sp< TextureProxy targetProxy,
const void *  data,
size_t  dataSize 
)
static

Definition at line 235 of file UploadTask.cpp.

238 {
239 if (!data) {
240 return Invalid(); // no data to upload
241 }
242
243 const TextureInfo& texInfo = textureProxy->textureInfo();
244
245 const Caps* caps = recorder->priv().caps();
246 SkASSERT(caps->isTexturable(texInfo));
247
248 SkTextureCompressionType compression = texInfo.compressionType();
249 if (compression == SkTextureCompressionType::kNone) {
250 return Invalid();
251 }
252
253 // Create a transfer buffer and fill with data.
254 const SkISize dimensions = textureProxy->dimensions();
256 SkDEBUGCODE(size_t computedSize =) SkCompressedDataSize(compression,
257 dimensions,
258 &srcMipOffsets,
259 texInfo.mipmapped() == Mipmapped::kYes);
260 SkASSERT(computedSize == dataSize);
261
262 unsigned int mipLevelCount = srcMipOffsets.size();
263 size_t bytesPerBlock = SkCompressedBlockSize(compression);
264 TArray<std::pair<size_t, size_t>> levelOffsetsAndRowBytes(mipLevelCount);
265 auto [combinedBufferSize, minAlignment] = compute_combined_buffer_size(
266 caps,
267 mipLevelCount,
268 bytesPerBlock,
269 dimensions,
270 compression,
271 &levelOffsetsAndRowBytes);
272 SkASSERT(combinedBufferSize);
273
274 UploadBufferManager* bufferMgr = recorder->priv().uploadBufferManager();
275 auto [writer, bufferInfo] = bufferMgr->getTextureUploadWriter(combinedBufferSize, minAlignment);
276
277 std::vector<BufferTextureCopyData> copyData(mipLevelCount);
278
279 if (!bufferInfo.fBuffer) {
280 SKGPU_LOG_W("Failed to get write-mapped buffer for texture upload of size %zu",
281 combinedBufferSize);
282 return Invalid();
283 }
284
285 UploadInstance upload{bufferInfo.fBuffer, bytesPerBlock, std::move(textureProxy)};
286
287 // Fill in copy data
288 int32_t currentWidth = dimensions.width();
289 int32_t currentHeight = dimensions.height();
290 for (unsigned int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
291 SkISize blockDimensions = CompressedDimensionsInBlocks(compression,
292 {currentWidth, currentHeight});
293 int32_t blockHeight = blockDimensions.height();
294
295 const size_t trimRowBytes = CompressedRowBytes(compression, currentWidth);
296 const size_t srcRowBytes = trimRowBytes;
297 const auto [dstMipOffset, dstRowBytes] = levelOffsetsAndRowBytes[currentMipLevel];
298
299 // copy data into the buffer, skipping any trailing bytes
300 const void* src = SkTAddOffset<const void>(data, srcMipOffsets[currentMipLevel]);
301
302 writer.write(dstMipOffset, src, srcRowBytes, dstRowBytes, trimRowBytes, blockHeight);
303
304 int32_t copyWidth = currentWidth;
305 int32_t copyHeight = currentHeight;
306 if (caps->fullCompressedUploadSizeMustAlignToBlockDims()) {
307 SkISize oneBlockDims = CompressedDimensions(compression, {1, 1});
308 copyWidth = SkAlignTo(copyWidth, oneBlockDims.fWidth);
309 copyHeight = SkAlignTo(copyHeight, oneBlockDims.fHeight);
310 }
311
312 upload.fCopyData.push_back({
313 /*fBufferOffset=*/bufferInfo.fOffset + dstMipOffset,
314 /*fBufferRowBytes=*/dstRowBytes,
315 /*fRect=*/SkIRect::MakeXYWH(0, 0, copyWidth, copyHeight),
316 /*fMipLevel=*/currentMipLevel
317 });
318
319 currentWidth = std::max(1, currentWidth / 2);
320 currentHeight = std::max(1, currentHeight / 2);
321 }
322
323 ATRACE_ANDROID_FRAMEWORK("Upload Compressed %sTexture [%dx%d]",
324 mipLevelCount > 1 ? "MipMap " : "",
325 dimensions.width(),
326 dimensions.height());
327
328 return upload;
329}
static constexpr size_t SkAlignTo(size_t x, size_t alignment)
Definition: SkAlign.h:33
size_t SkCompressedDataSize(SkTextureCompressionType type, SkISize dimensions, TArray< size_t > *individualMipOffsets, bool mipmapped)
size_t SkCompressedBlockSize(SkTextureCompressionType type)
SkTextureCompressionType
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
if(end==-1)
FlPixelBufferTexturePrivate * priv
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SkISize CompressedDimensionsInBlocks(SkTextureCompressionType type, SkISize baseDimensions)
Definition: DataUtils.cpp:210
size_t CompressedRowBytes(SkTextureCompressionType type, int width)
Definition: DataUtils.cpp:179
Mipmapped
Definition: GpuTypes.h:53
SkISize CompressedDimensions(SkTextureCompressionType type, SkISize baseDimensions)
Definition: DataUtils.cpp:195
Definition: ref_ptr.h:256
int32_t fHeight
Definition: SkSize.h:18
int32_t fWidth
Definition: SkSize.h:17
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63

◆ operator=()

UploadInstance & skgpu::graphite::UploadInstance::operator= ( UploadInstance &&  )
default

◆ prepareResources()

bool skgpu::graphite::UploadInstance::prepareResources ( ResourceProvider resourceProvider)

Definition at line 331 of file UploadTask.cpp.

331 {
332 // While most uploads are to already instantiated proxies (e.g. for client-created texture
333 // images) it is possible that writePixels() was issued as the first operation on a scratch
334 // Device, or that this is the first upload to the raster or text atlas proxies.
335 // TODO: Determine how to instantatiate textues in this case; atlas proxies shouldn't really be
336 // "scratch" because they aren't going to be reused for anything else in a Recording. At the
337 // same time, it could still go through the ScratchResourceManager and just never return them,
338 // which is no different from instantiating them directly with the ResourceProvider.
339 if (!TextureProxy::InstantiateIfNotLazy(resourceProvider, fTextureProxy.get())) {
340 SKGPU_LOG_E("Could not instantiate texture proxy for UploadTask!");
341 return false;
342 }
343 return true;
344}
#define SKGPU_LOG_E(fmt,...)
Definition: Log.h:38
static bool InstantiateIfNotLazy(ResourceProvider *, TextureProxy *)

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