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