diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index bd8b9088b6..c37987691f 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -952,6 +952,10 @@
R32 SInt to R32 UInt
R32 SFloat to R32 SInt
+
+ Force Identity Swizzle
+ Forces identity component swizzle for storage and input attachment images. Required by Vulkan spec. Disable only for debugging driver issues.
+
VRAM Usage Mode
Control how aggressively the emulator allocates and frees GPU memory.
diff --git a/src/common/settings.h b/src/common/settings.h
index 58ce0b5f11..4f6dda8f21 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -350,7 +350,7 @@ struct Values {
linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer};
SwitchableSetting accelerate_astc{linkage,
#ifdef ANDROID
- AstcDecodeMode::Cpu,
+ AstcDecodeMode::Gpu,
#else
AstcDecodeMode::Gpu,
#endif
@@ -401,7 +401,7 @@ struct Values {
true,
true};
SwitchableSetting fsr_sharpening_slider{linkage,
- 25,
+ 0,
0,
200,
"fsr_sharpening_slider",
@@ -457,6 +457,10 @@ struct Values {
FormatReinterpretation::Disabled,
"format_reinterpretation",
Category::RendererAdvanced};
+ SwitchableSetting force_identity_swizzle{linkage,
+ false,
+ "force_identity_swizzle",
+ Category::RendererAdvanced};
SwitchableSetting vram_usage_mode{linkage,
VramUsageMode::Conservative,
"vram_usage_mode",
diff --git a/src/qt_common/config/shared_translation.cpp b/src/qt_common/config/shared_translation.cpp
index 8f3881d9c7..2699c05daa 100644
--- a/src/qt_common/config/shared_translation.cpp
+++ b/src/qt_common/config/shared_translation.cpp
@@ -197,10 +197,15 @@ std::unique_ptr InitializeTranslations(QObject* parent)
"16:9, so modifications are required to get other ratios.\nAlso controls the "
"aspect ratio of captured screenshots."));
INSERT(Settings,
- format_reinterpretation,
- tr("Format Reinterpretation:"),
- tr("Reinterprets certain texture formats to improve performance.\nMay cause "
- "graphical issues in some games."));
+ format_reinterpretation,
+ tr("Format Reinterpretation:"),
+ tr("Reinterprets certain texture formats for accuracy rendering.\nMay cause "
+ "graphical issues in some games."));
+ INSERT(Settings,
+ force_identity_swizzle,
+ tr("Force Identity Swizzle"),
+ tr("Forces identity component swizzle for storage and input attachment images.\n"
+ "Required by Vulkan spec. Disable only for debugging driver issues."));
INSERT(Settings,
use_disk_shader_cache,
tr("Use persistent pipeline cache"),
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 426c446b91..c41539e43a 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -2168,6 +2168,11 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
.usage = ImageUsageFlags(format_info, format),
};
+ // Vulkan spec: STORAGE_IMAGE and INPUT_ATTACHMENT descriptors MUST use identity swizzle
+ // Using non-identity swizzle causes validation error and undefined behavior
+ const bool requires_identity_swizzle = Settings::values.force_identity_swizzle.GetValue() &&
+ (image_view_usage.usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) != 0;
+
const VkImageViewCreateInfo create_info{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = &image_view_usage,
@@ -2176,10 +2181,10 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
.viewType = VkImageViewType{},
.format = view_format,
.components{
- .r = ComponentSwizzle(swizzle[0]),
- .g = ComponentSwizzle(swizzle[1]),
- .b = ComponentSwizzle(swizzle[2]),
- .a = ComponentSwizzle(swizzle[3]),
+ .r = requires_identity_swizzle ? VK_COMPONENT_SWIZZLE_IDENTITY : ComponentSwizzle(swizzle[0]),
+ .g = requires_identity_swizzle ? VK_COMPONENT_SWIZZLE_IDENTITY : ComponentSwizzle(swizzle[1]),
+ .b = requires_identity_swizzle ? VK_COMPONENT_SWIZZLE_IDENTITY : ComponentSwizzle(swizzle[2]),
+ .a = requires_identity_swizzle ? VK_COMPONENT_SWIZZLE_IDENTITY : ComponentSwizzle(swizzle[3]),
},
.subresourceRange = MakeSubresourceRange(aspect_mask, info.range),
};