mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-28 17:45:39 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f49d727a07 | |||
| 119291dc77 | |||
| f7dbff2157 | |||
| b859d7fdf4 | |||
| f635827fa6 | |||
| 243453c172 | |||
| 39158b67a7 | |||
| 50cb8fd1c9 |
@@ -19,6 +19,23 @@
|
||||
namespace AudioCore::Sink {
|
||||
|
||||
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) {
|
||||
int device_count = 0;
|
||||
SDL_AudioDeviceID* devices = capture ? SDL_GetAudioRecordingDevices(&device_count)
|
||||
@@ -204,20 +221,14 @@ private:
|
||||
};
|
||||
|
||||
SDLSink::SDLSink(std::string_view target_device_name) {
|
||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
||||
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
|
||||
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
|
||||
return;
|
||||
if (InitializeAudio()) {
|
||||
if (target_device_name != auto_device_name && !target_device_name.empty()) {
|
||||
output_device = target_device_name;
|
||||
} 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;
|
||||
@@ -265,15 +276,10 @@ void SDLSink::SetSystemVolume(f32 volume) {
|
||||
}
|
||||
|
||||
std::vector<std::string> ListSDLSinkDevices(bool capture) {
|
||||
if (!InitializeAudio())
|
||||
return {}; //no devices
|
||||
|
||||
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;
|
||||
SDL_AudioDeviceID* devices =
|
||||
capture ? SDL_GetAudioRecordingDevices(&device_count)
|
||||
@@ -304,13 +310,8 @@ bool IsSDLSuitable() {
|
||||
return false;
|
||||
#else
|
||||
// Check SDL can init
|
||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
|
||||
LOG_ERROR(Audio_Sink, "SDL failed to init, it is not suitable. Error: {}",
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!InitializeAudio()!
|
||||
return false;
|
||||
|
||||
// We can set any latency frequency we want with SDL, so no need to check that.
|
||||
|
||||
|
||||
@@ -7,6 +7,4 @@
|
||||
#define STB_IMAGE_IMPLEMENTATION 1
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION 1
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION 1
|
||||
#define STBI_ONLY_JPEG 1
|
||||
|
||||
#include "common/stb.h"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#define STBI_ONLY_JPEG 1
|
||||
#define STBI_WRITE_NO_STDIO 1
|
||||
#include <stb_image.h>
|
||||
#include <stb_image_resize.h>
|
||||
#include <stb_image_write.h>
|
||||
|
||||
+34
-6
@@ -4,6 +4,7 @@
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "game_settings.h"
|
||||
@@ -248,12 +249,30 @@ struct System::Impl {
|
||||
}
|
||||
}
|
||||
|
||||
void SetNVDECActive(bool is_nvdec_active) {
|
||||
nvdec_active = is_nvdec_active;
|
||||
void NotifyNVDECChannelOpen(u64 process_id) {
|
||||
std::scoped_lock lock{nvdec_active_mutex};
|
||||
++nvdec_active_channels[process_id];
|
||||
}
|
||||
|
||||
void NotifyNVDECChannelClose(u64 process_id) {
|
||||
std::scoped_lock lock{nvdec_active_mutex};
|
||||
const auto it = nvdec_active_channels.find(process_id);
|
||||
if (it == nvdec_active_channels.end()) {
|
||||
return;
|
||||
}
|
||||
if (--it->second == 0) {
|
||||
nvdec_active_channels.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
bool GetNVDECActive() {
|
||||
return nvdec_active;
|
||||
std::scoped_lock lock{nvdec_active_mutex};
|
||||
return !nvdec_active_channels.empty();
|
||||
}
|
||||
|
||||
bool IsNVDECActiveForProcess(u64 process_id) {
|
||||
std::scoped_lock lock{nvdec_active_mutex};
|
||||
return nvdec_active_channels.contains(process_id);
|
||||
}
|
||||
|
||||
void InitializeDebugger(System& system, u16 port) {
|
||||
@@ -498,6 +517,8 @@ struct System::Impl {
|
||||
|
||||
mutable std::mutex suspend_guard;
|
||||
std::mutex general_channel_mutex;
|
||||
std::mutex nvdec_active_mutex;
|
||||
std::unordered_map<u64, u32> nvdec_active_channels;
|
||||
std::atomic_bool is_paused{};
|
||||
std::atomic_bool is_shutting_down{};
|
||||
std::atomic_bool is_powered_on{};
|
||||
@@ -505,7 +526,6 @@ struct System::Impl {
|
||||
bool extended_memory_layout : 1 = false;
|
||||
bool exit_locked : 1 = false;
|
||||
bool exit_requested : 1 = false;
|
||||
bool nvdec_active : 1 = false;
|
||||
|
||||
void EnsureGeneralChannelInitialized(System& system) {
|
||||
if (!general_channel_event) {
|
||||
@@ -569,14 +589,22 @@ void System::UnstallApplication() {
|
||||
impl->UnstallApplication();
|
||||
}
|
||||
|
||||
void System::SetNVDECActive(bool is_nvdec_active) {
|
||||
impl->SetNVDECActive(is_nvdec_active);
|
||||
void System::NotifyNVDECChannelOpen(u64 process_id) {
|
||||
impl->NotifyNVDECChannelOpen(process_id);
|
||||
}
|
||||
|
||||
void System::NotifyNVDECChannelClose(u64 process_id) {
|
||||
impl->NotifyNVDECChannelClose(process_id);
|
||||
}
|
||||
|
||||
bool System::GetNVDECActive() {
|
||||
return impl->GetNVDECActive();
|
||||
}
|
||||
|
||||
bool System::IsNVDECActiveForProcess(u64 process_id) {
|
||||
return impl->IsNVDECActiveForProcess(process_id);
|
||||
}
|
||||
|
||||
void System::InitializeDebugger() {
|
||||
impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue());
|
||||
}
|
||||
|
||||
+3
-1
@@ -191,8 +191,10 @@ public:
|
||||
std::unique_lock<std::mutex> StallApplication();
|
||||
void UnstallApplication();
|
||||
|
||||
void SetNVDECActive(bool is_nvdec_active);
|
||||
void NotifyNVDECChannelOpen(u64 process_id);
|
||||
void NotifyNVDECChannelClose(u64 process_id);
|
||||
[[nodiscard]] bool GetNVDECActive();
|
||||
[[nodiscard]] bool IsNVDECActiveForProcess(u64 process_id);
|
||||
|
||||
/**
|
||||
* Initialize the debugger.
|
||||
|
||||
@@ -324,6 +324,7 @@ Result IApplicationFunctions::NotifyRunning(Out<bool> out_became_running) {
|
||||
|
||||
Result IApplicationFunctions::GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id) {
|
||||
LOG_WARNING(Service_AM, "(stubbed)");
|
||||
R_UNLESS(out_pseudo_device_id, ResultUnknown);
|
||||
|
||||
// This should be hashed with the device specific hash
|
||||
// for now this will do
|
||||
|
||||
@@ -9,11 +9,7 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#define STBI_ONLY_JPEG 1
|
||||
#include <stb_image.h>
|
||||
#include <stb_image_resize.h>
|
||||
#include <stb_image_write.h>
|
||||
|
||||
#include "common/stb.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/logging.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/service/nvdrv/core/container.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
|
||||
@@ -71,17 +72,23 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
|
||||
|
||||
void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
|
||||
LOG_INFO(Service_NVDRV, "NVDEC video stream started");
|
||||
system.SetNVDECActive(true);
|
||||
sessions[fd] = session_id;
|
||||
if (const auto* session = core.GetSession(session_id);
|
||||
session != nullptr && session->process != nullptr) {
|
||||
system.NotifyNVDECChannelOpen(session->process->GetId());
|
||||
}
|
||||
host1x.StartDevice(fd, Tegra::Host1x::ChannelType::NvDec, channel_syncpoint);
|
||||
}
|
||||
|
||||
void nvhost_nvdec::OnClose(DeviceFD fd) {
|
||||
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
|
||||
host1x.StopDevice(fd, Tegra::Host1x::ChannelType::NvDec);
|
||||
system.SetNVDECActive(false);
|
||||
auto it = sessions.find(fd);
|
||||
if (it != sessions.end()) {
|
||||
if (const auto* session = core.GetSession(it->second);
|
||||
session != nullptr && session->process != nullptr) {
|
||||
system.NotifyNVDECChannelClose(session->process->GetId());
|
||||
}
|
||||
sessions.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,16 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <chrono>
|
||||
#include <fmt/ranges.h>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
@@ -33,6 +37,7 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se
|
||||
: SessionRequestHandler(system_.Kernel(), service_name_)
|
||||
, system{system_}
|
||||
, service_name{service_name_}
|
||||
, is_i_storage{std::string_view{service_name_} == "IStorage"}
|
||||
, handler_invoker{handler_invoker_}
|
||||
, max_sessions{max_sessions_}
|
||||
{}
|
||||
@@ -77,13 +82,22 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx,
|
||||
}
|
||||
|
||||
void ServiceFrameworkBase::InvokeRequest(HLERequestContext& ctx) {
|
||||
auto it = handlers.find(ctx.GetCommand());
|
||||
const auto command = ctx.GetCommand();
|
||||
auto it = handlers.find(command);
|
||||
const bool is_cmd_read = command == 0;
|
||||
FunctionInfoBase const* info = it == handlers.end() ? nullptr : &it->second;
|
||||
if (info == nullptr || info->handler_callback == nullptr)
|
||||
return ReportUnimplementedFunction(ctx, info);
|
||||
|
||||
LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer()));
|
||||
handler_invoker(this, info->handler_callback, ctx);
|
||||
|
||||
if (is_i_storage && is_cmd_read) {
|
||||
const auto* const process = ctx.GetThread().GetOwnerProcess();
|
||||
if (process != nullptr && system.IsNVDECActiveForProcess(process->GetId())) {
|
||||
std::this_thread::sleep_for(std::chrono::microseconds{600});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceFrameworkBase::InvokeRequestTipc(HLERequestContext& ctx) {
|
||||
|
||||
@@ -107,6 +107,8 @@ protected:
|
||||
Core::System& system;
|
||||
/// Identifier string used to connect to the service.
|
||||
const char* service_name;
|
||||
/// Whether this is the IStorage service.
|
||||
const bool is_i_storage;
|
||||
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
|
||||
InvokerFn* handler_invoker;
|
||||
/// Maximum number of concurrent sessions that this service can handle.
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging.h"
|
||||
#include "common/common_types.h"
|
||||
#include "dynarmic/backend/exception_handler.h"
|
||||
#include "dynarmic/common/context.h"
|
||||
@@ -53,23 +54,21 @@ class SigHandler {
|
||||
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;
|
||||
std::shared_mutex code_block_infos_mutex;
|
||||
struct sigaction old_sa_segv;
|
||||
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:
|
||||
SigHandler() noexcept {
|
||||
signal_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);
|
||||
auto const stack_size = std::max<size_t>(SIGSTKSZ, 2 * 1024 * 1024);
|
||||
signal_stack_memory = std::make_unique<uint8_t[]>(stack_size);
|
||||
|
||||
stack_t signal_stack{};
|
||||
signal_stack.ss_sp = signal_stack_memory;
|
||||
signal_stack.ss_size = signal_stack_size;
|
||||
signal_stack.ss_sp = signal_stack_memory.get();
|
||||
signal_stack.ss_size = stack_size;
|
||||
signal_stack.ss_flags = 0;
|
||||
if (sigaltstack(&signal_stack, nullptr) != 0) {
|
||||
fmt::print(stderr, "dynarmic: POSIX SigHandler: init failure at sigaltstack\n");
|
||||
@@ -87,7 +86,7 @@ public:
|
||||
supports_fast_mem = false;
|
||||
return;
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
#if defined(__APPLE__)
|
||||
if (sigaction(SIGBUS, &sa, &old_sa_bus) != 0) {
|
||||
fmt::print(stderr, "dynarmic: POSIX SigHandler: could not set SIGBUS handler\n");
|
||||
supports_fast_mem = false;
|
||||
@@ -96,10 +95,6 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
~SigHandler() noexcept {
|
||||
munmap(signal_stack_memory, signal_stack_size);
|
||||
}
|
||||
|
||||
void AddCodeBlock(u64 offset, CodeBlockInfo cbi) noexcept {
|
||||
std::unique_lock guard(code_block_infos_mutex);
|
||||
code_block_infos.insert_or_assign(offset, cbi);
|
||||
@@ -109,14 +104,17 @@ public:
|
||||
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;
|
||||
|
||||
void RegisterHandler() {
|
||||
std::lock_guard<std::mutex> guard(handler_lock);
|
||||
void SigHandler::RegisterHandler() {
|
||||
if (!sig_handler) {
|
||||
sig_handler.emplace();
|
||||
}
|
||||
@@ -125,51 +123,27 @@ void RegisterHandler() {
|
||||
void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
|
||||
DEBUG_ASSERT(sig == SIGSEGV || sig == SIGBUS);
|
||||
CTX_DECLARE(raw_context);
|
||||
#if defined(ARCHITECTURE_x86_64)
|
||||
{
|
||||
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()) {
|
||||
FakeCall fc = iter->second.cb(CTX_PC);
|
||||
#if defined(ARCHITECTURE_x86_64)
|
||||
CTX_SP -= sizeof(u64);
|
||||
*std::bit_cast<u64*>(CTX_SP) = fc.ret_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)
|
||||
{
|
||||
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;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fmt::print(stderr, "Unhandled {} at pc {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
|
||||
#elif defined(ARCHITECTURE_riscv64)
|
||||
{
|
||||
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);
|
||||
CTX_PC = fc.call_sepc;
|
||||
#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;
|
||||
#else
|
||||
ASSERT(false);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
fmt::print(stderr, "Unhandled {} at pc {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
|
||||
#else
|
||||
# error "Invalid architecture"
|
||||
#endif
|
||||
LOG_ERROR(Core, "Unhandled {} at {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
|
||||
|
||||
struct sigaction* retry_sa = sig == SIGSEGV ? &sig_handler->old_sa_segv : &sig_handler->old_sa_bus;
|
||||
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 {
|
||||
Impl(u64 offset_, u64 size_)
|
||||
: offset(offset_)
|
||||
, size(size_) {
|
||||
RegisterHandler();
|
||||
: offset(offset_)
|
||||
, size(size_)
|
||||
{
|
||||
SigHandler::RegisterHandler();
|
||||
}
|
||||
|
||||
void SetCallback(std::function<FakeCall(u64)> cb) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <variant>
|
||||
#include "dynarmic/backend/loongarch64/emit_loongarch64.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
|
||||
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);
|
||||
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));
|
||||
|
||||
@@ -136,14 +136,14 @@
|
||||
# endif
|
||||
#elif defined(ARCHITECTURE_riscv64)
|
||||
# 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)
|
||||
# elif defined(__linux__)
|
||||
# define CTX_SEPC (mctx.__gregs[REG_PC])
|
||||
# define CTX_PC (mctx.__gregs[REG_PC])
|
||||
# define CTX_SP (mctx.__gregs[REG_SP])
|
||||
# elif defined(__OpenBSD__)
|
||||
// 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)
|
||||
# else
|
||||
# error "unknown platform"
|
||||
|
||||
@@ -74,8 +74,8 @@ static constexpr char DEFAULT_DISCORD_IMAGE[] =
|
||||
"https://git.eden-emu.dev/eden-emu/eden/raw/branch/master/dist/qt_themes/default/icons/256x256/"
|
||||
"eden.png";
|
||||
|
||||
void DiscordImpl::UpdateGameStatus(bool use_default) {
|
||||
const std::string url = use_default ? std::string{DEFAULT_DISCORD_IMAGE} : game_url;
|
||||
void DiscordImpl::UpdateGameStatus(std::string_view game_url, bool has_boxart) {
|
||||
const std::string url = std::string{has_boxart ? game_url : DEFAULT_DISCORD_IMAGE};
|
||||
s64 start_time = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
@@ -98,7 +98,7 @@ void DiscordImpl::Update() {
|
||||
|
||||
// Used to format Icon URL for yuzu website game compatibility page
|
||||
std::string icon_name = GetGameString(game_title);
|
||||
game_url = fmt::format(
|
||||
auto const game_url = fmt::format(
|
||||
"https://raw.githubusercontent.com/eden-emulator/boxart/refs/heads/master/img/{}.png",
|
||||
icon_name);
|
||||
|
||||
@@ -117,7 +117,7 @@ void DiscordImpl::Update() {
|
||||
};
|
||||
|
||||
auto res = client.send(request);
|
||||
UpdateGameStatus(res && res->status == 200);
|
||||
UpdateGameStatus(game_url, res && res->status == 200);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -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-FileCopyrightText: 2018 Citra Emulator Project
|
||||
@@ -26,11 +26,9 @@ public:
|
||||
|
||||
private:
|
||||
std::string GetGameString(const std::string& title);
|
||||
void UpdateGameStatus(bool use_default);
|
||||
void UpdateGameStatus(std::string_view game_url, bool use_default);
|
||||
|
||||
std::string game_url{};
|
||||
std::string game_title{};
|
||||
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
|
||||
@@ -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-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);
|
||||
void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index,
|
||||
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,
|
||||
ScalarU32 swizzle);
|
||||
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-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");
|
||||
}
|
||||
|
||||
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,
|
||||
ScalarU32 swizzle) {
|
||||
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-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,
|
||||
std::string_view index, std::string_view clamp,
|
||||
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,
|
||||
std::string_view swizzle);
|
||||
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-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);
|
||||
}
|
||||
|
||||
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,
|
||||
std::string_view 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) {
|
||||
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;
|
||||
default:
|
||||
throw NotImplementedException("Stage {}", program.stage);
|
||||
@@ -443,6 +448,12 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
|
||||
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) {
|
||||
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-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 EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
|
||||
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 EmitDPdxFine(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);
|
||||
}
|
||||
|
||||
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) {
|
||||
const Id three{ctx.Const(3U)};
|
||||
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-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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
@@ -394,6 +394,8 @@ public:
|
||||
const IR::U32& seg_mask);
|
||||
[[nodiscard]] U32 ShuffleButterfly(const IR::U32& value, const IR::U32& index,
|
||||
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,
|
||||
FpControl control = {});
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Shader::IR {
|
||||
|
||||
namespace Detail {
|
||||
|
||||
OpcodeMeta META_TABLE[532] = {
|
||||
OpcodeMeta META_TABLE[534] = {
|
||||
#define OPCODE(name_token, type_token, ...) \
|
||||
{ \
|
||||
.name{#name_token}, \
|
||||
@@ -21,7 +21,7 @@ OpcodeMeta META_TABLE[532] = {
|
||||
#undef OPCODE
|
||||
};
|
||||
|
||||
u8 NUM_ARGS[532] = {
|
||||
u8 NUM_ARGS[534] = {
|
||||
#define OPCODE(name_token, type_token, ...) u8(CalculateNumArgsOf(Opcode::name_token)),
|
||||
#include "opcodes.inc"
|
||||
#undef OPCODE
|
||||
|
||||
@@ -57,12 +57,12 @@ static constexpr Type F64x2{Type::F64x2};
|
||||
static constexpr Type F64x3{Type::F64x3};
|
||||
static constexpr Type F64x4{Type::F64x4};
|
||||
|
||||
extern OpcodeMeta META_TABLE[532];
|
||||
extern OpcodeMeta META_TABLE[534];
|
||||
constexpr size_t CalculateNumArgsOf(Opcode op) noexcept {
|
||||
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)));
|
||||
}
|
||||
extern u8 NUM_ARGS[532];
|
||||
extern u8 NUM_ARGS[534];
|
||||
} // namespace Detail
|
||||
|
||||
/// 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-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -579,6 +582,8 @@ OPCODE(ShuffleIndex, U32, U32,
|
||||
OPCODE(ShuffleUp, U32, U32, U32, U32, U32, )
|
||||
OPCODE(ShuffleDown, 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(DPdxFine, 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-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 {
|
||||
u64 insn;
|
||||
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;
|
||||
} 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)};
|
||||
v.ir.SetPred(shfl.pred, v.ir.GetInBoundsFromOp(result));
|
||||
v.X(shfl.dest_reg, result);
|
||||
@@ -59,11 +77,14 @@ void TranslatorVisitor::SHFL(u64 insn) {
|
||||
BitField<29, 1, u64> src_b_flag;
|
||||
BitField<34, 13, u64> src_b_imm;
|
||||
} const flags{insn};
|
||||
const IR::U32 src_a{flags.src_a_flag != 0 ? ir.Imm32(static_cast<u32>(flags.src_a_imm))
|
||||
: GetReg20(insn)};
|
||||
const IR::U32 src_b{flags.src_b_flag != 0 ? ir.Imm32(static_cast<u32>(flags.src_b_imm))
|
||||
: GetReg39(insn)};
|
||||
Shuffle(*this, insn, src_a, src_b);
|
||||
const bool index_is_imm{flags.src_a_flag != 0};
|
||||
const bool mask_is_imm{flags.src_b_flag != 0};
|
||||
const IR::U32 src_a{index_is_imm ? ir.Imm32(static_cast<u32>(flags.src_a_imm))
|
||||
: GetReg20(insn)};
|
||||
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
|
||||
|
||||
@@ -498,6 +498,10 @@ void VisitUsages(Info& info, IR::Inst& inst) {
|
||||
case IR::Opcode::ShuffleButterfly:
|
||||
info.uses_subgroup_shuffles = true;
|
||||
break;
|
||||
case IR::Opcode::QuadBroadcast:
|
||||
case IR::Opcode::QuadSwap:
|
||||
info.uses_quad_shuffles = true;
|
||||
break;
|
||||
case IR::Opcode::GetCbufU8:
|
||||
case IR::Opcode::GetCbufS8:
|
||||
case IR::Opcode::GetCbufU16:
|
||||
|
||||
@@ -37,6 +37,8 @@ struct Profile {
|
||||
bool support_explicit_workgroup_layout{};
|
||||
bool support_workgroup_layout_8bit_access{};
|
||||
bool support_workgroup_layout_16bit_access{};
|
||||
bool support_shader_quad_control{};
|
||||
bool support_quad_shuffles{};
|
||||
bool support_vote{};
|
||||
u32 supported_subgroup_stages{0x7F};
|
||||
bool support_viewport_index_layer_non_geometry{};
|
||||
|
||||
@@ -252,6 +252,7 @@ struct Info {
|
||||
bool uses_is_helper_invocation{};
|
||||
bool uses_subgroup_invocation_id{};
|
||||
bool uses_subgroup_shuffles{};
|
||||
bool uses_quad_shuffles{};
|
||||
std::array<bool, 30> uses_patches{};
|
||||
|
||||
std::array<Interpolation, 32> interpolation{};
|
||||
|
||||
@@ -404,6 +404,8 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
device.IsWorkgroupMemoryExplicitLayout8BitAccessSupported(),
|
||||
.support_workgroup_layout_16bit_access =
|
||||
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),
|
||||
.supported_subgroup_stages = supported_subgroup_stages,
|
||||
.support_viewport_index_layer_non_geometry =
|
||||
|
||||
@@ -1386,6 +1386,11 @@ void Device::RemoveUnsuitableExtensions() {
|
||||
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
|
||||
extensions.workgroup_memory_explicit_layout =
|
||||
features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayout &&
|
||||
|
||||
@@ -75,6 +75,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||
FEATURE(KHR, Maintenance6, MAINTENANCE_6, maintenance6) \
|
||||
FEATURE(KHR, PipelineExecutableProperties, PIPELINE_EXECUTABLE_PROPERTIES, \
|
||||
pipeline_executable_properties) \
|
||||
FEATURE(KHR, ShaderQuadControl, SHADER_QUAD_CONTROL, shader_quad_control) \
|
||||
FEATURE(KHR, WorkgroupMemoryExplicitLayout, WORKGROUP_MEMORY_EXPLICIT_LAYOUT, \
|
||||
workgroup_memory_explicit_layout)
|
||||
|
||||
@@ -586,6 +587,11 @@ FN_MAX_LIMIT_LIST
|
||||
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.
|
||||
bool IsKhrImageFormatListSupported() const {
|
||||
return extensions.image_format_list || instance_version >= VK_API_VERSION_1_2;
|
||||
|
||||
Reference in New Issue
Block a user