@@ -127,6 +127,10 @@ void ResourceCommandEncoder::copyTextureToBuffer(
127
127
assert (srcSubresource.mipLevelCount <= 1 );
128
128
129
129
auto encoder = m_commandBuffer->getMetalBlitCommandEncoder ();
130
+ auto & desc = *static_cast <TextureResourceImpl*>(src)->getDesc ();
131
+ const TextureResource::Extents mipSize = calcMipSize (desc.size , srcSubresource.mipLevel );
132
+ Size bytesPerImage = mipSize.height * dstRowStride;
133
+
130
134
encoder->copyFromTexture (
131
135
static_cast <TextureResourceImpl*>(src)->m_texture .get (),
132
136
srcSubresource.baseArrayLayer ,
@@ -136,7 +140,7 @@ void ResourceCommandEncoder::copyTextureToBuffer(
136
140
static_cast <BufferResourceImpl*>(dst)->m_buffer .get (),
137
141
dstOffset,
138
142
dstRowStride,
139
- dstSize );
143
+ extent. depth == 1 ? 0 : bytesPerImage );
140
144
}
141
145
142
146
void ResourceCommandEncoder::uploadBufferData (
@@ -156,7 +160,106 @@ void ResourceCommandEncoder::uploadTextureData(
156
160
ITextureResource::SubresourceData* subResourceData,
157
161
GfxCount subResourceDataCount)
158
162
{
159
- SLANG_UNIMPLEMENTED_X (" uploadTextureData" );
163
+ auto dstTexture = static_cast <TextureResourceImpl*>(dst);
164
+ auto & desc = *dstTexture->getDesc ();
165
+
166
+ // Calculate buffer size needed
167
+ Size bufferSize = 0 ;
168
+ FormatInfo sizeInfo;
169
+ gfxGetFormatInfo (desc.format , &sizeInfo);
170
+ MTL::PixelFormat pixelFormat = MetalUtil::translatePixelFormat (desc.format );
171
+ bool isCompressed = gfxIsCompressedFormat (desc.format );
172
+
173
+ Size rowAlignment =
174
+ isCompressed
175
+ ? 1
176
+ : m_commandBuffer->m_device ->m_device ->minimumLinearTextureAlignmentForPixelFormat (
177
+ pixelFormat);
178
+
179
+ for (GfxIndex i = 0 ; i < subResourceRange.mipLevelCount ; ++i)
180
+ {
181
+ GfxIndex currentLevel = subResourceRange.mipLevel + i;
182
+ const TextureResource::Extents mipSize = calcMipSize (desc.size , currentLevel);
183
+
184
+ auto rowSizeInBytes = (mipSize.width + sizeInfo.blockWidth - 1 ) / sizeInfo.blockWidth *
185
+ sizeInfo.blockSizeInBytes ;
186
+ rowSizeInBytes = (rowSizeInBytes + rowAlignment - 1 ) & ~(rowAlignment - 1 );
187
+
188
+ auto numRows = (mipSize.height + sizeInfo.blockHeight - 1 ) / sizeInfo.blockHeight ;
189
+ bufferSize += (rowSizeInBytes * numRows) * mipSize.depth ;
190
+ }
191
+ bufferSize *= subResourceRange.layerCount ;
192
+
193
+ // Create staging buffer
194
+ NS::SharedPtr<MTL::Buffer> stagingBuffer = NS::TransferPtr (
195
+ m_commandBuffer->m_device ->m_device ->newBuffer (bufferSize, MTL::ResourceStorageModeShared));
196
+
197
+ if (!stagingBuffer)
198
+ return ;
199
+
200
+ auto encoder = m_commandBuffer->getMetalBlitCommandEncoder ();
201
+ if (!encoder)
202
+ return ;
203
+
204
+ // Copy data to staging buffer and then to texture
205
+ Size bufferOffset = 0 ;
206
+ for (GfxIndex i = 0 ; i < subResourceRange.layerCount ; i++)
207
+ {
208
+ // We only allocate staging buffer with size of one slice.
209
+ GfxIndex currentSlice = subResourceRange.baseArrayLayer + i;
210
+ uint8_t * bufferData = (uint8_t *)stagingBuffer->contents ();
211
+ Size dstOffset = 0 ;
212
+
213
+ for (GfxIndex j = 0 ; j < subResourceRange.mipLevelCount ; j++)
214
+ {
215
+ GfxIndex currentLevel = subResourceRange.mipLevel + j;
216
+ const auto & subresourceData = subResourceData[j];
217
+ const TextureResource::Extents mipSize = calcMipSize (desc.size , currentLevel);
218
+
219
+ auto rowSizeInBytes = (mipSize.width + sizeInfo.blockWidth - 1 ) / sizeInfo.blockWidth *
220
+ sizeInfo.blockSizeInBytes ;
221
+ auto rowSizeInBytesAligned = (rowSizeInBytes + rowAlignment - 1 ) & ~(rowAlignment - 1 );
222
+
223
+ auto numRows = (mipSize.height + sizeInfo.blockHeight - 1 ) / sizeInfo.blockHeight ;
224
+
225
+ const uint8_t * srcData = (const uint8_t *)subresourceData.data ;
226
+ if (rowSizeInBytesAligned == rowSizeInBytes)
227
+ {
228
+ // If the row size is already aligned, we can copy the data directly.
229
+ memcpy (bufferData + dstOffset, srcData, rowSizeInBytes * numRows * mipSize.depth );
230
+ }
231
+ else
232
+ {
233
+ for (GfxIndex k = 0 ; k < mipSize.depth ; ++k)
234
+ {
235
+ for (GfxIndex row = 0 ; row < numRows; ++row)
236
+ {
237
+ // Copy data to staging buffer, note that the staging buffer has to have the
238
+ // same alignment as the texture while the src data doesn't have such
239
+ // requirement, therefore we have to copy the data row by row. We don't care
240
+ // about the content of the alignment padding.
241
+ memcpy (bufferData + dstOffset, srcData, rowSizeInBytes);
242
+ dstOffset += rowSizeInBytesAligned;
243
+ srcData += rowSizeInBytes;
244
+ }
245
+ }
246
+ }
247
+
248
+ // Copy from staging buffer to texture
249
+ encoder->copyFromBuffer (
250
+ stagingBuffer.get (),
251
+ bufferOffset,
252
+ rowSizeInBytesAligned,
253
+ rowSizeInBytesAligned * numRows,
254
+ MTL::Size (mipSize.width , mipSize.height , mipSize.depth ),
255
+ dstTexture->m_texture .get (),
256
+ currentSlice,
257
+ currentLevel,
258
+ MTL::Origin (offset.x , offset.y , offset.z ));
259
+
260
+ bufferOffset += rowSizeInBytes * numRows * mipSize.depth ;
261
+ }
262
+ }
160
263
}
161
264
162
265
void ResourceCommandEncoder::bufferBarrier (
0 commit comments