[graphite] Add buffer to texture copy support

Allows copying of multiple regions into a single texture, which supports
both filling mipLevels and rectangles in atlases.

Bug: skia:12845
Change-Id: I5fef9bda01125958a5491b4c5c8b3a66184357d2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/504056
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
Jim Van Verth 2022-02-03 16:01:34 -05:00 committed by SkCQ
parent 744116876e
commit 9907a8637c
5 changed files with 105 additions and 11 deletions

View File

@ -117,22 +117,13 @@ void CommandBuffer::bindSamplers(const SamplerBindEntry* entries, int count) {
}
}
static bool check_max_blit_width(int widthInPixels) {
if (widthInPixels > 32767) {
SkASSERT(false); // surfaces should not be this wide anyway
return false;
}
return true;
}
bool CommandBuffer::copyTextureToBuffer(sk_sp<skgpu::Texture> texture,
SkIRect srcRect,
sk_sp<skgpu::Buffer> buffer,
size_t bufferOffset,
size_t bufferRowBytes) {
if (!check_max_blit_width(srcRect.width())) {
return false;
}
SkASSERT(texture);
SkASSERT(buffer);
if (!this->onCopyTextureToBuffer(texture.get(), srcRect, buffer.get(), bufferOffset,
bufferRowBytes)) {
@ -147,4 +138,24 @@ bool CommandBuffer::copyTextureToBuffer(sk_sp<skgpu::Texture> texture,
return true;
}
bool CommandBuffer::copyBufferToTexture(sk_sp<skgpu::Buffer> buffer,
sk_sp<skgpu::Texture> texture,
const BufferTextureCopyData* copyData,
int count) {
SkASSERT(buffer);
SkASSERT(texture);
SkASSERT(count > 0 && copyData);
if (!this->onCopyBufferToTexture(buffer.get(), texture.get(), copyData, count)) {
return false;
}
this->trackResource(std::move(buffer));
this->trackResource(std::move(texture));
SkDEBUGCODE(fHasWork = true;)
return true;
}
} // namespace skgpu

View File

@ -144,6 +144,16 @@ public:
sk_sp<Buffer>,
size_t bufferOffset,
size_t bufferRowBytes);
struct BufferTextureCopyData {
size_t fBufferOffset;
size_t fBufferRowBytes;
SkIRect fRect;
unsigned int fMipLevel;
};
bool copyBufferToTexture(sk_sp<Buffer>,
sk_sp<Texture>,
const BufferTextureCopyData*,
int count);
protected:
CommandBuffer();
@ -193,6 +203,10 @@ private:
const Buffer*,
size_t bufferOffset,
size_t bufferRowBytes) = 0;
virtual bool onCopyBufferToTexture(const Buffer*,
const Texture*,
const BufferTextureCopyData*,
int count) = 0;
#ifdef SK_DEBUG
bool fHasWork = false;

View File

@ -58,6 +58,23 @@ public:
destinationBytesPerImage: bufferRowBytes * srcRect.height()];
}
void copyFromBuffer(id<MTLBuffer> buffer,
size_t bufferOffset,
size_t bufferRowBytes,
id<MTLTexture> texture,
SkIRect dstRect,
unsigned int dstLevel) {
[(*fCommandEncoder) copyFromBuffer: buffer
sourceOffset: bufferOffset
sourceBytesPerRow: bufferRowBytes
sourceBytesPerImage: bufferRowBytes * dstRect.height()
sourceSize: MTLSizeMake(dstRect.width(), dstRect.height(), 1)
toTexture: texture
destinationSlice: 0
destinationLevel: dstLevel
destinationOrigin: MTLOriginMake(dstRect.left(), dstRect.top(), 0)];
}
void endEncoding() {
[(*fCommandEncoder) endEncoding];
}

View File

@ -87,6 +87,10 @@ private:
const skgpu::Buffer*,
size_t bufferOffset,
size_t bufferRowBytes) override;
bool onCopyBufferToTexture(const skgpu::Buffer*,
const skgpu::Texture*,
const BufferTextureCopyData* copyData,
int count) override;
BlitCommandEncoder* getBlitCommandEncoder();
void endBlitCommandEncoder();

View File

@ -394,6 +394,14 @@ void CommandBuffer::onDrawIndexedInstanced(PrimitiveType type, unsigned int base
}
}
static bool check_max_blit_width(int widthInPixels) {
if (widthInPixels > 32767) {
SkASSERT(false); // surfaces should not be this wide anyway
return false;
}
return true;
}
bool CommandBuffer::onCopyTextureToBuffer(const skgpu::Texture* texture,
SkIRect srcRect,
const skgpu::Buffer* buffer,
@ -401,6 +409,10 @@ bool CommandBuffer::onCopyTextureToBuffer(const skgpu::Texture* texture,
size_t bufferRowBytes) {
SkASSERT(!fActiveRenderCommandEncoder);
if (!check_max_blit_width(srcRect.width())) {
return false;
}
id<MTLTexture> mtlTexture = static_cast<const Texture*>(texture)->mtlTexture();
id<MTLBuffer> mtlBuffer = static_cast<const Buffer*>(buffer)->mtlBuffer();
@ -426,5 +438,41 @@ bool CommandBuffer::onCopyTextureToBuffer(const skgpu::Texture* texture,
return true;
}
bool CommandBuffer::onCopyBufferToTexture(const skgpu::Buffer* buffer,
const skgpu::Texture* texture,
const BufferTextureCopyData* copyData,
int count) {
SkASSERT(!fActiveRenderCommandEncoder);
id<MTLBuffer> mtlBuffer = static_cast<const Buffer*>(buffer)->mtlBuffer();
id<MTLTexture> mtlTexture = static_cast<const Texture*>(texture)->mtlTexture();
BlitCommandEncoder* blitCmdEncoder = this->getBlitCommandEncoder();
if (!blitCmdEncoder) {
return false;
}
#ifdef SK_ENABLE_MTL_DEBUG_INFO
blitCmdEncoder->pushDebugGroup(@"uploadToTexture");
#endif
for (int i = 0; i < count; ++i) {
if (!check_max_blit_width(copyData[i].fRect.width())) {
return false;
}
blitCmdEncoder->copyFromBuffer(mtlBuffer,
copyData[i].fBufferOffset,
copyData[i].fBufferRowBytes,
mtlTexture,
copyData[i].fRect,
copyData[i].fMipLevel);
}
#ifdef SK_ENABLE_MTL_DEBUG_INFO
blitCmdEncoder->popDebugGroup();
#endif
return true;
}
} // namespace skgpu::mtl