Compare commits
46 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12c0f682e6 | ||
|
|
9ff891ce71 | ||
|
|
82d80869fc | ||
|
|
b8c03411e7 | ||
|
|
3ff7a5de1a | ||
|
|
4447c9a46e | ||
|
|
e2f32e8c88 | ||
|
|
beba9c9b61 | ||
|
|
a222f02c7a | ||
|
|
4fce72c902 | ||
|
|
77b0d01639 | ||
|
|
09e3029c11 | ||
|
|
2221afaf26 | ||
|
|
45fcde817e | ||
|
|
29fbce9fe6 | ||
|
|
5754456292 | ||
|
|
3cc3176ad6 | ||
|
|
d5f53da79d | ||
|
|
a4696285af | ||
|
|
f6868ae4dd | ||
|
|
0ed80c9818 | ||
|
|
339a37f8cb | ||
|
|
da58eb6208 | ||
|
|
b32b9524ad | ||
|
|
3e1e6c66c0 | ||
|
|
8ef9075b1b | ||
|
|
0c531ff911 | ||
|
|
d5684dbe7d | ||
|
|
ed37192441 | ||
|
|
623429a27e | ||
|
|
456322dde6 | ||
|
|
821da3ed54 | ||
|
|
8d1d6e149f | ||
|
|
1085bbb0a3 | ||
|
|
a5bc86a9ac | ||
|
|
6982423931 | ||
|
|
e532b74e11 | ||
|
|
985ed1e160 | ||
|
|
f6e705737a | ||
|
|
66c4331de5 | ||
|
|
c586ac9be2 | ||
|
|
5b837157bd | ||
|
|
37014e9127 | ||
|
|
1e64b5e2ec | ||
|
|
15d63c3d3d | ||
|
|
9704acb982 |
@@ -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)
|
||||
|
||||
4
externals/find-modules/FindOpus.cmake
vendored
4
externals/find-modules/FindOpus.cmake
vendored
@@ -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
|
||||
|
||||
4
externals/find-modules/Findenet.cmake
vendored
4
externals/find-modules/Findenet.cmake
vendored
@@ -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
|
||||
|
||||
4
externals/find-modules/Findhttplib.cmake
vendored
4
externals/find-modules/Findhttplib.cmake
vendored
@@ -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
|
||||
|
||||
4
externals/find-modules/Findinih.cmake
vendored
4
externals/find-modules/Findinih.cmake
vendored
@@ -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
|
||||
|
||||
4
externals/find-modules/Findlibusb.cmake
vendored
4
externals/find-modules/Findlibusb.cmake
vendored
@@ -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
|
||||
|
||||
4
externals/find-modules/Findlz4.cmake
vendored
4
externals/find-modules/Findlz4.cmake
vendored
@@ -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
|
||||
|
||||
4
externals/find-modules/Findzstd.cmake
vendored
4
externals/find-modules/Findzstd.cmake
vendored
@@ -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
|
||||
|
||||
@@ -16,7 +16,6 @@ class CommandGenerator;
|
||||
*/
|
||||
class DetailAspect {
|
||||
public:
|
||||
DetailAspect() = default;
|
||||
DetailAspect(CommandGenerator& command_generator, PerformanceEntryType entry_type, s32 node_id,
|
||||
PerformanceDetailType detail_type);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -76,7 +76,8 @@ enum class ScalingFilter : u32 {
|
||||
enum class AntiAliasing : u32 {
|
||||
None = 0,
|
||||
Fxaa = 1,
|
||||
LastAA = Fxaa,
|
||||
Smaa = 2,
|
||||
LastAA = Smaa,
|
||||
};
|
||||
|
||||
struct ResolutionScalingInfo {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>());
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
1339
src/video_core/host_shaders/opengl_smaa.glsl
Normal file
1339
src/video_core/host_shaders/opengl_smaa.glsl
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
26
src/video_core/host_shaders/smaa_edge_detection.frag
Normal file
26
src/video_core/host_shaders/smaa_edge_detection.frag
Normal 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);
|
||||
}
|
||||
40
src/video_core/host_shaders/smaa_edge_detection.vert
Normal file
40
src/video_core/host_shaders/smaa_edge_detection.vert
Normal 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);
|
||||
}
|
||||
31
src/video_core/host_shaders/smaa_neighborhood_blending.frag
Normal file
31
src/video_core/host_shaders/smaa_neighborhood_blending.frag
Normal 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
|
||||
);
|
||||
}
|
||||
41
src/video_core/host_shaders/smaa_neighborhood_blending.vert
Normal file
41
src/video_core/host_shaders/smaa_neighborhood_blending.vert
Normal 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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
761
src/video_core/renderer_vulkan/vk_smaa.cpp
Normal file
761
src/video_core/renderer_vulkan/vk_smaa.cpp
Normal 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
|
||||
86
src/video_core/renderer_vulkan/vk_smaa.h
Normal file
86
src/video_core/renderer_vulkan/vk_smaa.h
Normal 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
|
||||
@@ -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)};
|
||||
|
||||
@@ -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
11223
src/video_core/smaa_area_tex.h
Normal file
File diff suppressed because it is too large
Load Diff
88
src/video_core/smaa_search_tex.h
Normal file
88
src/video_core/smaa_search_tex.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -320,6 +320,7 @@ private slots:
|
||||
void OnDisplayTitleBars(bool);
|
||||
void InitializeHotkeys();
|
||||
void ToggleFullscreen();
|
||||
bool UsingExclusiveFullscreen();
|
||||
void ShowFullscreen();
|
||||
void HideFullscreen();
|
||||
void ToggleWindowMode();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user