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