Compare commits

..

46 Commits

Author SHA1 Message Date
ameerj
12c0f682e6 hle_ipc: Reserve vectors before populating 2022-12-15 22:30:42 -05:00
Narr the Reg
9ff891ce71 Merge pull request #9431 from liamwhite/sixty-five-oh-two
vulkan_common: declare storageBuffer8BitAccess
2022-12-15 17:52:16 -06:00
Matías Locatti
82d80869fc Merge pull request #9430 from liamwhite/capable
spirv_emit_context: declare GroupNonUniform capability for SubgroupLocalInvocationId
2022-12-15 20:52:05 -03:00
liamwhite
b8c03411e7 Merge pull request #9433 from Tachi107/cmake-is-awful
build: tweak the find modules even more
2022-12-15 12:05:13 -05:00
liamwhite
3ff7a5de1a Merge pull request #7410 from Nefsen402/wayland-fixes
Wayland fixes
2022-12-15 12:05:01 -05:00
Andrea Pappacoda
4447c9a46e build: tweak the find modules even more
As described in
https://github.com/yuzu-emu/yuzu/pull/9395#discussion_r1047456172
checking for PKG_CONFIG_FOUND before calling pkg_search_module() is
unneeded, and some find modules (like FindFFmpeg.cmake) don't do this
already. Consequently, this patch removes these checks.
2022-12-15 11:52:50 +01:00
bunnei
e2f32e8c88 Merge pull request #9441 from yuzu-emu/revert-9232-audio-default-thread
Revert "hle: service: audio: Use default service thread."
2022-12-14 14:58:17 -08:00
bunnei
beba9c9b61 Revert "hle: service: audio: Use default service thread." 2022-12-14 14:57:33 -08:00
liamwhite
a222f02c7a Merge pull request #6688 from yzct12345/valid-intel-max
render_vulkan: Fix validation errors on less compatible Intel GPUs
2022-12-14 15:33:10 -05:00
Liam
4fce72c902 vulkan_common: declare storageBuffer8BitAccess 2022-12-13 18:28:50 -05:00
Liam
77b0d01639 spirv_emit_context: declare GroupNonUniform capability for SubgroupLocalInvocationId 2022-12-13 18:25:53 -05:00
Alexander Orzechowski
09e3029c11 gl_device: Use a more robust way to use strict context mode
Instead of checking a environment variable which may not actually
exist or is just wrong, ask QT if it's running on the wayland
platform.
2022-12-13 15:01:51 -05:00
Alexander Orzechowski
2221afaf26 OpenGL: Check for threading support
We need this.
2022-12-13 13:23:35 -05:00
Alexander Orzechowski
45fcde817e wayland: Always use exclusive fullscreen
Wayland does not allow clients to choose their own size and position
on the screen. The concept of fullscreening an application by sizing
it to the screen and removing decorations does not exist. Use
exclusive fullscreen instead.
2022-12-13 13:23:35 -05:00
Alexander Orzechowski
29fbce9fe6 RenderWidget: Set WA_DontCreateNativeAncestors
Some windowing systems like wayland are designed to show hardware accellerated
surfaces as subsurfaces and not native windows.
2022-12-13 13:23:35 -05:00
Alexander Orzechowski
5754456292 emu_window_sdl2: Respect hidpi
Use SDL_GL_GetDrawableSize instead of SDL_GetWindowSize which
will return the true size our swapchain needs to be in even
for hidpi displays.
2022-12-13 13:23:35 -05:00
Alexander Orzechowski
3cc3176ad6 video_core/vulkan: Explicity check swapchain size when deciding to recreate
Vulkan for whatever reason does not return VK_ERROR_OUT_OF_DATE_KHR when
the swapchain is the wrong size. Explicity make sure the size is indeed
up to date to workaround this.
2022-12-13 13:23:35 -05:00
Liam
d5f53da79d renderer_opengl: refactor context acquire 2022-12-13 13:23:23 -05:00
liamwhite
a4696285af Merge pull request #9425 from german77/german_unlimited
yuzu: Make unlimited frame rate non persistent between game boots
2022-12-12 22:16:17 -05:00
yzct12345
f6868ae4dd Fix validation errors on less compatible Intel GPU 2022-12-12 20:53:05 -05:00
Narr the Reg
0ed80c9818 yuzu: Make unlimited frame rate non persistent between game boots 2022-12-12 19:21:30 -06:00
bunnei
339a37f8cb Merge pull request #9398 from liamwhite/fail
general: improve handling of system startup failure
2022-12-12 14:37:42 -08:00
bunnei
da58eb6208 Merge pull request #9406 from vonchenplus/topology
video_core: Adjust topology update logic and Adjust Clear Manage
2022-12-12 14:37:06 -08:00
liamwhite
b32b9524ad Merge pull request #9404 from german77/sdl_filter
input_common: Filter SDL GUID
2022-12-12 17:34:11 -05:00
Narr the Reg
3e1e6c66c0 input_common: Filter SDL GUID 2022-12-12 10:37:55 -06:00
Mai
8ef9075b1b Merge pull request #9420 from liamwhite/aniso
video_core: fix off by one in anisotropic filtering amount
2022-12-12 03:34:09 +00:00
Mai
0c531ff911 Merge pull request #9419 from liamwhite/no-gl
cmake: make OpenGL loader optional
2022-12-11 21:09:52 +00:00
Mai
d5684dbe7d Merge pull request #9415 from liamwhite/dc
memory: correct semantics of data cache management operations
2022-12-11 21:09:31 +00:00
Liam
ed37192441 memory: correct semantics of data cache management operations 2022-12-11 12:46:34 -05:00
Matías Locatti
623429a27e Merge pull request #9409 from liamwhite/smaa2
video_core: Integrate SMAA
2022-12-11 01:38:28 -03:00
Liam
456322dde6 video_core: fix off by one in anisotropic filtering amount 2022-12-10 20:54:45 -05:00
Mai
821da3ed54 Merge pull request #9416 from liamwhite/penicillin
cmake: enable faster linkers if available
2022-12-10 20:43:03 +00:00
Liam
8d1d6e149f cmake: make OpenGL loader optional
Co-authored-by: liushuyu <liushuyu@users.noreply.github.com>
2022-12-10 15:12:27 -05:00
Liam
1085bbb0a3 cmake: enable faster linkers if available 2022-12-10 15:04:25 -05:00
Mai
a5bc86a9ac Merge pull request #9417 from liamwhite/debug-assert
memory: remove DEBUG_ASSERT pointer test
2022-12-10 19:08:45 +00:00
Mai
6982423931 Merge pull request #9418 from liamwhite/implicitly-deleted
audio_core: remove explicitly defaulted and implicitly deleted constructors
2022-12-10 19:04:57 +00:00
Liam
e532b74e11 audio_core: remove explicitly defaulted and implicitly deleted constructors 2022-12-10 13:05:15 -05:00
Liam
985ed1e160 memory: remove DEBUG_ASSERT pointer test 2022-12-10 13:02:38 -05:00
liamwhite
f6e705737a Merge pull request #9412 from Saalvage/fix/trace-log-compilation
Fix compilation error
2022-12-09 17:03:19 -05:00
bunnei
66c4331de5 Merge pull request #9411 from Saalvage/fix/unlock-mutex
Correctly unlock mutex before its destruction
2022-12-09 10:51:19 -08:00
Salvage
c586ac9be2 Remove the lock entirely as per PR discussion
Correctly unlock mutex before its destruction

As per https://en.cppreference.com/w/cpp/thread/mutex/~mutex destroying a locked mutex is undefined behavior and MSVC++ decides to throw in this case

Swap out unique for scoped lock and readd comment
2022-12-09 16:39:59 +01:00
Liam
5b837157bd video_core: Integrate SMAA
Co-authored-by: goldenx86 <goldenx86@users.noreply.github.com>
Co-authored-by: BreadFish64 <breadfish64@users.noreply.github.com>
2022-12-08 17:17:45 -05:00
FengChen
37014e9127 video_core: Add vertex_array_instance_* sbubbed called warning 2022-12-08 23:19:31 +08:00
FengChen
1e64b5e2ec video_core: The draw manager manages whether Clear is required. 2022-12-08 23:10:52 +08:00
FengChen
15d63c3d3d video_core: Adjust topology update logic 2022-12-08 22:40:28 +08:00
Liam
9704acb982 general: improve handling of system startup failure 2022-12-06 16:13:42 -05:00
74 changed files with 14191 additions and 292 deletions

View File

