Browse Source

Revert "[TEST] Debugger GPU unswizzle shaders"

lsfg-android
CamilleLaVey 4 weeks ago
parent
commit
62e8666eee
  1. 3
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
  2. 21
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
  3. 3
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
  4. 6
      src/android/app/src/main/res/values/strings.xml
  5. 10
      src/common/settings.h
  6. 9
      src/video_core/host_shaders/block_linear_unswizzle_3d_bcn.comp
  7. 1
      src/video_core/renderer_vulkan/renderer_vulkan.cpp
  8. 260
      src/video_core/renderer_vulkan/vk_compute_pass.cpp
  9. 52
      src/video_core/renderer_vulkan/vk_compute_pass.h
  10. 143
      src/video_core/renderer_vulkan/vk_texture_cache.cpp
  11. 23
      src/video_core/renderer_vulkan/vk_texture_cache.h
  12. 15
      src/video_core/vulkan_common/vulkan_device.h

3
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt

@ -39,9 +39,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_VERTEX_INPUT_DYNAMIC_STATE("vertex_input_dynamic_state"), RENDERER_VERTEX_INPUT_DYNAMIC_STATE("vertex_input_dynamic_state"),
RENDERER_SAMPLE_SHADING("sample_shading"), RENDERER_SAMPLE_SHADING("sample_shading"),
GPU_UNSWIZZLE_ENABLED("gpu_unswizzle_enabled"), GPU_UNSWIZZLE_ENABLED("gpu_unswizzle_enabled"),
GPU_COMPUTE_UNSWIZZLE_2D("gpu_compute_unswizzle_2d"),
GPU_COMPUTE_UNSWIZZLE_3D("gpu_compute_unswizzle_3d"),
GPU_COMPUTE_UNSWIZZLE_PITCH("gpu_compute_unswizzle_pitch"),
PICTURE_IN_PICTURE("picture_in_picture"), PICTURE_IN_PICTURE("picture_in_picture"),
USE_CUSTOM_RTC("custom_rtc_enabled"), USE_CUSTOM_RTC("custom_rtc_enabled"),
BLACK_BACKGROUNDS("black_backgrounds"), BLACK_BACKGROUNDS("black_backgrounds"),

21
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt

