Compare commits

..

3 Commits

Author SHA1 Message Date
lat9nq
61121d1b22 gl_device: Force GLASM on NVIDIA drivers 495-496
GLSL shaders currently do not render correctly on the recent NVIDIA
drivers. This adds a check that forces assembly shaders for these
drivers since they seem unaffected and adds a warning informing of the
decision.

Developers can disable the check by enabling graphics debugging.
2021-10-28 19:38:49 -04:00
Ameer J
40c8a8c627 Merge pull request #7186 from MightyCreak/fix-crash-configure-window
ui: fix crash when closing configure window
2021-10-26 22:15:45 -04:00
Romain Failliot
427ce8dcef ui: fix crash when closing configure window
This crash happens 100% of the time (on Linux at least), you just need
to open the configure window and click OK.

It seems to happen when the tabs are destroyed and once all the tabs are
destroyed, a final signal is sent with `index == -1`. So `debug_tab_tab`
doesn't exist anymore when this happens, so the crash.
2021-10-15 17:43:30 -04:00
9 changed files with 202 additions and 303 deletions

View File

@@ -1,5 +1,4 @@
// Copyright 2021 yuzu emulator team
// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -8,7 +7,6 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_writable_event.h"
@@ -74,125 +72,96 @@ NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector
}
NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
bool is_allocation) {
bool is_async) {
IocCtrlEventWaitParams params{};
std::memcpy(&params, input.data(), sizeof(params));
LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_allocation={}",
params.fence.id, params.fence.value, params.timeout, is_allocation);
LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}",
params.syncpt_id, params.threshold, params.timeout, is_async);
bool must_unmark_fail = !is_allocation;
const u32 event_id = params.value.raw;
SCOPE_EXIT({
std::memcpy(output.data(), &params, sizeof(params));
if (must_unmark_fail) {
events_interface.fails[event_id] = 0;
}
});
const u32 fence_id = static_cast<u32>(params.fence.id);
if (fence_id >= MaxSyncPoints) {
if (params.syncpt_id >= MaxSyncPoints) {
return NvResult::BadParameter;
}
if (params.fence.value == 0) {
u32 event_id = params.value & 0x00FF;
if (event_id >= MaxNvEvents) {
std::memcpy(output.data(), &params, sizeof(params));
return NvResult::BadParameter;
}
if (syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) {
params.value = syncpoint_manager.GetSyncpointMin(params.syncpt_id);
std::memcpy(output.data(), &params, sizeof(params));
events_interface.failed[event_id] = false;
return NvResult::Success;
}
if (syncpoint_manager.IsSyncpointExpired(fence_id, params.fence.value)) {
params.value.raw = syncpoint_manager.GetSyncpointMin(fence_id);
return NvResult::Success;
}
if (const auto new_value = syncpoint_manager.RefreshSyncpoint(fence_id);
syncpoint_manager.IsSyncpointExpired(fence_id, params.fence.value)) {
params.value.raw = new_value;
if (const auto new_value = syncpoint_manager.RefreshSyncpoint(params.syncpt_id);
syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) {
params.value = new_value;
std::memcpy(output.data(), &params, sizeof(params));
events_interface.failed[event_id] = false;
return NvResult::Success;
}
auto& event = events_interface.events[event_id];
auto& gpu = system.GPU();
const u32 target_value = params.fence.value;
const auto check_failing = [&]() {
if (!is_allocation && events_interface.fails[event_id] > 1) {
{
auto lk = system.StallCPU();
gpu.WaitFence(fence_id, target_value);
system.UnstallCPU();
}
return true;
}
return false;
};
// This is mostly to take into account unimplemented features. As synced
// gpu is always synced.
if (!gpu.IsAsync()) {
event.event->GetWritableEvent().Signal();
return NvResult::Success;
}
const u32 current_syncpoint_value = event.fence.value;
const s32 diff = current_syncpoint_value - params.threshold;
if (diff >= 0) {
event.event->GetWritableEvent().Signal();
params.value = current_syncpoint_value;
std::memcpy(output.data(), &params, sizeof(params));
events_interface.failed[event_id] = false;
return NvResult::Success;
}
const u32 target_value = current_syncpoint_value - diff;
if (!is_async) {
params.value = 0;
}
if (params.timeout == 0) {
if (check_failing()) {
return NvResult::Success;
}
std::memcpy(output.data(), &params, sizeof(params));
return NvResult::Timeout;
}
auto lock = events_interface.Lock();
u32 slot = [&]() {
if (is_allocation) {
params.value.raw = 0;
return events_interface.FindFreeEvent(fence_id);
} else {
return params.value.raw;
}
}();
if (slot >= MaxNvEvents) {
EventState status = events_interface.status[event_id];
const bool bad_parameter = status != EventState::Free && status != EventState::Registered;
if (bad_parameter) {
std::memcpy(output.data(), &params, sizeof(params));
return NvResult::BadParameter;
}
auto* event = events_interface.events[slot].event;
if (!event) {
return NvResult::BadParameter;
}
if (events_interface.IsBeingUsed(slot)) {
return NvResult::BadParameter;
}
if (check_failing()) {
return NvResult::Success;
}
params.value.raw = 0;
events_interface.status[slot].store(EventState::Waiting, std::memory_order_relaxed);
events_interface.assigned_syncpt[slot] = fence_id;
events_interface.assigned_value[slot] = target_value;
if (is_allocation) {
params.value.syncpoint_id_for_allocation.Assign(static_cast<u16>(fence_id));
params.value.event_allocated.Assign(1);
events_interface.SetEventStatus(event_id, EventState::Waiting);
events_interface.assigned_syncpt[event_id] = params.syncpt_id;
events_interface.assigned_value[event_id] = target_value;
if (is_async) {
params.value = params.syncpt_id << 4;
} else {
params.value.syncpoint_id.Assign(fence_id);
params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000;
}
params.value.raw |= slot;
gpu.RegisterSyncptInterrupt(fence_id, target_value);
return NvResult::Timeout;
}
NvResult nvhost_ctrl::FreeEvent(u32 slot) {
if (slot >= MaxNvEvents) {
return NvResult::BadParameter;
}
if (!events_interface.registered[slot]) {
params.value |= event_id;
event.event->GetWritableEvent().Clear();
if (events_interface.failed[event_id]) {
{
auto lk = system.StallCPU();
gpu.WaitFence(params.syncpt_id, target_value);
system.UnstallCPU();
}
std::memcpy(output.data(), &params, sizeof(params));
events_interface.failed[event_id] = false;
return NvResult::Success;
}
if (events_interface.IsBeingUsed(slot)) {
return NvResult::Busy;
}
events_interface.Free(slot);
return NvResult::Success;
gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
std::memcpy(output.data(), &params, sizeof(params));
return NvResult::Timeout;
}
NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
@@ -203,16 +172,16 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::ve
if (event_id >= MaxNvEvents) {
return NvResult::BadParameter;
}
auto lock = events_interface.Lock();
if (events_interface.registered[event_id]) {
const auto result = FreeEvent(event_id);
if (result != NvResult::Success) {
return result;
const auto event_state = events_interface.status[event_id];
if (event_state != EventState::Free) {
LOG_WARNING(Service_NVDRV, "Event already registered! Unregistering previous event");
events_interface.UnregisterEvent(event_id);
} else {
return NvResult::BadParameter;
}
}
events_interface.Create(event_id);
events_interface.RegisterEvent(event_id);
return NvResult::Success;
}
@@ -222,33 +191,32 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input,
std::memcpy(&params, input.data(), sizeof(params));
const u32 event_id = params.user_event_id & 0x00FF;
LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id);
auto lock = events_interface.Lock();
return FreeEvent(event_id);
if (event_id >= MaxNvEvents) {
return NvResult::BadParameter;
}
if (!events_interface.registered[event_id]) {
return NvResult::BadParameter;
}
events_interface.UnregisterEvent(event_id);
return NvResult::Success;
}
NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
IocCtrlEventClearParams params{};
IocCtrlEventSignalParams params{};
std::memcpy(&params, input.data(), sizeof(params));
u32 event_id = params.event_id.slot;
LOG_DEBUG(Service_NVDRV, "cleared event wait on, event_id: {:X}", event_id);
u32 event_id = params.event_id & 0x00FF;
LOG_WARNING(Service_NVDRV, "cleared event wait on, event_id: {:X}", event_id);
if (event_id >= MaxNvEvents) {
return NvResult::BadParameter;
}
auto lock = events_interface.Lock();
if (events_interface.status[event_id].exchange(
EventState::Cancelling, std::memory_order_acq_rel) == EventState::Waiting) {
system.GPU().CancelSyncptInterrupt(events_interface.assigned_syncpt[event_id],
events_interface.assigned_value[event_id]);
syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id);
if (events_interface.status[event_id] == EventState::Waiting) {
events_interface.LiberateEvent(event_id);
}
events_interface.fails[event_id]++;
events_interface.status[event_id].store(EventState::Cancelled, std::memory_order_release);
events_interface.events[event_id].event->GetWritableEvent().Clear();
events_interface.failed[event_id] = true;
syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id);
return NvResult::Success;
}

View File

@@ -6,7 +6,6 @@
#include <array>
#include <vector>
#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
#include "core/hle/service/nvdrv/nvdrv.h"
@@ -29,24 +28,6 @@ public:
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
union SyncpointEventValue {
u32 raw;
union {
BitField<0, 4, u32> partial_slot;
BitField<4, 28, u32> syncpoint_id;
};
struct {
u16 slot;
union {
BitField<0, 12, u16> syncpoint_id_for_allocation;
BitField<12, 1, u16> event_allocated;
};
};
};
static_assert(sizeof(SyncpointEventValue) == sizeof(u32));
private:
struct IocSyncptReadParams {
u32_le id{};
@@ -103,18 +84,27 @@ private:
};
static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size");
struct IocCtrlEventClearParams {
SyncpointEventValue event_id{};
struct IocCtrlEventSignalParams {
u32_le event_id{};
};
static_assert(sizeof(IocCtrlEventClearParams) == 4,
"IocCtrlEventClearParams is incorrect size");
static_assert(sizeof(IocCtrlEventSignalParams) == 4,
"IocCtrlEventSignalParams is incorrect size");
struct IocCtrlEventWaitParams {
Fence fence{};
u32_le timeout{};
SyncpointEventValue value{};
u32_le syncpt_id{};
u32_le threshold{};
s32_le timeout{};
u32_le value{};
};
static_assert(sizeof(IocCtrlEventWaitParams) == 16,
static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size");
struct IocCtrlEventWaitAsyncParams {
u32_le syncpt_id{};
u32_le threshold{};
u32_le timeout{};
u32_le value{};
};
static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16,
"IocCtrlEventWaitAsyncParams is incorrect size");
struct IocCtrlEventRegisterParams {
@@ -135,14 +125,11 @@ private:
static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size");
NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
bool is_allocation);
NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async);
NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);
NvResult FreeEvent(u32 slot);
EventInterface& events_interface;
SyncpointManager& syncpoint_manager;
};

