From 522440bcb2bd61e4c02d9efa3bf3d17f563c1f64 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Wed, 26 Aug 2026 14:49:01 -0400 Subject: [PATCH] [TEST] Bring the unswizzle work from tiled-gpu-v2 x2 + revert of vertex, indexes from AHB path --- src/video_core/buffer_cache/buffer_cache.h | 82 +-- .../buffer_cache/buffer_cache_base.h | 5 - src/video_core/host_shaders/CMakeLists.txt | 2 + .../block_linear_unswizzle_2d_buffer.comp | 104 ++++ .../block_linear_unswizzle_3d_buffer.comp | 105 ++++ .../renderer_vulkan/vk_buffer_cache.cpp | 24 - .../renderer_vulkan/vk_buffer_cache.h | 3 - .../renderer_vulkan/vk_compute_pass.cpp | 478 ++++++++++++++++++ .../renderer_vulkan/vk_compute_pass.h | 39 ++ .../renderer_vulkan/vk_texture_cache.cpp | 21 + .../renderer_vulkan/vk_texture_cache.h | 2 + 11 files changed, 759 insertions(+), 106 deletions(-) create mode 100644 src/video_core/host_shaders/block_linear_unswizzle_2d_buffer.comp create mode 100644 src/video_core/host_shaders/block_linear_unswizzle_3d_buffer.comp diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 196f93a453..ac48ab5e34 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -821,20 +821,6 @@ void BufferCache