@ -724,27 +724,6 @@ abstract class SettingsItem(
chunkSizeValuesId = R.array.gpuSwizzleChunkValues chunkSizeValuesId = R.array.gpuSwizzleChunkValues
) )
) )
put(
SwitchSetting(
BooleanSetting.GPU_COMPUTE_UNSWIZZLE_2D,
titleId = R.string.gpu_compute_unswizzle_2d,
descriptionId = R.string.gpu_compute_unswizzle_2d_description
)
)
put(
SwitchSetting(
BooleanSetting.GPU_COMPUTE_UNSWIZZLE_3D,
titleId = R.string.gpu_compute_unswizzle_3d,
descriptionId = R.string.gpu_compute_unswizzle_3d_description
)
)
put(
SwitchSetting(
BooleanSetting.GPU_COMPUTE_UNSWIZZLE_PITCH,
titleId = R.string.gpu_compute_unswizzle_pitch,
descriptionId = R.string.gpu_compute_unswizzle_pitch_description
)
)
put( put(
SingleChoiceSetting( SingleChoiceSetting(
IntSetting.FAST_CPU_TIME, IntSetting.FAST_CPU_TIME,

3
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt

@ -308,9 +308,6 @@ class SettingsFragmentPresenter(
add(BooleanSetting.RENDERER_ASYNCHRONOUS_GPU_EMULATION.key) add(BooleanSetting.RENDERER_ASYNCHRONOUS_GPU_EMULATION.key)
add(BooleanSetting.RENDERER_ASYNC_PRESENTATION.key) add(BooleanSetting.RENDERER_ASYNC_PRESENTATION.key)
add(SettingsItem.GPU_UNSWIZZLE_COMBINED) add(SettingsItem.GPU_UNSWIZZLE_COMBINED)
add(BooleanSetting.GPU_COMPUTE_UNSWIZZLE_2D.key)
add(BooleanSetting.GPU_COMPUTE_UNSWIZZLE_3D.key)
add(BooleanSetting.GPU_COMPUTE_UNSWIZZLE_PITCH.key)
add(HeaderSetting(R.string.extensions)) add(HeaderSetting(R.string.extensions))

6
src/android/app/src/main/res/values/strings.xml

@ -527,12 +527,6 @@
<string name="gpu_unswizzle_settings">GPU Unswizzle Settings</string> <string name="gpu_unswizzle_settings">GPU Unswizzle Settings</string>
<string name="gpu_unswizzle_settings_description">Configure GPU-based texture unswizzling parameters or disable it entirely. Adjust these settings to balance performance and texture loading quality.</string> <string name="gpu_unswizzle_settings_description">Configure GPU-based texture unswizzling parameters or disable it entirely. Adjust these settings to balance performance and texture loading quality.</string>
<string name="gpu_unswizzle_enable">Enable GPU Unswizzle</string> <string name="gpu_unswizzle_enable">Enable GPU Unswizzle</string>
<string name="gpu_compute_unswizzle_2d">GPU Compute Unswizzle (2D)</string>
<string name="gpu_compute_unswizzle_2d_description">Unswizzles block-linear 2D textures with a compute shader instead of the CPU. Disable to upload 2D textures through the CPU path.</string>
<string name="gpu_compute_unswizzle_3d">GPU Compute Unswizzle (3D)</string>
<string name="gpu_compute_unswizzle_3d_description">Unswizzles block-linear 3D textures with a compute shader instead of the CPU. Disable to upload 3D textures through the CPU path.</string>
<string name="gpu_compute_unswizzle_pitch">GPU Compute Unswizzle (Pitch)</string>
<string name="gpu_compute_unswizzle_pitch_description">Unswizzles pitch-linear textures with a compute shader instead of the CPU. Disable to upload linear textures through the CPU path.</string>
<string name="gpu_unswizzle_disabled">Disabled</string> <string name="gpu_unswizzle_disabled">Disabled</string>
<string name="gpu_unswizzle_texture_size">GPU Unswizzle Max Texture Size</string> <string name="gpu_unswizzle_texture_size">GPU Unswizzle Max Texture Size</string>
<string name="gpu_unswizzle_texture_size_description">Sets the maximum size (MB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead.</string> <string name="gpu_unswizzle_texture_size_description">Sets the maximum size (MB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead.</string>

10
src/common/settings.h

@ -605,16 +605,6 @@ struct Values {
SwitchableSetting<bool> gpu_unswizzle_enabled{linkage, false, "gpu_unswizzle_enabled", SwitchableSetting<bool> gpu_unswizzle_enabled{linkage, false, "gpu_unswizzle_enabled",
Category::RendererHacks}; Category::RendererHacks};
SwitchableSetting<bool> gpu_compute_unswizzle_2d{linkage, true, "gpu_compute_unswizzle_2d",
Category::RendererHacks};
SwitchableSetting<bool> gpu_compute_unswizzle_3d{linkage, true, "gpu_compute_unswizzle_3d",
Category::RendererHacks};
SwitchableSetting<bool> gpu_compute_unswizzle_pitch{linkage, true,
"gpu_compute_unswizzle_pitch",
Category::RendererHacks};
SwitchableSetting<ExtendedDynamicState> dyna_state{linkage, SwitchableSetting<ExtendedDynamicState> dyna_state{linkage,
#if defined(__ANDROID__) #if defined(__ANDROID__)
ExtendedDynamicState::Disabled, ExtendedDynamicState::Disabled,

9
src/video_core/host_shaders/block_linear_unswizzle_3d_bcn.comp

@ -1,10 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
#version 430 #version 430
#ifdef VULKAN #ifdef VULKAN
#define HAS_EXTENDED_TYPES 0
#extension GL_EXT_shader_16bit_storage : require
#extension GL_EXT_shader_8bit_storage : require
#define HAS_EXTENDED_TYPES 1
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants { #define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
#define END_PUSH_CONSTANTS }; #define END_PUSH_CONSTANTS };
#define UNIFORM(n) #define UNIFORM(n)
@ -40,6 +42,9 @@ layout(push_constant) uniform PushConstants {
uint block_depth; // Offset 48 uint block_depth; // Offset 48
uint block_depth_mask; // Offset 52 uint block_depth_mask; // Offset 52
int _pad; // Offset 56
ivec3 destination; // Offset 60
} pc; } pc;
#else #else
BEGIN_PUSH_CONSTANTS BEGIN_PUSH_CONSTANTS

1
src/video_core/renderer_vulkan/renderer_vulkan.cpp

@ -169,7 +169,6 @@ try
} }
RendererVulkan::~RendererVulkan() { RendererVulkan::~RendererVulkan() {
scheduler.WaitWorker();
scheduler.RegisterOnSubmit([] {}); scheduler.RegisterOnSubmit([] {});
void(device.GetLogical().WaitIdle()); void(device.GetLogical().WaitIdle());
} }

260
src/video_core/renderer_vulkan/vk_compute_pass.cpp

@ -24,10 +24,7 @@
#include "video_core/host_shaders/resolve_conditional_render_comp_spv.h" #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_quad_indexed_comp_spv.h"
#include "video_core/host_shaders/vulkan_uint8_comp_spv.h" #include "video_core/host_shaders/vulkan_uint8_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/block_linear_unswizzle_3d_bcn_comp_spv.h" #include "video_core/host_shaders/block_linear_unswizzle_3d_bcn_comp_spv.h"
#include "video_core/host_shaders/pitch_unswizzle_comp_spv.h"
#include "video_core/renderer_vulkan/vk_compute_pass.h" #include "video_core/renderer_vulkan/vk_compute_pass.h"
#include "video_core/surface.h" #include "video_core/surface.h"
#include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h"
@ -236,26 +233,6 @@ struct QueriesPrefixScanPushConstants {
struct ConditionalRenderingResolvePushConstants { struct ConditionalRenderingResolvePushConstants {
u32 compare_to_zero; u32 compare_to_zero;
}; };
struct BlockLinear3DImagePushConstants {
alignas(16) std::array<u32, 3> origin;
alignas(16) std::array<s32, 3> destination;
u32 bytes_per_block_log2;
u32 slice_size;
u32 block_size;
u32 x_shift;
u32 block_height;
u32 block_height_mask;
u32 block_depth;
u32 block_depth_mask;
};
struct PitchUnswizzlePushConstants {
std::array<u32, 2> origin;
std::array<s32, 2> destination;
u32 bytes_per_block;
u32 pitch;
};
} // Anonymous namespace } // Anonymous namespace
ComputePass::ComputePass(const Device& device_, Scheduler& scheduler, DescriptorPool& descriptor_pool, ComputePass::ComputePass(const Device& device_, Scheduler& scheduler, DescriptorPool& descriptor_pool,
@ -677,235 +654,6 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
scheduler.Finish(); scheduler.Finish();
} }
namespace {
void RecordUnswizzleImageEntry(vk::CommandBuffer cmdbuf, VkPipeline pipeline, VkImage image,
VkImageAspectFlags aspect_mask, bool is_initialized) {
const VkImageMemoryBarrier image_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = static_cast<VkAccessFlags>(is_initialized ? VK_ACCESS_SHADER_WRITE_BIT
: VK_ACCESS_NONE),
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange{
.aspectMask = aspect_mask,
.baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
cmdbuf.PipelineBarrier(is_initialized ? vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER
: VkPipelineStageFlags(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT),
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
}
void RecordUnswizzleImageExit(vk::CommandBuffer cmdbuf, VkImage image,
VkImageAspectFlags aspect_mask) {
const VkImageMemoryBarrier image_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange{
.aspectMask = aspect_mask,
.baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER, 0, image_barrier);
}
} // Anonymous namespace
BlockLinearUnswizzleImage2DPass::BlockLinearUnswizzleImage2DPass(
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<sizeof(BlockLinearSwizzle2DParams)>,
BLOCK_LINEAR_UNSWIZZLE_2D_COMP_SPV),
scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
BlockLinearUnswizzleImage2DPass::~BlockLinearUnswizzleImage2DPass() = default;
void BlockLinearUnswizzleImage2DPass::Unswizzle(
Image& image, const StagingBufferRef& map,
std::span<const VideoCommon::SwizzleParameters> swizzles) {
using namespace VideoCommon::Accelerated;
scheduler.RequestOutsideRenderPassOperationContext();
const VkPipeline vk_pipeline = *pipeline;
const VkImageAspectFlags aspect_mask = image.AspectMask();
const VkImage vk_image = image.Handle();
const bool is_initialized = image.ExchangeInitialization();
scheduler.Record([vk_pipeline, vk_image, aspect_mask, is_initialized](vk::CommandBuffer cmdbuf) {
RecordUnswizzleImageEntry(cmdbuf, vk_pipeline, vk_image, aspect_mask, is_initialized);
});
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, 32U);
const u32 num_dispatches_z = image.info.resources.layers;
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 auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_dispatches_z, 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, num_dispatches_z);
});
}
scheduler.Record([vk_image, aspect_mask](vk::CommandBuffer cmdbuf) {
RecordUnswizzleImageExit(cmdbuf, vk_image, aspect_mask);
});
scheduler.Finish();
}
BlockLinearUnswizzleImage3DPass::BlockLinearUnswizzleImage3DPass(
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<sizeof(BlockLinear3DImagePushConstants)>,
BLOCK_LINEAR_UNSWIZZLE_3D_COMP_SPV),
scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
BlockLinearUnswizzleImage3DPass::~BlockLinearUnswizzleImage3DPass() = default;
void BlockLinearUnswizzleImage3DPass::Unswizzle(
Image& image, const StagingBufferRef& map,
std::span<const VideoCommon::SwizzleParameters> swizzles) {
using namespace VideoCommon::Accelerated;
scheduler.RequestOutsideRenderPassOperationContext();
const VkPipeline vk_pipeline = *pipeline;
const VkImageAspectFlags aspect_mask = image.AspectMask();
const VkImage vk_image = image.Handle();
const bool is_initialized = image.ExchangeInitialization();
scheduler.Record([vk_pipeline, vk_image, aspect_mask, is_initialized](vk::CommandBuffer cmdbuf) {
RecordUnswizzleImageEntry(cmdbuf, vk_pipeline, vk_image, aspect_mask, is_initialized);
});
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, 16U);
const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 8U);
const u32 num_dispatches_z = Common::DivCeil(swizzle.num_tiles.depth, 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 auto p = MakeBlockLinearSwizzle3DParams(swizzle, image.info);
const BlockLinear3DImagePushConstants params{
.origin = p.origin,
.destination = p.destination,
.bytes_per_block_log2 = p.bytes_per_block_log2,
.slice_size = p.slice_size,
.block_size = p.block_size,
.x_shift = p.x_shift,
.block_height = p.block_height,
.block_height_mask = p.block_height_mask,
.block_depth = p.block_depth,
.block_depth_mask = p.block_depth_mask,
};
scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_dispatches_z, 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, num_dispatches_z);
});
}
scheduler.Record([vk_image, aspect_mask](vk::CommandBuffer cmdbuf) {
RecordUnswizzleImageExit(cmdbuf, vk_image, aspect_mask);
});
scheduler.Finish();
}
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<sizeof(PitchUnswizzlePushConstants)>,
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<const VideoCommon::SwizzleParameters> swizzles) {
scheduler.RequestOutsideRenderPassOperationContext();
const VkPipeline vk_pipeline = *pipeline;
const VkImageAspectFlags aspect_mask = image.AspectMask();
const VkImage vk_image = image.Handle();
const bool is_initialized = image.ExchangeInitialization();
scheduler.Record([vk_pipeline, vk_image, aspect_mask, is_initialized](vk::CommandBuffer cmdbuf) {
RecordUnswizzleImageEntry(cmdbuf, vk_pipeline, vk_image, aspect_mask, is_initialized);
});
const u32 bytes_per_block = VideoCore::Surface::BytesPerBlock(image.info.format);
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, 32U);
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 = 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);
});
}
scheduler.Record([vk_image, aspect_mask](vk::CommandBuffer cmdbuf) {
RecordUnswizzleImageExit(cmdbuf, vk_image, aspect_mask);
});
scheduler.Finish();
}
constexpr u32 BL3D_BINDING_INPUT_BUFFER = 0; constexpr u32 BL3D_BINDING_INPUT_BUFFER = 0;
constexpr u32 BL3D_BINDING_OUTPUT_BUFFER = 1; constexpr u32 BL3D_BINDING_OUTPUT_BUFFER = 1;
@ -923,6 +671,10 @@ struct alignas(16) BlockLinearUnswizzle3DPushConstants {
u32 block_depth; // Offset 48 u32 block_depth; // Offset 48
u32 block_depth_mask; // Offset 52 u32 block_depth_mask; // Offset 52
s32 _pad; // Offset 56
s32 destination[3]; // Offset 60
s32 _pad_end; // Offset 72
}; };
static_assert(sizeof(BlockLinearUnswizzle3DPushConstants) <= 128); static_assert(sizeof(BlockLinearUnswizzle3DPushConstants) <= 128);
@ -1029,6 +781,10 @@ void BlockLinearUnswizzle3DPass::UnswizzleChunk(
pc.origin[1] = params.origin[1]; pc.origin[1] = params.origin[1];
pc.origin[2] = z_start; // Current chunk's Z start pc.origin[2] = z_start; // Current chunk's Z start
pc.destination[0] = params.destination[0];
pc.destination[1] = params.destination[1];
pc.destination[2] = 0; // Shader writes to start of output buffer
pc.bytes_per_block_log2 = params.bytes_per_block_log2; pc.bytes_per_block_log2 = params.bytes_per_block_log2;
pc.slice_size = params.slice_size; pc.slice_size = params.slice_size;
pc.block_size = params.block_size; pc.block_size = params.block_size;

52
src/video_core/renderer_vulkan/vk_compute_pass.h

@ -25,7 +25,6 @@ struct SwizzleParameters;
namespace Vulkan { namespace Vulkan {
using VideoCommon::Accelerated::BlockLinearSwizzle2DParams;
using VideoCommon::Accelerated::BlockLinearSwizzle3DParams; using VideoCommon::Accelerated::BlockLinearSwizzle3DParams;
class Device; class Device;
@ -166,57 +165,6 @@ private:
}; };
class BlockLinearUnswizzleImage2DPass final : public ComputePass {
public:
explicit BlockLinearUnswizzleImage2DPass(
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
StagingBufferPool& staging_buffer_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
~BlockLinearUnswizzleImage2DPass();
void Unswizzle(Image& image, const StagingBufferRef& map,
std::span<const VideoCommon::SwizzleParameters> swizzles);
private:
Scheduler& scheduler;
StagingBufferPool& staging_buffer_pool;
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
};
class BlockLinearUnswizzleImage3DPass final : public ComputePass {
public:
explicit BlockLinearUnswizzleImage3DPass(
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
StagingBufferPool& staging_buffer_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
~BlockLinearUnswizzleImage3DPass();
void Unswizzle(Image& image, const StagingBufferRef& map,
std::span<const VideoCommon::SwizzleParameters> swizzles);
private:
Scheduler& scheduler;
StagingBufferPool& staging_buffer_pool;
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
};
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<const VideoCommon::SwizzleParameters> swizzles);
private:
Scheduler& scheduler;
StagingBufferPool& staging_buffer_pool;
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
};
class MSAACopyPass final : public ComputePass { class MSAACopyPass final : public ComputePass {
public: public:
explicit MSAACopyPass(const Device& device_, Scheduler& scheduler_, explicit MSAACopyPass(const Device& device_, Scheduler& scheduler_,

143
src/video_core/renderer_vulkan/vk_texture_cache.cpp

@ -6,9 +6,7 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cstdlib>
#include <optional> #include <optional>
#include <string_view>
#include <span> #include <span>
#include <memory> #include <memory>
#include <vector> #include <vector>
@ -222,50 +220,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
return allocator.CreateImage(image_ci); return allocator.CreateImage(image_ci);
} }
[[nodiscard]] VkFormat UnswizzleStorageFormat(u32 bytes_per_block) {
switch (bytes_per_block) {
case 1:
return VK_FORMAT_R8_UINT;
case 2:
return VK_FORMAT_R16_UINT;
case 4:
return VK_FORMAT_R32_UINT;
case 8:
return VK_FORMAT_R32G32_UINT;
case 16:
return VK_FORMAT_R32G32B32A32_UINT;
default:
ASSERT_MSG(false, "Invalid bytes_per_block={} for accelerated unswizzle", bytes_per_block);
return VK_FORMAT_R32_UINT;
}
}
[[nodiscard]] bool IsUnswizzleStorageFormatSupported(const Device& device, u32 bytes_per_block) {
switch (bytes_per_block) {
case 1:
if (!device.IsStorageBuffer8BitAccessSupported()) {
return false;
}
break;
case 2:
if (!device.IsStorageBuffer16BitAccessSupported()) {
return false;
}
break;
case 4:
case 8:
case 16:
break;
default:
return false;
}
return device.IsFormatSupported(UnswizzleStorageFormat(bytes_per_block),
VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT, FormatType::Optimal);
}
[[nodiscard]] vk::ImageView MakeStorageView(const vk::Device& device, u32 level, VkImage image, [[nodiscard]] vk::ImageView MakeStorageView(const vk::Device& device, u32 level, VkImage image,
VkFormat format,
VkImageViewType view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY) {
VkFormat format) {
static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{ static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
@ -276,7 +232,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
.pNext = &storage_image_view_usage_create_info, .pNext = &storage_image_view_usage_create_info,
.flags = 0, .flags = 0,
.image = image, .image = image,
.viewType = view_type,
.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
.format = format, .format = format,
.components{ .components{
.r = VK_COMPONENT_SWIZZLE_IDENTITY, .r = VK_COMPONENT_SWIZZLE_IDENTITY,
@ -959,56 +915,10 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
if (!device.IsKhrImageFormatListSupported()) { if (!device.IsKhrImageFormatListSupported()) {
return; return;
} }
bool enable_2d = Settings::values.gpu_compute_unswizzle_2d.GetValue();
bool enable_3d = Settings::values.gpu_compute_unswizzle_3d.GetValue();
bool enable_pitch = Settings::values.gpu_compute_unswizzle_pitch.GetValue();
if (const char* const unswizzle_env = std::getenv("GPU_COMPUTE_UNSWIZZLE")) {
const std::string_view selection{unswizzle_env};
if (selection == "0" || selection == "none") {
enable_2d = enable_3d = enable_pitch = false;
} else if (selection != "1" && selection != "all") {
enable_2d = selection.find("2d") != std::string_view::npos;
enable_3d = selection.find("3d") != std::string_view::npos;
enable_pitch = selection.find("pitch") != std::string_view::npos;
}
LOG_INFO(Render_Vulkan, "GPU_COMPUTE_UNSWIZZLE={} (2d={}, 3d={}, pitch={})", selection,
enable_2d, enable_3d, enable_pitch);
}
const bool unswizzle_caps_ok = device.IsStorageBuffer8BitAccessSupported() &&
device.IsStorageBuffer16BitAccessSupported() &&
device.IsFormatlessImageStoreSupported();
if (!unswizzle_caps_ok) {
LOG_INFO(Render_Vulkan,
"GPU image unswizzle passes unsupported (8bit={}, 16bit={}, formatless={})",
device.IsStorageBuffer8BitAccessSupported(),
device.IsStorageBuffer16BitAccessSupported(),
device.IsFormatlessImageStoreSupported());
} else {
if (enable_2d) {
bl_unswizzle_2d_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
compute_pass_descriptor_queue);
}
if (enable_3d) {
bl_unswizzle_3d_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
compute_pass_descriptor_queue);
}
if (enable_pitch) {
pitch_unswizzle_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
compute_pass_descriptor_queue);
}
}
for (size_t index_a = 0; index_a < VideoCore::Surface::MaxPixelFormat; index_a++) { for (size_t index_a = 0; index_a < VideoCore::Surface::MaxPixelFormat; index_a++) {
const auto image_format = static_cast<PixelFormat>(index_a); const auto image_format = static_cast<PixelFormat>(index_a);
if (IsPixelFormatASTC(image_format) && !device.IsOptimalAstcSupported()) { if (IsPixelFormatASTC(image_format) && !device.IsOptimalAstcSupported()) {
view_formats[index_a].push_back(VK_FORMAT_A8B8G8R8_UNORM_PACK32); view_formats[index_a].push_back(VK_FORMAT_A8B8G8R8_UNORM_PACK32);
} else if (HasImageUnswizzlePasses() && !IsPixelFormatBCn(image_format) &&
VideoCore::Surface::GetFormatType(image_format) ==
VideoCore::Surface::SurfaceType::ColorTexture) {
const u32 bytes_per_block = VideoCore::Surface::BytesPerBlock(image_format);
if (IsUnswizzleStorageFormatSupported(device, bytes_per_block)) {
view_formats[index_a].push_back(UnswizzleStorageFormat(bytes_per_block));
}
} }
for (size_t index_b = 0; index_b < VideoCore::Surface::MaxPixelFormat; index_b++) { for (size_t index_b = 0; index_b < VideoCore::Surface::MaxPixelFormat; index_b++) {
const auto view_format = static_cast<PixelFormat>(index_b); const auto view_format = static_cast<PixelFormat>(index_b);
@ -1701,14 +1611,6 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
flags |= VideoCommon::ImageFlagBits::Converted; flags |= VideoCommon::ImageFlagBits::Converted;
flags |= VideoCommon::ImageFlagBits::CostlyLoad; flags |= VideoCommon::ImageFlagBits::CostlyLoad;
} }
if (runtime->HasUnswizzlePassFor(info.type) && !IsPixelFormatASTC(info.format) &&
!IsPixelFormatBCn(info.format) && info.num_samples == 1 &&
VideoCore::Surface::GetFormatType(info.format) ==
VideoCore::Surface::SurfaceType::ColorTexture) {
if (IsUnswizzleStorageFormatSupported(runtime->device, BytesPerBlock(info.format))) {
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
}
}
if (runtime->device.HasDebuggingToolAttached()) { if (runtime->device.HasDebuggingToolAttached()) {
original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
} }
@ -2074,20 +1976,13 @@ VkImageView Image::StorageImageView(s32 level) noexcept {
if (!view) { if (!view) {
auto format_info = auto format_info =
MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, true, info.format); MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, true, info.format);
VkImageViewType view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
if (WillUseAcceleratedAstcDecode(runtime->device, info)) { if (WillUseAcceleratedAstcDecode(runtime->device, info)) {
format_info.format = WillUseWidenedAstcFormat(runtime->device, info) format_info.format = WillUseWidenedAstcFormat(runtime->device, info)
? VK_FORMAT_R32G32B32A32_SFLOAT ? VK_FORMAT_R32G32B32A32_SFLOAT
: VK_FORMAT_A8B8G8R8_UNORM_PACK32; : VK_FORMAT_A8B8G8R8_UNORM_PACK32;
} else if (True(flags & ImageFlagBits::AcceleratedUpload) &&
!IsPixelFormatASTC(info.format) && !IsPixelFormatBCn(info.format)) {
format_info.format = UnswizzleStorageFormat(BytesPerBlock(info.format));
view_type = info.type == ImageType::e3D ? VK_IMAGE_VIEW_TYPE_3D
: info.type == ImageType::Linear ? VK_IMAGE_VIEW_TYPE_2D
: VK_IMAGE_VIEW_TYPE_2D_ARRAY;
} }
view = MakeStorageView(runtime->device.GetLogical(), level, *(this->*current_image), view = MakeStorageView(runtime->device.GetLogical(), level, *(this->*current_image),
format_info.format, view_type);
format_info.format);
} }
return *view; return *view;
} }
@ -2621,36 +2516,16 @@ void TextureCacheRuntime::AccelerateImageUpload(
return astc_decoder_pass->Assemble(image, map, swizzles); return astc_decoder_pass->Assemble(image, map, swizzles);
} }
if (IsPixelFormatBCn(image.info.format)) {
if (Settings::values.gpu_unswizzle_enabled.GetValue() && bl3d_unswizzle_pass &&
image.info.type == ImageType::e3D && image.info.resources.levels == 1 &&
image.info.resources.layers == 1) {
return bl3d_unswizzle_pass->Unswizzle(image, map, swizzles, z_start, z_count);
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");
} }
ASSERT(false && "GPU unswizzle is disabled for BCn 3D texture");
ASSERT(false);
return; return;
} }
if (HasImageUnswizzlePasses()) {
switch (image.info.type) {
case ImageType::e2D:
if (bl_unswizzle_2d_pass) {
return bl_unswizzle_2d_pass->Unswizzle(image, map, swizzles);
}
break;
case ImageType::e3D:
if (bl_unswizzle_3d_pass) {
return bl_unswizzle_3d_pass->Unswizzle(image, map, swizzles);
}
break;
case ImageType::Linear:
if (pitch_unswizzle_pass) {
return pitch_unswizzle_pass->Unswizzle(image, map, swizzles);
}
break;
default:
break;
}
if (bl3d_unswizzle_pass && IsPixelFormatBCn(image.info.format) && image.info.type == ImageType::e3D && image.info.resources.levels == 1 && image.info.resources.layers == 1) {
return bl3d_unswizzle_pass->Unswizzle(image, map, swizzles, z_start, z_count);
} }
ASSERT(false); ASSERT(false);

23
src/video_core/renderer_vulkan/vk_texture_cache.h

@ -130,30 +130,7 @@ public:
std::optional<ASTCDecoderPass> astc_decoder_pass; std::optional<ASTCDecoderPass> astc_decoder_pass;
std::optional<BlockLinearUnswizzle3DPass> bl3d_unswizzle_pass; std::optional<BlockLinearUnswizzle3DPass> bl3d_unswizzle_pass;
std::optional<BlockLinearUnswizzleImage2DPass> bl_unswizzle_2d_pass;
std::optional<BlockLinearUnswizzleImage3DPass> bl_unswizzle_3d_pass;
std::optional<PitchUnswizzlePass> pitch_unswizzle_pass;
std::optional<MSAACopyPass> msaa_copy_pass; std::optional<MSAACopyPass> msaa_copy_pass;
/// True when the buffer->image unswizzle pass for this image type is active.
bool HasUnswizzlePassFor(VideoCommon::ImageType type) const noexcept {
switch (type) {
case VideoCommon::ImageType::e2D:
return bl_unswizzle_2d_pass.has_value();
case VideoCommon::ImageType::e3D:
return bl_unswizzle_3d_pass.has_value();
case VideoCommon::ImageType::Linear:
return pitch_unswizzle_pass.has_value();
default:
return false;
}
}
/// True when any buffer->image unswizzle pass is active on this device.
bool HasImageUnswizzlePasses() const noexcept {
return bl_unswizzle_2d_pass.has_value() || bl_unswizzle_3d_pass.has_value() ||
pitch_unswizzle_pass.has_value();
}
const Settings::ResolutionScalingInfo& resolution; const Settings::ResolutionScalingInfo& resolution;
std::array<std::vector<VkFormat>, VideoCore::Surface::MaxPixelFormat> view_formats; std::array<std::vector<VkFormat>, VideoCore::Surface::MaxPixelFormat> view_formats;

15
src/video_core/vulkan_common/vulkan_device.h

@ -400,16 +400,6 @@ FN_MAX_LIMIT_LIST
return features.bit16_storage.uniformAndStorageBuffer16BitAccess; return features.bit16_storage.uniformAndStorageBuffer16BitAccess;
} }
/// Returns true if the device supports reading 8-bit values from a storage buffer.
bool IsStorageBuffer8BitAccessSupported() const {
return features.bit8_storage.storageBuffer8BitAccess;
}
/// Returns true if the device supports reading 16-bit values from a storage buffer.
bool IsStorageBuffer16BitAccessSupported() const {
return features.bit16_storage.storageBuffer16BitAccess;
}
/// Returns true if the device supports binding multisample images as storage images. /// Returns true if the device supports binding multisample images as storage images.
bool IsStorageImageMultisampleSupported() const { bool IsStorageImageMultisampleSupported() const {
return features.features.shaderStorageImageMultisample; return features.features.shaderStorageImageMultisample;
@ -440,11 +430,6 @@ FN_MAX_LIMIT_LIST
return features.features.shaderStorageImageReadWithoutFormat; return features.features.shaderStorageImageReadWithoutFormat;
} }
/// Returns true if formatless image store is supported.
bool IsFormatlessImageStoreSupported() const {
return features.features.shaderStorageImageWriteWithoutFormat;
}
/// Returns true if shader int64 is supported. /// Returns true if shader int64 is supported.
bool IsShaderInt64Supported() const { bool IsShaderInt64Supported() const {
return features.features.shaderInt64; return features.features.shaderInt64;

Loading…
Cancel
Save