• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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