summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/gfx/metal/metal-command-encoder.cpp107
-rw-r--r--tools/gfx/metal/metal-device.cpp4
2 files changed, 108 insertions, 3 deletions
diff --git a/tools/gfx/metal/metal-command-encoder.cpp b/tools/gfx/metal/metal-command-encoder.cpp
index cd6682172..92314fa99 100644
--- a/tools/gfx/metal/metal-command-encoder.cpp
+++ b/tools/gfx/metal/metal-command-encoder.cpp
@@ -127,6 +127,10 @@ void ResourceCommandEncoder::copyTextureToBuffer(
assert(srcSubresource.mipLevelCount <= 1);
auto encoder = m_commandBuffer->getMetalBlitCommandEncoder();
+ auto& desc = *static_cast<TextureResourceImpl*>(src)->getDesc();
+ const TextureResource::Extents mipSize = calcMipSize(desc.size, srcSubresource.mipLevel);
+ Size bytesPerImage = mipSize.height * dstRowStride;
+
encoder->copyFromTexture(
static_cast<TextureResourceImpl*>(src)->m_texture.get(),
srcSubresource.baseArrayLayer,
@@ -136,7 +140,7 @@ void ResourceCommandEncoder::copyTextureToBuffer(
static_cast<BufferResourceImpl*>(dst)->m_buffer.get(),
dstOffset,
dstRowStride,
- dstSize);
+ extent.depth == 1 ? 0 : bytesPerImage);
}
void ResourceCommandEncoder::uploadBufferData(
@@ -156,7 +160,106 @@ void ResourceCommandEncoder::uploadTextureData(
ITextureResource::SubresourceData* subResourceData,
GfxCount subResourceDataCount)
{
- SLANG_UNIMPLEMENTED_X("uploadTextureData");
+ auto dstTexture = static_cast<TextureResourceImpl*>(dst);
+ auto& desc = *dstTexture->getDesc();
+
+ // Calculate buffer size needed
+ Size bufferSize = 0;
+ FormatInfo sizeInfo;
+ gfxGetFormatInfo(desc.format, &sizeInfo);
+ MTL::PixelFormat pixelFormat = MetalUtil::translatePixelFormat(desc.format);
+ bool isCompressed = gfxIsCompressedFormat(desc.format);
+
+ Size rowAlignment =
+ isCompressed
+ ? 1
+ : m_commandBuffer->m_device->m_device->minimumLinearTextureAlignmentForPixelFormat(
+ pixelFormat);
+
+ for (GfxIndex i = 0; i < subResourceRange.mipLevelCount; ++i)
+ {
+ GfxIndex currentLevel = subResourceRange.mipLevel + i;
+ const TextureResource::Extents mipSize = calcMipSize(desc.size, currentLevel);
+
+ auto rowSizeInBytes = (mipSize.width + sizeInfo.blockWidth - 1) / sizeInfo.blockWidth *
+ sizeInfo.blockSizeInBytes;
+ rowSizeInBytes = (rowSizeInBytes + rowAlignment - 1) & ~(rowAlignment - 1);
+
+ auto numRows = (mipSize.height + sizeInfo.blockHeight - 1) / sizeInfo.blockHeight;
+ bufferSize += (rowSizeInBytes * numRows) * mipSize.depth;
+ }
+ bufferSize *= subResourceRange.layerCount;
+
+ // Create staging buffer
+ NS::SharedPtr<MTL::Buffer> stagingBuffer = NS::TransferPtr(
+ m_commandBuffer->m_device->m_device->newBuffer(bufferSize, MTL::ResourceStorageModeShared));
+
+ if (!stagingBuffer)
+ return;
+
+ auto encoder = m_commandBuffer->getMetalBlitCommandEncoder();
+ if (!encoder)
+ return;
+
+ // Copy data to staging buffer and then to texture
+ Size bufferOffset = 0;
+ for (GfxIndex i = 0; i < subResourceRange.layerCount; i++)
+ {
+ // We only allocate staging buffer with size of one slice.
+ GfxIndex currentSlice = subResourceRange.baseArrayLayer + i;
+ uint8_t* bufferData = (uint8_t*)stagingBuffer->contents();
+ Size dstOffset = 0;
+
+ for (GfxIndex j = 0; j < subResourceRange.mipLevelCount; j++)
+ {
+ GfxIndex currentLevel = subResourceRange.mipLevel + j;
+ const auto& subresourceData = subResourceData[j];
+ const TextureResource::Extents mipSize = calcMipSize(desc.size, currentLevel);
+
+ auto rowSizeInBytes = (mipSize.width + sizeInfo.blockWidth - 1) / sizeInfo.blockWidth *
+ sizeInfo.blockSizeInBytes;
+ auto rowSizeInBytesAligned = (rowSizeInBytes + rowAlignment - 1) & ~(rowAlignment - 1);
+
+ auto numRows = (mipSize.height + sizeInfo.blockHeight - 1) / sizeInfo.blockHeight;
+
+ const uint8_t* srcData = (const uint8_t*)subresourceData.data;
+ if (rowSizeInBytesAligned == rowSizeInBytes)
+ {
+ // If the row size is already aligned, we can copy the data directly.
+ memcpy(bufferData + dstOffset, srcData, rowSizeInBytes * numRows * mipSize.depth);
+ }
+ else
+ {
+ for (GfxIndex k = 0; k < mipSize.depth; ++k)
+ {
+ for (GfxIndex row = 0; row < numRows; ++row)
+ {
+ // Copy data to staging buffer, note that the staging buffer has to have the
+ // same alignment as the texture while the src data doesn't have such
+ // requirement, therefore we have to copy the data row by row. We don't care
+ // about the content of the alignment padding.
+ memcpy(bufferData + dstOffset, srcData, rowSizeInBytes);
+ dstOffset += rowSizeInBytesAligned;
+ srcData += rowSizeInBytes;
+ }
+ }
+ }
+
+ // Copy from staging buffer to texture
+ encoder->copyFromBuffer(
+ stagingBuffer.get(),
+ bufferOffset,
+ rowSizeInBytesAligned,
+ rowSizeInBytesAligned * numRows,
+ MTL::Size(mipSize.width, mipSize.height, mipSize.depth),
+ dstTexture->m_texture.get(),
+ currentSlice,
+ currentLevel,
+ MTL::Origin(offset.x, offset.y, offset.z));
+
+ bufferOffset += rowSizeInBytes * numRows * mipSize.depth;
+ }
+ }
}
void ResourceCommandEncoder::bufferBarrier(
diff --git a/tools/gfx/metal/metal-device.cpp b/tools/gfx/metal/metal-device.cpp
index 34b00d0dd..90904e0e2 100644
--- a/tools/gfx/metal/metal-device.cpp
+++ b/tools/gfx/metal/metal-device.cpp
@@ -331,7 +331,9 @@ Result DeviceImpl::getTextureAllocationInfo(
FormatInfo formatInfo;
gfxGetFormatInfo(desc.format, &formatInfo);
MTL::PixelFormat pixelFormat = MetalUtil::translatePixelFormat(desc.format);
- Size alignment = m_device->minimumLinearTextureAlignmentForPixelFormat(pixelFormat);
+ bool isCompressed = gfxIsCompressedFormat(desc.format);
+ Size alignment =
+ isCompressed ? 1 : m_device->minimumLinearTextureAlignmentForPixelFormat(pixelFormat);
Size size = 0;
ITextureResource::Extents extents = desc.size;
extents.width = extents.width ? extents.width : 1;