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/vulkan/UtilsVulkan.h"
16 
17 #include "common/Assert.h"
18 #include "dawn_native/EnumMaskIterator.h"
19 #include "dawn_native/Format.h"
20 #include "dawn_native/Pipeline.h"
21 #include "dawn_native/ShaderModule.h"
22 #include "dawn_native/vulkan/DeviceVk.h"
23 #include "dawn_native/vulkan/Forward.h"
24 #include "dawn_native/vulkan/TextureVk.h"
25 #include "dawn_native/vulkan/VulkanError.h"
26 
27 namespace dawn_native { namespace vulkan {
28 
ToVulkanCompareOp(wgpu::CompareFunction op)29     VkCompareOp ToVulkanCompareOp(wgpu::CompareFunction op) {
30         switch (op) {
31             case wgpu::CompareFunction::Never:
32                 return VK_COMPARE_OP_NEVER;
33             case wgpu::CompareFunction::Less:
34                 return VK_COMPARE_OP_LESS;
35             case wgpu::CompareFunction::LessEqual:
36                 return VK_COMPARE_OP_LESS_OR_EQUAL;
37             case wgpu::CompareFunction::Greater:
38                 return VK_COMPARE_OP_GREATER;
39             case wgpu::CompareFunction::GreaterEqual:
40                 return VK_COMPARE_OP_GREATER_OR_EQUAL;
41             case wgpu::CompareFunction::Equal:
42                 return VK_COMPARE_OP_EQUAL;
43             case wgpu::CompareFunction::NotEqual:
44                 return VK_COMPARE_OP_NOT_EQUAL;
45             case wgpu::CompareFunction::Always:
46                 return VK_COMPARE_OP_ALWAYS;
47 
48             case wgpu::CompareFunction::Undefined:
49                 break;
50         }
51         UNREACHABLE();
52     }
53 
54     // Convert Dawn texture aspects to  Vulkan texture aspect flags
VulkanAspectMask(const Aspect& aspects)55     VkImageAspectFlags VulkanAspectMask(const Aspect& aspects) {
56         VkImageAspectFlags flags = 0;
57         for (Aspect aspect : IterateEnumMask(aspects)) {
58             switch (aspect) {
59                 case Aspect::Color:
60                     flags |= VK_IMAGE_ASPECT_COLOR_BIT;
61                     break;
62                 case Aspect::Depth:
63                     flags |= VK_IMAGE_ASPECT_DEPTH_BIT;
64                     break;
65                 case Aspect::Stencil:
66                     flags |= VK_IMAGE_ASPECT_STENCIL_BIT;
67                     break;
68 
69                 case Aspect::CombinedDepthStencil:
70                     flags |= VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
71                     break;
72 
73                 case Aspect::Plane0:
74                 case Aspect::Plane1:
75                 case Aspect::None:
76                     UNREACHABLE();
77             }
78         }
79         return flags;
80     }
81 
82     // Vulkan SPEC requires the source/destination region specified by each element of
83     // pRegions must be a region that is contained within srcImage/dstImage. Here the size of
84     // the image refers to the virtual size, while Dawn validates texture copy extent with the
85     // physical size, so we need to re-calculate the texture copy extent to ensure it should fit
86     // in the virtual size of the subresource.
ComputeTextureCopyExtent(const TextureCopy& textureCopy, const Extent3D& copySize)87     Extent3D ComputeTextureCopyExtent(const TextureCopy& textureCopy, const Extent3D& copySize) {
88         Extent3D validTextureCopyExtent = copySize;
89         const TextureBase* texture = textureCopy.texture.Get();
90         Extent3D virtualSizeAtLevel = texture->GetMipLevelVirtualSize(textureCopy.mipLevel);
91         ASSERT(textureCopy.origin.x <= virtualSizeAtLevel.width);
92         ASSERT(textureCopy.origin.y <= virtualSizeAtLevel.height);
93         if (copySize.width > virtualSizeAtLevel.width - textureCopy.origin.x) {
94             ASSERT(texture->GetFormat().isCompressed);
95             validTextureCopyExtent.width = virtualSizeAtLevel.width - textureCopy.origin.x;
96         }
97         if (copySize.height > virtualSizeAtLevel.height - textureCopy.origin.y) {
98             ASSERT(texture->GetFormat().isCompressed);
99             validTextureCopyExtent.height = virtualSizeAtLevel.height - textureCopy.origin.y;
100         }
101 
102         return validTextureCopyExtent;
103     }
104 
ComputeBufferImageCopyRegion(const BufferCopy& bufferCopy, const TextureCopy& textureCopy, const Extent3D& copySize)105     VkBufferImageCopy ComputeBufferImageCopyRegion(const BufferCopy& bufferCopy,
106                                                    const TextureCopy& textureCopy,
107                                                    const Extent3D& copySize) {
108         TextureDataLayout passDataLayout;
109         passDataLayout.offset = bufferCopy.offset;
110         passDataLayout.rowsPerImage = bufferCopy.rowsPerImage;
111         passDataLayout.bytesPerRow = bufferCopy.bytesPerRow;
112         return ComputeBufferImageCopyRegion(passDataLayout, textureCopy, copySize);
113     }
114 
ComputeBufferImageCopyRegion(const TextureDataLayout& dataLayout, const TextureCopy& textureCopy, const Extent3D& copySize)115     VkBufferImageCopy ComputeBufferImageCopyRegion(const TextureDataLayout& dataLayout,
116                                                    const TextureCopy& textureCopy,
117                                                    const Extent3D& copySize) {
118         const Texture* texture = ToBackend(textureCopy.texture.Get());
119 
120         VkBufferImageCopy region;
121 
122         region.bufferOffset = dataLayout.offset;
123         // In Vulkan the row length is in texels while it is in bytes for Dawn
124         const TexelBlockInfo& blockInfo =
125             texture->GetFormat().GetAspectInfo(textureCopy.aspect).block;
126         ASSERT(dataLayout.bytesPerRow % blockInfo.byteSize == 0);
127         region.bufferRowLength = dataLayout.bytesPerRow / blockInfo.byteSize * blockInfo.width;
128         region.bufferImageHeight = dataLayout.rowsPerImage * blockInfo.height;
129 
130         region.imageSubresource.aspectMask = VulkanAspectMask(textureCopy.aspect);
131         region.imageSubresource.mipLevel = textureCopy.mipLevel;
132 
133         switch (textureCopy.texture->GetDimension()) {
134             case wgpu::TextureDimension::e2D: {
135                 region.imageOffset.x = textureCopy.origin.x;
136                 region.imageOffset.y = textureCopy.origin.y;
137                 region.imageOffset.z = 0;
138 
139                 region.imageSubresource.baseArrayLayer = textureCopy.origin.z;
140                 region.imageSubresource.layerCount = copySize.depthOrArrayLayers;
141 
142                 Extent3D imageExtent = ComputeTextureCopyExtent(textureCopy, copySize);
143                 region.imageExtent.width = imageExtent.width;
144                 region.imageExtent.height = imageExtent.height;
145                 region.imageExtent.depth = 1;
146                 break;
147             }
148 
149             case wgpu::TextureDimension::e3D: {
150                 region.imageOffset.x = textureCopy.origin.x;
151                 region.imageOffset.y = textureCopy.origin.y;
152                 region.imageOffset.z = textureCopy.origin.z;
153 
154                 region.imageSubresource.baseArrayLayer = 0;
155                 region.imageSubresource.layerCount = 1;
156 
157                 Extent3D imageExtent = ComputeTextureCopyExtent(textureCopy, copySize);
158                 region.imageExtent.width = imageExtent.width;
159                 region.imageExtent.height = imageExtent.height;
160                 region.imageExtent.depth = imageExtent.depthOrArrayLayers;
161                 break;
162             }
163 
164             case wgpu::TextureDimension::e1D:
165                 UNREACHABLE();
166         }
167 
168         return region;
169     }
170 
SetDebugName(Device* device, VkObjectType objectType, uint64_t objectHandle, const char* prefix, std::string label)171     void SetDebugName(Device* device,
172                       VkObjectType objectType,
173                       uint64_t objectHandle,
174                       const char* prefix,
175                       std::string label) {
176         if (!objectHandle) {
177             return;
178         }
179 
180         if (device->GetGlobalInfo().HasExt(InstanceExt::DebugUtils)) {
181             VkDebugUtilsObjectNameInfoEXT objectNameInfo;
182             objectNameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
183             objectNameInfo.pNext = nullptr;
184             objectNameInfo.objectType = objectType;
185             objectNameInfo.objectHandle = objectHandle;
186 
187             if (label.empty() || !device->IsToggleEnabled(Toggle::UseUserDefinedLabelsInBackend)) {
188                 objectNameInfo.pObjectName = prefix;
189                 device->fn.SetDebugUtilsObjectNameEXT(device->GetVkDevice(), &objectNameInfo);
190                 return;
191             }
192 
193             std::string objectName = prefix;
194             objectName += "_";
195             objectName += label;
196             objectNameInfo.pObjectName = objectName.c_str();
197             device->fn.SetDebugUtilsObjectNameEXT(device->GetVkDevice(), &objectNameInfo);
198         }
199     }
200 
GetVkSpecializationInfo( const ProgrammableStage& programmableStage, VkSpecializationInfo* specializationInfo, std::vector<OverridableConstantScalar>* specializationDataEntries, std::vector<VkSpecializationMapEntry>* specializationMapEntries)201     VkSpecializationInfo* GetVkSpecializationInfo(
202         const ProgrammableStage& programmableStage,
203         VkSpecializationInfo* specializationInfo,
204         std::vector<OverridableConstantScalar>* specializationDataEntries,
205         std::vector<VkSpecializationMapEntry>* specializationMapEntries) {
206         ASSERT(specializationInfo);
207         ASSERT(specializationDataEntries);
208         ASSERT(specializationMapEntries);
209 
210         if (programmableStage.constants.size() == 0) {
211             return nullptr;
212         }
213 
214         const EntryPointMetadata& entryPointMetaData =
215             programmableStage.module->GetEntryPoint(programmableStage.entryPoint);
216 
217         for (const auto& pipelineConstant : programmableStage.constants) {
218             const std::string& identifier = pipelineConstant.first;
219             double value = pipelineConstant.second;
220 
221             // This is already validated so `identifier` must exist
222             const auto& moduleConstant = entryPointMetaData.overridableConstants.at(identifier);
223 
224             specializationMapEntries->push_back(
225                 VkSpecializationMapEntry{moduleConstant.id,
226                                          static_cast<uint32_t>(specializationDataEntries->size() *
227                                                                sizeof(OverridableConstantScalar)),
228                                          sizeof(OverridableConstantScalar)});
229 
230             OverridableConstantScalar entry{};
231             switch (moduleConstant.type) {
232                 case EntryPointMetadata::OverridableConstant::Type::Boolean:
233                     entry.b = static_cast<int32_t>(value);
234                     break;
235                 case EntryPointMetadata::OverridableConstant::Type::Float32:
236                     entry.f32 = static_cast<float>(value);
237                     break;
238                 case EntryPointMetadata::OverridableConstant::Type::Int32:
239                     entry.i32 = static_cast<int32_t>(value);
240                     break;
241                 case EntryPointMetadata::OverridableConstant::Type::Uint32:
242                     entry.u32 = static_cast<uint32_t>(value);
243                     break;
244                 default:
245                     UNREACHABLE();
246             }
247             specializationDataEntries->push_back(entry);
248         }
249 
250         specializationInfo->mapEntryCount = static_cast<uint32_t>(specializationMapEntries->size());
251         specializationInfo->pMapEntries = specializationMapEntries->data();
252         specializationInfo->dataSize =
253             specializationDataEntries->size() * sizeof(OverridableConstantScalar);
254         specializationInfo->pData = specializationDataEntries->data();
255 
256         return specializationInfo;
257     }
258 
259 }}  // namespace dawn_native::vulkan
260