summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/global_scheduler_context.cpp6
-rw-r--r--src/core/hle/kernel/k_interrupt_manager.cpp34
-rw-r--r--src/core/hle/kernel/k_interrupt_manager.h17
-rw-r--r--src/core/hle/kernel/k_process.cpp12
-rw-r--r--src/core/hle/kernel/k_process.h4
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp8
-rw-r--r--src/core/hle/kernel/k_thread.cpp44
-rw-r--r--src/core/hle/kernel/k_thread.h6
-rw-r--r--src/core/hle/kernel/svc.cpp21
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp16
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_instructions.h1
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp4
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp51
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp4
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_instructions.h2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp4
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_special.cpp4
-rw-r--r--src/shader_recompiler/backend/glsl/glsl_emit_context.cpp7
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp25
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_instructions.h1
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc1
-rw-r--r--src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp1
-rw-r--r--src/shader_recompiler/ir_opt/constant_propagation_pass.cpp23
-rw-r--r--src/shader_recompiler/profile.h4
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp10
-rw-r--r--src/video_core/renderer_opengl/gl_device.h10
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp39
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h2
-rw-r--r--src/video_core/texture_cache/util.cpp10
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp9
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h5
-rw-r--r--src/yuzu/applets/qt_controller.cpp68
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp53
-rw-r--r--src/yuzu/main.cpp4
36 files changed, 390 insertions, 124 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 698c4f912..b1a746727 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -187,6 +187,8 @@ add_library(core STATIC
hle/kernel/k_event.h
hle/kernel/k_handle_table.cpp
hle/kernel/k_handle_table.h
+ hle/kernel/k_interrupt_manager.cpp
+ hle/kernel/k_interrupt_manager.h
hle/kernel/k_light_condition_variable.cpp
hle/kernel/k_light_condition_variable.h
hle/kernel/k_light_lock.cpp
diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp
index 4f4e338e3..baad2c5d6 100644
--- a/src/core/hle/kernel/global_scheduler_context.cpp
+++ b/src/core/hle/kernel/global_scheduler_context.cpp
@@ -9,6 +9,7 @@
#include "core/hle/kernel/global_scheduler_context.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/physical_core.h"
namespace Kernel {
@@ -42,6 +43,11 @@ void GlobalSchedulerContext::PreemptThreads() {
for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
const u32 priority = preemption_priorities[core_id];
kernel.Scheduler(core_id).RotateScheduledQueue(core_id, priority);
+
+ // Signal an interrupt occurred. For core 3, this is a certainty, as preemption will result
+ // in the rotator thread being scheduled. For cores 0-2, this is to simulate or system
+ // interrupts that may have occurred.
+ kernel.PhysicalCore(core_id).Interrupt();
}
}
diff --git a/src/core/hle/kernel/k_interrupt_manager.cpp b/src/core/hle/kernel/k_interrupt_manager.cpp
new file mode 100644
index 000000000..e5dd39751
--- /dev/null
+++ b/src/core/hle/kernel/k_interrupt_manager.cpp
@@ -0,0 +1,34 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/kernel/k_interrupt_manager.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/kernel.h"
+
+namespace Kernel::KInterruptManager {
+
+void HandleInterrupt(KernelCore& kernel, s32 core_id) {
+ auto* process = kernel.CurrentProcess();
+ if (!process) {
+ return;
+ }
+
+ auto& scheduler = kernel.Scheduler(core_id);
+ auto& current_thread = *scheduler.GetCurrentThread();
+
+ // If the user disable count is set, we may need to pin the current thread.
+ if (current_thread.GetUserDisableCount() && !process->GetPinnedThread(core_id)) {
+ KScopedSchedulerLock sl{kernel};
+
+ // Pin the current thread.
+ process->PinCurrentThread(core_id);
+
+ // Set the interrupt flag for the thread.
+ scheduler.GetCurrentThread()->SetInterruptFlag();
+ }
+}
+
+} // namespace Kernel::KInterruptManager
diff --git a/src/core/hle/kernel/k_interrupt_manager.h b/src/core/hle/kernel/k_interrupt_manager.h
new file mode 100644
index 000000000..05924801e
--- /dev/null
+++ b/src/core/hle/kernel/k_interrupt_manager.h
@@ -0,0 +1,17 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Kernel {
+
+class KernelCore;
+
+namespace KInterruptManager {
+void HandleInterrupt(KernelCore& kernel, s32 core_id);
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 73f8bc4fe..bf98a51e2 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -220,30 +220,28 @@ bool KProcess::ReleaseUserException(KThread* thread) {
}
}
-void KProcess::PinCurrentThread() {
+void KProcess::PinCurrentThread(s32 core_id) {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
// Get the current thread.
- const s32 core_id = GetCurrentCoreId(kernel);
- KThread* cur_thread = GetCurrentThreadPointer(kernel);
+ KThread* cur_thread = kernel.Scheduler(static_cast<std::size_t>(core_id)).GetCurrentThread();
// If the thread isn't terminated, pin it.
if (!cur_thread->IsTerminationRequested()) {
// Pin it.
PinThread(core_id, cur_thread);
- cur_thread->Pin();
+ cur_thread->Pin(core_id);
// An update is needed.
KScheduler::SetSchedulerUpdateNeeded(kernel);
}
}
-void KProcess::UnpinCurrentThread() {
+void KProcess::UnpinCurrentThread(s32 core_id) {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
// Get the current thread.
- const s32 core_id = GetCurrentCoreId(kernel);
- KThread* cur_thread = GetCurrentThreadPointer(kernel);
+ KThread* cur_thread = kernel.Scheduler(static_cast<std::size_t>(core_id)).GetCurrentThread();
// Unpin it.
cur_thread->Unpin();
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index cb93c7e24..e7c8b5838 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -345,8 +345,8 @@ public:
bool IsSignaled() const override;
- void PinCurrentThread();
- void UnpinCurrentThread();
+ void PinCurrentThread(s32 core_id);
+ void UnpinCurrentThread(s32 core_id);
void UnpinThread(KThread* thread);
KLightLock& GetStateLock() {
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index 277201de4..31cec990e 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -15,6 +15,7 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/cpu_manager.h"
+#include "core/hle/kernel/k_interrupt_manager.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
@@ -53,6 +54,13 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul
}
cores_pending_reschedule &= ~(1ULL << core);
}
+
+ for (std::size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; ++core_id) {
+ if (kernel.PhysicalCore(core_id).IsInterrupted()) {
+ KInterruptManager::HandleInterrupt(kernel, static_cast<s32>(core_id));
+ }
+ }
+
if (must_context_switch) {
auto core_scheduler = kernel.CurrentScheduler();
kernel.ExitSVCProfile();
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index b8c993748..71e029a3f 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <atomic>
#include <cinttypes>
#include <optional>
#include <vector>
@@ -33,6 +34,7 @@
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/time_manager.h"
#include "core/hle/result.h"
+#include "core/memory.h"
#ifdef ARCHITECTURE_x86_64
#include "core/arm/dynarmic/arm_dynarmic_32.h"
@@ -63,6 +65,13 @@ namespace Kernel {
namespace {
+struct ThreadLocalRegion {
+ static constexpr std::size_t MessageBufferSize = 0x100;
+ std::array<u32, MessageBufferSize / sizeof(u32)> message_buffer;
+ std::atomic_uint16_t disable_count;
+ std::atomic_uint16_t interrupt_flag;
+};
+
class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait {
public:
explicit ThreadQueueImplForKThreadSleep(KernelCore& kernel_)
@@ -346,7 +355,7 @@ void KThread::StartTermination() {
if (parent != nullptr) {
parent->ReleaseUserException(this);
if (parent->GetPinnedThread(GetCurrentCoreId(kernel)) == this) {
- parent->UnpinCurrentThread();
+ parent->UnpinCurrentThread(core_id);
}
}
@@ -372,7 +381,7 @@ void KThread::StartTermination() {
this->Close();
}
-void KThread::Pin() {
+void KThread::Pin(s32 current_core) {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
// Set ourselves as pinned.
@@ -389,7 +398,6 @@ void KThread::Pin() {
// Bind ourselves to this core.
const s32 active_core = GetActiveCore();
- const s32 current_core = GetCurrentCoreId(kernel);
SetActiveCore(current_core);
physical_ideal_core_id = current_core;
@@ -482,6 +490,36 @@ void KThread::Unpin() {
}
}
+u16 KThread::GetUserDisableCount() const {
+ if (!IsUserThread()) {
+ // We only emulate TLS for user threads
+ return {};
+ }
+
+ auto& memory = kernel.System().Memory();
+ return memory.Read16(tls_address + offsetof(ThreadLocalRegion, disable_count));
+}
+
+void KThread::SetInterruptFlag() {
+ if (!IsUserThread()) {
+ // We only emulate TLS for user threads
+ return;
+ }
+
+ auto& memory = kernel.System().Memory();
+ memory.Write16(tls_address + offsetof(ThreadLocalRegion, interrupt_flag), 1);
+}
+
+void KThread::ClearInterruptFlag() {
+ if (!IsUserThread()) {
+ // We only emulate TLS for user threads
+ return;
+ }
+
+ auto& memory = kernel.System().Memory();
+ memory.Write16(tls_address + offsetof(ThreadLocalRegion, interrupt_flag), 0);
+}
+
ResultCode KThread::GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask) {
KScopedSchedulerLock sl{kernel};
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index c8a08bd71..83dfde69b 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -307,6 +307,10 @@ public:
return parent != nullptr;
}
+ u16 GetUserDisableCount() const;
+ void SetInterruptFlag();
+ void ClearInterruptFlag();
+
[[nodiscard]] KThread* GetLockOwner() const {
return lock_owner;
}
@@ -490,7 +494,7 @@ public:
this->GetStackParameters().disable_count--;
}
- void Pin();
+ void Pin(s32 current_core);
void Unpin();
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 63e2dff19..250ef9042 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -2027,6 +2027,25 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign
count);
}
+static void SynchronizePreemptionState(Core::System& system) {
+ auto& kernel = system.Kernel();
+
+ // Lock the scheduler.
+ KScopedSchedulerLock sl{kernel};
+
+ // If the current thread is pinned, unpin it.
+ KProcess* cur_process = system.Kernel().CurrentProcess();
+ const auto core_id = GetCurrentCoreId(kernel);
+
+ if (cur_process->GetPinnedThread(core_id) == GetCurrentThreadPointer(kernel)) {
+ // Clear the current thread's interrupt flag.
+ GetCurrentThread(kernel).ClearInterruptFlag();
+
+ // Unpin the current thread.
+ cur_process->UnpinCurrentThread(core_id);
+ }
+}
+
static ResultCode SignalToAddress32(Core::System& system, u32 address, Svc::SignalType signal_type,
s32 value, s32 count) {
return SignalToAddress(system, address, signal_type, value, count);
@@ -2797,7 +2816,7 @@ static const FunctionDef SVC_Table_64[] = {
{0x33, SvcWrap64<GetThreadContext>, "GetThreadContext"},
{0x34, SvcWrap64<WaitForAddress>, "WaitForAddress"},
{0x35, SvcWrap64<SignalToAddress>, "SignalToAddress"},
- {0x36, nullptr, "SynchronizePreemptionState"},
+ {0x36, SvcWrap64<SynchronizePreemptionState>, "SynchronizePreemptionState"},
{0x37, nullptr, "Unknown"},
{0x38, nullptr, "Unknown"},
{0x39, nullptr, "Unknown"},
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
index 6f98d0998..7434a1f92 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
@@ -126,6 +126,22 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal
}
}
+void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, ScalarU32) {
+ switch (attr) {
+ case IR::Attribute::PrimitiveId:
+ ctx.Add("MOV.S {}.x,primitive.id;", inst);
+ break;
+ case IR::Attribute::InstanceId:
+ ctx.Add("MOV.S {}.x,{}.instance;", inst, ctx.attrib_name);
+ break;
+ case IR::Attribute::VertexId:
+ ctx.Add("MOV.S {}.x,{}.id;", inst, ctx.attrib_name);
+ break;
+ default:
+ throw NotImplementedException("Get U32 attribute {}", attr);
+ }
+}
+
void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, ScalarF32 value,
[[maybe_unused]] ScalarU32 vertex) {
const u32 element{static_cast<u32>(attr) % 4};
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
index 1f343bff5..b48007856 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
@@ -50,6 +50,7 @@ void EmitGetCbufU32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, ScalarU32 vertex);
+void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, ScalarU32 vertex);
void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, ScalarF32 value, ScalarU32 vertex);
void EmitGetAttributeIndexed(EmitContext& ctx, IR::Inst& inst, ScalarS32 offset, ScalarU32 vertex);
void EmitSetAttributeIndexed(EmitContext& ctx, ScalarU32 offset, ScalarF32 value, ScalarU32 vertex);
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
index 0f2668d9e..e0ead7a53 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
@@ -7,6 +7,7 @@
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
#include "shader_recompiler/frontend/ir/value.h"
+#include "shader_recompiler/profile.h"
namespace Shader::Backend::GLSL {
namespace {
@@ -30,8 +31,9 @@ void EmitConditionRef(EmitContext& ctx, IR::Inst& inst, const IR::Value& value)
inst.DestructiveAddUsage(1);
const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U1)};
const auto input{ctx.var_alloc.Consume(value)};
+ const auto suffix{ctx.profile.has_gl_bool_ref_bug ? "?true:false" : ""};
if (ret != input) {
- ctx.Add("{}={};", ret, input);
+ ctx.Add("{}={}{};", ret, input, suffix);
}
}
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
index 6477bd192..0c1fbc7b1 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
@@ -102,39 +102,46 @@ void GetCbuf16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, const
void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
const IR::Value& offset) {
- GetCbuf8(ctx, inst, binding, offset, "ftou");
+ const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};
+ GetCbuf8(ctx, inst, binding, offset, cast);
}
void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
const IR::Value& offset) {
- GetCbuf8(ctx, inst, binding, offset, "ftoi");
+ const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "int" : "ftoi"};
+ GetCbuf8(ctx, inst, binding, offset, cast);
}
void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
const IR::Value& offset) {
- GetCbuf16(ctx, inst, binding, offset, "ftou");
+ const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};
+ GetCbuf16(ctx, inst, binding, offset, cast);
}
void EmitGetCbufS16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
const IR::Value& offset) {
- GetCbuf16(ctx, inst, binding, offset, "ftoi");
+ const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "int" : "ftoi"};
+ GetCbuf16(ctx, inst, binding, offset, cast);
}
void EmitGetCbufU32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
const IR::Value& offset) {
const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)};
- GetCbuf(ctx, ret, binding, offset, 32, "ftou");
+ const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};
+ GetCbuf(ctx, ret, binding, offset, 32, cast);
}
void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
const IR::Value& offset) {
const auto ret{ctx.var_alloc.Define(inst, GlslVarType::F32)};
- GetCbuf(ctx, ret, binding, offset, 32);
+ const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "utof" : ""};
+ GetCbuf(ctx, ret, binding, offset, 32, cast);
}
void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
const IR::Value& offset) {
const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())};
+ const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};
if (offset.IsImmediate()) {
static constexpr u32 cbuf_size{0x10000};
const u32 u32_offset{offset.U32()};
@@ -145,26 +152,26 @@ void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding
return;
}
if (u32_offset % 2 == 0) {
- ctx.AddU32x2("{}=ftou({}[{}].{}{});", inst, cbuf, u32_offset / 16,
+ ctx.AddU32x2("{}={}({}[{}].{}{});", inst, cast, cbuf, u32_offset / 16,
OffsetSwizzle(u32_offset), OffsetSwizzle(u32_offset + 4));
} else {
- ctx.AddU32x2("{}=uvec2(ftou({}[{}].{}),ftou({}[{}].{}));", inst, cbuf, u32_offset / 16,
- OffsetSwizzle(u32_offset), cbuf, (u32_offset + 4) / 16,
- OffsetSwizzle(u32_offset + 4));
+ ctx.AddU32x2("{}=uvec2({}({}[{}].{}),{}({}[{}].{}));", inst, cast, cbuf,
+ u32_offset / 16, OffsetSwizzle(u32_offset), cast, cbuf,
+ (u32_offset + 4) / 16, OffsetSwizzle(u32_offset + 4));
}
return;
}
const auto offset_var{ctx.var_alloc.Consume(offset)};
if (!ctx.profile.has_gl_component_indexing_bug) {
- ctx.AddU32x2("{}=uvec2(ftou({}[{}>>4][({}>>2)%4]),ftou({}[({}+4)>>4][(({}+4)>>2)%4]));",
- inst, cbuf, offset_var, offset_var, cbuf, offset_var, offset_var);
+ ctx.AddU32x2("{}=uvec2({}({}[{}>>4][({}>>2)%4]),{}({}[({}+4)>>4][(({}+4)>>2)%4]));", inst,
+ cast, cbuf, offset_var, offset_var, cast, cbuf, offset_var, offset_var);
return;
}
const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32x2)};
const auto cbuf_offset{fmt::format("{}>>2", offset_var)};
for (u32 swizzle = 0; swizzle < 4; ++swizzle) {
- ctx.Add("if(({}&3)=={}){}=uvec2(ftou({}[{}>>4].{}),ftou({}[({}+4)>>4].{}));", cbuf_offset,
- swizzle, ret, cbuf, offset_var, "xyzw"[swizzle], cbuf, offset_var,
+ ctx.Add("if(({}&3)=={}){}=uvec2({}({}[{}>>4].{}),{}({}[({}+4)>>4].{}));", cbuf_offset,
+ swizzle, ret, cast, cbuf, offset_var, "xyzw"[swizzle], cast, cbuf, offset_var,
"xyzw"[(swizzle + 1) % 4]);
}
}
@@ -221,6 +228,22 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
}
}
+void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, std::string_view) {
+ switch (attr) {
+ case IR::Attribute::PrimitiveId:
+ ctx.AddU32("{}=uint(gl_PrimitiveID);", inst);
+ break;
+ case IR::Attribute::InstanceId:
+ ctx.AddU32("{}=uint(gl_InstanceID);", inst);
+ break;
+ case IR::Attribute::VertexId:
+ ctx.AddU32("{}=uint(gl_VertexID);", inst);
+ break;
+ default:
+ throw NotImplementedException("Get U32 attribute {}", attr);
+ }
+}
+
void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view value,
[[maybe_unused]] std::string_view vertex) {
if (IR::IsGeneric(attr)) {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp
index b765a251b..474189d87 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp
@@ -125,11 +125,11 @@ void EmitFPNeg16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& i
}
void EmitFPNeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
- ctx.AddF32("{}=-({});", inst, value);
+ ctx.AddF32("{}=0.f-({});", inst, value);
}
void EmitFPNeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
- ctx.AddF64("{}=-({});", inst, value);
+ ctx.AddF64("{}=double(0.)-({});", inst, value);
}
void EmitFPSin(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
index f86502e4c..6cabbc717 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
@@ -60,6 +60,8 @@ void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding
const IR::Value& offset);
void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
std::string_view vertex);
+void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
+ std::string_view vertex);
void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view value,
std::string_view vertex);
void EmitGetAttributeIndexed(EmitContext& ctx, IR::Inst& inst, std::string_view offset,
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp
index 44060df33..b0d85be99 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp
@@ -87,11 +87,11 @@ void EmitUDiv32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::strin
}
void EmitINeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
- ctx.AddU32("{}=uint(-({}));", inst, value);
+ ctx.AddU32("{}=uint(int(0)-int({}));", inst, value);
}
void EmitINeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
- ctx.AddU64("{}=-({});", inst, value);
+ ctx.AddU64("{}=uint64_t(int64_t(0)-int64_t({}));", inst, value);
}
void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp
index b8ddafe48..fcf620b79 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp
@@ -90,7 +90,9 @@ void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value&
if (phi_reg == val_reg) {
return;
}
- ctx.Add("{}={};", phi_reg, val_reg);
+ const bool needs_workaround{ctx.profile.has_gl_bool_ref_bug && phi_type == IR::Type::U1};
+ const auto suffix{needs_workaround ? "?true:false" : ""};
+ ctx.Add("{}={}{};", phi_reg, val_reg, suffix);
}
void EmitPrologue(EmitContext& ctx) {
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
index bc9d2a904..bb7f1a0fd 100644
--- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
+++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
@@ -428,9 +428,10 @@ void EmitContext::DefineConstantBuffers(Bindings& bindings) {
return;
}
for (const auto& desc : info.constant_buffer_descriptors) {
- header += fmt::format(
- "layout(std140,binding={}) uniform {}_cbuf_{}{{vec4 {}_cbuf{}[{}];}};",
- bindings.uniform_buffer, stage_name, desc.index, stage_name, desc.index, 4 * 1024);
+ const auto cbuf_type{profile.has_gl_cbuf_ftou_bug ? "uvec4" : "vec4"};
+ header += fmt::format("layout(std140,binding={}) uniform {}_cbuf_{}{{{} {}_cbuf{}[{}];}};",
+ bindings.uniform_buffer, stage_name, desc.index, cbuf_type,
+ stage_name, desc.index, 4 * 1024);
bindings.uniform_buffer += desc.count;
}
}
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index 14f470812..8ea730c80 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
@@ -355,6 +355,31 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
}
}
+Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, Id) {
+ switch (attr) {
+ case IR::Attribute::PrimitiveId:
+ return ctx.OpLoad(ctx.U32[1], ctx.primitive_id);
+ case IR::Attribute::InstanceId:
+ if (ctx.profile.support_vertex_instance_id) {
+ return ctx.OpLoad(ctx.U32[1], ctx.instance_id);
+ } else {
+ const Id index{ctx.OpLoad(ctx.U32[1], ctx.instance_index)};
+ const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_instance)};
+ return ctx.OpISub(ctx.U32[1], index, base);
+ }
+ case IR::Attribute::VertexId:
+ if (ctx.profile.support_vertex_instance_id) {
+ return ctx.OpLoad(ctx.U32[1], ctx.vertex_id);
+ } else {
+ const Id index{ctx.OpLoad(ctx.U32[1], ctx.vertex_index)};
+ const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)};
+ return ctx.OpISub(ctx.U32[1], index, base);
+ }
+ default:
+ throw NotImplementedException("Read U32 attribute {}", attr);
+ }
+}
+
void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, [[maybe_unused]] Id vertex) {
const std::optional<OutAttr> output{OutputAttrPointer(ctx, attr)};
if (!output) {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
index 6cd22dd3e..887112deb 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
@@ -53,6 +53,7 @@ Id EmitGetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& o
Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex);
+Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, Id vertex);
void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, Id vertex);
Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset, Id vertex);
void EmitSetAttributeIndexed(EmitContext& ctx, Id offset, Id value, Id vertex);
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc
index 6929919df..b94ce7406 100644
--- a/src/shader_recompiler/frontend/ir/opcodes.inc
+++ b/src/shader_recompiler/frontend/ir/opcodes.inc
@@ -40,6 +40,7 @@ OPCODE(GetCbufU32, U32, U32,
OPCODE(GetCbufF32, F32, U32, U32, )
OPCODE(GetCbufU32x2, U32x2, U32, U32, )
OPCODE(GetAttribute, F32, Attribute, U32, )
+OPCODE(GetAttributeU32, U32, Attribute, U32, )
OPCODE(SetAttribute, Void, Attribute, F32, U32, )
OPCODE(GetAttributeIndexed, F32, U32, U32, )
OPCODE(SetAttributeIndexed, Void, U32, F32, U32, )
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
index 1e476d83d..a78c469be 100644
--- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
+++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
@@ -389,6 +389,7 @@ void VisitUsages(Info& info, IR::Inst& inst) {
info.uses_demote_to_helper_invocation = true;
break;
case IR::Opcode::GetAttribute:
+ case IR::Opcode::GetAttributeU32:
info.loads.mask[static_cast<size_t>(inst.Arg(0).Attribute())] = true;
break;
case IR::Opcode::SetAttribute:
diff --git a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
index d089fdd12..c134a12bc 100644
--- a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
+++ b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
@@ -505,6 +505,29 @@ void FoldBitCast(IR::Inst& inst, IR::Opcode reverse) {
return;
}
}
+ if constexpr (op == IR::Opcode::BitCastU32F32) {
+ // Workaround for new NVIDIA driver bug, where:
+ // uint attr = ftou(itof(gl_InstanceID));
+ // always returned 0.
+ // We can instead manually optimize this and work around the driver bug:
+ // uint attr = uint(gl_InstanceID);
+ if (arg_inst->GetOpcode() == IR::Opcode::GetAttribute) {
+ const IR::Attribute attr{arg_inst->Arg(0).Attribute()};
+ switch (attr) {
+ case IR::Attribute::PrimitiveId:
+ case IR::Attribute::InstanceId:
+ case IR::Attribute::VertexId:
+ break;
+ default:
+ return;
+ }
+ // Replace the bitcasts with an integer attribute get
+ inst.ReplaceOpcode(IR::Opcode::GetAttributeU32);
+ inst.SetArg(0, arg_inst->Arg(0));
+ inst.SetArg(1, arg_inst->Arg(1));
+ return;
+ }
+ }
}
void FoldInverseFunc(IR::Inst& inst, IR::Opcode reverse) {
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h
index f0c3b3b17..dc4c806ff 100644
--- a/src/shader_recompiler/profile.h
+++ b/src/shader_recompiler/profile.h
@@ -65,6 +65,10 @@ struct Profile {
bool has_gl_component_indexing_bug{};
/// The precise type qualifier is broken in the fragment stage of some drivers
bool has_gl_precise_bug{};
+ /// Some drivers do not properly support floatBitsToUint when used on cbufs
+ bool has_gl_cbuf_ftou_bug{};
+ /// Some drivers poorly optimize boolean variable references
+ bool has_gl_bool_ref_bug{};
/// Ignores SPIR-V ordered vs unordered using GLSL semantics
bool ignore_nan_fp_comparisons{};
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index 0764ea6e0..e62912a22 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -182,17 +182,13 @@ Device::Device() {
shader_backend = Settings::ShaderBackend::GLSL;
}
- if (shader_backend == Settings::ShaderBackend::GLSL && is_nvidia &&
- !Settings::values.renderer_debug) {
+ if (shader_backend == Settings::ShaderBackend::GLSL && is_nvidia) {
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;
+ has_cbuf_ftou_bug = true;
+ has_bool_ref_bug = true;
}
}
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h
index de9e41659..95c2e8d38 100644
--- a/src/video_core/renderer_opengl/gl_device.h
+++ b/src/video_core/renderer_opengl/gl_device.h
@@ -152,6 +152,14 @@ public:
return need_fastmath_off;
}
+ bool HasCbufFtouBug() const {
+ return has_cbuf_ftou_bug;
+ }
+
+ bool HasBoolRefBug() const {
+ return has_bool_ref_bug;
+ }
+
Settings::ShaderBackend GetShaderBackend() const {
return shader_backend;
}
@@ -200,6 +208,8 @@ private:
bool has_sparse_texture_2{};
bool warp_size_potentially_larger_than_guest{};
bool need_fastmath_off{};
+ bool has_cbuf_ftou_bug{};
+ bool has_bool_ref_bug{};
std::string vendor_name;
};
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 29c6e1a5f..ec558a9af 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -214,6 +214,8 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo
.has_broken_fp16_float_controls = false,
.has_gl_component_indexing_bug = device.HasComponentIndexingBug(),
.has_gl_precise_bug = device.HasPreciseBug(),
+ .has_gl_cbuf_ftou_bug = device.HasCbufFtouBug(),
+ .has_gl_bool_ref_bug = device.HasBoolRefBug(),
.ignore_nan_fp_comparisons = true,
.gl_max_compute_smem_size = device.GetMaxComputeSharedMemorySize(),
},
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index c3050887c..0ba56ff1e 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -1344,7 +1344,6 @@ bool Image::ScaleUp(bool ignore) {
return false;
}
has_scaled = true;
- const auto& device = runtime->device;
if (!scaled_image) {
const bool is_2d = info.type == ImageType::e2D;
const u32 scaled_width = resolution.ScaleUp(info.size.width);
@@ -1352,7 +1351,7 @@ bool Image::ScaleUp(bool ignore) {
auto scaled_info = info;
scaled_info.size.width = scaled_width;
scaled_info.size.height = scaled_height;
- scaled_image = MakeImage(device, scaled_info);
+ scaled_image = MakeImage(runtime->device, scaled_info);
auto& allocator = runtime->memory_allocator;
scaled_commit = MemoryCommit(allocator.Commit(scaled_image, MemoryUsage::DeviceLocal));
ignore = false;
@@ -1361,18 +1360,13 @@ bool Image::ScaleUp(bool ignore) {
if (ignore) {
return true;
}
-
if (aspect_mask == 0) {
aspect_mask = ImageAspectMask(info.format);
}
- static constexpr auto OPTIMAL_FORMAT = FormatType::Optimal;
- const PixelFormat format = StorageFormat(info.format);
- const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).format;
- const auto blit_usage = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
- if (device.IsFormatSupported(vk_format, blit_usage, OPTIMAL_FORMAT)) {
- BlitScale(*scheduler, *original_image, *scaled_image, info, aspect_mask, resolution);
- } else {
+ if (NeedsScaleHelper()) {
return BlitScaleHelper(true);
+ } else {
+ BlitScale(*scheduler, *original_image, *scaled_image, info, aspect_mask, resolution);
}
return true;
}
@@ -1394,15 +1388,10 @@ bool Image::ScaleDown(bool ignore) {
if (aspect_mask == 0) {
aspect_mask = ImageAspectMask(info.format);
}
- static constexpr auto OPTIMAL_FORMAT = FormatType::Optimal;
- const PixelFormat format = StorageFormat(info.format);
- const auto& device = runtime->device;
- const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).format;
- const auto blit_usage = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
- if (device.IsFormatSupported(vk_format, blit_usage, OPTIMAL_FORMAT)) {
- BlitScale(*scheduler, *scaled_image, *original_image, info, aspect_mask, resolution, false);
- } else {
+ if (NeedsScaleHelper()) {
return BlitScaleHelper(false);
+ } else {
+ BlitScale(*scheduler, *scaled_image, *original_image, info, aspect_mask, resolution, false);
}
return true;
}
@@ -1470,6 +1459,20 @@ bool Image::BlitScaleHelper(bool scale_up) {
return true;
}
+bool Image::NeedsScaleHelper() const {
+ const auto& device = runtime->device;
+ const bool needs_msaa_helper = info.num_samples > 1 && device.CantBlitMSAA();
+ if (needs_msaa_helper) {
+ return true;
+ }
+ static constexpr auto OPTIMAL_FORMAT = FormatType::Optimal;
+ const PixelFormat format = StorageFormat(info.format);
+ const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).format;
+ const auto blit_usage = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
+ const bool needs_blit_helper = !device.IsFormatSupported(vk_format, blit_usage, OPTIMAL_FORMAT);
+ return needs_blit_helper;
+}
+
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
ImageId image_id_, Image& image)
: VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device},
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 2f12be78b..c81130dd2 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -149,6 +149,8 @@ public:
private:
bool BlitScaleHelper(bool scale_up);
+ bool NeedsScaleHelper() const;
+
VKScheduler* scheduler{};
TextureCacheRuntime* runtime{};
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index 7bd31b211..d8e19cb2f 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -364,14 +364,14 @@ template <u32 GOB_EXTENT>
[[nodiscard]] std::optional<SubresourceExtent> ResolveOverlapRightAddress2D(
const ImageInfo& new_info, GPUVAddr gpu_addr, const ImageBase& overlap, bool strict_size) {
- const u32 layer_stride = new_info.layer_stride;
- const s32 new_size = layer_stride * new_info.resources.layers;
- const s32 diff = static_cast<s32>(overlap.gpu_addr - gpu_addr);
+ const u64 layer_stride = new_info.layer_stride;
+ const u64 new_size = layer_stride * new_info.resources.layers;
+ const u64 diff = overlap.gpu_addr - gpu_addr;
if (diff > new_size) {
return std::nullopt;
}
- const s32 base_layer = diff / layer_stride;
- const s32 mip_offset = diff % layer_stride;
+ const s32 base_layer = static_cast<s32>(diff / layer_stride);
+ const s32 mip_offset = static_cast<s32>(diff % layer_stride);
const std::array offsets = CalculateMipLevelOffsets(new_info);
const auto end = offsets.begin() + new_info.resources.levels;
const auto it = std::find(offsets.begin(), end, static_cast<u32>(mip_offset));
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 9862b815b..3d78efddc 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -638,15 +638,20 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
}
}
- if (ext_vertex_input_dynamic_state && driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) {
+ const bool is_intel_windows = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS;
+ if (ext_vertex_input_dynamic_state && is_intel_windows) {
LOG_WARNING(Render_Vulkan, "Blacklisting Intel for VK_EXT_vertex_input_dynamic_state");
ext_vertex_input_dynamic_state = false;
}
- if (is_float16_supported && driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) {
+ if (is_float16_supported && is_intel_windows) {
// Intel's compiler crashes when using fp16 on Astral Chain, disable it for the time being.
LOG_WARNING(Render_Vulkan, "Blacklisting Intel proprietary from float16 math");
is_float16_supported = false;
}
+ if (is_intel_windows) {
+ LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits");
+ cant_blit_msaa = true;
+ }
supports_d24_depth =
IsFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT,
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index 4c9d86aad..37d140ebd 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -350,6 +350,10 @@ public:
return supports_d24_depth;
}
+ bool CantBlitMSAA() const {
+ return cant_blit_msaa;
+ }
+
private:
/// Checks if the physical device is suitable.
void CheckSuitability(bool requires_swapchain) const;
@@ -443,6 +447,7 @@ private:
bool has_renderdoc{}; ///< Has RenderDoc attached
bool has_nsight_graphics{}; ///< Has Nsight Graphics attached
bool supports_d24_depth{}; ///< Supports D24 depth buffers.
+ bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting.
// Telemetry parameters
std::string vendor_name; ///< Device's driver name.
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp
index d63193131..4239c17f5 100644
--- a/src/yuzu/applets/qt_controller.cpp
+++ b/src/yuzu/applets/qt_controller.cpp
@@ -400,36 +400,66 @@ void QtControllerSelectorDialog::SetSupportedControllers() {
}
void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index) {
+ const auto npad_style_set = system.HIDCore().GetSupportedStyleTag();
auto& pairs = index_controller_type_pairs[player_index];
pairs.clear();
emulated_controllers[player_index]->clear();
- pairs.emplace_back(emulated_controllers[player_index]->count(),
- Core::HID::NpadStyleIndex::ProController);
- emulated_controllers[player_index]->addItem(tr("Pro Controller"));
+ const auto add_item = [&](Core::HID::NpadStyleIndex controller_type,
+ const QString& controller_name) {
+ pairs.emplace_back(emulated_controllers[player_index]->count(), controller_type);
+ emulated_controllers[player_index]->addItem(controller_name);
+ };
- pairs.emplace_back(emulated_controllers[player_index]->count(),
- Core::HID::NpadStyleIndex::JoyconDual);
- emulated_controllers[player_index]->addItem(tr("Dual Joycons"));
+ if (npad_style_set.fullkey == 1) {
+ add_item(Core::HID::NpadStyleIndex::ProController, tr("Pro Controller"));
+ }
- pairs.emplace_back(emulated_controllers[player_index]->count(),
- Core::HID::NpadStyleIndex::JoyconLeft);
- emulated_controllers[player_index]->addItem(tr("Left Joycon"));
+ if (npad_style_set.joycon_dual == 1) {
+ add_item(Core::HID::NpadStyleIndex::JoyconDual, tr("Dual Joycons"));
+ }
- pairs.emplace_back(emulated_controllers[player_index]->count(),
- Core::HID::NpadStyleIndex::JoyconRight);
- emulated_controllers[player_index]->addItem(tr("Right Joycon"));
+ if (npad_style_set.joycon_left == 1) {
+ add_item(Core::HID::NpadStyleIndex::JoyconLeft, tr("Left Joycon"));
+ }
- if (player_index == 0) {
- pairs.emplace_back(emulated_controllers[player_index]->count(),
- Core::HID::NpadStyleIndex::Handheld);
- emulated_controllers[player_index]->addItem(tr("Handheld"));
+ if (npad_style_set.joycon_right == 1) {
+ add_item(Core::HID::NpadStyleIndex::JoyconRight, tr("Right Joycon"));
}
- pairs.emplace_back(emulated_controllers[player_index]->count(),
- Core::HID::NpadStyleIndex::GameCube);
- emulated_controllers[player_index]->addItem(tr("GameCube Controller"));
+ if (player_index == 0 && npad_style_set.handheld == 1) {
+ add_item(Core::HID::NpadStyleIndex::Handheld, tr("Handheld"));
+ }
+
+ if (npad_style_set.gamecube == 1) {
+ add_item(Core::HID::NpadStyleIndex::GameCube, tr("GameCube Controller"));
+ }
+
+ // Disable all unsupported controllers
+ if (!Settings::values.enable_all_controllers) {
+ return;
+ }
+
+ if (npad_style_set.palma == 1) {
+ add_item(Core::HID::NpadStyleIndex::Pokeball, tr("Poke Ball Plus"));
+ }
+
+ if (npad_style_set.lark == 1) {
+ add_item(Core::HID::NpadStyleIndex::NES, tr("NES Controller"));
+ }
+
+ if (npad_style_set.lucia == 1) {
+ add_item(Core::HID::NpadStyleIndex::SNES, tr("SNES Controller"));
+ }
+
+ if (npad_style_set.lagoon == 1) {
+ add_item(Core::HID::NpadStyleIndex::N64, tr("N64 Controller"));
+ }
+
+ if (npad_style_set.lager == 1) {
+ add_item(Core::HID::NpadStyleIndex::SegaGenesis, tr("Sega Genesis"));
+ }
}
Core::HID::NpadStyleIndex QtControllerSelectorDialog::GetControllerTypeFromIndex(
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index cb6163702..8c6249fc2 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -907,78 +907,63 @@ void ConfigureInputPlayer::UpdateUI() {
}
void ConfigureInputPlayer::SetConnectableControllers() {
- Core::HID::NpadStyleTag npad_style_set = hid_core.GetSupportedStyleTag();
+ const auto npad_style_set = hid_core.GetSupportedStyleTag();
index_controller_type_pairs.clear();
ui->comboControllerType->clear();
+ const auto add_item = [&](Core::HID::NpadStyleIndex controller_type,
+ const QString& controller_name) {
+ index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), controller_type);
+ ui->comboControllerType->addItem(controller_name);
+ };
+
if (npad_style_set.fullkey == 1) {
- index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
- Core::HID::NpadStyleIndex::ProController);
- ui->comboControllerType->addItem(tr("Pro Controller"));
+ add_item(Core::HID::NpadStyleIndex::ProController, tr("Pro Controller"));
}
if (npad_style_set.joycon_dual == 1) {
- index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
- Core::HID::NpadStyleIndex::JoyconDual);
- ui->comboControllerType->addItem(tr("Dual Joycons"));
+ add_item(Core::HID::NpadStyleIndex::JoyconDual, tr("Dual Joycons"));
}
if (npad_style_set.joycon_left == 1) {
- index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
- Core::HID::NpadStyleIndex::JoyconLeft);
- ui->comboControllerType->addItem(tr("Left Joycon"));
+ add_item(Core::HID::NpadStyleIndex::JoyconLeft, tr("Left Joycon"));
}
if (npad_style_set.joycon_right == 1) {
- index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
- Core::HID::NpadStyleIndex::JoyconRight);
- ui->comboControllerType->addItem(tr("Right Joycon"));
+ add_item(Core::HID::NpadStyleIndex::JoyconRight, tr("Right Joycon"));
}
if (player_index == 0 && npad_style_set.handheld == 1) {
- index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
- Core::HID::NpadStyleIndex::Handheld);
- ui->comboControllerType->addItem(tr("Handheld"));
+ add_item(Core::HID::NpadStyleIndex::Handheld, tr("Handheld"));
}
if (npad_style_set.gamecube == 1) {
- index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
- Core::HID::NpadStyleIndex::GameCube);
- ui->comboControllerType->addItem(tr("GameCube Controller"));
+ add_item(Core::HID::NpadStyleIndex::GameCube, tr("GameCube Controller"));
}
// Disable all unsupported controllers
if (!Settings::values.enable_all_controllers) {
return;
}
+
if (npad_style_set.palma == 1) {
- index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
- Core::HID::NpadStyleIndex::Pokeball);
- ui->comboControllerType->addItem(tr("Poke Ball Plus"));
+ add_item(Core::HID::NpadStyleIndex::Pokeball, tr("Poke Ball Plus"));
}
if (npad_style_set.lark == 1) {
- index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
- Core::HID::NpadStyleIndex::NES);
- ui->comboControllerType->addItem(tr("NES Controller"));
+ add_item(Core::HID::NpadStyleIndex::NES, tr("NES Controller"));
}
if (npad_style_set.lucia == 1) {
- index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
- Core::HID::NpadStyleIndex::SNES);
- ui->comboControllerType->addItem(tr("SNES Controller"));
+ add_item(Core::HID::NpadStyleIndex::SNES, tr("SNES Controller"));
}
if (npad_style_set.lagoon == 1) {
- index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
- Core::HID::NpadStyleIndex::N64);
- ui->comboControllerType->addItem(tr("N64 Controller"));
+ add_item(Core::HID::NpadStyleIndex::N64, tr("N64 Controller"));
}
if (npad_style_set.lager == 1) {
- index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
- Core::HID::NpadStyleIndex::SegaGenesis);
- ui->comboControllerType->addItem(tr("Sega Genesis"));
+ add_item(Core::HID::NpadStyleIndex::SegaGenesis, tr("Sega Genesis"));
}
}
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 1e02d715b..53f11a9ac 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1547,6 +1547,8 @@ void GMainWindow::ShutdownGame() {
emu_thread->wait();
emu_thread = nullptr;
+ emulation_running = false;
+
discord_rpc->Update();
// The emulation is stopped, so closing the window or not does not matter anymore
@@ -1585,8 +1587,6 @@ void GMainWindow::ShutdownGame() {
emu_frametime_label->setVisible(false);
renderer_status_button->setEnabled(true);
- emulation_running = false;
-
game_path.clear();
// When closing the game, destroy the GLWindow to clear the context after the game is closed