::BindHostIndexBuffer() { const u32 size = channel_state->index_buffer.size; const auto& draw_state = maxwell3d->draw_manager.draw_state; if (draw_state.inline_index_draw_indexes.empty()) { - if constexpr (USE_UNIFIED_MEMORY && !HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { - const auto window = - TryResolveUnifiedRange(channel_state->index_buffer.device_addr, size); - if (window && runtime.IsUnifiedIndexRange(draw_state.topology, - draw_state.index_buffer.format, - window->offset)) { - runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format, - draw_state.index_buffer.first, - draw_state.index_buffer.count, - runtime.UnifiedWindowBuffer(window->window), - static_cast(window->offset), size); - return; - } - } SynchronizeBuffer(buffer, channel_state->index_buffer.device_addr, size); } else { if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) { @@ -888,7 +874,6 @@ void BufferCache

::UpdateVertexBufferSlot(u32 index, const Binding& binding) { enabled_vertex_buffers_mask |= (1u << index); } else { enabled_vertex_buffers_mask &= ~(1u << index); - unified_vertex_buffers_mask &= ~(1u << index); } } @@ -921,39 +906,15 @@ void BufferCache

::BindHostVertexBuffers() { const Binding& binding = VertexBufferSlot(index); Buffer& buffer = slot_buffers[binding.buffer_id]; TouchBuffer(buffer, binding.buffer_id); - bool needs_bind = flags[Dirty::VertexBuffer0 + index]; - u32 unified_window = NO_UNIFIED_WINDOW; - u64 unified_offset = 0; - if constexpr (USE_UNIFIED_MEMORY) { - const bool was_unified = ((unified_vertex_buffers_mask >> index) & 1) != 0; - if (needs_bind || was_unified) { - const auto window = TryResolveUnifiedRange(binding.device_addr, binding.size); - if (window) { - unified_window = static_cast(window->window); - unified_offset = window->offset; - } - } - if (was_unified && unified_window == NO_UNIFIED_WINDOW) { - needs_bind = true; - } - } - if (unified_window == NO_UNIFIED_WINDOW) { - SynchronizeBuffer(buffer, binding.device_addr, binding.size); - } - if (!needs_bind) { + SynchronizeBuffer(buffer, binding.device_addr, binding.size); + if (!flags[Dirty::VertexBuffer0 + index]) { flush_bindings(); continue; } flags[Dirty::VertexBuffer0 + index] = false; const u32 stride = maxwell3d->regs.vertex_streams[index].stride; - u32 offset = static_cast(unified_offset); - if (unified_window == NO_UNIFIED_WINDOW) { - offset = buffer.Offset(binding.device_addr); - buffer.MarkUsage(offset, binding.size); - unified_vertex_buffers_mask &= ~(1u << index); - } else { - unified_vertex_buffers_mask |= 1u << index; - } + const u32 offset = buffer.Offset(binding.device_addr); + buffer.MarkUsage(offset, binding.size); if (!bindings.buffers.empty() && index != last_index + 1) { flush_bindings(); } @@ -964,7 +925,6 @@ void BufferCache

::BindHostVertexBuffers() { bindings.offsets.push_back(offset); bindings.sizes.push_back(binding.size); bindings.strides.push_back(stride); - bindings.unified_windows.push_back(unified_window); last_index = index; } flush_bindings(); @@ -972,31 +932,12 @@ void BufferCache

::BindHostVertexBuffers() { HostBindings host_bindings; bool any_valid{false}; auto& flags = maxwell3d->dirty.flags; - std::array unified_windows; - std::array unified_offsets{}; - unified_windows.fill(NO_UNIFIED_WINDOW); for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) { const Binding& binding = channel_state->vertex_buffers[index]; Buffer& buffer = slot_buffers[binding.buffer_id]; TouchBuffer(buffer, binding.buffer_id); - bool needs_bind = flags[Dirty::VertexBuffer0 + index]; - if constexpr (USE_UNIFIED_MEMORY) { - const bool was_unified = ((unified_vertex_buffers_mask >> index) & 1) != 0; - if (needs_bind || was_unified) { - const auto window = TryResolveUnifiedRange(binding.device_addr, binding.size); - if (window) { - unified_windows[index] = static_cast(window->window); - unified_offsets[index] = window->offset; - } - } - if (was_unified && unified_windows[index] == NO_UNIFIED_WINDOW) { - needs_bind = true; - } - } - if (unified_windows[index] == NO_UNIFIED_WINDOW) { - SynchronizeBuffer(buffer, binding.device_addr, binding.size); - } - if (!needs_bind) { + SynchronizeBuffer(buffer, binding.device_addr, binding.size); + if (!flags[Dirty::VertexBuffer0 + index]) { continue; } flags[Dirty::VertexBuffer0 + index] = false; @@ -1015,20 +956,13 @@ void BufferCache

::BindHostVertexBuffers() { Buffer& buffer = slot_buffers[binding.buffer_id]; const u32 stride = maxwell3d->regs.vertex_streams[index].stride; - u32 offset = static_cast(unified_offsets[index]); - if (unified_windows[index] == NO_UNIFIED_WINDOW) { - offset = buffer.Offset(binding.device_addr); - buffer.MarkUsage(offset, binding.size); - unified_vertex_buffers_mask &= ~(1u << index); - } else { - unified_vertex_buffers_mask |= 1u << index; - } + const u32 offset = buffer.Offset(binding.device_addr); + buffer.MarkUsage(offset, binding.size); host_bindings.buffers.push_back(&buffer); host_bindings.offsets.push_back(offset); host_bindings.sizes.push_back(binding.size); host_bindings.strides.push_back(stride); - host_bindings.unified_windows.push_back(unified_windows[index]); } runtime.BindVertexBuffers(host_bindings); } diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index 581f0d3b3f..b84cd2709c 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -97,15 +96,12 @@ static constexpr Binding NULL_BINDING{ .buffer_id = NULL_BUFFER_ID, }; -static constexpr u32 NO_UNIFIED_WINDOW = (std::numeric_limits::max)(); - template struct HostBindings { boost::container::static_vector buffers; boost::container::static_vector offsets; boost::container::static_vector sizes; boost::container::static_vector strides; - boost::container::static_vector unified_windows; u32 min_index{NUM_VERTEX_BUFFERS}; u32 max_index{0}; }; @@ -509,7 +505,6 @@ private: u32 last_index_count = 0; u32 enabled_vertex_buffers_mask = 0; - u32 unified_vertex_buffers_mask = 0; u64 vertex_buffers_serial = 0; std::array v_buffer{}; diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index c4e7ac3f6f..f8b64c57e8 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -17,12 +17,14 @@ set(SHADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/astc_decoder.comp ${CMAKE_CURRENT_SOURCE_DIR}/blit_color_float.frag ${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_2d.comp + ${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_2d_buffer.comp ${CMAKE_CURRENT_SOURCE_DIR}/blit_color_msaa.frag ${CMAKE_CURRENT_SOURCE_DIR}/blit_depth.frag ${CMAKE_CURRENT_SOURCE_DIR}/blit_depth_msaa.frag ${CMAKE_CURRENT_SOURCE_DIR}/blit_depth_stencil_msaa.frag ${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_3d.comp ${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_3d_bcn.comp + ${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_3d_buffer.comp ${CMAKE_CURRENT_SOURCE_DIR}/convert_abgr8_to_d24s8.frag ${CMAKE_CURRENT_SOURCE_DIR}/convert_abgr8_to_d32f.frag ${CMAKE_CURRENT_SOURCE_DIR}/convert_d32f_to_abgr8.frag diff --git a/src/video_core/host_shaders/block_linear_unswizzle_2d_buffer.comp b/src/video_core/host_shaders/block_linear_unswizzle_2d_buffer.comp new file mode 100644 index 0000000000..3fc71e05b6 --- /dev/null +++ b/src/video_core/host_shaders/block_linear_unswizzle_2d_buffer.comp @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#version 430 + +#extension GL_EXT_shader_16bit_storage : require +#extension GL_EXT_shader_8bit_storage : require + +#define BINDING_INPUT_BUFFER 0 +#define BINDING_OUTPUT_BUFFER 1 + +layout(push_constant) uniform PushConstants { + uvec3 dim; + uint bytes_per_block_log2; + + uvec3 origin; + uint layer_stride; + + uint block_size; + uint x_shift; + uint block_height; + uint block_height_mask; +} pc; + +layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU32 { uint u32data[]; }; +layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU64 { uvec2 u64data[]; }; +layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU128 { uvec4 u128data[]; }; + +layout(binding = BINDING_OUTPUT_BUFFER, std430) writeonly buffer OutputBuffer { + uint out_u32[]; +}; + +layout(local_size_x = 16, local_size_y = 8, local_size_z = 1) in; + +const uint GOB_SIZE_X = 64; +const uint GOB_SIZE_Y = 8; + +const uint GOB_SIZE_X_SHIFT = 6; +const uint GOB_SIZE_Y_SHIFT = 3; +const uint GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT; + +const uvec2 SWIZZLE_MASK = uvec2(GOB_SIZE_X - 1u, GOB_SIZE_Y - 1u); + +uint SwizzleTable(uint pos) { + const uint t[8] = uint[]( + 0x12100200, 0x13110301, 0x16140604, 0x17150705, + 0x1a180a08, 0x1b190b09, 0x1e1c0e0c, 0x1f1d0f0d + ); + const uint i = pos >> 4; + const uint h = (t[i / 4] >> ((i % 4) * 8)) & 0xff; + return (h << 4) | (pos & 0xf); +} + +uint SwizzleOffset(uvec2 pos) { + pos = pos & SWIZZLE_MASK; + return SwizzleTable(pos.y * 64u + pos.x); +} + +uvec4 ReadTexel(uint offset) { + switch (pc.bytes_per_block_log2) { + case 2u: + return uvec4(u32data[offset / 4u], 0u, 0u, 0u); + case 3u: + return uvec4(u64data[offset / 8u], 0u, 0u); + case 4u: + return u128data[offset / 16u]; + } + return uvec4(0u); +} + +void main() { + uvec3 coord = gl_GlobalInvocationID; + if (coord.x >= pc.dim.x || coord.y >= pc.dim.y || coord.z >= pc.dim.z) { + return; + } + + uvec3 pos = coord + pc.origin; + pos.x <<= pc.bytes_per_block_log2; + + uint swizzle = SwizzleOffset(pos.xy); + uint block_y = pos.y >> GOB_SIZE_Y_SHIFT; + + uint offset = 0u; + offset += pos.z * pc.layer_stride; + offset += (block_y >> pc.block_height) * pc.block_size; + offset += (block_y & pc.block_height_mask) << GOB_SIZE_SHIFT; + offset += (pos.x >> GOB_SIZE_X_SHIFT) << pc.x_shift; + offset += swizzle; + + uvec4 texel = ReadTexel(offset); + + uint words = 1u << (pc.bytes_per_block_log2 - 2u); + uint linear_index = coord.x + coord.y * pc.dim.x + coord.z * pc.dim.x * pc.dim.y; + uint out_idx = linear_index * words; + + out_u32[out_idx] = texel.x; + if (words > 1u) { + out_u32[out_idx + 1u] = texel.y; + } + if (words > 2u) { + out_u32[out_idx + 2u] = texel.z; + out_u32[out_idx + 3u] = texel.w; + } +} diff --git a/src/video_core/host_shaders/block_linear_unswizzle_3d_buffer.comp b/src/video_core/host_shaders/block_linear_unswizzle_3d_buffer.comp new file mode 100644 index 0000000000..7333568eb7 --- /dev/null +++ b/src/video_core/host_shaders/block_linear_unswizzle_3d_buffer.comp @@ -0,0 +1,105 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#version 430 + +#define BINDING_INPUT_BUFFER 0 +#define BINDING_OUTPUT_BUFFER 1 + +layout(push_constant) uniform PushConstants { + uvec3 dim; + uint bytes_per_block_log2; + + uvec3 origin; + uint slice_size; + + uint block_size; + uint x_shift; + uint block_height; + uint block_height_mask; + + uint block_depth; + uint block_depth_mask; +} pc; + +layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU32 { uint u32data[]; }; +layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU64 { uvec2 u64data[]; }; +layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU128 { uvec4 u128data[]; }; + +layout(binding = BINDING_OUTPUT_BUFFER, std430) writeonly buffer OutputBuffer { + uint out_u32[]; +}; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 4) in; + +const uint GOB_SIZE_X = 64; +const uint GOB_SIZE_Y = 8; + +const uint GOB_SIZE_X_SHIFT = 6; +const uint GOB_SIZE_Y_SHIFT = 3; +const uint GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT; + +const uvec2 SWIZZLE_MASK = uvec2(GOB_SIZE_X - 1u, GOB_SIZE_Y - 1u); + +uint SwizzleTable(uint pos) { + const uint t[8] = uint[]( + 0x12100200, 0x13110301, 0x16140604, 0x17150705, + 0x1a180a08, 0x1b190b09, 0x1e1c0e0c, 0x1f1d0f0d + ); + const uint i = pos >> 4; + const uint h = (t[i / 4] >> ((i % 4) * 8)) & 0xff; + return (h << 4) | (pos & 0xf); +} + +uint SwizzleOffset(uvec2 pos) { + pos = pos & SWIZZLE_MASK; + return SwizzleTable(pos.y * 64u + pos.x); +} + +uvec4 ReadTexel(uint offset) { + switch (pc.bytes_per_block_log2) { + case 2u: + return uvec4(u32data[offset / 4u], 0u, 0u, 0u); + case 3u: + return uvec4(u64data[offset / 8u], 0u, 0u); + case 4u: + return u128data[offset / 16u]; + } + return uvec4(0u); +} + +void main() { + uvec3 coord = gl_GlobalInvocationID; + if (coord.x >= pc.dim.x || coord.y >= pc.dim.y || coord.z >= pc.dim.z) { + return; + } + + uvec3 pos = coord + pc.origin; + pos.x <<= pc.bytes_per_block_log2; + + uint swizzle = SwizzleOffset(pos.xy); + uint block_y = pos.y >> GOB_SIZE_Y_SHIFT; + + uint offset = 0u; + offset += (pos.z >> pc.block_depth) * pc.slice_size; + offset += (pos.z & pc.block_depth_mask) << (GOB_SIZE_SHIFT + pc.block_height); + offset += (block_y >> pc.block_height) * pc.block_size; + offset += (block_y & pc.block_height_mask) << GOB_SIZE_SHIFT; + offset += (pos.x >> GOB_SIZE_X_SHIFT) << pc.x_shift; + offset += swizzle; + + uvec4 texel = ReadTexel(offset); + + uint words = 1u << (pc.bytes_per_block_log2 - 2u); + uint linear_index = coord.x + coord.y * pc.dim.x + coord.z * pc.dim.x * pc.dim.y; + uint out_idx = linear_index * words; + + out_u32[out_idx] = texel.x; + if (words > 1u) { + out_u32[out_idx + 1u] = texel.y; + } + if (words > 2u) { + out_u32[out_idx + 2u] = texel.z; + out_u32[out_idx + 3u] = texel.w; + } +} diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index c5ea286762..0b93b081f5 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -727,25 +727,6 @@ void BufferCacheRuntime::ClearBuffer(VkBuffer dest_buffer, u32 offset, size_t si }); } -bool BufferCacheRuntime::IsUnifiedIndexRange(PrimitiveTopology topology, IndexFormat index_format, - u64 offset) const { - const VkIndexType vk_index_type = MaxwellToVK::IndexFormat(index_format); - const bool needs_uint8_pass = - vk_index_type == VK_INDEX_TYPE_UINT8_EXT && !device.IsExtIndexTypeUint8Supported(); - if (topology == PrimitiveTopology::Quads || topology == PrimitiveTopology::QuadStrip || - needs_uint8_pass) { - return (offset % device.GetStorageBufferAlignment()) == 0; - } - switch (vk_index_type) { - case VK_INDEX_TYPE_UINT32: - return (offset % 4) == 0; - case VK_INDEX_TYPE_UINT16: - return (offset % 2) == 0; - default: - return true; - } -} - void BufferCacheRuntime::BindIndexBuffer(PrimitiveTopology topology, IndexFormat index_format, u32 base_vertex, u32 num_indices, VkBuffer buffer, u32 offset, [[maybe_unused]] u32 size) { @@ -821,11 +802,6 @@ void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings& bindings) { boost::container::static_vector buffer_handles(bindings.buffers.size()); for (u32 i = 0; i < bindings.buffers.size(); ++i) { - if (i < bindings.unified_windows.size() && - bindings.unified_windows[i] != VideoCommon::NO_UNIFIED_WINDOW) { - buffer_handles[i] = unified_memory->GetWindowBuffer(bindings.unified_windows[i]); - continue; - } auto handle = bindings.buffers[i]->Handle(); if (handle == VK_NULL_HANDLE) { bindings.offsets[i] = 0; diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index a15afcc03d..73649bfeb8 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h @@ -218,9 +218,6 @@ public: (offset % device.GetStorageBufferAlignment()) == 0; } - [[nodiscard]] bool IsUnifiedIndexRange(PrimitiveTopology topology, IndexFormat index_format, - u64 offset) const; - void BindTextureBuffer(Buffer& buffer, u32 offset, u32 size, VideoCore::Surface::PixelFormat format) { guest_descriptor_queue.AddTexelBuffer(buffer.View(offset, size, format), diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 80c434dc8f..77ccdcd16f 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp @@ -22,7 +22,9 @@ #include "video_core/host_shaders/resolve_conditional_render_comp_spv.h" #include "video_core/host_shaders/vulkan_quad_indexed_comp_spv.h" #include "video_core/host_shaders/vulkan_uint8_comp_spv.h" +#include "video_core/host_shaders/block_linear_unswizzle_2d_buffer_comp_spv.h" #include "video_core/host_shaders/block_linear_unswizzle_3d_bcn_comp_spv.h" +#include "video_core/host_shaders/block_linear_unswizzle_3d_buffer_comp_spv.h" #include "video_core/renderer_vulkan/vk_compute_pass.h" #include "video_core/surface.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h" @@ -872,4 +874,480 @@ void BlockLinearUnswizzle3DPass::UnswizzleChunk( }); } +namespace { +constexpr u32 BL2D_BINDING_INPUT_BUFFER = 0; +constexpr u32 BL2D_BINDING_OUTPUT_BUFFER = 1; + +struct alignas(16) BlockLinearUnswizzle2DPushConstants { + std::array dim; + u32 bytes_per_block_log2; + std::array origin; + u32 layer_stride; + u32 block_size; + u32 x_shift; + u32 block_height; + u32 block_height_mask; +}; +static_assert(sizeof(BlockLinearUnswizzle2DPushConstants) <= 128); + +constexpr std::array BL2D_BINDINGS{{ + { + .binding = BL2D_BINDING_INPUT_BUFFER, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .pImmutableSamplers = nullptr, + }, + { + .binding = BL2D_BINDING_OUTPUT_BUFFER, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .pImmutableSamplers = nullptr, + }, +}}; + +constexpr std::array BL2D_TEMPLATE{{ + { + .dstBinding = BL2D_BINDING_INPUT_BUFFER, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .offset = BL2D_BINDING_INPUT_BUFFER * sizeof(DescriptorUpdateEntry), + .stride = sizeof(DescriptorUpdateEntry), + }, + { + .dstBinding = BL2D_BINDING_OUTPUT_BUFFER, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .offset = BL2D_BINDING_OUTPUT_BUFFER * sizeof(DescriptorUpdateEntry), + .stride = sizeof(DescriptorUpdateEntry), + }, +}}; + +constexpr DescriptorBankInfo BL2D_BANK_INFO{ + .uniform_buffers = 0, + .storage_buffers = 2, + .texture_buffers = 0, + .image_buffers = 0, + .textures = 0, + .images = 0, + .score = 2, +}; +} // Anonymous namespace + +BlockLinearUnswizzle2DPass::BlockLinearUnswizzle2DPass( + const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_, + StagingBufferPool& staging_buffer_pool_, + ComputePassDescriptorQueue& compute_pass_descriptor_queue_) + : ComputePass(device_, scheduler_, descriptor_pool_, BL2D_BINDINGS, BL2D_TEMPLATE, + BL2D_BANK_INFO, + COMPUTE_PUSH_CONSTANT_RANGE, + BLOCK_LINEAR_UNSWIZZLE_2D_BUFFER_COMP_SPV), + scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, + compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {} + +BlockLinearUnswizzle2DPass::~BlockLinearUnswizzle2DPass() = default; + +bool BlockLinearUnswizzle2DPass::IsSupported(const Device& device, + const VideoCommon::ImageInfo& info) { + if (info.type != VideoCommon::ImageType::e2D) { + return false; + } + if (info.resources.levels != 1 || info.resources.layers != 1) { + return false; + } + if (info.num_samples > 1) { + return false; + } + if (VideoCore::Surface::IsPixelFormatASTC(info.format) && !device.IsOptimalAstcSupported()) { + return false; + } + if (VideoCore::Surface::IsPixelFormatBCn(info.format) && !device.IsOptimalBcnSupported()) { + return false; + } + const u32 bytes_per_block = VideoCore::Surface::BytesPerBlock(info.format); + return bytes_per_block == 4 || bytes_per_block == 8 || bytes_per_block == 16; +} + +void BlockLinearUnswizzle2DPass::Unswizzle( + Image& image, const StagingBufferRef& swizzled, + std::span swizzles) { + if (swizzles.empty()) { + return; + } + const VideoCommon::SwizzleParameters& sw = swizzles.front(); + const auto params = VideoCommon::Accelerated::MakeBlockLinearSwizzle2DParams(sw, image.info); + + const u32 width = sw.num_tiles.width; + const u32 height = sw.num_tiles.height; + const u32 texel_width = image.info.size.width; + const u32 texel_height = image.info.size.height; + const u32 depth = image.info.resources.layers; + const u32 bytes_per_block = 1u << params.bytes_per_block_log2; + const VkDeviceSize output_size = + static_cast(width) * height * depth * bytes_per_block; + + const StagingBufferRef output = + staging_buffer_pool.Request(static_cast(output_size), MemoryUsage::DeviceLocal); + + BlockLinearUnswizzle2DPushConstants pc{}; + pc.dim = {width, height, depth}; + pc.bytes_per_block_log2 = params.bytes_per_block_log2; + pc.origin = params.origin; + pc.layer_stride = params.layer_stride; + pc.block_size = params.block_size; + pc.x_shift = params.x_shift; + pc.block_height = params.block_height; + pc.block_height_mask = params.block_height_mask; + + scheduler.RequestOutsideRenderPassOperationContext(); + + compute_pass_descriptor_queue.Acquire(scheduler, 2); + compute_pass_descriptor_queue.AddBuffer(swizzled.buffer, sw.buffer_offset + swizzled.offset, + image.guest_size_bytes - sw.buffer_offset); + compute_pass_descriptor_queue.AddBuffer(output.buffer, output.offset, output_size); + + const void* descriptor_data = compute_pass_descriptor_queue.UpdateData(); + const VkDescriptorSet set = descriptor_allocator.Commit(); + + const u32 gx = Common::DivCeil(width, 16u); + const u32 gy = Common::DivCeil(height, 8u); + const bool is_initialized = image.ExchangeInitialization(); + + const VkBuffer out_buffer = output.buffer; + const VkDeviceSize out_offset = output.offset; + const VkImage dst_image = image.Handle(); + const VkImageAspectFlags aspect = image.AspectMask(); + + scheduler.Record([this, set, descriptor_data, pc, gx, gy, depth, output_size, out_buffer, + out_offset, dst_image, aspect, width, height, + is_initialized](vk::CommandBuffer cmdbuf) { + if (dst_image == VK_NULL_HANDLE || out_buffer == VK_NULL_HANDLE) { + return; + } + device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data); + cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline); + cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {}); + cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(pc), &pc); + cmdbuf.Dispatch(gx, gy, depth); + + const VkBufferMemoryBarrier buffer_barrier{ + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = out_buffer, + .offset = out_offset, + .size = output_size, + }; + const VkImageMemoryBarrier pre_copy{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = static_cast(is_initialized ? VK_ACCESS_SHADER_READ_BIT + : VK_ACCESS_NONE), + .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dst_image, + .subresourceRange{ + .aspectMask = aspect, + .baseMipLevel = 0, + .levelCount = VK_REMAINING_MIP_LEVELS, + .baseArrayLayer = 0, + .layerCount = VK_REMAINING_ARRAY_LAYERS, + }, + }; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | + (is_initialized ? vk::PIPELINE_STAGE_GRAPHICS_COMPUTE + : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT), + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, buffer_barrier, pre_copy); + + const VkBufferImageCopy copy{ + .bufferOffset = out_offset, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource{ + .aspectMask = aspect, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = depth, + }, + .imageOffset = {0, 0, 0}, + .imageExtent = {texel_width, texel_height, 1}, + }; + cmdbuf.CopyBufferToImage(out_buffer, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); + + const VkImageMemoryBarrier post_copy{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dst_image, + .subresourceRange{ + .aspectMask = aspect, + .baseMipLevel = 0, + .levelCount = VK_REMAINING_MIP_LEVELS, + .baseArrayLayer = 0, + .layerCount = VK_REMAINING_ARRAY_LAYERS, + }, + }; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, + 0, {}, {}, post_copy); + }); +} + +namespace { +constexpr u32 BL3DB_BINDING_INPUT_BUFFER = 0; +constexpr u32 BL3DB_BINDING_OUTPUT_BUFFER = 1; + +struct alignas(16) BlockLinearUnswizzle3DBufferPushConstants { + std::array dim; + u32 bytes_per_block_log2; + std::array origin; + u32 slice_size; + u32 block_size; + u32 x_shift; + u32 block_height; + u32 block_height_mask; + u32 block_depth; + u32 block_depth_mask; +}; +static_assert(sizeof(BlockLinearUnswizzle3DBufferPushConstants) <= 128); + +constexpr std::array BL3DB_BINDINGS{{ + { + .binding = BL3DB_BINDING_INPUT_BUFFER, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .pImmutableSamplers = nullptr, + }, + { + .binding = BL3DB_BINDING_OUTPUT_BUFFER, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .pImmutableSamplers = nullptr, + }, +}}; + +constexpr std::array BL3DB_TEMPLATE{{ + { + .dstBinding = BL3DB_BINDING_INPUT_BUFFER, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .offset = BL3DB_BINDING_INPUT_BUFFER * sizeof(DescriptorUpdateEntry), + .stride = sizeof(DescriptorUpdateEntry), + }, + { + .dstBinding = BL3DB_BINDING_OUTPUT_BUFFER, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .offset = BL3DB_BINDING_OUTPUT_BUFFER * sizeof(DescriptorUpdateEntry), + .stride = sizeof(DescriptorUpdateEntry), + }, +}}; + +constexpr DescriptorBankInfo BL3DB_BANK_INFO{ + .uniform_buffers = 0, + .storage_buffers = 2, + .texture_buffers = 0, + .image_buffers = 0, + .textures = 0, + .images = 0, + .score = 2, +}; +} // Anonymous namespace + +BlockLinearUnswizzle3DBufferPass::BlockLinearUnswizzle3DBufferPass( + const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_, + StagingBufferPool& staging_buffer_pool_, + ComputePassDescriptorQueue& compute_pass_descriptor_queue_) + : ComputePass(device_, scheduler_, descriptor_pool_, BL3DB_BINDINGS, BL3DB_TEMPLATE, + BL3DB_BANK_INFO, + COMPUTE_PUSH_CONSTANT_RANGE, + BLOCK_LINEAR_UNSWIZZLE_3D_BUFFER_COMP_SPV), + scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, + compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {} + +BlockLinearUnswizzle3DBufferPass::~BlockLinearUnswizzle3DBufferPass() = default; + +bool BlockLinearUnswizzle3DBufferPass::IsSupported(const Device& device, + const VideoCommon::ImageInfo& info) { + if (info.type != VideoCommon::ImageType::e3D) { + return false; + } + if (info.resources.levels != 1 || info.resources.layers != 1) { + return false; + } + if (info.num_samples > 1) { + return false; + } + if (info.size.depth <= 1) { + return false; + } + if (VideoCore::Surface::IsPixelFormatASTC(info.format)) { + return false; + } + if (VideoCore::Surface::IsPixelFormatBCn(info.format) && !device.IsOptimalBcnSupported()) { + return false; + } + const u32 bytes_per_block = VideoCore::Surface::BytesPerBlock(info.format); + return bytes_per_block == 4 || bytes_per_block == 8 || bytes_per_block == 16; +} + +void BlockLinearUnswizzle3DBufferPass::Unswizzle( + Image& image, const StagingBufferRef& swizzled, + std::span swizzles) { + if (swizzles.empty()) { + return; + } + + const VideoCommon::SwizzleParameters& sw = swizzles.front(); + const auto params = VideoCommon::Accelerated::MakeBlockLinearSwizzle3DParams(sw, image.info); + + const u32 blocks_x = sw.num_tiles.width; + const u32 blocks_y = sw.num_tiles.height; + const u32 blocks_z = sw.num_tiles.depth; + const u32 bytes_per_block = 1u << params.bytes_per_block_log2; + const VkDeviceSize output_size = + static_cast(blocks_x) * blocks_y * blocks_z * bytes_per_block; + + const StagingBufferRef output = + staging_buffer_pool.Request(static_cast(output_size), MemoryUsage::DeviceLocal); + + BlockLinearUnswizzle3DBufferPushConstants pc{}; + pc.dim = {blocks_x, blocks_y, blocks_z}; + pc.bytes_per_block_log2 = params.bytes_per_block_log2; + pc.origin = params.origin; + pc.slice_size = params.slice_size; + pc.block_size = params.block_size; + pc.x_shift = params.x_shift; + pc.block_height = params.block_height; + pc.block_height_mask = params.block_height_mask; + pc.block_depth = params.block_depth; + pc.block_depth_mask = params.block_depth_mask; + + scheduler.RequestOutsideRenderPassOperationContext(); + + compute_pass_descriptor_queue.Acquire(scheduler, 2); + compute_pass_descriptor_queue.AddBuffer(swizzled.buffer, sw.buffer_offset + swizzled.offset, + image.guest_size_bytes - sw.buffer_offset); + compute_pass_descriptor_queue.AddBuffer(output.buffer, output.offset, output_size); + + const void* descriptor_data = compute_pass_descriptor_queue.UpdateData(); + const VkDescriptorSet set = descriptor_allocator.Commit(); + + const u32 gx = Common::DivCeil(blocks_x, 8u); + const u32 gy = Common::DivCeil(blocks_y, 8u); + const u32 gz = Common::DivCeil(blocks_z, 4u); + const bool is_initialized = image.ExchangeInitialization(); + + const VkBuffer out_buffer = output.buffer; + const VkDeviceSize out_offset = output.offset; + const VkImage dst_image = image.Handle(); + const VkImageAspectFlags aspect = image.AspectMask(); + const VkExtent3D extent{ + .width = image.info.size.width, + .height = image.info.size.height, + .depth = image.info.size.depth, + }; + + scheduler.Record([this, set, descriptor_data, pc, gx, gy, gz, output_size, out_buffer, + out_offset, dst_image, aspect, extent, + is_initialized](vk::CommandBuffer cmdbuf) { + if (dst_image == VK_NULL_HANDLE || out_buffer == VK_NULL_HANDLE) { + return; + } + device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data); + cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline); + cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {}); + cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(pc), &pc); + cmdbuf.Dispatch(gx, gy, gz); + + const VkBufferMemoryBarrier buffer_barrier{ + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = out_buffer, + .offset = out_offset, + .size = output_size, + }; + const VkImageMemoryBarrier pre_copy{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = static_cast(is_initialized ? VK_ACCESS_SHADER_READ_BIT + : VK_ACCESS_NONE), + .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dst_image, + .subresourceRange{ + .aspectMask = aspect, + .baseMipLevel = 0, + .levelCount = VK_REMAINING_MIP_LEVELS, + .baseArrayLayer = 0, + .layerCount = VK_REMAINING_ARRAY_LAYERS, + }, + }; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | + (is_initialized ? vk::PIPELINE_STAGE_GRAPHICS_COMPUTE + : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT), + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, buffer_barrier, pre_copy); + + const VkBufferImageCopy copy{ + .bufferOffset = out_offset, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource{ + .aspectMask = aspect, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .imageOffset = {0, 0, 0}, + .imageExtent = extent, + }; + cmdbuf.CopyBufferToImage(out_buffer, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); + + const VkImageMemoryBarrier post_copy{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dst_image, + .subresourceRange{ + .aspectMask = aspect, + .baseMipLevel = 0, + .levelCount = VK_REMAINING_MIP_LEVELS, + .baseArrayLayer = 0, + .layerCount = VK_REMAINING_ARRAY_LAYERS, + }, + }; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, + 0, {}, {}, post_copy); + }); +} + } // 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 3d30aa6bdc..c08d8724f6 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.h +++ b/src/video_core/renderer_vulkan/vk_compute_pass.h @@ -164,4 +164,43 @@ private: ComputePassDescriptorQueue& compute_pass_descriptor_queue; }; +class BlockLinearUnswizzle2DPass final : public ComputePass { +public: + explicit BlockLinearUnswizzle2DPass(const Device& device_, Scheduler& scheduler_, + DescriptorPool& descriptor_pool_, + StagingBufferPool& staging_buffer_pool_, + ComputePassDescriptorQueue& compute_pass_descriptor_queue_); + ~BlockLinearUnswizzle2DPass(); + + [[nodiscard]] static bool IsSupported(const Device& device, + const VideoCommon::ImageInfo& info); + + void Unswizzle(Image& image, const StagingBufferRef& swizzled, + std::span swizzles); + +private: + Scheduler& scheduler; + StagingBufferPool& staging_buffer_pool; + ComputePassDescriptorQueue& compute_pass_descriptor_queue; +}; + +class BlockLinearUnswizzle3DBufferPass final : public ComputePass { +public: + explicit BlockLinearUnswizzle3DBufferPass( + const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_, + StagingBufferPool& staging_buffer_pool_, + ComputePassDescriptorQueue& compute_pass_descriptor_queue_); + ~BlockLinearUnswizzle3DBufferPass(); + + [[nodiscard]] static bool IsSupported(const Device& device, const VideoCommon::ImageInfo& info); + + void Unswizzle(Image& image, const StagingBufferRef& swizzled, + std::span swizzles); + +private: + Scheduler& scheduler; + StagingBufferPool& staging_buffer_pool; + ComputePassDescriptorQueue& compute_pass_descriptor_queue; +}; + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index c3f56408b5..5d3bad180c 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -968,6 +968,10 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched bl3d_unswizzle_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool, compute_pass_descriptor_queue); } + bl2d_unswizzle_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool, + compute_pass_descriptor_queue); + bl3db_unswizzle_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool, + compute_pass_descriptor_queue); } void TextureCacheRuntime::Finish() { @@ -1894,6 +1898,14 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu } flags |= VideoCommon::ImageFlagBits::Converted; flags |= VideoCommon::ImageFlagBits::CostlyLoad; + } else if (runtime->bl2d_unswizzle_pass && + BlockLinearUnswizzle2DPass::IsSupported(runtime->device, info)) { + flags |= VideoCommon::ImageFlagBits::AcceleratedUpload; + flags |= VideoCommon::ImageFlagBits::CostlyLoad; + } else if (runtime->bl3db_unswizzle_pass && + BlockLinearUnswizzle3DBufferPass::IsSupported(runtime->device, info)) { + flags |= VideoCommon::ImageFlagBits::AcceleratedUpload; + flags |= VideoCommon::ImageFlagBits::CostlyLoad; } if (IsPixelFormatBCn(info.format) && !runtime->device.IsOptimalBcnSupported()) { flags |= VideoCommon::ImageFlagBits::Converted; @@ -3141,6 +3153,15 @@ void TextureCacheRuntime::AccelerateImageUpload( return astc_decoder_pass->Assemble(image, map, swizzles); } + if (bl2d_unswizzle_pass && BlockLinearUnswizzle2DPass::IsSupported(device, image.info)) { + return bl2d_unswizzle_pass->Unswizzle(image, map, swizzles); + } + + if (bl3db_unswizzle_pass && + BlockLinearUnswizzle3DBufferPass::IsSupported(device, image.info)) { + return bl3db_unswizzle_pass->Unswizzle(image, map, swizzles); + } + if (!Settings::values.gpu_unswizzle_enabled.GetValue() || !bl3d_unswizzle_pass) { if (IsPixelFormatBCn(image.info.format) && image.info.type == ImageType::e3D) { ASSERT(false && "GPU unswizzle is disabled for BCn 3D texture"); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 1b1e35aa45..1fb1f3e5f5 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -159,6 +159,8 @@ public: std::optional astc_decoder_pass; std::optional bl3d_unswizzle_pass; + std::optional bl2d_unswizzle_pass; + std::optional bl3db_unswizzle_pass; const Settings::ResolutionScalingInfo& resolution; std::array, VideoCore::Surface::MaxPixelFormat> view_formats;