LCOV - code coverage report
Current view: top level - source/renderer/backend/vulkan - Texture.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 1 172 0.6 %
Date: 2023-01-19 00:18:29 Functions: 2 8 25.0 %

          Line data    Source code
       1             : /* Copyright (C) 2023 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "Texture.h"
      21             : 
      22             : #include "renderer/backend/vulkan/Device.h"
      23             : #include "renderer/backend/vulkan/Mapping.h"
      24             : #include "renderer/backend/vulkan/SamplerManager.h"
      25             : #include "renderer/backend/vulkan/Utilities.h"
      26             : 
      27             : namespace Renderer
      28             : {
      29             : 
      30             : namespace Backend
      31             : {
      32             : 
      33             : namespace Vulkan
      34             : {
      35             : 
      36             : // static
      37           0 : std::unique_ptr<CTexture> CTexture::Create(
      38             :     CDevice* device, const char* name, const Type type, const uint32_t usage,
      39             :     const Format format, const uint32_t width, const uint32_t height,
      40             :     const Sampler::Desc& defaultSamplerDesc,
      41             :     const uint32_t MIPLevelCount, const uint32_t sampleCount)
      42             : {
      43           0 :     std::unique_ptr<CTexture> texture(new CTexture());
      44           0 :     texture->m_Device = device;
      45             : 
      46           0 :     texture->m_Format = format;
      47           0 :     texture->m_Type = type;
      48           0 :     texture->m_Usage = usage;
      49           0 :     texture->m_Width = width;
      50           0 :     texture->m_Height = height;
      51           0 :     texture->m_MIPLevelCount = MIPLevelCount;
      52           0 :     texture->m_SampleCount = sampleCount;
      53           0 :     texture->m_LayerCount = type == ITexture::Type::TEXTURE_CUBE ? 6 : 1;
      54             : 
      55           0 :     if (type == Type::TEXTURE_2D_MULTISAMPLE)
      56           0 :         ENSURE(sampleCount > 1);
      57             : 
      58           0 :     VkFormat imageFormat = VK_FORMAT_UNDEFINED;
      59             :     // A8 and L8 are special cases for GL2.1, because it doesn't have a proper
      60             :     // channel swizzling.
      61           0 :     if (format == Format::A8_UNORM || format == Format::L8_UNORM)
      62           0 :         imageFormat = VK_FORMAT_R8_UNORM;
      63             :     else
      64           0 :         imageFormat = Mapping::FromFormat(format);
      65           0 :     texture->m_VkFormat = imageFormat;
      66             : 
      67           0 :     VkImageType imageType = VK_IMAGE_TYPE_2D;
      68           0 :     VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
      69             : 
      70             :     const VkPhysicalDevice physicalDevice =
      71           0 :         device->GetChoosenPhysicalDevice().device;
      72             : 
      73           0 :     VkFormatProperties formatProperties{};
      74           0 :     vkGetPhysicalDeviceFormatProperties(
      75             :         physicalDevice, imageFormat, &formatProperties);
      76             : 
      77           0 :     VkImageUsageFlags usageFlags = 0;
      78             :     // Vulkan 1.0 implies that TRANSFER_SRC and TRANSFER_DST are supported.
      79             :     // TODO: account Vulkan 1.1.
      80           0 :     if (usage & Usage::TRANSFER_SRC)
      81           0 :         usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
      82           0 :     if (usage & Usage::TRANSFER_DST)
      83           0 :         usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
      84           0 :     if (usage & Usage::SAMPLED)
      85             :     {
      86           0 :         ENSURE(type != Type::TEXTURE_2D_MULTISAMPLE);
      87           0 :         if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))
      88             :         {
      89           0 :             LOGERROR("Format %d doesn't support sampling for optimal tiling.", static_cast<int>(imageFormat));
      90           0 :             return nullptr;
      91             :         }
      92           0 :         usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT;
      93             :     }
      94           0 :     if (usage & Usage::COLOR_ATTACHMENT)
      95             :     {
      96           0 :         ENSURE(device->IsFramebufferFormatSupported(format));
      97           0 :         if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
      98             :         {
      99           0 :             LOGERROR("Format %d doesn't support color attachment for optimal tiling.", static_cast<int>(imageFormat));
     100           0 :             return nullptr;
     101             :         }
     102           0 :         usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
     103             :     }
     104           0 :     if (usage & Usage::DEPTH_STENCIL_ATTACHMENT)
     105             :     {
     106           0 :         ENSURE(IsDepthFormat(format));
     107           0 :         if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))
     108             :         {
     109           0 :             LOGERROR("Format %d doesn't support depth stencil attachment for optimal tiling.", static_cast<int>(imageFormat));
     110           0 :             return nullptr;
     111             :         }
     112           0 :         usageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
     113             :     }
     114             : 
     115           0 :     if (IsDepthFormat(format))
     116             :     {
     117           0 :         texture->m_AttachmentImageAspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
     118           0 :         texture->m_SamplerImageAspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
     119           0 :         if (format == Format::D24_UNORM_S8_UINT || format == Format::D32_SFLOAT_S8_UINT)
     120           0 :             texture->m_AttachmentImageAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
     121             :     }
     122             :     else
     123             :     {
     124           0 :         texture->m_AttachmentImageAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
     125           0 :         texture->m_SamplerImageAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
     126             :     }
     127             : 
     128           0 :     VkImageCreateInfo imageCreateInfo{};
     129           0 :     imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
     130           0 :     imageCreateInfo.imageType = imageType;
     131           0 :     imageCreateInfo.extent.width = width;
     132           0 :     imageCreateInfo.extent.height = height;
     133           0 :     imageCreateInfo.extent.depth = 1;
     134           0 :     imageCreateInfo.mipLevels = MIPLevelCount;
     135           0 :     imageCreateInfo.arrayLayers = type == Type::TEXTURE_CUBE ? 6 : 1;
     136           0 :     imageCreateInfo.format = imageFormat;
     137           0 :     imageCreateInfo.samples = Mapping::FromSampleCount(sampleCount);
     138           0 :     imageCreateInfo.tiling = tiling;
     139           0 :     imageCreateInfo.usage = usageFlags;
     140           0 :     imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
     141           0 :     imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
     142             : 
     143           0 :     if (type == Type::TEXTURE_CUBE)
     144           0 :         imageCreateInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
     145             : 
     146           0 :     VmaAllocationCreateInfo allocationCreateInfo{};
     147           0 :     if ((usage & Usage::COLOR_ATTACHMENT) || (usage & Usage::DEPTH_STENCIL_ATTACHMENT))
     148           0 :         allocationCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
     149             : #ifndef NDEBUG
     150           0 :     allocationCreateInfo.flags |= VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT;
     151           0 :     allocationCreateInfo.pUserData = const_cast<char*>(name);
     152             : #endif
     153           0 :     allocationCreateInfo.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
     154           0 :     allocationCreateInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
     155           0 :     const VkResult createImageResult = vmaCreateImage(
     156             :         device->GetVMAAllocator(), &imageCreateInfo, &allocationCreateInfo,
     157           0 :         &texture->m_Image, &texture->m_Allocation, nullptr);
     158           0 :     if (createImageResult != VK_SUCCESS)
     159             :     {
     160           0 :         LOGERROR("Failed to create VkImage: %d", static_cast<int>(createImageResult));
     161           0 :         return nullptr;
     162             :     }
     163             : 
     164           0 :     VkImageViewCreateInfo imageViewCreateInfo{};
     165           0 :     imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
     166           0 :     imageViewCreateInfo.image = texture->m_Image;
     167           0 :     imageViewCreateInfo.viewType = type == Type::TEXTURE_CUBE ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D;
     168           0 :     imageViewCreateInfo.format = imageFormat;
     169           0 :     imageViewCreateInfo.subresourceRange.baseMipLevel = 0;
     170           0 :     imageViewCreateInfo.subresourceRange.levelCount = MIPLevelCount;
     171           0 :     imageViewCreateInfo.subresourceRange.baseArrayLayer = 0;
     172           0 :     imageViewCreateInfo.subresourceRange.layerCount = type == Type::TEXTURE_CUBE ? 6 : 1;
     173           0 :     if (format == Format::A8_UNORM)
     174             :     {
     175           0 :         imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_ZERO;
     176           0 :         imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_ZERO;
     177           0 :         imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_ZERO;
     178           0 :         imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_R;
     179             :     }
     180           0 :     else if (format == Format::L8_UNORM)
     181             :     {
     182           0 :         imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R;
     183           0 :         imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_R;
     184           0 :         imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_R;
     185           0 :         imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_ONE;
     186             :     }
     187             :     else
     188             :     {
     189           0 :         imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
     190           0 :         imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
     191           0 :         imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
     192           0 :         imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
     193             :     }
     194             : 
     195           0 :     imageViewCreateInfo.subresourceRange.aspectMask = texture->m_AttachmentImageAspectMask;
     196           0 :     ENSURE_VK_SUCCESS(vkCreateImageView(
     197             :         device->GetVkDevice(), &imageViewCreateInfo, nullptr, &texture->m_AttachmentImageView));
     198           0 :     imageViewCreateInfo.subresourceRange.aspectMask = texture->m_SamplerImageAspectMask;
     199           0 :     ENSURE_VK_SUCCESS(vkCreateImageView(
     200             :         device->GetVkDevice(), &imageViewCreateInfo, nullptr, &texture->m_SamplerImageView));
     201             : 
     202           0 :     if (usage & Usage::SAMPLED)
     203             :     {
     204           0 :         texture->m_Sampler = device->GetSamplerManager().GetOrCreateSampler(
     205             :             defaultSamplerDesc);
     206           0 :         texture->m_IsCompareEnabled = defaultSamplerDesc.compareEnabled;
     207             :     }
     208             : 
     209           0 :     device->SetObjectName(VK_OBJECT_TYPE_IMAGE, texture->m_Image, name);
     210           0 :     if (texture->m_AttachmentImageView != VK_NULL_HANDLE)
     211           0 :         device->SetObjectName(VK_OBJECT_TYPE_IMAGE_VIEW, texture->m_AttachmentImageView, name);
     212           0 :     if (texture->m_SamplerImageView != VK_NULL_HANDLE)
     213           0 :         device->SetObjectName(VK_OBJECT_TYPE_IMAGE_VIEW, texture->m_SamplerImageView, name);
     214             : 
     215           0 :     return texture;
     216             : }
     217             : 
     218             : // static
     219           0 : std::unique_ptr<CTexture> CTexture::WrapBackbufferImage(
     220             :     CDevice* device, const char* name, const VkImage image, const VkFormat format,
     221             :     const VkImageUsageFlags usage, const uint32_t width, const uint32_t height)
     222             : {
     223           0 :     std::unique_ptr<CTexture> texture(new CTexture());
     224           0 :     texture->m_Device = device;
     225             : 
     226           0 :     texture->m_Format = Format::UNDEFINED;
     227           0 :     texture->m_Type = Type::TEXTURE_2D;
     228           0 :     if (usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
     229           0 :         texture->m_Usage |= Usage::COLOR_ATTACHMENT;
     230           0 :     if (usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
     231           0 :         texture->m_Usage |= Usage::TRANSFER_SRC;
     232           0 :     if (usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
     233           0 :         texture->m_Usage |= Usage::TRANSFER_DST;
     234           0 :     texture->m_Width = width;
     235           0 :     texture->m_Height = height;
     236           0 :     texture->m_MIPLevelCount = 1;
     237           0 :     texture->m_SampleCount = 1;
     238           0 :     texture->m_LayerCount = 1;
     239           0 :     texture->m_VkFormat = format;
     240             :     // The image is owned by its swapchain, but we don't set a special flag
     241             :     // because the ownership is detected by m_Allocation presence.
     242           0 :     texture->m_Image = image;
     243           0 :     texture->m_AttachmentImageAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
     244           0 :     texture->m_SamplerImageAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
     245             : 
     246           0 :     VkImageViewCreateInfo imageViewCreateInfo{};
     247           0 :     imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
     248           0 :     imageViewCreateInfo.image = image;
     249           0 :     imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
     250           0 :     imageViewCreateInfo.format = format;
     251           0 :     imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
     252           0 :     imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
     253           0 :     imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
     254           0 :     imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
     255           0 :     imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
     256           0 :     imageViewCreateInfo.subresourceRange.baseMipLevel = 0;
     257           0 :     imageViewCreateInfo.subresourceRange.levelCount = 1;
     258           0 :     imageViewCreateInfo.subresourceRange.baseArrayLayer = 0;
     259           0 :     imageViewCreateInfo.subresourceRange.layerCount = 1;
     260           0 :     ENSURE_VK_SUCCESS(vkCreateImageView(
     261             :         device->GetVkDevice(), &imageViewCreateInfo, nullptr, &texture->m_AttachmentImageView));
     262           0 :     device->SetObjectName(VK_OBJECT_TYPE_IMAGE_VIEW, texture->m_AttachmentImageView, name);
     263             : 
     264           0 :     return texture;
     265             : }
     266             : 
     267           0 : CTexture::CTexture()
     268             : {
     269             :     static uint32_t m_LastAvailableUID = 1;
     270           0 :     m_UID = m_LastAvailableUID++;
     271           0 : }
     272             : 
     273           0 : CTexture::~CTexture()
     274             : {
     275           0 :     if (m_AttachmentImageView != VK_NULL_HANDLE)
     276           0 :         m_Device->ScheduleObjectToDestroy(
     277           0 :             VK_OBJECT_TYPE_IMAGE_VIEW, m_AttachmentImageView, VK_NULL_HANDLE);
     278             : 
     279           0 :     if (m_SamplerImageView != VK_NULL_HANDLE)
     280           0 :         m_Device->ScheduleObjectToDestroy(
     281           0 :             VK_OBJECT_TYPE_IMAGE_VIEW, m_SamplerImageView, VK_NULL_HANDLE);
     282             : 
     283           0 :     if (m_Allocation != VK_NULL_HANDLE)
     284           0 :         m_Device->ScheduleObjectToDestroy(
     285           0 :             VK_OBJECT_TYPE_IMAGE, m_Image, m_Allocation);
     286             : 
     287           0 :     m_Device->ScheduleTextureToDestroy(m_UID);
     288           0 : }
     289             : 
     290           0 : IDevice* CTexture::GetDevice()
     291             : {
     292           0 :     return m_Device;
     293             : }
     294             : 
     295             : } // namespace Vulkan
     296             : 
     297             : } // namespace Backend
     298             : 
     299           3 : } // namespace Renderer

Generated by: LCOV version 1.13