mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-28 01:39:05 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b859d7fdf4 | |||
| f635827fa6 | |||
| 243453c172 | |||
| 39158b67a7 | |||
| 50cb8fd1c9 | |||
| faaf1bac64 |
@@ -19,6 +19,23 @@
|
|||||||
namespace AudioCore::Sink {
|
namespace AudioCore::Sink {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
[[nodiscard]] bool InitializeAudio() {
|
||||||
|
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
||||||
|
// See https://github.com/PCSX2/pcsx2/pull/12312
|
||||||
|
// "SDL and cubeb backends previously resulted in different names for the output which
|
||||||
|
// caused them be identified as different applications by the OS."
|
||||||
|
//
|
||||||
|
// Keep in sync with cubeb_sink.cpp name.
|
||||||
|
SDL_SetHint("SDL_AUDIO_DEVICE_APP_NAME", "yuzu Latency Getter");
|
||||||
|
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_AudioDeviceID FindAudioDeviceByName(const std::string& device_name, bool capture) {
|
SDL_AudioDeviceID FindAudioDeviceByName(const std::string& device_name, bool capture) {
|
||||||
int device_count = 0;
|
int device_count = 0;
|
||||||
SDL_AudioDeviceID* devices = capture ? SDL_GetAudioRecordingDevices(&device_count)
|
SDL_AudioDeviceID* devices = capture ? SDL_GetAudioRecordingDevices(&device_count)
|
||||||
@@ -204,20 +221,14 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
SDLSink::SDLSink(std::string_view target_device_name) {
|
SDLSink::SDLSink(std::string_view target_device_name) {
|
||||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
if (InitializeAudio()) {
|
||||||
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
|
if (target_device_name != auto_device_name && !target_device_name.empty()) {
|
||||||
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
|
output_device = target_device_name;
|
||||||
return;
|
} else {
|
||||||
|
output_device.clear();
|
||||||
}
|
}
|
||||||
|
device_channels = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target_device_name != auto_device_name && !target_device_name.empty()) {
|
|
||||||
output_device = target_device_name;
|
|
||||||
} else {
|
|
||||||
output_device.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
device_channels = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SDLSink::~SDLSink() = default;
|
SDLSink::~SDLSink() = default;
|
||||||
@@ -265,15 +276,10 @@ void SDLSink::SetSystemVolume(f32 volume) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> ListSDLSinkDevices(bool capture) {
|
std::vector<std::string> ListSDLSinkDevices(bool capture) {
|
||||||
|
if (!InitializeAudio())
|
||||||
|
return {}; //no devices
|
||||||
|
|
||||||
std::vector<std::string> device_list;
|
std::vector<std::string> device_list;
|
||||||
|
|
||||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
|
||||||
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
|
|
||||||
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int device_count = 0;
|
int device_count = 0;
|
||||||
SDL_AudioDeviceID* devices =
|
SDL_AudioDeviceID* devices =
|
||||||
capture ? SDL_GetAudioRecordingDevices(&device_count)
|
capture ? SDL_GetAudioRecordingDevices(&device_count)
|
||||||
@@ -304,13 +310,8 @@ bool IsSDLSuitable() {
|
|||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
// Check SDL can init
|
// Check SDL can init
|
||||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
if (!InitializeAudio()!
|
||||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
|
return false;
|
||||||
LOG_ERROR(Audio_Sink, "SDL failed to init, it is not suitable. Error: {}",
|
|
||||||
SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can set any latency frequency we want with SDL, so no need to check that.
|
// We can set any latency frequency we want with SDL, so no need to check that.
|
||||||
|
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ struct ColorConsoleBackend final : public Backend {
|
|||||||
auto const df = GetDirectFormatArgs(entry);
|
auto const df = GetDirectFormatArgs(entry);
|
||||||
// more restrictive, because take for example this simple prelude:
|
// more restrictive, because take for example this simple prelude:
|
||||||
// [ 50.872256] Config <Info> common/settings.cpp:142:LogSettings:
|
// [ 50.872256] Config <Info> common/settings.cpp:142:LogSettings:
|
||||||
char buffer[128];
|
char buffer[256];
|
||||||
auto result = fmt::format_to_n(buffer, sizeof(buffer) - 1, "\x1b{}[{:4d}.{:06d}] {} <{}> {}:{}:{}: ", color_str, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message);
|
auto result = fmt::format_to_n(buffer, sizeof(buffer) - 1, "\x1b{}[{:4d}.{:06d}] {} <{}> {}:{}:{}: ", color_str, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message);
|
||||||
std::fwrite(buffer, 1, (std::min)(sizeof(buffer) - 1, result.size), stdout);
|
std::fwrite(buffer, 1, (std::min)(sizeof(buffer) - 1, result.size), stdout);
|
||||||
std::fwrite(entry.message, 1, entry.message_len, stdout);
|
std::fwrite(entry.message, 1, entry.message_len, stdout);
|
||||||
@@ -425,14 +425,14 @@ void SetColorConsoleBackendEnabled(bool enabled) {
|
|||||||
|
|
||||||
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, unsigned int line_num, const char* function, fmt::string_view format, const fmt::format_args& args) {
|
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, unsigned int line_num, const char* function, fmt::string_view format, const fmt::format_args& args) {
|
||||||
if (logging_instance && logging_instance->filter.CheckMessage(log_class, log_level)) {
|
if (logging_instance && logging_instance->filter.CheckMessage(log_class, log_level)) {
|
||||||
|
auto const flush = ::Settings::values.log_flush_line.GetValue();
|
||||||
char buffer[BUFSIZ];
|
char buffer[BUFSIZ];
|
||||||
auto result = fmt::vformat_to_n(buffer, sizeof(buffer) - 1, format, args);
|
auto result = fmt::vformat_to_n(buffer, sizeof(buffer) - 1, format, args);
|
||||||
buffer[result.size] = '\0';
|
buffer[(std::min)(result.size, sizeof(buffer) - 1)] = '\0';
|
||||||
auto const flush = ::Settings::values.log_flush_line.GetValue();
|
|
||||||
logging_instance->ForEachBackend([=](Backend& backend) {
|
logging_instance->ForEachBackend([=](Backend& backend) {
|
||||||
backend.Write(Entry{
|
backend.Write(Entry{
|
||||||
.message = buffer,
|
.message = buffer,
|
||||||
.message_len = (std::min)(sizeof(buffer) - 1, result.size),
|
.message_len = (std::min)(result.size, sizeof(buffer) - 1),
|
||||||
.timestamp = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - logging_instance->time_origin),
|
.timestamp = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - logging_instance->time_origin),
|
||||||
.log_class = log_class,
|
.log_class = log_class,
|
||||||
.log_level = log_level,
|
.log_level = log_level,
|
||||||
|
|||||||
@@ -132,11 +132,9 @@ void LogSettings() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LOG_INFO(Config, "Eden Configuration:");
|
||||||
std::string settings_str{};
|
|
||||||
for (auto const& e : settings_list)
|
for (auto const& e : settings_list)
|
||||||
settings_str += e;
|
LOG_INFO(Config, "{}", e);
|
||||||
LOG_INFO(Config, "Eden Configuration:\n{}", settings_str);
|
|
||||||
#define LOG_PATH(NAME) \
|
#define LOG_PATH(NAME) \
|
||||||
LOG_INFO(Config, #NAME ": {}", Common::FS::PathToUTF8String(Common::FS::GetEdenPath(Common::FS::EdenPath::NAME)))
|
LOG_INFO(Config, #NAME ": {}", Common::FS::PathToUTF8String(Common::FS::GetEdenPath(Common::FS::EdenPath::NAME)))
|
||||||
LOG_PATH(CacheDir);
|
LOG_PATH(CacheDir);
|
||||||
|
|||||||
@@ -7,6 +7,4 @@
|
|||||||
#define STB_IMAGE_IMPLEMENTATION 1
|
#define STB_IMAGE_IMPLEMENTATION 1
|
||||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION 1
|
#define STB_IMAGE_RESIZE_IMPLEMENTATION 1
|
||||||
#define STB_IMAGE_WRITE_IMPLEMENTATION 1
|
#define STB_IMAGE_WRITE_IMPLEMENTATION 1
|
||||||
#define STBI_ONLY_JPEG 1
|
|
||||||
|
|
||||||
#include "common/stb.h"
|
#include "common/stb.h"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define STBI_ONLY_JPEG 1
|
#define STBI_ONLY_JPEG 1
|
||||||
|
#define STBI_WRITE_NO_STDIO 1
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
#include <stb_image_resize.h>
|
#include <stb_image_resize.h>
|
||||||
#include <stb_image_write.h>
|
#include <stb_image_write.h>
|
||||||
|
|||||||
@@ -9,11 +9,7 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#define STBI_ONLY_JPEG 1
|
#include "common/stb.h"
|
||||||
#include <stb_image.h>
|
|
||||||
#include <stb_image_resize.h>
|
|
||||||
#include <stb_image_write.h>
|
|
||||||
|
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/file_sys/control_metadata.h"
|
#include "core/file_sys/control_metadata.h"
|
||||||
#include "core/file_sys/patch_manager.h"
|
#include "core/file_sys/patch_manager.h"
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/logging.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "dynarmic/backend/exception_handler.h"
|
#include "dynarmic/backend/exception_handler.h"
|
||||||
#include "dynarmic/common/context.h"
|
#include "dynarmic/common/context.h"
|
||||||
@@ -53,23 +54,21 @@ class SigHandler {
|
|||||||
return e.first <= offset && e.first + e.second.size > offset;
|
return e.first <= offset && e.first + e.second.size > offset;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
static void SigAction(int sig, siginfo_t* info, void* raw_context);
|
|
||||||
|
|
||||||
bool supports_fast_mem = true;
|
|
||||||
void* signal_stack_memory = nullptr;
|
|
||||||
ankerl::unordered_dense::map<u64, CodeBlockInfo> code_block_infos;
|
ankerl::unordered_dense::map<u64, CodeBlockInfo> code_block_infos;
|
||||||
std::shared_mutex code_block_infos_mutex;
|
std::shared_mutex code_block_infos_mutex;
|
||||||
struct sigaction old_sa_segv;
|
struct sigaction old_sa_segv;
|
||||||
struct sigaction old_sa_bus;
|
struct sigaction old_sa_bus;
|
||||||
std::size_t signal_stack_size;
|
std::unique_ptr<uint8_t[]> signal_stack_memory;
|
||||||
|
bool supports_fast_mem = true;
|
||||||
public:
|
public:
|
||||||
SigHandler() noexcept {
|
SigHandler() noexcept {
|
||||||
signal_stack_size = std::max<size_t>(SIGSTKSZ, 2 * 1024 * 1024);
|
auto const stack_size = std::max<size_t>(SIGSTKSZ, 2 * 1024 * 1024);
|
||||||
signal_stack_memory = mmap(nullptr, signal_stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
signal_stack_memory = std::make_unique<uint8_t[]>(stack_size);
|
||||||
|
|
||||||
stack_t signal_stack{};
|
stack_t signal_stack{};
|
||||||
signal_stack.ss_sp = signal_stack_memory;
|
signal_stack.ss_sp = signal_stack_memory.get();
|
||||||
signal_stack.ss_size = signal_stack_size;
|
signal_stack.ss_size = stack_size;
|
||||||
signal_stack.ss_flags = 0;
|
signal_stack.ss_flags = 0;
|
||||||
if (sigaltstack(&signal_stack, nullptr) != 0) {
|
if (sigaltstack(&signal_stack, nullptr) != 0) {
|
||||||
fmt::print(stderr, "dynarmic: POSIX SigHandler: init failure at sigaltstack\n");
|
fmt::print(stderr, "dynarmic: POSIX SigHandler: init failure at sigaltstack\n");
|
||||||
@@ -87,7 +86,7 @@ public:
|
|||||||
supports_fast_mem = false;
|
supports_fast_mem = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef __APPLE__
|
#if defined(__APPLE__)
|
||||||
if (sigaction(SIGBUS, &sa, &old_sa_bus) != 0) {
|
if (sigaction(SIGBUS, &sa, &old_sa_bus) != 0) {
|
||||||
fmt::print(stderr, "dynarmic: POSIX SigHandler: could not set SIGBUS handler\n");
|
fmt::print(stderr, "dynarmic: POSIX SigHandler: could not set SIGBUS handler\n");
|
||||||
supports_fast_mem = false;
|
supports_fast_mem = false;
|
||||||
@@ -96,10 +95,6 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
~SigHandler() noexcept {
|
|
||||||
munmap(signal_stack_memory, signal_stack_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddCodeBlock(u64 offset, CodeBlockInfo cbi) noexcept {
|
void AddCodeBlock(u64 offset, CodeBlockInfo cbi) noexcept {
|
||||||
std::unique_lock guard(code_block_infos_mutex);
|
std::unique_lock guard(code_block_infos_mutex);
|
||||||
code_block_infos.insert_or_assign(offset, cbi);
|
code_block_infos.insert_or_assign(offset, cbi);
|
||||||
@@ -109,14 +104,17 @@ public:
|
|||||||
code_block_infos.erase(offset);
|
code_block_infos.erase(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SupportsFastmem() const noexcept { return supports_fast_mem; }
|
[[nodiscard]] inline bool SupportsFastmem() const noexcept {
|
||||||
|
return supports_fast_mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RegisterHandler();
|
||||||
|
static void SigAction(int sig, siginfo_t* info, void* raw_context);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::mutex handler_lock;
|
|
||||||
std::optional<SigHandler> sig_handler;
|
std::optional<SigHandler> sig_handler;
|
||||||
|
|
||||||
void RegisterHandler() {
|
void SigHandler::RegisterHandler() {
|
||||||
std::lock_guard<std::mutex> guard(handler_lock);
|
|
||||||
if (!sig_handler) {
|
if (!sig_handler) {
|
||||||
sig_handler.emplace();
|
sig_handler.emplace();
|
||||||
}
|
}
|
||||||
@@ -125,51 +123,27 @@ void RegisterHandler() {
|
|||||||
void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
|
void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
|
||||||
DEBUG_ASSERT(sig == SIGSEGV || sig == SIGBUS);
|
DEBUG_ASSERT(sig == SIGSEGV || sig == SIGBUS);
|
||||||
CTX_DECLARE(raw_context);
|
CTX_DECLARE(raw_context);
|
||||||
#if defined(ARCHITECTURE_x86_64)
|
|
||||||
{
|
{
|
||||||
std::shared_lock guard(sig_handler->code_block_infos_mutex);
|
std::shared_lock guard(sig_handler->code_block_infos_mutex);
|
||||||
if (auto const iter = sig_handler->FindCodeBlockInfo(CTX_PC); iter != sig_handler->code_block_infos.end()) {
|
if (auto const iter = sig_handler->FindCodeBlockInfo(CTX_PC); iter != sig_handler->code_block_infos.end()) {
|
||||||
FakeCall fc = iter->second.cb(CTX_PC);
|
FakeCall fc = iter->second.cb(CTX_PC);
|
||||||
|
#if defined(ARCHITECTURE_x86_64)
|
||||||
CTX_SP -= sizeof(u64);
|
CTX_SP -= sizeof(u64);
|
||||||
*std::bit_cast<u64*>(CTX_SP) = fc.ret_rip;
|
*std::bit_cast<u64*>(CTX_SP) = fc.ret_rip;
|
||||||
CTX_PC = fc.call_rip;
|
CTX_PC = fc.call_rip;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt::print(stderr, "Unhandled {} at rip {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
|
|
||||||
#elif defined(ARCHITECTURE_arm64)
|
#elif defined(ARCHITECTURE_arm64)
|
||||||
{
|
|
||||||
std::shared_lock guard(sig_handler->code_block_infos_mutex);
|
|
||||||
if (const auto iter = sig_handler->FindCodeBlockInfo(CTX_PC); iter != sig_handler->code_block_infos.end()) {
|
|
||||||
FakeCall fc = iter->second.cb(CTX_PC);
|
|
||||||
CTX_PC = fc.call_pc;
|
CTX_PC = fc.call_pc;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt::print(stderr, "Unhandled {} at pc {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
|
|
||||||
#elif defined(ARCHITECTURE_riscv64)
|
#elif defined(ARCHITECTURE_riscv64)
|
||||||
{
|
CTX_PC = fc.call_sepc;
|
||||||
std::shared_lock guard(sig_handler->code_block_infos_mutex);
|
|
||||||
if (const auto iter = sig_handler->FindCodeBlockInfo(CTX_SEPC); iter != sig_handler->code_block_infos.end()) {
|
|
||||||
FakeCall fc = iter->second.cb(CTX_SEPC);
|
|
||||||
CTX_SEPC = fc.call_sepc;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt::print(stderr, "Unhandled {} at pc {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_SEPC);
|
|
||||||
#elif defined(ARCHITECTURE_loongarch64)
|
#elif defined(ARCHITECTURE_loongarch64)
|
||||||
{
|
|
||||||
std::shared_lock guard(sig_handler->code_block_infos_mutex);
|
|
||||||
if (const auto iter = sig_handler->FindCodeBlockInfo(CTX_PC); iter != sig_handler->code_block_infos.end()) {
|
|
||||||
FakeCall fc = iter->second.cb(CTX_PC);
|
|
||||||
CTX_PC = fc.call_pc;
|
CTX_PC = fc.call_pc;
|
||||||
|
#else
|
||||||
|
ASSERT(false);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt::print(stderr, "Unhandled {} at pc {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
|
LOG_ERROR(Core, "Unhandled {} at {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
|
||||||
#else
|
|
||||||
# error "Invalid architecture"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct sigaction* retry_sa = sig == SIGSEGV ? &sig_handler->old_sa_segv : &sig_handler->old_sa_bus;
|
struct sigaction* retry_sa = sig == SIGSEGV ? &sig_handler->old_sa_segv : &sig_handler->old_sa_bus;
|
||||||
if (retry_sa->sa_flags & SA_SIGINFO) {
|
if (retry_sa->sa_flags & SA_SIGINFO) {
|
||||||
@@ -190,9 +164,10 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
|
|||||||
|
|
||||||
struct ExceptionHandler::Impl final {
|
struct ExceptionHandler::Impl final {
|
||||||
Impl(u64 offset_, u64 size_)
|
Impl(u64 offset_, u64 size_)
|
||||||
: offset(offset_)
|
: offset(offset_)
|
||||||
, size(size_) {
|
, size(size_)
|
||||||
RegisterHandler();
|
{
|
||||||
|
SigHandler::RegisterHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetCallback(std::function<FakeCall(u64)> cb) {
|
void SetCallback(std::function<FakeCall(u64)> cb) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
#include "dynarmic/backend/loongarch64/emit_loongarch64.h"
|
#include "dynarmic/backend/loongarch64/emit_loongarch64.h"
|
||||||
|
|
||||||
#include "dynarmic/backend/loongarch64/a32_jitstate.h"
|
#include "dynarmic/backend/loongarch64/a32_jitstate.h"
|
||||||
@@ -95,7 +96,8 @@ EmittedBlockInfo EmitLoongArch64(lagoon_assembler_t& as, IR::Block block, const
|
|||||||
|
|
||||||
// TODO: Emit Terminal
|
// TODO: Emit Terminal
|
||||||
const auto term = block.GetTerminal();
|
const auto term = block.GetTerminal();
|
||||||
const IR::Term::LinkBlock* link_block_term = boost::get<IR::Term::LinkBlock>(&term);
|
const IR::Term::LeafTerminal* leaft_term = std::get_if<IR::Term::LeafTerminal>(&term);
|
||||||
|
const IR::Term::LinkBlock* link_block_term = std::get_if<IR::Term::LinkBlock>(leaft_term);
|
||||||
ASSERT(link_block_term);
|
ASSERT(link_block_term);
|
||||||
la_load_immediate64(&as, Xscratch0, link_block_term->next.Value());
|
la_load_immediate64(&as, Xscratch0, link_block_term->next.Value());
|
||||||
la_st_w(&as, Xscratch0, Xstate, static_cast<int32_t>(offsetof(A32JitState, regs) + sizeof(u32) * 15));
|
la_st_w(&as, Xscratch0, Xstate, static_cast<int32_t>(offsetof(A32JitState, regs) + sizeof(u32) * 15));
|
||||||
|
|||||||
@@ -136,14 +136,14 @@
|
|||||||
# endif
|
# endif
|
||||||
#elif defined(ARCHITECTURE_riscv64)
|
#elif defined(ARCHITECTURE_riscv64)
|
||||||
# if defined(__FreeBSD__)
|
# if defined(__FreeBSD__)
|
||||||
# define CTX_SEPC (mctx.mc_gpregs.gp_sepc)
|
# define CTX_PC (mctx.mc_gpregs.gp_sepc)
|
||||||
# define CTX_SP (mctx.mc_gpregs.gp_sp)
|
# define CTX_SP (mctx.mc_gpregs.gp_sp)
|
||||||
# elif defined(__linux__)
|
# elif defined(__linux__)
|
||||||
# define CTX_SEPC (mctx.__gregs[REG_PC])
|
# define CTX_PC (mctx.__gregs[REG_PC])
|
||||||
# define CTX_SP (mctx.__gregs[REG_SP])
|
# define CTX_SP (mctx.__gregs[REG_SP])
|
||||||
# elif defined(__OpenBSD__)
|
# elif defined(__OpenBSD__)
|
||||||
// https://github.com/openbsd/src/blob/master/sys/arch/riscv64/include/signal.h
|
// https://github.com/openbsd/src/blob/master/sys/arch/riscv64/include/signal.h
|
||||||
# define CTX_SEPC (ucontext->sc_sepc)
|
# define CTX_PC (ucontext->sc_sepc)
|
||||||
# define CTX_SP (ucontext->sc_sp)
|
# define CTX_SP (ucontext->sc_sp)
|
||||||
# else
|
# else
|
||||||
# error "unknown platform"
|
# error "unknown platform"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -665,6 +665,8 @@ void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU3
|
|||||||
const IR::Value& clamp, const IR::Value& segmentation_mask);
|
const IR::Value& clamp, const IR::Value& segmentation_mask);
|
||||||
void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index,
|
void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index,
|
||||||
const IR::Value& clamp, const IR::Value& segmentation_mask);
|
const IR::Value& clamp, const IR::Value& segmentation_mask);
|
||||||
|
void EmitQuadBroadcast(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 lane);
|
||||||
|
void EmitQuadSwap(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 direction);
|
||||||
void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, ScalarF32 op_a, ScalarF32 op_b,
|
void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, ScalarF32 op_a, ScalarF32 op_b,
|
||||||
ScalarU32 swizzle);
|
ScalarU32 swizzle);
|
||||||
void EmitDPdxFine(EmitContext& ctx, IR::Inst& inst, ScalarF32 op_a);
|
void EmitDPdxFine(EmitContext& ctx, IR::Inst& inst, ScalarF32 op_a);
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -97,6 +100,24 @@ void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, Sca
|
|||||||
Shuffle(ctx, inst, value, index, clamp, segmentation_mask, "XOR");
|
Shuffle(ctx, inst, value, index, clamp, segmentation_mask, "XOR");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitQuadBroadcast(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 lane) {
|
||||||
|
const Register ret{ctx.reg_alloc.Define(inst)};
|
||||||
|
ctx.Add("AND.U RC.x,{}.threadid,~3;"
|
||||||
|
"AND.U RC.y,{},3;"
|
||||||
|
"OR.U RC.x,RC.x,RC.y;"
|
||||||
|
"SHFIDX.U {},{},RC.x,0x1C03;"
|
||||||
|
"MOV.U {}.x,{}.y;",
|
||||||
|
ctx.stage_name, lane, ret, value, ret, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitQuadSwap(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 direction) {
|
||||||
|
const Register ret{ctx.reg_alloc.Define(inst)};
|
||||||
|
ctx.Add("ADD.U RC.x,{},1;"
|
||||||
|
"SHFXOR.U {},{},RC.x,0x1C03;"
|
||||||
|
"MOV.U {}.x,{}.y;",
|
||||||
|
direction, ret, value, ret, ret);
|
||||||
|
}
|
||||||
|
|
||||||
void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, ScalarF32 op_a, ScalarF32 op_b,
|
void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, ScalarF32 op_a, ScalarF32 op_b,
|
||||||
ScalarU32 swizzle) {
|
ScalarU32 swizzle) {
|
||||||
const auto ret{ctx.reg_alloc.Define(inst)};
|
const auto ret{ctx.reg_alloc.Define(inst)};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -743,6 +743,10 @@ void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
|||||||
void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||||
std::string_view index, std::string_view clamp,
|
std::string_view index, std::string_view clamp,
|
||||||
std::string_view segmentation_mask);
|
std::string_view segmentation_mask);
|
||||||
|
void EmitQuadBroadcast(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||||
|
std::string_view lane);
|
||||||
|
void EmitQuadSwap(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||||
|
std::string_view direction);
|
||||||
void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, std::string_view op_a, std::string_view op_b,
|
void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, std::string_view op_a, std::string_view op_b,
|
||||||
std::string_view swizzle);
|
std::string_view swizzle);
|
||||||
void EmitDPdxFine(EmitContext& ctx, IR::Inst& inst, std::string_view op_a);
|
void EmitDPdxFine(EmitContext& ctx, IR::Inst& inst, std::string_view op_a);
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -200,6 +203,18 @@ void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view val
|
|||||||
ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
|
ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitQuadBroadcast(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||||
|
std::string_view lane) {
|
||||||
|
const auto src_thread_id{fmt::format("(({}&~3)|({}& 3))", THREAD_ID, lane)};
|
||||||
|
ctx.AddU32("{}=readInvocationARB({},{});", inst, value, src_thread_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitQuadSwap(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||||
|
std::string_view direction) {
|
||||||
|
const auto src_thread_id{fmt::format("({}^({}+1))", THREAD_ID, direction)};
|
||||||
|
ctx.AddU32("{}=readInvocationARB({},{});", inst, value, src_thread_id);
|
||||||
|
}
|
||||||
|
|
||||||
void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, std::string_view op_a, std::string_view op_b,
|
void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, std::string_view op_a, std::string_view op_b,
|
||||||
std::string_view swizzle) {
|
std::string_view swizzle) {
|
||||||
const auto mask{fmt::format("({}>>((gl_SubGroupInvocationARB&3)<<1))&3", swizzle)};
|
const auto mask{fmt::format("({}>>((gl_SubGroupInvocationARB&3)<<1))&3", swizzle)};
|
||||||
|
|||||||
@@ -322,6 +322,11 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
|
|||||||
if (ctx.runtime_info.force_early_z) {
|
if (ctx.runtime_info.force_early_z) {
|
||||||
ctx.AddExecutionMode(main, spv::ExecutionMode::EarlyFragmentTests);
|
ctx.AddExecutionMode(main, spv::ExecutionMode::EarlyFragmentTests);
|
||||||
}
|
}
|
||||||
|
if (ctx.profile.support_shader_quad_control && program.info.uses_quad_shuffles) {
|
||||||
|
ctx.AddExtension("SPV_KHR_quad_control");
|
||||||
|
ctx.AddCapability(spv::Capability::QuadControlKHR);
|
||||||
|
ctx.AddExecutionMode(main, spv::ExecutionMode::RequireFullQuadsKHR);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException("Stage {}", program.stage);
|
throw NotImplementedException("Stage {}", program.stage);
|
||||||
@@ -443,6 +448,12 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
|
|||||||
ctx.AddCapability(spv::Capability::GroupNonUniformVote);
|
ctx.AddCapability(spv::Capability::GroupNonUniformVote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (info.uses_quad_shuffles) {
|
||||||
|
if (profile.support_quad_shuffles) {
|
||||||
|
ctx.AddCapability(spv::Capability::GroupNonUniformQuad);
|
||||||
|
}
|
||||||
|
ctx.AddCapability(spv::Capability::GroupNonUniformShuffle);
|
||||||
|
}
|
||||||
if (info.uses_int64_bit_atomics && profile.support_int64_atomics) {
|
if (info.uses_int64_bit_atomics && profile.support_int64_atomics) {
|
||||||
ctx.AddCapability(spv::Capability::Int64Atomics);
|
ctx.AddCapability(spv::Capability::Int64Atomics);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -622,6 +622,8 @@ Id EmitShuffleDown(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clam
|
|||||||
Id segmentation_mask);
|
Id segmentation_mask);
|
||||||
Id EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
|
Id EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
|
||||||
Id segmentation_mask);
|
Id segmentation_mask);
|
||||||
|
Id EmitQuadBroadcast(EmitContext& ctx, Id value, Id lane);
|
||||||
|
Id EmitQuadSwap(EmitContext& ctx, Id value, Id direction);
|
||||||
Id EmitFSwizzleAdd(EmitContext& ctx, Id op_a, Id op_b, Id swizzle);
|
Id EmitFSwizzleAdd(EmitContext& ctx, Id op_a, Id op_b, Id swizzle);
|
||||||
Id EmitDPdxFine(EmitContext& ctx, Id op_a);
|
Id EmitDPdxFine(EmitContext& ctx, Id op_a);
|
||||||
Id EmitDPdyFine(EmitContext& ctx, Id op_a);
|
Id EmitDPdyFine(EmitContext& ctx, Id op_a);
|
||||||
|
|||||||
@@ -260,6 +260,21 @@ Id EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id
|
|||||||
return SelectValue(ctx, in_range, value, src_thread_id);
|
return SelectValue(ctx, in_range, value, src_thread_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Id EmitQuadBroadcast(EmitContext& ctx, Id value, Id lane) {
|
||||||
|
if (ctx.profile.support_quad_shuffles) {
|
||||||
|
return ctx.OpGroupNonUniformQuadBroadcast(ctx.U32[1], SubgroupScope(ctx), value, lane);
|
||||||
|
}
|
||||||
|
const Id base{ctx.OpBitwiseAnd(ctx.U32[1], GetThreadId(ctx), ctx.Const(~3u))};
|
||||||
|
const Id local_lane{ctx.OpBitwiseAnd(ctx.U32[1], lane, ctx.Const(3u))};
|
||||||
|
const Id src_thread_id{ctx.OpBitwiseOr(ctx.U32[1], base, local_lane)};
|
||||||
|
return ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Id EmitQuadSwap(EmitContext& ctx, Id value, Id direction) {
|
||||||
|
const Id xor_mask{ctx.OpIAdd(ctx.U32[1], direction, ctx.Const(1u))};
|
||||||
|
return ctx.OpGroupNonUniformShuffleXor(ctx.U32[1], SubgroupScope(ctx), value, xor_mask);
|
||||||
|
}
|
||||||
|
|
||||||
Id EmitFSwizzleAdd(EmitContext& ctx, Id op_a, Id op_b, Id swizzle) {
|
Id EmitFSwizzleAdd(EmitContext& ctx, Id op_a, Id op_b, Id swizzle) {
|
||||||
const Id three{ctx.Const(3U)};
|
const Id three{ctx.Const(3U)};
|
||||||
Id mask{GetThreadId(ctx)};
|
Id mask{GetThreadId(ctx)};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -2100,6 +2100,14 @@ U32 IREmitter::ShuffleButterfly(const IR::U32& value, const IR::U32& index, cons
|
|||||||
return Inst<U32>(Opcode::ShuffleButterfly, value, index, clamp, seg_mask);
|
return Inst<U32>(Opcode::ShuffleButterfly, value, index, clamp, seg_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U32 IREmitter::QuadBroadcast(const IR::U32& value, const IR::U32& lane) {
|
||||||
|
return Inst<U32>(Opcode::QuadBroadcast, value, lane);
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 IREmitter::QuadSwap(const IR::U32& value, const IR::U32& direction) {
|
||||||
|
return Inst<U32>(Opcode::QuadSwap, value, direction);
|
||||||
|
}
|
||||||
|
|
||||||
F32 IREmitter::FSwizzleAdd(const F32& a, const F32& b, const U32& swizzle, FpControl control) {
|
F32 IREmitter::FSwizzleAdd(const F32& a, const F32& b, const U32& swizzle, FpControl control) {
|
||||||
return Inst<F32>(Opcode::FSwizzleAdd, Flags{control}, a, b, swizzle);
|
return Inst<F32>(Opcode::FSwizzleAdd, Flags{control}, a, b, swizzle);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -394,6 +394,8 @@ public:
|
|||||||
const IR::U32& seg_mask);
|
const IR::U32& seg_mask);
|
||||||
[[nodiscard]] U32 ShuffleButterfly(const IR::U32& value, const IR::U32& index,
|
[[nodiscard]] U32 ShuffleButterfly(const IR::U32& value, const IR::U32& index,
|
||||||
const IR::U32& clamp, const IR::U32& seg_mask);
|
const IR::U32& clamp, const IR::U32& seg_mask);
|
||||||
|
[[nodiscard]] U32 QuadBroadcast(const IR::U32& value, const IR::U32& lane);
|
||||||
|
[[nodiscard]] U32 QuadSwap(const IR::U32& value, const IR::U32& direction);
|
||||||
[[nodiscard]] F32 FSwizzleAdd(const F32& a, const F32& b, const U32& swizzle,
|
[[nodiscard]] F32 FSwizzleAdd(const F32& a, const F32& b, const U32& swizzle,
|
||||||
FpControl control = {});
|
FpControl control = {});
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace Shader::IR {
|
|||||||
|
|
||||||
namespace Detail {
|
namespace Detail {
|
||||||
|
|
||||||
OpcodeMeta META_TABLE[532] = {
|
OpcodeMeta META_TABLE[534] = {
|
||||||
#define OPCODE(name_token, type_token, ...) \
|
#define OPCODE(name_token, type_token, ...) \
|
||||||
{ \
|
{ \
|
||||||
.name{#name_token}, \
|
.name{#name_token}, \
|
||||||
@@ -21,7 +21,7 @@ OpcodeMeta META_TABLE[532] = {
|
|||||||
#undef OPCODE
|
#undef OPCODE
|
||||||
};
|
};
|
||||||
|
|
||||||
u8 NUM_ARGS[532] = {
|
u8 NUM_ARGS[534] = {
|
||||||
#define OPCODE(name_token, type_token, ...) u8(CalculateNumArgsOf(Opcode::name_token)),
|
#define OPCODE(name_token, type_token, ...) u8(CalculateNumArgsOf(Opcode::name_token)),
|
||||||
#include "opcodes.inc"
|
#include "opcodes.inc"
|
||||||
#undef OPCODE
|
#undef OPCODE
|
||||||
|
|||||||
@@ -57,12 +57,12 @@ static constexpr Type F64x2{Type::F64x2};
|
|||||||
static constexpr Type F64x3{Type::F64x3};
|
static constexpr Type F64x3{Type::F64x3};
|
||||||
static constexpr Type F64x4{Type::F64x4};
|
static constexpr Type F64x4{Type::F64x4};
|
||||||
|
|
||||||
extern OpcodeMeta META_TABLE[532];
|
extern OpcodeMeta META_TABLE[534];
|
||||||
constexpr size_t CalculateNumArgsOf(Opcode op) noexcept {
|
constexpr size_t CalculateNumArgsOf(Opcode op) noexcept {
|
||||||
const auto& arg_types = META_TABLE[size_t(op)].arg_types;
|
const auto& arg_types = META_TABLE[size_t(op)].arg_types;
|
||||||
return size_t(std::distance(arg_types.begin(), std::ranges::find(arg_types, Type::Void)));
|
return size_t(std::distance(arg_types.begin(), std::ranges::find(arg_types, Type::Void)));
|
||||||
}
|
}
|
||||||
extern u8 NUM_ARGS[532];
|
extern u8 NUM_ARGS[534];
|
||||||
} // namespace Detail
|
} // namespace Detail
|
||||||
|
|
||||||
/// Get return type of an opcode
|
/// Get return type of an opcode
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -579,6 +582,8 @@ OPCODE(ShuffleIndex, U32, U32,
|
|||||||
OPCODE(ShuffleUp, U32, U32, U32, U32, U32, )
|
OPCODE(ShuffleUp, U32, U32, U32, U32, U32, )
|
||||||
OPCODE(ShuffleDown, U32, U32, U32, U32, U32, )
|
OPCODE(ShuffleDown, U32, U32, U32, U32, U32, )
|
||||||
OPCODE(ShuffleButterfly, U32, U32, U32, U32, U32, )
|
OPCODE(ShuffleButterfly, U32, U32, U32, U32, U32, )
|
||||||
|
OPCODE(QuadBroadcast, U32, U32, U32, )
|
||||||
|
OPCODE(QuadSwap, U32, U32, U32, )
|
||||||
OPCODE(FSwizzleAdd, F32, F32, F32, U32, )
|
OPCODE(FSwizzleAdd, F32, F32, F32, U32, )
|
||||||
OPCODE(DPdxFine, F32, F32, )
|
OPCODE(DPdxFine, F32, F32, )
|
||||||
OPCODE(DPdyFine, F32, F32, )
|
OPCODE(DPdyFine, F32, F32, )
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -36,7 +36,10 @@ enum class ShuffleMode : u64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shuffle(TranslatorVisitor& v, u64 insn, const IR::U32& index, const IR::U32& mask) {
|
constexpr u32 QUAD_MASK = (28u << 8) | 3u;
|
||||||
|
|
||||||
|
void Shuffle(TranslatorVisitor& v, u64 insn, const IR::U32& index, const IR::U32& mask,
|
||||||
|
bool index_is_imm, u32 index_imm, bool mask_is_imm, u32 mask_imm) {
|
||||||
union {
|
union {
|
||||||
u64 insn;
|
u64 insn;
|
||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
@@ -45,6 +48,21 @@ void Shuffle(TranslatorVisitor& v, u64 insn, const IR::U32& index, const IR::U32
|
|||||||
BitField<48, 3, IR::Pred> pred;
|
BitField<48, 3, IR::Pred> pred;
|
||||||
} const shfl{insn};
|
} const shfl{insn};
|
||||||
|
|
||||||
|
const bool is_quad_candidate{mask_is_imm && mask_imm == QUAD_MASK && index_is_imm &&
|
||||||
|
v.env.ShaderStage() == Stage::Fragment};
|
||||||
|
if (is_quad_candidate) {
|
||||||
|
if (shfl.mode == ShuffleMode::IDX && index_imm <= 3) {
|
||||||
|
v.X(shfl.dest_reg, v.ir.QuadBroadcast(v.X(shfl.src_reg), v.ir.Imm32(index_imm)));
|
||||||
|
v.ir.SetPred(shfl.pred, v.ir.Imm1(true));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (shfl.mode == ShuffleMode::BFLY && index_imm >= 1 && index_imm <= 3) {
|
||||||
|
v.X(shfl.dest_reg, v.ir.QuadSwap(v.X(shfl.src_reg), v.ir.Imm32(index_imm - 1)));
|
||||||
|
v.ir.SetPred(shfl.pred, v.ir.Imm1(true));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const IR::U32 result{ShuffleOperation(v.ir, v.X(shfl.src_reg), index, mask, shfl.mode)};
|
const IR::U32 result{ShuffleOperation(v.ir, v.X(shfl.src_reg), index, mask, shfl.mode)};
|
||||||
v.ir.SetPred(shfl.pred, v.ir.GetInBoundsFromOp(result));
|
v.ir.SetPred(shfl.pred, v.ir.GetInBoundsFromOp(result));
|
||||||
v.X(shfl.dest_reg, result);
|
v.X(shfl.dest_reg, result);
|
||||||
@@ -59,11 +77,14 @@ void TranslatorVisitor::SHFL(u64 insn) {
|
|||||||
BitField<29, 1, u64> src_b_flag;
|
BitField<29, 1, u64> src_b_flag;
|
||||||
BitField<34, 13, u64> src_b_imm;
|
BitField<34, 13, u64> src_b_imm;
|
||||||
} const flags{insn};
|
} const flags{insn};
|
||||||
const IR::U32 src_a{flags.src_a_flag != 0 ? ir.Imm32(static_cast<u32>(flags.src_a_imm))
|
const bool index_is_imm{flags.src_a_flag != 0};
|
||||||
: GetReg20(insn)};
|
const bool mask_is_imm{flags.src_b_flag != 0};
|
||||||
const IR::U32 src_b{flags.src_b_flag != 0 ? ir.Imm32(static_cast<u32>(flags.src_b_imm))
|
const IR::U32 src_a{index_is_imm ? ir.Imm32(static_cast<u32>(flags.src_a_imm))
|
||||||
: GetReg39(insn)};
|
: GetReg20(insn)};
|
||||||
Shuffle(*this, insn, src_a, src_b);
|
const IR::U32 src_b{mask_is_imm ? ir.Imm32(static_cast<u32>(flags.src_b_imm))
|
||||||
|
: GetReg39(insn)};
|
||||||
|
Shuffle(*this, insn, src_a, src_b, index_is_imm, static_cast<u32>(flags.src_a_imm),
|
||||||
|
mask_is_imm, static_cast<u32>(flags.src_b_imm));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Shader::Maxwell
|
} // namespace Shader::Maxwell
|
||||||
|
|||||||
@@ -498,6 +498,10 @@ void VisitUsages(Info& info, IR::Inst& inst) {
|
|||||||
case IR::Opcode::ShuffleButterfly:
|
case IR::Opcode::ShuffleButterfly:
|
||||||
info.uses_subgroup_shuffles = true;
|
info.uses_subgroup_shuffles = true;
|
||||||
break;
|
break;
|
||||||
|
case IR::Opcode::QuadBroadcast:
|
||||||
|
case IR::Opcode::QuadSwap:
|
||||||
|
info.uses_quad_shuffles = true;
|
||||||
|
break;
|
||||||
case IR::Opcode::GetCbufU8:
|
case IR::Opcode::GetCbufU8:
|
||||||
case IR::Opcode::GetCbufS8:
|
case IR::Opcode::GetCbufS8:
|
||||||
case IR::Opcode::GetCbufU16:
|
case IR::Opcode::GetCbufU16:
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ struct Profile {
|
|||||||
bool support_explicit_workgroup_layout{};
|
bool support_explicit_workgroup_layout{};
|
||||||
bool support_workgroup_layout_8bit_access{};
|
bool support_workgroup_layout_8bit_access{};
|
||||||
bool support_workgroup_layout_16bit_access{};
|
bool support_workgroup_layout_16bit_access{};
|
||||||
|
bool support_shader_quad_control{};
|
||||||
|
bool support_quad_shuffles{};
|
||||||
bool support_vote{};
|
bool support_vote{};
|
||||||
u32 supported_subgroup_stages{0x7F};
|
u32 supported_subgroup_stages{0x7F};
|
||||||
bool support_viewport_index_layer_non_geometry{};
|
bool support_viewport_index_layer_non_geometry{};
|
||||||
|
|||||||
@@ -252,6 +252,7 @@ struct Info {
|
|||||||
bool uses_is_helper_invocation{};
|
bool uses_is_helper_invocation{};
|
||||||
bool uses_subgroup_invocation_id{};
|
bool uses_subgroup_invocation_id{};
|
||||||
bool uses_subgroup_shuffles{};
|
bool uses_subgroup_shuffles{};
|
||||||
|
bool uses_quad_shuffles{};
|
||||||
std::array<bool, 30> uses_patches{};
|
std::array<bool, 30> uses_patches{};
|
||||||
|
|
||||||
std::array<Interpolation, 32> interpolation{};
|
std::array<Interpolation, 32> interpolation{};
|
||||||
|
|||||||
@@ -404,6 +404,8 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
|||||||
device.IsWorkgroupMemoryExplicitLayout8BitAccessSupported(),
|
device.IsWorkgroupMemoryExplicitLayout8BitAccessSupported(),
|
||||||
.support_workgroup_layout_16bit_access =
|
.support_workgroup_layout_16bit_access =
|
||||||
device.IsWorkgroupMemoryExplicitLayout16BitAccessSupported(),
|
device.IsWorkgroupMemoryExplicitLayout16BitAccessSupported(),
|
||||||
|
.support_shader_quad_control = device.IsKhrShaderQuadControlSupported(),
|
||||||
|
.support_quad_shuffles = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_QUAD_BIT),
|
||||||
.support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
|
.support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
|
||||||
.supported_subgroup_stages = supported_subgroup_stages,
|
.supported_subgroup_stages = supported_subgroup_stages,
|
||||||
.support_viewport_index_layer_non_geometry =
|
.support_viewport_index_layer_non_geometry =
|
||||||
|
|||||||
@@ -508,6 +508,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
|||||||
LOG_WARNING(Render_Vulkan, "Qualcomm drivers require scaled vertex format emulation.");
|
LOG_WARNING(Render_Vulkan, "Qualcomm drivers require scaled vertex format emulation.");
|
||||||
has_broken_descriptor_aliasing = true;
|
has_broken_descriptor_aliasing = true;
|
||||||
LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken descriptor aliasing.");
|
LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken descriptor aliasing.");
|
||||||
|
LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken color write enable.");
|
||||||
|
RemoveExtensionFeature(extensions.color_write_enable, features.color_write_enable,
|
||||||
|
VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME);
|
||||||
LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken shader atomic int64.");
|
LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken shader atomic int64.");
|
||||||
RemoveExtensionFeature(extensions.shader_atomic_int64, features.shader_atomic_int64,
|
RemoveExtensionFeature(extensions.shader_atomic_int64, features.shader_atomic_int64,
|
||||||
VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME);
|
VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME);
|
||||||
@@ -1383,6 +1386,11 @@ void Device::RemoveUnsuitableExtensions() {
|
|||||||
VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME);
|
VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VK_KHR_shader_quad_control
|
||||||
|
extensions.shader_quad_control = features.shader_quad_control.shaderQuadControl;
|
||||||
|
RemoveExtensionFeatureIfUnsuitable(extensions.shader_quad_control, features.shader_quad_control,
|
||||||
|
VK_KHR_SHADER_QUAD_CONTROL_EXTENSION_NAME);
|
||||||
|
|
||||||
// VK_KHR_workgroup_memory_explicit_layout
|
// VK_KHR_workgroup_memory_explicit_layout
|
||||||
extensions.workgroup_memory_explicit_layout =
|
extensions.workgroup_memory_explicit_layout =
|
||||||
features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayout &&
|
features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayout &&
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
|||||||
FEATURE(KHR, Maintenance6, MAINTENANCE_6, maintenance6) \
|
FEATURE(KHR, Maintenance6, MAINTENANCE_6, maintenance6) \
|
||||||
FEATURE(KHR, PipelineExecutableProperties, PIPELINE_EXECUTABLE_PROPERTIES, \
|
FEATURE(KHR, PipelineExecutableProperties, PIPELINE_EXECUTABLE_PROPERTIES, \
|
||||||
pipeline_executable_properties) \
|
pipeline_executable_properties) \
|
||||||
|
FEATURE(KHR, ShaderQuadControl, SHADER_QUAD_CONTROL, shader_quad_control) \
|
||||||
FEATURE(KHR, WorkgroupMemoryExplicitLayout, WORKGROUP_MEMORY_EXPLICIT_LAYOUT, \
|
FEATURE(KHR, WorkgroupMemoryExplicitLayout, WORKGROUP_MEMORY_EXPLICIT_LAYOUT, \
|
||||||
workgroup_memory_explicit_layout)
|
workgroup_memory_explicit_layout)
|
||||||
|
|
||||||
@@ -586,6 +587,11 @@ FN_MAX_LIMIT_LIST
|
|||||||
features.features.shaderInt16;
|
features.features.shaderInt16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the device supports VK_KHR_shader_quad_control.
|
||||||
|
bool IsKhrShaderQuadControlSupported() const {
|
||||||
|
return extensions.shader_quad_control && features.shader_quad_control.shaderQuadControl;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the device supports VK_KHR_image_format_list.
|
/// Returns true if the device supports VK_KHR_image_format_list.
|
||||||
bool IsKhrImageFormatListSupported() const {
|
bool IsKhrImageFormatListSupported() const {
|
||||||
return extensions.image_format_list || instance_version >= VK_API_VERSION_1_2;
|
return extensions.image_format_list || instance_version >= VK_API_VERSION_1_2;
|
||||||
|
|||||||
Reference in New Issue
Block a user