summaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/CMakeLists.txt6
-rw-r--r--src/video_core/engines/maxwell_3d.cpp12
-rw-r--r--src/video_core/gpu.cpp1
-rw-r--r--src/video_core/gpu_thread.cpp2
-rw-r--r--src/video_core/renderer_base.cpp1
-rw-r--r--src/video_core/renderer_base.h5
-rw-r--r--src/video_core/renderer_null/renderer_null.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_context.h1
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp8
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp9
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h6
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp54
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp10
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp17
-rw-r--r--src/video_core/renderer_vulkan/vk_present_manager.cpp52
-rw-r--r--src/video_core/renderer_vulkan/vk_present_manager.h15
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp18
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp14
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp10
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_turbo_mode.cpp21
-rw-r--r--src/video_core/renderer_vulkan/vk_turbo_mode.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_update_descriptor.h2
-rw-r--r--src/video_core/vulkan_common/vulkan_debug_callback.cpp28
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp103
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h14
-rw-r--r--src/video_core/vulkan_common/vulkan_library.cpp18
-rw-r--r--src/video_core/vulkan_common/vulkan_library.h6
29 files changed, 394 insertions, 49 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 308d013d6..94e3000ba 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -281,7 +281,7 @@ create_target_directory_groups(video_core)
281target_link_libraries(video_core PUBLIC common core) 281target_link_libraries(video_core PUBLIC common core)
282target_link_libraries(video_core PUBLIC glad shader_recompiler stb) 282target_link_libraries(video_core PUBLIC glad shader_recompiler stb)
283 283
284if (YUZU_USE_BUNDLED_FFMPEG AND NOT WIN32) 284if (YUZU_USE_BUNDLED_FFMPEG AND NOT (WIN32 OR ANDROID))
285 add_dependencies(video_core ffmpeg-build) 285 add_dependencies(video_core ffmpeg-build)
286endif() 286endif()
287 287
@@ -345,3 +345,7 @@ endif()
345if (YUZU_ENABLE_LTO) 345if (YUZU_ENABLE_LTO)
346 set_property(TARGET video_core PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) 346 set_property(TARGET video_core PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
347endif() 347endif()
348
349if (ANDROID AND ARCHITECTURE_arm64)
350 target_link_libraries(video_core PRIVATE adrenotools)
351endif()
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 2f986097f..62d70e9f3 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -593,6 +593,12 @@ void Maxwell3D::ProcessQueryCondition() {
593} 593}
594 594
595void Maxwell3D::ProcessCounterReset() { 595void Maxwell3D::ProcessCounterReset() {
596#if ANDROID
597 if (!Settings::IsGPULevelHigh()) {
598 // This is problematic on Android, disable on GPU Normal.
599 return;
600 }
601#endif
596 switch (regs.clear_report_value) { 602 switch (regs.clear_report_value) {
597 case Regs::ClearReport::ZPassPixelCount: 603 case Regs::ClearReport::ZPassPixelCount:
598 rasterizer->ResetCounter(QueryType::SamplesPassed); 604 rasterizer->ResetCounter(QueryType::SamplesPassed);
@@ -614,6 +620,12 @@ std::optional<u64> Maxwell3D::GetQueryResult() {
614 case Regs::ReportSemaphore::Report::Payload: 620 case Regs::ReportSemaphore::Report::Payload:
615 return regs.report_semaphore.payload; 621 return regs.report_semaphore.payload;
616 case Regs::ReportSemaphore::Report::ZPassPixelCount64: 622 case Regs::ReportSemaphore::Report::ZPassPixelCount64:
623#if ANDROID
624 if (!Settings::IsGPULevelHigh()) {
625 // This is problematic on Android, disable on GPU Normal.
626 return 120;
627 }
628#endif
617 // Deferred. 629 // Deferred.
618 rasterizer->Query(regs.report_semaphore.Address(), QueryType::SamplesPassed, 630 rasterizer->Query(regs.report_semaphore.Address(), QueryType::SamplesPassed,
619 system.GPU().GetTicks()); 631 system.GPU().GetTicks());
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 295a416a8..456f733cf 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -14,6 +14,7 @@
14#include "core/core.h" 14#include "core/core.h"
15#include "core/core_timing.h" 15#include "core/core_timing.h"
16#include "core/frontend/emu_window.h" 16#include "core/frontend/emu_window.h"
17#include "core/frontend/graphics_context.h"
17#include "core/hle/service/nvdrv/nvdata.h" 18#include "core/hle/service/nvdrv/nvdata.h"
18#include "core/perf_stats.h" 19#include "core/perf_stats.h"
19#include "video_core/cdma_pusher.h" 20#include "video_core/cdma_pusher.h"
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 3c5317777..889144f38 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -7,7 +7,7 @@
7#include "common/settings.h" 7#include "common/settings.h"
8#include "common/thread.h" 8#include "common/thread.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/frontend/emu_window.h" 10#include "core/frontend/graphics_context.h"
11#include "video_core/control/scheduler.h" 11#include "video_core/control/scheduler.h"
12#include "video_core/dma_pusher.h" 12#include "video_core/dma_pusher.h"
13#include "video_core/gpu.h" 13#include "video_core/gpu.h"
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index e8761a747..2d3f58201 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -5,6 +5,7 @@
5 5
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/frontend/emu_window.h" 7#include "core/frontend/emu_window.h"
8#include "core/frontend/graphics_context.h"
8#include "video_core/renderer_base.h" 9#include "video_core/renderer_base.h"
9 10
10namespace VideoCore { 11namespace VideoCore {
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 8d20cbece..3e12a8813 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -9,7 +9,7 @@
9 9
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "core/frontend/emu_window.h" 12#include "core/frontend/framebuffer_layout.h"
13#include "video_core/gpu.h" 13#include "video_core/gpu.h"
14#include "video_core/rasterizer_interface.h" 14#include "video_core/rasterizer_interface.h"
15 15
@@ -89,6 +89,9 @@ public:
89 void RequestScreenshot(void* data, std::function<void(bool)> callback, 89 void RequestScreenshot(void* data, std::function<void(bool)> callback,
90 const Layout::FramebufferLayout& layout); 90 const Layout::FramebufferLayout& layout);
91 91
92 /// This is called to notify the rendering backend of a surface change
93 virtual void NotifySurfaceChanged() {}
94
92protected: 95protected:
93 Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle. 96 Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
94 std::unique_ptr<Core::Frontend::GraphicsContext> context; 97 std::unique_ptr<Core::Frontend::GraphicsContext> context;
diff --git a/src/video_core/renderer_null/renderer_null.cpp b/src/video_core/renderer_null/renderer_null.cpp
index e2a189b63..be92cc2f4 100644
--- a/src/video_core/renderer_null/renderer_null.cpp
+++ b/src/video_core/renderer_null/renderer_null.cpp
@@ -1,6 +1,8 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/frontend/emu_window.h"
5#include "core/frontend/graphics_context.h"
4#include "video_core/renderer_null/renderer_null.h" 6#include "video_core/renderer_null/renderer_null.h"
5 7
6namespace Null { 8namespace Null {
diff --git a/src/video_core/renderer_opengl/gl_shader_context.h b/src/video_core/renderer_opengl/gl_shader_context.h
index ca2bd8e8e..207a75d42 100644
--- a/src/video_core/renderer_opengl/gl_shader_context.h
+++ b/src/video_core/renderer_opengl/gl_shader_context.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include "core/frontend/emu_window.h" 6#include "core/frontend/emu_window.h"
7#include "core/frontend/graphics_context.h"
7#include "shader_recompiler/frontend/ir/basic_block.h" 8#include "shader_recompiler/frontend/ir/basic_block.h"
8#include "shader_recompiler/frontend/maxwell/control_flow.h" 9#include "shader_recompiler/frontend/maxwell/control_flow.h"
9 10
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index b75d7220d..9a0b10568 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -347,6 +347,14 @@ VkPrimitiveTopology PrimitiveTopology([[maybe_unused]] const Device& device,
347 347
348VkFormat VertexFormat(const Device& device, Maxwell::VertexAttribute::Type type, 348VkFormat VertexFormat(const Device& device, Maxwell::VertexAttribute::Type type,
349 Maxwell::VertexAttribute::Size size) { 349 Maxwell::VertexAttribute::Size size) {
350 if (device.MustEmulateScaledFormats()) {
351 if (type == Maxwell::VertexAttribute::Type::SScaled) {
352 type = Maxwell::VertexAttribute::Type::SInt;
353 } else if (type == Maxwell::VertexAttribute::Type::UScaled) {
354 type = Maxwell::VertexAttribute::Type::UInt;
355 }
356 }
357
350 const VkFormat format{([&]() { 358 const VkFormat format{([&]() {
351 switch (type) { 359 switch (type) {
352 case Maxwell::VertexAttribute::Type::UnusedEnumDoNotUseBecauseItWillGoAway: 360 case Maxwell::VertexAttribute::Type::UnusedEnumDoNotUseBecauseItWillGoAway:
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 8e31eba34..77128c6e2 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -16,7 +16,7 @@
16#include "common/settings.h" 16#include "common/settings.h"
17#include "common/telemetry.h" 17#include "common/telemetry.h"
18#include "core/core_timing.h" 18#include "core/core_timing.h"
19#include "core/frontend/emu_window.h" 19#include "core/frontend/graphics_context.h"
20#include "core/telemetry_session.h" 20#include "core/telemetry_session.h"
21#include "video_core/gpu.h" 21#include "video_core/gpu.h"
22#include "video_core/renderer_vulkan/renderer_vulkan.h" 22#include "video_core/renderer_vulkan/renderer_vulkan.h"
@@ -84,8 +84,8 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
84 Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, 84 Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
85 std::unique_ptr<Core::Frontend::GraphicsContext> context_) try 85 std::unique_ptr<Core::Frontend::GraphicsContext> context_) try
86 : RendererBase(emu_window, std::move(context_)), telemetry_session(telemetry_session_), 86 : RendererBase(emu_window, std::move(context_)), telemetry_session(telemetry_session_),
87 cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary()), 87 cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary(context.get())),
88 instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, 88 instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
89 Settings::values.renderer_debug.GetValue())), 89 Settings::values.renderer_debug.GetValue())),
90 debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), 90 debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
91 surface(CreateSurface(instance, render_window.GetWindowInfo())), 91 surface(CreateSurface(instance, render_window.GetWindowInfo())),
@@ -93,7 +93,8 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
93 state_tracker(), scheduler(device, state_tracker), 93 state_tracker(), scheduler(device, state_tracker),
94 swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, 94 swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
95 render_window.GetFramebufferLayout().height, false), 95 render_window.GetFramebufferLayout().height, false),
96 present_manager(render_window, device, memory_allocator, scheduler, swapchain), 96 present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain,
97 surface),
97 blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, present_manager, 98 blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, present_manager,
98 scheduler, screen_info), 99 scheduler, screen_info),
99 rasterizer(render_window, gpu, cpu_memory, screen_info, device, memory_allocator, 100 rasterizer(render_window, gpu, cpu_memory, screen_info, device, memory_allocator,
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index f44367cb2..b2e8cbd1b 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -54,6 +54,10 @@ public:
54 return device.GetDriverName(); 54 return device.GetDriverName();
55 } 55 }
56 56
57 void NotifySurfaceChanged() override {
58 present_manager.NotifySurfaceChanged();
59 }
60
57private: 61private:
58 void Report() const; 62 void Report() const;
59 63
@@ -63,7 +67,7 @@ private:
63 Core::Memory::Memory& cpu_memory; 67 Core::Memory::Memory& cpu_memory;
64 Tegra::GPU& gpu; 68 Tegra::GPU& gpu;
65 69
66 Common::DynamicLibrary library; 70 std::shared_ptr<Common::DynamicLibrary> library;
67 vk::InstanceDispatch dld; 71 vk::InstanceDispatch dld;
68 72
69 vk::Instance instance; 73 vk::Instance instance;
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 1e0fdd3d9..7cdde992b 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -37,6 +37,10 @@
37#include "video_core/vulkan_common/vulkan_memory_allocator.h" 37#include "video_core/vulkan_common/vulkan_memory_allocator.h"
38#include "video_core/vulkan_common/vulkan_wrapper.h" 38#include "video_core/vulkan_common/vulkan_wrapper.h"
39 39
40#ifdef ANDROID
41extern u32 GetAndroidScreenRotation();
42#endif
43
40namespace Vulkan { 44namespace Vulkan {
41 45
42namespace { 46namespace {
@@ -74,7 +78,48 @@ struct ScreenRectVertex {
74 } 78 }
75}; 79};
76 80
77constexpr std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) { 81#ifdef ANDROID
82
83std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) {
84 constexpr u32 ROTATION_0 = 0;
85 constexpr u32 ROTATION_90 = 1;
86 constexpr u32 ROTATION_180 = 2;
87 constexpr u32 ROTATION_270 = 3;
88
89 // clang-format off
90 switch (GetAndroidScreenRotation()) {
91 case ROTATION_0:
92 // Desktop
93 return { 2.f / width, 0.f, 0.f, 0.f,
94 0.f, 2.f / height, 0.f, 0.f,
95 0.f, 0.f, 1.f, 0.f,
96 -1.f, -1.f, 0.f, 1.f};
97 case ROTATION_180:
98 // Reverse desktop
99 return {-2.f / width, 0.f, 0.f, 0.f,
100 0.f, -2.f / height, 0.f, 0.f,
101 0.f, 0.f, 1.f, 0.f,
102 1.f, 1.f, 0.f, 1.f};
103 case ROTATION_270:
104 // Reverse landscape
105 return { 0.f, -2.f / width, 0.f, 0.f,
106 2.f / height, 0.f, 0.f, 0.f,
107 0.f, 0.f, 1.f, 0.f,
108 -1.f, 1.f, 0.f, 1.f};
109 case ROTATION_90:
110 default:
111 // Landscape
112 return { 0.f, 2.f / width, 0.f, 0.f,
113 -2.f / height, 0.f, 0.f, 0.f,
114 0.f, 0.f, 1.f, 0.f,
115 1.f, -1.f, 0.f, 1.f};
116 }
117 // clang-format on
118}
119
120#else
121
122std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) {
78 // clang-format off 123 // clang-format off
79 return { 2.f / width, 0.f, 0.f, 0.f, 124 return { 2.f / width, 0.f, 0.f, 0.f,
80 0.f, 2.f / height, 0.f, 0.f, 125 0.f, 2.f / height, 0.f, 0.f,
@@ -83,6 +128,8 @@ constexpr std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) {
83 // clang-format on 128 // clang-format on
84} 129}
85 130
131#endif
132
86u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) { 133u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) {
87 using namespace VideoCore::Surface; 134 using namespace VideoCore::Surface;
88 return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)); 135 return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format));
@@ -441,7 +488,12 @@ void BlitScreen::DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& f
441 if (const std::size_t swapchain_images = swapchain.GetImageCount(); 488 if (const std::size_t swapchain_images = swapchain.GetImageCount();
442 swapchain_images != image_count || current_srgb != is_srgb) { 489 swapchain_images != image_count || current_srgb != is_srgb) {
443 current_srgb = is_srgb; 490 current_srgb = is_srgb;
491#ifdef ANDROID
492 // Android is already ordered the same as Switch.
493 image_view_format = current_srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
494#else
444 image_view_format = current_srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM; 495 image_view_format = current_srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
496#endif
445 image_count = swapchain_images; 497 image_count = swapchain_images;
446 Recreate(); 498 Recreate();
447 } 499 }
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 9627eb129..daa128399 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -303,9 +303,13 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_, MemoryAllocator& m
303 DescriptorPool& descriptor_pool) 303 DescriptorPool& descriptor_pool)
304 : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_}, 304 : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_},
305 staging_pool{staging_pool_}, guest_descriptor_queue{guest_descriptor_queue_}, 305 staging_pool{staging_pool_}, guest_descriptor_queue{guest_descriptor_queue_},
306 uint8_pass(device, scheduler, descriptor_pool, staging_pool, compute_pass_descriptor_queue),
307 quad_index_pass(device, scheduler, descriptor_pool, staging_pool, 306 quad_index_pass(device, scheduler, descriptor_pool, staging_pool,
308 compute_pass_descriptor_queue) { 307 compute_pass_descriptor_queue) {
308 if (device.GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY) {
309 // TODO: FixMe: Uint8Pass compute shader does not build on some Qualcomm drivers.
310 uint8_pass = std::make_unique<Uint8Pass>(device, scheduler, descriptor_pool, staging_pool,
311 compute_pass_descriptor_queue);
312 }
309 quad_array_index_buffer = std::make_shared<QuadArrayIndexBuffer>(device_, memory_allocator_, 313 quad_array_index_buffer = std::make_shared<QuadArrayIndexBuffer>(device_, memory_allocator_,
310 scheduler_, staging_pool_); 314 scheduler_, staging_pool_);
311 quad_strip_index_buffer = std::make_shared<QuadStripIndexBuffer>(device_, memory_allocator_, 315 quad_strip_index_buffer = std::make_shared<QuadStripIndexBuffer>(device_, memory_allocator_,
@@ -442,7 +446,9 @@ void BufferCacheRuntime::BindIndexBuffer(PrimitiveTopology topology, IndexFormat
442 topology == PrimitiveTopology::QuadStrip); 446 topology == PrimitiveTopology::QuadStrip);
443 } else if (vk_index_type == VK_INDEX_TYPE_UINT8_EXT && !device.IsExtIndexTypeUint8Supported()) { 447 } else if (vk_index_type == VK_INDEX_TYPE_UINT8_EXT && !device.IsExtIndexTypeUint8Supported()) {
444 vk_index_type = VK_INDEX_TYPE_UINT16; 448 vk_index_type = VK_INDEX_TYPE_UINT16;
445 std::tie(vk_buffer, vk_offset) = uint8_pass.Assemble(num_indices, buffer, offset); 449 if (uint8_pass) {
450 std::tie(vk_buffer, vk_offset) = uint8_pass->Assemble(num_indices, buffer, offset);
451 }
446 } 452 }
447 if (vk_buffer == VK_NULL_HANDLE) { 453 if (vk_buffer == VK_NULL_HANDLE) {
448 // Vulkan doesn't support null index buffers. Replace it with our own null buffer. 454 // Vulkan doesn't support null index buffers. Replace it with our own null buffer.
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index 5e9602905..794dd0758 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -139,7 +139,7 @@ private:
139 vk::Buffer null_buffer; 139 vk::Buffer null_buffer;
140 MemoryCommit null_buffer_commit; 140 MemoryCommit null_buffer_commit;
141 141
142 Uint8Pass uint8_pass; 142 std::unique_ptr<Uint8Pass> uint8_pass;
143 QuadIndexedPass quad_index_pass; 143 QuadIndexedPass quad_index_pass;
144}; 144};
145 145
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 66dfe5733..9482e91b0 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -114,14 +114,16 @@ Shader::AttributeType CastAttributeType(const FixedPipelineState::VertexAttribut
114 return Shader::AttributeType::Disabled; 114 return Shader::AttributeType::Disabled;
115 case Maxwell::VertexAttribute::Type::SNorm: 115 case Maxwell::VertexAttribute::Type::SNorm:
116 case Maxwell::VertexAttribute::Type::UNorm: 116 case Maxwell::VertexAttribute::Type::UNorm:
117 case Maxwell::VertexAttribute::Type::UScaled:
118 case Maxwell::VertexAttribute::Type::SScaled:
119 case Maxwell::VertexAttribute::Type::Float: 117 case Maxwell::VertexAttribute::Type::Float:
120 return Shader::AttributeType::Float; 118 return Shader::AttributeType::Float;
121 case Maxwell::VertexAttribute::Type::SInt: 119 case Maxwell::VertexAttribute::Type::SInt:
122 return Shader::AttributeType::SignedInt; 120 return Shader::AttributeType::SignedInt;
123 case Maxwell::VertexAttribute::Type::UInt: 121 case Maxwell::VertexAttribute::Type::UInt:
124 return Shader::AttributeType::UnsignedInt; 122 return Shader::AttributeType::UnsignedInt;
123 case Maxwell::VertexAttribute::Type::UScaled:
124 return Shader::AttributeType::UnsignedScaled;
125 case Maxwell::VertexAttribute::Type::SScaled:
126 return Shader::AttributeType::SignedScaled;
125 } 127 }
126 return Shader::AttributeType::Float; 128 return Shader::AttributeType::Float;
127} 129}
@@ -286,14 +288,17 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
286 texture_cache{texture_cache_}, shader_notify{shader_notify_}, 288 texture_cache{texture_cache_}, shader_notify{shader_notify_},
287 use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()}, 289 use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()},
288 use_vulkan_pipeline_cache{Settings::values.use_vulkan_driver_pipeline_cache.GetValue()}, 290 use_vulkan_pipeline_cache{Settings::values.use_vulkan_driver_pipeline_cache.GetValue()},
289 workers(std::max(std::thread::hardware_concurrency(), 2U) - 1, "VkPipelineBuilder"), 291 workers(device.GetDriverID() == VK_DRIVER_ID_QUALCOMM_PROPRIETARY
292 ? 1
293 : (std::max(std::thread::hardware_concurrency(), 2U) - 1),
294 "VkPipelineBuilder"),
290 serialization_thread(1, "VkPipelineSerialization") { 295 serialization_thread(1, "VkPipelineSerialization") {
291 const auto& float_control{device.FloatControlProperties()}; 296 const auto& float_control{device.FloatControlProperties()};
292 const VkDriverId driver_id{device.GetDriverID()}; 297 const VkDriverId driver_id{device.GetDriverID()};
293 profile = Shader::Profile{ 298 profile = Shader::Profile{
294 .supported_spirv = device.SupportedSpirvVersion(), 299 .supported_spirv = device.SupportedSpirvVersion(),
295 .unified_descriptor_binding = true, 300 .unified_descriptor_binding = true,
296 .support_descriptor_aliasing = true, 301 .support_descriptor_aliasing = device.IsDescriptorAliasingSupported(),
297 .support_int8 = device.IsInt8Supported(), 302 .support_int8 = device.IsInt8Supported(),
298 .support_int16 = device.IsShaderInt16Supported(), 303 .support_int16 = device.IsShaderInt16Supported(),
299 .support_int64 = device.IsShaderInt64Supported(), 304 .support_int64 = device.IsShaderInt64Supported(),
@@ -324,6 +329,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
324 .support_derivative_control = true, 329 .support_derivative_control = true,
325 .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), 330 .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),
326 .support_native_ndc = device.IsExtDepthClipControlSupported(), 331 .support_native_ndc = device.IsExtDepthClipControlSupported(),
332 .support_scaled_attributes = !device.MustEmulateScaledFormats(),
327 333
328 .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), 334 .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
329 335
@@ -341,7 +347,8 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
341 .has_broken_signed_operations = false, 347 .has_broken_signed_operations = false,
342 .has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY, 348 .has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY,
343 .ignore_nan_fp_comparisons = false, 349 .ignore_nan_fp_comparisons = false,
344 }; 350 .has_broken_spirv_subgroup_mask_vector_extract_dynamic =
351 driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY};
345 host_info = Shader::HostTranslateInfo{ 352 host_info = Shader::HostTranslateInfo{
346 .support_float16 = device.IsFloat16Supported(), 353 .support_float16 = device.IsFloat16Supported(),
347 .support_int64 = device.IsShaderInt64Supported(), 354 .support_int64 = device.IsShaderInt64Supported(),
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp
index c49583013..10ace0420 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp
@@ -4,10 +4,12 @@
4#include "common/microprofile.h" 4#include "common/microprofile.h"
5#include "common/settings.h" 5#include "common/settings.h"
6#include "common/thread.h" 6#include "common/thread.h"
7#include "core/frontend/emu_window.h"
7#include "video_core/renderer_vulkan/vk_present_manager.h" 8#include "video_core/renderer_vulkan/vk_present_manager.h"
8#include "video_core/renderer_vulkan/vk_scheduler.h" 9#include "video_core/renderer_vulkan/vk_scheduler.h"
9#include "video_core/renderer_vulkan/vk_swapchain.h" 10#include "video_core/renderer_vulkan/vk_swapchain.h"
10#include "video_core/vulkan_common/vulkan_device.h" 11#include "video_core/vulkan_common/vulkan_device.h"
12#include "video_core/vulkan_common/vulkan_surface.h"
11 13
12namespace Vulkan { 14namespace Vulkan {
13 15
@@ -92,14 +94,17 @@ bool CanBlitToSwapchain(const vk::PhysicalDevice& physical_device, VkFormat form
92 94
93} // Anonymous namespace 95} // Anonymous namespace
94 96
95PresentManager::PresentManager(Core::Frontend::EmuWindow& render_window_, const Device& device_, 97PresentManager::PresentManager(const vk::Instance& instance_,
98 Core::Frontend::EmuWindow& render_window_, const Device& device_,
96 MemoryAllocator& memory_allocator_, Scheduler& scheduler_, 99 MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
97 Swapchain& swapchain_) 100 Swapchain& swapchain_, vk::SurfaceKHR& surface_)
98 : render_window{render_window_}, device{device_}, 101 : instance{instance_}, render_window{render_window_}, device{device_},
99 memory_allocator{memory_allocator_}, scheduler{scheduler_}, swapchain{swapchain_}, 102 memory_allocator{memory_allocator_}, scheduler{scheduler_}, swapchain{swapchain_},
100 blit_supported{CanBlitToSwapchain(device.GetPhysical(), swapchain.GetImageViewFormat())}, 103 surface{surface_}, blit_supported{CanBlitToSwapchain(device.GetPhysical(),
104 swapchain.GetImageViewFormat())},
101 use_present_thread{Settings::values.async_presentation.GetValue()}, 105 use_present_thread{Settings::values.async_presentation.GetValue()},
102 image_count{swapchain.GetImageCount()} { 106 image_count{swapchain.GetImageCount()}, last_render_surface{
107 render_window_.GetWindowInfo().render_surface} {
103 108
104 auto& dld = device.GetLogical(); 109 auto& dld = device.GetLogical();
105 cmdpool = dld.CreateCommandPool({ 110 cmdpool = dld.CreateCommandPool({
@@ -286,14 +291,45 @@ void PresentManager::PresentThread(std::stop_token token) {
286 } 291 }
287} 292}
288 293
294void PresentManager::NotifySurfaceChanged() {
295#ifdef ANDROID
296 std::scoped_lock lock{recreate_surface_mutex};
297 recreate_surface_cv.notify_one();
298#endif
299}
300
289void PresentManager::CopyToSwapchain(Frame* frame) { 301void PresentManager::CopyToSwapchain(Frame* frame) {
290 MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain); 302 MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain);
291 303
292 const auto recreate_swapchain = [&] { 304 const auto recreate_swapchain = [&] {
293 swapchain.Create(frame->width, frame->height, frame->is_srgb); 305 swapchain.Create(*surface, frame->width, frame->height, frame->is_srgb);
294 image_count = swapchain.GetImageCount(); 306 image_count = swapchain.GetImageCount();
295 }; 307 };
296 308
309#ifdef ANDROID
310 std::unique_lock lock{recreate_surface_mutex};
311
312 const auto needs_recreation = [&] {
313 if (last_render_surface != render_window.GetWindowInfo().render_surface) {
314 return true;
315 }
316 if (swapchain.NeedsRecreation(frame->is_srgb)) {
317 return true;
318 }
319 return false;
320 };
321
322 recreate_surface_cv.wait_for(lock, std::chrono::milliseconds(400),
323 [&]() { return !needs_recreation(); });
324
325 // If the frontend recreated the surface, recreate the renderer surface and swapchain.
326 if (last_render_surface != render_window.GetWindowInfo().render_surface) {
327 last_render_surface = render_window.GetWindowInfo().render_surface;
328 surface = CreateSurface(instance, render_window.GetWindowInfo());
329 recreate_swapchain();
330 }
331#endif
332
297 // If the size or colorspace of the incoming frames has changed, recreate the swapchain 333 // If the size or colorspace of the incoming frames has changed, recreate the swapchain
298 // to account for that. 334 // to account for that.
299 const bool srgb_changed = swapchain.NeedsRecreation(frame->is_srgb); 335 const bool srgb_changed = swapchain.NeedsRecreation(frame->is_srgb);
@@ -436,7 +472,7 @@ void PresentManager::CopyToSwapchain(Frame* frame) {
436 472
437 // Submit the image copy/blit to the swapchain 473 // Submit the image copy/blit to the swapchain
438 { 474 {
439 std::scoped_lock lock{scheduler.submit_mutex}; 475 std::scoped_lock submit_lock{scheduler.submit_mutex};
440 switch (const VkResult result = 476 switch (const VkResult result =
441 device.GetGraphicsQueue().Submit(submit_info, *frame->present_done)) { 477 device.GetGraphicsQueue().Submit(submit_info, *frame->present_done)) {
442 case VK_SUCCESS: 478 case VK_SUCCESS:
@@ -454,4 +490,4 @@ void PresentManager::CopyToSwapchain(Frame* frame) {
454 swapchain.Present(render_semaphore); 490 swapchain.Present(render_semaphore);
455} 491}
456 492
457} // namespace Vulkan 493} // namespace Vulkan \ No newline at end of file
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h
index 420a775e2..4ac2e2395 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.h
+++ b/src/video_core/renderer_vulkan/vk_present_manager.h
@@ -37,8 +37,9 @@ struct Frame {
37 37
38class PresentManager { 38class PresentManager {
39public: 39public:
40 PresentManager(Core::Frontend::EmuWindow& render_window, const Device& device, 40 PresentManager(const vk::Instance& instance, Core::Frontend::EmuWindow& render_window,
41 MemoryAllocator& memory_allocator, Scheduler& scheduler, Swapchain& swapchain); 41 const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler,
42 Swapchain& swapchain, vk::SurfaceKHR& surface);
42 ~PresentManager(); 43 ~PresentManager();
43 44
44 /// Returns the last used presentation frame 45 /// Returns the last used presentation frame
@@ -54,30 +55,38 @@ public:
54 /// Waits for the present thread to finish presenting all queued frames. 55 /// Waits for the present thread to finish presenting all queued frames.
55 void WaitPresent(); 56 void WaitPresent();
56 57
58 /// This is called to notify the rendering backend of a surface change
59 void NotifySurfaceChanged();
60
57private: 61private:
58 void PresentThread(std::stop_token token); 62 void PresentThread(std::stop_token token);
59 63
60 void CopyToSwapchain(Frame* frame); 64 void CopyToSwapchain(Frame* frame);
61 65
62private: 66private:
67 const vk::Instance& instance;
63 Core::Frontend::EmuWindow& render_window; 68 Core::Frontend::EmuWindow& render_window;
64 const Device& device; 69 const Device& device;
65 MemoryAllocator& memory_allocator; 70 MemoryAllocator& memory_allocator;
66 Scheduler& scheduler; 71 Scheduler& scheduler;
67 Swapchain& swapchain; 72 Swapchain& swapchain;
73 vk::SurfaceKHR& surface;
68 vk::CommandPool cmdpool; 74 vk::CommandPool cmdpool;
69 std::vector<Frame> frames; 75 std::vector<Frame> frames;
70 std::queue<Frame*> present_queue; 76 std::queue<Frame*> present_queue;
71 std::queue<Frame*> free_queue; 77 std::queue<Frame*> free_queue;
72 std::condition_variable_any frame_cv; 78 std::condition_variable_any frame_cv;
73 std::condition_variable free_cv; 79 std::condition_variable free_cv;
80 std::condition_variable recreate_surface_cv;
74 std::mutex swapchain_mutex; 81 std::mutex swapchain_mutex;
82 std::mutex recreate_surface_mutex;
75 std::mutex queue_mutex; 83 std::mutex queue_mutex;
76 std::mutex free_mutex; 84 std::mutex free_mutex;
77 std::jthread present_thread; 85 std::jthread present_thread;
78 bool blit_supported; 86 bool blit_supported;
79 bool use_present_thread; 87 bool use_present_thread;
80 std::size_t image_count; 88 std::size_t image_count{};
89 void* last_render_surface{};
81}; 90};
82 91
83} // namespace Vulkan 92} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 8d3a9736b..84e3a30cc 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -188,7 +188,14 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
188 FlushWork(); 188 FlushWork();
189 gpu_memory->FlushCaching(); 189 gpu_memory->FlushCaching();
190 190
191#if ANDROID
192 if (Settings::IsGPULevelHigh()) {
193 // This is problematic on Android, disable on GPU Normal.
194 query_cache.UpdateCounters();
195 }
196#else
191 query_cache.UpdateCounters(); 197 query_cache.UpdateCounters();
198#endif
192 199
193 GraphicsPipeline* const pipeline{pipeline_cache.CurrentGraphicsPipeline()}; 200 GraphicsPipeline* const pipeline{pipeline_cache.CurrentGraphicsPipeline()};
194 if (!pipeline) { 201 if (!pipeline) {
@@ -272,7 +279,14 @@ void RasterizerVulkan::DrawTexture() {
272 SCOPE_EXIT({ gpu.TickWork(); }); 279 SCOPE_EXIT({ gpu.TickWork(); });
273 FlushWork(); 280 FlushWork();
274 281
282#if ANDROID
283 if (Settings::IsGPULevelHigh()) {
284 // This is problematic on Android, disable on GPU Normal.
285 query_cache.UpdateCounters();
286 }
287#else
275 query_cache.UpdateCounters(); 288 query_cache.UpdateCounters();
289#endif
276 290
277 texture_cache.SynchronizeGraphicsDescriptors(); 291 texture_cache.SynchronizeGraphicsDescriptors();
278 texture_cache.UpdateRenderTargets(false); 292 texture_cache.UpdateRenderTargets(false);
@@ -743,7 +757,11 @@ void RasterizerVulkan::LoadDiskResources(u64 title_id, std::stop_token stop_load
743} 757}
744 758
745void RasterizerVulkan::FlushWork() { 759void RasterizerVulkan::FlushWork() {
760#ifdef ANDROID
761 static constexpr u32 DRAWS_TO_DISPATCH = 1024;
762#else
746 static constexpr u32 DRAWS_TO_DISPATCH = 4096; 763 static constexpr u32 DRAWS_TO_DISPATCH = 4096;
764#endif // ANDROID
747 765
748 // Only check multiples of 8 draws 766 // Only check multiples of 8 draws
749 static_assert(DRAWS_TO_DISPATCH % 8 == 0); 767 static_assert(DRAWS_TO_DISPATCH % 8 == 0);
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index 80455ec08..17ef61147 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -239,7 +239,14 @@ u64 Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_se
239void Scheduler::AllocateNewContext() { 239void Scheduler::AllocateNewContext() {
240 // Enable counters once again. These are disabled when a command buffer is finished. 240 // Enable counters once again. These are disabled when a command buffer is finished.
241 if (query_cache) { 241 if (query_cache) {
242#if ANDROID
243 if (Settings::IsGPULevelHigh()) {
244 // This is problematic on Android, disable on GPU Normal.
245 query_cache->UpdateCounters();
246 }
247#else
242 query_cache->UpdateCounters(); 248 query_cache->UpdateCounters();
249#endif
243 } 250 }
244} 251}
245 252
@@ -250,7 +257,14 @@ void Scheduler::InvalidateState() {
250} 257}
251 258
252void Scheduler::EndPendingOperations() { 259void Scheduler::EndPendingOperations() {
260#if ANDROID
261 if (Settings::IsGPULevelHigh()) {
262 // This is problematic on Android, disable on GPU Normal.
263 query_cache->DisableStreams();
264 }
265#else
253 query_cache->DisableStreams(); 266 query_cache->DisableStreams();
267#endif
254 EndRenderPass(); 268 EndRenderPass();
255} 269}
256 270
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index 8c0dec590..afcf34fba 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -107,16 +107,17 @@ VkCompositeAlphaFlagBitsKHR ChooseAlphaFlags(const VkSurfaceCapabilitiesKHR& cap
107Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, 107Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_,
108 u32 width_, u32 height_, bool srgb) 108 u32 width_, u32 height_, bool srgb)
109 : surface{surface_}, device{device_}, scheduler{scheduler_} { 109 : surface{surface_}, device{device_}, scheduler{scheduler_} {
110 Create(width_, height_, srgb); 110 Create(surface_, width_, height_, srgb);
111} 111}
112 112
113Swapchain::~Swapchain() = default; 113Swapchain::~Swapchain() = default;
114 114
115void Swapchain::Create(u32 width_, u32 height_, bool srgb) { 115void Swapchain::Create(VkSurfaceKHR surface_, u32 width_, u32 height_, bool srgb) {
116 is_outdated = false; 116 is_outdated = false;
117 is_suboptimal = false; 117 is_suboptimal = false;
118 width = width_; 118 width = width_;
119 height = height_; 119 height = height_;
120 surface = surface_;
120 121
121 const auto physical_device = device.GetPhysical(); 122 const auto physical_device = device.GetPhysical();
122 const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface)}; 123 const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface)};
@@ -266,7 +267,12 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo
266 267
267 images = swapchain.GetImages(); 268 images = swapchain.GetImages();
268 image_count = static_cast<u32>(images.size()); 269 image_count = static_cast<u32>(images.size());
270#ifdef ANDROID
271 // Android is already ordered the same as Switch.
272 image_view_format = srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
273#else
269 image_view_format = srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM; 274 image_view_format = srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
275#endif
270} 276}
271 277
272void Swapchain::CreateSemaphores() { 278void Swapchain::CreateSemaphores() {
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h
index bf1ea7254..b8a1465a6 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.h
+++ b/src/video_core/renderer_vulkan/vk_swapchain.h
@@ -24,7 +24,7 @@ public:
24 ~Swapchain(); 24 ~Swapchain();
25 25
26 /// Creates (or recreates) the swapchain with a given size. 26 /// Creates (or recreates) the swapchain with a given size.
27 void Create(u32 width, u32 height, bool srgb); 27 void Create(VkSurfaceKHR surface, u32 width, u32 height, bool srgb);
28 28
29 /// Acquires the next image in the swapchain, waits as needed. 29 /// Acquires the next image in the swapchain, waits as needed.
30 bool AcquireNextImage(); 30 bool AcquireNextImage();
@@ -118,7 +118,7 @@ private:
118 118
119 bool NeedsPresentModeUpdate() const; 119 bool NeedsPresentModeUpdate() const;
120 120
121 const VkSurfaceKHR surface; 121 VkSurfaceKHR surface;
122 const Device& device; 122 const Device& device;
123 Scheduler& scheduler; 123 Scheduler& scheduler;
124 124
diff --git a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp
index db04943eb..a802d3c49 100644
--- a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp
+++ b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp
@@ -1,6 +1,10 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#if defined(ANDROID) && defined(ARCHITECTURE_arm64)
5#include <adrenotools/driver.h>
6#endif
7
4#include "common/literals.h" 8#include "common/literals.h"
5#include "video_core/host_shaders/vulkan_turbo_mode_comp_spv.h" 9#include "video_core/host_shaders/vulkan_turbo_mode_comp_spv.h"
6#include "video_core/renderer_vulkan/renderer_vulkan.h" 10#include "video_core/renderer_vulkan/renderer_vulkan.h"
@@ -13,7 +17,10 @@ namespace Vulkan {
13using namespace Common::Literals; 17using namespace Common::Literals;
14 18
15TurboMode::TurboMode(const vk::Instance& instance, const vk::InstanceDispatch& dld) 19TurboMode::TurboMode(const vk::Instance& instance, const vk::InstanceDispatch& dld)
16 : m_device{CreateDevice(instance, dld, VK_NULL_HANDLE)}, m_allocator{m_device, false} { 20#ifndef ANDROID
21 : m_device{CreateDevice(instance, dld, VK_NULL_HANDLE)}, m_allocator{m_device, false}
22#endif
23{
17 { 24 {
18 std::scoped_lock lk{m_submission_lock}; 25 std::scoped_lock lk{m_submission_lock};
19 m_submission_time = std::chrono::steady_clock::now(); 26 m_submission_time = std::chrono::steady_clock::now();
@@ -30,6 +37,7 @@ void TurboMode::QueueSubmitted() {
30} 37}
31 38
32void TurboMode::Run(std::stop_token stop_token) { 39void TurboMode::Run(std::stop_token stop_token) {
40#ifndef ANDROID
33 auto& dld = m_device.GetLogical(); 41 auto& dld = m_device.GetLogical();
34 42
35 // Allocate buffer. 2MiB should be sufficient. 43 // Allocate buffer. 2MiB should be sufficient.
@@ -142,8 +150,14 @@ void TurboMode::Run(std::stop_token stop_token) {
142 // Create a single command buffer. 150 // Create a single command buffer.
143 auto cmdbufs = command_pool.Allocate(1, VK_COMMAND_BUFFER_LEVEL_PRIMARY); 151 auto cmdbufs = command_pool.Allocate(1, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
144 auto cmdbuf = vk::CommandBuffer{cmdbufs[0], m_device.GetDispatchLoader()}; 152 auto cmdbuf = vk::CommandBuffer{cmdbufs[0], m_device.GetDispatchLoader()};
153#endif
145 154
146 while (!stop_token.stop_requested()) { 155 while (!stop_token.stop_requested()) {
156#ifdef ANDROID
157#ifdef ARCHITECTURE_arm64
158 adrenotools_set_turbo(true);
159#endif
160#else
147 // Reset the fence. 161 // Reset the fence.
148 fence.Reset(); 162 fence.Reset();
149 163
@@ -209,7 +223,7 @@ void TurboMode::Run(std::stop_token stop_token) {
209 223
210 // Wait for completion. 224 // Wait for completion.
211 fence.Wait(); 225 fence.Wait();
212 226#endif
213 // Wait for the next graphics queue submission if necessary. 227 // Wait for the next graphics queue submission if necessary.
214 std::unique_lock lk{m_submission_lock}; 228 std::unique_lock lk{m_submission_lock};
215 Common::CondvarWait(m_submission_cv, lk, stop_token, [this] { 229 Common::CondvarWait(m_submission_cv, lk, stop_token, [this] {
@@ -217,6 +231,9 @@ void TurboMode::Run(std::stop_token stop_token) {
217 std::chrono::milliseconds{100}; 231 std::chrono::milliseconds{100};
218 }); 232 });
219 } 233 }
234#if defined(ANDROID) && defined(ARCHITECTURE_arm64)
235 adrenotools_set_turbo(false);
236#endif
220} 237}
221 238
222} // namespace Vulkan 239} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_turbo_mode.h b/src/video_core/renderer_vulkan/vk_turbo_mode.h
index 99b5ac50b..9341c9867 100644
--- a/src/video_core/renderer_vulkan/vk_turbo_mode.h
+++ b/src/video_core/renderer_vulkan/vk_turbo_mode.h
@@ -23,8 +23,10 @@ public:
23private: 23private:
24 void Run(std::stop_token stop_token); 24 void Run(std::stop_token stop_token);
25 25
26#ifndef ANDROID
26 Device m_device; 27 Device m_device;
27 MemoryAllocator m_allocator; 28 MemoryAllocator m_allocator;
29#endif
28 std::mutex m_submission_lock; 30 std::mutex m_submission_lock;
29 std::condition_variable_any m_submission_cv; 31 std::condition_variable_any m_submission_cv;
30 std::chrono::time_point<std::chrono::steady_clock> m_submission_time{}; 32 std::chrono::time_point<std::chrono::steady_clock> m_submission_time{};
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h
index 310fb551a..e77b576ec 100644
--- a/src/video_core/renderer_vulkan/vk_update_descriptor.h
+++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h
@@ -31,7 +31,7 @@ struct DescriptorUpdateEntry {
31class UpdateDescriptorQueue final { 31class UpdateDescriptorQueue final {
32 // This should be plenty for the vast majority of cases. Most desktop platforms only 32 // This should be plenty for the vast majority of cases. Most desktop platforms only
33 // provide up to 3 swapchain images. 33 // provide up to 3 swapchain images.
34 static constexpr size_t FRAMES_IN_FLIGHT = 5; 34 static constexpr size_t FRAMES_IN_FLIGHT = 7;
35 static constexpr size_t FRAME_PAYLOAD_SIZE = 0x20000; 35 static constexpr size_t FRAME_PAYLOAD_SIZE = 0x20000;
36 static constexpr size_t PAYLOAD_SIZE = FRAME_PAYLOAD_SIZE * FRAMES_IN_FLIGHT; 36 static constexpr size_t PAYLOAD_SIZE = FRAME_PAYLOAD_SIZE * FRAMES_IN_FLIGHT;
37 37
diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.cpp b/src/video_core/vulkan_common/vulkan_debug_callback.cpp
index 10a001b8f..9de484c29 100644
--- a/src/video_core/vulkan_common/vulkan_debug_callback.cpp
+++ b/src/video_core/vulkan_common/vulkan_debug_callback.cpp
@@ -13,11 +13,39 @@ VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
13 [[maybe_unused]] void* user_data) { 13 [[maybe_unused]] void* user_data) {
14 // Skip logging known false-positive validation errors 14 // Skip logging known false-positive validation errors
15 switch (static_cast<u32>(data->messageIdNumber)) { 15 switch (static_cast<u32>(data->messageIdNumber)) {
16#ifdef ANDROID
17 case 0xbf9cf353u: // VUID-vkCmdBindVertexBuffers2-pBuffers-04111
18 // The below are due to incorrect reporting of extendedDynamicState
19 case 0x1093bebbu: // VUID-vkCmdSetCullMode-None-03384
20 case 0x9215850fu: // VUID-vkCmdSetDepthTestEnable-None-03352
21 case 0x86bf18dcu: // VUID-vkCmdSetDepthWriteEnable-None-03354
22 case 0x0792ad08u: // VUID-vkCmdSetStencilOp-None-03351
23 case 0x93e1ba4eu: // VUID-vkCmdSetFrontFace-None-03383
24 case 0xac9c13c5u: // VUID-vkCmdSetStencilTestEnable-None-03350
25 case 0xc9a2001bu: // VUID-vkCmdSetDepthBoundsTestEnable-None-03349
26 case 0x8b7159a7u: // VUID-vkCmdSetDepthCompareOp-None-03353
27 // The below are due to incorrect reporting of extendedDynamicState2
28 case 0xb13c8036u: // VUID-vkCmdSetDepthBiasEnable-None-04872
29 case 0xdff2e5c1u: // VUID-vkCmdSetRasterizerDiscardEnable-None-04871
30 case 0x0cc85f41u: // VUID-vkCmdSetPrimitiveRestartEnable-None-04866
31 case 0x01257b492: // VUID-vkCmdSetLogicOpEXT-None-0486
32 // The below are due to incorrect reporting of vertexInputDynamicState
33 case 0x398e0dabu: // VUID-vkCmdSetVertexInputEXT-None-04790
34 // The below are due to incorrect reporting of extendedDynamicState3
35 case 0x970c11a5u: // VUID-vkCmdSetColorWriteMaskEXT-extendedDynamicState3ColorWriteMask-07364
36 case 0x6b453f78u: // VUID-vkCmdSetColorBlendEnableEXT-extendedDynamicState3ColorBlendEnable-07355
37 case 0xf66469d0u: // VUID-vkCmdSetColorBlendEquationEXT-extendedDynamicState3ColorBlendEquation-07356
38 case 0x1d43405eu: // VUID-vkCmdSetLogicOpEnableEXT-extendedDynamicState3LogicOpEnable-07365
39 case 0x638462e8u: // VUID-vkCmdSetDepthClampEnableEXT-extendedDynamicState3DepthClampEnable-07448
40 // Misc
41 case 0xe0a2da61u: // VUID-vkCmdDrawIndexed-format-07753
42#else
16 case 0x682a878au: // VUID-vkCmdBindVertexBuffers2EXT-pBuffers-parameter 43 case 0x682a878au: // VUID-vkCmdBindVertexBuffers2EXT-pBuffers-parameter
17 case 0x99fb7dfdu: // UNASSIGNED-RequiredParameter (vkCmdBindVertexBuffers2EXT pBuffers[0]) 44 case 0x99fb7dfdu: // UNASSIGNED-RequiredParameter (vkCmdBindVertexBuffers2EXT pBuffers[0])
18 case 0xe8616bf2u: // Bound VkDescriptorSet 0x0[] was destroyed. Likely push_descriptor related 45 case 0xe8616bf2u: // Bound VkDescriptorSet 0x0[] was destroyed. Likely push_descriptor related
19 case 0x1608dec0u: // Image layout in vkUpdateDescriptorSet doesn't match descriptor use 46 case 0x1608dec0u: // Image layout in vkUpdateDescriptorSet doesn't match descriptor use
20 case 0x55362756u: // Descriptor binding and framebuffer attachment overlap 47 case 0x55362756u: // Descriptor binding and framebuffer attachment overlap
48#endif
21 return VK_FALSE; 49 return VK_FALSE;
22 default: 50 default:
23 break; 51 break;
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index aea677cb3..0158b6b0d 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -18,6 +18,10 @@
18#include "video_core/vulkan_common/vulkan_device.h" 18#include "video_core/vulkan_common/vulkan_device.h"
19#include "video_core/vulkan_common/vulkan_wrapper.h" 19#include "video_core/vulkan_common/vulkan_wrapper.h"
20 20
21#if defined(ANDROID) && defined(ARCHITECTURE_arm64)
22#include <adrenotools/bcenabler.h>
23#endif
24
21namespace Vulkan { 25namespace Vulkan {
22using namespace Common::Literals; 26using namespace Common::Literals;
23namespace { 27namespace {
@@ -262,6 +266,32 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::Physica
262 return format_properties; 266 return format_properties;
263} 267}
264 268
269#if defined(ANDROID) && defined(ARCHITECTURE_arm64)
270void OverrideBcnFormats(std::unordered_map<VkFormat, VkFormatProperties>& format_properties) {
271 // These properties are extracted from Adreno driver 512.687.0
272 constexpr VkFormatFeatureFlags tiling_features{
273 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT |
274 VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
275 VK_FORMAT_FEATURE_TRANSFER_DST_BIT};
276
277 constexpr VkFormatFeatureFlags buffer_features{VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT};
278
279 static constexpr std::array bcn_formats{
280 VK_FORMAT_BC1_RGBA_SRGB_BLOCK, VK_FORMAT_BC1_RGBA_UNORM_BLOCK, VK_FORMAT_BC2_SRGB_BLOCK,
281 VK_FORMAT_BC2_UNORM_BLOCK, VK_FORMAT_BC3_SRGB_BLOCK, VK_FORMAT_BC3_UNORM_BLOCK,
282 VK_FORMAT_BC4_SNORM_BLOCK, VK_FORMAT_BC4_UNORM_BLOCK, VK_FORMAT_BC5_SNORM_BLOCK,
283 VK_FORMAT_BC5_UNORM_BLOCK, VK_FORMAT_BC6H_SFLOAT_BLOCK, VK_FORMAT_BC6H_UFLOAT_BLOCK,
284 VK_FORMAT_BC7_SRGB_BLOCK, VK_FORMAT_BC7_UNORM_BLOCK,
285 };
286
287 for (const auto format : bcn_formats) {
288 format_properties[format].linearTilingFeatures = tiling_features;
289 format_properties[format].optimalTilingFeatures = tiling_features;
290 format_properties[format].bufferFeatures = buffer_features;
291 }
292}
293#endif
294
265NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical, 295NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
266 const std::set<std::string, std::less<>>& exts) { 296 const std::set<std::string, std::less<>>& exts) {
267 if (exts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME)) { 297 if (exts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME)) {
@@ -302,6 +332,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
302 const bool is_suitable = GetSuitability(surface != nullptr); 332 const bool is_suitable = GetSuitability(surface != nullptr);
303 333
304 const VkDriverId driver_id = properties.driver.driverID; 334 const VkDriverId driver_id = properties.driver.driverID;
335 const auto device_id = properties.properties.deviceID;
305 const bool is_radv = driver_id == VK_DRIVER_ID_MESA_RADV; 336 const bool is_radv = driver_id == VK_DRIVER_ID_MESA_RADV;
306 const bool is_amd_driver = 337 const bool is_amd_driver =
307 driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE; 338 driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE;
@@ -310,9 +341,12 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
310 const bool is_intel_anv = driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA; 341 const bool is_intel_anv = driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA;
311 const bool is_nvidia = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY; 342 const bool is_nvidia = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY;
312 const bool is_mvk = driver_id == VK_DRIVER_ID_MOLTENVK; 343 const bool is_mvk = driver_id == VK_DRIVER_ID_MOLTENVK;
344 const bool is_qualcomm = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
345 const bool is_turnip = driver_id == VK_DRIVER_ID_MESA_TURNIP;
346 const bool is_s8gen2 = device_id == 0x43050a01;
313 347
314 if (is_mvk && !is_suitable) { 348 if ((is_mvk || is_qualcomm || is_turnip) && !is_suitable) {
315 LOG_WARNING(Render_Vulkan, "Unsuitable driver is MoltenVK, continuing anyway"); 349 LOG_WARNING(Render_Vulkan, "Unsuitable driver, continuing anyway");
316 } else if (!is_suitable) { 350 } else if (!is_suitable) {
317 throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER); 351 throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER);
318 } 352 }
@@ -355,6 +389,59 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
355 CollectPhysicalMemoryInfo(); 389 CollectPhysicalMemoryInfo();
356 CollectToolingInfo(); 390 CollectToolingInfo();
357 391
392#ifdef ANDROID
393 if (is_qualcomm || is_turnip) {
394 LOG_WARNING(Render_Vulkan,
395 "Qualcomm and Turnip drivers have broken VK_EXT_custom_border_color");
396 extensions.custom_border_color = false;
397 loaded_extensions.erase(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
398 }
399
400 if (is_qualcomm) {
401 must_emulate_scaled_formats = true;
402
403 LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken VK_EXT_extended_dynamic_state");
404 extensions.extended_dynamic_state = false;
405 loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
406
407 LOG_WARNING(Render_Vulkan,
408 "Qualcomm drivers have a slow VK_KHR_push_descriptor implementation");
409 extensions.push_descriptor = false;
410 loaded_extensions.erase(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
411
412#ifdef ARCHITECTURE_arm64
413 // Patch the driver to enable BCn textures.
414 const auto major = (properties.properties.driverVersion >> 24) << 2;
415 const auto minor = (properties.properties.driverVersion >> 12) & 0xFFFU;
416 const auto vendor = properties.properties.vendorID;
417 const auto patch_status = adrenotools_get_bcn_type(major, minor, vendor);
418
419 if (patch_status == ADRENOTOOLS_BCN_PATCH) {
420 LOG_INFO(Render_Vulkan, "Patching Adreno driver to support BCn texture formats");
421 if (adrenotools_patch_bcn(
422 reinterpret_cast<void*>(dld.vkGetPhysicalDeviceFormatProperties))) {
423 OverrideBcnFormats(format_properties);
424 } else {
425 LOG_ERROR(Render_Vulkan, "Patch failed! Driver code may now crash");
426 }
427 } else if (patch_status == ADRENOTOOLS_BCN_BLOB) {
428 LOG_INFO(Render_Vulkan, "Adreno driver supports BCn textures without patches");
429 } else {
430 LOG_WARNING(Render_Vulkan, "Adreno driver can't be patched to enable BCn textures");
431 }
432#endif // ARCHITECTURE_arm64
433 }
434
435 const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY;
436 if (is_arm) {
437 must_emulate_scaled_formats = true;
438
439 LOG_WARNING(Render_Vulkan, "ARM drivers have broken VK_EXT_extended_dynamic_state");
440 extensions.extended_dynamic_state = false;
441 loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
442 }
443#endif // ANDROID
444
358 if (is_nvidia) { 445 if (is_nvidia) {
359 const u32 nv_major_version = (properties.properties.driverVersion >> 22) & 0x3ff; 446 const u32 nv_major_version = (properties.properties.driverVersion >> 22) & 0x3ff;
360 const auto arch = GetNvidiaArchitecture(physical, supported_extensions); 447 const auto arch = GetNvidiaArchitecture(physical, supported_extensions);
@@ -388,7 +475,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
388 loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); 475 loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
389 } 476 }
390 } 477 }
391 if (extensions.extended_dynamic_state2 && is_radv) { 478 if (extensions.extended_dynamic_state2 && (is_radv || is_qualcomm)) {
392 const u32 version = (properties.properties.driverVersion << 3) >> 3; 479 const u32 version = (properties.properties.driverVersion << 3) >> 3;
393 if (version < VK_MAKE_API_VERSION(0, 22, 3, 1)) { 480 if (version < VK_MAKE_API_VERSION(0, 22, 3, 1)) {
394 LOG_WARNING( 481 LOG_WARNING(
@@ -415,7 +502,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
415 dynamic_state3_enables = false; 502 dynamic_state3_enables = false;
416 } 503 }
417 } 504 }
418 if (extensions.vertex_input_dynamic_state && is_radv) { 505 if (extensions.vertex_input_dynamic_state && (is_radv || is_qualcomm)) {
506 // Qualcomm S8gen2 drivers do not properly support vertex_input_dynamic_state.
419 // TODO(ameerj): Blacklist only offending driver versions 507 // TODO(ameerj): Blacklist only offending driver versions
420 // TODO(ameerj): Confirm if RDNA1 is affected 508 // TODO(ameerj): Confirm if RDNA1 is affected
421 const bool is_rdna2 = 509 const bool is_rdna2 =
@@ -467,8 +555,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
467 LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits"); 555 LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits");
468 cant_blit_msaa = true; 556 cant_blit_msaa = true;
469 } 557 }
470 if (is_intel_anv) { 558 if (is_intel_anv || (is_qualcomm && !is_s8gen2)) {
471 LOG_WARNING(Render_Vulkan, "ANV driver does not support native BGR format"); 559 LOG_WARNING(Render_Vulkan, "Driver does not support native BGR format");
472 must_emulate_bgr565 = true; 560 must_emulate_bgr565 = true;
473 } 561 }
474 if (extensions.push_descriptor && is_intel_anv) { 562 if (extensions.push_descriptor && is_intel_anv) {
@@ -633,7 +721,8 @@ bool Device::ShouldBoostClocks() const {
633 driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE || 721 driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE ||
634 driver_id == VK_DRIVER_ID_MESA_RADV || driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY || 722 driver_id == VK_DRIVER_ID_MESA_RADV || driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY ||
635 driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS || 723 driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS ||
636 driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA; 724 driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA ||
725 driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP;
637 726
638 const bool is_steam_deck = vendor_id == 0x1002 && device_id == 0x163F; 727 const bool is_steam_deck = vendor_id == 0x1002 && device_id == 0x163F;
639 728
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index 5f1c63ff9..b692b4be4 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -295,6 +295,11 @@ public:
295 return features.features.textureCompressionASTC_LDR; 295 return features.features.textureCompressionASTC_LDR;
296 } 296 }
297 297
298 /// Returns true if descriptor aliasing is natively supported.
299 bool IsDescriptorAliasingSupported() const {
300 return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
301 }
302
298 /// Returns true if the device supports float16 natively. 303 /// Returns true if the device supports float16 natively.
299 bool IsFloat16Supported() const { 304 bool IsFloat16Supported() const {
300 return features.shader_float16_int8.shaderFloat16; 305 return features.shader_float16_int8.shaderFloat16;
@@ -495,6 +500,10 @@ public:
495 } 500 }
496 501
497 bool HasTimelineSemaphore() const { 502 bool HasTimelineSemaphore() const {
503 if (GetDriverID() == VK_DRIVER_ID_QUALCOMM_PROPRIETARY) {
504 // Timeline semaphores do not work properly on all Qualcomm drivers.
505 return false;
506 }
498 return features.timeline_semaphore.timelineSemaphore; 507 return features.timeline_semaphore.timelineSemaphore;
499 } 508 }
500 509
@@ -551,6 +560,10 @@ public:
551 return cant_blit_msaa; 560 return cant_blit_msaa;
552 } 561 }
553 562
563 bool MustEmulateScaledFormats() const {
564 return must_emulate_scaled_formats;
565 }
566
554 bool MustEmulateBGR565() const { 567 bool MustEmulateBGR565() const {
555 return must_emulate_bgr565; 568 return must_emulate_bgr565;
556 } 569 }
@@ -666,6 +679,7 @@ private:
666 bool has_nsight_graphics{}; ///< Has Nsight Graphics attached 679 bool has_nsight_graphics{}; ///< Has Nsight Graphics attached
667 bool supports_d24_depth{}; ///< Supports D24 depth buffers. 680 bool supports_d24_depth{}; ///< Supports D24 depth buffers.
668 bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting. 681 bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting.
682 bool must_emulate_scaled_formats{}; ///< Requires scaled vertex format emulation
669 bool must_emulate_bgr565{}; ///< Emulates BGR565 by swizzling RGB565 format. 683 bool must_emulate_bgr565{}; ///< Emulates BGR565 by swizzling RGB565 format.
670 bool dynamic_state3_blending{}; ///< Has all blending features of dynamic_state3. 684 bool dynamic_state3_blending{}; ///< Has all blending features of dynamic_state3.
671 bool dynamic_state3_enables{}; ///< Has all enables features of dynamic_state3. 685 bool dynamic_state3_enables{}; ///< Has all enables features of dynamic_state3.
diff --git a/src/video_core/vulkan_common/vulkan_library.cpp b/src/video_core/vulkan_common/vulkan_library.cpp
index 4eb3913ee..47f6f2a03 100644
--- a/src/video_core/vulkan_common/vulkan_library.cpp
+++ b/src/video_core/vulkan_common/vulkan_library.cpp
@@ -10,29 +10,35 @@
10 10
11namespace Vulkan { 11namespace Vulkan {
12 12
13Common::DynamicLibrary OpenLibrary() { 13std::shared_ptr<Common::DynamicLibrary> OpenLibrary(
14 [[maybe_unused]] Core::Frontend::GraphicsContext* context) {
14 LOG_DEBUG(Render_Vulkan, "Looking for a Vulkan library"); 15 LOG_DEBUG(Render_Vulkan, "Looking for a Vulkan library");
15 Common::DynamicLibrary library; 16#if defined(ANDROID) && defined(ARCHITECTURE_arm64)
17 // Android manages its Vulkan driver from the frontend.
18 return context->GetDriverLibrary();
19#else
20 auto library = std::make_shared<Common::DynamicLibrary>();
16#ifdef __APPLE__ 21#ifdef __APPLE__
17 // Check if a path to a specific Vulkan library has been specified. 22 // Check if a path to a specific Vulkan library has been specified.
18 char* const libvulkan_env = std::getenv("LIBVULKAN_PATH"); 23 char* const libvulkan_env = std::getenv("LIBVULKAN_PATH");
19 if (!libvulkan_env || !library.Open(libvulkan_env)) { 24 if (!libvulkan_env || !library->Open(libvulkan_env)) {
20 // Use the libvulkan.dylib from the application bundle. 25 // Use the libvulkan.dylib from the application bundle.
21 const auto filename = 26 const auto filename =
22 Common::FS::GetBundleDirectory() / "Contents/Frameworks/libvulkan.dylib"; 27 Common::FS::GetBundleDirectory() / "Contents/Frameworks/libvulkan.dylib";
23 void(library.Open(Common::FS::PathToUTF8String(filename).c_str())); 28 void(library->Open(Common::FS::PathToUTF8String(filename).c_str()));
24 } 29 }
25#else 30#else
26 std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1); 31 std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);
27 LOG_DEBUG(Render_Vulkan, "Trying Vulkan library: {}", filename); 32 LOG_DEBUG(Render_Vulkan, "Trying Vulkan library: {}", filename);
28 if (!library.Open(filename.c_str())) { 33 if (!library->Open(filename.c_str())) {
29 // Android devices may not have libvulkan.so.1, only libvulkan.so. 34 // Android devices may not have libvulkan.so.1, only libvulkan.so.
30 filename = Common::DynamicLibrary::GetVersionedFilename("vulkan"); 35 filename = Common::DynamicLibrary::GetVersionedFilename("vulkan");
31 LOG_DEBUG(Render_Vulkan, "Trying Vulkan library (second attempt): {}", filename); 36 LOG_DEBUG(Render_Vulkan, "Trying Vulkan library (second attempt): {}", filename);
32 void(library.Open(filename.c_str())); 37 void(library->Open(filename.c_str()));
33 } 38 }
34#endif 39#endif
35 return library; 40 return library;
41#endif
36} 42}
37 43
38} // namespace Vulkan 44} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_library.h b/src/video_core/vulkan_common/vulkan_library.h
index 364ca979b..e1734525e 100644
--- a/src/video_core/vulkan_common/vulkan_library.h
+++ b/src/video_core/vulkan_common/vulkan_library.h
@@ -3,10 +3,14 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <memory>
7
6#include "common/dynamic_library.h" 8#include "common/dynamic_library.h"
9#include "core/frontend/graphics_context.h"
7 10
8namespace Vulkan { 11namespace Vulkan {
9 12
10Common::DynamicLibrary OpenLibrary(); 13std::shared_ptr<Common::DynamicLibrary> OpenLibrary(
14 [[maybe_unused]] Core::Frontend::GraphicsContext* context = nullptr);
11 15
12} // namespace Vulkan 16} // namespace Vulkan