View File

@@ -1,8 +1,3 @@
// Copyright 2021 yuzu emulator team
// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
@@ -86,15 +81,11 @@ enum class NvResult : u32 {
ModuleNotPresent = 0xA000E,
};
// obtained from
// https://github.com/skyline-emu/skyline/blob/nvdec-dev/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/ctrl.h#L47
enum class EventState {
Available = 0,
Waiting = 1,
Cancelling = 2,
Signalling = 3,
Signalled = 4,
Cancelled = 5,
Free = 0,
Registered = 1,
Waiting = 2,
Busy = 3,
};
union Ioctl {

View File

@@ -1,9 +1,7 @@
// Copyright 2021 yuzu emulator team
// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <bit>
#include <utility>
#include <fmt/format.h>
@@ -30,64 +28,6 @@
namespace Service::Nvidia {
std::unique_lock<std::mutex> EventInterface::Lock() {
return std::unique_lock<std::mutex>(events_mutex);
}
void EventInterface::Signal(u32 event_id) {
if (status[event_id].exchange(EventState::Signalling, std::memory_order_acq_rel) ==
EventState::Waiting) {
events[event_id].event->GetWritableEvent().Signal();
}
status[event_id].store(EventState::Signalled, std::memory_order_release);
}
void EventInterface::Create(u32 event_id) {
events[event_id].event =
module.service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", event_id));
status[event_id] = EventState::Available;
registered[event_id] = true;
const u64 mask = 1ULL << event_id;
events_mask |= mask;
}
void EventInterface::Free(u32 event_id) {
module.service_context.CloseEvent(events[event_id].event);
events[event_id].event = nullptr;
status[event_id] = EventState::Available;
registered[event_id] = false;
const u64 mask = ~(1ULL << event_id);
events_mask &= mask;
}
u32 EventInterface::FindFreeEvent(u32 syncpoint_id) {
u32 slot{MaxNvEvents};
u32 free_slot{MaxNvEvents};
for (u32 i = 0; i < MaxNvEvents; i++) {
if (events[i].event) {
if (!IsBeingUsed(i)) {
slot = i;
if (assigned_syncpt[i] == syncpoint_id) {
return slot;
}
}
} else if (free_slot == MaxNvEvents) {
free_slot = i;
}
}
if (free_slot < MaxNvEvents) {
Create(free_slot);
return free_slot;
}
if (slot < MaxNvEvents) {
return slot;
}
LOG_CRITICAL(Service_NVDRV, "Failed to allocate an event");
return 0;
}
void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
Core::System& system) {
auto module_ = std::make_shared<Module>(system);
@@ -100,11 +40,11 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
}
Module::Module(Core::System& system)
: syncpoint_manager{system.GPU()}, events_interface{*this}, service_context{system, "nvdrv"} {
events_interface.events_mask = 0;
: syncpoint_manager{system.GPU()}, service_context{system, "nvdrv"} {
for (u32 i = 0; i < MaxNvEvents; i++) {
events_interface.status[i] = EventState::Available;
events_interface.events[i].event = nullptr;
events_interface.events[i].event =
service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", i));
events_interface.status[i] = EventState::Free;
events_interface.registered[i] = false;
}
auto nvmap_dev = std::make_shared<Devices::nvmap>(system);
@@ -124,11 +64,8 @@ Module::Module(Core::System& system)
}
Module::~Module() {
auto lock = events_interface.Lock();
for (u32 i = 0; i < MaxNvEvents; i++) {
if (events_interface.registered[i]) {
service_context.CloseEvent(events_interface.events[i].event);
}
service_context.CloseEvent(events_interface.events[i].event);
}
}
@@ -234,35 +171,21 @@ NvResult Module::Close(DeviceFD fd) {
}
void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) {
const u32 max = MaxNvEvents - std::countl_zero(events_interface.events_mask);
const u32 min = std::countr_zero(events_interface.events_mask);
for (u32 i = min; i < max; i++) {
for (u32 i = 0; i < MaxNvEvents; i++) {
if (events_interface.assigned_syncpt[i] == syncpoint_id &&
events_interface.assigned_value[i] == value) {
events_interface.Signal(i);
events_interface.LiberateEvent(i);
events_interface.events[i].event->GetWritableEvent().Signal();
}
}
}
Kernel::KEvent* Module::GetEvent(u32 event_id) {
const auto event = Devices::nvhost_ctrl::SyncpointEventValue{.raw = event_id};
Kernel::KReadableEvent& Module::GetEvent(const u32 event_id) {
return events_interface.events[event_id].event->GetReadableEvent();
}
const bool allocated = event.event_allocated.Value() != 0;
const u32 slot{allocated ? event.partial_slot.Value() : static_cast<u32>(event.slot)};
if (slot >= MaxNvEvents) {
return nullptr;
}
const u32 syncpoint_id{allocated ? event.syncpoint_id_for_allocation.Value()
: event.syncpoint_id.Value()};
auto lock = events_interface.Lock();
if (events_interface.registered[slot] &&
events_interface.assigned_syncpt[slot] == syncpoint_id) {
return events_interface.events[slot].event;
}
return nullptr;
Kernel::KWritableEvent& Module::GetEventWriteable(const u32 event_id) {
return events_interface.events[event_id].event->GetWritableEvent();
}
} // namespace Service::Nvidia

View File

@@ -1,5 +1,4 @@
// Copyright 2018 yuzu emulator team
// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -41,22 +40,17 @@ struct NvEvent {
Fence fence{};
};
class Module;
class EventInterface {
public:
EventInterface(Module& module_) : module{module_} {}
// Mask representing registered events
struct EventInterface {
// Mask representing currently busy events
u64 events_mask{};
// Each kernel event associated to an NV event
std::array<NvEvent, MaxNvEvents> events{};
std::array<NvEvent, MaxNvEvents> events;
// The status of the current NVEvent
std::array<std::atomic<EventState>, MaxNvEvents> status{};
std::array<EventState, MaxNvEvents> status{};
// Tells if an NVEvent is registered or not
std::array<bool, MaxNvEvents> registered{};
// Tells the NVEvent that it has failed.
std::array<u32, MaxNvEvents> fails{};
std::array<bool, MaxNvEvents> failed{};
// When an NVEvent is waiting on GPU interrupt, this is the sync_point
// associated with it.
std::array<u32, MaxNvEvents> assigned_syncpt{};
@@ -65,26 +59,50 @@ public:
std::array<u32, MaxNvEvents> assigned_value{};
// Constant to denote an unasigned syncpoint.
static constexpr u32 unassigned_syncpt = 0xFFFFFFFF;
bool IsBeingUsed(u32 event_id) {
const auto current_status = status[event_id].load(std::memory_order_acquire);
return current_status == EventState::Waiting || current_status == EventState::Cancelling ||
current_status == EventState::Signalling;
std::optional<u32> GetFreeEvent() const {
u64 mask = events_mask;
for (u32 i = 0; i < MaxNvEvents; i++) {
const bool is_free = (mask & 0x1) == 0;
if (is_free) {
if (status[i] == EventState::Registered || status[i] == EventState::Free) {
return {i};
}
}
mask = mask >> 1;
}
return std::nullopt;
}
void SetEventStatus(const u32 event_id, EventState new_status) {
EventState old_status = status[event_id];
if (old_status == new_status) {
return;
}
status[event_id] = new_status;
if (new_status == EventState::Registered) {
registered[event_id] = true;
}
if (new_status == EventState::Waiting || new_status == EventState::Busy) {
events_mask |= (1ULL << event_id);
}
}
void RegisterEvent(const u32 event_id) {
registered[event_id] = true;
if (status[event_id] == EventState::Free) {
status[event_id] = EventState::Registered;
}
}
void UnregisterEvent(const u32 event_id) {
registered[event_id] = false;
if (status[event_id] == EventState::Registered) {
status[event_id] = EventState::Free;
}
}
void LiberateEvent(const u32 event_id) {
status[event_id] = registered[event_id] ? EventState::Registered : EventState::Free;
events_mask &= ~(1ULL << event_id);
assigned_syncpt[event_id] = unassigned_syncpt;
assigned_value[event_id] = 0;
}
std::unique_lock<std::mutex> Lock();
void Signal(u32 event_id);
void Create(u32 event_id);
void Free(u32 event_id);
u32 FindFreeEvent(u32 syncpoint_id);
private:
std::mutex events_mutex;
Module& module;
};
class Module final {
@@ -121,11 +139,11 @@ public:
void SignalSyncpt(const u32 syncpoint_id, const u32 value);
Kernel::KEvent* GetEvent(u32 event_id);
Kernel::KReadableEvent& GetEvent(u32 event_id);
Kernel::KWritableEvent& GetEventWriteable(u32 event_id);
private:
friend class EventInterface;
/// Manages syncpoints on the host
SyncpointManager syncpoint_manager;
@@ -141,9 +159,6 @@ private:
EventInterface events_interface;
KernelHelpers::ServiceContext service_context;
void CreateEvent(u32 event_id);
void FreeEvent(u32 event_id);
};
/// Registers all NVDRV services with the specified service manager.

View File

@@ -6,7 +6,6 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_writable_event.h"
@@ -169,7 +168,7 @@ void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto fd = rp.Pop<DeviceFD>();
const auto event_id = rp.Pop<u32>();
const auto event_id = rp.Pop<u32>() & 0x00FF;
LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id);
if (!is_initialized) {
@@ -185,14 +184,12 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
return;
}
auto* event = nvdrv->GetEvent(event_id);
if (event) {
if (event_id < MaxNvEvents) {
IPC::ResponseBuilder rb{ctx, 3, 1};
rb.Push(ResultSuccess);
auto& readable_event = event->GetReadableEvent();
readable_event.Clear();
rb.PushCopyObjects(readable_event);
auto& event = nvdrv->GetEvent(event_id);
event.Clear();
rb.PushCopyObjects(event);
rb.PushEnum(NvResult::Success);
} else {
IPC::ResponseBuilder rb{ctx, 3};

View File

@@ -216,7 +216,7 @@ public:
void RegisterSyncptInterrupt(u32 syncpoint_id, u32 value);
bool CancelSyncptInterrupt(u32 syncpoint_id, u32 value);
[[nodiscard]] bool CancelSyncptInterrupt(u32 syncpoint_id, u32 value);
[[nodiscard]] u64 GetTicks() const;

View File

@@ -181,6 +181,21 @@ Device::Device() {
LOG_ERROR(Render_OpenGL, "Assembly shaders enabled but not supported");
shader_backend = Settings::ShaderBackend::GLSL;
}
if (shader_backend == Settings::ShaderBackend::GLSL && is_nvidia &&
!Settings::values.renderer_debug) {
const std::string_view driver_version = version.substr(13);
const int version_major =
std::atoi(driver_version.substr(0, driver_version.find(".")).data());
if (version_major >= 495) {
LOG_WARNING(Render_OpenGL, "NVIDIA drivers 495 and later causes significant problems "
"with yuzu. Forcing GLASM as a mitigation.");
shader_backend = Settings::ShaderBackend::GLASM;
use_assembly_shaders = true;
}
}
// Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation.
use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue() &&
!(is_amd || (is_intel && !is_linux));

View File

@@ -81,8 +81,11 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry,
SetConfiguration();
PopulateSelectionList();
connect(ui->tabWidget, &QTabWidget::currentChanged, this,
[this]() { debug_tab_tab->SetCurrentIndex(0); });
connect(ui->tabWidget, &QTabWidget::currentChanged, this, [this](int index) {
if (index != -1) {
debug_tab_tab->SetCurrentIndex(0);
}
});
connect(ui_tab.get(), &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged);
connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
&ConfigureDialog::UpdateVisibleTabs);