renderer_vulkan: Centralize pixel format trait management. (#18)
* renderer_vulkan: Centralize pixel format trait management. * renderer_vulkan: Add D24 <-> D32 conversion support.
This commit is contained in:
		| @@ -18,51 +18,3 @@ | |||||||
|  |  | ||||||
| #define VMA_STATIC_VULKAN_FUNCTIONS 0 | #define VMA_STATIC_VULKAN_FUNCTIONS 0 | ||||||
| #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 | #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 | ||||||
|  |  | ||||||
| namespace Vulkan { |  | ||||||
|  |  | ||||||
| /// Return the image aspect associated on the provided format |  | ||||||
| constexpr vk::ImageAspectFlags GetImageAspect(vk::Format format) { |  | ||||||
|     switch (format) { |  | ||||||
|     case vk::Format::eD16UnormS8Uint: |  | ||||||
|     case vk::Format::eD24UnormS8Uint: |  | ||||||
|     case vk::Format::eD32SfloatS8Uint: |  | ||||||
|         return vk::ImageAspectFlagBits::eStencil | vk::ImageAspectFlagBits::eDepth; |  | ||||||
|         break; |  | ||||||
|     case vk::Format::eD16Unorm: |  | ||||||
|     case vk::Format::eX8D24UnormPack32: |  | ||||||
|     case vk::Format::eD32Sfloat: |  | ||||||
|         return vk::ImageAspectFlagBits::eDepth; |  | ||||||
|         break; |  | ||||||
|     default: |  | ||||||
|         return vk::ImageAspectFlagBits::eColor; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /// Returns a bit mask with the required usage of a format with a particular aspect |  | ||||||
| constexpr vk::ImageUsageFlags GetImageUsage(vk::ImageAspectFlags aspect) { |  | ||||||
|     auto usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst | |  | ||||||
|                  vk::ImageUsageFlagBits::eTransferSrc; |  | ||||||
|  |  | ||||||
|     if (aspect & vk::ImageAspectFlagBits::eDepth) { |  | ||||||
|         return usage | vk::ImageUsageFlagBits::eDepthStencilAttachment; |  | ||||||
|     } else { |  | ||||||
|         return usage | vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eColorAttachment; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /// Returns a bit mask with the required features of a format with a particular aspect |  | ||||||
| constexpr vk::FormatFeatureFlags GetFormatFeatures(vk::ImageAspectFlags aspect) { |  | ||||||
|     auto usage = vk::FormatFeatureFlagBits::eSampledImage | |  | ||||||
|                  vk::FormatFeatureFlagBits::eTransferDst | vk::FormatFeatureFlagBits::eTransferSrc | |  | ||||||
|                  vk::FormatFeatureFlagBits::eBlitSrc | vk::FormatFeatureFlagBits::eBlitDst; |  | ||||||
|  |  | ||||||
|     if (aspect & vk::ImageAspectFlagBits::eDepth) { |  | ||||||
|         return usage | vk::FormatFeatureFlagBits::eDepthStencilAttachment; |  | ||||||
|     } else { |  | ||||||
|         return usage | vk::FormatFeatureFlagBits::eStorageImage | |  | ||||||
|                vk::FormatFeatureFlagBits::eColorAttachment; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| } // namespace Vulkan |  | ||||||
|   | |||||||
| @@ -276,6 +276,80 @@ FormatTraits Instance::GetTraits(VideoCore::PixelFormat pixel_format) const { | |||||||
|     return format_table[index]; |     return format_table[index]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | vk::ImageAspectFlags MakeAspect(VideoCore::SurfaceType type) { | ||||||
|  |     switch (type) { | ||||||
|  |     case VideoCore::SurfaceType::Color: | ||||||
|  |     case VideoCore::SurfaceType::Texture: | ||||||
|  |     case VideoCore::SurfaceType::Fill: | ||||||
|  |         return vk::ImageAspectFlagBits::eColor; | ||||||
|  |     case VideoCore::SurfaceType::Depth: | ||||||
|  |         return vk::ImageAspectFlagBits::eDepth; | ||||||
|  |     case VideoCore::SurfaceType::DepthStencil: | ||||||
|  |         return vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil; | ||||||
|  |     default: | ||||||
|  |         LOG_CRITICAL(Render_Vulkan, "Invalid surface type {}", type); | ||||||
|  |         UNREACHABLE(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return vk::ImageAspectFlagBits::eColor; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | FormatTraits Instance::DetermineTraits(VideoCore::PixelFormat pixel_format, vk::Format format) { | ||||||
|  |     const vk::ImageAspectFlags format_aspect = | ||||||
|  |         MakeAspect(VideoCore::GetFormatType(pixel_format)); | ||||||
|  |     const vk::FormatProperties format_properties = physical_device.getFormatProperties(format); | ||||||
|  |  | ||||||
|  |     const vk::FormatFeatureFlagBits attachment_usage = | ||||||
|  |         (format_aspect & vk::ImageAspectFlagBits::eDepth) | ||||||
|  |             ? vk::FormatFeatureFlagBits::eDepthStencilAttachment | ||||||
|  |             : vk::FormatFeatureFlagBits::eColorAttachmentBlend; | ||||||
|  |  | ||||||
|  |     const vk::FormatFeatureFlags storage_usage = vk::FormatFeatureFlagBits::eStorageImage; | ||||||
|  |     const vk::FormatFeatureFlags transfer_usage = vk::FormatFeatureFlagBits::eSampledImage; | ||||||
|  |     const vk::FormatFeatureFlags blit_usage = | ||||||
|  |         vk::FormatFeatureFlagBits::eBlitSrc | vk::FormatFeatureFlagBits::eBlitDst; | ||||||
|  |  | ||||||
|  |     const bool supports_transfer = | ||||||
|  |         (format_properties.optimalTilingFeatures & transfer_usage) == transfer_usage; | ||||||
|  |     const bool supports_blit = (format_properties.optimalTilingFeatures & blit_usage) == blit_usage; | ||||||
|  |     const bool supports_attachment = | ||||||
|  |         (format_properties.optimalTilingFeatures & attachment_usage) == attachment_usage && | ||||||
|  |         pixel_format != VideoCore::PixelFormat::RGB8; | ||||||
|  |     const bool supports_storage = | ||||||
|  |         (format_properties.optimalTilingFeatures & storage_usage) == storage_usage; | ||||||
|  |     const bool requires_conversion = | ||||||
|  |         // Requires component flip. | ||||||
|  |         pixel_format == VideoCore::PixelFormat::RGBA8 || | ||||||
|  |         // Requires (de)interleaving. | ||||||
|  |         pixel_format == VideoCore::PixelFormat::D24S8; | ||||||
|  |  | ||||||
|  |     // Find the most inclusive usage flags for this format | ||||||
|  |     vk::ImageUsageFlags best_usage; | ||||||
|  |     if (supports_blit || supports_transfer) { | ||||||
|  |         best_usage |= vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst | | ||||||
|  |                       vk::ImageUsageFlagBits::eTransferSrc; | ||||||
|  |     } | ||||||
|  |     if (supports_attachment) { | ||||||
|  |         best_usage |= (format_aspect & vk::ImageAspectFlagBits::eDepth) | ||||||
|  |                           ? vk::ImageUsageFlagBits::eDepthStencilAttachment | ||||||
|  |                           : vk::ImageUsageFlagBits::eColorAttachment; | ||||||
|  |     } | ||||||
|  |     if (supports_storage) { | ||||||
|  |         best_usage |= vk::ImageUsageFlagBits::eStorage; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return FormatTraits{ | ||||||
|  |         .transfer_support = supports_transfer, | ||||||
|  |         .blit_support = supports_blit, | ||||||
|  |         .attachment_support = supports_attachment, | ||||||
|  |         .storage_support = supports_storage, | ||||||
|  |         .requires_conversion = requires_conversion, | ||||||
|  |         .usage = best_usage, | ||||||
|  |         .aspect = format_aspect, | ||||||
|  |         .native = format, | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  |  | ||||||
| void Instance::CreateFormatTable() { | void Instance::CreateFormatTable() { | ||||||
|     constexpr std::array pixel_formats = { |     constexpr std::array pixel_formats = { | ||||||
|         VideoCore::PixelFormat::RGBA8,  VideoCore::PixelFormat::RGB8, |         VideoCore::PixelFormat::RGBA8,  VideoCore::PixelFormat::RGB8, | ||||||
| @@ -288,73 +362,32 @@ void Instance::CreateFormatTable() { | |||||||
|         VideoCore::PixelFormat::D16,    VideoCore::PixelFormat::D24, |         VideoCore::PixelFormat::D16,    VideoCore::PixelFormat::D24, | ||||||
|         VideoCore::PixelFormat::D24S8}; |         VideoCore::PixelFormat::D24S8}; | ||||||
|  |  | ||||||
|     const vk::FormatFeatureFlags storage_usage = vk::FormatFeatureFlagBits::eStorageImage; |  | ||||||
|     const vk::FormatFeatureFlags transfer_usage = vk::FormatFeatureFlagBits::eSampledImage; |  | ||||||
|     const vk::FormatFeatureFlags blit_usage = |  | ||||||
|         vk::FormatFeatureFlagBits::eBlitSrc | vk::FormatFeatureFlagBits::eBlitDst; |  | ||||||
|  |  | ||||||
|     for (const auto& pixel_format : pixel_formats) { |     for (const auto& pixel_format : pixel_formats) { | ||||||
|         const vk::Format format = ToVkFormat(pixel_format); |         const auto format = ToVkFormat(pixel_format); | ||||||
|         const vk::FormatProperties properties = physical_device.getFormatProperties(format); |         FormatTraits traits = DetermineTraits(pixel_format, format); | ||||||
|         const vk::ImageAspectFlags aspect = GetImageAspect(format); |  | ||||||
|  |  | ||||||
|         const vk::FormatFeatureFlagBits attachment_usage = |  | ||||||
|             (aspect & vk::ImageAspectFlagBits::eDepth) |  | ||||||
|                 ? vk::FormatFeatureFlagBits::eDepthStencilAttachment |  | ||||||
|                 : vk::FormatFeatureFlagBits::eColorAttachmentBlend; |  | ||||||
|  |  | ||||||
|         const bool supports_transfer = |  | ||||||
|             (properties.optimalTilingFeatures & transfer_usage) == transfer_usage; |  | ||||||
|         const bool supports_blit = (properties.optimalTilingFeatures & blit_usage) == blit_usage; |  | ||||||
|         bool supports_attachment = |  | ||||||
|             (properties.optimalTilingFeatures & attachment_usage) == attachment_usage; |  | ||||||
|         const bool supports_storage = |  | ||||||
|             (properties.optimalTilingFeatures & storage_usage) == storage_usage; |  | ||||||
|  |  | ||||||
|         // Find the most inclusive usage flags for this format |  | ||||||
|         vk::ImageUsageFlags best_usage; |  | ||||||
|         if (supports_blit || supports_transfer) { |  | ||||||
|             best_usage |= vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst | |  | ||||||
|                           vk::ImageUsageFlagBits::eTransferSrc; |  | ||||||
|         } |  | ||||||
|         if (supports_attachment) { |  | ||||||
|             best_usage |= (aspect & vk::ImageAspectFlagBits::eDepth) |  | ||||||
|                               ? vk::ImageUsageFlagBits::eDepthStencilAttachment |  | ||||||
|                               : vk::ImageUsageFlagBits::eColorAttachment; |  | ||||||
|         } |  | ||||||
|         if (supports_storage) { |  | ||||||
|             best_usage |= vk::ImageUsageFlagBits::eStorage; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|  |         const bool is_suitable = | ||||||
|  |             traits.transfer_support && traits.attachment_support && | ||||||
|  |             (traits.blit_support || traits.aspect & vk::ImageAspectFlagBits::eDepth); | ||||||
|  |         // Fall back if the native format is not suitable. | ||||||
|  |         if (!is_suitable) { | ||||||
|             // Always fallback to RGBA8 or D32(S8) for convenience |             // Always fallback to RGBA8 or D32(S8) for convenience | ||||||
|         vk::Format fallback = vk::Format::eR8G8B8A8Unorm; |             auto fallback = vk::Format::eR8G8B8A8Unorm; | ||||||
|         if (aspect & vk::ImageAspectFlagBits::eDepth) { |             if (traits.aspect & vk::ImageAspectFlagBits::eDepth) { | ||||||
|                 fallback = vk::Format::eD32Sfloat; |                 fallback = vk::Format::eD32Sfloat; | ||||||
|             if (aspect & vk::ImageAspectFlagBits::eStencil) { |                 if (traits.aspect & vk::ImageAspectFlagBits::eStencil) { | ||||||
|                     fallback = vk::Format::eD32SfloatS8Uint; |                     fallback = vk::Format::eD32SfloatS8Uint; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|         // Report completely unsupported formats |  | ||||||
|         if (!supports_blit && !supports_attachment && !supports_storage) { |  | ||||||
|             LOG_WARNING(Render_Vulkan, "Format {} unsupported, falling back unconditionally to {}", |             LOG_WARNING(Render_Vulkan, "Format {} unsupported, falling back unconditionally to {}", | ||||||
|                         vk::to_string(format), vk::to_string(fallback)); |                         vk::to_string(format), vk::to_string(fallback)); | ||||||
|         } |             traits = DetermineTraits(pixel_format, fallback); | ||||||
|  |             // Always requires conversion if backing format does not match. | ||||||
|         if (pixel_format == VideoCore::PixelFormat::RGB8) { |             traits.requires_conversion = true; | ||||||
|             supports_attachment = false; |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         const u32 index = static_cast<u32>(pixel_format); |         const u32 index = static_cast<u32>(pixel_format); | ||||||
|         format_table[index] = FormatTraits{ |         format_table[index] = traits; | ||||||
|             .transfer_support = supports_transfer, |  | ||||||
|             .blit_support = supports_blit, |  | ||||||
|             .attachment_support = supports_attachment, |  | ||||||
|             .storage_support = supports_storage, |  | ||||||
|             .usage = best_usage, |  | ||||||
|             .native = format, |  | ||||||
|             .fallback = fallback, |  | ||||||
|         }; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -23,9 +23,11 @@ struct FormatTraits { | |||||||
|     bool blit_support = false;       ///< True if the format supports blit operations |     bool blit_support = false;       ///< True if the format supports blit operations | ||||||
|     bool attachment_support = false; ///< True if the format supports being used as an attachment |     bool attachment_support = false; ///< True if the format supports being used as an attachment | ||||||
|     bool storage_support = false;    ///< True if the format supports storage operations |     bool storage_support = false;    ///< True if the format supports storage operations | ||||||
|  |     bool requires_conversion = | ||||||
|  |         false;                   ///< True if the format requires conversion to the native format | ||||||
|     vk::ImageUsageFlags usage{}; ///< Most supported usage for the native format |     vk::ImageUsageFlags usage{}; ///< Most supported usage for the native format | ||||||
|  |     vk::ImageAspectFlags aspect; ///< Aspect flags of the format | ||||||
|     vk::Format native = vk::Format::eUndefined; ///< Closest possible native format |     vk::Format native = vk::Format::eUndefined; ///< Closest possible native format | ||||||
|     vk::Format fallback = vk::Format::eUndefined; ///< Best fallback format |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /// The global Vulkan instance | /// The global Vulkan instance | ||||||
| @@ -202,7 +204,8 @@ public: | |||||||
|  |  | ||||||
| private: | private: | ||||||
|     /// Returns the optimal supported usage for the requested format |     /// Returns the optimal supported usage for the requested format | ||||||
|     vk::FormatFeatureFlags GetFormatFeatures(vk::Format format); |     [[nodiscard]] FormatTraits DetermineTraits(VideoCore::PixelFormat pixel_format, | ||||||
|  |                                                vk::Format format); | ||||||
|  |  | ||||||
|     /// Creates the format compatibility table for the current device |     /// Creates the format compatibility table for the current device | ||||||
|     void CreateFormatTable(); |     void CreateFormatTable(); | ||||||
|   | |||||||
| @@ -63,8 +63,10 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window, const Instan | |||||||
|     : instance{instance}, scheduler{scheduler}, runtime{runtime}, |     : instance{instance}, scheduler{scheduler}, runtime{runtime}, | ||||||
|       renderpass_cache{renderpass_cache}, desc_manager{desc_manager}, res_cache{*this, runtime}, |       renderpass_cache{renderpass_cache}, desc_manager{desc_manager}, res_cache{*this, runtime}, | ||||||
|       pipeline_cache{instance, scheduler, renderpass_cache, desc_manager}, |       pipeline_cache{instance, scheduler, renderpass_cache, desc_manager}, | ||||||
|       null_surface{NULL_PARAMS, vk::Format::eR8G8B8A8Unorm, NULL_USAGE, runtime}, |       null_surface{NULL_PARAMS, vk::Format::eR8G8B8A8Unorm, NULL_USAGE, | ||||||
|       null_storage_surface{NULL_PARAMS, vk::Format::eR32Uint, NULL_STORAGE_USAGE, runtime}, |                    vk::ImageAspectFlagBits::eColor, runtime}, | ||||||
|  |       null_storage_surface{NULL_PARAMS, vk::Format::eR32Uint, NULL_STORAGE_USAGE, | ||||||
|  |                            vk::ImageAspectFlagBits::eColor, runtime}, | ||||||
|       stream_buffer{instance, scheduler, BUFFER_USAGE, STREAM_BUFFER_SIZE}, |       stream_buffer{instance, scheduler, BUFFER_USAGE, STREAM_BUFFER_SIZE}, | ||||||
|       texture_buffer{instance, scheduler, TEX_BUFFER_USAGE, TextureBufferSize(instance)}, |       texture_buffer{instance, scheduler, TEX_BUFFER_USAGE, TextureBufferSize(instance)}, | ||||||
|       texture_lf_buffer{instance, scheduler, TEX_BUFFER_USAGE, TextureBufferSize(instance)} { |       texture_lf_buffer{instance, scheduler, TEX_BUFFER_USAGE, TextureBufferSize(instance)} { | ||||||
|   | |||||||
| @@ -47,15 +47,8 @@ RenderpassCache::RenderpassCache(const Instance& instance, Scheduler& scheduler) | |||||||
|             const FormatTraits color_traits = instance.GetTraits(ToFormatColor(color)); |             const FormatTraits color_traits = instance.GetTraits(ToFormatColor(color)); | ||||||
|             const FormatTraits depth_traits = instance.GetTraits(ToFormatDepth(depth)); |             const FormatTraits depth_traits = instance.GetTraits(ToFormatDepth(depth)); | ||||||
|  |  | ||||||
|             const vk::Format color_format = color_traits.transfer_support && |             const vk::Format color_format = color_traits.native; | ||||||
|                                                     color_traits.blit_support && |             const vk::Format depth_format = depth_traits.native; | ||||||
|                                                     color_traits.attachment_support |  | ||||||
|                                                 ? color_traits.native |  | ||||||
|                                                 : color_traits.fallback; |  | ||||||
|             const vk::Format depth_format = |  | ||||||
|                 depth_traits.transfer_support && depth_traits.attachment_support |  | ||||||
|                     ? depth_traits.native |  | ||||||
|                     : depth_traits.fallback; |  | ||||||
|  |  | ||||||
|             if (color_format == vk::Format::eUndefined && depth_format == vk::Format::eUndefined) { |             if (color_format == vk::Format::eUndefined && depth_format == vk::Format::eUndefined) { | ||||||
|                 continue; |                 continue; | ||||||
|   | |||||||
| @@ -26,24 +26,6 @@ struct RecordParams { | |||||||
|     vk::Image dst_image; |     vk::Image dst_image; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| [[nodiscard]] vk::ImageAspectFlags MakeAspect(VideoCore::SurfaceType type) { |  | ||||||
|     switch (type) { |  | ||||||
|     case VideoCore::SurfaceType::Color: |  | ||||||
|     case VideoCore::SurfaceType::Texture: |  | ||||||
|     case VideoCore::SurfaceType::Fill: |  | ||||||
|         return vk::ImageAspectFlagBits::eColor; |  | ||||||
|     case VideoCore::SurfaceType::Depth: |  | ||||||
|         return vk::ImageAspectFlagBits::eDepth; |  | ||||||
|     case VideoCore::SurfaceType::DepthStencil: |  | ||||||
|         return vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil; |  | ||||||
|     default: |  | ||||||
|         LOG_CRITICAL(Render_Vulkan, "Invalid surface type {}", type); |  | ||||||
|         UNREACHABLE(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return vk::ImageAspectFlagBits::eColor; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| [[nodiscard]] vk::Filter MakeFilter(VideoCore::PixelFormat pixel_format) { | [[nodiscard]] vk::Filter MakeFilter(VideoCore::PixelFormat pixel_format) { | ||||||
|     switch (pixel_format) { |     switch (pixel_format) { | ||||||
|     case VideoCore::PixelFormat::D16: |     case VideoCore::PixelFormat::D16: | ||||||
| @@ -93,6 +75,17 @@ u32 UnpackDepthStencil(const StagingData& data, vk::Format dest) { | |||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |     case vk::Format::eD32SfloatS8Uint: { | ||||||
|  |         for (; stencil_offset < data.size; depth_offset += 4) { | ||||||
|  |             std::byte* ptr = mapped.data() + depth_offset; | ||||||
|  |             const u32 d24s8 = VideoCore::MakeInt<u32>(ptr); | ||||||
|  |             const float d32 = (d24s8 >> 8) / 16777215.f; | ||||||
|  |             mapped[stencil_offset] = static_cast<std::byte>(d24s8 & 0xFF); | ||||||
|  |             std::memcpy(ptr, &d32, 4); | ||||||
|  |             stencil_offset++; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|     default: |     default: | ||||||
|         LOG_ERROR(Render_Vulkan, "Unimplemtend convertion for depth format {}", |         LOG_ERROR(Render_Vulkan, "Unimplemtend convertion for depth format {}", | ||||||
|                   vk::to_string(dest)); |                   vk::to_string(dest)); | ||||||
| @@ -172,26 +165,18 @@ void TextureRuntime::Finish() { | |||||||
| ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelFormat format, | ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelFormat format, | ||||||
|                                     VideoCore::TextureType type) { |                                     VideoCore::TextureType type) { | ||||||
|     const FormatTraits traits = instance.GetTraits(format); |     const FormatTraits traits = instance.GetTraits(format); | ||||||
|     const vk::ImageAspectFlags aspect = MakeAspect(VideoCore::GetFormatType(format)); |     return Allocate(width, height, format, type, traits.native, traits.usage, traits.aspect); | ||||||
|  |  | ||||||
|     // Depth buffers are not supposed to support blit by the spec so don't require it. |  | ||||||
|     const bool is_suitable = traits.transfer_support && traits.attachment_support && |  | ||||||
|                              (traits.blit_support || aspect & vk::ImageAspectFlagBits::eDepth); |  | ||||||
|     const vk::Format vk_format = is_suitable ? traits.native : traits.fallback; |  | ||||||
|     const vk::ImageUsageFlags vk_usage = is_suitable ? traits.usage : GetImageUsage(aspect); |  | ||||||
|  |  | ||||||
|     return Allocate(width, height, format, type, vk_format, vk_usage); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| MICROPROFILE_DEFINE(Vulkan_ImageAlloc, "Vulkan", "TextureRuntime Finish", MP_RGB(192, 52, 235)); | MICROPROFILE_DEFINE(Vulkan_ImageAlloc, "Vulkan", "TextureRuntime Finish", MP_RGB(192, 52, 235)); | ||||||
| ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelFormat pixel_format, | ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelFormat pixel_format, | ||||||
|                                     VideoCore::TextureType type, vk::Format format, |                                     VideoCore::TextureType type, vk::Format format, | ||||||
|                                     vk::ImageUsageFlags usage) { |                                     vk::ImageUsageFlags usage, vk::ImageAspectFlags aspect) { | ||||||
|     MICROPROFILE_SCOPE(Vulkan_ImageAlloc); |     MICROPROFILE_SCOPE(Vulkan_ImageAlloc); | ||||||
|  |  | ||||||
|     ImageAlloc alloc{}; |     ImageAlloc alloc{}; | ||||||
|     alloc.format = format; |     alloc.format = format; | ||||||
|     alloc.aspect = GetImageAspect(format); |     alloc.aspect = aspect; | ||||||
|  |  | ||||||
|     // The internal format does not provide enough guarantee of texture uniqueness |     // The internal format does not provide enough guarantee of texture uniqueness | ||||||
|     // especially when many pixel formats fallback to RGBA8 |     // especially when many pixel formats fallback to RGBA8 | ||||||
| @@ -384,6 +369,8 @@ void TextureRuntime::FormatConvert(const Surface& surface, bool upload, std::spa | |||||||
|             return Pica::Texture::ConvertBGRToRGBA(source, dest); |             return Pica::Texture::ConvertBGRToRGBA(source, dest); | ||||||
|         case VideoCore::PixelFormat::RGBA4: |         case VideoCore::PixelFormat::RGBA4: | ||||||
|             return Pica::Texture::ConvertRGBA4ToRGBA8(source, dest); |             return Pica::Texture::ConvertRGBA4ToRGBA8(source, dest); | ||||||
|  |         case VideoCore::PixelFormat::D24: | ||||||
|  |             return Pica::Texture::ConvertD24ToD32(source, dest); | ||||||
|         default: |         default: | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @@ -395,6 +382,8 @@ void TextureRuntime::FormatConvert(const Surface& surface, bool upload, std::spa | |||||||
|             return Pica::Texture::ConvertRGBA8ToRGBA4(source, dest); |             return Pica::Texture::ConvertRGBA8ToRGBA4(source, dest); | ||||||
|         case VideoCore::PixelFormat::RGB8: |         case VideoCore::PixelFormat::RGB8: | ||||||
|             return Pica::Texture::ConvertRGBAToBGR(source, dest); |             return Pica::Texture::ConvertRGBAToBGR(source, dest); | ||||||
|  |         case VideoCore::PixelFormat::D24: | ||||||
|  |             return Pica::Texture::ConvertD32ToD24(source, dest); | ||||||
|         default: |         default: | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @@ -850,10 +839,9 @@ const ReinterpreterList& TextureRuntime::GetPossibleReinterpretations( | |||||||
|  |  | ||||||
| bool TextureRuntime::NeedsConvertion(VideoCore::PixelFormat format) const { | bool TextureRuntime::NeedsConvertion(VideoCore::PixelFormat format) const { | ||||||
|     const FormatTraits traits = instance.GetTraits(format); |     const FormatTraits traits = instance.GetTraits(format); | ||||||
|     const VideoCore::SurfaceType type = VideoCore::GetFormatType(format); |     return traits.requires_conversion && | ||||||
|     return type == VideoCore::SurfaceType::Color && |            // DepthStencil formats are handled elsewhere due to de-interleaving. | ||||||
|            (format == VideoCore::PixelFormat::RGBA8 || !traits.blit_support || |            traits.aspect != (vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil); | ||||||
|             !traits.attachment_support); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| Surface::Surface(TextureRuntime& runtime) | Surface::Surface(TextureRuntime& runtime) | ||||||
| @@ -870,12 +858,12 @@ Surface::Surface(const VideoCore::SurfaceParams& params, TextureRuntime& runtime | |||||||
| } | } | ||||||
|  |  | ||||||
| Surface::Surface(const VideoCore::SurfaceParams& params, vk::Format format, | Surface::Surface(const VideoCore::SurfaceParams& params, vk::Format format, | ||||||
|                  vk::ImageUsageFlags usage, TextureRuntime& runtime) |                  vk::ImageUsageFlags usage, vk::ImageAspectFlags aspect, TextureRuntime& runtime) | ||||||
|     : VideoCore::SurfaceBase<Surface>{params}, runtime{runtime}, instance{runtime.GetInstance()}, |     : VideoCore::SurfaceBase<Surface>{params}, runtime{runtime}, instance{runtime.GetInstance()}, | ||||||
|       scheduler{runtime.GetScheduler()} { |       scheduler{runtime.GetScheduler()} { | ||||||
|     if (format != vk::Format::eUndefined) { |     if (format != vk::Format::eUndefined) { | ||||||
|         alloc = runtime.Allocate(GetScaledWidth(), GetScaledHeight(), pixel_format, texture_type, |         alloc = runtime.Allocate(GetScaledWidth(), GetScaledHeight(), pixel_format, texture_type, | ||||||
|                                  format, usage); |                                  format, usage, aspect); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1214,7 +1202,7 @@ void Surface::DepthStencilDownload(const VideoCore::BufferTextureCopy& download, | |||||||
|     Surface r32_surface{r32_params, vk::Format::eR32Uint, |     Surface r32_surface{r32_params, vk::Format::eR32Uint, | ||||||
|                         vk::ImageUsageFlagBits::eTransferSrc | |                         vk::ImageUsageFlagBits::eTransferSrc | | ||||||
|                             vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eStorage, |                             vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eStorage, | ||||||
|                         runtime}; |                         vk::ImageAspectFlagBits::eColor, runtime}; | ||||||
|  |  | ||||||
|     const VideoCore::TextureBlit blit = { |     const VideoCore::TextureBlit blit = { | ||||||
|         .src_level = download.texture_level, |         .src_level = download.texture_level, | ||||||
|   | |||||||
| @@ -106,7 +106,7 @@ public: | |||||||
|     /// Allocates a vulkan image |     /// Allocates a vulkan image | ||||||
|     [[nodiscard]] ImageAlloc Allocate(u32 width, u32 height, VideoCore::PixelFormat pixel_format, |     [[nodiscard]] ImageAlloc Allocate(u32 width, u32 height, VideoCore::PixelFormat pixel_format, | ||||||
|                                       VideoCore::TextureType type, vk::Format format, |                                       VideoCore::TextureType type, vk::Format format, | ||||||
|                                       vk::ImageUsageFlags usage); |                                       vk::ImageUsageFlags usage, vk::ImageAspectFlags aspect); | ||||||
|  |  | ||||||
|     /// Performs required format convertions on the staging data |     /// Performs required format convertions on the staging data | ||||||
|     void FormatConvert(const Surface& surface, bool upload, std::span<std::byte> source, |     void FormatConvert(const Surface& surface, bool upload, std::span<std::byte> source, | ||||||
| @@ -173,7 +173,7 @@ public: | |||||||
|     Surface(TextureRuntime& runtime); |     Surface(TextureRuntime& runtime); | ||||||
|     Surface(const VideoCore::SurfaceParams& params, TextureRuntime& runtime); |     Surface(const VideoCore::SurfaceParams& params, TextureRuntime& runtime); | ||||||
|     Surface(const VideoCore::SurfaceParams& params, vk::Format format, vk::ImageUsageFlags usage, |     Surface(const VideoCore::SurfaceParams& params, vk::Format format, vk::ImageUsageFlags usage, | ||||||
|             TextureRuntime& runtime); |             vk::ImageAspectFlags aspect, TextureRuntime& runtime); | ||||||
|     ~Surface() override; |     ~Surface() override; | ||||||
|  |  | ||||||
|     /// Uploads pixel data in staging to a rectangle region of the surface texture |     /// Uploads pixel data in staging to a rectangle region of the surface texture | ||||||
|   | |||||||
| @@ -300,6 +300,26 @@ void ConvertRGBA8ToRGB5A1(std::span<const std::byte> source, std::span<std::byte | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void ConvertD24ToD32(std::span<const std::byte> source, std::span<std::byte> dest) { | ||||||
|  |     u32 j = 0; | ||||||
|  |     for (std::size_t i = 0; i < dest.size(); i += 4) { | ||||||
|  |         auto d32 = | ||||||
|  |             Common::Color::DecodeD24(reinterpret_cast<const u8*>(source.data() + j)) / 16777215.f; | ||||||
|  |         std::memcpy(dest.data() + i, &d32, sizeof(d32)); | ||||||
|  |         j += 3; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ConvertD32ToD24(std::span<const std::byte> source, std::span<std::byte> dest) { | ||||||
|  |     u32 j = 0; | ||||||
|  |     for (std::size_t i = 0; i < dest.size(); i += 3) { | ||||||
|  |         float d32; | ||||||
|  |         std::memcpy(&d32, source.data() + j, sizeof(d32)); | ||||||
|  |         Common::Color::EncodeD24(d32 * 0xFFFFFF, reinterpret_cast<u8*>(dest.data() + i)); | ||||||
|  |         j += 4; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| void ConvertD32S8ToD24S8(std::span<const std::byte> source, std::span<std::byte> dest) { | void ConvertD32S8ToD24S8(std::span<const std::byte> source, std::span<std::byte> dest) { | ||||||
|     std::size_t depth_offset = 0; |     std::size_t depth_offset = 0; | ||||||
|     std::size_t stencil_offset = 4 * source.size() / 5; |     std::size_t stencil_offset = 4 * source.size() / 5; | ||||||
|   | |||||||
| @@ -89,6 +89,10 @@ void ConvertRGB5A1ToRGBA8(std::span<const std::byte> source, std::span<std::byte | |||||||
|  |  | ||||||
| void ConvertRGBA8ToRGB5A1(std::span<const std::byte> source, std::span<std::byte> dest); | void ConvertRGBA8ToRGB5A1(std::span<const std::byte> source, std::span<std::byte> dest); | ||||||
|  |  | ||||||
|  | void ConvertD24ToD32(std::span<const std::byte> source, std::span<std::byte> dest); | ||||||
|  |  | ||||||
|  | void ConvertD32ToD24(std::span<const std::byte> source, std::span<std::byte> dest); | ||||||
|  |  | ||||||
| void ConvertD32S8ToD24S8(std::span<const std::byte> source, std::span<std::byte> dest); | void ConvertD32S8ToD24S8(std::span<const std::byte> source, std::span<std::byte> dest); | ||||||
|  |  | ||||||
| void InterleaveD24S8(std::span<const std::byte> source, std::span<std::byte> dest); | void InterleaveD24S8(std::span<const std::byte> source, std::span<std::byte> dest); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user