From 9907a8637c50e51cca5e1ca1e21602ef79336816 Mon Sep 17 00:00:00 2001 From: Jim Van Verth Date: Thu, 3 Feb 2022 16:01:34 -0500 Subject: [PATCH] [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 Commit-Queue: Jim Van Verth --- experimental/graphite/src/CommandBuffer.cpp | 33 ++++++++----- experimental/graphite/src/CommandBuffer.h | 14 ++++++ .../graphite/src/mtl/MtlBlitCommandEncoder.h | 17 +++++++ .../graphite/src/mtl/MtlCommandBuffer.h | 4 ++ .../graphite/src/mtl/MtlCommandBuffer.mm | 48 +++++++++++++++++++ 5 files changed, 105 insertions(+), 11 deletions(-) diff --git a/experimental/graphite/src/CommandBuffer.cpp b/experimental/graphite/src/CommandBuffer.cpp index e96e6cf1db..460934d6be 100644 --- a/experimental/graphite/src/CommandBuffer.cpp +++ b/experimental/graphite/src/CommandBuffer.cpp @@ -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 texture, SkIRect srcRect, sk_sp 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 texture, return true; } +bool CommandBuffer::copyBufferToTexture(sk_sp buffer, + sk_sp 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 diff --git a/experimental/graphite/src/CommandBuffer.h b/experimental/graphite/src/CommandBuffer.h index 08ef70e290..adbd920a80 100644 --- a/experimental/graphite/src/CommandBuffer.h +++ b/experimental/graphite/src/CommandBuffer.h @@ -144,6 +144,16 @@ public: sk_sp, size_t bufferOffset, size_t bufferRowBytes); + struct BufferTextureCopyData { + size_t fBufferOffset; + size_t fBufferRowBytes; + SkIRect fRect; + unsigned int fMipLevel; + }; + bool copyBufferToTexture(sk_sp, + sk_sp, + 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; diff --git a/experimental/graphite/src/mtl/MtlBlitCommandEncoder.h b/experimental/graphite/src/mtl/MtlBlitCommandEncoder.h index f476596bd4..92dac6f22c 100644 --- a/experimental/graphite/src/mtl/MtlBlitCommandEncoder.h +++ b/experimental/graphite/src/mtl/MtlBlitCommandEncoder.h @@ -58,6 +58,23 @@ public: destinationBytesPerImage: bufferRowBytes * srcRect.height()]; } + void copyFromBuffer(id buffer, + size_t bufferOffset, + size_t bufferRowBytes, + id 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]; } diff --git a/experimental/graphite/src/mtl/MtlCommandBuffer.h b/experimental/graphite/src/mtl/MtlCommandBuffer.h index 80956143c8..11f822f6c1 100644 --- a/experimental/graphite/src/mtl/MtlCommandBuffer.h +++ b/experimental/graphite/src/mtl/MtlCommandBuffer.h @@ -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(); diff --git a/experimental/graphite/src/mtl/MtlCommandBuffer.mm b/experimental/graphite/src/mtl/MtlCommandBuffer.mm index 909928bbcb..297d5e01e3 100644 --- a/experimental/graphite/src/mtl/MtlCommandBuffer.mm +++ b/experimental/graphite/src/mtl/MtlCommandBuffer.mm @@ -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 = static_cast(texture)->mtlTexture(); id mtlBuffer = static_cast(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 = static_cast(buffer)->mtlBuffer(); + id mtlTexture = static_cast(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