summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--CMakeLists.txt2
-rw-r--r--externals/nx_tzdb/CMakeLists.txt96
-rw-r--r--externals/nx_tzdb/NxTzdbCreateHeader.cmake8
-rw-r--r--externals/nx_tzdb/include/nx_tzdb.h2
m---------externals/nx_tzdb/tzdb_to_nx0
m---------externals/vcpkg0
-rw-r--r--src/core/file_sys/system_archive/time_zone_binary.cpp2
-rw-r--r--src/core/hle/kernel/k_thread.cpp15
-rw-r--r--src/core/hle/kernel/k_thread.h4
-rw-r--r--src/core/hle/service/time/time_zone_manager.cpp5
-rw-r--r--src/core/hle/service/time/time_zone_service.cpp10
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h9
-rw-r--r--src/video_core/engines/draw_manager.cpp10
-rw-r--r--src/video_core/memory_manager.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_compute_pipeline.cpp23
-rw-r--r--src/video_core/renderer_opengl/gl_graphics_pipeline.cpp27
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp72
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h11
-rw-r--r--src/video_core/renderer_vulkan/pipeline_helper.h11
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp20
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp8
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp8
-rw-r--r--src/video_core/renderer_vulkan/vk_master_semaphore.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp51
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h9
-rw-r--r--src/video_core/texture_cache/image_view_base.cpp52
-rw-r--r--src/video_core/texture_cache/image_view_base.h2
-rw-r--r--src/video_core/texture_cache/texture_cache.h30
-rw-r--r--src/video_core/texture_cache/texture_cache_base.h12
-rw-r--r--src/video_core/textures/texture.cpp7
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp11
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h34
-rw-r--r--src/yuzu/CMakeLists.txt2
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp5
-rw-r--r--src/yuzu/configuration/configure_dialog.h7
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp55
-rw-r--r--src/yuzu/configuration/configure_graphics.h3
-rw-r--r--src/yuzu/configuration/configure_per_game.cpp5
-rw-r--r--src/yuzu/configuration/configure_per_game.h3
-rw-r--r--src/yuzu/main.cpp8
-rw-r--r--src/yuzu/main.h6
-rw-r--r--src/yuzu/vk_device_info.cpp61
-rw-r--r--src/yuzu/vk_device_info.h36
-rw-r--r--vcpkg.json2
46 files changed, 534 insertions, 223 deletions
diff --git a/.gitmodules b/.gitmodules
index 95eae8109..89f2ad924 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -52,3 +52,6 @@
52[submodule "libadrenotools"] 52[submodule "libadrenotools"]
53 path = externals/libadrenotools 53 path = externals/libadrenotools
54 url = https://github.com/bylaws/libadrenotools 54 url = https://github.com/bylaws/libadrenotools
55[submodule "tzdb_to_nx"]
56 path = externals/nx_tzdb/tzdb_to_nx
57 url = https://github.com/lat9nq/tzdb_to_nx.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3d03bbf94..6d3146c9e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -59,6 +59,8 @@ option(YUZU_CHECK_SUBMODULES "Check if submodules are present" ON)
59 59
60option(YUZU_ENABLE_LTO "Enable link-time optimization" OFF) 60option(YUZU_ENABLE_LTO "Enable link-time optimization" OFF)
61 61
62option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" OFF)
63
62CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF) 64CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF)
63 65
64# On Android, fetch and compile libcxx before doing anything else 66# On Android, fetch and compile libcxx before doing anything else
diff --git a/externals/nx_tzdb/CMakeLists.txt b/externals/nx_tzdb/CMakeLists.txt
index 2f625c108..d5a1c6317 100644
--- a/externals/nx_tzdb/CMakeLists.txt
+++ b/externals/nx_tzdb/CMakeLists.txt
@@ -1,24 +1,60 @@
1# SPDX-FileCopyrightText: 2023 yuzu Emulator Project 1# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2# SPDX-License-Identifier: GPL-2.0-or-later 2# SPDX-License-Identifier: GPL-2.0-or-later
3 3
4set(NX_TZDB_VERSION "220816") 4set(NX_TZDB_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/include")
5set(NX_TZDB_DOWNLOAD_URL "https://github.com/lat9nq/tzdb_to_nx/releases/download/${NX_TZDB_VERSION}/${NX_TZDB_VERSION}.zip") 5
6add_library(nx_tzdb INTERFACE)
7
8find_program(GIT git)
9find_program(GNU_MAKE make)
10find_program(GNU_DATE date)
6 11
12set(CAN_BUILD_NX_TZDB true)
13
14if (NOT GIT)
15 set(CAN_BUILD_NX_TZDB false)
16endif()
17if (NOT GNU_MAKE)
18 set(CAN_BUILD_NX_TZDB false)
19endif()
20if (NOT GNU_DATE)
21 set(CAN_BUILD_NX_TZDB false)
22endif()
23if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR ANDROID)
24 # tzdb_to_nx currently requires a posix-compliant host
25 # MinGW and Android are handled here due to the executable format being different from the host system
26 # TODO (lat9nq): cross-compiling support
27 set(CAN_BUILD_NX_TZDB false)
28endif()
29
30set(NX_TZDB_VERSION "220816")
7set(NX_TZDB_ARCHIVE "${CMAKE_CURRENT_BINARY_DIR}/${NX_TZDB_VERSION}.zip") 31set(NX_TZDB_ARCHIVE "${CMAKE_CURRENT_BINARY_DIR}/${NX_TZDB_VERSION}.zip")
8set(NX_TZDB_DIR "${CMAKE_CURRENT_BINARY_DIR}/nx_tzdb")
9 32
10set(NX_TZDB_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/include") 33set(NX_TZDB_ROMFS_DIR "${CMAKE_CURRENT_BINARY_DIR}/nx_tzdb")
34
35if ((NOT CAN_BUILD_NX_TZDB OR YUZU_DOWNLOAD_TIME_ZONE_DATA) AND NOT EXISTS ${NX_TZDB_ARCHIVE})
36 set(NX_TZDB_DOWNLOAD_URL "https://github.com/lat9nq/tzdb_to_nx/releases/download/${NX_TZDB_VERSION}/${NX_TZDB_VERSION}.zip")
37
38 message(STATUS "Downloading time zone data from ${NX_TZDB_DOWNLOAD_URL}...")
39 file(DOWNLOAD ${NX_TZDB_DOWNLOAD_URL} ${NX_TZDB_ARCHIVE}
40 STATUS NX_TZDB_DOWNLOAD_STATUS)
41 list(GET NX_TZDB_DOWNLOAD_STATUS 0 NX_TZDB_DOWNLOAD_STATUS_CODE)
42 if (NOT NX_TZDB_DOWNLOAD_STATUS_CODE EQUAL 0)
43 message(FATAL_ERROR "Time zone data download failed (status code ${NX_TZDB_DOWNLOAD_STATUS_CODE})")
44 endif()
11 45
12if (NOT EXISTS ${NX_TZDB_ARCHIVE})
13 file(DOWNLOAD ${NX_TZDB_DOWNLOAD_URL} ${NX_TZDB_ARCHIVE})
14 file(ARCHIVE_EXTRACT 46 file(ARCHIVE_EXTRACT
15 INPUT 47 INPUT
16 ${NX_TZDB_ARCHIVE} 48 ${NX_TZDB_ARCHIVE}
17 DESTINATION 49 DESTINATION
18 ${NX_TZDB_DIR}) 50 ${NX_TZDB_ROMFS_DIR})
51elseif (CAN_BUILD_NX_TZDB AND NOT YUZU_DOWNLOAD_TIME_ZONE_DATA)
52 add_subdirectory(tzdb_to_nx)
53 add_dependencies(nx_tzdb x80e)
54
55 set(NX_TZDB_ROMFS_DIR "${NX_TZDB_DIR}")
19endif() 56endif()
20 57
21add_library(nx_tzdb INTERFACE)
22target_include_directories(nx_tzdb 58target_include_directories(nx_tzdb
23 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include 59 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include
24 INTERFACE ${NX_TZDB_INCLUDE_DIR}) 60 INTERFACE ${NX_TZDB_INCLUDE_DIR})
@@ -41,25 +77,25 @@ function(CreateHeader ZONE_PATH HEADER_NAME)
41 target_sources(nx_tzdb PRIVATE ${HEADER_PATH}) 77 target_sources(nx_tzdb PRIVATE ${HEADER_PATH})
42endfunction() 78endfunction()
43 79
44CreateHeader(${NX_TZDB_DIR} base) 80CreateHeader(${NX_TZDB_ROMFS_DIR} base)
45CreateHeader(${NX_TZDB_DIR}/zoneinfo zoneinfo) 81CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo zoneinfo)
46CreateHeader(${NX_TZDB_DIR}/zoneinfo/Africa africa) 82CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Africa africa)
47CreateHeader(${NX_TZDB_DIR}/zoneinfo/America america) 83CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America america)
48CreateHeader(${NX_TZDB_DIR}/zoneinfo/America/Argentina america_argentina) 84CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Argentina america_argentina)
49CreateHeader(${NX_TZDB_DIR}/zoneinfo/America/Indiana america_indiana) 85CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Indiana america_indiana)
50CreateHeader(${NX_TZDB_DIR}/zoneinfo/America/Kentucky america_kentucky) 86CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Kentucky america_kentucky)
51CreateHeader(${NX_TZDB_DIR}/zoneinfo/America/North_Dakota america_north_dakota) 87CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/North_Dakota america_north_dakota)
52CreateHeader(${NX_TZDB_DIR}/zoneinfo/Antartica antartica) 88CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Antarctica antarctica)
53CreateHeader(${NX_TZDB_DIR}/zoneinfo/Arctic arctic) 89CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Arctic arctic)
54CreateHeader(${NX_TZDB_DIR}/zoneinfo/Asia asia) 90CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Asia asia)
55CreateHeader(${NX_TZDB_DIR}/zoneinfo/Atlantic atlantic) 91CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Atlantic atlantic)
56CreateHeader(${NX_TZDB_DIR}/zoneinfo/Australia australia) 92CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Australia australia)
57CreateHeader(${NX_TZDB_DIR}/zoneinfo/Brazil brazil) 93CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Brazil brazil)
58CreateHeader(${NX_TZDB_DIR}/zoneinfo/Canada canada) 94CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Canada canada)
59CreateHeader(${NX_TZDB_DIR}/zoneinfo/Chile chile) 95CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Chile chile)
60CreateHeader(${NX_TZDB_DIR}/zoneinfo/Etc etc) 96CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Etc etc)
61CreateHeader(${NX_TZDB_DIR}/zoneinfo/Europe europe) 97CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Europe europe)
62CreateHeader(${NX_TZDB_DIR}/zoneinfo/Indian indian) 98CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Indian indian)
63CreateHeader(${NX_TZDB_DIR}/zoneinfo/Mexico mexico) 99CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Mexico mexico)
64CreateHeader(${NX_TZDB_DIR}/zoneinfo/Pacific pacific) 100CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Pacific pacific)
65CreateHeader(${NX_TZDB_DIR}/zoneinfo/US us) 101CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/US us)
diff --git a/externals/nx_tzdb/NxTzdbCreateHeader.cmake b/externals/nx_tzdb/NxTzdbCreateHeader.cmake
index 69166aa5b..8c29e1167 100644
--- a/externals/nx_tzdb/NxTzdbCreateHeader.cmake
+++ b/externals/nx_tzdb/NxTzdbCreateHeader.cmake
@@ -15,7 +15,7 @@ set(DIRECTORY_NAME ${HEADER_NAME})
15 15
16set(FILE_DATA "") 16set(FILE_DATA "")
17foreach(ZONE_FILE ${FILE_LIST}) 17foreach(ZONE_FILE ${FILE_LIST})
18 if ("${ZONE_FILE}" STREQUAL "\n") 18 if (ZONE_FILE STREQUAL "\n")
19 continue() 19 continue()
20 endif() 20 endif()
21 21
@@ -26,13 +26,13 @@ foreach(ZONE_FILE ${FILE_LIST})
26 foreach(I RANGE 0 ${ZONE_DATA_LEN} 2) 26 foreach(I RANGE 0 ${ZONE_DATA_LEN} 2)
27 math(EXPR BREAK_LINE "(${I} + 2) % 38") 27 math(EXPR BREAK_LINE "(${I} + 2) % 38")
28 28
29 string(SUBSTRING "${ZONE_DATA}" "${I}" "2" HEX_DATA) 29 string(SUBSTRING "${ZONE_DATA}" "${I}" 2 HEX_DATA)
30 if ("${HEX_DATA}" STREQUAL "") 30 if (NOT HEX_DATA)
31 break() 31 break()
32 endif() 32 endif()
33 33
34 string(APPEND FILE_DATA "0x${HEX_DATA},") 34 string(APPEND FILE_DATA "0x${HEX_DATA},")
35 if ("${BREAK_LINE}" STREQUAL "0") 35 if (BREAK_LINE EQUAL 0)
36 string(APPEND FILE_DATA "\n") 36 string(APPEND FILE_DATA "\n")
37 else() 37 else()
38 string(APPEND FILE_DATA " ") 38 string(APPEND FILE_DATA " ")
diff --git a/externals/nx_tzdb/include/nx_tzdb.h b/externals/nx_tzdb/include/nx_tzdb.h
index d7b1e4304..1f7c6069a 100644
--- a/externals/nx_tzdb/include/nx_tzdb.h
+++ b/externals/nx_tzdb/include/nx_tzdb.h
@@ -9,7 +9,7 @@
9#include "nx_tzdb/america_indiana.h" 9#include "nx_tzdb/america_indiana.h"
10#include "nx_tzdb/america_kentucky.h" 10#include "nx_tzdb/america_kentucky.h"
11#include "nx_tzdb/america_north_dakota.h" 11#include "nx_tzdb/america_north_dakota.h"
12#include "nx_tzdb/antartica.h" 12#include "nx_tzdb/antarctica.h"
13#include "nx_tzdb/arctic.h" 13#include "nx_tzdb/arctic.h"
14#include "nx_tzdb/asia.h" 14#include "nx_tzdb/asia.h"
15#include "nx_tzdb/atlantic.h" 15#include "nx_tzdb/atlantic.h"
diff --git a/externals/nx_tzdb/tzdb_to_nx b/externals/nx_tzdb/tzdb_to_nx
new file mode 160000
Subproject 34df65eff295c2bd9ee9e6a077d662486d5cabb
diff --git a/externals/vcpkg b/externals/vcpkg
Subproject a487471068f4cb1cbb4eeb340763cdcc0a75fd6 Subproject cbf56573a987527b39272e88cbdd11389b78c6e
diff --git a/src/core/file_sys/system_archive/time_zone_binary.cpp b/src/core/file_sys/system_archive/time_zone_binary.cpp
index ceb0b41c6..7c17bbefa 100644
--- a/src/core/file_sys/system_archive/time_zone_binary.cpp
+++ b/src/core/file_sys/system_archive/time_zone_binary.cpp
@@ -15,7 +15,7 @@ namespace FileSys::SystemArchive {
15const static std::map<std::string, const std::map<const char*, const std::vector<u8>>&> 15const static std::map<std::string, const std::map<const char*, const std::vector<u8>>&>
16 tzdb_zoneinfo_dirs = {{"Africa", NxTzdb::africa}, 16 tzdb_zoneinfo_dirs = {{"Africa", NxTzdb::africa},
17 {"America", NxTzdb::america}, 17 {"America", NxTzdb::america},
18 {"Antartica", NxTzdb::antartica}, 18 {"Antarctica", NxTzdb::antarctica},
19 {"Arctic", NxTzdb::arctic}, 19 {"Arctic", NxTzdb::arctic},
20 {"Asia", NxTzdb::asia}, 20 {"Asia", NxTzdb::asia},
21 {"Atlantic", NxTzdb::atlantic}, 21 {"Atlantic", NxTzdb::atlantic},
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 70480b725..908811e2c 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -4,6 +4,8 @@
4#include <algorithm> 4#include <algorithm>
5#include <atomic> 5#include <atomic>
6#include <cinttypes> 6#include <cinttypes>
7#include <condition_variable>
8#include <mutex>
7#include <optional> 9#include <optional>
8#include <vector> 10#include <vector>
9 11
@@ -1313,7 +1315,8 @@ void KThread::RequestDummyThreadWait() {
1313 ASSERT(this->IsDummyThread()); 1315 ASSERT(this->IsDummyThread());
1314 1316
1315 // We will block when the scheduler lock is released. 1317 // We will block when the scheduler lock is released.
1316 m_dummy_thread_runnable.store(false); 1318 std::scoped_lock lock{m_dummy_thread_mutex};
1319 m_dummy_thread_runnable = false;
1317} 1320}
1318 1321
1319void KThread::DummyThreadBeginWait() { 1322void KThread::DummyThreadBeginWait() {
@@ -1323,7 +1326,8 @@ void KThread::DummyThreadBeginWait() {
1323 } 1326 }
1324 1327
1325 // Block until runnable is no longer false. 1328 // Block until runnable is no longer false.
1326 m_dummy_thread_runnable.wait(false); 1329 std::unique_lock lock{m_dummy_thread_mutex};
1330 m_dummy_thread_cv.wait(lock, [this] { return m_dummy_thread_runnable; });
1327} 1331}
1328 1332
1329void KThread::DummyThreadEndWait() { 1333void KThread::DummyThreadEndWait() {
@@ -1331,8 +1335,11 @@ void KThread::DummyThreadEndWait() {
1331 ASSERT(this->IsDummyThread()); 1335 ASSERT(this->IsDummyThread());
1332 1336
1333 // Wake up the waiting thread. 1337 // Wake up the waiting thread.
1334 m_dummy_thread_runnable.store(true); 1338 {
1335 m_dummy_thread_runnable.notify_one(); 1339 std::scoped_lock lock{m_dummy_thread_mutex};
1340 m_dummy_thread_runnable = true;
1341 }
1342 m_dummy_thread_cv.notify_one();
1336} 1343}
1337 1344
1338void KThread::BeginWait(KThreadQueue* queue) { 1345void KThread::BeginWait(KThreadQueue* queue) {
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index f9814ac8f..37fe5db77 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -892,7 +892,9 @@ private:
892 std::shared_ptr<Common::Fiber> m_host_context{}; 892 std::shared_ptr<Common::Fiber> m_host_context{};
893 ThreadType m_thread_type{}; 893 ThreadType m_thread_type{};
894 StepState m_step_state{}; 894 StepState m_step_state{};
895 std::atomic<bool> m_dummy_thread_runnable{true}; 895 bool m_dummy_thread_runnable{true};
896 std::mutex m_dummy_thread_mutex{};
897 std::condition_variable m_dummy_thread_cv{};
896 898
897 // For debugging 899 // For debugging
898 std::vector<KSynchronizationObject*> m_wait_objects_for_debugging{}; 900 std::vector<KSynchronizationObject*> m_wait_objects_for_debugging{};
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp
index e1728c06d..63aacd19f 100644
--- a/src/core/hle/service/time/time_zone_manager.cpp
+++ b/src/core/hle/service/time/time_zone_manager.cpp
@@ -849,8 +849,9 @@ static Result CreateCalendarTime(s64 time, int gmt_offset, CalendarTimeInternal&
849static Result ToCalendarTimeInternal(const TimeZoneRule& rules, s64 time, 849static Result ToCalendarTimeInternal(const TimeZoneRule& rules, s64 time,
850 CalendarTimeInternal& calendar_time, 850 CalendarTimeInternal& calendar_time,
851 CalendarAdditionalInfo& calendar_additional_info) { 851 CalendarAdditionalInfo& calendar_additional_info) {
852 if ((rules.go_ahead && time < rules.ats[0]) || 852 ASSERT(rules.go_ahead ? rules.time_count > 0 : true);
853 (rules.go_back && time > rules.ats[rules.time_count - 1])) { 853 if ((rules.go_back && time < rules.ats[0]) ||
854 (rules.go_ahead && time > rules.ats[rules.time_count - 1])) {
854 s64 seconds{}; 855 s64 seconds{};
855 if (time < rules.ats[0]) { 856 if (time < rules.ats[0]) {
856 seconds = rules.ats[0] - time; 857 seconds = rules.ats[0] - time;
diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp
index e8273e152..8171c82a5 100644
--- a/src/core/hle/service/time/time_zone_service.cpp
+++ b/src/core/hle/service/time/time_zone_service.cpp
@@ -112,20 +112,14 @@ void ITimeZoneService::LoadTimeZoneRule(HLERequestContext& ctx) {
112 LOG_DEBUG(Service_Time, "called, location_name={}", location_name); 112 LOG_DEBUG(Service_Time, "called, location_name={}", location_name);
113 113
114 TimeZone::TimeZoneRule time_zone_rule{}; 114 TimeZone::TimeZoneRule time_zone_rule{};
115 if (const Result result{ 115 const Result result{time_zone_content_manager.LoadTimeZoneRule(time_zone_rule, location_name)};
116 time_zone_content_manager.LoadTimeZoneRule(time_zone_rule, location_name)};
117 result != ResultSuccess) {
118 IPC::ResponseBuilder rb{ctx, 2};
119 rb.Push(result);
120 return;
121 }
122 116
123 std::vector<u8> time_zone_rule_outbuffer(sizeof(TimeZone::TimeZoneRule)); 117 std::vector<u8> time_zone_rule_outbuffer(sizeof(TimeZone::TimeZoneRule));
124 std::memcpy(time_zone_rule_outbuffer.data(), &time_zone_rule, sizeof(TimeZone::TimeZoneRule)); 118 std::memcpy(time_zone_rule_outbuffer.data(), &time_zone_rule, sizeof(TimeZone::TimeZoneRule));
125 ctx.WriteBuffer(time_zone_rule_outbuffer); 119 ctx.WriteBuffer(time_zone_rule_outbuffer);
126 120
127 IPC::ResponseBuilder rb{ctx, 2}; 121 IPC::ResponseBuilder rb{ctx, 2};
128 rb.Push(ResultSuccess); 122 rb.Push(result);
129} 123}
130 124
131void ITimeZoneService::ToCalendarTime(HLERequestContext& ctx) { 125void ITimeZoneService::ToCalendarTime(HLERequestContext& ctx) {
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 9bafd8cc0..45977d578 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -719,9 +719,15 @@ void BufferCache<P>::BindHostVertexBuffers() {
719 bool any_valid{false}; 719 bool any_valid{false};
720 auto& flags = maxwell3d->dirty.flags; 720 auto& flags = maxwell3d->dirty.flags;
721 for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) { 721 for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
722 const Binding& binding = channel_state->vertex_buffers[index];
723 Buffer& buffer = slot_buffers[binding.buffer_id];
724 TouchBuffer(buffer, binding.buffer_id);
725 SynchronizeBuffer(buffer, binding.cpu_addr, binding.size);
722 if (!flags[Dirty::VertexBuffer0 + index]) { 726 if (!flags[Dirty::VertexBuffer0 + index]) {
723 continue; 727 continue;
724 } 728 }
729 flags[Dirty::VertexBuffer0 + index] = false;
730
725 host_bindings.min_index = std::min(host_bindings.min_index, index); 731 host_bindings.min_index = std::min(host_bindings.min_index, index);
726 host_bindings.max_index = std::max(host_bindings.max_index, index); 732 host_bindings.max_index = std::max(host_bindings.max_index, index);
727 any_valid = true; 733 any_valid = true;
@@ -735,9 +741,6 @@ void BufferCache<P>::BindHostVertexBuffers() {
735 const Binding& binding = channel_state->vertex_buffers[index]; 741 const Binding& binding = channel_state->vertex_buffers[index];
736 Buffer& buffer = slot_buffers[binding.buffer_id]; 742 Buffer& buffer = slot_buffers[binding.buffer_id];
737 743
738 TouchBuffer(buffer, binding.buffer_id);
739 SynchronizeBuffer(buffer, binding.cpu_addr, binding.size);
740
741 const u32 stride = maxwell3d->regs.vertex_streams[index].stride; 744 const u32 stride = maxwell3d->regs.vertex_streams[index].stride;
742 const u32 offset = buffer.Offset(binding.cpu_addr); 745 const u32 offset = buffer.Offset(binding.cpu_addr);
743 746
diff --git a/src/video_core/engines/draw_manager.cpp b/src/video_core/engines/draw_manager.cpp
index 0e94c521a..f34090791 100644
--- a/src/video_core/engines/draw_manager.cpp
+++ b/src/video_core/engines/draw_manager.cpp
@@ -1,6 +1,7 @@
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 "common/settings.h"
4#include "video_core/dirty_flags.h" 5#include "video_core/dirty_flags.h"
5#include "video_core/engines/draw_manager.h" 6#include "video_core/engines/draw_manager.h"
6#include "video_core/rasterizer_interface.h" 7#include "video_core/rasterizer_interface.h"
@@ -195,8 +196,12 @@ void DrawManager::DrawTexture() {
195 if (lower_left) { 196 if (lower_left) {
196 draw_texture_state.dst_y0 -= dst_height; 197 draw_texture_state.dst_y0 -= dst_height;
197 } 198 }
198 draw_texture_state.dst_x1 = draw_texture_state.dst_x0 + dst_width; 199 draw_texture_state.dst_x1 =
199 draw_texture_state.dst_y1 = draw_texture_state.dst_y0 + dst_height; 200 draw_texture_state.dst_x0 +
201 static_cast<f32>(Settings::values.resolution_info.ScaleUp(static_cast<u32>(dst_width)));
202 draw_texture_state.dst_y1 =
203 draw_texture_state.dst_y0 +
204 static_cast<f32>(Settings::values.resolution_info.ScaleUp(static_cast<u32>(dst_height)));
200 draw_texture_state.src_x0 = static_cast<float>(regs.draw_texture.src_x0) / 4096.f; 205 draw_texture_state.src_x0 = static_cast<float>(regs.draw_texture.src_x0) / 4096.f;
201 draw_texture_state.src_y0 = static_cast<float>(regs.draw_texture.src_y0) / 4096.f; 206 draw_texture_state.src_y0 = static_cast<float>(regs.draw_texture.src_y0) / 4096.f;
202 draw_texture_state.src_x1 = 207 draw_texture_state.src_x1 =
@@ -207,7 +212,6 @@ void DrawManager::DrawTexture() {
207 draw_texture_state.src_y0; 212 draw_texture_state.src_y0;
208 draw_texture_state.src_sampler = regs.draw_texture.src_sampler; 213 draw_texture_state.src_sampler = regs.draw_texture.src_sampler;
209 draw_texture_state.src_texture = regs.draw_texture.src_texture; 214 draw_texture_state.src_texture = regs.draw_texture.src_texture;
210
211 maxwell3d->rasterizer->DrawTexture(); 215 maxwell3d->rasterizer->DrawTexture();
212} 216}
213 217
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 7b2cde7a7..b2f7e160a 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -111,7 +111,7 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cp
111 [[maybe_unused]] const auto current_entry_type = GetEntry<false>(current_gpu_addr); 111 [[maybe_unused]] const auto current_entry_type = GetEntry<false>(current_gpu_addr);
112 SetEntry<false>(current_gpu_addr, entry_type); 112 SetEntry<false>(current_gpu_addr, entry_type);
113 if (current_entry_type != entry_type) { 113 if (current_entry_type != entry_type) {
114 rasterizer->ModifyGPUMemory(unique_identifier, gpu_addr, page_size); 114 rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, page_size);
115 } 115 }
116 if constexpr (entry_type == EntryType::Mapped) { 116 if constexpr (entry_type == EntryType::Mapped) {
117 const VAddr current_cpu_addr = cpu_addr + offset; 117 const VAddr current_cpu_addr = cpu_addr + offset;
@@ -134,7 +134,7 @@ GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr
134 [[maybe_unused]] const auto current_entry_type = GetEntry<true>(current_gpu_addr); 134 [[maybe_unused]] const auto current_entry_type = GetEntry<true>(current_gpu_addr);
135 SetEntry<true>(current_gpu_addr, entry_type); 135 SetEntry<true>(current_gpu_addr, entry_type);
136 if (current_entry_type != entry_type) { 136 if (current_entry_type != entry_type) {
137 rasterizer->ModifyGPUMemory(unique_identifier, gpu_addr, big_page_size); 137 rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, big_page_size);
138 } 138 }
139 if constexpr (entry_type == EntryType::Mapped) { 139 if constexpr (entry_type == EntryType::Mapped) {
140 const VAddr current_cpu_addr = cpu_addr + offset; 140 const VAddr current_cpu_addr = cpu_addr + offset;
diff --git a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp
index 1a0cea9b7..3151c0db8 100644
--- a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp
+++ b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp
@@ -87,7 +87,8 @@ void ComputePipeline::Configure() {
87 texture_cache.SynchronizeComputeDescriptors(); 87 texture_cache.SynchronizeComputeDescriptors();
88 88
89 boost::container::static_vector<VideoCommon::ImageViewInOut, MAX_TEXTURES + MAX_IMAGES> views; 89 boost::container::static_vector<VideoCommon::ImageViewInOut, MAX_TEXTURES + MAX_IMAGES> views;
90 std::array<GLuint, MAX_TEXTURES> samplers; 90 boost::container::static_vector<VideoCommon::SamplerId, MAX_TEXTURES> samplers;
91 std::array<GLuint, MAX_TEXTURES> gl_samplers;
91 std::array<GLuint, MAX_TEXTURES> textures; 92 std::array<GLuint, MAX_TEXTURES> textures;
92 std::array<GLuint, MAX_IMAGES> images; 93 std::array<GLuint, MAX_IMAGES> images;
93 GLsizei sampler_binding{}; 94 GLsizei sampler_binding{};
@@ -131,7 +132,6 @@ void ComputePipeline::Configure() {
131 for (u32 index = 0; index < desc.count; ++index) { 132 for (u32 index = 0; index < desc.count; ++index) {
132 const auto handle{read_handle(desc, index)}; 133 const auto handle{read_handle(desc, index)};
133 views.push_back({handle.first}); 134 views.push_back({handle.first});
134 samplers[sampler_binding++] = 0;
135 } 135 }
136 } 136 }
137 for (const auto& desc : info.image_buffer_descriptors) { 137 for (const auto& desc : info.image_buffer_descriptors) {
@@ -142,8 +142,8 @@ void ComputePipeline::Configure() {
142 const auto handle{read_handle(desc, index)}; 142 const auto handle{read_handle(desc, index)};
143 views.push_back({handle.first}); 143 views.push_back({handle.first});
144 144
145 Sampler* const sampler = texture_cache.GetComputeSampler(handle.second); 145 VideoCommon::SamplerId sampler = texture_cache.GetComputeSamplerId(handle.second);
146 samplers[sampler_binding++] = sampler->Handle(); 146 samplers.push_back(sampler);
147 } 147 }
148 } 148 }
149 for (const auto& desc : info.image_descriptors) { 149 for (const auto& desc : info.image_descriptors) {
@@ -186,10 +186,17 @@ void ComputePipeline::Configure() {
186 186
187 const VideoCommon::ImageViewInOut* views_it{views.data() + num_texture_buffers + 187 const VideoCommon::ImageViewInOut* views_it{views.data() + num_texture_buffers +
188 num_image_buffers}; 188 num_image_buffers};
189 const VideoCommon::SamplerId* samplers_it{samplers.data()};
189 texture_binding += num_texture_buffers; 190 texture_binding += num_texture_buffers;
190 image_binding += num_image_buffers; 191 image_binding += num_image_buffers;
191 192
192 u32 texture_scaling_mask{}; 193 u32 texture_scaling_mask{};
194
195 for (const auto& desc : info.texture_buffer_descriptors) {
196 for (u32 index = 0; index < desc.count; ++index) {
197 gl_samplers[sampler_binding++] = 0;
198 }
199 }
193 for (const auto& desc : info.texture_descriptors) { 200 for (const auto& desc : info.texture_descriptors) {
194 for (u32 index = 0; index < desc.count; ++index) { 201 for (u32 index = 0; index < desc.count; ++index) {
195 ImageView& image_view{texture_cache.GetImageView((views_it++)->id)}; 202 ImageView& image_view{texture_cache.GetImageView((views_it++)->id)};
@@ -198,6 +205,12 @@ void ComputePipeline::Configure() {
198 texture_scaling_mask |= 1u << texture_binding; 205 texture_scaling_mask |= 1u << texture_binding;
199 } 206 }
200 ++texture_binding; 207 ++texture_binding;
208
209 const Sampler& sampler{texture_cache.GetSampler(*(samplers_it++))};
210 const bool use_fallback_sampler{sampler.HasAddedAnisotropy() &&
211 !image_view.SupportsAnisotropy()};
212 gl_samplers[sampler_binding++] =
213 use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy() : sampler.Handle();
201 } 214 }
202 } 215 }
203 u32 image_scaling_mask{}; 216 u32 image_scaling_mask{};
@@ -228,7 +241,7 @@ void ComputePipeline::Configure() {
228 if (texture_binding != 0) { 241 if (texture_binding != 0) {
229 ASSERT(texture_binding == sampler_binding); 242 ASSERT(texture_binding == sampler_binding);
230 glBindTextures(0, texture_binding, textures.data()); 243 glBindTextures(0, texture_binding, textures.data());
231 glBindSamplers(0, sampler_binding, samplers.data()); 244 glBindSamplers(0, sampler_binding, gl_samplers.data());
232 } 245 }
233 if (image_binding != 0) { 246 if (image_binding != 0) {
234 glBindImageTextures(0, image_binding, images.data()); 247 glBindImageTextures(0, image_binding, images.data());
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
index 89000d6e0..c58f760b8 100644
--- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
+++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
@@ -275,9 +275,9 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
275template <typename Spec> 275template <typename Spec>
276void GraphicsPipeline::ConfigureImpl(bool is_indexed) { 276void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
277 std::array<VideoCommon::ImageViewInOut, MAX_TEXTURES + MAX_IMAGES> views; 277 std::array<VideoCommon::ImageViewInOut, MAX_TEXTURES + MAX_IMAGES> views;
278 std::array<GLuint, MAX_TEXTURES> samplers; 278 std::array<VideoCommon::SamplerId, MAX_TEXTURES> samplers;
279 size_t views_index{}; 279 size_t views_index{};
280 GLsizei sampler_binding{}; 280 size_t samplers_index{};
281 281
282 texture_cache.SynchronizeGraphicsDescriptors(); 282 texture_cache.SynchronizeGraphicsDescriptors();
283 283
@@ -337,7 +337,6 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
337 for (u32 index = 0; index < desc.count; ++index) { 337 for (u32 index = 0; index < desc.count; ++index) {
338 const auto handle{read_handle(desc, index)}; 338 const auto handle{read_handle(desc, index)};
339 views[views_index++] = {handle.first}; 339 views[views_index++] = {handle.first};
340 samplers[sampler_binding++] = 0;
341 } 340 }
342 } 341 }
343 } 342 }
@@ -351,8 +350,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
351 const auto handle{read_handle(desc, index)}; 350 const auto handle{read_handle(desc, index)};
352 views[views_index++] = {handle.first}; 351 views[views_index++] = {handle.first};
353 352
354 Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.second)}; 353 VideoCommon::SamplerId sampler{texture_cache.GetGraphicsSamplerId(handle.second)};
355 samplers[sampler_binding++] = sampler->Handle(); 354 samplers[samplers_index++] = sampler;
356 } 355 }
357 } 356 }
358 if constexpr (Spec::has_images) { 357 if constexpr (Spec::has_images) {
@@ -445,10 +444,13 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
445 program_manager.BindSourcePrograms(source_programs); 444 program_manager.BindSourcePrograms(source_programs);
446 } 445 }
447 const VideoCommon::ImageViewInOut* views_it{views.data()}; 446 const VideoCommon::ImageViewInOut* views_it{views.data()};
447 const VideoCommon::SamplerId* samplers_it{samplers.data()};
448 GLsizei texture_binding = 0; 448 GLsizei texture_binding = 0;
449 GLsizei image_binding = 0; 449 GLsizei image_binding = 0;
450 GLsizei sampler_binding{};
450 std::array<GLuint, MAX_TEXTURES> textures; 451 std::array<GLuint, MAX_TEXTURES> textures;
451 std::array<GLuint, MAX_IMAGES> images; 452 std::array<GLuint, MAX_IMAGES> images;
453 std::array<GLuint, MAX_TEXTURES> gl_samplers;
452 const auto prepare_stage{[&](size_t stage) { 454 const auto prepare_stage{[&](size_t stage) {
453 buffer_cache.runtime.SetImagePointers(&textures[texture_binding], &images[image_binding]); 455 buffer_cache.runtime.SetImagePointers(&textures[texture_binding], &images[image_binding]);
454 buffer_cache.BindHostStageBuffers(stage); 456 buffer_cache.BindHostStageBuffers(stage);
@@ -465,6 +467,13 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
465 u32 stage_image_binding{}; 467 u32 stage_image_binding{};
466 468
467 const auto& info{stage_infos[stage]}; 469 const auto& info{stage_infos[stage]};
470 if constexpr (Spec::has_texture_buffers) {
471 for (const auto& desc : info.texture_buffer_descriptors) {
472 for (u32 index = 0; index < desc.count; ++index) {
473 gl_samplers[sampler_binding++] = 0;
474 }
475 }
476 }
468 for (const auto& desc : info.texture_descriptors) { 477 for (const auto& desc : info.texture_descriptors) {
469 for (u32 index = 0; index < desc.count; ++index) { 478 for (u32 index = 0; index < desc.count; ++index) {
470 ImageView& image_view{texture_cache.GetImageView((views_it++)->id)}; 479 ImageView& image_view{texture_cache.GetImageView((views_it++)->id)};
@@ -474,6 +483,12 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
474 } 483 }
475 ++texture_binding; 484 ++texture_binding;
476 ++stage_texture_binding; 485 ++stage_texture_binding;
486
487 const Sampler& sampler{texture_cache.GetSampler(*(samplers_it++))};
488 const bool use_fallback_sampler{sampler.HasAddedAnisotropy() &&
489 !image_view.SupportsAnisotropy()};
490 gl_samplers[sampler_binding++] =
491 use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy() : sampler.Handle();
477 } 492 }
478 } 493 }
479 for (const auto& desc : info.image_descriptors) { 494 for (const auto& desc : info.image_descriptors) {
@@ -534,7 +549,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
534 if (texture_binding != 0) { 549 if (texture_binding != 0) {
535 ASSERT(texture_binding == sampler_binding); 550 ASSERT(texture_binding == sampler_binding);
536 glBindTextures(0, texture_binding, textures.data()); 551 glBindTextures(0, texture_binding, textures.data());
537 glBindSamplers(0, sampler_binding, samplers.data()); 552 glBindSamplers(0, sampler_binding, gl_samplers.data());
538 } 553 }
539 if (image_binding != 0) { 554 if (image_binding != 0) {
540 glBindImageTextures(0, image_binding, images.data()); 555 glBindImageTextures(0, image_binding, images.data());
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 1c5dbcdd8..3b446be07 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -1268,36 +1268,48 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const TSCEntry& config) {
1268 1268
1269 UNIMPLEMENTED_IF(config.cubemap_anisotropy != 1); 1269 UNIMPLEMENTED_IF(config.cubemap_anisotropy != 1);
1270 1270
1271 sampler.Create(); 1271 const f32 max_anisotropy = std::clamp(config.MaxAnisotropy(), 1.0f, 16.0f);
1272 const GLuint handle = sampler.handle; 1272
1273 glSamplerParameteri(handle, GL_TEXTURE_WRAP_S, MaxwellToGL::WrapMode(config.wrap_u)); 1273 const auto create_sampler = [&](const f32 anisotropy) {
1274 glSamplerParameteri(handle, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(config.wrap_v)); 1274 OGLSampler new_sampler;
1275 glSamplerParameteri(handle, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(config.wrap_p)); 1275 new_sampler.Create();
1276 glSamplerParameteri(handle, GL_TEXTURE_COMPARE_MODE, compare_mode); 1276 const GLuint handle = new_sampler.handle;
1277 glSamplerParameteri(handle, GL_TEXTURE_COMPARE_FUNC, compare_func); 1277 glSamplerParameteri(handle, GL_TEXTURE_WRAP_S, MaxwellToGL::WrapMode(config.wrap_u));
1278 glSamplerParameteri(handle, GL_TEXTURE_MAG_FILTER, mag); 1278 glSamplerParameteri(handle, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(config.wrap_v));
1279 glSamplerParameteri(handle, GL_TEXTURE_MIN_FILTER, min); 1279 glSamplerParameteri(handle, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(config.wrap_p));
1280 glSamplerParameterf(handle, GL_TEXTURE_LOD_BIAS, config.LodBias()); 1280 glSamplerParameteri(handle, GL_TEXTURE_COMPARE_MODE, compare_mode);
1281 glSamplerParameterf(handle, GL_TEXTURE_MIN_LOD, config.MinLod()); 1281 glSamplerParameteri(handle, GL_TEXTURE_COMPARE_FUNC, compare_func);
1282 glSamplerParameterf(handle, GL_TEXTURE_MAX_LOD, config.MaxLod()); 1282 glSamplerParameteri(handle, GL_TEXTURE_MAG_FILTER, mag);
1283 glSamplerParameterfv(handle, GL_TEXTURE_BORDER_COLOR, config.BorderColor().data()); 1283 glSamplerParameteri(handle, GL_TEXTURE_MIN_FILTER, min);
1284 1284 glSamplerParameterf(handle, GL_TEXTURE_LOD_BIAS, config.LodBias());
1285 if (GLAD_GL_ARB_texture_filter_anisotropic || GLAD_GL_EXT_texture_filter_anisotropic) { 1285 glSamplerParameterf(handle, GL_TEXTURE_MIN_LOD, config.MinLod());
1286 const f32 max_anisotropy = std::clamp(config.MaxAnisotropy(), 1.0f, 16.0f); 1286 glSamplerParameterf(handle, GL_TEXTURE_MAX_LOD, config.MaxLod());
1287 glSamplerParameterf(handle, GL_TEXTURE_MAX_ANISOTROPY, max_anisotropy); 1287 glSamplerParameterfv(handle, GL_TEXTURE_BORDER_COLOR, config.BorderColor().data());
1288 } else { 1288
1289 LOG_WARNING(Render_OpenGL, "GL_ARB_texture_filter_anisotropic is required"); 1289 if (GLAD_GL_ARB_texture_filter_anisotropic || GLAD_GL_EXT_texture_filter_anisotropic) {
1290 } 1290 glSamplerParameterf(handle, GL_TEXTURE_MAX_ANISOTROPY, anisotropy);
1291 if (GLAD_GL_ARB_texture_filter_minmax || GLAD_GL_EXT_texture_filter_minmax) { 1291 } else {
1292 glSamplerParameteri(handle, GL_TEXTURE_REDUCTION_MODE_ARB, reduction_filter); 1292 LOG_WARNING(Render_OpenGL, "GL_ARB_texture_filter_anisotropic is required");
1293 } else if (reduction_filter != GL_WEIGHTED_AVERAGE_ARB) { 1293 }
1294 LOG_WARNING(Render_OpenGL, "GL_ARB_texture_filter_minmax is required"); 1294 if (GLAD_GL_ARB_texture_filter_minmax || GLAD_GL_EXT_texture_filter_minmax) {
1295 } 1295 glSamplerParameteri(handle, GL_TEXTURE_REDUCTION_MODE_ARB, reduction_filter);
1296 if (GLAD_GL_ARB_seamless_cubemap_per_texture || GLAD_GL_AMD_seamless_cubemap_per_texture) { 1296 } else if (reduction_filter != GL_WEIGHTED_AVERAGE_ARB) {
1297 glSamplerParameteri(handle, GL_TEXTURE_CUBE_MAP_SEAMLESS, seamless); 1297 LOG_WARNING(Render_OpenGL, "GL_ARB_texture_filter_minmax is required");
1298 } else if (seamless == GL_FALSE) { 1298 }
1299 // We default to false because it's more common 1299 if (GLAD_GL_ARB_seamless_cubemap_per_texture || GLAD_GL_AMD_seamless_cubemap_per_texture) {
1300 LOG_WARNING(Render_OpenGL, "GL_ARB_seamless_cubemap_per_texture is required"); 1300 glSamplerParameteri(handle, GL_TEXTURE_CUBE_MAP_SEAMLESS, seamless);
1301 } else if (seamless == GL_FALSE) {
1302 // We default to false because it's more common
1303 LOG_WARNING(Render_OpenGL, "GL_ARB_seamless_cubemap_per_texture is required");
1304 }
1305 return new_sampler;
1306 };
1307
1308 sampler = create_sampler(max_anisotropy);
1309
1310 const f32 max_anisotropy_default = static_cast<f32>(1U << config.max_anisotropy);
1311 if (max_anisotropy > max_anisotropy_default) {
1312 sampler_default_anisotropy = create_sampler(max_anisotropy_default);
1301 } 1313 }
1302} 1314}
1303 1315
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 1148b73d7..3676eaaa9 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -309,12 +309,21 @@ class Sampler {
309public: 309public:
310 explicit Sampler(TextureCacheRuntime&, const Tegra::Texture::TSCEntry&); 310 explicit Sampler(TextureCacheRuntime&, const Tegra::Texture::TSCEntry&);
311 311
312 GLuint Handle() const noexcept { 312 [[nodiscard]] GLuint Handle() const noexcept {
313 return sampler.handle; 313 return sampler.handle;
314 } 314 }
315 315
316 [[nodiscard]] GLuint HandleWithDefaultAnisotropy() const noexcept {
317 return sampler_default_anisotropy.handle;
318 }
319
320 [[nodiscard]] bool HasAddedAnisotropy() const noexcept {
321 return static_cast<bool>(sampler_default_anisotropy.handle);
322 }
323
316private: 324private:
317 OGLSampler sampler; 325 OGLSampler sampler;
326 OGLSampler sampler_default_anisotropy;
318}; 327};
319 328
320class Framebuffer { 329class Framebuffer {
diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h
index 983e1c2e1..71c783709 100644
--- a/src/video_core/renderer_vulkan/pipeline_helper.h
+++ b/src/video_core/renderer_vulkan/pipeline_helper.h
@@ -178,7 +178,7 @@ public:
178inline void PushImageDescriptors(TextureCache& texture_cache, 178inline void PushImageDescriptors(TextureCache& texture_cache,
179 GuestDescriptorQueue& guest_descriptor_queue, 179 GuestDescriptorQueue& guest_descriptor_queue,
180 const Shader::Info& info, RescalingPushConstant& rescaling, 180 const Shader::Info& info, RescalingPushConstant& rescaling,
181 const VkSampler*& samplers, 181 const VideoCommon::SamplerId*& samplers,
182 const VideoCommon::ImageViewInOut*& views) { 182 const VideoCommon::ImageViewInOut*& views) {
183 const u32 num_texture_buffers = Shader::NumDescriptors(info.texture_buffer_descriptors); 183 const u32 num_texture_buffers = Shader::NumDescriptors(info.texture_buffer_descriptors);
184 const u32 num_image_buffers = Shader::NumDescriptors(info.image_buffer_descriptors); 184 const u32 num_image_buffers = Shader::NumDescriptors(info.image_buffer_descriptors);
@@ -187,10 +187,15 @@ inline void PushImageDescriptors(TextureCache& texture_cache,
187 for (const auto& desc : info.texture_descriptors) { 187 for (const auto& desc : info.texture_descriptors) {
188 for (u32 index = 0; index < desc.count; ++index) { 188 for (u32 index = 0; index < desc.count; ++index) {
189 const VideoCommon::ImageViewId image_view_id{(views++)->id}; 189 const VideoCommon::ImageViewId image_view_id{(views++)->id};
190 const VkSampler sampler{*(samplers++)}; 190 const VideoCommon::SamplerId sampler_id{*(samplers++)};
191 ImageView& image_view{texture_cache.GetImageView(image_view_id)}; 191 ImageView& image_view{texture_cache.GetImageView(image_view_id)};
192 const VkImageView vk_image_view{image_view.Handle(desc.type)}; 192 const VkImageView vk_image_view{image_view.Handle(desc.type)};
193 guest_descriptor_queue.AddSampledImage(vk_image_view, sampler); 193 const Sampler& sampler{texture_cache.GetSampler(sampler_id)};
194 const bool use_fallback_sampler{sampler.HasAddedAnisotropy() &&
195 !image_view.SupportsAnisotropy()};
196 const VkSampler vk_sampler{use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy()
197 : sampler.Handle()};
198 guest_descriptor_queue.AddSampledImage(vk_image_view, vk_sampler);
194 rescaling.PushTexture(texture_cache.IsRescaling(image_view)); 199 rescaling.PushTexture(texture_cache.IsRescaling(image_view));
195 } 200 }
196 } 201 }
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 8c33722d3..e30fcb1ed 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -516,15 +516,15 @@ void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bi
516 buffer_handles.push_back(handle); 516 buffer_handles.push_back(handle);
517 } 517 }
518 if (device.IsExtExtendedDynamicStateSupported()) { 518 if (device.IsExtExtendedDynamicStateSupported()) {
519 scheduler.Record([bindings = bindings, 519 scheduler.Record([bindings = std::move(bindings),
520 buffer_handles = buffer_handles](vk::CommandBuffer cmdbuf) { 520 buffer_handles = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) {
521 cmdbuf.BindVertexBuffers2EXT( 521 cmdbuf.BindVertexBuffers2EXT(
522 bindings.min_index, bindings.max_index - bindings.min_index, buffer_handles.data(), 522 bindings.min_index, bindings.max_index - bindings.min_index, buffer_handles.data(),
523 bindings.offsets.data(), bindings.sizes.data(), bindings.strides.data()); 523 bindings.offsets.data(), bindings.sizes.data(), bindings.strides.data());
524 }); 524 });
525 } else { 525 } else {
526 scheduler.Record([bindings = bindings, 526 scheduler.Record([bindings = std::move(bindings),
527 buffer_handles = buffer_handles](vk::CommandBuffer cmdbuf) { 527 buffer_handles = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) {
528 cmdbuf.BindVertexBuffers(bindings.min_index, bindings.max_index - bindings.min_index, 528 cmdbuf.BindVertexBuffers(bindings.min_index, bindings.max_index - bindings.min_index,
529 buffer_handles.data(), bindings.offsets.data()); 529 buffer_handles.data(), bindings.offsets.data());
530 }); 530 });
@@ -561,12 +561,12 @@ void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings<
561 for (u32 index = 0; index < bindings.buffers.size(); ++index) { 561 for (u32 index = 0; index < bindings.buffers.size(); ++index) {
562 buffer_handles.push_back(bindings.buffers[index]->Handle()); 562 buffer_handles.push_back(bindings.buffers[index]->Handle());
563 } 563 }
564 scheduler.Record( 564 scheduler.Record([bindings = std::move(bindings),
565 [bindings = bindings, buffer_handles = buffer_handles](vk::CommandBuffer cmdbuf) { 565 buffer_handles = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) {
566 cmdbuf.BindTransformFeedbackBuffersEXT(0, static_cast<u32>(buffer_handles.size()), 566 cmdbuf.BindTransformFeedbackBuffersEXT(0, static_cast<u32>(buffer_handles.size()),
567 buffer_handles.data(), bindings.offsets.data(), 567 buffer_handles.data(), bindings.offsets.data(),
568 bindings.sizes.data()); 568 bindings.sizes.data());
569 }); 569 });
570} 570}
571 571
572void BufferCacheRuntime::ReserveNullBuffer() { 572void BufferCacheRuntime::ReserveNullBuffer() {
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index 733e70d9d..73e585c2b 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -115,7 +115,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
115 115
116 static constexpr size_t max_elements = 64; 116 static constexpr size_t max_elements = 64;
117 boost::container::static_vector<VideoCommon::ImageViewInOut, max_elements> views; 117 boost::container::static_vector<VideoCommon::ImageViewInOut, max_elements> views;
118 boost::container::static_vector<VkSampler, max_elements> samplers; 118 boost::container::static_vector<VideoCommon::SamplerId, max_elements> samplers;
119 119
120 const auto& qmd{kepler_compute.launch_description}; 120 const auto& qmd{kepler_compute.launch_description};
121 const auto& cbufs{qmd.const_buffer_config}; 121 const auto& cbufs{qmd.const_buffer_config};
@@ -160,8 +160,8 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
160 const auto handle{read_handle(desc, index)}; 160 const auto handle{read_handle(desc, index)};
161 views.push_back({handle.first}); 161 views.push_back({handle.first});
162 162
163 Sampler* const sampler = texture_cache.GetComputeSampler(handle.second); 163 VideoCommon::SamplerId sampler = texture_cache.GetComputeSamplerId(handle.second);
164 samplers.push_back(sampler->Handle()); 164 samplers.push_back(sampler);
165 } 165 }
166 } 166 }
167 for (const auto& desc : info.image_descriptors) { 167 for (const auto& desc : info.image_descriptors) {
@@ -192,7 +192,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
192 buffer_cache.BindHostComputeBuffers(); 192 buffer_cache.BindHostComputeBuffers();
193 193
194 RescalingPushConstant rescaling; 194 RescalingPushConstant rescaling;
195 const VkSampler* samplers_it{samplers.data()}; 195 const VideoCommon::SamplerId* samplers_it{samplers.data()};
196 const VideoCommon::ImageViewInOut* views_it{views.data()}; 196 const VideoCommon::ImageViewInOut* views_it{views.data()};
197 PushImageDescriptors(texture_cache, guest_descriptor_queue, info, rescaling, samplers_it, 197 PushImageDescriptors(texture_cache, guest_descriptor_queue, info, rescaling, samplers_it,
198 views_it); 198 views_it);
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 506b78f08..c1595642e 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -298,7 +298,7 @@ void GraphicsPipeline::AddTransition(GraphicsPipeline* transition) {
298template <typename Spec> 298template <typename Spec>
299void GraphicsPipeline::ConfigureImpl(bool is_indexed) { 299void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
300 std::array<VideoCommon::ImageViewInOut, MAX_IMAGE_ELEMENTS> views; 300 std::array<VideoCommon::ImageViewInOut, MAX_IMAGE_ELEMENTS> views;
301 std::array<VkSampler, MAX_IMAGE_ELEMENTS> samplers; 301 std::array<VideoCommon::SamplerId, MAX_IMAGE_ELEMENTS> samplers;
302 size_t sampler_index{}; 302 size_t sampler_index{};
303 size_t view_index{}; 303 size_t view_index{};
304 304
@@ -367,8 +367,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
367 const auto handle{read_handle(desc, index)}; 367 const auto handle{read_handle(desc, index)};
368 views[view_index++] = {handle.first}; 368 views[view_index++] = {handle.first};
369 369
370 Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.second)}; 370 VideoCommon::SamplerId sampler{texture_cache.GetGraphicsSamplerId(handle.second)};
371 samplers[sampler_index++] = sampler->Handle(); 371 samplers[sampler_index++] = sampler;
372 } 372 }
373 } 373 }
374 if constexpr (Spec::has_images) { 374 if constexpr (Spec::has_images) {
@@ -453,7 +453,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
453 453
454 RescalingPushConstant rescaling; 454 RescalingPushConstant rescaling;
455 RenderAreaPushConstant render_area; 455 RenderAreaPushConstant render_area;
456 const VkSampler* samplers_it{samplers.data()}; 456 const VideoCommon::SamplerId* samplers_it{samplers.data()};
457 const VideoCommon::ImageViewInOut* views_it{views.data()}; 457 const VideoCommon::ImageViewInOut* views_it{views.data()};
458 const auto prepare_stage{[&](size_t stage) LAMBDA_FORCEINLINE { 458 const auto prepare_stage{[&](size_t stage) LAMBDA_FORCEINLINE {
459 buffer_cache.BindHostStageBuffers(stage); 459 buffer_cache.BindHostStageBuffers(stage);
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
index b128c4f6e..5eeda08d2 100644
--- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
@@ -3,6 +3,7 @@
3 3
4#include <thread> 4#include <thread>
5 5
6#include "common/polyfill_ranges.h"
6#include "common/settings.h" 7#include "common/settings.h"
7#include "video_core/renderer_vulkan/vk_master_semaphore.h" 8#include "video_core/renderer_vulkan/vk_master_semaphore.h"
8#include "video_core/vulkan_common/vulkan_device.h" 9#include "video_core/vulkan_common/vulkan_device.h"
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 18e040a1b..a2cfb2105 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -705,10 +705,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
705std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( 705std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
706 ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env, 706 ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env,
707 PipelineStatistics* statistics, bool build_in_parallel) try { 707 PipelineStatistics* statistics, bool build_in_parallel) try {
708 // TODO: Remove this when Intel fixes their shader compiler. 708 if (device.HasBrokenCompute()) {
709 // https://github.com/IGCIT/Intel-GPU-Community-Issue-Tracker-IGCIT/issues/159
710 if (device.GetDriverID() == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS &&
711 !Settings::values.enable_compute_pipelines.GetValue()) {
712 LOG_ERROR(Render_Vulkan, "Skipping 0x{:016x}", key.Hash()); 709 LOG_ERROR(Render_Vulkan, "Skipping 0x{:016x}", key.Hash());
713 return nullptr; 710 return nullptr;
714 } 711 }
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 8711e2a87..f025f618b 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -1802,27 +1802,36 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
1802 // Some games have samplers with garbage. Sanitize them here. 1802 // Some games have samplers with garbage. Sanitize them here.
1803 const f32 max_anisotropy = std::clamp(tsc.MaxAnisotropy(), 1.0f, 16.0f); 1803 const f32 max_anisotropy = std::clamp(tsc.MaxAnisotropy(), 1.0f, 16.0f);
1804 1804
1805 sampler = device.GetLogical().CreateSampler(VkSamplerCreateInfo{ 1805 const auto create_sampler = [&](const f32 anisotropy) {
1806 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, 1806 return device.GetLogical().CreateSampler(VkSamplerCreateInfo{
1807 .pNext = pnext, 1807 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
1808 .flags = 0, 1808 .pNext = pnext,
1809 .magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter), 1809 .flags = 0,
1810 .minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter), 1810 .magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter),
1811 .mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter), 1811 .minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter),
1812 .addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter), 1812 .mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter),
1813 .addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter), 1813 .addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter),
1814 .addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter), 1814 .addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter),
1815 .mipLodBias = tsc.LodBias(), 1815 .addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter),
1816 .anisotropyEnable = static_cast<VkBool32>(max_anisotropy > 1.0f ? VK_TRUE : VK_FALSE), 1816 .mipLodBias = tsc.LodBias(),
1817 .maxAnisotropy = max_anisotropy, 1817 .anisotropyEnable = static_cast<VkBool32>(anisotropy > 1.0f ? VK_TRUE : VK_FALSE),
1818 .compareEnable = tsc.depth_compare_enabled, 1818 .maxAnisotropy = anisotropy,
1819 .compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func), 1819 .compareEnable = tsc.depth_compare_enabled,
1820 .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(), 1820 .compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func),
1821 .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(), 1821 .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(),
1822 .borderColor = 1822 .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(),
1823 arbitrary_borders ? VK_BORDER_COLOR_FLOAT_CUSTOM_EXT : ConvertBorderColor(color), 1823 .borderColor =
1824 .unnormalizedCoordinates = VK_FALSE, 1824 arbitrary_borders ? VK_BORDER_COLOR_FLOAT_CUSTOM_EXT : ConvertBorderColor(color),
1825 }); 1825 .unnormalizedCoordinates = VK_FALSE,
1826 });
1827 };
1828
1829 sampler = create_sampler(max_anisotropy);
1830
1831 const f32 max_anisotropy_default = static_cast<f32>(1U << tsc.max_anisotropy);
1832 if (max_anisotropy > max_anisotropy_default) {
1833 sampler_default_anisotropy = create_sampler(max_anisotropy_default);
1834 }
1826} 1835}
1827 1836
1828Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers, 1837Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers,
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 0f7a5ffd4..f14525dcb 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -279,8 +279,17 @@ public:
279 return *sampler; 279 return *sampler;
280 } 280 }
281 281
282 [[nodiscard]] VkSampler HandleWithDefaultAnisotropy() const noexcept {
283 return *sampler_default_anisotropy;
284 }
285
286 [[nodiscard]] bool HasAddedAnisotropy() const noexcept {
287 return static_cast<bool>(sampler_default_anisotropy);
288 }
289
282private: 290private:
283 vk::Sampler sampler; 291 vk::Sampler sampler;
292 vk::Sampler sampler_default_anisotropy;
284}; 293};
285 294
286class Framebuffer { 295class Framebuffer {
diff --git a/src/video_core/texture_cache/image_view_base.cpp b/src/video_core/texture_cache/image_view_base.cpp
index d134b6738..0c5f4450d 100644
--- a/src/video_core/texture_cache/image_view_base.cpp
+++ b/src/video_core/texture_cache/image_view_base.cpp
@@ -45,4 +45,56 @@ ImageViewBase::ImageViewBase(const ImageInfo& info, const ImageViewInfo& view_in
45 45
46ImageViewBase::ImageViewBase(const NullImageViewParams&) : image_id{NULL_IMAGE_ID} {} 46ImageViewBase::ImageViewBase(const NullImageViewParams&) : image_id{NULL_IMAGE_ID} {}
47 47
48bool ImageViewBase::SupportsAnisotropy() const noexcept {
49 const bool has_mips = range.extent.levels > 1;
50 const bool is_2d = type == ImageViewType::e2D || type == ImageViewType::e2DArray;
51 if (!has_mips || !is_2d) {
52 return false;
53 }
54
55 switch (format) {
56 case PixelFormat::R8_UNORM:
57 case PixelFormat::R8_SNORM:
58 case PixelFormat::R8_SINT:
59 case PixelFormat::R8_UINT:
60 case PixelFormat::BC4_UNORM:
61 case PixelFormat::BC4_SNORM:
62 case PixelFormat::BC5_UNORM:
63 case PixelFormat::BC5_SNORM:
64 case PixelFormat::R32G32_FLOAT:
65 case PixelFormat::R32G32_SINT:
66 case PixelFormat::R32_FLOAT:
67 case PixelFormat::R16_FLOAT:
68 case PixelFormat::R16_UNORM:
69 case PixelFormat::R16_SNORM:
70 case PixelFormat::R16_UINT:
71 case PixelFormat::R16_SINT:
72 case PixelFormat::R16G16_UNORM:
73 case PixelFormat::R16G16_FLOAT:
74 case PixelFormat::R16G16_UINT:
75 case PixelFormat::R16G16_SINT:
76 case PixelFormat::R16G16_SNORM:
77 case PixelFormat::R8G8_UNORM:
78 case PixelFormat::R8G8_SNORM:
79 case PixelFormat::R8G8_SINT:
80 case PixelFormat::R8G8_UINT:
81 case PixelFormat::R32G32_UINT:
82 case PixelFormat::R32_UINT:
83 case PixelFormat::R32_SINT:
84 case PixelFormat::G4R4_UNORM:
85 // Depth formats
86 case PixelFormat::D32_FLOAT:
87 case PixelFormat::D16_UNORM:
88 // Stencil formats
89 case PixelFormat::S8_UINT:
90 // DepthStencil formats
91 case PixelFormat::D24_UNORM_S8_UINT:
92 case PixelFormat::S8_UINT_D24_UNORM:
93 case PixelFormat::D32_FLOAT_S8_UINT:
94 return false;
95 default:
96 return true;
97 }
98}
99
48} // namespace VideoCommon 100} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/image_view_base.h b/src/video_core/texture_cache/image_view_base.h
index a25ae1d4a..87549ffff 100644
--- a/src/video_core/texture_cache/image_view_base.h
+++ b/src/video_core/texture_cache/image_view_base.h
@@ -33,6 +33,8 @@ struct ImageViewBase {
33 return type == ImageViewType::Buffer; 33 return type == ImageViewType::Buffer;
34 } 34 }
35 35
36 [[nodiscard]] bool SupportsAnisotropy() const noexcept;
37
36 ImageId image_id{}; 38 ImageId image_id{};
37 GPUVAddr gpu_addr = 0; 39 GPUVAddr gpu_addr = 0;
38 PixelFormat format{}; 40 PixelFormat format{};
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index f11998e20..d25339c8c 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -222,30 +222,50 @@ void TextureCache<P>::CheckFeedbackLoop(std::span<const ImageViewInOut> views) {
222 222
223template <class P> 223template <class P>
224typename P::Sampler* TextureCache<P>::GetGraphicsSampler(u32 index) { 224typename P::Sampler* TextureCache<P>::GetGraphicsSampler(u32 index) {
225 return &slot_samplers[GetGraphicsSamplerId(index)];
226}
227
228template <class P>
229typename P::Sampler* TextureCache<P>::GetComputeSampler(u32 index) {
230 return &slot_samplers[GetComputeSamplerId(index)];
231}
232
233template <class P>
234SamplerId TextureCache<P>::GetGraphicsSamplerId(u32 index) {
225 if (index > channel_state->graphics_sampler_table.Limit()) { 235 if (index > channel_state->graphics_sampler_table.Limit()) {
226 LOG_DEBUG(HW_GPU, "Invalid sampler index={}", index); 236 LOG_DEBUG(HW_GPU, "Invalid sampler index={}", index);
227 return &slot_samplers[NULL_SAMPLER_ID]; 237 return NULL_SAMPLER_ID;
228 } 238 }
229 const auto [descriptor, is_new] = channel_state->graphics_sampler_table.Read(index); 239 const auto [descriptor, is_new] = channel_state->graphics_sampler_table.Read(index);
230 SamplerId& id = channel_state->graphics_sampler_ids[index]; 240 SamplerId& id = channel_state->graphics_sampler_ids[index];
231 if (is_new) { 241 if (is_new) {
232 id = FindSampler(descriptor); 242 id = FindSampler(descriptor);
233 } 243 }
234 return &slot_samplers[id]; 244 return id;
235} 245}
236 246
237template <class P> 247template <class P>
238typename P::Sampler* TextureCache<P>::GetComputeSampler(u32 index) { 248SamplerId TextureCache<P>::GetComputeSamplerId(u32 index) {
239 if (index > channel_state->compute_sampler_table.Limit()) { 249 if (index > channel_state->compute_sampler_table.Limit()) {
240 LOG_DEBUG(HW_GPU, "Invalid sampler index={}", index); 250 LOG_DEBUG(HW_GPU, "Invalid sampler index={}", index);
241 return &slot_samplers[NULL_SAMPLER_ID]; 251 return NULL_SAMPLER_ID;
242 } 252 }
243 const auto [descriptor, is_new] = channel_state->compute_sampler_table.Read(index); 253 const auto [descriptor, is_new] = channel_state->compute_sampler_table.Read(index);
244 SamplerId& id = channel_state->compute_sampler_ids[index]; 254 SamplerId& id = channel_state->compute_sampler_ids[index];
245 if (is_new) { 255 if (is_new) {
246 id = FindSampler(descriptor); 256 id = FindSampler(descriptor);
247 } 257 }
248 return &slot_samplers[id]; 258 return id;
259}
260
261template <class P>
262const typename P::Sampler& TextureCache<P>::GetSampler(SamplerId id) const noexcept {
263 return slot_samplers[id];
264}
265
266template <class P>
267typename P::Sampler& TextureCache<P>::GetSampler(SamplerId id) noexcept {
268 return slot_samplers[id];
249} 269}
250 270
251template <class P> 271template <class P>
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h
index c347eccd6..44232b961 100644
--- a/src/video_core/texture_cache/texture_cache_base.h
+++ b/src/video_core/texture_cache/texture_cache_base.h
@@ -159,6 +159,18 @@ public:
159 /// Get the sampler from the compute descriptor table in the specified index 159 /// Get the sampler from the compute descriptor table in the specified index
160 Sampler* GetComputeSampler(u32 index); 160 Sampler* GetComputeSampler(u32 index);
161 161
162 /// Get the sampler id from the graphics descriptor table in the specified index
163 SamplerId GetGraphicsSamplerId(u32 index);
164
165 /// Get the sampler id from the compute descriptor table in the specified index
166 SamplerId GetComputeSamplerId(u32 index);
167
168 /// Return a constant reference to the given sampler id
169 [[nodiscard]] const Sampler& GetSampler(SamplerId id) const noexcept;
170
171 /// Return a reference to the given sampler id
172 [[nodiscard]] Sampler& GetSampler(SamplerId id) noexcept;
173
162 /// Refresh the state for graphics image view and sampler descriptors 174 /// Refresh the state for graphics image view and sampler descriptors
163 void SynchronizeGraphicsDescriptors(); 175 void SynchronizeGraphicsDescriptors();
164 176
diff --git a/src/video_core/textures/texture.cpp b/src/video_core/textures/texture.cpp
index 4a80a59f9..d8b88d9bc 100644
--- a/src/video_core/textures/texture.cpp
+++ b/src/video_core/textures/texture.cpp
@@ -62,7 +62,12 @@ std::array<float, 4> TSCEntry::BorderColor() const noexcept {
62} 62}
63 63
64float TSCEntry::MaxAnisotropy() const noexcept { 64float TSCEntry::MaxAnisotropy() const noexcept {
65 if (max_anisotropy == 0 && mipmap_filter != TextureMipmapFilter::Linear) { 65 const bool is_suitable_mipmap_filter = mipmap_filter != TextureMipmapFilter::None;
66 const bool has_regular_lods = min_lod_clamp == 0 && max_lod_clamp >= 256;
67 const bool is_bilinear_filter = min_filter == TextureFilter::Linear &&
68 reduction_filter == SamplerReduction::WeightedAverage;
69 if (max_anisotropy == 0 && (!is_suitable_mipmap_filter || !has_regular_lods ||
70 !is_bilinear_filter || depth_compare_enabled)) {
66 return 1.0f; 71 return 1.0f;
67 } 72 }
68 const auto anisotropic_settings = Settings::values.max_anisotropy.GetValue(); 73 const auto anisotropic_settings = Settings::values.max_anisotropy.GetValue();
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 3d2e9a16a..fa9cde75b 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -562,6 +562,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
562 LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits"); 562 LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits");
563 cant_blit_msaa = true; 563 cant_blit_msaa = true;
564 } 564 }
565 has_broken_compute =
566 CheckBrokenCompute(properties.driver.driverID, properties.properties.driverVersion) &&
567 !Settings::values.enable_compute_pipelines.GetValue();
565 if (is_intel_anv || (is_qualcomm && !is_s8gen2)) { 568 if (is_intel_anv || (is_qualcomm && !is_s8gen2)) {
566 LOG_WARNING(Render_Vulkan, "Driver does not support native BGR format"); 569 LOG_WARNING(Render_Vulkan, "Driver does not support native BGR format");
567 must_emulate_bgr565 = true; 570 must_emulate_bgr565 = true;
@@ -783,9 +786,6 @@ bool Device::GetSuitability(bool requires_swapchain) {
783 786
784 FOR_EACH_VK_FEATURE_EXT(FEATURE_EXTENSION); 787 FOR_EACH_VK_FEATURE_EXT(FEATURE_EXTENSION);
785 FOR_EACH_VK_EXTENSION(EXTENSION); 788 FOR_EACH_VK_EXTENSION(EXTENSION);
786#ifdef _WIN32
787 FOR_EACH_VK_EXTENSION_WIN32(EXTENSION);
788#endif
789 789
790#undef FEATURE_EXTENSION 790#undef FEATURE_EXTENSION
791#undef EXTENSION 791#undef EXTENSION
@@ -804,11 +804,6 @@ bool Device::GetSuitability(bool requires_swapchain) {
804 804
805 FOR_EACH_VK_RECOMMENDED_EXTENSION(LOG_EXTENSION); 805 FOR_EACH_VK_RECOMMENDED_EXTENSION(LOG_EXTENSION);
806 FOR_EACH_VK_MANDATORY_EXTENSION(CHECK_EXTENSION); 806 FOR_EACH_VK_MANDATORY_EXTENSION(CHECK_EXTENSION);
807#ifdef _WIN32
808 FOR_EACH_VK_MANDATORY_EXTENSION_WIN32(CHECK_EXTENSION);
809#else
810 FOR_EACH_VK_MANDATORY_EXTENSION_GENERIC(CHECK_EXTENSION);
811#endif
812 807
813 if (requires_swapchain) { 808 if (requires_swapchain) {
814 CHECK_EXTENSION(VK_KHR_SWAPCHAIN_EXTENSION_NAME); 809 CHECK_EXTENSION(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index f314d0ffe..0b634a876 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -10,6 +10,7 @@
10#include <vector> 10#include <vector>
11 11
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/logging/log.h"
13#include "common/settings.h" 14#include "common/settings.h"
14#include "video_core/vulkan_common/vulkan_wrapper.h" 15#include "video_core/vulkan_common/vulkan_wrapper.h"
15 16
@@ -68,7 +69,6 @@
68 EXTENSION(EXT, VERTEX_ATTRIBUTE_DIVISOR, vertex_attribute_divisor) \ 69 EXTENSION(EXT, VERTEX_ATTRIBUTE_DIVISOR, vertex_attribute_divisor) \
69 EXTENSION(KHR, DRAW_INDIRECT_COUNT, draw_indirect_count) \ 70 EXTENSION(KHR, DRAW_INDIRECT_COUNT, draw_indirect_count) \
70 EXTENSION(KHR, DRIVER_PROPERTIES, driver_properties) \ 71 EXTENSION(KHR, DRIVER_PROPERTIES, driver_properties) \
71 EXTENSION(KHR, EXTERNAL_MEMORY_FD, external_memory_fd) \
72 EXTENSION(KHR, PUSH_DESCRIPTOR, push_descriptor) \ 72 EXTENSION(KHR, PUSH_DESCRIPTOR, push_descriptor) \
73 EXTENSION(KHR, SAMPLER_MIRROR_CLAMP_TO_EDGE, sampler_mirror_clamp_to_edge) \ 73 EXTENSION(KHR, SAMPLER_MIRROR_CLAMP_TO_EDGE, sampler_mirror_clamp_to_edge) \
74 EXTENSION(KHR, SHADER_FLOAT_CONTROLS, shader_float_controls) \ 74 EXTENSION(KHR, SHADER_FLOAT_CONTROLS, shader_float_controls) \
@@ -80,9 +80,6 @@
80 EXTENSION(NV, VIEWPORT_ARRAY2, viewport_array2) \ 80 EXTENSION(NV, VIEWPORT_ARRAY2, viewport_array2) \
81 EXTENSION(NV, VIEWPORT_SWIZZLE, viewport_swizzle) 81 EXTENSION(NV, VIEWPORT_SWIZZLE, viewport_swizzle)
82 82
83#define FOR_EACH_VK_EXTENSION_WIN32(EXTENSION) \
84 EXTENSION(KHR, EXTERNAL_MEMORY_WIN32, external_memory_win32)
85
86// Define extensions which must be supported. 83// Define extensions which must be supported.
87#define FOR_EACH_VK_MANDATORY_EXTENSION(EXTENSION_NAME) \ 84#define FOR_EACH_VK_MANDATORY_EXTENSION(EXTENSION_NAME) \
88 EXTENSION_NAME(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME) \ 85 EXTENSION_NAME(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME) \
@@ -90,12 +87,6 @@
90 EXTENSION_NAME(VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME) \ 87 EXTENSION_NAME(VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME) \
91 EXTENSION_NAME(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME) 88 EXTENSION_NAME(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME)
92 89
93#define FOR_EACH_VK_MANDATORY_EXTENSION_GENERIC(EXTENSION_NAME) \
94 EXTENSION_NAME(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME)
95
96#define FOR_EACH_VK_MANDATORY_EXTENSION_WIN32(EXTENSION_NAME) \
97 EXTENSION_NAME(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME)
98
99// Define extensions where the absence of the extension may result in a degraded experience. 90// Define extensions where the absence of the extension may result in a degraded experience.
100#define FOR_EACH_VK_RECOMMENDED_EXTENSION(EXTENSION_NAME) \ 91#define FOR_EACH_VK_RECOMMENDED_EXTENSION(EXTENSION_NAME) \
101 EXTENSION_NAME(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME) \ 92 EXTENSION_NAME(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME) \
@@ -528,6 +519,11 @@ public:
528 return has_renderdoc || has_nsight_graphics || Settings::values.renderer_debug.GetValue(); 519 return has_renderdoc || has_nsight_graphics || Settings::values.renderer_debug.GetValue();
529 } 520 }
530 521
522 /// @returns True if compute pipelines can cause crashing.
523 bool HasBrokenCompute() const {
524 return has_broken_compute;
525 }
526
531 /// Returns true when the device does not properly support cube compatibility. 527 /// Returns true when the device does not properly support cube compatibility.
532 bool HasBrokenCubeImageCompability() const { 528 bool HasBrokenCubeImageCompability() const {
533 return has_broken_cube_compatibility; 529 return has_broken_cube_compatibility;
@@ -589,6 +585,22 @@ public:
589 return supports_conditional_barriers; 585 return supports_conditional_barriers;
590 } 586 }
591 587
588 [[nodiscard]] static constexpr bool CheckBrokenCompute(VkDriverId driver_id,
589 u32 driver_version) {
590 if (driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) {
591 const u32 major = VK_API_VERSION_MAJOR(driver_version);
592 const u32 minor = VK_API_VERSION_MINOR(driver_version);
593 const u32 patch = VK_API_VERSION_PATCH(driver_version);
594 if (major == 0 && minor == 405 && patch < 286) {
595 LOG_WARNING(
596 Render_Vulkan,
597 "Intel proprietary drivers 0.405.0 until 0.405.286 have broken compute");
598 return true;
599 }
600 }
601 return false;
602 }
603
592private: 604private:
593 /// Checks if the physical device is suitable and configures the object state 605 /// Checks if the physical device is suitable and configures the object state
594 /// with all necessary info about its properties. 606 /// with all necessary info about its properties.
@@ -636,7 +648,6 @@ private:
636 FOR_EACH_VK_FEATURE_1_3(FEATURE); 648 FOR_EACH_VK_FEATURE_1_3(FEATURE);
637 FOR_EACH_VK_FEATURE_EXT(FEATURE); 649 FOR_EACH_VK_FEATURE_EXT(FEATURE);
638 FOR_EACH_VK_EXTENSION(EXTENSION); 650 FOR_EACH_VK_EXTENSION(EXTENSION);
639 FOR_EACH_VK_EXTENSION_WIN32(EXTENSION);
640 651
641#undef EXTENSION 652#undef EXTENSION
642#undef FEATURE 653#undef FEATURE
@@ -683,6 +694,7 @@ private:
683 bool is_integrated{}; ///< Is GPU an iGPU. 694 bool is_integrated{}; ///< Is GPU an iGPU.
684 bool is_virtual{}; ///< Is GPU a virtual GPU. 695 bool is_virtual{}; ///< Is GPU a virtual GPU.
685 bool is_non_gpu{}; ///< Is SoftwareRasterizer, FPGA, non-GPU device. 696 bool is_non_gpu{}; ///< Is SoftwareRasterizer, FPGA, non-GPU device.
697 bool has_broken_compute{}; ///< Compute shaders can cause crashes
686 bool has_broken_cube_compatibility{}; ///< Has broken cube compatibility bit 698 bool has_broken_cube_compatibility{}; ///< Has broken cube compatibility bit
687 bool has_renderdoc{}; ///< Has RenderDoc attached 699 bool has_renderdoc{}; ///< Has RenderDoc attached
688 bool has_nsight_graphics{}; ///< Has Nsight Graphics attached 700 bool has_nsight_graphics{}; ///< Has Nsight Graphics attached
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 84d9ca796..733c296e4 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -210,6 +210,8 @@ add_executable(yuzu
210 util/url_request_interceptor.h 210 util/url_request_interceptor.h
211 util/util.cpp 211 util/util.cpp
212 util/util.h 212 util/util.h
213 vk_device_info.cpp
214 vk_device_info.h
213 compatdb.cpp 215 compatdb.cpp
214 compatdb.h 216 compatdb.h
215 yuzu.qrc 217 yuzu.qrc
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index 8e76a819a..bdf83ebfe 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -6,6 +6,7 @@
6#include "common/settings.h" 6#include "common/settings.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "ui_configure.h" 8#include "ui_configure.h"
9#include "vk_device_info.h"
9#include "yuzu/configuration/config.h" 10#include "yuzu/configuration/config.h"
10#include "yuzu/configuration/configure_audio.h" 11#include "yuzu/configuration/configure_audio.h"
11#include "yuzu/configuration/configure_cpu.h" 12#include "yuzu/configuration/configure_cpu.h"
@@ -28,6 +29,7 @@
28 29
29ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, 30ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
30 InputCommon::InputSubsystem* input_subsystem, 31 InputCommon::InputSubsystem* input_subsystem,
32 std::vector<VkDeviceInfo::Record>& vk_device_records,
31 Core::System& system_, bool enable_web_config) 33 Core::System& system_, bool enable_web_config)
32 : QDialog(parent), ui{std::make_unique<Ui::ConfigureDialog>()}, 34 : QDialog(parent), ui{std::make_unique<Ui::ConfigureDialog>()},
33 registry(registry_), system{system_}, audio_tab{std::make_unique<ConfigureAudio>(system_, 35 registry(registry_), system{system_}, audio_tab{std::make_unique<ConfigureAudio>(system_,
@@ -38,7 +40,8 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
38 general_tab{std::make_unique<ConfigureGeneral>(system_, this)}, 40 general_tab{std::make_unique<ConfigureGeneral>(system_, this)},
39 graphics_advanced_tab{std::make_unique<ConfigureGraphicsAdvanced>(system_, this)}, 41 graphics_advanced_tab{std::make_unique<ConfigureGraphicsAdvanced>(system_, this)},
40 graphics_tab{std::make_unique<ConfigureGraphics>( 42 graphics_tab{std::make_unique<ConfigureGraphics>(
41 system_, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, this)}, 43 system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); },
44 this)},
42 hotkeys_tab{std::make_unique<ConfigureHotkeys>(system_.HIDCore(), this)}, 45 hotkeys_tab{std::make_unique<ConfigureHotkeys>(system_.HIDCore(), this)},
43 input_tab{std::make_unique<ConfigureInput>(system_, this)}, 46 input_tab{std::make_unique<ConfigureInput>(system_, this)},
44 network_tab{std::make_unique<ConfigureNetwork>(system_, this)}, 47 network_tab{std::make_unique<ConfigureNetwork>(system_, this)},
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index a086a07c4..2a08b7fee 100644
--- a/src/yuzu/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
@@ -4,7 +4,9 @@
4#pragma once 4#pragma once
5 5
6#include <memory> 6#include <memory>
7#include <vector>
7#include <QDialog> 8#include <QDialog>
9#include "yuzu/vk_device_info.h"
8 10
9namespace Core { 11namespace Core {
10class System; 12class System;
@@ -40,8 +42,9 @@ class ConfigureDialog : public QDialog {
40 42
41public: 43public:
42 explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, 44 explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
43 InputCommon::InputSubsystem* input_subsystem, Core::System& system_, 45 InputCommon::InputSubsystem* input_subsystem,
44 bool enable_web_config = true); 46 std::vector<VkDeviceInfo::Record>& vk_device_records,
47 Core::System& system_, bool enable_web_config = true);
45 ~ConfigureDialog() override; 48 ~ConfigureDialog() override;
46 49
47 void ApplyConfiguration(); 50 void ApplyConfiguration();
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index 431585216..a4965524a 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -1,10 +1,6 @@
1// SPDX-FileCopyrightText: 2016 Citra Emulator Project 1// SPDX-FileCopyrightText: 2016 Citra Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4// Include this early to include Vulkan headers how we want to
5#include "video_core/vulkan_common/vulkan_device.h"
6#include "video_core/vulkan_common/vulkan_wrapper.h"
7
8#include <algorithm> 4#include <algorithm>
9#include <functional> 5#include <functional>
10#include <iosfwd> 6#include <iosfwd>
@@ -34,13 +30,11 @@
34#include "common/settings.h" 30#include "common/settings.h"
35#include "core/core.h" 31#include "core/core.h"
36#include "ui_configure_graphics.h" 32#include "ui_configure_graphics.h"
37#include "video_core/vulkan_common/vulkan_instance.h"
38#include "video_core/vulkan_common/vulkan_library.h"
39#include "video_core/vulkan_common/vulkan_surface.h"
40#include "yuzu/configuration/configuration_shared.h" 33#include "yuzu/configuration/configuration_shared.h"
41#include "yuzu/configuration/configure_graphics.h" 34#include "yuzu/configuration/configure_graphics.h"
42#include "yuzu/qt_common.h" 35#include "yuzu/qt_common.h"
43#include "yuzu/uisettings.h" 36#include "yuzu/uisettings.h"
37#include "yuzu/vk_device_info.h"
44 38
45static const std::vector<VkPresentModeKHR> default_present_modes{VK_PRESENT_MODE_IMMEDIATE_KHR, 39static const std::vector<VkPresentModeKHR> default_present_modes{VK_PRESENT_MODE_IMMEDIATE_KHR,
46 VK_PRESENT_MODE_FIFO_KHR}; 40 VK_PRESENT_MODE_FIFO_KHR};
@@ -77,9 +71,10 @@ static constexpr Settings::VSyncMode PresentModeToSetting(VkPresentModeKHR mode)
77} 71}
78 72
79ConfigureGraphics::ConfigureGraphics(const Core::System& system_, 73ConfigureGraphics::ConfigureGraphics(const Core::System& system_,
74 std::vector<VkDeviceInfo::Record>& records_,
80 const std::function<void()>& expose_compute_option_, 75 const std::function<void()>& expose_compute_option_,
81 QWidget* parent) 76 QWidget* parent)
82 : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, 77 : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, records{records_},
83 expose_compute_option{expose_compute_option_}, system{system_} { 78 expose_compute_option{expose_compute_option_}, system{system_} {
84 vulkan_device = Settings::values.vulkan_device.GetValue(); 79 vulkan_device = Settings::values.vulkan_device.GetValue();
85 RetrieveVulkanDevices(); 80 RetrieveVulkanDevices();
@@ -504,47 +499,19 @@ void ConfigureGraphics::UpdateAPILayout() {
504 } 499 }
505} 500}
506 501
507void ConfigureGraphics::RetrieveVulkanDevices() try { 502void ConfigureGraphics::RetrieveVulkanDevices() {
508 if (UISettings::values.has_broken_vulkan) {
509 return;
510 }
511
512 using namespace Vulkan;
513
514 auto* window = this->window()->windowHandle();
515 auto wsi = QtCommon::GetWindowSystemInfo(window);
516
517 vk::InstanceDispatch dld;
518 const auto library = OpenLibrary();
519 const vk::Instance instance = CreateInstance(*library, dld, VK_API_VERSION_1_1, wsi.type);
520 const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
521 vk::SurfaceKHR surface = CreateSurface(instance, wsi);
522
523 vulkan_devices.clear(); 503 vulkan_devices.clear();
524 vulkan_devices.reserve(physical_devices.size()); 504 vulkan_devices.reserve(records.size());
525 device_present_modes.clear(); 505 device_present_modes.clear();
526 device_present_modes.reserve(physical_devices.size()); 506 device_present_modes.reserve(records.size());
527 for (const VkPhysicalDevice device : physical_devices) { 507 for (const auto& record : records) {
528 const auto physical_device = vk::PhysicalDevice(device, dld); 508 vulkan_devices.push_back(QString::fromStdString(record.name));
529 const std::string name = physical_device.GetProperties().deviceName; 509 device_present_modes.push_back(record.vsync_support);
530 const std::vector<VkPresentModeKHR> present_modes = 510
531 physical_device.GetSurfacePresentModesKHR(*surface); 511 if (record.has_broken_compute) {
532 vulkan_devices.push_back(QString::fromStdString(name));
533 device_present_modes.push_back(present_modes);
534
535 VkPhysicalDeviceDriverProperties driver_properties{};
536 driver_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
537 driver_properties.pNext = nullptr;
538 VkPhysicalDeviceProperties2 properties{};
539 properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
540 properties.pNext = &driver_properties;
541 dld.vkGetPhysicalDeviceProperties2(physical_device, &properties);
542 if (driver_properties.driverID == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) {
543 expose_compute_option(); 512 expose_compute_option();
544 } 513 }
545 } 514 }
546} catch (const Vulkan::vk::Exception& exception) {
547 LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what());
548} 515}
549 516
550Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const { 517Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const {
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 364b1cac2..be9310b74 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -12,6 +12,7 @@
12#include <qobjectdefs.h> 12#include <qobjectdefs.h>
13#include <vulkan/vulkan_core.h> 13#include <vulkan/vulkan_core.h>
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "vk_device_info.h"
15 16
16class QEvent; 17class QEvent;
17class QObject; 18class QObject;
@@ -39,6 +40,7 @@ class ConfigureGraphics : public QWidget {
39 40
40public: 41public:
41 explicit ConfigureGraphics(const Core::System& system_, 42 explicit ConfigureGraphics(const Core::System& system_,
43 std::vector<VkDeviceInfo::Record>& records,
42 const std::function<void()>& expose_compute_option_, 44 const std::function<void()>& expose_compute_option_,
43 QWidget* parent = nullptr); 45 QWidget* parent = nullptr);
44 ~ConfigureGraphics() override; 46 ~ConfigureGraphics() override;
@@ -77,6 +79,7 @@ private:
77 ConfigurationShared::CheckState use_disk_shader_cache; 79 ConfigurationShared::CheckState use_disk_shader_cache;
78 ConfigurationShared::CheckState use_asynchronous_gpu_emulation; 80 ConfigurationShared::CheckState use_asynchronous_gpu_emulation;
79 81
82 std::vector<VkDeviceInfo::Record>& records;
80 std::vector<QString> vulkan_devices; 83 std::vector<QString> vulkan_devices;
81 std::vector<std::vector<VkPresentModeKHR>> device_present_modes; 84 std::vector<std::vector<VkPresentModeKHR>> device_present_modes;
82 std::vector<VkPresentModeKHR> 85 std::vector<VkPresentModeKHR>
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
index 7ac162586..eb96e6068 100644
--- a/src/yuzu/configuration/configure_per_game.cpp
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -6,6 +6,7 @@
6#include <memory> 6#include <memory>
7#include <string> 7#include <string>
8#include <utility> 8#include <utility>
9#include <vector>
9 10
10#include <fmt/format.h> 11#include <fmt/format.h>
11 12
@@ -34,8 +35,10 @@
34#include "yuzu/configuration/configure_system.h" 35#include "yuzu/configuration/configure_system.h"
35#include "yuzu/uisettings.h" 36#include "yuzu/uisettings.h"
36#include "yuzu/util/util.h" 37#include "yuzu/util/util.h"
38#include "yuzu/vk_device_info.h"
37 39
38ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::string& file_name, 40ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::string& file_name,
41 std::vector<VkDeviceInfo::Record>& vk_device_records,
39 Core::System& system_) 42 Core::System& system_)
40 : QDialog(parent), 43 : QDialog(parent),
41 ui(std::make_unique<Ui::ConfigurePerGame>()), title_id{title_id_}, system{system_} { 44 ui(std::make_unique<Ui::ConfigurePerGame>()), title_id{title_id_}, system{system_} {
@@ -50,7 +53,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
50 general_tab = std::make_unique<ConfigureGeneral>(system_, this); 53 general_tab = std::make_unique<ConfigureGeneral>(system_, this);
51 graphics_advanced_tab = std::make_unique<ConfigureGraphicsAdvanced>(system_, this); 54 graphics_advanced_tab = std::make_unique<ConfigureGraphicsAdvanced>(system_, this);
52 graphics_tab = std::make_unique<ConfigureGraphics>( 55 graphics_tab = std::make_unique<ConfigureGraphics>(
53 system_, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, this); 56 system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, this);
54 input_tab = std::make_unique<ConfigureInputPerGame>(system_, game_config.get(), this); 57 input_tab = std::make_unique<ConfigureInputPerGame>(system_, game_config.get(), this);
55 system_tab = std::make_unique<ConfigureSystem>(system_, this); 58 system_tab = std::make_unique<ConfigureSystem>(system_, this);
56 59
diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h
index 85752f1fa..7ec1ded06 100644
--- a/src/yuzu/configuration/configure_per_game.h
+++ b/src/yuzu/configuration/configure_per_game.h
@@ -5,11 +5,13 @@
5 5
6#include <memory> 6#include <memory>
7#include <string> 7#include <string>
8#include <vector>
8 9
9#include <QDialog> 10#include <QDialog>
10#include <QList> 11#include <QList>
11 12
12#include "core/file_sys/vfs_types.h" 13#include "core/file_sys/vfs_types.h"
14#include "vk_device_info.h"
13#include "yuzu/configuration/config.h" 15#include "yuzu/configuration/config.h"
14 16
15namespace Core { 17namespace Core {
@@ -45,6 +47,7 @@ class ConfigurePerGame : public QDialog {
45public: 47public:
46 // Cannot use std::filesystem::path due to https://bugreports.qt.io/browse/QTBUG-73263 48 // Cannot use std::filesystem::path due to https://bugreports.qt.io/browse/QTBUG-73263
47 explicit ConfigurePerGame(QWidget* parent, u64 title_id_, const std::string& file_name, 49 explicit ConfigurePerGame(QWidget* parent, u64 title_id_, const std::string& file_name,
50 std::vector<VkDeviceInfo::Record>& vk_device_records,
48 Core::System& system_); 51 Core::System& system_);
49 ~ConfigurePerGame() override; 52 ~ConfigurePerGame() override;
50 53
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 013715b44..8768a7c3c 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -147,6 +147,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
147#include "yuzu/startup_checks.h" 147#include "yuzu/startup_checks.h"
148#include "yuzu/uisettings.h" 148#include "yuzu/uisettings.h"
149#include "yuzu/util/clickable_label.h" 149#include "yuzu/util/clickable_label.h"
150#include "yuzu/vk_device_info.h"
150 151
151#ifdef YUZU_DBGHELP 152#ifdef YUZU_DBGHELP
152#include "yuzu/mini_dump.h" 153#include "yuzu/mini_dump.h"
@@ -440,6 +441,8 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan
440 441
441 renderer_status_button->setDisabled(true); 442 renderer_status_button->setDisabled(true);
442 renderer_status_button->setChecked(false); 443 renderer_status_button->setChecked(false);
444 } else {
445 VkDeviceInfo::PopulateRecords(vk_device_records, this->window()->windowHandle());
443 } 446 }
444 447
445#if defined(HAVE_SDL2) && !defined(_WIN32) 448#if defined(HAVE_SDL2) && !defined(_WIN32)
@@ -3494,7 +3497,8 @@ void GMainWindow::OnConfigure() {
3494 const auto old_language_index = Settings::values.language_index.GetValue(); 3497 const auto old_language_index = Settings::values.language_index.GetValue();
3495 3498
3496 Settings::SetConfiguringGlobal(true); 3499 Settings::SetConfiguringGlobal(true);
3497 ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), *system, 3500 ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(),
3501 vk_device_records, *system,
3498 !multiplayer_state->IsHostingPublicRoom()); 3502 !multiplayer_state->IsHostingPublicRoom());
3499 connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this, 3503 connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this,
3500 &GMainWindow::OnLanguageChanged); 3504 &GMainWindow::OnLanguageChanged);
@@ -3765,7 +3769,7 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file
3765 const auto v_file = Core::GetGameFileFromPath(vfs, file_name); 3769 const auto v_file = Core::GetGameFileFromPath(vfs, file_name);
3766 3770
3767 Settings::SetConfiguringGlobal(false); 3771 Settings::SetConfiguringGlobal(false);
3768 ConfigurePerGame dialog(this, title_id, file_name, *system); 3772 ConfigurePerGame dialog(this, title_id, file_name, vk_device_records, *system);
3769 dialog.LoadFromFile(v_file); 3773 dialog.LoadFromFile(v_file);
3770 const auto result = dialog.exec(); 3774 const auto result = dialog.exec();
3771 3775
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 6bb70972f..e0e775d87 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -118,6 +118,10 @@ enum class ReinitializeKeyBehavior {
118 Warning, 118 Warning,
119}; 119};
120 120
121namespace VkDeviceInfo {
122class Record;
123}
124
121class GMainWindow : public QMainWindow { 125class GMainWindow : public QMainWindow {
122 Q_OBJECT 126 Q_OBJECT
123 127
@@ -418,6 +422,8 @@ private:
418 422
419 GameListPlaceholder* game_list_placeholder; 423 GameListPlaceholder* game_list_placeholder;
420 424
425 std::vector<VkDeviceInfo::Record> vk_device_records;
426
421 // Status bar elements 427 // Status bar elements
422 QLabel* message_label = nullptr; 428 QLabel* message_label = nullptr;
423 QLabel* shader_building_label = nullptr; 429 QLabel* shader_building_label = nullptr;
diff --git a/src/yuzu/vk_device_info.cpp b/src/yuzu/vk_device_info.cpp
new file mode 100644
index 000000000..7c26a3dc7
--- /dev/null
+++ b/src/yuzu/vk_device_info.cpp
@@ -0,0 +1,61 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <utility>
5#include <vector>
6#include "common/dynamic_library.h"
7#include "common/logging/log.h"
8#include "video_core/vulkan_common/vulkan_device.h"
9#include "video_core/vulkan_common/vulkan_instance.h"
10#include "video_core/vulkan_common/vulkan_library.h"
11#include "video_core/vulkan_common/vulkan_surface.h"
12#include "video_core/vulkan_common/vulkan_wrapper.h"
13#include "vulkan/vulkan_core.h"
14#include "yuzu/qt_common.h"
15#include "yuzu/vk_device_info.h"
16
17class QWindow;
18
19namespace VkDeviceInfo {
20Record::Record(std::string_view name_, const std::vector<VkPresentModeKHR>& vsync_modes_,
21 bool has_broken_compute_)
22 : name{name_}, vsync_support{vsync_modes_}, has_broken_compute{has_broken_compute_} {}
23
24Record::~Record() = default;
25
26void PopulateRecords(std::vector<Record>& records, QWindow* window) try {
27 using namespace Vulkan;
28
29 auto wsi = QtCommon::GetWindowSystemInfo(window);
30
31 vk::InstanceDispatch dld;
32 const auto library = OpenLibrary();
33 const vk::Instance instance = CreateInstance(*library, dld, VK_API_VERSION_1_1, wsi.type);
34 const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
35 vk::SurfaceKHR surface = CreateSurface(instance, wsi);
36
37 records.clear();
38 records.reserve(physical_devices.size());
39 for (const VkPhysicalDevice device : physical_devices) {
40 const auto physical_device = vk::PhysicalDevice(device, dld);
41 const std::string name = physical_device.GetProperties().deviceName;
42 const std::vector<VkPresentModeKHR> present_modes =
43 physical_device.GetSurfacePresentModesKHR(*surface);
44
45 VkPhysicalDeviceDriverProperties driver_properties{};
46 driver_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
47 driver_properties.pNext = nullptr;
48 VkPhysicalDeviceProperties2 properties{};
49 properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
50 properties.pNext = &driver_properties;
51 dld.vkGetPhysicalDeviceProperties2(physical_device, &properties);
52
53 bool has_broken_compute{Vulkan::Device::CheckBrokenCompute(
54 driver_properties.driverID, properties.properties.driverVersion)};
55
56 records.push_back(VkDeviceInfo::Record(name, present_modes, has_broken_compute));
57 }
58} catch (const Vulkan::vk::Exception& exception) {
59 LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what());
60}
61} // namespace VkDeviceInfo
diff --git a/src/yuzu/vk_device_info.h b/src/yuzu/vk_device_info.h
new file mode 100644
index 000000000..bda8262f4
--- /dev/null
+++ b/src/yuzu/vk_device_info.h
@@ -0,0 +1,36 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <algorithm>
7#include <iterator>
8#include <memory>
9#include <string>
10#include <string_view>
11#include <vector>
12#include "common/common_types.h"
13#include "vulkan/vulkan_core.h"
14
15class QWindow;
16
17namespace Settings {
18enum class VSyncMode : u32;
19}
20// #include "common/settings.h"
21
22namespace VkDeviceInfo {
23// Short class to record Vulkan driver information for configuration purposes
24class Record {
25public:
26 explicit Record(std::string_view name, const std::vector<VkPresentModeKHR>& vsync_modes,
27 bool has_broken_compute);
28 ~Record();
29
30 const std::string name;
31 const std::vector<VkPresentModeKHR> vsync_support;
32 const bool has_broken_compute;
33};
34
35void PopulateRecords(std::vector<Record>& records, QWindow* window);
36} // namespace VkDeviceInfo
diff --git a/vcpkg.json b/vcpkg.json
index 2fa2c80be..7d9e631a1 100644
--- a/vcpkg.json
+++ b/vcpkg.json
@@ -1,7 +1,7 @@
1{ 1{
2 "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json", 2 "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
3 "name": "yuzu", 3 "name": "yuzu",
4 "builtin-baseline": "a487471068f4cb1cbb4eeb340763cdcc0a75fd68", 4 "builtin-baseline": "cbf56573a987527b39272e88cbdd11389b78c6e4",
5 "version": "1.0", 5 "version": "1.0",
6 "dependencies": [ 6 "dependencies": [
7 "boost-algorithm", 7 "boost-algorithm",