@@ -22,6 +22,8 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
CMAKE_DEPENDENT_OPTION(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" ON "ENABLE_SDL2;NOT MSVC" OFF)
option(ENABLE_OPENGL "Enable OpenGL" ON)
mark_as_advanced(FORCE ENABLE_OPENGL)
option(ENABLE_QT "Enable the Qt frontend" ON)
option(ENABLE_QT6 "Allow usage of Qt6 to be attempted" OFF)
set(QT6_LOCATION "" CACHE PATH "Additional Location to search for Qt6 libraries like C:/Qt/6.3.1/msvc2019_64/")
@@ -51,6 +53,8 @@ option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}")
option(YUZU_CHECK_SUBMODULES "Check if submodules are present" ON)
CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF)
if (YUZU_USE_BUNDLED_VCPKG)
if (YUZU_TESTS)
list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests")
@@ -579,6 +583,21 @@ if (MSVC AND CMAKE_GENERATOR STREQUAL "Ninja")
)
endif()
if (YUZU_USE_FASTER_LD AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# We will assume that if the compiler is GCC, it will attempt to use ld.bfd by default.
# Try to pick a faster linker.
find_program(LLD lld)
find_program(MOLD mold)
if (MOLD AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.1")
message(NOTICE "Selecting mold as linker")
add_link_options("-fuse-ld=mold")
elseif (LLD)
message(NOTICE "Selecting lld as linker")
add_link_options("-fuse-ld=lld")
endif()
endif()
enable_testing()
add_subdirectory(externals)
add_subdirectory(src)

View File

@@ -2,9 +2,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
find_package(PkgConfig QUIET)
if (PKG_CONFIG_FOUND)
pkg_search_module(OPUS QUIET IMPORTED_TARGET opus)
endif()
pkg_search_module(OPUS QUIET IMPORTED_TARGET opus)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Opus

View File

@@ -3,9 +3,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
find_package(PkgConfig QUIET)
if (PKG_CONFIG_FOUND)
pkg_search_module(ENET QUIET IMPORTED_TARGET libenet)
endif()
pkg_search_module(ENET QUIET IMPORTED_TARGET libenet)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(enet

View File

@@ -9,9 +9,7 @@ if (httplib_FOUND)
find_package_handle_standard_args(httplib CONFIG_MODE)
else()
find_package(PkgConfig QUIET)
if (PKG_CONFIG_FOUND)
pkg_search_module(HTTPLIB QUIET IMPORTED_TARGET cpp-httplib)
endif()
pkg_search_module(HTTPLIB QUIET IMPORTED_TARGET cpp-httplib)
find_package_handle_standard_args(httplib
REQUIRED_VARS HTTPLIB_INCLUDEDIR
VERSION_VAR HTTPLIB_VERSION

View File

@@ -3,9 +3,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
find_package(PkgConfig QUIET)
if (PKG_CONFIG_FOUND)
pkg_search_module(INIREADER QUIET IMPORTED_TARGET INIReader)
endif()
pkg_search_module(INIREADER QUIET IMPORTED_TARGET INIReader)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(inih

View File

@@ -3,9 +3,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
find_package(PkgConfig QUIET)
if (PKG_CONFIG_FOUND)
pkg_search_module(LIBUSB QUIET IMPORTED_TARGET libusb-1.0)
endif()
pkg_search_module(LIBUSB QUIET IMPORTED_TARGET libusb-1.0)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(libusb

View File

@@ -8,9 +8,7 @@ if (lz4_FOUND)
find_package_handle_standard_args(lz4 CONFIG_MODE)
else()
find_package(PkgConfig QUIET)
if (PKG_CONFIG_FOUND)
pkg_search_module(LZ4 QUIET IMPORTED_TARGET liblz4)
endif()
pkg_search_module(LZ4 QUIET IMPORTED_TARGET liblz4)
find_package_handle_standard_args(lz4
REQUIRED_VARS LZ4_LINK_LIBRARIES
VERSION_VAR LZ4_VERSION

View File

@@ -8,9 +8,7 @@ if (zstd_FOUND)
find_package_handle_standard_args(zstd CONFIG_MODE)
else()
find_package(PkgConfig QUIET)
if (PKG_CONFIG_FOUND)
pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd)
endif()
pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd)
find_package_handle_standard_args(zstd
REQUIRED_VARS ZSTD_LINK_LIBRARIES
VERSION_VAR ZSTD_VERSION

View File

@@ -16,7 +16,6 @@ class CommandGenerator;
*/
class DetailAspect {
public:
DetailAspect() = default;
DetailAspect(CommandGenerator& command_generator, PerformanceEntryType entry_type, s32 node_id,
PerformanceDetailType detail_type);

View File

@@ -16,7 +16,6 @@ class CommandGenerator;
*/
class EntryAspect {
public:
EntryAspect() = default;
EntryAspect(CommandGenerator& command_generator, PerformanceEntryType type, s32 node_id);
/// Command generator the command will be generated into

View File

@@ -34,8 +34,6 @@ add_library(common STATIC
bit_util.h
cityhash.cpp
cityhash.h
cache_management.cpp
cache_management.h
common_funcs.h
common_precompiled_headers.h
common_types.h

View File

@@ -1,59 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cstdint>
#include <cstring>
#include "common/cache_management.h"
namespace Common {
#if defined(ARCHITECTURE_x86_64)
// Most cache operations are no-ops on x86
void DataCacheLineCleanByVAToPoU(void* start, size_t size) {}
void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size) {}
void DataCacheLineCleanByVAToPoC(void* start, size_t size) {}
void DataCacheZeroByVA(void* start, size_t size) {
std::memset(start, 0, size);
}
#elif defined(ARCHITECTURE_arm64)
// BS/DminLine is log2(cache size in words), we want size in bytes
#define EXTRACT_DMINLINE(ctr_el0) (1 << ((((ctr_el0) >> 16) & 0xf) + 2))
#define EXTRACT_BS(dczid_el0) (1 << (((dczid_el0)&0xf) + 2))
#define DEFINE_DC_OP(op_name, function_name) \
void function_name(void* start, size_t size) { \
size_t ctr_el0; \
asm volatile("mrs %[ctr_el0], ctr_el0\n\t" : [ctr_el0] "=r"(ctr_el0)); \
size_t cacheline_size = EXTRACT_DMINLINE(ctr_el0); \
uintptr_t va_start = reinterpret_cast<uintptr_t>(start); \
uintptr_t va_end = va_start + size; \
for (uintptr_t va = va_start; va < va_end; va += cacheline_size) { \
asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory"); \
} \
}
#define DEFINE_DC_OP_DCZID(op_name, function_name) \
void function_name(void* start, size_t size) { \
size_t dczid_el0; \
asm volatile("mrs %[dczid_el0], dczid_el0\n\t" : [dczid_el0] "=r"(dczid_el0)); \
size_t cacheline_size = EXTRACT_BS(dczid_el0); \
uintptr_t va_start = reinterpret_cast<uintptr_t>(start); \
uintptr_t va_end = va_start + size; \
for (uintptr_t va = va_start; va < va_end; va += cacheline_size) { \
asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory"); \
} \
}
DEFINE_DC_OP(cvau, DataCacheLineCleanByVAToPoU);
DEFINE_DC_OP(civac, DataCacheLineCleanAndInvalidateByVAToPoC);
DEFINE_DC_OP(cvac, DataCacheLineCleanByVAToPoC);
DEFINE_DC_OP_DCZID(zva, DataCacheZeroByVA);
#endif
} // namespace Common

View File

@@ -1,27 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <cstddef>
namespace Common {
// Data cache instructions enabled at EL0 by SCTLR_EL1.UCI.
// VA = virtual address
// PoC = point of coherency
// PoU = point of unification
// dc cvau
void DataCacheLineCleanByVAToPoU(void* start, size_t size);
// dc civac
void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size);
// dc cvac
void DataCacheLineCleanByVAToPoC(void* start, size_t size);
// dc zva
void DataCacheZeroByVA(void* start, size_t size);
} // namespace Common

View File

@@ -76,7 +76,8 @@ enum class ScalingFilter : u32 {
enum class AntiAliasing : u32 {
None = 0,
Fxaa = 1,
LastAA = Fxaa,
Smaa = 2,
LastAA = Smaa,
};
struct ResolutionScalingInfo {

View File

@@ -11,6 +11,7 @@
#include <mutex>
#include <thread>
#include "common/common_types.h"
#include "common/polyfill_thread.h"
namespace Common {
@@ -69,7 +70,7 @@ public:
explicit Barrier(std::size_t count_) : count(count_) {}
/// Blocks until all "count" threads have called Sync()
void Sync() {
bool Sync(std::stop_token token = {}) {
std::unique_lock lk{mutex};
const std::size_t current_generation = generation;
@@ -77,14 +78,16 @@ public:
generation++;
waiting = 0;
condvar.notify_all();
return true;
} else {
condvar.wait(lk,
[this, current_generation] { return current_generation != generation; });
CondvarWait(condvar, lk, token,
[this, current_generation] { return current_generation != generation; });
return !token.stop_requested();
}
}
private:
std::condition_variable condvar;
std::condition_variable_any condvar;
std::mutex mutex;
std::size_t count;
std::size_t waiting = 0;

View File

@@ -389,7 +389,9 @@ struct System::Impl {
kernel.ShutdownCores();
cpu_manager.Shutdown();
debugger.reset();
services->KillNVNFlinger();
if (services) {
services->KillNVNFlinger();
}
kernel.CloseServices();
services.reset();
service_manager.reset();

View File

@@ -20,23 +20,20 @@ namespace Core {
CpuManager::CpuManager(System& system_) : system{system_} {}
CpuManager::~CpuManager() = default;
void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager,
std::size_t core) {
cpu_manager.RunThread(core);
}
void CpuManager::Initialize() {
num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1;
gpu_barrier = std::make_unique<Common::Barrier>(num_cores + 1);
for (std::size_t core = 0; core < num_cores; core++) {
core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core);
core_data[core].host_thread =
std::jthread([this, core](std::stop_token token) { RunThread(token, core); });
}
}
void CpuManager::Shutdown() {
for (std::size_t core = 0; core < num_cores; core++) {
if (core_data[core].host_thread.joinable()) {
core_data[core].host_thread.request_stop();
core_data[core].host_thread.join();
}
}
@@ -184,7 +181,7 @@ void CpuManager::ShutdownThread() {
UNREACHABLE();
}
void CpuManager::RunThread(std::size_t core) {
void CpuManager::RunThread(std::stop_token token, std::size_t core) {
/// Initialization
system.RegisterCoreThread(core);
std::string name;
@@ -206,7 +203,9 @@ void CpuManager::RunThread(std::size_t core) {
});
// Running
gpu_barrier->Sync();
if (!gpu_barrier->Sync(token)) {
return;
}
if (!is_async_gpu && !is_multicore) {
system.GPU().ObtainContext();

View File

@@ -81,12 +81,10 @@ private:
void SingleCoreRunGuestThread();
void SingleCoreRunIdleThread();
static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core);
void GuestActivate();
void HandleInterrupt();
void ShutdownThread();
void RunThread(std::size_t core);
void RunThread(std::stop_token stop_token, std::size_t core);
struct CoreData {
std::shared_ptr<Common::Fiber> host_context;

View File

@@ -131,6 +131,10 @@ public:
return active_config;
}
bool StrictContextRequired() const {
return strict_context_required;
}
/**
* Requests the internal configuration to be replaced by the specified argument at some point in
* the future.
@@ -207,6 +211,8 @@ protected:
WindowSystemInfo window_info;
bool strict_context_required = false;
private:
/**
* Handler called when the minimal client area was requested to be changed via SetConfig.

View File

@@ -167,6 +167,9 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
}
if (incoming) {
// Populate the object lists with the data in the IPC request.
incoming_copy_handles.reserve(handle_descriptor_header->num_handles_to_copy);
incoming_move_handles.reserve(handle_descriptor_header->num_handles_to_move);
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
incoming_copy_handles.push_back(rp.Pop<Handle>());
}
@@ -181,6 +184,11 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
}
}
buffer_x_desciptors.reserve(command_header->num_buf_x_descriptors);
buffer_a_desciptors.reserve(command_header->num_buf_a_descriptors);
buffer_b_desciptors.reserve(command_header->num_buf_b_descriptors);
buffer_w_desciptors.reserve(command_header->num_buf_w_descriptors);
for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) {
buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>());
}

View File

@@ -104,12 +104,16 @@ struct KernelCore::Impl {
}
void CloseCurrentProcess() {
(*current_process).Finalize();
// current_process->Close();
// TODO: The current process should be destroyed based on accurate ref counting after
KProcess* old_process = current_process.exchange(nullptr);
if (old_process == nullptr) {
return;
}
// old_process->Close();
// TODO: The process should be destroyed based on accurate ref counting after
// calling Close(). Adding a manual Destroy() call instead to avoid a memory leak.
(*current_process).Destroy();
current_process = nullptr;
old_process->Finalize();
old_process->Destroy();
}
void Shutdown() {

View File

@@ -163,9 +163,6 @@ ServiceThread::Impl::~Impl() {
m_wakeup_event->Signal();
m_host_thread.join();
// Lock mutex.
m_session_mutex.lock();
// Close all remaining sessions.
for (const auto& [server_session, manager] : m_sessions) {
server_session->Close();

View File

@@ -203,8 +203,9 @@ private:
};
AudInU::AudInU(Core::System& system_)
: ServiceFramework{system_, "audin:u"}, service_context{system_, "AudInU"},
impl{std::make_unique<AudioCore::AudioIn::Manager>(system_)} {
: ServiceFramework{system_, "audin:u", ServiceThreadType::CreateNew},
service_context{system_, "AudInU"}, impl{std::make_unique<AudioCore::AudioIn::Manager>(
system_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &AudInU::ListAudioIns, "ListAudioIns"},

View File

@@ -26,8 +26,9 @@ public:
explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,
size_t session_id, const std::string& device_name,
const AudioOutParameter& in_params, u32 handle, u64 applet_resource_user_id)
: ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
event{service_context.CreateEvent("AudioOutEvent")},
: ServiceFramework{system_, "IAudioOut", ServiceThreadType::CreateNew},
service_context{system_, "IAudioOut"}, event{service_context.CreateEvent(
"AudioOutEvent")},
impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {
// clang-format off
@@ -220,8 +221,9 @@ private:
};
AudOutU::AudOutU(Core::System& system_)
: ServiceFramework{system_, "audout:u"}, service_context{system_, "AudOutU"},
impl{std::make_unique<AudioCore::AudioOut::Manager>(system_)} {
: ServiceFramework{system_, "audout:u", ServiceThreadType::CreateNew},
service_context{system_, "AudOutU"}, impl{std::make_unique<AudioCore::AudioOut::Manager>(
system_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &AudOutU::ListAudioOuts, "ListAudioOuts"},

View File

@@ -35,9 +35,10 @@ public:
AudioCore::AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
u32 process_handle, u64 applet_resource_user_id, s32 session_id)
: ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
impl{std::make_unique<Renderer>(system_, manager, rendered_event)} {
: ServiceFramework{system_, "IAudioRenderer", ServiceThreadType::CreateNew},
service_context{system_, "IAudioRenderer"}, rendered_event{service_context.CreateEvent(
"IAudioRendererEvent")},
manager{manager_}, impl{std::make_unique<Renderer>(system_, manager, rendered_event)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
@@ -242,8 +243,10 @@ class IAudioDevice final : public ServiceFramework<IAudioDevice> {
public:
explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
u32 device_num)
: ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
: ServiceFramework{system_, "IAudioDevice", ServiceThreadType::CreateNew},
service_context{system_, "IAudioDevice"}, impl{std::make_unique<AudioDevice>(
system_, applet_resource_user_id,
revision)},
event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
static const FunctionInfo functions[] = {
{0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
@@ -418,7 +421,7 @@ private:
};
AudRenU::AudRenU(Core::System& system_)
: ServiceFramework{system_, "audren:u"},
: ServiceFramework{system_, "audren:u", ServiceThreadType::CreateNew},
service_context{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {
// clang-format off
static const FunctionInfo functions[] = {

View File

@@ -6,7 +6,6 @@
#include "common/assert.h"
#include "common/atomic_ops.h"
#include "common/cache_management.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/page_table.h"
@@ -195,13 +194,11 @@ struct Memory::Impl {
break;
}
case Common::PageType::Memory: {
DEBUG_ASSERT(pointer);
u8* mem_ptr = pointer + page_offset + (page_index << YUZU_PAGEBITS);
on_memory(copy_amount, mem_ptr);
break;
}
case Common::PageType::DebugMemory: {
DEBUG_ASSERT(pointer);
u8* const mem_ptr{GetPointerFromDebugMemory(current_vaddr)};
on_memory(copy_amount, mem_ptr);
break;
@@ -342,10 +339,9 @@ struct Memory::Impl {
LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}", current_vaddr);
throw InvalidMemoryException();
},
[&](const std::size_t block_size, u8* const host_ptr) { cb(block_size, host_ptr); },
[&](const std::size_t block_size, u8* const host_ptr) {},
[&](const VAddr current_vaddr, const std::size_t block_size, u8* const host_ptr) {
system.GPU().FlushRegion(current_vaddr, block_size);
cb(block_size, host_ptr);
cb(current_vaddr, block_size);
},
[](const std::size_t block_size) {});
} catch (InvalidMemoryException&) {
@@ -356,27 +352,30 @@ struct Memory::Impl {
}
Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
auto perform = [&](const std::size_t block_size, u8* const host_ptr) {
// Do nothing; this operation (dc ivac) cannot be supported
// from EL0
auto on_rasterizer = [&](const VAddr current_vaddr, const std::size_t block_size) {
// dc ivac: Invalidate to point of coherency
// GPU flush -> CPU invalidate
system.GPU().FlushRegion(current_vaddr, block_size);
};
return PerformCacheOperation(process, dest_addr, size, perform);
return PerformCacheOperation(process, dest_addr, size, on_rasterizer);
}
Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
auto perform = [&](const std::size_t block_size, u8* const host_ptr) {
auto on_rasterizer = [&](const VAddr current_vaddr, const std::size_t block_size) {
// dc cvac: Store to point of coherency
Common::DataCacheLineCleanByVAToPoC(host_ptr, block_size);
// CPU flush -> GPU invalidate
system.GPU().InvalidateRegion(current_vaddr, block_size);
};
return PerformCacheOperation(process, dest_addr, size, perform);
return PerformCacheOperation(process, dest_addr, size, on_rasterizer);
}
Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
auto perform = [&](const std::size_t block_size, u8* const host_ptr) {
auto on_rasterizer = [&](const VAddr current_vaddr, const std::size_t block_size) {
// dc civac: Store to point of coherency, and invalidate from cache
Common::DataCacheLineCleanAndInvalidateByVAToPoC(host_ptr, block_size);
// CPU flush -> GPU invalidate
system.GPU().InvalidateRegion(current_vaddr, block_size);
};
return PerformCacheOperation(process, dest_addr, size, perform);
return PerformCacheOperation(process, dest_addr, size, on_rasterizer);
}
void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) {

View File

@@ -16,6 +16,8 @@ Common::UUID GetGUID(SDL_Joystick* joystick) {
const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
std::array<u8, 16> data{};
std::memcpy(data.data(), guid.data, sizeof(data));
// Clear controller name crc
std::memset(data.data() + 2, 0, sizeof(u16));
return Common::UUID{data};
}
} // Anonymous namespace

View File

@@ -1345,8 +1345,10 @@ void EmitContext::DefineInputs(const IR::Program& program) {
if (info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles ||
(profile.warp_size_potentially_larger_than_guest &&
(info.uses_subgroup_vote || info.uses_subgroup_mask))) {
AddCapability(spv::Capability::GroupNonUniform);
subgroup_local_invocation_id =
DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId);
Decorate(subgroup_local_invocation_id, spv::Decoration::Flat);
}
if (info.uses_fswzadd) {
const Id f32_one{Const(1.0f)};

View File

@@ -178,6 +178,8 @@ add_library(video_core STATIC
renderer_vulkan/vk_scheduler.h
renderer_vulkan/vk_shader_util.cpp
renderer_vulkan/vk_shader_util.h
renderer_vulkan/vk_smaa.cpp
renderer_vulkan/vk_smaa.h
renderer_vulkan/vk_staging_buffer_pool.cpp
renderer_vulkan/vk_staging_buffer_pool.h
renderer_vulkan/vk_state_tracker.cpp
@@ -195,6 +197,8 @@ add_library(video_core STATIC
shader_environment.h
shader_notify.cpp
shader_notify.h
smaa_area_tex.h
smaa_search_tex.h
surface.cpp
surface.h
texture_cache/accelerated_swizzle.cpp

View File

@@ -46,21 +46,26 @@ void DrawManager::ProcessMethodCall(u32 method, u32 argument) {
SetInlineIndexBuffer(regs.inline_index_4x8.index2);
SetInlineIndexBuffer(regs.inline_index_4x8.index3);
break;
case MAXWELL3D_REG_INDEX(topology_override):
use_topology_override = true;
case MAXWELL3D_REG_INDEX(vertex_array_instance_first):
case MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent): {
LOG_WARNING(HW_GPU, "(STUBBED) called");
break;
}
default:
break;
}
}
void DrawManager::Clear(u32 layer_count) {
maxwell3d->rasterizer->Clear(layer_count);
if (maxwell3d->ShouldExecute()) {
maxwell3d->rasterizer->Clear(layer_count);
}
}
void DrawManager::DrawDeferred() {
if (draw_state.draw_mode != DrawMode::Instance || draw_state.instance_count == 0)
if (draw_state.draw_mode != DrawMode::Instance || draw_state.instance_count == 0) {
return;
}
DrawEnd(draw_state.instance_count + 1, true);
draw_state.instance_count = 0;
}
@@ -115,8 +120,9 @@ void DrawManager::DrawEnd(u32 instance_count, bool force_draw) {
const auto& regs{maxwell3d->regs};
switch (draw_state.draw_mode) {
case DrawMode::Instance:
if (!force_draw)
if (!force_draw) {
break;
}
[[fallthrough]];
case DrawMode::General:
draw_state.base_instance = regs.global_base_instance_index;
@@ -156,25 +162,28 @@ void DrawManager::DrawIndexSmall(u32 argument) {
ProcessDraw(true, 1);
}
void DrawManager::ProcessTopologyOverride() {
if (!use_topology_override)
return;
void DrawManager::UpdateTopology() {
const auto& regs{maxwell3d->regs};
switch (regs.topology_override) {
case PrimitiveTopologyOverride::None:
switch (regs.primitive_topology_control) {
case PrimitiveTopologyControl::UseInBeginMethods:
break;
case PrimitiveTopologyOverride::Points:
draw_state.topology = PrimitiveTopology::Points;
break;
case PrimitiveTopologyOverride::Lines:
draw_state.topology = PrimitiveTopology::Lines;
break;
case PrimitiveTopologyOverride::LineStrip:
draw_state.topology = PrimitiveTopology::LineStrip;
break;
default:
draw_state.topology = static_cast<PrimitiveTopology>(regs.topology_override);
case PrimitiveTopologyControl::UseSeparateState:
switch (regs.topology_override) {
case PrimitiveTopologyOverride::None:
break;
case PrimitiveTopologyOverride::Points:
draw_state.topology = PrimitiveTopology::Points;
break;
case PrimitiveTopologyOverride::Lines:
draw_state.topology = PrimitiveTopology::Lines;
break;
case PrimitiveTopologyOverride::LineStrip:
draw_state.topology = PrimitiveTopology::LineStrip;
break;
default:
draw_state.topology = static_cast<PrimitiveTopology>(regs.topology_override);
break;
}
break;
}
}
@@ -183,9 +192,10 @@ void DrawManager::ProcessDraw(bool draw_indexed, u32 instance_count) {
LOG_TRACE(HW_GPU, "called, topology={}, count={}", draw_state.topology,
draw_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count);
ProcessTopologyOverride();
UpdateTopology();
if (maxwell3d->ShouldExecute())
if (maxwell3d->ShouldExecute()) {
maxwell3d->rasterizer->Draw(draw_indexed, instance_count);
}
}
} // namespace Tegra::Engines

View File

@@ -10,6 +10,7 @@ class RasterizerInterface;
}
namespace Tegra::Engines {
using PrimitiveTopologyControl = Maxwell3D::Regs::PrimitiveTopologyControl;
using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology;
using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride;
using IndexBuffer = Maxwell3D::Regs::IndexBuffer;
@@ -58,12 +59,11 @@ private:
void DrawIndexSmall(u32 argument);
void ProcessTopologyOverride();
void UpdateTopology();
void ProcessDraw(bool draw_indexed, u32 instance_count);
Maxwell3D* maxwell3d{};
State draw_state{};
bool use_topology_override{};
};
} // namespace Tegra::Engines

View File

@@ -223,8 +223,6 @@ struct GPU::Impl {
/// core timing events.
void Start() {
gpu_thread.StartThread(*renderer, renderer->Context(), *scheduler);
cpu_context = renderer->GetRenderWindow().CreateSharedContext();
cpu_context->MakeCurrent();
}
void NotifyShutdown() {
@@ -235,6 +233,9 @@ struct GPU::Impl {
/// Obtain the CPU Context
void ObtainContext() {
if (!cpu_context) {
cpu_context = renderer->GetRenderWindow().CreateSharedContext();
}
cpu_context->MakeCurrent();
}

View File

@@ -26,9 +26,16 @@ set(SHADER_FILES
opengl_present.frag
opengl_present.vert
opengl_present_scaleforce.frag
opengl_smaa.glsl
pitch_unswizzle.comp
present_bicubic.frag
present_gaussian.frag
smaa_edge_detection.vert
smaa_edge_detection.frag
smaa_blending_weight_calculation.vert
smaa_blending_weight_calculation.frag
smaa_neighborhood_blending.vert
smaa_neighborhood_blending.frag
vulkan_blit_color_float.frag
vulkan_blit_depth_stencil.frag
vulkan_fidelityfx_fsr_easu_fp16.comp

View File

@@ -11,10 +11,6 @@ string(TOUPPER ${CONTENTS_NAME} CONTENTS_NAME)
FILE(READ ${SOURCE_FILE} line_contents)
# Replace double quotes with single quotes,
# as double quotes will be used to wrap the lines
STRING(REGEX REPLACE "\"" "'" line_contents "${line_contents}")
# CMake separates list elements with semicolons, but semicolons
# are used extensively in the shader code.
# Replace with a temporary marker, to be reverted later.
@@ -25,7 +21,7 @@ STRING(REGEX REPLACE "\n" ";" line_contents "${line_contents}")
# Build the shader string, wrapping each line in double quotes.
foreach(line IN LISTS line_contents)
string(CONCAT CONTENTS "${CONTENTS}" \"${line}\\n\"\n)
string(CONCAT CONTENTS "${CONTENTS}" "R\"(${line}\n)\" ")
endforeach()
# Revert the original semicolons in the source.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#version 460
#extension GL_GOOGLE_include_directive : enable
layout (binding = 0) uniform sampler2D edges_tex;
layout (binding = 1) uniform sampler2D area_tex;
layout (binding = 2) uniform sampler2D search_tex;
layout (location = 0) in vec2 tex_coord;
layout (location = 1) in vec2 pix_coord;
layout (location = 2) in vec4 offset[3];
layout (location = 0) out vec4 frag_color;
vec4 metrics = vec4(1.0 / textureSize(edges_tex, 0), textureSize(edges_tex, 0));
#define SMAA_RT_METRICS metrics
#define SMAA_GLSL_4
#define SMAA_PRESET_ULTRA
#define SMAA_INCLUDE_VS 0
#define SMAA_INCLUDE_PS 1
#include "opengl_smaa.glsl"
void main() {
frag_color = SMAABlendingWeightCalculationPS(tex_coord,
pix_coord,
offset,
edges_tex,
area_tex,
search_tex,
vec4(0)
);
}

View File

@@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#version 460
#extension GL_GOOGLE_include_directive : enable
#ifdef VULKAN
#define VERTEX_ID gl_VertexIndex
#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
#define VERTEX_ID gl_VertexID
#endif
out gl_PerVertex {
vec4 gl_Position;
};
const vec2 vertices[3] =
vec2[3](vec2(-1,-1), vec2(3,-1), vec2(-1, 3));
layout (binding = 0) uniform sampler2D edges_tex;
layout (binding = 1) uniform sampler2D area_tex;
layout (binding = 2) uniform sampler2D search_tex;
layout (location = 0) out vec2 tex_coord;
layout (location = 1) out vec2 pix_coord;
layout (location = 2) out vec4 offset[3];
vec4 metrics = vec4(1.0 / textureSize(edges_tex, 0), textureSize(edges_tex, 0));
#define SMAA_RT_METRICS metrics
#define SMAA_GLSL_4
#define SMAA_PRESET_ULTRA
#define SMAA_INCLUDE_VS 1
#define SMAA_INCLUDE_PS 0
#include "opengl_smaa.glsl"
void main() {
vec2 vertex = vertices[VERTEX_ID];
gl_Position = vec4(vertex, 0.0, 1.0);
tex_coord = (vertex + 1.0) / 2.0;
SMAABlendingWeightCalculationVS(tex_coord, pix_coord, offset);
}

View File

@@ -0,0 +1,26 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#version 460
#extension GL_GOOGLE_include_directive : enable
layout (binding = 0) uniform sampler2D input_tex;
layout (location = 0) in vec2 tex_coord;
layout (location = 1) in vec4 offset[3];
layout (location = 0) out vec2 frag_color;
vec4 metrics = vec4(1.0 / textureSize(input_tex, 0), textureSize(input_tex, 0));
#define SMAA_RT_METRICS metrics
#define SMAA_GLSL_4
#define SMAA_PRESET_ULTRA
#define SMAA_INCLUDE_VS 0
#define SMAA_INCLUDE_PS 1
#include "opengl_smaa.glsl"
void main() {
frag_color = SMAAColorEdgeDetectionPS(tex_coord, offset, input_tex);
}

View File

@@ -0,0 +1,40 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#version 460
#extension GL_GOOGLE_include_directive : enable
#ifdef VULKAN
#define VERTEX_ID gl_VertexIndex
#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
#define VERTEX_ID gl_VertexID
#endif
out gl_PerVertex {
vec4 gl_Position;
};
const vec2 vertices[3] =
vec2[3](vec2(-1,-1), vec2(3,-1), vec2(-1, 3));
layout (binding = 0) uniform sampler2D input_tex;
layout (location = 0) out vec2 tex_coord;
layout (location = 1) out vec4 offset[3];
vec4 metrics = vec4(1.0 / textureSize(input_tex, 0), textureSize(input_tex, 0));
#define SMAA_RT_METRICS metrics
#define SMAA_GLSL_4
#define SMAA_PRESET_ULTRA
#define SMAA_INCLUDE_VS 1
#define SMAA_INCLUDE_PS 0
#include "opengl_smaa.glsl"
void main() {
vec2 vertex = vertices[VERTEX_ID];
gl_Position = vec4(vertex, 0.0, 1.0);
tex_coord = (vertex + 1.0) / 2.0;
SMAAEdgeDetectionVS(tex_coord, offset);
}

View File

@@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#version 460
#extension GL_GOOGLE_include_directive : enable
layout (binding = 0) uniform sampler2D input_tex;
layout (binding = 1) uniform sampler2D blend_tex;
layout (location = 0) in vec2 tex_coord;
layout (location = 1) in vec4 offset;
layout (location = 0) out vec4 frag_color;
vec4 metrics = vec4(1.0 / textureSize(input_tex, 0), textureSize(input_tex, 0));
#define SMAA_RT_METRICS metrics
#define SMAA_GLSL_4
#define SMAA_PRESET_ULTRA
#define SMAA_INCLUDE_VS 0
#define SMAA_INCLUDE_PS 1
#include "opengl_smaa.glsl"
void main() {
frag_color = SMAANeighborhoodBlendingPS(tex_coord,
offset,
input_tex,
blend_tex
);
}

View File

@@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#version 460
#extension GL_GOOGLE_include_directive : enable
#ifdef VULKAN
#define VERTEX_ID gl_VertexIndex
#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
#define VERTEX_ID gl_VertexID
#endif
out gl_PerVertex {
vec4 gl_Position;
};
const vec2 vertices[3] =
vec2[3](vec2(-1,-1), vec2(3,-1), vec2(-1, 3));
layout (binding = 0) uniform sampler2D input_tex;
layout (binding = 1) uniform sampler2D blend_tex;
layout (location = 0) out vec2 tex_coord;
layout (location = 1) out vec4 offset;
vec4 metrics = vec4(1.0 / textureSize(input_tex, 0), textureSize(input_tex, 0));
#define SMAA_RT_METRICS metrics
#define SMAA_GLSL_4
#define SMAA_PRESET_ULTRA
#define SMAA_INCLUDE_VS 1
#define SMAA_INCLUDE_PS 0
#include "opengl_smaa.glsl"
void main() {
vec2 vertex = vertices[VERTEX_ID];
gl_Position = vec4(vertex, 0.0, 1.0);
tex_coord = (vertex + 1.0) / 2.0;
SMAANeighborhoodBlendingVS(tex_coord, offset);
}

View File

@@ -112,7 +112,7 @@ bool IsASTCSupported() {
}
} // Anonymous namespace
Device::Device() {
Device::Device(Core::Frontend::EmuWindow& emu_window) {
if (!GLAD_GL_VERSION_4_6) {
LOG_ERROR(Render_OpenGL, "OpenGL 4.6 is not available");
throw std::runtime_error{"Insufficient version"};
@@ -126,9 +126,9 @@ Device::Device() {
const bool is_intel = vendor_name == "Intel";
#ifdef __unix__
const bool is_linux = true;
constexpr bool is_linux = true;
#else
const bool is_linux = false;
constexpr bool is_linux = false;
#endif
bool disable_fast_buffer_sub_data = false;
@@ -193,9 +193,11 @@ Device::Device() {
}
}
strict_context_required = emu_window.StrictContextRequired();
// Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation.
// Blocks EGL on Wayland from using asynchronous shader compilation.
use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue() &&
!(is_amd || (is_intel && !is_linux));
!(is_amd || (is_intel && !is_linux)) && !strict_context_required;
use_driver_cache = is_nvidia;
LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);

View File

@@ -5,6 +5,7 @@
#include <cstddef>
#include "common/common_types.h"
#include "core/frontend/emu_window.h"
#include "shader_recompiler/stage.h"
namespace Settings {
@@ -15,7 +16,7 @@ namespace OpenGL {
class Device {
public:
explicit Device();
explicit Device(Core::Frontend::EmuWindow& emu_window);
[[nodiscard]] std::string GetVendorName() const;
@@ -173,6 +174,10 @@ public:
return can_report_memory;
}
bool StrictContextRequired() const {
return strict_context_required;
}
private:
static bool TestVariableAoffi();
static bool TestPreciseBug();
@@ -216,6 +221,7 @@ private:
bool has_cbuf_ftou_bug{};
bool has_bool_ref_bug{};
bool can_report_memory{};
bool strict_context_required{};
std::string vendor_name;
};

View File

@@ -138,9 +138,6 @@ void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_load
void RasterizerOpenGL::Clear(u32 layer_count) {
MICROPROFILE_SCOPE(OpenGL_Clears);
if (!maxwell3d->ShouldExecute()) {
return;
}
const auto& regs = maxwell3d->regs;
bool use_color{};

View File

@@ -174,6 +174,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo
texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, program_manager{program_manager_},
state_tracker{state_tracker_}, shader_notify{shader_notify_},
use_asynchronous_shaders{device.UseAsynchronousShaders()},
strict_context_required{device.StrictContextRequired()},
profile{
.supported_spirv = 0x00010000,
@@ -255,9 +256,14 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
}
shader_cache_filename = base_dir / "opengl.bin";
if (!workers) {
if (!workers && !strict_context_required) {
workers = CreateWorkers();
}
std::optional<Context> strict_context;
if (strict_context_required) {
strict_context.emplace(emu_window);
}
struct {
std::mutex mutex;
size_t total{};
@@ -265,44 +271,49 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
bool has_loaded{};
} state;
const auto queue_work{[&](Common::UniqueFunction<void, Context*>&& work) {
if (strict_context_required) {
work(&strict_context.value());
} else {
workers->QueueWork(std::move(work));
}
}};
const auto load_compute{[&](std::ifstream& file, FileEnvironment env) {
ComputePipelineKey key;
file.read(reinterpret_cast<char*>(&key), sizeof(key));
workers->QueueWork(
[this, key, env = std::move(env), &state, &callback](Context* ctx) mutable {
ctx->pools.ReleaseContents();
auto pipeline{CreateComputePipeline(ctx->pools, key, env)};
std::scoped_lock lock{state.mutex};
if (pipeline) {
compute_cache.emplace(key, std::move(pipeline));
}
++state.built;
if (state.has_loaded) {
callback(VideoCore::LoadCallbackStage::Build, state.built, state.total);
}
});
queue_work([this, key, env = std::move(env), &state, &callback](Context* ctx) mutable {
ctx->pools.ReleaseContents();
auto pipeline{CreateComputePipeline(ctx->pools, key, env)};
std::scoped_lock lock{state.mutex};
if (pipeline) {
compute_cache.emplace(key, std::move(pipeline));
}
++state.built;
if (state.has_loaded) {
callback(VideoCore::LoadCallbackStage::Build, state.built, state.total);
}
});
++state.total;
}};
const auto load_graphics{[&](std::ifstream& file, std::vector<FileEnvironment> envs) {
GraphicsPipelineKey key;
file.read(reinterpret_cast<char*>(&key), sizeof(key));
workers->QueueWork(
[this, key, envs = std::move(envs), &state, &callback](Context* ctx) mutable {
boost::container::static_vector<Shader::Environment*, 5> env_ptrs;
for (auto& env : envs) {
env_ptrs.push_back(&env);
}
ctx->pools.ReleaseContents();
auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)};
std::scoped_lock lock{state.mutex};
if (pipeline) {
graphics_cache.emplace(key, std::move(pipeline));
}
++state.built;
if (state.has_loaded) {
callback(VideoCore::LoadCallbackStage::Build, state.built, state.total);
}
});
queue_work([this, key, envs = std::move(envs), &state, &callback](Context* ctx) mutable {
boost::container::static_vector<Shader::Environment*, 5> env_ptrs;
for (auto& env : envs) {
env_ptrs.push_back(&env);
}
ctx->pools.ReleaseContents();
auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)};
std::scoped_lock lock{state.mutex};
if (pipeline) {
graphics_cache.emplace(key, std::move(pipeline));
}
++state.built;
if (state.has_loaded) {
callback(VideoCore::LoadCallbackStage::Build, state.built, state.total);
}
});
++state.total;
}};
LoadPipelines(stop_loading, shader_cache_filename, CACHE_VERSION, load_compute, load_graphics);
@@ -314,6 +325,9 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
state.has_loaded = true;
lock.unlock();
if (strict_context_required) {
return;
}
workers->WaitForRequests(stop_loading);
if (!use_asynchronous_shaders) {
workers.reset();

View File

@@ -69,6 +69,7 @@ private:
StateTracker& state_tracker;
VideoCore::ShaderNotify& shader_notify;
const bool use_asynchronous_shaders;
const bool strict_context_required;
GraphicsPipelineKey graphics_key{};
GraphicsPipeline* current_pipeline{};

View File

@@ -22,12 +22,21 @@
#include "video_core/host_shaders/opengl_present_frag.h"
#include "video_core/host_shaders/opengl_present_scaleforce_frag.h"
#include "video_core/host_shaders/opengl_present_vert.h"
#include "video_core/host_shaders/opengl_smaa_glsl.h"
#include "video_core/host_shaders/present_bicubic_frag.h"
#include "video_core/host_shaders/present_gaussian_frag.h"
#include "video_core/host_shaders/smaa_blending_weight_calculation_frag.h"
#include "video_core/host_shaders/smaa_blending_weight_calculation_vert.h"
#include "video_core/host_shaders/smaa_edge_detection_frag.h"
#include "video_core/host_shaders/smaa_edge_detection_vert.h"
#include "video_core/host_shaders/smaa_neighborhood_blending_frag.h"
#include "video_core/host_shaders/smaa_neighborhood_blending_vert.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/gl_shader_manager.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
#include "video_core/smaa_area_tex.h"
#include "video_core/smaa_search_tex.h"
#include "video_core/textures/decoders.h"
namespace OpenGL {
@@ -131,8 +140,8 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_,
Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
std::unique_ptr<Core::Frontend::GraphicsContext> context_)
: RendererBase{emu_window_, std::move(context_)}, telemetry_session{telemetry_session_},
emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, state_tracker{},
program_manager{device},
emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, device{emu_window_},
state_tracker{}, program_manager{device},
rasterizer(emu_window, gpu, cpu_memory, device, screen_info, program_manager, state_tracker) {
if (Settings::values.renderer_debug && GLAD_GL_KHR_debug) {
glEnable(GL_DEBUG_OUTPUT);
@@ -258,6 +267,28 @@ void RendererOpenGL::InitOpenGLObjects() {
// Create shader programs
fxaa_vertex = CreateProgram(HostShaders::FXAA_VERT, GL_VERTEX_SHADER);
fxaa_fragment = CreateProgram(HostShaders::FXAA_FRAG, GL_FRAGMENT_SHADER);
const auto SmaaShader = [](std::string_view specialized_source, GLenum stage) {
std::string shader_source{specialized_source};
constexpr std::string_view include_string = "#include \"opengl_smaa.glsl\"";
const std::size_t pos = shader_source.find(include_string);
ASSERT(pos != std::string::npos);
shader_source.replace(pos, include_string.size(), HostShaders::OPENGL_SMAA_GLSL);
return CreateProgram(shader_source, stage);
};
smaa_edge_detection_vert = SmaaShader(HostShaders::SMAA_EDGE_DETECTION_VERT, GL_VERTEX_SHADER);
smaa_edge_detection_frag =
SmaaShader(HostShaders::SMAA_EDGE_DETECTION_FRAG, GL_FRAGMENT_SHADER);
smaa_blending_weight_calculation_vert =
SmaaShader(HostShaders::SMAA_BLENDING_WEIGHT_CALCULATION_VERT, GL_VERTEX_SHADER);
smaa_blending_weight_calculation_frag =
SmaaShader(HostShaders::SMAA_BLENDING_WEIGHT_CALCULATION_FRAG, GL_FRAGMENT_SHADER);
smaa_neighborhood_blending_vert =
SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_VERT, GL_VERTEX_SHADER);
smaa_neighborhood_blending_frag =
SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_FRAG, GL_FRAGMENT_SHADER);
present_vertex = CreateProgram(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER);
present_bilinear_fragment = CreateProgram(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER);
present_bicubic_fragment = CreateProgram(HostShaders::PRESENT_BICUBIC_FRAG, GL_FRAGMENT_SHADER);
@@ -293,7 +324,16 @@ void RendererOpenGL::InitOpenGLObjects() {
// Clear screen to black
LoadColorToActiveGLTexture(0, 0, 0, 0, screen_info.texture);
fxaa_framebuffer.Create();
aa_framebuffer.Create();
smaa_area_tex.Create(GL_TEXTURE_2D);
glTextureStorage2D(smaa_area_tex.handle, 1, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT);
glTextureSubImage2D(smaa_area_tex.handle, 0, 0, 0, AREATEX_WIDTH, AREATEX_HEIGHT, GL_RG,
GL_UNSIGNED_BYTE, areaTexBytes);
smaa_search_tex.Create(GL_TEXTURE_2D);
glTextureStorage2D(smaa_search_tex.handle, 1, GL_R8, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT);
glTextureSubImage2D(smaa_search_tex.handle, 0, 0, 0, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, GL_RED,
GL_UNSIGNED_BYTE, searchTexBytes);
}
void RendererOpenGL::AddTelemetryFields() {
@@ -346,13 +386,22 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
texture.resource.Release();
texture.resource.Create(GL_TEXTURE_2D);
glTextureStorage2D(texture.resource.handle, 1, internal_format, texture.width, texture.height);
fxaa_texture.Release();
fxaa_texture.Create(GL_TEXTURE_2D);
glTextureStorage2D(fxaa_texture.handle, 1, GL_RGBA16F,
aa_texture.Release();
aa_texture.Create(GL_TEXTURE_2D);
glTextureStorage2D(aa_texture.handle, 1, GL_RGBA16F,
Settings::values.resolution_info.ScaleUp(screen_info.texture.width),
Settings::values.resolution_info.ScaleUp(screen_info.texture.height));
glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, aa_texture.handle, 0);
smaa_edges_tex.Release();
smaa_edges_tex.Create(GL_TEXTURE_2D);
glTextureStorage2D(smaa_edges_tex.handle, 1, GL_RG16F,
Settings::values.resolution_info.ScaleUp(screen_info.texture.width),
Settings::values.resolution_info.ScaleUp(screen_info.texture.height));
smaa_blend_tex.Release();
smaa_blend_tex.Create(GL_TEXTURE_2D);
glTextureStorage2D(smaa_blend_tex.handle, 1, GL_RGBA16F,
Settings::values.resolution_info.ScaleUp(screen_info.texture.width),
Settings::values.resolution_info.ScaleUp(screen_info.texture.height));
glNamedFramebufferTexture(fxaa_framebuffer.handle, GL_COLOR_ATTACHMENT0, fxaa_texture.handle,
0);
}
void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
@@ -377,11 +426,6 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
state_tracker.ClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
// Update background color before drawing
glClearColor(Settings::values.bg_red.GetValue() / 255.0f,
Settings::values.bg_green.GetValue() / 255.0f,
Settings::values.bg_blue.GetValue() / 255.0f, 1.0f);
glEnable(GL_CULL_FACE);
glDisable(GL_COLOR_LOGIC_OP);
glDisable(GL_DEPTH_TEST);
@@ -394,12 +438,12 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
glCullFace(GL_BACK);
glFrontFace(GL_CW);
glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthRangeIndexed(0, 0.0, 0.0);
glBindTextureUnit(0, screen_info.display_texture);
if (Settings::values.anti_aliasing.GetValue() == Settings::AntiAliasing::Fxaa) {
program_manager.BindPresentPrograms(fxaa_vertex.handle, fxaa_fragment.handle);
const auto anti_aliasing = Settings::values.anti_aliasing.GetValue();
if (anti_aliasing != Settings::AntiAliasing::None) {
glEnablei(GL_SCISSOR_TEST, 0);
auto viewport_width = screen_info.texture.width;
auto scissor_width = framebuffer_crop_rect.GetWidth();
@@ -420,21 +464,60 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
glScissorIndexed(0, 0, 0, scissor_width, scissor_height);
glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(viewport_width),
static_cast<GLfloat>(viewport_height));
glDepthRangeIndexed(0, 0.0, 0.0);
glBindSampler(0, present_sampler.handle);
GLint old_read_fb;
GLint old_draw_fb;
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb);
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fxaa_framebuffer.handle);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
switch (anti_aliasing) {
case Settings::AntiAliasing::Fxaa: {
program_manager.BindPresentPrograms(fxaa_vertex.handle, fxaa_fragment.handle);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, aa_framebuffer.handle);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
} break;
case Settings::AntiAliasing::Smaa: {
glClearColor(0, 0, 0, 0);
glFrontFace(GL_CCW);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, aa_framebuffer.handle);
glBindSampler(1, present_sampler.handle);
glBindSampler(2, present_sampler.handle);
glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0,
smaa_edges_tex.handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
program_manager.BindPresentPrograms(smaa_edge_detection_vert.handle,
smaa_edge_detection_frag.handle);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindTextureUnit(0, smaa_edges_tex.handle);
glBindTextureUnit(1, smaa_area_tex.handle);
glBindTextureUnit(2, smaa_search_tex.handle);
glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0,
smaa_blend_tex.handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
program_manager.BindPresentPrograms(smaa_blending_weight_calculation_vert.handle,
smaa_blending_weight_calculation_frag.handle);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindTextureUnit(0, screen_info.display_texture);
glBindTextureUnit(1, smaa_blend_tex.handle);
glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0,
aa_texture.handle, 0);
program_manager.BindPresentPrograms(smaa_neighborhood_blending_vert.handle,
smaa_neighborhood_blending_frag.handle);
glDrawArrays(GL_TRIANGLES, 0, 3);
glFrontFace(GL_CW);
} break;
default:
UNREACHABLE();
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb);
glBindTextureUnit(0, fxaa_texture.handle);
glBindTextureUnit(0, aa_texture.handle);
}
const std::array ortho_matrix =
MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height));
@@ -551,6 +634,11 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
glBindSampler(0, present_sampler_nn.handle);
}
// Update background color before drawing
glClearColor(Settings::values.bg_red.GetValue() / 255.0f,
Settings::values.bg_green.GetValue() / 255.0f,
Settings::values.bg_blue.GetValue() / 255.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

View File

@@ -127,8 +127,19 @@ private:
/// Display information for Switch screen
ScreenInfo screen_info;
OGLTexture fxaa_texture;
OGLFramebuffer fxaa_framebuffer;
OGLTexture aa_texture;
OGLFramebuffer aa_framebuffer;
OGLProgram smaa_edge_detection_vert;
OGLProgram smaa_blending_weight_calculation_vert;
OGLProgram smaa_neighborhood_blending_vert;
OGLProgram smaa_edge_detection_frag;
OGLProgram smaa_blending_weight_calculation_frag;
OGLProgram smaa_neighborhood_blending_frag;
OGLTexture smaa_area_tex;
OGLTexture smaa_search_tex;
OGLTexture smaa_edges_tex;
OGLTexture smaa_blend_tex;
/// OpenGL framebuffer data
std::vector<u8> gl_framebuffer_data;

View File

@@ -139,23 +139,25 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
RenderScreenshot(*framebuffer, use_accelerated);
bool has_been_recreated = false;
const auto recreate_swapchain = [&] {
const auto recreate_swapchain = [&](u32 width, u32 height) {
if (!has_been_recreated) {
has_been_recreated = true;
scheduler.Finish();
}
const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout();
swapchain.Create(layout.width, layout.height, is_srgb);
swapchain.Create(width, height, is_srgb);
};
if (swapchain.NeedsRecreation(is_srgb)) {
recreate_swapchain();
const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout();
if (swapchain.NeedsRecreation(is_srgb) || swapchain.GetWidth() != layout.width ||
swapchain.GetHeight() != layout.height) {
recreate_swapchain(layout.width, layout.height);
}
bool is_outdated;
do {
swapchain.AcquireNextImage();
is_outdated = swapchain.IsOutDated();
if (is_outdated) {
recreate_swapchain();
recreate_swapchain(layout.width, layout.height);
}
} while (is_outdated);
if (has_been_recreated) {

View File

@@ -29,6 +29,7 @@
#include "video_core/renderer_vulkan/vk_fsr.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/renderer_vulkan/vk_smaa.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
#include "video_core/surface.h"
#include "video_core/textures/decoders.h"
@@ -156,6 +157,7 @@ VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
scheduler.Wait(resource_ticks[image_index]);
resource_ticks[image_index] = scheduler.CurrentTick();
VkImage source_image = use_accelerated ? screen_info.image : *raw_images[image_index];
VkImageView source_image_view =
use_accelerated ? screen_info.image_view : *raw_image_views[image_index];
@@ -242,7 +244,7 @@ VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
}
const auto anti_alias_pass = Settings::values.anti_aliasing.GetValue();
if (use_accelerated && anti_alias_pass != Settings::AntiAliasing::None) {
if (use_accelerated && anti_alias_pass == Settings::AntiAliasing::Fxaa) {
UpdateAADescriptorSet(image_index, source_image_view, false);
const u32 up_scale = Settings::values.resolution_info.up_scale;
const u32 down_shift = Settings::values.resolution_info.down_shift;
@@ -340,7 +342,18 @@ VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
});
source_image_view = *aa_image_view;
}
if (use_accelerated && anti_alias_pass == Settings::AntiAliasing::Smaa) {
if (!smaa) {
const u32 up_scale = Settings::values.resolution_info.up_scale;
const u32 down_shift = Settings::values.resolution_info.down_shift;
const VkExtent2D smaa_size{
.width = (up_scale * framebuffer.width) >> down_shift,
.height = (up_scale * framebuffer.height) >> down_shift,
};
CreateSMAA(smaa_size);
}
source_image_view = smaa->Draw(scheduler, image_index, source_image, source_image_view);
}
if (fsr) {
auto crop_rect = framebuffer.crop_rect;
if (crop_rect.GetWidth() == 0) {
@@ -467,6 +480,7 @@ void BlitScreen::CreateDynamicResources() {
CreateFramebuffers();
CreateGraphicsPipeline();
fsr.reset();
smaa.reset();
if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) {
CreateFSR();
}
@@ -490,6 +504,7 @@ void BlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer) {
raw_height = framebuffer.height;
pixel_format = framebuffer.pixel_format;
smaa.reset();
ReleaseRawImages();
CreateStagingBuffer(framebuffer);
@@ -1448,6 +1463,10 @@ void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig&
ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, left_start + right * scale_v);
}
void BlitScreen::CreateSMAA(VkExtent2D smaa_size) {
smaa = std::make_unique<SMAA>(device, memory_allocator, image_count, smaa_size);
}
void BlitScreen::CreateFSR() {
const auto& layout = render_window.GetFramebufferLayout();
const VkExtent2D fsr_size{

View File

@@ -40,9 +40,11 @@ class Device;
class FSR;
class RasterizerVulkan;
class Scheduler;
class SMAA;
class Swapchain;
struct ScreenInfo {
VkImage image{};
VkImageView image_view{};
u32 width{};
u32 height{};
@@ -101,6 +103,7 @@ private:
void SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer,
const Layout::FramebufferLayout layout) const;
void CreateSMAA(VkExtent2D smaa_size);
void CreateFSR();
u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const;
@@ -163,6 +166,7 @@ private:
Service::android::PixelFormat pixel_format{};
std::unique_ptr<FSR> fsr;
std::unique_ptr<SMAA> smaa;
};
} // namespace Vulkan

View File

@@ -285,6 +285,9 @@ void BufferCacheRuntime::BindQuadArrayIndexBuffer(u32 first, u32 count) {
void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size,
u32 stride) {
if (index >= device.GetMaxVertexInputBindings()) {
return;
}
if (device.IsExtExtendedDynamicStateSupported()) {
scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) {
const VkDeviceSize vk_offset = buffer != VK_NULL_HANDLE ? offset : 0;

View File

@@ -529,7 +529,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
static_vector<VkVertexInputBindingDivisorDescriptionEXT, 32> vertex_binding_divisors;
static_vector<VkVertexInputAttributeDescription, 32> vertex_attributes;
if (key.state.dynamic_vertex_input) {
for (size_t index = 0; index < key.state.attributes.size(); ++index) {
const size_t num_vertex_arrays = std::min(
key.state.attributes.size(), static_cast<size_t>(device.GetMaxVertexInputBindings()));
for (size_t index = 0; index < num_vertex_arrays; ++index) {
const u32 type = key.state.DynamicAttributeType(index);
if (!stage_infos[0].loads.Generic(index) || type == 0) {
continue;
@@ -551,7 +553,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
});
}
} else {
for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
const size_t num_vertex_arrays = std::min(
Maxwell::NumVertexArrays, static_cast<size_t>(device.GetMaxVertexInputBindings()));
for (size_t index = 0; index < num_vertex_arrays; ++index) {
const bool instanced = key.state.binding_divisors[index] != 0;
const auto rate =
instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
@@ -580,6 +584,8 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
});
}
}
ASSERT(vertex_attributes.size() <= device.GetMaxVertexInputAttributes());
VkPipelineVertexInputStateCreateInfo vertex_input_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.pNext = nullptr,

View File

@@ -341,6 +341,15 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
.support_snorm_render_buffer = true,
.support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(),
};
if (device.GetMaxVertexInputAttributes() < Maxwell::NumVertexAttributes) {
LOG_WARNING(Render_Vulkan, "maxVertexInputAttributes is too low: {} < {}",
device.GetMaxVertexInputAttributes(), Maxwell::NumVertexAttributes);
}
if (device.GetMaxVertexInputBindings() < Maxwell::NumVertexArrays) {
LOG_WARNING(Render_Vulkan, "maxVertexInputBindings is too low: {} < {}",
device.GetMaxVertexInputBindings(), Maxwell::NumVertexArrays);
}
}
PipelineCache::~PipelineCache() = default;

View File

@@ -216,9 +216,6 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) {
void RasterizerVulkan::Clear(u32 layer_count) {
MICROPROFILE_SCOPE(Vulkan_Clearing);
if (!maxwell3d->ShouldExecute()) {
return;
}
FlushWork();
query_cache.UpdateCounters();
@@ -583,6 +580,7 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config,
if (!image_view) {
return false;
}
screen_info.image = image_view->ImageHandle();
screen_info.image_view = image_view->Handle(Shader::TextureType::Color2D);
screen_info.width = image_view->size.width;
screen_info.height = image_view->size.height;

View File

@@ -0,0 +1,761 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <list>
#include "common/assert.h"
#include "common/polyfill_ranges.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/renderer_vulkan/vk_smaa.h"
#include "video_core/smaa_area_tex.h"
#include "video_core/smaa_search_tex.h"
#include "video_core/vulkan_common/vulkan_device.h"
#include "video_core/host_shaders/smaa_blending_weight_calculation_frag_spv.h"
#include "video_core/host_shaders/smaa_blending_weight_calculation_vert_spv.h"
#include "video_core/host_shaders/smaa_edge_detection_frag_spv.h"
#include "video_core/host_shaders/smaa_edge_detection_vert_spv.h"
#include "video_core/host_shaders/smaa_neighborhood_blending_frag_spv.h"
#include "video_core/host_shaders/smaa_neighborhood_blending_vert_spv.h"
namespace Vulkan {
namespace {
#define ARRAY_TO_SPAN(a) std::span(a, (sizeof(a) / sizeof(a[0])))
std::pair<vk::Image, MemoryCommit> CreateWrappedImage(const Device& device,
MemoryAllocator& allocator,
VkExtent2D dimensions, VkFormat format) {
const VkImageCreateInfo image_ci{
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.imageType = VK_IMAGE_TYPE_2D,
.format = format,
.extent = {.width = dimensions.width, .height = dimensions.height, .depth = 1},
.mipLevels = 1,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
};
auto image = device.GetLogical().CreateImage(image_ci);
auto commit = allocator.Commit(image, Vulkan::MemoryUsage::DeviceLocal);
return std::make_pair(std::move(image), std::move(commit));
}
void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout,
VkImageLayout source_layout = VK_IMAGE_LAYOUT_GENERAL) {
constexpr VkFlags flags{VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT};
const VkImageMemoryBarrier barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = flags,
.dstAccessMask = flags,
.oldLayout = source_layout,
.newLayout = target_layout,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, barrier);
}
void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler,
vk::Image& image, VkExtent2D dimensions, VkFormat format,
std::span<const u8> initial_contents = {}) {
auto upload_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = initial_contents.size_bytes(),
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
});
auto upload_commit = allocator.Commit(upload_buffer, MemoryUsage::Upload);
std::ranges::copy(initial_contents, upload_commit.Map().begin());
const std::array<VkBufferImageCopy, 1> regions{{{
.bufferOffset = 0,
.bufferRowLength = dimensions.width,
.bufferImageHeight = dimensions.height,
.imageSubresource{.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1},
.imageOffset{},
.imageExtent{.width = dimensions.width, .height = dimensions.height, .depth = 1},
}}};
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([&](vk::CommandBuffer cmdbuf) {
TransitionImageLayout(cmdbuf, *image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_UNDEFINED);
cmdbuf.CopyBufferToImage(*upload_buffer, *image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
regions);
TransitionImageLayout(cmdbuf, *image, VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
});
scheduler.Finish();
// This should go out of scope before the commit
auto upload_buffer2 = std::move(upload_buffer);
}
vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) {
return device.GetLogical().CreateImageView(VkImageViewCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.image = *image,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = format,
.components{},
.subresourceRange{.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1},
});
}
vk::RenderPass CreateWrappedRenderPass(const Device& device, VkFormat format) {
const VkAttachmentDescription attachment{
.flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT,
.format = format,
.samples = VK_SAMPLE_COUNT_1_BIT,
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
.initialLayout = VK_IMAGE_LAYOUT_GENERAL,
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
};
constexpr VkAttachmentReference color_attachment_ref{
.attachment = 0,
.layout = VK_IMAGE_LAYOUT_GENERAL,
};
const VkSubpassDescription subpass_description{
.flags = 0,
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.inputAttachmentCount = 0,
.pInputAttachments = nullptr,
.colorAttachmentCount = 1,
.pColorAttachments = &color_attachment_ref,
.pResolveAttachments = nullptr,
.pDepthStencilAttachment = nullptr,
.preserveAttachmentCount = 0,
.pPreserveAttachments = nullptr,
};
constexpr VkSubpassDependency dependency{
.srcSubpass = VK_SUBPASS_EXTERNAL,
.dstSubpass = 0,
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.dependencyFlags = 0,
};
return device.GetLogical().CreateRenderPass(VkRenderPassCreateInfo{
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.attachmentCount = 1,
.pAttachments = &attachment,
.subpassCount = 1,
.pSubpasses = &subpass_description,
.dependencyCount = 1,
.pDependencies = &dependency,
});
}
vk::Framebuffer CreateWrappedFramebuffer(const Device& device, vk::RenderPass& render_pass,
vk::ImageView& dest_image, VkExtent2D extent) {
return device.GetLogical().CreateFramebuffer(VkFramebufferCreateInfo{
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.renderPass = *render_pass,
.attachmentCount = 1,
.pAttachments = dest_image.address(),
.width = extent.width,
.height = extent.height,
.layers = 1,
});
}
vk::Sampler CreateWrappedSampler(const Device& device) {
return device.GetLogical().CreateSampler(VkSamplerCreateInfo{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.magFilter = VK_FILTER_LINEAR,
.minFilter = VK_FILTER_LINEAR,
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.mipLodBias = 0.0f,
.anisotropyEnable = VK_FALSE,
.maxAnisotropy = 0.0f,
.compareEnable = VK_FALSE,
.compareOp = VK_COMPARE_OP_NEVER,
.minLod = 0.0f,
.maxLod = 0.0f,
.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK,
.unnormalizedCoordinates = VK_FALSE,
});
}
vk::ShaderModule CreateWrappedShaderModule(const Device& device, std::span<const u32> code) {
return device.GetLogical().CreateShaderModule(VkShaderModuleCreateInfo{
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.codeSize = code.size_bytes(),
.pCode = code.data(),
});
}
vk::DescriptorPool CreateWrappedDescriptorPool(const Device& device, u32 max_descriptors,
u32 max_sets) {
const VkDescriptorPoolSize pool_size{
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = static_cast<u32>(max_descriptors),
};
return device.GetLogical().CreateDescriptorPool(VkDescriptorPoolCreateInfo{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.maxSets = max_sets,
.poolSizeCount = 1,
.pPoolSizes = &pool_size,
});
}
vk::DescriptorSetLayout CreateWrappedDescriptorSetLayout(const Device& device,
u32 max_sampler_bindings) {
std::vector<VkDescriptorSetLayoutBinding> bindings(max_sampler_bindings);
for (u32 i = 0; i < max_sampler_bindings; i++) {
bindings[i] = {
.binding = i,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
.pImmutableSamplers = nullptr,
};
}
return device.GetLogical().CreateDescriptorSetLayout(VkDescriptorSetLayoutCreateInfo{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.bindingCount = static_cast<u32>(bindings.size()),
.pBindings = bindings.data(),
});
}
vk::DescriptorSets CreateWrappedDescriptorSets(vk::DescriptorPool& pool,
vk::Span<VkDescriptorSetLayout> layouts) {
return pool.Allocate(VkDescriptorSetAllocateInfo{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.pNext = nullptr,
.descriptorPool = *pool,
.descriptorSetCount = layouts.size(),
.pSetLayouts = layouts.data(),
});
}
vk::PipelineLayout CreateWrappedPipelineLayout(const Device& device,
vk::DescriptorSetLayout& layout) {
return device.GetLogical().CreatePipelineLayout(VkPipelineLayoutCreateInfo{
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.setLayoutCount = 1,
.pSetLayouts = layout.address(),
.pushConstantRangeCount = 0,
.pPushConstantRanges = nullptr,
});
}
vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass,
vk::PipelineLayout& layout,
std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) {
const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.module = *std::get<0>(shaders),
.pName = "main",
.pSpecializationInfo = nullptr,
},
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.module = *std::get<1>(shaders),
.pName = "main",
.pSpecializationInfo = nullptr,
},
}};
constexpr VkPipelineVertexInputStateCreateInfo vertex_input_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.vertexBindingDescriptionCount = 0,
.pVertexBindingDescriptions = nullptr,
.vertexAttributeDescriptionCount = 0,
.pVertexAttributeDescriptions = nullptr,
};
constexpr VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
.primitiveRestartEnable = VK_FALSE,
};
constexpr VkPipelineViewportStateCreateInfo viewport_state_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.viewportCount = 1,
.pViewports = nullptr,
.scissorCount = 1,
.pScissors = nullptr,
};
constexpr VkPipelineRasterizationStateCreateInfo rasterization_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.depthClampEnable = VK_FALSE,
.rasterizerDiscardEnable = VK_FALSE,
.polygonMode = VK_POLYGON_MODE_FILL,
.cullMode = VK_CULL_MODE_NONE,
.frontFace = VK_FRONT_FACE_CLOCKWISE,
.depthBiasEnable = VK_FALSE,
.depthBiasConstantFactor = 0.0f,
.depthBiasClamp = 0.0f,
.depthBiasSlopeFactor = 0.0f,
.lineWidth = 1.0f,
};
constexpr VkPipelineMultisampleStateCreateInfo multisampling_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
.sampleShadingEnable = VK_FALSE,
.minSampleShading = 0.0f,
.pSampleMask = nullptr,
.alphaToCoverageEnable = VK_FALSE,
.alphaToOneEnable = VK_FALSE,
};
constexpr VkPipelineColorBlendAttachmentState color_blend_attachment{
.blendEnable = VK_FALSE,
.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
.colorBlendOp = VK_BLEND_OP_ADD,
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
.alphaBlendOp = VK_BLEND_OP_ADD,
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
};
const VkPipelineColorBlendStateCreateInfo color_blend_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.logicOpEnable = VK_FALSE,
.logicOp = VK_LOGIC_OP_COPY,
.attachmentCount = 1,
.pAttachments = &color_blend_attachment,
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
};
constexpr std::array dynamic_states{
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR,
};
const VkPipelineDynamicStateCreateInfo dynamic_state_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.dynamicStateCount = static_cast<u32>(dynamic_states.size()),
.pDynamicStates = dynamic_states.data(),
};
return device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.stageCount = static_cast<u32>(shader_stages.size()),
.pStages = shader_stages.data(),
.pVertexInputState = &vertex_input_ci,
.pInputAssemblyState = &input_assembly_ci,
.pTessellationState = nullptr,
.pViewportState = &viewport_state_ci,
.pRasterizationState = &rasterization_ci,
.pMultisampleState = &multisampling_ci,
.pDepthStencilState = nullptr,
.pColorBlendState = &color_blend_ci,
.pDynamicState = &dynamic_state_ci,
.layout = *layout,
.renderPass = *renderpass,
.subpass = 0,
.basePipelineHandle = 0,
.basePipelineIndex = 0,
});
}
VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images,
VkSampler sampler, VkImageView view,
VkDescriptorSet set, u32 binding) {
ASSERT(images.capacity() > images.size());
auto& image_info = images.emplace_back(VkDescriptorImageInfo{
.sampler = sampler,
.imageView = view,
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
});
return VkWriteDescriptorSet{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
.dstSet = set,
.dstBinding = binding,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = &image_info,
.pBufferInfo = nullptr,
.pTexelBufferView = nullptr,
};
}
void ClearColorImage(vk::CommandBuffer& cmdbuf, VkImage image) {
constexpr std::array<VkImageSubresourceRange, 1> subresources{{{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
}}};
TransitionImageLayout(cmdbuf, image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_UNDEFINED);
cmdbuf.ClearColorImage(image, VK_IMAGE_LAYOUT_GENERAL, {}, subresources);
}
void BeginRenderPass(vk::CommandBuffer& cmdbuf, vk::RenderPass& render_pass,
VkFramebuffer framebuffer, VkExtent2D extent) {
const VkRenderPassBeginInfo renderpass_bi{
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.pNext = nullptr,
.renderPass = *render_pass,
.framebuffer = framebuffer,
.renderArea{
.offset{},
.extent = extent,
},
.clearValueCount = 0,
.pClearValues = nullptr,
};
cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
const VkViewport viewport{
.x = 0.0f,
.y = 0.0f,
.width = static_cast<float>(extent.width),
.height = static_cast<float>(extent.height),
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
const VkRect2D scissor{
.offset = {0, 0},
.extent = extent,
};
cmdbuf.SetViewport(0, viewport);
cmdbuf.SetScissor(0, scissor);
}
} // Anonymous namespace
SMAA::SMAA(const Device& device, MemoryAllocator& allocator, size_t image_count, VkExtent2D extent)
: m_device(device), m_allocator(allocator), m_extent(extent),
m_image_count(static_cast<u32>(image_count)) {
CreateImages();
CreateRenderPasses();
CreateSampler();
CreateShaders();
CreateDescriptorPool();
CreateDescriptorSetLayouts();
CreateDescriptorSets();
CreatePipelineLayouts();
CreatePipelines();
}
void SMAA::CreateImages() {
constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT};
constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT};
std::tie(m_static_images[Area], m_static_buffer_commits[Area]) =
CreateWrappedImage(m_device, m_allocator, area_extent, VK_FORMAT_R8G8_UNORM);
std::tie(m_static_images[Search], m_static_buffer_commits[Search]) =
CreateWrappedImage(m_device, m_allocator, search_extent, VK_FORMAT_R8_UNORM);
m_static_image_views[Area] =
CreateWrappedImageView(m_device, m_static_images[Area], VK_FORMAT_R8G8_UNORM);
m_static_image_views[Search] =
CreateWrappedImageView(m_device, m_static_images[Search], VK_FORMAT_R8_UNORM);
for (u32 i = 0; i < m_image_count; i++) {
Images& images = m_dynamic_images.emplace_back();
std::tie(images.images[Blend], images.buffer_commits[Blend]) =
CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
std::tie(images.images[Edges], images.buffer_commits[Edges]) =
CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT);
std::tie(images.images[Output], images.buffer_commits[Output]) =
CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
images.image_views[Blend] =
CreateWrappedImageView(m_device, images.images[Blend], VK_FORMAT_R16G16B16A16_SFLOAT);
images.image_views[Edges] =
CreateWrappedImageView(m_device, images.images[Edges], VK_FORMAT_R16G16_SFLOAT);
images.image_views[Output] =
CreateWrappedImageView(m_device, images.images[Output], VK_FORMAT_R16G16B16A16_SFLOAT);
}
}
void SMAA::CreateRenderPasses() {
m_renderpasses[EdgeDetection] = CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16_SFLOAT);
m_renderpasses[BlendingWeightCalculation] =
CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT);
m_renderpasses[NeighborhoodBlending] =
CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT);
for (auto& images : m_dynamic_images) {
images.framebuffers[EdgeDetection] = CreateWrappedFramebuffer(
m_device, m_renderpasses[EdgeDetection], images.image_views[Edges], m_extent);
images.framebuffers[BlendingWeightCalculation] =
CreateWrappedFramebuffer(m_device, m_renderpasses[BlendingWeightCalculation],
images.image_views[Blend], m_extent);
images.framebuffers[NeighborhoodBlending] = CreateWrappedFramebuffer(
m_device, m_renderpasses[NeighborhoodBlending], images.image_views[Output], m_extent);
}
}
void SMAA::CreateSampler() {
m_sampler = CreateWrappedSampler(m_device);
}
void SMAA::CreateShaders() {
// These match the order of the SMAAStage enum
constexpr std::array vert_shader_sources{
ARRAY_TO_SPAN(SMAA_EDGE_DETECTION_VERT_SPV),
ARRAY_TO_SPAN(SMAA_BLENDING_WEIGHT_CALCULATION_VERT_SPV),
ARRAY_TO_SPAN(SMAA_NEIGHBORHOOD_BLENDING_VERT_SPV),
};
constexpr std::array frag_shader_sources{
ARRAY_TO_SPAN(SMAA_EDGE_DETECTION_FRAG_SPV),
ARRAY_TO_SPAN(SMAA_BLENDING_WEIGHT_CALCULATION_FRAG_SPV),
ARRAY_TO_SPAN(SMAA_NEIGHBORHOOD_BLENDING_FRAG_SPV),
};
for (size_t i = 0; i < MaxSMAAStage; i++) {
m_vertex_shaders[i] = CreateWrappedShaderModule(m_device, vert_shader_sources[i]);
m_fragment_shaders[i] = CreateWrappedShaderModule(m_device, frag_shader_sources[i]);
}
}
void SMAA::CreateDescriptorPool() {
// Edge detection: 1 descriptor
// Blending weight calculation: 3 descriptors
// Neighborhood blending: 2 descriptors
// 6 descriptors, 3 descriptor sets per image
m_descriptor_pool = CreateWrappedDescriptorPool(m_device, 6 * m_image_count, 3 * m_image_count);
}
void SMAA::CreateDescriptorSetLayouts() {
m_descriptor_set_layouts[EdgeDetection] = CreateWrappedDescriptorSetLayout(m_device, 1);
m_descriptor_set_layouts[BlendingWeightCalculation] =
CreateWrappedDescriptorSetLayout(m_device, 3);
m_descriptor_set_layouts[NeighborhoodBlending] = CreateWrappedDescriptorSetLayout(m_device, 2);
}
void SMAA::CreateDescriptorSets() {
std::vector<VkDescriptorSetLayout> layouts(m_descriptor_set_layouts.size());
std::ranges::transform(m_descriptor_set_layouts, layouts.begin(),
[](auto& layout) { return *layout; });
for (auto& images : m_dynamic_images) {
images.descriptor_sets = CreateWrappedDescriptorSets(m_descriptor_pool, layouts);
}
}
void SMAA::CreatePipelineLayouts() {
for (size_t i = 0; i < MaxSMAAStage; i++) {
m_pipeline_layouts[i] = CreateWrappedPipelineLayout(m_device, m_descriptor_set_layouts[i]);
}
}
void SMAA::CreatePipelines() {
for (size_t i = 0; i < MaxSMAAStage; i++) {
m_pipelines[i] =
CreateWrappedPipeline(m_device, m_renderpasses[i], m_pipeline_layouts[i],
std::tie(m_vertex_shaders[i], m_fragment_shaders[i]));
}
}
void SMAA::UpdateDescriptorSets(VkImageView image_view, size_t image_index) {
Images& images = m_dynamic_images[image_index];
std::vector<VkDescriptorImageInfo> image_infos;
std::vector<VkWriteDescriptorSet> updates;
image_infos.reserve(6);
updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, image_view,
images.descriptor_sets[EdgeDetection], 0));
updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *images.image_views[Edges],
images.descriptor_sets[BlendingWeightCalculation],
0));
updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *m_static_image_views[Area],
images.descriptor_sets[BlendingWeightCalculation],
1));
updates.push_back(
CreateWriteDescriptorSet(image_infos, *m_sampler, *m_static_image_views[Search],
images.descriptor_sets[BlendingWeightCalculation], 2));
updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, image_view,
images.descriptor_sets[NeighborhoodBlending], 0));
updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *images.image_views[Blend],
images.descriptor_sets[NeighborhoodBlending], 1));
m_device.GetLogical().UpdateDescriptorSets(updates, {});
}
void SMAA::UploadImages(Scheduler& scheduler) {
if (m_images_ready) {
return;
}
constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT};
constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT};
UploadImage(m_device, m_allocator, scheduler, m_static_images[Area], area_extent,
VK_FORMAT_R8G8_UNORM, ARRAY_TO_SPAN(areaTexBytes));
UploadImage(m_device, m_allocator, scheduler, m_static_images[Search], search_extent,
VK_FORMAT_R8_UNORM, ARRAY_TO_SPAN(searchTexBytes));
scheduler.Record([&](vk::CommandBuffer& cmdbuf) {
for (auto& images : m_dynamic_images) {
for (size_t i = 0; i < MaxDynamicImage; i++) {
ClearColorImage(cmdbuf, *images.images[i]);
}
}
});
scheduler.Finish();
m_images_ready = true;
}
VkImageView SMAA::Draw(Scheduler& scheduler, size_t image_index, VkImage source_image,
VkImageView source_image_view) {
Images& images = m_dynamic_images[image_index];
VkImage output_image = *images.images[Output];
VkImage edges_image = *images.images[Edges];
VkImage blend_image = *images.images[Blend];
VkDescriptorSet edge_detection_descriptor_set = images.descriptor_sets[EdgeDetection];
VkDescriptorSet blending_weight_calculation_descriptor_set =
images.descriptor_sets[BlendingWeightCalculation];
VkDescriptorSet neighborhood_blending_descriptor_set =
images.descriptor_sets[NeighborhoodBlending];
VkFramebuffer edge_detection_framebuffer = *images.framebuffers[EdgeDetection];
VkFramebuffer blending_weight_calculation_framebuffer =
*images.framebuffers[BlendingWeightCalculation];
VkFramebuffer neighborhood_blending_framebuffer = *images.framebuffers[NeighborhoodBlending];
UploadImages(scheduler);
UpdateDescriptorSets(source_image_view, image_index);
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([=, this](vk::CommandBuffer& cmdbuf) {
TransitionImageLayout(cmdbuf, source_image, VK_IMAGE_LAYOUT_GENERAL);
TransitionImageLayout(cmdbuf, edges_image, VK_IMAGE_LAYOUT_GENERAL);
BeginRenderPass(cmdbuf, m_renderpasses[EdgeDetection], edge_detection_framebuffer,
m_extent);
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelines[EdgeDetection]);
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS,
*m_pipeline_layouts[EdgeDetection], 0,
edge_detection_descriptor_set, {});
cmdbuf.Draw(3, 1, 0, 0);
cmdbuf.EndRenderPass();
TransitionImageLayout(cmdbuf, edges_image, VK_IMAGE_LAYOUT_GENERAL);
TransitionImageLayout(cmdbuf, blend_image, VK_IMAGE_LAYOUT_GENERAL);
BeginRenderPass(cmdbuf, m_renderpasses[BlendingWeightCalculation],
blending_weight_calculation_framebuffer, m_extent);
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS,
*m_pipelines[BlendingWeightCalculation]);
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS,
*m_pipeline_layouts[BlendingWeightCalculation], 0,
blending_weight_calculation_descriptor_set, {});
cmdbuf.Draw(3, 1, 0, 0);
cmdbuf.EndRenderPass();
TransitionImageLayout(cmdbuf, blend_image, VK_IMAGE_LAYOUT_GENERAL);
TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL);
BeginRenderPass(cmdbuf, m_renderpasses[NeighborhoodBlending],
neighborhood_blending_framebuffer, m_extent);
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelines[NeighborhoodBlending]);
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS,
*m_pipeline_layouts[NeighborhoodBlending], 0,
neighborhood_blending_descriptor_set, {});
cmdbuf.Draw(3, 1, 0, 0);
cmdbuf.EndRenderPass();
TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL);
});
return *images.image_views[Output];
}
} // namespace Vulkan

View File

@@ -0,0 +1,86 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan {
class Device;
class Scheduler;
class StagingBufferPool;
class SMAA {
public:
explicit SMAA(const Device& device, MemoryAllocator& allocator, size_t image_count,
VkExtent2D extent);
VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImage source_image,
VkImageView source_image_view);
private:
enum SMAAStage {
EdgeDetection = 0,
BlendingWeightCalculation = 1,
NeighborhoodBlending = 2,
MaxSMAAStage = 3,
};
enum StaticImageType {
Area = 0,
Search = 1,
MaxStaticImage = 2,
};
enum DynamicImageType {
Blend = 0,
Edges = 1,
Output = 2,
MaxDynamicImage = 3,
};
void CreateImages();
void CreateRenderPasses();
void CreateSampler();
void CreateShaders();
void CreateDescriptorPool();
void CreateDescriptorSetLayouts();
void CreateDescriptorSets();
void CreatePipelineLayouts();
void CreatePipelines();
void UpdateDescriptorSets(VkImageView image_view, size_t image_index);
void UploadImages(Scheduler& scheduler);
const Device& m_device;
MemoryAllocator& m_allocator;
const VkExtent2D m_extent;
const u32 m_image_count;
vk::DescriptorPool m_descriptor_pool{};
std::array<vk::DescriptorSetLayout, MaxSMAAStage> m_descriptor_set_layouts{};
std::array<vk::PipelineLayout, MaxSMAAStage> m_pipeline_layouts{};
std::array<vk::ShaderModule, MaxSMAAStage> m_vertex_shaders{};
std::array<vk::ShaderModule, MaxSMAAStage> m_fragment_shaders{};
std::array<vk::Pipeline, MaxSMAAStage> m_pipelines{};
std::array<vk::RenderPass, MaxSMAAStage> m_renderpasses{};
std::array<MemoryCommit, MaxStaticImage> m_static_buffer_commits;
std::array<vk::Image, MaxStaticImage> m_static_images{};
std::array<vk::ImageView, MaxStaticImage> m_static_image_views{};
struct Images {
vk::DescriptorSets descriptor_sets{};
std::array<MemoryCommit, MaxDynamicImage> buffer_commits;
std::array<vk::Image, MaxDynamicImage> images{};
std::array<vk::ImageView, MaxDynamicImage> image_views{};
std::array<vk::Framebuffer, MaxSMAAStage> framebuffers{};
};
std::vector<Images> m_dynamic_images{};
bool m_images_ready{};
vk::Sampler m_sampler{};
};
} // namespace Vulkan

View File

@@ -67,17 +67,19 @@ VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 wi
} // Anonymous namespace
Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, u32 width,
u32 height, bool srgb)
Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_,
u32 width_, u32 height_, bool srgb)
: surface{surface_}, device{device_}, scheduler{scheduler_} {
Create(width, height, srgb);
Create(width_, height_, srgb);
}
Swapchain::~Swapchain() = default;
void Swapchain::Create(u32 width, u32 height, bool srgb) {
void Swapchain::Create(u32 width_, u32 height_, bool srgb) {
is_outdated = false;
is_suboptimal = false;
width = width_;
height = height_;
const auto physical_device = device.GetPhysical();
const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface)};
@@ -88,7 +90,7 @@ void Swapchain::Create(u32 width, u32 height, bool srgb) {
device.GetLogical().WaitIdle();
Destroy();
CreateSwapchain(capabilities, width, height, srgb);
CreateSwapchain(capabilities, srgb);
CreateSemaphores();
CreateImageViews();
@@ -148,8 +150,7 @@ void Swapchain::Present(VkSemaphore render_semaphore) {
}
}
void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height,
bool srgb) {
void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) {
const auto physical_device{device.GetPhysical()};
const auto formats{physical_device.GetSurfaceFormatsKHR(surface)};
const auto present_modes{physical_device.GetSurfacePresentModesKHR(surface)};

View File

@@ -80,9 +80,16 @@ public:
return *present_semaphores[frame_index];
}
u32 GetWidth() const {
return width;
}
u32 GetHeight() const {
return height;
}
private:
void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height,
bool srgb);
void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb);
void CreateSemaphores();
void CreateImageViews();
@@ -105,6 +112,9 @@ private:
std::vector<u64> resource_ticks;
std::vector<vk::Semaphore> present_semaphores;
u32 width;
u32 height;
u32 image_index{};
u32 frame_index{};

11223
src/video_core/smaa_area_tex.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,88 @@
// SPDX-FileCopyrightText: 2013 Jorge Jimenez (jorge@iryoku.com)
// SPDX-FileCopyrightText: 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com)
// SPDX-FileCopyrightText: 2013 Belen Masia (bmasia@unizar.es)
// SPDX-FileCopyrightText: 2013 Fernando Navarro (fernandn@microsoft.com)
// SPDX-FileCopyrightText: 2013 Diego Gutierrez (diegog@unizar.es)
// SPDX-License-Identifier: MIT
#ifndef SEARCHTEX_H
#define SEARCHTEX_H
#define SEARCHTEX_WIDTH 64
#define SEARCHTEX_HEIGHT 16
#define SEARCHTEX_PITCH SEARCHTEX_WIDTH
#define SEARCHTEX_SIZE (SEARCHTEX_HEIGHT * SEARCHTEX_PITCH)
/**
* Stored in R8 format. Load it in the following format:
* - DX9: D3DFMT_L8
* - DX10: DXGI_FORMAT_R8_UNORM
*/
static const unsigned char searchTexBytes[] = {
0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
#endif

View File

@@ -64,10 +64,11 @@ float TSCEntry::MaxAnisotropy() const noexcept {
return 1.0f;
}
const auto anisotropic_settings = Settings::values.max_anisotropy.GetValue();
u32 added_anisotropic{};
s32 added_anisotropic{};
if (anisotropic_settings == 0) {
added_anisotropic = Settings::values.resolution_info.up_scale >>
Settings::values.resolution_info.down_shift;
added_anisotropic = std::max(added_anisotropic - 1, 0);
} else {
added_anisotropic = Settings::values.max_anisotropy.GetValue() - 1U;
}

View File

@@ -421,7 +421,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
VkPhysicalDevice8BitStorageFeatures bit8_storage{
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES,
.pNext = nullptr,
.storageBuffer8BitAccess = false,
.storageBuffer8BitAccess = true,
.uniformAndStorageBuffer8BitAccess = true,
.storagePushConstant8 = false,
};
@@ -1044,6 +1044,7 @@ void Device::CheckSuitability(bool requires_swapchain) const {
std::make_pair(bit16_storage.storageBuffer16BitAccess, "storageBuffer16BitAccess"),
std::make_pair(bit16_storage.uniformAndStorageBuffer16BitAccess,
"uniformAndStorageBuffer16BitAccess"),
std::make_pair(bit8_storage.storageBuffer8BitAccess, "storageBuffer8BitAccess"),
std::make_pair(bit8_storage.uniformAndStorageBuffer8BitAccess,
"uniformAndStorageBuffer8BitAccess"),
std::make_pair(host_query_reset.hostQueryReset, "hostQueryReset"),
@@ -1380,6 +1381,10 @@ void Device::SetupFeatures() {
is_shader_storage_image_multisample = features.shaderStorageImageMultisample;
is_blit_depth_stencil_supported = TestDepthStencilBlits();
is_optimal_astc_supported = IsOptimalAstcSupported(features);
const VkPhysicalDeviceLimits& limits{properties.limits};
max_vertex_input_attributes = limits.maxVertexInputAttributes;
max_vertex_input_bindings = limits.maxVertexInputBindings;
}
void Device::SetupProperties() {

View File

@@ -368,6 +368,14 @@ public:
return must_emulate_bgr565;
}
u32 GetMaxVertexInputAttributes() const {
return max_vertex_input_attributes;
}
u32 GetMaxVertexInputBindings() const {
return max_vertex_input_bindings;
}
private:
/// Checks if the physical device is suitable.
void CheckSuitability(bool requires_swapchain) const;
@@ -467,6 +475,8 @@ private:
bool supports_d24_depth{}; ///< Supports D24 depth buffers.
bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting.
bool must_emulate_bgr565{}; ///< Emulates BGR565 by swizzling RGB565 format.
u32 max_vertex_input_attributes{}; ///< Max vertex input attributes in pipeline
u32 max_vertex_input_bindings{}; ///< Max vertex input buffers in pipeline
// Telemetry parameters
std::string vendor_name; ///< Device's driver name.

View File

@@ -86,6 +86,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkCmdBindVertexBuffers);
X(vkCmdBlitImage);
X(vkCmdClearAttachments);
X(vkCmdClearColorImage);
X(vkCmdCopyBuffer);
X(vkCmdCopyBufferToImage);
X(vkCmdCopyImage);

View File

@@ -205,6 +205,7 @@ struct DeviceDispatch : InstanceDispatch {
PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT{};
PFN_vkCmdBlitImage vkCmdBlitImage{};
PFN_vkCmdClearAttachments vkCmdClearAttachments{};
PFN_vkCmdClearColorImage vkCmdClearColorImage{};
PFN_vkCmdCopyBuffer vkCmdCopyBuffer{};
PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage{};
PFN_vkCmdCopyImage vkCmdCopyImage{};
@@ -1024,6 +1025,11 @@ public:
rects.data());
}
void ClearColorImage(VkImage image, VkImageLayout layout, VkClearColorValue color,
Span<VkImageSubresourceRange> ranges) {
dld->vkCmdClearColorImage(handle, image, layout, &color, ranges.size(), ranges.data());
}
void BlitImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image,
VkImageLayout dst_layout, Span<VkImageBlit> regions,
VkFilter filter) const noexcept {

View File

@@ -402,7 +402,7 @@ if (MSVC)
copy_yuzu_FFmpeg_deps(yuzu)
endif()
if (NOT APPLE)
if (NOT APPLE AND ENABLE_OPENGL)
target_compile_definitions(yuzu PRIVATE HAS_OPENGL)
endif()

View File

@@ -61,8 +61,6 @@ void EmuThread::run() {
// Main process has been loaded. Make the context current to this thread and begin GPU and CPU
// execution.
gpu.Start();
gpu.ObtainContext();
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
@@ -77,6 +75,7 @@ void EmuThread::run() {
emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
gpu.ReleaseContext();
gpu.Start();
system.GetCpuManager().OnGpuReady();
@@ -224,6 +223,7 @@ class RenderWidget : public QWidget {
public:
explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) {
setAttribute(Qt::WA_NativeWindow);
setAttribute(Qt::WA_DontCreateNativeAncestors);
setAttribute(Qt::WA_PaintOnScreen);
}
@@ -314,6 +314,8 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
input_subsystem->Initialize();
this->setMouseTracking(true);
strict_context_required = QGuiApplication::platformName() == QStringLiteral("wayland");
connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram,
Qt::QueuedConnection);
@@ -952,6 +954,12 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal
bool GRenderWindow::InitializeOpenGL() {
#ifdef HAS_OPENGL
if (!QOpenGLContext::supportsThreadedOpenGL()) {
QMessageBox::warning(this, tr("OpenGL not available!"),
tr("OpenGL shared contexts are not supported."));
return false;
}
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
// WA_DontShowOnScreen, WA_DeleteOnClose
auto child = new OpenGLRenderWidget(this);

View File

@@ -697,7 +697,6 @@ void Config::ReadRendererValues() {
ReadGlobalSetting(Settings::values.fsr_sharpening_slider);
ReadGlobalSetting(Settings::values.anti_aliasing);
ReadGlobalSetting(Settings::values.max_anisotropy);
ReadGlobalSetting(Settings::values.use_speed_limit);
ReadGlobalSetting(Settings::values.speed_limit);
ReadGlobalSetting(Settings::values.use_disk_shader_cache);
ReadGlobalSetting(Settings::values.gpu_accuracy);
@@ -1328,7 +1327,6 @@ void Config::SaveRendererValues() {
static_cast<u32>(Settings::values.anti_aliasing.GetDefault()),
Settings::values.anti_aliasing.UsingGlobal());
WriteGlobalSetting(Settings::values.max_anisotropy);
WriteGlobalSetting(Settings::values.use_speed_limit);
WriteGlobalSetting(Settings::values.speed_limit);
WriteGlobalSetting(Settings::values.use_disk_shader_cache);
WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()),

View File

@@ -487,6 +487,11 @@
<string>FXAA</string>
</property>
</item>
<item>
<property name="text">
<string>SMAA</string>
</property>
</item>
</widget>
</item>
</layout>
@@ -524,6 +529,12 @@
</property>
<item>
<layout class="QHBoxLayout" name="fsr_sharpening_label_group">
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QComboBox" name="fsr_sharpening_combobox">
<property name="sizePolicy">

View File

@@ -1790,6 +1790,9 @@ void GMainWindow::ShutdownGame() {
AllowOSSleep();
// Disable unlimited frame rate
Settings::values.use_speed_limit.SetValue(true);
system->SetShuttingDown(true);
system->DetachDebugger();
discord_rpc->Pause();
@@ -2912,9 +2915,14 @@ static QScreen* GuessCurrentScreen(QWidget* window) {
});
}
bool GMainWindow::UsingExclusiveFullscreen() {
return Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive ||
QGuiApplication::platformName() == QStringLiteral("wayland");
}
void GMainWindow::ShowFullscreen() {
const auto show_fullscreen = [](QWidget* window) {
if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
const auto show_fullscreen = [this](QWidget* window) {
if (UsingExclusiveFullscreen()) {
window->showFullScreen();
return;
}
@@ -2942,7 +2950,7 @@ void GMainWindow::ShowFullscreen() {
void GMainWindow::HideFullscreen() {
if (ui->action_Single_Window_Mode->isChecked()) {
if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
if (UsingExclusiveFullscreen()) {
showNormal();
restoreGeometry(UISettings::values.geometry);
} else {
@@ -2956,7 +2964,7 @@ void GMainWindow::HideFullscreen() {
statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked());
ui->menubar->show();
} else {
if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
if (UsingExclusiveFullscreen()) {
render_window->showNormal();
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
} else {
@@ -3628,6 +3636,9 @@ void GMainWindow::UpdateAAText() {
case Settings::AntiAliasing::Fxaa:
aa_status_button->setText(tr("FXAA"));
break;
case Settings::AntiAliasing::Smaa:
aa_status_button->setText(tr("SMAA"));
break;
default:
aa_status_button->setText(tr("NO AA"));
break;

View File

@@ -320,6 +320,7 @@ private slots:
void OnDisplayTitleBars(bool);
void InitializeHotkeys();
void ToggleFullscreen();
bool UsingExclusiveFullscreen();
void ShowFullscreen();
void HideFullscreen();
void ToggleWindowMode();

View File

@@ -115,7 +115,7 @@ bool EmuWindow_SDL2::IsShown() const {
void EmuWindow_SDL2::OnResize() {
int width, height;
SDL_GetWindowSize(render_window, &width, &height);
SDL_GL_GetDrawableSize(render_window, &width, &height);
UpdateCurrentFramebufferLayout(width, height);
}

View File

@@ -104,6 +104,8 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsyste
exit(1);
}
strict_context_required = strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0;
SetWindowIcon();
if (fullscreen) {