1 // Copyright 2019 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "dawn_native/d3d12/UtilsD3D12.h" 16 17 #include "common/Assert.h" 18 #include "dawn_native/Format.h" 19 #include "dawn_native/d3d12/BufferD3D12.h" 20 #include "dawn_native/d3d12/CommandRecordingContext.h" 21 #include "dawn_native/d3d12/D3D12Error.h" 22 #include "dawn_native/d3d12/DeviceD3D12.h" 23 24 #include <stringapiset.h> 25 26 namespace dawn_native { namespace d3d12 { 27 ConvertStringToWstring(const char * str)28 ResultOrError<std::wstring> ConvertStringToWstring(const char* str) { 29 size_t len = strlen(str); 30 if (len == 0) { 31 return std::wstring(); 32 } 33 int numChars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, len, nullptr, 0); 34 if (numChars == 0) { 35 return DAWN_INTERNAL_ERROR("Failed to convert string to wide string"); 36 } 37 std::wstring result; 38 result.resize(numChars); 39 int numConvertedChars = 40 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, len, &result[0], numChars); 41 if (numConvertedChars != numChars) { 42 return DAWN_INTERNAL_ERROR("Failed to convert string to wide string"); 43 } 44 return std::move(result); 45 } 46 ToD3D12ComparisonFunc(wgpu::CompareFunction func)47 D3D12_COMPARISON_FUNC ToD3D12ComparisonFunc(wgpu::CompareFunction func) { 48 switch (func) { 49 case wgpu::CompareFunction::Never: 50 return D3D12_COMPARISON_FUNC_NEVER; 51 case wgpu::CompareFunction::Less: 52 return D3D12_COMPARISON_FUNC_LESS; 53 case wgpu::CompareFunction::LessEqual: 54 return D3D12_COMPARISON_FUNC_LESS_EQUAL; 55 case wgpu::CompareFunction::Greater: 56 return D3D12_COMPARISON_FUNC_GREATER; 57 case wgpu::CompareFunction::GreaterEqual: 58 return D3D12_COMPARISON_FUNC_GREATER_EQUAL; 59 case wgpu::CompareFunction::Equal: 60 return D3D12_COMPARISON_FUNC_EQUAL; 61 case wgpu::CompareFunction::NotEqual: 62 return D3D12_COMPARISON_FUNC_NOT_EQUAL; 63 case wgpu::CompareFunction::Always: 64 return D3D12_COMPARISON_FUNC_ALWAYS; 65 66 case wgpu::CompareFunction::Undefined: 67 UNREACHABLE(); 68 } 69 } 70 ComputeTextureCopyLocationForTexture(const Texture * texture,uint32_t level,uint32_t layer,Aspect aspect)71 D3D12_TEXTURE_COPY_LOCATION ComputeTextureCopyLocationForTexture(const Texture* texture, 72 uint32_t level, 73 uint32_t layer, 74 Aspect aspect) { 75 D3D12_TEXTURE_COPY_LOCATION copyLocation; 76 copyLocation.pResource = texture->GetD3D12Resource(); 77 copyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; 78 copyLocation.SubresourceIndex = texture->GetSubresourceIndex(level, layer, aspect); 79 80 return copyLocation; 81 } 82 ComputeBufferLocationForCopyTextureRegion(const Texture * texture,ID3D12Resource * bufferResource,const Extent3D & bufferSize,const uint64_t offset,const uint32_t rowPitch,Aspect aspect)83 D3D12_TEXTURE_COPY_LOCATION ComputeBufferLocationForCopyTextureRegion( 84 const Texture* texture, 85 ID3D12Resource* bufferResource, 86 const Extent3D& bufferSize, 87 const uint64_t offset, 88 const uint32_t rowPitch, 89 Aspect aspect) { 90 D3D12_TEXTURE_COPY_LOCATION bufferLocation; 91 bufferLocation.pResource = bufferResource; 92 bufferLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; 93 bufferLocation.PlacedFootprint.Offset = offset; 94 bufferLocation.PlacedFootprint.Footprint.Format = 95 texture->GetD3D12CopyableSubresourceFormat(aspect); 96 bufferLocation.PlacedFootprint.Footprint.Width = bufferSize.width; 97 bufferLocation.PlacedFootprint.Footprint.Height = bufferSize.height; 98 bufferLocation.PlacedFootprint.Footprint.Depth = bufferSize.depthOrArrayLayers; 99 bufferLocation.PlacedFootprint.Footprint.RowPitch = rowPitch; 100 return bufferLocation; 101 } 102 ComputeD3D12BoxFromOffsetAndSize(const Origin3D & offset,const Extent3D & copySize)103 D3D12_BOX ComputeD3D12BoxFromOffsetAndSize(const Origin3D& offset, const Extent3D& copySize) { 104 D3D12_BOX sourceRegion; 105 sourceRegion.left = offset.x; 106 sourceRegion.top = offset.y; 107 sourceRegion.front = offset.z; 108 sourceRegion.right = offset.x + copySize.width; 109 sourceRegion.bottom = offset.y + copySize.height; 110 sourceRegion.back = offset.z + copySize.depthOrArrayLayers; 111 return sourceRegion; 112 } 113 IsTypeless(DXGI_FORMAT format)114 bool IsTypeless(DXGI_FORMAT format) { 115 // List generated from <dxgiformat.h> 116 switch (format) { 117 case DXGI_FORMAT_R32G32B32A32_TYPELESS: 118 case DXGI_FORMAT_R32G32B32_TYPELESS: 119 case DXGI_FORMAT_R16G16B16A16_TYPELESS: 120 case DXGI_FORMAT_R32G32_TYPELESS: 121 case DXGI_FORMAT_R32G8X24_TYPELESS: 122 case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: 123 case DXGI_FORMAT_R10G10B10A2_TYPELESS: 124 case DXGI_FORMAT_R8G8B8A8_TYPELESS: 125 case DXGI_FORMAT_R16G16_TYPELESS: 126 case DXGI_FORMAT_R32_TYPELESS: 127 case DXGI_FORMAT_R24G8_TYPELESS: 128 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: 129 case DXGI_FORMAT_R8G8_TYPELESS: 130 case DXGI_FORMAT_R16_TYPELESS: 131 case DXGI_FORMAT_R8_TYPELESS: 132 case DXGI_FORMAT_BC1_TYPELESS: 133 case DXGI_FORMAT_BC2_TYPELESS: 134 case DXGI_FORMAT_BC3_TYPELESS: 135 case DXGI_FORMAT_BC4_TYPELESS: 136 case DXGI_FORMAT_BC5_TYPELESS: 137 case DXGI_FORMAT_B8G8R8A8_TYPELESS: 138 case DXGI_FORMAT_B8G8R8X8_TYPELESS: 139 case DXGI_FORMAT_BC6H_TYPELESS: 140 case DXGI_FORMAT_BC7_TYPELESS: 141 return true; 142 default: 143 return false; 144 } 145 } 146 RecordCopyBufferToTextureFromTextureCopySplit(ID3D12GraphicsCommandList * commandList,const TextureCopySubresource & baseCopySplit,ID3D12Resource * bufferResource,uint64_t baseOffset,uint64_t bufferBytesPerRow,Texture * texture,uint32_t textureMiplevel,uint32_t textureLayer,Aspect aspect)147 void RecordCopyBufferToTextureFromTextureCopySplit(ID3D12GraphicsCommandList* commandList, 148 const TextureCopySubresource& baseCopySplit, 149 ID3D12Resource* bufferResource, 150 uint64_t baseOffset, 151 uint64_t bufferBytesPerRow, 152 Texture* texture, 153 uint32_t textureMiplevel, 154 uint32_t textureLayer, 155 Aspect aspect) { 156 ASSERT(HasOneBit(aspect)); 157 const D3D12_TEXTURE_COPY_LOCATION textureLocation = 158 ComputeTextureCopyLocationForTexture(texture, textureMiplevel, textureLayer, aspect); 159 160 for (uint32_t i = 0; i < baseCopySplit.count; ++i) { 161 const TextureCopySubresource::CopyInfo& info = baseCopySplit.copies[i]; 162 163 // TODO(jiawei.shao@intel.com): pre-compute bufferLocation and sourceRegion as 164 // members in TextureCopySubresource::CopyInfo. 165 const uint64_t offsetBytes = info.alignedOffset + baseOffset; 166 const D3D12_TEXTURE_COPY_LOCATION bufferLocation = 167 ComputeBufferLocationForCopyTextureRegion(texture, bufferResource, info.bufferSize, 168 offsetBytes, bufferBytesPerRow, aspect); 169 const D3D12_BOX sourceRegion = 170 ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize); 171 172 commandList->CopyTextureRegion(&textureLocation, info.textureOffset.x, 173 info.textureOffset.y, info.textureOffset.z, 174 &bufferLocation, &sourceRegion); 175 } 176 } 177 CopyBufferTo2DTextureWithCopySplit(CommandRecordingContext * commandContext,const TextureCopy & textureCopy,ID3D12Resource * bufferResource,const uint64_t offset,const uint32_t bytesPerRow,const uint32_t rowsPerImage,const Extent3D & copySize,Texture * texture,Aspect aspect)178 void CopyBufferTo2DTextureWithCopySplit(CommandRecordingContext* commandContext, 179 const TextureCopy& textureCopy, 180 ID3D12Resource* bufferResource, 181 const uint64_t offset, 182 const uint32_t bytesPerRow, 183 const uint32_t rowsPerImage, 184 const Extent3D& copySize, 185 Texture* texture, 186 Aspect aspect) { 187 ASSERT(HasOneBit(aspect)); 188 // See comments in Compute2DTextureCopySplits() for more details. 189 const TexelBlockInfo& blockInfo = texture->GetFormat().GetAspectInfo(aspect).block; 190 const TextureCopySplits copySplits = Compute2DTextureCopySplits( 191 textureCopy.origin, copySize, blockInfo, offset, bytesPerRow, rowsPerImage); 192 193 const uint64_t bytesPerLayer = bytesPerRow * rowsPerImage; 194 195 // copySplits.copySubresources[1] is always calculated for the second copy layer with 196 // extra "bytesPerLayer" copy offset compared with the first copy layer. So 197 // here we use an array bufferOffsetsForNextLayer to record the extra offsets 198 // for each copy layer: bufferOffsetsForNextLayer[0] is the extra offset for 199 // the next copy layer that uses copySplits.copySubresources[0], and 200 // bufferOffsetsForNextLayer[1] is the extra offset for the next copy layer 201 // that uses copySplits.copySubresources[1]. 202 std::array<uint64_t, TextureCopySplits::kMaxTextureCopySubresources> 203 bufferOffsetsForNextLayer = {{0u, 0u}}; 204 205 for (uint32_t copyLayer = 0; copyLayer < copySize.depthOrArrayLayers; ++copyLayer) { 206 const uint32_t splitIndex = copyLayer % copySplits.copySubresources.size(); 207 208 const TextureCopySubresource& copySplitPerLayerBase = 209 copySplits.copySubresources[splitIndex]; 210 const uint64_t bufferOffsetForNextLayer = bufferOffsetsForNextLayer[splitIndex]; 211 const uint32_t copyTextureLayer = copyLayer + textureCopy.origin.z; 212 213 RecordCopyBufferToTextureFromTextureCopySplit( 214 commandContext->GetCommandList(), copySplitPerLayerBase, bufferResource, 215 bufferOffsetForNextLayer, bytesPerRow, texture, textureCopy.mipLevel, 216 copyTextureLayer, aspect); 217 218 bufferOffsetsForNextLayer[splitIndex] += 219 bytesPerLayer * copySplits.copySubresources.size(); 220 } 221 } 222 CopyBufferTo3DTexture(CommandRecordingContext * commandContext,const TextureCopy & textureCopy,ID3D12Resource * bufferResource,const uint64_t offset,const uint32_t bytesPerRow,const uint32_t rowsPerImage,const Extent3D & copySize,Texture * texture,Aspect aspect)223 void CopyBufferTo3DTexture(CommandRecordingContext* commandContext, 224 const TextureCopy& textureCopy, 225 ID3D12Resource* bufferResource, 226 const uint64_t offset, 227 const uint32_t bytesPerRow, 228 const uint32_t rowsPerImage, 229 const Extent3D& copySize, 230 Texture* texture, 231 Aspect aspect) { 232 ASSERT(HasOneBit(aspect)); 233 // See comments in Compute3DTextureCopySplits() for more details. 234 const TexelBlockInfo& blockInfo = texture->GetFormat().GetAspectInfo(aspect).block; 235 const TextureCopySubresource copyRegions = Compute3DTextureCopySplits( 236 textureCopy.origin, copySize, blockInfo, offset, bytesPerRow, rowsPerImage); 237 238 RecordCopyBufferToTextureFromTextureCopySplit(commandContext->GetCommandList(), copyRegions, 239 bufferResource, 0, bytesPerRow, texture, 240 textureCopy.mipLevel, 0, aspect); 241 } 242 RecordCopyBufferToTexture(CommandRecordingContext * commandContext,const TextureCopy & textureCopy,ID3D12Resource * bufferResource,const uint64_t offset,const uint32_t bytesPerRow,const uint32_t rowsPerImage,const Extent3D & copySize,Texture * texture,Aspect aspect)243 void RecordCopyBufferToTexture(CommandRecordingContext* commandContext, 244 const TextureCopy& textureCopy, 245 ID3D12Resource* bufferResource, 246 const uint64_t offset, 247 const uint32_t bytesPerRow, 248 const uint32_t rowsPerImage, 249 const Extent3D& copySize, 250 Texture* texture, 251 Aspect aspect) { 252 // Record the CopyTextureRegion commands for 3D textures. Multiple depths of 3D 253 // textures can be copied in one shot and copySplits are not needed. 254 if (texture->GetDimension() == wgpu::TextureDimension::e3D) { 255 CopyBufferTo3DTexture(commandContext, textureCopy, bufferResource, offset, bytesPerRow, 256 rowsPerImage, copySize, texture, aspect); 257 } else { 258 // Compute the copySplits and record the CopyTextureRegion commands for 2D 259 // textures. 260 CopyBufferTo2DTextureWithCopySplit(commandContext, textureCopy, bufferResource, offset, 261 bytesPerRow, rowsPerImage, copySize, texture, 262 aspect); 263 } 264 } 265 RecordCopyTextureToBufferFromTextureCopySplit(ID3D12GraphicsCommandList * commandList,const TextureCopySubresource & baseCopySplit,Buffer * buffer,uint64_t baseOffset,uint64_t bufferBytesPerRow,Texture * texture,uint32_t textureMiplevel,uint32_t textureLayer,Aspect aspect)266 void RecordCopyTextureToBufferFromTextureCopySplit(ID3D12GraphicsCommandList* commandList, 267 const TextureCopySubresource& baseCopySplit, 268 Buffer* buffer, 269 uint64_t baseOffset, 270 uint64_t bufferBytesPerRow, 271 Texture* texture, 272 uint32_t textureMiplevel, 273 uint32_t textureLayer, 274 Aspect aspect) { 275 const D3D12_TEXTURE_COPY_LOCATION textureLocation = 276 ComputeTextureCopyLocationForTexture(texture, textureMiplevel, textureLayer, aspect); 277 278 for (uint32_t i = 0; i < baseCopySplit.count; ++i) { 279 const TextureCopySubresource::CopyInfo& info = baseCopySplit.copies[i]; 280 281 // TODO(jiawei.shao@intel.com): pre-compute bufferLocation and sourceRegion as 282 // members in TextureCopySubresource::CopyInfo. 283 const uint64_t offsetBytes = info.alignedOffset + baseOffset; 284 const D3D12_TEXTURE_COPY_LOCATION bufferLocation = 285 ComputeBufferLocationForCopyTextureRegion(texture, buffer->GetD3D12Resource(), 286 info.bufferSize, offsetBytes, 287 bufferBytesPerRow, aspect); 288 const D3D12_BOX sourceRegion = 289 ComputeD3D12BoxFromOffsetAndSize(info.textureOffset, info.copySize); 290 291 commandList->CopyTextureRegion(&bufferLocation, info.bufferOffset.x, 292 info.bufferOffset.y, info.bufferOffset.z, 293 &textureLocation, &sourceRegion); 294 } 295 } 296 Copy2DTextureToBufferWithCopySplit(ID3D12GraphicsCommandList * commandList,const TextureCopy & textureCopy,const BufferCopy & bufferCopy,Texture * texture,Buffer * buffer,const Extent3D & copySize)297 void Copy2DTextureToBufferWithCopySplit(ID3D12GraphicsCommandList* commandList, 298 const TextureCopy& textureCopy, 299 const BufferCopy& bufferCopy, 300 Texture* texture, 301 Buffer* buffer, 302 const Extent3D& copySize) { 303 ASSERT(HasOneBit(textureCopy.aspect)); 304 const TexelBlockInfo& blockInfo = 305 texture->GetFormat().GetAspectInfo(textureCopy.aspect).block; 306 307 // See comments around Compute2DTextureCopySplits() for more details. 308 const TextureCopySplits copySplits = 309 Compute2DTextureCopySplits(textureCopy.origin, copySize, blockInfo, bufferCopy.offset, 310 bufferCopy.bytesPerRow, bufferCopy.rowsPerImage); 311 312 const uint64_t bytesPerLayer = bufferCopy.bytesPerRow * bufferCopy.rowsPerImage; 313 314 // copySplits.copySubresources[1] is always calculated for the second copy layer with 315 // extra "bytesPerLayer" copy offset compared with the first copy layer. So 316 // here we use an array bufferOffsetsForNextLayer to record the extra offsets 317 // for each copy layer: bufferOffsetsForNextLayer[0] is the extra offset for 318 // the next copy layer that uses copySplits.copySubresources[0], and 319 // bufferOffsetsForNextLayer[1] is the extra offset for the next copy layer 320 // that uses copySplits.copySubresources[1]. 321 std::array<uint64_t, TextureCopySplits::kMaxTextureCopySubresources> 322 bufferOffsetsForNextLayer = {{0u, 0u}}; 323 for (uint32_t copyLayer = 0; copyLayer < copySize.depthOrArrayLayers; ++copyLayer) { 324 const uint32_t splitIndex = copyLayer % copySplits.copySubresources.size(); 325 326 const TextureCopySubresource& copySplitPerLayerBase = 327 copySplits.copySubresources[splitIndex]; 328 const uint64_t bufferOffsetForNextLayer = bufferOffsetsForNextLayer[splitIndex]; 329 const uint32_t copyTextureLayer = copyLayer + textureCopy.origin.z; 330 331 RecordCopyTextureToBufferFromTextureCopySplit( 332 commandList, copySplitPerLayerBase, buffer, bufferOffsetForNextLayer, 333 bufferCopy.bytesPerRow, texture, textureCopy.mipLevel, copyTextureLayer, 334 textureCopy.aspect); 335 336 bufferOffsetsForNextLayer[splitIndex] += 337 bytesPerLayer * copySplits.copySubresources.size(); 338 } 339 } 340 Copy3DTextureToBuffer(ID3D12GraphicsCommandList * commandList,const TextureCopy & textureCopy,const BufferCopy & bufferCopy,Texture * texture,Buffer * buffer,const Extent3D & copySize)341 void Copy3DTextureToBuffer(ID3D12GraphicsCommandList* commandList, 342 const TextureCopy& textureCopy, 343 const BufferCopy& bufferCopy, 344 Texture* texture, 345 Buffer* buffer, 346 const Extent3D& copySize) { 347 ASSERT(HasOneBit(textureCopy.aspect)); 348 const TexelBlockInfo& blockInfo = 349 texture->GetFormat().GetAspectInfo(textureCopy.aspect).block; 350 351 // See comments around Compute3DTextureCopySplits() for more details. 352 const TextureCopySubresource copyRegions = 353 Compute3DTextureCopySplits(textureCopy.origin, copySize, blockInfo, bufferCopy.offset, 354 bufferCopy.bytesPerRow, bufferCopy.rowsPerImage); 355 356 RecordCopyTextureToBufferFromTextureCopySplit(commandList, copyRegions, buffer, 0, 357 bufferCopy.bytesPerRow, texture, 358 textureCopy.mipLevel, 0, textureCopy.aspect); 359 } 360 RecordCopyTextureToBuffer(ID3D12GraphicsCommandList * commandList,const TextureCopy & textureCopy,const BufferCopy & bufferCopy,Texture * texture,Buffer * buffer,const Extent3D & copySize)361 void RecordCopyTextureToBuffer(ID3D12GraphicsCommandList* commandList, 362 const TextureCopy& textureCopy, 363 const BufferCopy& bufferCopy, 364 Texture* texture, 365 Buffer* buffer, 366 const Extent3D& copySize) { 367 if (texture->GetDimension() == wgpu::TextureDimension::e3D) { 368 Copy3DTextureToBuffer(commandList, textureCopy, bufferCopy, texture, buffer, copySize); 369 } else { 370 Copy2DTextureToBufferWithCopySplit(commandList, textureCopy, bufferCopy, texture, 371 buffer, copySize); 372 } 373 } 374 SetDebugName(Device * device,ID3D12Object * object,const char * prefix,std::string label)375 void SetDebugName(Device* device, ID3D12Object* object, const char* prefix, std::string label) { 376 if (!object) { 377 return; 378 } 379 380 if (label.empty() || !device->IsToggleEnabled(Toggle::UseUserDefinedLabelsInBackend)) { 381 object->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(prefix), prefix); 382 return; 383 } 384 385 std::string objectName = prefix; 386 objectName += "_"; 387 objectName += label; 388 object->SetPrivateData(WKPDID_D3DDebugObjectName, objectName.length(), objectName.c_str()); 389 } 390 391 }} // namespace dawn_native::d3d12 392