diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index d8137d6fab..4dd65f0269 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp @@ -12,6 +12,8 @@ #include "video_core/renderer_vulkan/vk_texture_cache.h" +#include + #include "common/assert.h" #include "common/common_types.h" #include "common/div_ceil.h" @@ -19,6 +21,7 @@ #include "video_core/host_shaders/astc_decoder_comp_spv.h" #include "video_core/host_shaders/block_linear_unswizzle_2d_comp_spv.h" #include "video_core/host_shaders/block_linear_unswizzle_3d_comp_spv.h" +#include "video_core/host_shaders/pitch_unswizzle_comp_spv.h" #include "video_core/host_shaders/queries_prefix_scan_sum_comp_spv.h" #include "video_core/host_shaders/queries_prefix_scan_sum_nosubgroups_comp_spv.h" #include "video_core/host_shaders/resolve_conditional_render_comp_spv.h" @@ -200,6 +203,13 @@ struct BlockLinear3DImagePushConstants { u32 block_depth_mask; }; +struct PitchUnswizzlePushConstants { + std::array origin; + std::array destination; + u32 bytes_per_block_log2; + u32 pitch; +}; + struct QueriesPrefixScanPushConstants { u32 min_accumulation_base; u32 max_accumulation_base; @@ -816,4 +826,55 @@ void BlockLinearUnswizzleImage3DPass::Unswizzle( RecordUnswizzleEndBarrier(scheduler, vk_image, aspect_mask); } +PitchUnswizzlePass::PitchUnswizzlePass(const Device& device_, Scheduler& scheduler_, + DescriptorPool& descriptor_pool_, + StagingBufferPool& staging_buffer_pool_, + ComputePassDescriptorQueue& compute_pass_descriptor_queue_) + : ComputePass(device_, scheduler_, descriptor_pool_, ASTC_DESCRIPTOR_SET_BINDINGS, + ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY, ASTC_BANK_INFO, + COMPUTE_PUSH_CONSTANT_RANGE, + PITCH_UNSWIZZLE_COMP_SPV), + scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, + compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {} + +PitchUnswizzlePass::~PitchUnswizzlePass() = default; + +void PitchUnswizzlePass::Unswizzle(Image& image, const StagingBufferRef& map, + std::span swizzles) { + const u32 bytes_per_block = VideoCore::Surface::BytesPerBlock(image.info.format); + ASSERT(std::has_single_bit(bytes_per_block)); + scheduler.RequestOutsideRenderPassOperationContext(); + const VkImageAspectFlags aspect_mask = image.AspectMask(); + const VkImage vk_image = image.Handle(); + RecordUnswizzleBeginBarrier(scheduler, *pipeline, vk_image, aspect_mask, + image.ExchangeInitialization()); + for (const VideoCommon::SwizzleParameters& swizzle : swizzles) { + const size_t input_offset = swizzle.buffer_offset + map.offset; + const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U); + const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 8U); + + compute_pass_descriptor_queue.Acquire(scheduler, 2); + compute_pass_descriptor_queue.AddBuffer(map.buffer, input_offset, + image.guest_size_bytes - swizzle.buffer_offset); + compute_pass_descriptor_queue.AddImage(image.StorageImageView(swizzle.level)); + const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()}; + + const PitchUnswizzlePushConstants params{ + .origin = {0, 0}, + .destination = {0, 0}, + .bytes_per_block_log2 = static_cast(std::countr_zero(bytes_per_block)), + .pitch = image.info.pitch, + }; + scheduler.Record([this, num_dispatches_x, num_dispatches_y, params, + descriptor_data](vk::CommandBuffer cmdbuf) { + const VkDescriptorSet set = descriptor_allocator.Commit(); + device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data); + cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {}); + cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, params); + cmdbuf.Dispatch(num_dispatches_x, num_dispatches_y, 1); + }); + } + RecordUnswizzleEndBarrier(scheduler, vk_image, aspect_mask); +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h index d791554d32..f871648647 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.h +++ b/src/video_core/renderer_vulkan/vk_compute_pass.h @@ -153,6 +153,23 @@ private: MemoryAllocator& memory_allocator; }; +class PitchUnswizzlePass final : public ComputePass { +public: + explicit PitchUnswizzlePass(const Device& device_, Scheduler& scheduler_, + DescriptorPool& descriptor_pool_, + StagingBufferPool& staging_buffer_pool_, + ComputePassDescriptorQueue& compute_pass_descriptor_queue_); + ~PitchUnswizzlePass(); + + void Unswizzle(Image& image, const StagingBufferRef& map, + std::span swizzles); + +private: + Scheduler& scheduler; + StagingBufferPool& staging_buffer_pool; + ComputePassDescriptorQueue& compute_pass_descriptor_queue; +}; + class BlockLinearUnswizzleImage3DPass final : public ComputePass { public: explicit BlockLinearUnswizzleImage3DPass( diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index fb64e89574..749a49c898 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -195,7 +195,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { } [[nodiscard]] bool WillUseAcceleratedUnswizzle(const Device& device, const ImageInfo& info) { - const bool supported_type = info.type == ImageType::e2D || info.type == ImageType::e3D; + const bool supported_type = info.type == ImageType::e2D || info.type == ImageType::e3D || + info.type == ImageType::Linear; if (!supported_type || info.num_samples > 1) { return false; } @@ -317,7 +318,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { VkFormat format, VkImageViewType view_type) { u32 layer_count = VK_REMAINING_ARRAY_LAYERS; - if (view_type == VK_IMAGE_VIEW_TYPE_3D) { + if (view_type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) { layer_count = 1; } static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{ @@ -1022,6 +1023,8 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched compute_pass_descriptor_queue); bl_unswizzle_3d_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool, compute_pass_descriptor_queue); + pitch_unswizzle_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool, + compute_pass_descriptor_queue); } if (!device.IsKhrImageFormatListSupported()) { return; @@ -2369,6 +2372,8 @@ VkImageView Image::StorageImageView(s32 level) noexcept { format_info.format = UnswizzleStorageFormat(BytesPerBlock(info.format)); if (info.type == ImageType::e3D) { view_type = VK_IMAGE_VIEW_TYPE_3D; + } else if (info.type == ImageType::Linear) { + view_type = VK_IMAGE_VIEW_TYPE_2D; } } view = MakeStorageView(runtime->device.GetLogical(), level, *original_image, @@ -3180,6 +3185,8 @@ void TextureCacheRuntime::AccelerateImageUpload( astc_decoder_pass->Assemble(image, map, swizzles); } else if (image.info.type == ImageType::e3D) { bl_unswizzle_3d_pass->Unswizzle(image, map, swizzles); + } else if (image.info.type == ImageType::Linear) { + pitch_unswizzle_pass->Unswizzle(image, map, swizzles); } else { bl_unswizzle_2d_pass->Unswizzle(image, map, swizzles); } diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 5023a94b8b..2e6b547e72 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -158,6 +158,7 @@ public: std::optional astc_decoder_pass; std::optional bl_unswizzle_2d_pass; std::optional bl_unswizzle_3d_pass; + std::optional pitch_unswizzle_pass; const Settings::ResolutionScalingInfo& resolution; std::array, VideoCore::Surface::MaxPixelFormat> view_formats;