Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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 343 of file UploadTask.cpp.

345 {
346 using Status = Task::Status;
347 SkASSERT(fTextureProxy && fTextureProxy->isInstantiated());
348
349 if (fConditionalContext && !fConditionalContext->needsUpload(context)) {
350 // Assume that if a conditional context says to dynamically not upload that another
351 // time through the tasks should try to upload again.
352 return Status::kSuccess;
353 }
354
355 if (fTextureProxy->texture() != replayData.fTarget) {
356 // The CommandBuffer doesn't take ownership of the upload buffer here; it's owned by
357 // UploadBufferManager, which will transfer ownership in transferToCommandBuffer.
358 if (!commandBuffer->copyBufferToTexture(fBuffer,
359 fTextureProxy->refTexture(),
360 fCopyData.data(),
361 fCopyData.size())) {
362 return Status::kFail;
363 }
364 } else {
365 // Here we assume that multiple copies in a single UploadInstance are always used for
366 // mipmaps of a single image, and that we won't ever copy to a replay target with mipmaps.
367 SkASSERT(fCopyData.size() == 1);
368 const BufferTextureCopyData& copyData = fCopyData[0];
369 SkIRect dstRect = copyData.fRect;
370 dstRect.offset(replayData.fTranslation);
371 SkIRect croppedDstRect = dstRect;
372 if (!croppedDstRect.intersect(SkIRect::MakeSize(fTextureProxy->dimensions()))) {
373 // The replay translation can change on each insert, so subsequent replays may
374 // actually intersect the copy rect.
375 return Status::kSuccess;
376 }
377
378 BufferTextureCopyData transformedCopyData = copyData;
379 transformedCopyData.fBufferOffset +=
380 (croppedDstRect.y() - dstRect.y()) * copyData.fBufferRowBytes +
381 (croppedDstRect.x() - dstRect.x()) * fBytesPerPixel;
382 transformedCopyData.fRect = croppedDstRect;
383
384 if (!commandBuffer->copyBufferToTexture(fBuffer,
385 fTextureProxy->refTexture(),
386 &transformedCopyData, 1)) {
387 return Status::kFail;
388 }
389 }
390
391 // The conditional context will return false if the upload should not happen anymore. If there's
392 // no context assume that the upload should always be executed on replay.
393 if (!fConditionalContext || fConditionalContext->uploadSubmitted()) {
394 return Status::kSuccess;
395 } else {
396 return Status::kDiscard;
397 }
398}
#define SkASSERT(cond)
Definition SkAssert.h:116
Task::Status Status
Definition TaskList.cpp:13
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}
#define SKGPU_LOG_W(fmt,...)
Definition Log.h:40
#define SkAssertResult(cond)
Definition SkAssert.h:123
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)
#define ATRACE_ANDROID_FRAMEWORK(fmt,...)
void alloc(const SkImageInfo &)
SkColorType colorType() const
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
UploadBufferManager * uploadBufferManager()
std::tuple< TextureUploadWriter, BindBufferInfo > getTextureUploadWriter(size_t requiredBytes, size_t requiredAlignment)
static UploadInstance Invalid()
Definition UploadTask.h:84
UploadInstance(UploadInstance &&)
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)
int32_t height
int32_t width
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
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)
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
FlPixelBufferTexturePrivate * priv
SkISize CompressedDimensionsInBlocks(SkTextureCompressionType type, SkISize baseDimensions)
size_t CompressedRowBytes(SkTextureCompressionType type, int width)
Mipmapped
Definition GpuTypes.h:53
SkISize CompressedDimensions(SkTextureCompressionType type, SkISize baseDimensions)
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

◆ 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 if (!fTextureProxy) {
333 SKGPU_LOG_E("No texture proxy specified for UploadTask");
334 return false;
335 }
336 if (!TextureProxy::InstantiateIfNotLazy(resourceProvider, fTextureProxy.get())) {
337 SKGPU_LOG_E("Could not instantiate texture proxy for UploadTask!");
338 return false;
339 }
340 return true;
341}
#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: