• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
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 
16 #include "gpu_image_vk.h"
17 
18 #include <cinttypes>
19 #include <vulkan/vulkan_core.h>
20 
21 #include <base/math/mathf.h>
22 
23 #if (RENDER_PERF_ENABLED == 1)
24 #include <core/implementation_uids.h>
25 #include <core/perf/intf_performance_data_manager.h>
26 #endif
27 
28 #include <render/namespace.h>
29 
30 #include "device/device.h"
31 #include "device/gpu_resource_desc_flag_validation.h"
32 #include "util/log.h"
33 #include "vulkan/device_vk.h"
34 #include "vulkan/validate_vk.h"
35 
36 RENDER_BEGIN_NAMESPACE()
37 namespace {
38 #if (RENDER_PERF_ENABLED == 1)
RecordAllocation(const int64_t alignedByteSize)39 void RecordAllocation(const int64_t alignedByteSize)
40 {
41     if (auto* inst = CORE_NS::GetInstance<CORE_NS::IPerformanceDataManagerFactory>(CORE_NS::UID_PERFORMANCE_FACTORY);
42         inst) {
43         CORE_NS::IPerformanceDataManager* pdm = inst->Get("Memory");
44         pdm->UpdateData("AllGpuImages", "GPU_IMAGE", alignedByteSize);
45     }
46 }
47 #endif
48 
49 #if (RENDER_VALIDATION_ENABLED == 1)
ValidateFormat(const DevicePlatformDataVk & devicePlat,const GpuImageDesc & desc)50 void ValidateFormat(const DevicePlatformDataVk& devicePlat, const GpuImageDesc& desc)
51 {
52     const VkFormat format = (VkFormat)desc.format;
53     VkFormatProperties formatProperties;
54     vkGetPhysicalDeviceFormatProperties(devicePlat.physicalDevice, // physicalDevice
55         format,                                                    // format
56         &formatProperties);                                        // pFormatProperties
57     const VkFormatFeatureFlags optimalTilingFeatureFlags = formatProperties.optimalTilingFeatures;
58     bool valid = true;
59     if (desc.usageFlags & ImageUsageFlagBits::CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
60         if ((optimalTilingFeatureFlags & VkFormatFeatureFlagBits::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) ==
61             0) {
62             valid = false;
63         }
64     }
65     if (desc.usageFlags & ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
66         if ((optimalTilingFeatureFlags & VkFormatFeatureFlagBits::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0) {
67             valid = false;
68         }
69     }
70     if (desc.usageFlags & ImageUsageFlagBits::CORE_IMAGE_USAGE_STORAGE_BIT) {
71         if ((optimalTilingFeatureFlags & VkFormatFeatureFlagBits::VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0) {
72             valid = false;
73         }
74     }
75 
76     if (valid == false) {
77         PLUGIN_LOG_E("Unsupported image format feature flags (CORE_FORMAT: %u)", desc.format);
78         PLUGIN_ASSERT(false);
79     }
80 }
81 #endif
82 
83 constexpr uint32_t IMAGE_VIEW_USAGE_FLAGS { CORE_IMAGE_USAGE_SAMPLED_BIT | CORE_IMAGE_USAGE_STORAGE_BIT |
84                                             CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
85                                             CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
86                                             CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT |
87                                             CORE_IMAGE_USAGE_INPUT_ATTACHMENT_BIT };
88 
CheckDepthFormat(const DeviceVk & deviceVk,const BASE_NS::Format format)89 BASE_NS::Format CheckDepthFormat(const DeviceVk& deviceVk, const BASE_NS::Format format)
90 {
91     const auto& devPlat = deviceVk.GetPlatformInternalDataVk();
92     for (const auto& supportedDepthFormat : devPlat.supportedDepthFormats) {
93         if (format == supportedDepthFormat) {
94             return format;
95         }
96     }
97     if (!devPlat.supportedDepthFormats.empty()) {
98 #if (RENDER_VALIDATION_ENABLED == 1)
99         PLUGIN_LOG_W("RENDER_VALIDATION: unsupported depth format (%u), using format (%u)", format,
100             devPlat.supportedDepthFormats[0]);
101 #endif
102         return devPlat.supportedDepthFormats[0];
103     } else {
104         return BASE_NS::Format::BASE_FORMAT_UNDEFINED;
105     }
106 }
107 
GetBaseImageViewType(const VkImageViewType imageViewType)108 inline VkImageViewType GetBaseImageViewType(const VkImageViewType imageViewType)
109 {
110     if (imageViewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY) {
111         return VK_IMAGE_VIEW_TYPE_1D;
112     } else if (imageViewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY) {
113         return VK_IMAGE_VIEW_TYPE_2D;
114     } else if (imageViewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) {
115         return VK_IMAGE_VIEW_TYPE_CUBE;
116     }
117     return imageViewType;
118 }
119 
GetPlatMemory(const VmaAllocationInfo & allocationInfo,const VkMemoryPropertyFlags flags)120 inline GpuResourceMemoryVk GetPlatMemory(const VmaAllocationInfo& allocationInfo, const VkMemoryPropertyFlags flags)
121 {
122     return GpuResourceMemoryVk { allocationInfo.deviceMemory, allocationInfo.offset, allocationInfo.size,
123         allocationInfo.pMappedData, allocationInfo.memoryType, flags };
124 }
125 
InvalidFboSwizzle(const VkComponentMapping & componentMapping)126 inline bool InvalidFboSwizzle(const VkComponentMapping& componentMapping)
127 {
128     return ((componentMapping.r != VK_COMPONENT_SWIZZLE_IDENTITY) ||
129             (componentMapping.g != VK_COMPONENT_SWIZZLE_IDENTITY) ||
130             (componentMapping.b != VK_COMPONENT_SWIZZLE_IDENTITY) ||
131             (componentMapping.a != VK_COMPONENT_SWIZZLE_IDENTITY));
132 }
133 
FillImageDescVk(const GpuImageDesc & desc,GpuImagePlatformDataVk & plat)134 void FillImageDescVk(const GpuImageDesc& desc, GpuImagePlatformDataVk& plat)
135 {
136     plat.format = static_cast<VkFormat>(desc.format);
137     plat.aspectFlags = GpuImageUtilsVk::GetImageAspectFlagsFromFormat(plat.format);
138     plat.usage = static_cast<VkImageUsageFlags>(desc.usageFlags);
139     plat.extent = { desc.width, desc.height, desc.depth };
140     plat.tiling = static_cast<VkImageTiling>(desc.imageTiling);
141     plat.type = static_cast<VkImageType>(desc.imageType);
142     plat.samples = static_cast<VkSampleCountFlagBits>(desc.sampleCountFlags);
143     plat.mipLevels = desc.mipCount;
144     plat.arrayLayers = desc.layerCount;
145 }
146 
147 struct ImageInputStruct {
148     VkImage image { VK_NULL_HANDLE };
149     VkFormat format { VK_FORMAT_UNDEFINED };
150     VkComponentMapping componentMapping {};
151 };
152 
CreateImageView(const VkDevice device,const VkSamplerYcbcrConversionInfo * ycbcrConversionInfo,const ImageInputStruct & imageInput,const VkImageViewType imageViewType,const VkImageAspectFlags imageAspectFlags,const uint32_t baseMipLevel,const uint32_t levelCount,const uint32_t baseArrayLayer,const uint32_t layerCount)153 VkImageView CreateImageView(const VkDevice device, const VkSamplerYcbcrConversionInfo* ycbcrConversionInfo,
154     const ImageInputStruct& imageInput, const VkImageViewType imageViewType, const VkImageAspectFlags imageAspectFlags,
155     const uint32_t baseMipLevel, const uint32_t levelCount, const uint32_t baseArrayLayer, const uint32_t layerCount)
156 {
157     const VkImageSubresourceRange imageSubresourceRange {
158         imageAspectFlags, // aspectMask
159         baseMipLevel,     // baseMipLevel
160         levelCount,       // levelCount
161         baseArrayLayer,   // baseArrayLayer
162         layerCount        // layerCount
163     };
164 
165     const VkImageViewCreateInfo imageViewCreateInfo {
166         VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType
167         ycbcrConversionInfo,                      // pNext
168         0,                                        // flags
169         imageInput.image,                         // image
170         imageViewType,                            // viewType
171         imageInput.format,                        // format
172         imageInput.componentMapping,              // components
173         imageSubresourceRange,                    // subresourceRange
174     };
175 
176     VkImageView imageView = VK_NULL_HANDLE;
177     VALIDATE_VK_RESULT(vkCreateImageView(device, // device
178         &imageViewCreateInfo,                    // pCreateInfo
179         nullptr,                                 // pAllocator
180         &imageView));                            // pView
181 
182     return imageView;
183 }
184 } // namespace
185 
GpuImageVk(Device & device,const GpuImageDesc & desc)186 GpuImageVk::GpuImageVk(Device& device, const GpuImageDesc& desc) : GpuImage(), device_(device), desc_(desc)
187 {
188     PLUGIN_ASSERT_MSG(desc_.memoryPropertyFlags & MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
189         "Device local memory is only memory property supported for Vulkan GpuImage (flags: %u)",
190         desc_.memoryPropertyFlags);
191 
192     FillImageDescVk(desc_, plat_);
193     if (plat_.aspectFlags & VK_IMAGE_ASPECT_DEPTH_BIT) {
194         desc_.format = CheckDepthFormat((const DeviceVk&)device_, desc_.format);
195         if (desc_.format != desc.format) {
196             plat_.format = static_cast<VkFormat>(desc_.format);
197             plat_.aspectFlags = GpuImageUtilsVk::GetImageAspectFlagsFromFormat(plat_.format);
198         }
199     }
200 #if (RENDER_VALIDATION_ENABLED == 1)
201     ValidateFormat((const DevicePlatformDataVk&)device_.GetPlatformData(), desc_);
202 #endif
203 
204     CreateVkImage();
205     if (desc_.usageFlags & IMAGE_VIEW_USAGE_FLAGS) {
206         CreateVkImageViews(plat_.aspectFlags, nullptr);
207     }
208 
209 #if (RENDER_PERF_ENABLED == 1)
210     RecordAllocation(static_cast<int64_t>(mem_.allocationInfo.size));
211 #endif
212 
213 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
214     PLUGIN_LOG_E("gpu image id >: 0x%" PRIxPTR, (uintptr_t)plat_.image);
215 #endif
216 }
217 
GpuImageVk(Device & device,const GpuImageDesc & desc,const GpuImagePlatformData & platformData,const uintptr_t hwBuffer)218 GpuImageVk::GpuImageVk(
219     Device& device, const GpuImageDesc& desc, const GpuImagePlatformData& platformData, const uintptr_t hwBuffer)
220     : device_(device), plat_((const GpuImagePlatformDataVk&)platformData), desc_(desc), hwBuffer_(hwBuffer),
221       ownsResources_(false)
222 {
223     plat_.imageViewBase = plat_.imageView;
224     FillImageDescVk(desc_, plat_);
225     if (hwBuffer) {
226         CreatePlatformHwBuffer();
227     }
228 }
229 
~GpuImageVk()230 GpuImageVk::~GpuImageVk()
231 {
232     auto destroyImageViews = [](VkDevice device, auto& vec) {
233         for (auto& ref : vec) {
234             vkDestroyImageView(device, // device
235                 ref,                   // imageView
236                 nullptr);              // pAllocator
237         }
238         vec.clear();
239     };
240     // hw buffer variant creates image views and needs to destroy those as well
241     const VkDevice device = ((const DevicePlatformDataVk&)device_.GetPlatformData()).device;
242     if (ownsResources_ || (hwBuffer_ != 0)) {
243         vkDestroyImageView(device, // device
244             plat_.imageView,       // imageView
245             nullptr);              // pAllocator
246         if (destroyImageViewBase_) {
247             vkDestroyImageView(device, // device
248                 plat_.imageViewBase,   // imageView
249                 nullptr);              // pAllocator
250         }
251         destroyImageViews(device, platViews_.mipImageViews);
252         destroyImageViews(device, platViews_.layerImageViews);
253     }
254 
255     if (ownsResources_) {
256 #if (RENDER_PERF_ENABLED == 1)
257         RecordAllocation(-static_cast<int64_t>(mem_.allocationInfo.size));
258 #endif
259 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
260         PLUGIN_LOG_E("gpu image id <: 0x%" PRIxPTR, (uintptr_t)plat_.image);
261 #endif
262         PlatformGpuMemoryAllocator* gpuMemAllocator = device_.GetPlatformGpuMemoryAllocator();
263         PLUGIN_ASSERT(gpuMemAllocator);
264         if (gpuMemAllocator) {
265             gpuMemAllocator->DestroyImage(plat_.image, mem_.allocation);
266         }
267     } else if (hwBuffer_ != 0) {
268         DestroyPlatformHwBuffer();
269     }
270 }
271 
CreateVkImage()272 void GpuImageVk::CreateVkImage()
273 {
274     const VkImageCreateInfo imageCreateInfo {
275         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                // sType
276         nullptr,                                            // pNext
277         static_cast<VkImageCreateFlags>(desc_.createFlags), // flags
278         plat_.type,                                         // imageType
279         plat_.format,                                       // format
280         plat_.extent,                                       // extent
281         plat_.mipLevels,                                    // mipLevels
282         plat_.arrayLayers,                                  // arrayLayers
283         plat_.samples,                                      // samples
284         plat_.tiling,                                       // tiling
285         plat_.usage,                                        // usage
286         VkSharingMode::VK_SHARING_MODE_EXCLUSIVE,           // sharingMode
287         0,                                                  // queueFamilyIndexCount
288         nullptr,                                            // pQueueFamilyIndices
289         VkImageLayout::VK_IMAGE_LAYOUT_UNDEFINED,           // initialLayout
290     };
291 
292     VkMemoryPropertyFlags memoryPropertyFlags = static_cast<VkMemoryPropertyFlags>(desc_.memoryPropertyFlags);
293     const VkMemoryPropertyFlags requiredFlags =
294         (memoryPropertyFlags & (~(VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT |
295                                    CORE_MEMORY_PROPERTY_PROTECTED_BIT)));
296     const VkMemoryPropertyFlags preferredFlags = memoryPropertyFlags;
297 
298     PlatformGpuMemoryAllocator* gpuMemAllocator = device_.GetPlatformGpuMemoryAllocator();
299     if (gpuMemAllocator) {
300         // can be null handle -> default allocator
301         const VmaPool customPool = gpuMemAllocator->GetImagePool(desc_);
302 
303         const VmaAllocationCreateInfo allocationCreateInfo {
304             0,                                                   // flags
305             VmaMemoryUsage::VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, // usage
306             requiredFlags,                                       // requiredFlags
307             preferredFlags,                                      // preferredFlags
308             0,                                                   // memoryTypeBits
309             customPool,                                          // pool
310             nullptr,                                             // pUserData
311             0.f,                                                 // priority
312         };
313 
314         gpuMemAllocator->CreateImage(
315             imageCreateInfo, allocationCreateInfo, plat_.image, mem_.allocation, mem_.allocationInfo);
316     }
317 
318     plat_.memory = GetPlatMemory(mem_.allocationInfo, preferredFlags);
319 }
320 
CreateVkImageViews(VkImageAspectFlags imageAspectFlags,const VkSamplerYcbcrConversionInfo * ycbcrConversionInfo)321 void GpuImageVk::CreateVkImageViews(
322     VkImageAspectFlags imageAspectFlags, const VkSamplerYcbcrConversionInfo* ycbcrConversionInfo)
323 {
324     const VkDevice vkDevice = ((const DevicePlatformDataVk&)device_.GetPlatformData()).device;
325 
326     const VkImageViewType imageViewType = (VkImageViewType)desc_.imageViewType;
327     const VkImageAspectFlags shaderViewImageAspectFlags = imageAspectFlags & (~VK_IMAGE_ASPECT_STENCIL_BIT);
328 
329     const VkComponentMapping componentMapping = {
330         (VkComponentSwizzle)desc_.componentMapping.r,
331         (VkComponentSwizzle)desc_.componentMapping.g,
332         (VkComponentSwizzle)desc_.componentMapping.b,
333         (VkComponentSwizzle)desc_.componentMapping.a,
334     };
335 
336     const ImageInputStruct imageInput = { plat_.image, plat_.format, componentMapping };
337     // Create basic image view for sampling and general usage
338     plat_.imageView = CreateImageView(vkDevice, ycbcrConversionInfo, imageInput, imageViewType,
339         shaderViewImageAspectFlags, 0, plat_.mipLevels, 0, plat_.arrayLayers);
340     plat_.imageViewBase = plat_.imageView;
341 
342     const bool invalidFboSwizzle = InvalidFboSwizzle(componentMapping);
343     const bool notValidImageViewForAttachment = (plat_.mipLevels > 1) || (plat_.arrayLayers > 1) || invalidFboSwizzle;
344     const bool usageNeedsViews = (plat_.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
345                                                     VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) > 0;
346     const bool separateViewNeeded = (imageAspectFlags != shaderViewImageAspectFlags);
347     if (separateViewNeeded || (usageNeedsViews && notValidImageViewForAttachment)) {
348         destroyImageViewBase_ = true;
349         const VkImageViewType baseImageViewType = GetBaseImageViewType(imageViewType);
350         {
351             ImageInputStruct imageInputIdentity = imageInput;
352             imageInputIdentity.componentMapping = {}; // identity needed for fbo
353             plat_.imageViewBase = CreateImageView(
354                 vkDevice, ycbcrConversionInfo, imageInputIdentity, baseImageViewType, imageAspectFlags, 0, 1, 0, 1);
355         }
356 
357         if (plat_.mipLevels > 1) {
358             platViews_.mipImageViews.resize(plat_.mipLevels);
359             for (uint32_t mipIdx = 0; mipIdx < plat_.mipLevels; ++mipIdx) {
360                 platViews_.mipImageViews[mipIdx] = CreateImageView(
361                     vkDevice, ycbcrConversionInfo, imageInput, baseImageViewType, imageAspectFlags, mipIdx, 1, 0, 1);
362             }
363         }
364         if (plat_.arrayLayers > 1) {
365             platViews_.layerImageViews.resize(plat_.arrayLayers);
366             for (uint32_t layerIdx = 0; layerIdx < plat_.arrayLayers; ++layerIdx) {
367                 platViews_.layerImageViews[layerIdx] = CreateImageView(
368                     vkDevice, ycbcrConversionInfo, imageInput, baseImageViewType, imageAspectFlags, 0, 1, layerIdx, 1);
369             }
370         }
371     }
372 }
373 
GetDesc() const374 const GpuImageDesc& GpuImageVk::GetDesc() const
375 {
376     return desc_;
377 }
378 
GetBasePlatformData() const379 const GpuImagePlatformData& GpuImageVk::GetBasePlatformData() const
380 {
381     return plat_;
382 }
383 
GetPlatformData() const384 const GpuImagePlatformDataVk& GpuImageVk::GetPlatformData() const
385 {
386     return plat_;
387 }
388 
GetPlatformDataViews() const389 const GpuImagePlatformDataViewsVk& GpuImageVk::GetPlatformDataViews() const
390 {
391     return platViews_;
392 }
393 
GetPlaformDataConversion() const394 const GpuImagePlatformDataConversion& GpuImageVk::GetPlaformDataConversion() const
395 {
396     return platConversion_;
397 }
398 
GetAdditionalFlags() const399 GpuImage::AdditionalFlags GpuImageVk::GetAdditionalFlags() const
400 {
401     return (platConversion_.samplerConversion) ? ADDITIONAL_PLATFORM_CONVERSION_BIT : 0u;
402 }
403 
404 namespace GpuImageUtilsVk {
GetImageAspectFlagsFromFormat(const VkFormat format)405 VkImageAspectFlags GetImageAspectFlagsFromFormat(const VkFormat format)
406 {
407     VkImageAspectFlags flags {};
408 
409     const bool isDepthFormat =
410         ((format == VkFormat::VK_FORMAT_D16_UNORM) || (format == VkFormat::VK_FORMAT_X8_D24_UNORM_PACK32) ||
411             (format == VkFormat::VK_FORMAT_D32_SFLOAT) || (format == VkFormat::VK_FORMAT_D24_UNORM_S8_UINT))
412             ? true
413             : false;
414     if (isDepthFormat) {
415         flags |= VkImageAspectFlagBits::VK_IMAGE_ASPECT_DEPTH_BIT;
416 
417         const bool isStencilFormat =
418             ((format == VkFormat::VK_FORMAT_D16_UNORM_S8_UINT) || (format == VkFormat::VK_FORMAT_D24_UNORM_S8_UINT) ||
419                 (format == VkFormat::VK_FORMAT_D32_SFLOAT_S8_UINT))
420                 ? true
421                 : false;
422         if (isStencilFormat) {
423             flags |= VkImageAspectFlagBits::VK_IMAGE_ASPECT_STENCIL_BIT;
424         }
425     } else {
426         flags |= VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT;
427     }
428 
429     return flags;
430 }
431 } // namespace GpuImageUtilsVk
432 RENDER_END_NAMESPACE()
433