diff options
52 files changed, 481 insertions, 210 deletions
diff --git a/.ci/scripts/android/build.sh b/.ci/scripts/android/build.sh index d135af029..98593017f 100755 --- a/.ci/scripts/android/build.sh +++ b/.ci/scripts/android/build.sh @@ -6,7 +6,12 @@ export NDK_CCACHE="$(which ccache)" ccache -s -BUILD_FLAVOR=mainline +BUILD_FLAVOR="mainline" + +BUILD_TYPE="release" +if [ "${GITHUB_REPOSITORY}" == "yuzu-emu/yuzu" ]; then + BUILD_TYPE="relWithDebInfo" +fi if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then export ANDROID_KEYSTORE_FILE="${GITHUB_WORKSPACE}/ks.jks" @@ -15,7 +20,7 @@ fi cd src/android chmod +x ./gradlew -./gradlew "assemble${BUILD_FLAVOR}Release" "bundle${BUILD_FLAVOR}Release" +./gradlew "assemble${BUILD_FLAVOR}${BUILD_TYPE}" "bundle${BUILD_FLAVOR}${BUILD_TYPE}" ccache -s diff --git a/.ci/scripts/android/upload.sh b/.ci/scripts/android/upload.sh index 5f8ca73c0..26b1a7efa 100755 --- a/.ci/scripts/android/upload.sh +++ b/.ci/scripts/android/upload.sh @@ -7,9 +7,16 @@ REV_NAME="yuzu-${GITDATE}-${GITREV}" -BUILD_FLAVOR=mainline +BUILD_FLAVOR="mainline" -cp src/android/app/build/outputs/apk/"${BUILD_FLAVOR}/release/app-${BUILD_FLAVOR}-release.apk" \ +BUILD_TYPE_LOWER="release" +BUILD_TYPE_UPPER="Release" +if [ "${GITHUB_REPOSITORY}" == "yuzu-emu/yuzu" ]; then + BUILD_TYPE_LOWER="relWithDebInfo" + BUILD_TYPE_UPPER="RelWithDebInfo" +fi + +cp src/android/app/build/outputs/apk/"${BUILD_FLAVOR}/${BUILD_TYPE_LOWER}/app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.apk" \ "artifacts/${REV_NAME}.apk" -cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}Release"/"app-${BUILD_FLAVOR}-release.aab" \ +cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}${BUILD_TYPE_UPPER}"/"app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.aab" \ "artifacts/${REV_NAME}.aab" diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt index 21e4e1afd..df760440f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt @@ -18,7 +18,8 @@ enum class IntSetting(override val key: String) : AbstractIntSetting { RENDERER_ANTI_ALIASING("anti_aliasing"), RENDERER_SCREEN_LAYOUT("screen_layout"), RENDERER_ASPECT_RATIO("aspect_ratio"), - AUDIO_OUTPUT_ENGINE("output_engine"); + AUDIO_OUTPUT_ENGINE("output_engine"), + MAX_ANISOTROPY("max_anisotropy"); override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 2e97aee2c..12f7aa1ab 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -245,6 +245,15 @@ abstract class SettingsItem( ) put( SingleChoiceSetting( + IntSetting.MAX_ANISOTROPY, + R.string.anisotropic_filtering, + R.string.anisotropic_filtering_description, + R.array.anisoEntries, + R.array.anisoValues + ) + ) + put( + SingleChoiceSetting( IntSetting.AUDIO_OUTPUT_ENGINE, R.string.audio_output_engine, 0, @@ -298,6 +307,7 @@ abstract class SettingsItem( override val key: String = FASTMEM_COMBINED override val isRuntimeModifiable: Boolean = false + override val pairedSettingKey = BooleanSetting.CPU_DEBUG_MODE.key override val defaultValue: Boolean = true override val isSwitchable: Boolean = true override var global: Boolean diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index a7e965589..db1a1076c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -149,6 +149,7 @@ class SettingsFragmentPresenter( add(IntSetting.RENDERER_VSYNC.key) add(IntSetting.RENDERER_SCALING_FILTER.key) add(IntSetting.RENDERER_ANTI_ALIASING.key) + add(IntSetting.MAX_ANISOTROPY.key) add(IntSetting.RENDERER_SCREEN_LAYOUT.key) add(IntSetting.RENDERER_ASPECT_RATIO.key) add(BooleanSetting.PICTURE_IN_PICTURE.key) diff --git a/src/android/app/src/main/res/layout/list_item_setting_switch.xml b/src/android/app/src/main/res/layout/list_item_setting_switch.xml index 5cb84182e..1c08e2e1b 100644 --- a/src/android/app/src/main/res/layout/list_item_setting_switch.xml +++ b/src/android/app/src/main/res/layout/list_item_setting_switch.xml @@ -24,7 +24,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="24dp" - android:gravity="center_vertical" + android:layout_gravity="center_vertical" android:orientation="vertical" android:layout_weight="1"> diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index e3915ef4f..c882a8e62 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -267,4 +267,21 @@ <item>3</item> </integer-array> + <string-array name="anisoEntries"> + <item>@string/auto</item> + <item>@string/slider_default</item> + <item>@string/multiplier_two</item> + <item>@string/multiplier_four</item> + <item>@string/multiplier_eight</item> + <item>@string/multiplier_sixteen</item> + </string-array> + <integer-array name="anisoValues"> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>4</item> + <item>5</item> + </integer-array> + </resources> diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 0b80b04a4..4d5c268fe 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -225,6 +225,8 @@ <string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string> <string name="use_disk_shader_cache">Disk shader cache</string> <string name="use_disk_shader_cache_description">Reduces stuttering by locally storing and loading generated shaders.</string> + <string name="anisotropic_filtering">Anisotropic filtering</string> + <string name="anisotropic_filtering_description">Improves the quality of textures when viewed at oblique angles</string> <!-- Debug settings strings --> <string name="cpu">CPU</string> @@ -506,6 +508,12 @@ <string name="oboe">oboe</string> <string name="cubeb">cubeb</string> + <!-- Anisotropic filtering options --> + <string name="multiplier_two">2x</string> + <string name="multiplier_four">4x</string> + <string name="multiplier_eight">8x</string> + <string name="multiplier_sixteen">16x</string> + <!-- Black backgrounds theme --> <string name="use_black_backgrounds">Black backgrounds</string> <string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string> diff --git a/src/common/assert.cpp b/src/common/assert.cpp index 6026b7dc2..e2c2cade3 100644 --- a/src/common/assert.cpp +++ b/src/common/assert.cpp @@ -3,16 +3,19 @@ #include "common/assert.h" #include "common/common_funcs.h" +#include "common/logging/backend.h" #include "common/settings.h" void assert_fail_impl() { if (Settings::values.use_debug_asserts) { + Common::Log::Stop(); Crash(); } } [[noreturn]] void unreachable_impl() { + Common::Log::Stop(); Crash(); throw std::runtime_error("Unreachable code"); } diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index d4f27197c..7a267f8c0 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -208,6 +208,10 @@ public: instance->StartBackendThread(); } + static void Stop() { + instance->StopBackendThread(); + } + Impl(const Impl&) = delete; Impl& operator=(const Impl&) = delete; @@ -259,6 +263,15 @@ private: }); } + void StopBackendThread() { + backend_thread.request_stop(); + if (backend_thread.joinable()) { + backend_thread.join(); + } + + ForEachBackend([](Backend& backend) { backend.Flush(); }); + } + Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, const char* function, std::string&& message) const { using std::chrono::duration_cast; @@ -313,6 +326,10 @@ void Start() { Impl::Start(); } +void Stop() { + Impl::Stop(); +} + void DisableLoggingInTests() { initialization_in_progress_suppress_logging = true; } diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h index 12e5e2498..2a9926e9e 100644 --- a/src/common/logging/backend.h +++ b/src/common/logging/backend.h @@ -14,6 +14,9 @@ void Initialize(); void Start(); +/// Explicitly stops the logger thread and flushes the buffers +void Stop(); + void DisableLoggingInTests(); /** diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h index 5c961b202..e7e9fdb38 100644 --- a/src/common/ring_buffer.h +++ b/src/common/ring_buffer.h @@ -103,7 +103,7 @@ private: // Having them on the same cache-line would result in false-sharing between them. // TODO: Remove this ifdef whenever clang and GCC support // std::hardware_destructive_interference_size. -#if defined(_MSC_VER) && _MSC_VER >= 1911 +#ifdef __cpp_lib_hardware_interference_size alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0}; alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0}; #else diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index e960edb47..367d01dc7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -988,6 +988,8 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) arm/dynarmic/dynarmic_cp15.h arm/dynarmic/dynarmic_exclusive_monitor.cpp arm/dynarmic/dynarmic_exclusive_monitor.h + hle/service/jit/jit_code_memory.cpp + hle/service/jit/jit_code_memory.h hle/service/jit/jit_context.cpp hle/service/jit/jit_context.h hle/service/jit/jit.cpp diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp index 7be1322cc..31033634c 100644 --- a/src/core/file_sys/ips_layer.cpp +++ b/src/core/file_sys/ips_layer.cpp @@ -73,6 +73,9 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) { return nullptr; auto in_data = in->ReadAllBytes(); + if (in_data.size() == 0) { + return nullptr; + } std::vector<u8> temp(type == IPSFileType::IPS ? 3 : 4); u64 offset = 5; // After header @@ -88,6 +91,10 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) { else real_offset = (temp[0] << 16) | (temp[1] << 8) | temp[2]; + if (real_offset > in_data.size()) { + return nullptr; + } + u16 data_size{}; if (ips->ReadObject(&data_size, offset) != sizeof(u16)) return nullptr; diff --git a/src/core/hle/kernel/k_auto_object_container.cpp b/src/core/hle/kernel/k_auto_object_container.cpp index 636b3f993..7bea1a1c2 100644 --- a/src/core/hle/kernel/k_auto_object_container.cpp +++ b/src/core/hle/kernel/k_auto_object_container.cpp @@ -8,19 +8,22 @@ namespace Kernel { void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) { - KScopedLightLock lk(m_lock); + // KScopedInterruptDisable di; + KScopedSpinLock lk(m_lock); m_object_list.insert_unique(*obj); } void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) { - KScopedLightLock lk(m_lock); + // KScopedInterruptDisable di; + KScopedSpinLock lk(m_lock); m_object_list.erase(*obj); } size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) { - KScopedLightLock lk(m_lock); + // KScopedInterruptDisable di; + KScopedSpinLock lk(m_lock); return std::count_if(m_object_list.begin(), m_object_list.end(), [&](const auto& obj) { return obj.GetOwner() == owner; }); diff --git a/src/core/hle/kernel/k_auto_object_container.h b/src/core/hle/kernel/k_auto_object_container.h index badd75d2a..770743d21 100644 --- a/src/core/hle/kernel/k_auto_object_container.h +++ b/src/core/hle/kernel/k_auto_object_container.h @@ -7,7 +7,7 @@ #include "common/common_funcs.h" #include "core/hle/kernel/k_auto_object.h" -#include "core/hle/kernel/k_light_lock.h" +#include "core/hle/kernel/k_spin_lock.h" namespace Kernel { @@ -21,32 +21,7 @@ public: using ListType = boost::intrusive::rbtree<KAutoObjectWithList>; - class ListAccessor : public KScopedLightLock { - public: - explicit ListAccessor(KAutoObjectWithListContainer* container) - : KScopedLightLock(container->m_lock), m_list(container->m_object_list) {} - explicit ListAccessor(KAutoObjectWithListContainer& container) - : KScopedLightLock(container.m_lock), m_list(container.m_object_list) {} - - typename ListType::iterator begin() const { - return m_list.begin(); - } - - typename ListType::iterator end() const { - return m_list.end(); - } - - typename ListType::iterator find(typename ListType::const_reference ref) const { - return m_list.find(ref); - } - - private: - ListType& m_list; - }; - - friend class ListAccessor; - - KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {} + KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(), m_object_list() {} void Initialize() {} void Finalize() {} @@ -56,7 +31,7 @@ public: size_t GetOwnedCount(KProcess* owner); private: - KLightLock m_lock; + KSpinLock m_lock; ListType m_object_list; }; diff --git a/src/core/hle/kernel/k_capabilities.cpp b/src/core/hle/kernel/k_capabilities.cpp index 274fee493..d2288c30d 100644 --- a/src/core/hle/kernel/k_capabilities.cpp +++ b/src/core/hle/kernel/k_capabilities.cpp @@ -185,6 +185,10 @@ Result KCapabilities::ProcessMapRegionCapability(const u32 cap, F f) { case RegionType::NoMapping: break; case RegionType::KernelTraceBuffer: + if constexpr (!IsKTraceEnabled) { + break; + } + [[fallthrough]]; case RegionType::OnMemoryBootImage: case RegionType::DTB: R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm)); @@ -330,8 +334,6 @@ Result KCapabilities::SetCapabilities(std::span<const u32> caps, KProcessPageTab // Map the range. R_TRY(this->MapRange_(cap, size_cap, page_table)); - } else if (GetCapabilityType(cap) == CapabilityType::MapRegion && !IsKTraceEnabled) { - continue; } else { R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table)); } diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h index 4e6dcd66b..1bf68e6b0 100644 --- a/src/core/hle/kernel/k_handle_table.h +++ b/src/core/hle/kernel/k_handle_table.h @@ -30,7 +30,7 @@ public: public: explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {} - Result Initialize(KProcess* owner, s32 size) { + Result Initialize(s32 size) { // Check that the table size is valid. R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory); @@ -44,7 +44,6 @@ public: m_next_linear_id = MinLinearId; m_count = 0; m_free_head_index = -1; - m_owner = owner; // Free all entries. for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) { @@ -91,8 +90,7 @@ public: // Handle pseudo-handles. if constexpr (std::derived_from<KProcess, T>) { if (handle == Svc::PseudoHandle::CurrentProcess) { - // TODO: this should be the current process - auto* const cur_process = m_owner; + auto* const cur_process = GetCurrentProcessPointer(m_kernel); ASSERT(cur_process != nullptr); return cur_process; } @@ -302,7 +300,6 @@ private: private: KernelCore& m_kernel; - KProcess* m_owner{}; std::array<EntryInfo, MaxTableSize> m_entry_infos{}; std::array<KAutoObject*, MaxTableSize> m_objects{}; mutable KSpinLock m_lock; diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index b5c6867a1..53c0e3316 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -552,7 +552,7 @@ private: Result InitializeHandleTable(s32 size) { // Try to initialize the handle table. - R_TRY(m_handle_table.Initialize(this, size)); + R_TRY(m_handle_table.Initialize(size)); // We succeeded, so note that we did. m_is_handle_table_initialized = true; diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index f6ca3dc48..adaabdd6d 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -1147,8 +1147,7 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server *out_context = std::make_shared<Service::HLERequestContext>(m_kernel, memory, this, client_thread); (*out_context)->SetSessionRequestManager(manager); - (*out_context) - ->PopulateFromIncomingCommandBuffer(*client_thread->GetOwnerProcess(), cmd_buf); + (*out_context)->PopulateFromIncomingCommandBuffer(cmd_buf); // We succeeded. R_SUCCEED(); } else { diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h index 8a0b08761..530b45218 100644 --- a/src/core/hle/kernel/k_transfer_memory.h +++ b/src/core/hle/kernel/k_transfer_memory.h @@ -5,6 +5,7 @@ #include <optional> +#include "core/hle/kernel/k_light_lock.h" #include "core/hle/kernel/k_page_group.h" #include "core/hle/kernel/slab_helpers.h" #include "core/hle/kernel/svc_types.h" diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index a266d7c21..97eb56ff0 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1513,8 +1513,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) return; } - auto transfer_mem = - system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle); + auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle); if (transfer_mem.IsNull()) { LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); @@ -1524,8 +1523,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) } std::vector<u8> memory(transfer_mem->GetSize()); - system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), - memory.size()); + ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); @@ -1547,8 +1545,7 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) { return; } - auto transfer_mem = - system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle); + auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle); if (transfer_mem.IsNull()) { LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); @@ -1558,8 +1555,7 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) { } std::vector<u8> memory(transfer_mem->GetSize()); - system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), - memory.size()); + ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 23e56c77a..bd4ca753b 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -454,10 +454,8 @@ void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) { return; } - const auto& handle_table{system.ApplicationProcess()->GetHandleTable()}; - auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)}; - auto transfer_memory{ - process->GetHandleTable().GetObject<Kernel::KTransferMemory>(transfer_memory_handle)}; + auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)}; + auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; const auto session_id{impl->GetSessionId()}; if (session_id == -1) { diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 6a7bf9416..91f33aabd 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -278,9 +278,7 @@ void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) { auto params = rp.PopRaw<OpusParameters>(); auto transfer_memory_size{rp.Pop<u32>()}; auto transfer_memory_handle{ctx.GetCopyHandle(0)}; - auto transfer_memory{ - system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( - transfer_memory_handle)}; + auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}", params.sample_rate, params.channel_count, transfer_memory_size); @@ -323,9 +321,7 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) { auto transfer_memory_size{rp.Pop<u32>()}; auto transfer_memory_handle{ctx.GetCopyHandle(0)}; - auto transfer_memory{ - system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( - transfer_memory_handle)}; + auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " @@ -374,9 +370,7 @@ void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) { auto params = rp.PopRaw<OpusParametersEx>(); auto transfer_memory_size{rp.Pop<u32>()}; auto transfer_memory_handle{ctx.GetCopyHandle(0)}; - auto transfer_memory{ - system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( - transfer_memory_handle)}; + auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}", params.sample_rate, params.channel_count, transfer_memory_size); @@ -414,9 +408,7 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) { auto transfer_memory_size{rp.Pop<u32>()}; auto transfer_memory_handle{ctx.GetCopyHandle(0)}; - auto transfer_memory{ - system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( - transfer_memory_handle)}; + auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp index 06a01c02c..3174672af 100644 --- a/src/core/hle/service/hid/hid_server.cpp +++ b/src/core/hle/service/hid/hid_server.cpp @@ -1850,8 +1850,7 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) { ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes"); ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes"); - auto t_mem_1 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( - t_mem_1_handle); + auto t_mem_1 = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_1_handle); if (t_mem_1.IsNull()) { LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle); @@ -1860,8 +1859,7 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) { return; } - auto t_mem_2 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( - t_mem_2_handle); + auto t_mem_2 = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_2_handle); if (t_mem_2.IsNull()) { LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle); @@ -2142,8 +2140,7 @@ void IHidServer::WritePalmaWaveEntry(HLERequestContext& ctx) { ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes"); - auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( - t_mem_handle); + auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle); if (t_mem.IsNull()) { LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp index 80aac221b..d12f9beb0 100644 --- a/src/core/hle/service/hid/hidbus.cpp +++ b/src/core/hle/service/hid/hidbus.cpp @@ -448,8 +448,7 @@ void HidBus::EnableJoyPollingReceiveMode(HLERequestContext& ctx) { ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes"); - auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( - t_mem_handle); + auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle); if (t_mem.IsNull()) { LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 39b9a4474..008debfd1 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -197,8 +197,7 @@ void IRS::RunImageTransferProcessor(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; const auto t_mem_handle{ctx.GetCopyHandle(0)}; - auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( - t_mem_handle); + auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle); if (t_mem.IsNull()) { LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); @@ -444,8 +443,7 @@ void IRS::RunImageTransferExProcessor(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; const auto t_mem_handle{ctx.GetCopyHandle(0)}; - auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( - t_mem_handle); + auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle); LOG_INFO(Service_IRS, "called, npad_type={}, npad_id={}, transfer_memory_size={}, " diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp index 38955932c..39df77e43 100644 --- a/src/core/hle/service/hle_ipc.cpp +++ b/src/core/hle/service/hle_ipc.cpp @@ -146,10 +146,7 @@ HLERequestContext::HLERequestContext(Kernel::KernelCore& kernel_, Core::Memory:: HLERequestContext::~HLERequestContext() = default; -void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, - bool incoming) { - client_handle_table = &process.GetHandleTable(); - +void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { IPC::RequestParser rp(src_cmdbuf); command_header = rp.PopRaw<IPC::CommandHeader>(); @@ -162,7 +159,7 @@ void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* sr if (command_header->enable_handle_descriptor) { handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>(); if (handle_descriptor_header->send_current_pid) { - pid = process.GetProcessId(); + pid = thread->GetOwnerProcess()->GetProcessId(); rp.Skip(2, false); } if (incoming) { @@ -270,9 +267,10 @@ void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* sr rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. } -Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, - u32_le* src_cmdbuf) { - ParseCommandBuffer(process, src_cmdbuf, true); +Result HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf) { + client_handle_table = &thread->GetOwnerProcess()->GetHandleTable(); + + ParseCommandBuffer(src_cmdbuf, true); if (command_header->IsCloseCommand()) { // Close does not populate the rest of the IPC header @@ -284,9 +282,9 @@ Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& pr return ResultSuccess; } -Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread) { +Result HLERequestContext::WriteToOutgoingCommandBuffer() { auto current_offset = handles_offset; - auto& owner_process = *requesting_thread.GetOwnerProcess(); + auto& owner_process = *thread->GetOwnerProcess(); auto& handle_table = owner_process.GetHandleTable(); for (auto& object : outgoing_copy_objects) { @@ -319,7 +317,7 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesti } // Copy the translated command buffer back into the thread's command buffer area. - memory.WriteBlock(requesting_thread.GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32)); + memory.WriteBlock(thread->GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32)); return ResultSuccess; } diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h index 18d464c63..40d86943e 100644 --- a/src/core/hle/service/hle_ipc.h +++ b/src/core/hle/service/hle_ipc.h @@ -17,6 +17,7 @@ #include "common/concepts.h" #include "common/swap.h" #include "core/hle/ipc.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/svc_common.h" union Result; @@ -196,10 +197,10 @@ public: } /// Populates this context with data from the requesting process/thread. - Result PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf); + Result PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf); /// Writes data from this context back to the requesting process/thread. - Result WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread); + Result WriteToOutgoingCommandBuffer(); [[nodiscard]] u32_le GetHipcCommand() const { return command; @@ -359,8 +360,17 @@ public: return *thread; } - Kernel::KHandleTable& GetClientHandleTable() { - return *client_handle_table; + [[nodiscard]] Core::Memory::Memory& GetMemory() const { + return memory; + } + + template <typename T> + Kernel::KScopedAutoObject<T> GetObjectFromHandle(u32 handle) { + auto obj = client_handle_table->GetObjectForIpc(handle, thread); + if (obj.IsNotNull()) { + return obj->DynamicCast<T*>(); + } + return nullptr; } [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const { @@ -378,7 +388,7 @@ public: private: friend class IPC::ResponseBuilder; - void ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, bool incoming); + void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming); std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; Kernel::KServerSession* server_session{}; diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp index 65851fc05..77aa6d7d1 100644 --- a/src/core/hle/service/jit/jit.cpp +++ b/src/core/hle/service/jit/jit.cpp @@ -4,11 +4,11 @@ #include "core/arm/debug.h" #include "core/arm/symbols.h" #include "core/core.h" -#include "core/hle/kernel/k_code_memory.h" #include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/result.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/jit/jit.h" +#include "core/hle/service/jit/jit_code_memory.h" #include "core/hle/service/jit/jit_context.h" #include "core/hle/service/server_manager.h" #include "core/hle/service/service.h" @@ -23,9 +23,11 @@ struct CodeRange { class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { public: - explicit IJitEnvironment(Core::System& system_, Kernel::KProcess& process_, CodeRange user_rx, - CodeRange user_ro) - : ServiceFramework{system_, "IJitEnvironment"}, process{&process_}, + explicit IJitEnvironment(Core::System& system_, + Kernel::KScopedAutoObject<Kernel::KProcess>&& process_, + CodeMemory&& user_rx_, CodeMemory&& user_ro_) + : ServiceFramework{system_, "IJitEnvironment"}, process{std::move(process_)}, + user_rx{std::move(user_rx_)}, user_ro{std::move(user_ro_)}, context{system_.ApplicationMemory()} { // clang-format off static const FunctionInfo functions[] = { @@ -39,10 +41,13 @@ public: RegisterHandlers(functions); // Identity map user code range into sysmodule context - configuration.user_ro_memory = user_ro; - configuration.user_rx_memory = user_rx; - configuration.sys_ro_memory = user_ro; - configuration.sys_rx_memory = user_rx; + configuration.user_rx_memory.size = user_rx.GetSize(); + configuration.user_rx_memory.offset = user_rx.GetAddress(); + configuration.user_ro_memory.size = user_ro.GetSize(); + configuration.user_ro_memory.offset = user_ro.GetAddress(); + + configuration.sys_rx_memory = configuration.user_rx_memory; + configuration.sys_ro_memory = configuration.user_ro_memory; } void GenerateCode(HLERequestContext& ctx) { @@ -188,7 +193,7 @@ public: return; } - auto tmem{process->GetHandleTable().GetObject<Kernel::KTransferMemory>(tmem_handle)}; + auto tmem{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(tmem_handle)}; if (tmem.IsNull()) { LOG_ERROR(Service_JIT, "attempted to load plugin with invalid transfer memory handle"); IPC::ResponseBuilder rb{ctx, 2}; @@ -318,6 +323,8 @@ private: } Kernel::KScopedAutoObject<Kernel::KProcess> process; + CodeMemory user_rx; + CodeMemory user_ro; GuestCallbacks callbacks; JITConfiguration configuration; JITContext context; @@ -335,6 +342,7 @@ public: RegisterHandlers(functions); } +private: void CreateJitEnvironment(HLERequestContext& ctx) { LOG_DEBUG(Service_JIT, "called"); @@ -356,11 +364,7 @@ public: return; } - // Fetch using the handle table for the application process here, - // since we are not multiprocess yet. - const auto& handle_table{system.ApplicationProcess()->GetHandleTable()}; - - auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)}; + auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)}; if (process.IsNull()) { LOG_ERROR(Service_JIT, "process is null for handle=0x{:08X}", process_handle); IPC::ResponseBuilder rb{ctx, 2}; @@ -368,7 +372,7 @@ public: return; } - auto rx_mem{handle_table.GetObject<Kernel::KCodeMemory>(rx_mem_handle)}; + auto rx_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(rx_mem_handle)}; if (rx_mem.IsNull()) { LOG_ERROR(Service_JIT, "rx_mem is null for handle=0x{:08X}", rx_mem_handle); IPC::ResponseBuilder rb{ctx, 2}; @@ -376,7 +380,7 @@ public: return; } - auto ro_mem{handle_table.GetObject<Kernel::KCodeMemory>(ro_mem_handle)}; + auto ro_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(ro_mem_handle)}; if (ro_mem.IsNull()) { LOG_ERROR(Service_JIT, "ro_mem is null for handle=0x{:08X}", ro_mem_handle); IPC::ResponseBuilder rb{ctx, 2}; @@ -384,20 +388,35 @@ public: return; } - const CodeRange user_rx{ - .offset = GetInteger(rx_mem->GetSourceAddress()), - .size = parameters.rx_size, - }; + CodeMemory rx, ro; + Result res; - const CodeRange user_ro{ - .offset = GetInteger(ro_mem->GetSourceAddress()), - .size = parameters.ro_size, - }; + res = rx.Initialize(*process, *rx_mem, parameters.rx_size, + Kernel::Svc::MemoryPermission::ReadExecute, generate_random); + if (R_FAILED(res)) { + LOG_ERROR(Service_JIT, "rx_mem could not be mapped for handle=0x{:08X}", rx_mem_handle); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); + return; + } + + res = ro.Initialize(*process, *ro_mem, parameters.ro_size, + Kernel::Svc::MemoryPermission::Read, generate_random); + if (R_FAILED(res)) { + LOG_ERROR(Service_JIT, "ro_mem could not be mapped for handle=0x{:08X}", ro_mem_handle); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); + return; + } IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface<IJitEnvironment>(system, *process, user_rx, user_ro); + rb.PushIpcInterface<IJitEnvironment>(system, std::move(process), std::move(rx), + std::move(ro)); } + +private: + std::mt19937_64 generate_random{}; }; void LoopProcess(Core::System& system) { diff --git a/src/core/hle/service/jit/jit_code_memory.cpp b/src/core/hle/service/jit/jit_code_memory.cpp new file mode 100644 index 000000000..2b480488a --- /dev/null +++ b/src/core/hle/service/jit/jit_code_memory.cpp @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/jit/jit_code_memory.h" + +namespace Service::JIT { + +Result CodeMemory::Initialize(Kernel::KProcess& process, Kernel::KCodeMemory& code_memory, + size_t size, Kernel::Svc::MemoryPermission perm, + std::mt19937_64& generate_random) { + auto& page_table = process.GetPageTable(); + const u64 alias_code_start = + GetInteger(page_table.GetAliasCodeRegionStart()) / Kernel::PageSize; + const u64 alias_code_size = page_table.GetAliasCodeRegionSize() / Kernel::PageSize; + + // NOTE: This will retry indefinitely until mapping the code memory succeeds. + while (true) { + // Generate a new trial address. + const u64 mapped_address = + (alias_code_start + (generate_random() % alias_code_size)) * Kernel::PageSize; + + // Try to map the address + R_TRY_CATCH(code_memory.MapToOwner(mapped_address, size, perm)) { + R_CATCH(Kernel::ResultInvalidMemoryRegion) { + // If we could not map here, retry. + continue; + } + } + R_END_TRY_CATCH; + + // Set members. + m_code_memory = std::addressof(code_memory); + m_size = size; + m_address = mapped_address; + m_perm = perm; + + // Open a new reference to the code memory. + m_code_memory->Open(); + + // We succeeded. + R_SUCCEED(); + } +} + +void CodeMemory::Finalize() { + if (m_code_memory) { + R_ASSERT(m_code_memory->UnmapFromOwner(m_address, m_size)); + m_code_memory->Close(); + } + + m_code_memory = nullptr; +} + +} // namespace Service::JIT diff --git a/src/core/hle/service/jit/jit_code_memory.h b/src/core/hle/service/jit/jit_code_memory.h new file mode 100644 index 000000000..6376d4c4e --- /dev/null +++ b/src/core/hle/service/jit/jit_code_memory.h @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <random> + +#include "core/hle/kernel/k_code_memory.h" + +namespace Service::JIT { + +class CodeMemory { +public: + YUZU_NON_COPYABLE(CodeMemory); + + explicit CodeMemory() = default; + + CodeMemory(CodeMemory&& rhs) { + std::swap(m_code_memory, rhs.m_code_memory); + std::swap(m_size, rhs.m_size); + std::swap(m_address, rhs.m_address); + std::swap(m_perm, rhs.m_perm); + } + + ~CodeMemory() { + this->Finalize(); + } + +public: + Result Initialize(Kernel::KProcess& process, Kernel::KCodeMemory& code_memory, size_t size, + Kernel::Svc::MemoryPermission perm, std::mt19937_64& generate_random); + void Finalize(); + + size_t GetSize() const { + return m_size; + } + + u64 GetAddress() const { + return m_address; + } + +private: + Kernel::KCodeMemory* m_code_memory{}; + size_t m_size{}; + u64 m_address{}; + Kernel::Svc::MemoryPermission m_perm{}; +}; + +} // namespace Service::JIT diff --git a/src/core/hle/service/ro/ro.cpp b/src/core/hle/service/ro/ro.cpp index 17110d3f1..f0658bb5d 100644 --- a/src/core/hle/service/ro/ro.cpp +++ b/src/core/hle/service/ro/ro.cpp @@ -651,10 +651,9 @@ private: void RegisterProcessHandle(HLERequestContext& ctx) { LOG_DEBUG(Service_LDR, "(called)"); - auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0)); + auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0)); auto client_pid = ctx.GetPID(); - auto result = interface.RegisterProcessHandle(client_pid, - process_h->DynamicCast<Kernel::KProcess*>()); + auto result = interface.RegisterProcessHandle(client_pid, process.GetPointerUnsafe()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); @@ -671,12 +670,11 @@ private: IPC::RequestParser rp{ctx}; auto params = rp.PopRaw<InputParameters>(); - auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0)); + auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0)); auto client_pid = ctx.GetPID(); - auto result = - interface.RegisterProcessModuleInfo(client_pid, params.nrr_address, params.nrr_size, - process_h->DynamicCast<Kernel::KProcess*>()); + auto result = interface.RegisterProcessModuleInfo( + client_pid, params.nrr_address, params.nrr_size, process.GetPointerUnsafe()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 00531b021..39124c5fd 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -203,7 +203,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session, // If emulation was shutdown, we are closing service threads, do not write the response back to // memory that may be shutting down as well. if (system.IsPoweredOn()) { - ctx.WriteToOutgoingCommandBuffer(ctx.GetThread()); + ctx.WriteToOutgoingCommandBuffer(); } return result; diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index ed023fcfe..89ebab08e 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -96,9 +96,9 @@ Id ImageType(EmitContext& ctx, const ImageDescriptor& desc, Id sampled_type) { } Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin, - spv::StorageClass storage_class) { + spv::StorageClass storage_class, std::optional<Id> initializer = std::nullopt) { const Id pointer_type{ctx.TypePointer(storage_class, type)}; - const Id id{ctx.AddGlobalVariable(pointer_type, storage_class)}; + const Id id{ctx.AddGlobalVariable(pointer_type, storage_class, initializer)}; if (builtin) { ctx.Decorate(id, spv::Decoration::BuiltIn, *builtin); } @@ -144,11 +144,12 @@ Id DefineInput(EmitContext& ctx, Id type, bool per_invocation, } Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations, - std::optional<spv::BuiltIn> builtin = std::nullopt) { + std::optional<spv::BuiltIn> builtin = std::nullopt, + std::optional<Id> initializer = std::nullopt) { if (invocations && ctx.stage == Stage::TessellationControl) { type = ctx.TypeArray(type, ctx.Const(*invocations)); } - return DefineVariable(ctx, type, builtin, spv::StorageClass::Output); + return DefineVariable(ctx, type, builtin, spv::StorageClass::Output, initializer); } void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invocations) { @@ -811,10 +812,14 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) { labels.push_back(OpLabel()); } if (info.stores.ClipDistances()) { - literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2); - labels.push_back(OpLabel()); - literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2); - labels.push_back(OpLabel()); + if (profile.max_user_clip_distances >= 4) { + literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2); + labels.push_back(OpLabel()); + } + if (profile.max_user_clip_distances >= 8) { + literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2); + labels.push_back(OpLabel()); + } } OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); OpSwitch(compare_index, default_label, literals, labels); @@ -843,17 +848,21 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) { ++label_index; } if (info.stores.ClipDistances()) { - AddLabel(labels[label_index]); - const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)}; - OpStore(pointer, store_value); - OpReturn(); - ++label_index; - AddLabel(labels[label_index]); - const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))}; - const Id pointer2{OpAccessChain(output_f32, clip_distances, fixed_index)}; - OpStore(pointer2, store_value); - OpReturn(); - ++label_index; + if (profile.max_user_clip_distances >= 4) { + AddLabel(labels[label_index]); + const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)}; + OpStore(pointer, store_value); + OpReturn(); + ++label_index; + } + if (profile.max_user_clip_distances >= 8) { + AddLabel(labels[label_index]); + const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))}; + const Id pointer{OpAccessChain(output_f32, clip_distances, fixed_index)}; + OpStore(pointer, store_value); + OpReturn(); + ++label_index; + } } AddLabel(end_block); OpUnreachable(); @@ -1532,9 +1541,16 @@ void EmitContext::DefineOutputs(const IR::Program& program) { if (stage == Stage::Fragment) { throw NotImplementedException("Storing ClipDistance in fragment stage"); } - const Id type{TypeArray( - F32[1], Const(std::min(info.used_clip_distances, profile.max_user_clip_distances)))}; - clip_distances = DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance); + if (profile.max_user_clip_distances > 0) { + const u32 used{std::min(profile.max_user_clip_distances, 8u)}; + const std::array<Id, 8> zero{f32_zero_value, f32_zero_value, f32_zero_value, + f32_zero_value, f32_zero_value, f32_zero_value, + f32_zero_value, f32_zero_value}; + const Id type{TypeArray(F32[1], Const(used))}; + const Id initializer{ConstantComposite(type, std::span(zero).subspan(0, used))}; + clip_distances = + DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance, initializer); + } } if (info.stores[IR::Attribute::Layer] && (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index 046c8085e..46e853e04 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp @@ -327,12 +327,13 @@ public: explicit HLE_DrawIndirectByteCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override { + const bool force = maxwell3d.Rasterizer().HasDrawTransformFeedback(); + auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0xFFFFU); - if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) { + if (!force && (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology))) { Fallback(parameters); return; } - auto& params = maxwell3d.draw_manager->GetIndirectParams(); params.is_byte_count = true; params.is_indexed = false; @@ -503,6 +504,8 @@ public: maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true); maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(inline_data)), regs.transform_feedback.controls[0].stride, true); + + maxwell3d.Rasterizer().RegisterTransformFeedback(regs.upload.dest.Address()); } }; diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index af1469147..49224ca85 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -173,5 +173,13 @@ public: virtual void BindChannel(Tegra::Control::ChannelState& channel) {} virtual void ReleaseChannel(s32 channel_id) {} + + /// Register the address as a Transform Feedback Object + virtual void RegisterTransformFeedback(GPUVAddr tfb_object_addr) {} + + /// Returns true when the rasterizer has Draw Transform Feedback capabilities + virtual bool HasDrawTransformFeedback() { + return false; + } }; } // namespace VideoCore diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index b787b6994..517ac14dd 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp @@ -376,4 +376,15 @@ void BufferCacheRuntime::BindImageBuffer(Buffer& buffer, u32 offset, u32 size, P *image_handles++ = buffer.View(offset, size, format); } +void BufferCacheRuntime::BindTransformFeedbackObject(GPUVAddr tfb_object_addr) { + OGLTransformFeedback& tfb_object = tfb_objects[tfb_object_addr]; + tfb_object.Create(); + glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfb_object.handle); +} + +GLuint BufferCacheRuntime::GetTransformFeedbackObject(GPUVAddr tfb_object_addr) { + ASSERT(tfb_objects.contains(tfb_object_addr)); + return tfb_objects[tfb_object_addr].handle; +} + } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h index 1e8708f59..2c18de166 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.h +++ b/src/video_core/renderer_opengl/gl_buffer_cache.h @@ -5,6 +5,7 @@ #include <array> #include <span> +#include <unordered_map> #include "common/common_types.h" #include "video_core/buffer_cache/buffer_cache_base.h" @@ -121,6 +122,9 @@ public: void BindImageBuffer(Buffer& buffer, u32 offset, u32 size, VideoCore::Surface::PixelFormat format); + void BindTransformFeedbackObject(GPUVAddr tfb_object_addr); + GLuint GetTransformFeedbackObject(GPUVAddr tfb_object_addr); + u64 GetDeviceMemoryUsage() const; void BindFastUniformBuffer(size_t stage, u32 binding_index, u32 size) { @@ -233,6 +237,7 @@ private: u32 index_buffer_offset = 0; u64 device_access_memory; + std::unordered_map<GPUVAddr, OGLTransformFeedback> tfb_objects; }; struct BufferCacheParams { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 339950d2e..7a5fad735 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -309,6 +309,13 @@ void RasterizerOpenGL::DrawIndirect() { const auto& params = maxwell3d->draw_manager->GetIndirectParams(); buffer_cache.SetDrawIndirect(¶ms); PrepareDraw(params.is_indexed, [this, ¶ms](GLenum primitive_mode) { + if (params.is_byte_count) { + const GPUVAddr tfb_object_base_addr = params.indirect_start_address - 4U; + const GLuint tfb_object = + buffer_cache_runtime.GetTransformFeedbackObject(tfb_object_base_addr); + glDrawTransformFeedback(primitive_mode, tfb_object); + return; + } const auto [buffer, offset] = buffer_cache.GetDrawIndirectBuffer(); const GLvoid* const gl_offset = reinterpret_cast<const GLvoid*>(static_cast<uintptr_t>(offset)); @@ -1371,6 +1378,10 @@ void RasterizerOpenGL::ReleaseChannel(s32 channel_id) { query_cache.EraseChannel(channel_id); } +void RasterizerOpenGL::RegisterTransformFeedback(GPUVAddr tfb_object_addr) { + buffer_cache_runtime.BindTransformFeedbackObject(tfb_object_addr); +} + AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_, TextureCache& texture_cache_) : buffer_cache{buffer_cache_}, texture_cache{texture_cache_} {} diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index b79d7a70c..ce3460938 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -139,6 +139,12 @@ public: void ReleaseChannel(s32 channel_id) override; + void RegisterTransformFeedback(GPUVAddr tfb_object_addr) override; + + bool HasDrawTransformFeedback() override { + return true; + } + private: static constexpr size_t MAX_TEXTURES = 192; static constexpr size_t MAX_IMAGES = 48; diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp index eae8fd110..1d2c9b70a 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.cpp +++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp @@ -207,4 +207,21 @@ void OGLQuery::Release() { handle = 0; } +void OGLTransformFeedback::Create() { + if (handle != 0) + return; + + MICROPROFILE_SCOPE(OpenGL_ResourceCreation); + glCreateTransformFeedbacks(1, &handle); +} + +void OGLTransformFeedback::Release() { + if (handle == 0) + return; + + MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); + glDeleteTransformFeedbacks(1, &handle); + handle = 0; +} + } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index 77362acd2..6ca8227bd 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h @@ -323,4 +323,31 @@ public: GLuint handle = 0; }; +class OGLTransformFeedback final { +public: + YUZU_NON_COPYABLE(OGLTransformFeedback); + + OGLTransformFeedback() = default; + + OGLTransformFeedback(OGLTransformFeedback&& o) noexcept : handle(std::exchange(o.handle, 0)) {} + + ~OGLTransformFeedback() { + Release(); + } + + OGLTransformFeedback& operator=(OGLTransformFeedback&& o) noexcept { + Release(); + handle = std::exchange(o.handle, 0); + return *this; + } + + /// Creates a new internal OpenGL resource and stores the handle + void Create(); + + /// Deletes the internal OpenGL resource + void Release(); + + GLuint handle = 0; +}; + } // namespace OpenGL diff --git a/src/video_core/texture_cache/decode_bc.cpp b/src/video_core/texture_cache/decode_bc.cpp index 3e26474a3..a018c6df4 100644 --- a/src/video_core/texture_cache/decode_bc.cpp +++ b/src/video_core/texture_cache/decode_bc.cpp @@ -60,66 +60,72 @@ u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format) { } template <auto decompress, PixelFormat pixel_format> -void DecompressBlocks(std::span<const u8> input, std::span<u8> output, Extent3D extent, +void DecompressBlocks(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy, bool is_signed = false) { const u32 out_bpp = ConvertedBytesPerBlock(pixel_format); - const u32 block_width = std::min(extent.width, BLOCK_SIZE); - const u32 block_height = std::min(extent.height, BLOCK_SIZE); - const u32 pitch = extent.width * out_bpp; + const u32 block_size = BlockSize(pixel_format); + const u32 width = copy.image_extent.width; + const u32 height = copy.image_extent.height * copy.image_subresource.num_layers; + const u32 depth = copy.image_extent.depth; + const u32 block_width = std::min(width, BLOCK_SIZE); + const u32 block_height = std::min(height, BLOCK_SIZE); + const u32 pitch = width * out_bpp; size_t input_offset = 0; size_t output_offset = 0; - for (u32 slice = 0; slice < extent.depth; ++slice) { - for (u32 y = 0; y < extent.height; y += block_height) { - size_t row_offset = 0; - for (u32 x = 0; x < extent.width; - x += block_width, row_offset += block_width * out_bpp) { - const u8* src = input.data() + input_offset; - u8* const dst = output.data() + output_offset + row_offset; + for (u32 slice = 0; slice < depth; ++slice) { + for (u32 y = 0; y < height; y += block_height) { + size_t src_offset = input_offset; + size_t dst_offset = output_offset; + for (u32 x = 0; x < width; x += block_width) { + const u8* src = input.data() + src_offset; + u8* const dst = output.data() + dst_offset; if constexpr (IsSigned(pixel_format)) { - decompress(src, dst, x, y, extent.width, extent.height, is_signed); + decompress(src, dst, x, y, width, height, is_signed); } else { - decompress(src, dst, x, y, extent.width, extent.height); + decompress(src, dst, x, y, width, height); } - input_offset += BlockSize(pixel_format); + src_offset += block_size; + dst_offset += block_width * out_bpp; } + input_offset += copy.buffer_row_length * block_size / block_width; output_offset += block_height * pitch; } } } -void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent, +void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy, VideoCore::Surface::PixelFormat pixel_format) { switch (pixel_format) { case PixelFormat::BC1_RGBA_UNORM: case PixelFormat::BC1_RGBA_SRGB: - DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, extent); + DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, copy); break; case PixelFormat::BC2_UNORM: case PixelFormat::BC2_SRGB: - DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, extent); + DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, copy); break; case PixelFormat::BC3_UNORM: case PixelFormat::BC3_SRGB: - DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, extent); + DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, copy); break; case PixelFormat::BC4_SNORM: case PixelFormat::BC4_UNORM: DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>( - input, output, extent, pixel_format == PixelFormat::BC4_SNORM); + input, output, copy, pixel_format == PixelFormat::BC4_SNORM); break; case PixelFormat::BC5_SNORM: case PixelFormat::BC5_UNORM: DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>( - input, output, extent, pixel_format == PixelFormat::BC5_SNORM); + input, output, copy, pixel_format == PixelFormat::BC5_SNORM); break; case PixelFormat::BC6H_SFLOAT: case PixelFormat::BC6H_UFLOAT: DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>( - input, output, extent, pixel_format == PixelFormat::BC6H_SFLOAT); + input, output, copy, pixel_format == PixelFormat::BC6H_SFLOAT); break; case PixelFormat::BC7_SRGB: case PixelFormat::BC7_UNORM: - DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, extent); + DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, copy); break; default: LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format); diff --git a/src/video_core/texture_cache/decode_bc.h b/src/video_core/texture_cache/decode_bc.h index 41d1ec0a3..4e3b9b8ac 100644 --- a/src/video_core/texture_cache/decode_bc.h +++ b/src/video_core/texture_cache/decode_bc.h @@ -13,7 +13,7 @@ namespace VideoCommon { [[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format); -void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent, +void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy, VideoCore::Surface::PixelFormat pixel_format); } // namespace VideoCommon diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 15596c925..fcf70068e 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp @@ -837,6 +837,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory std::span<u8> output) { const size_t guest_size_bytes = input.size_bytes(); const u32 bpp_log2 = BytesPerBlockLog2(info.format); + const Extent2D tile_size = DefaultBlockSize(info.format); const Extent3D size = info.size; if (info.type == ImageType::Linear) { @@ -847,7 +848,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory return {{ .buffer_offset = 0, .buffer_size = guest_size_bytes, - .buffer_row_length = info.pitch >> bpp_log2, + .buffer_row_length = info.pitch * tile_size.width >> bpp_log2, .buffer_image_height = size.height, .image_subresource = { @@ -862,7 +863,6 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory const LevelInfo level_info = MakeLevelInfo(info); const s32 num_layers = info.resources.layers; const s32 num_levels = info.resources.levels; - const Extent2D tile_size = DefaultBlockSize(info.format); const std::array level_sizes = CalculateLevelSizes(level_info, num_levels); const Extent2D gob = GobSize(bpp_log2, info.block.height, info.tile_width_spacing); const u32 layer_size = CalculateLevelBytes(level_sizes, num_levels); @@ -926,8 +926,6 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8 const auto input_offset = input.subspan(copy.buffer_offset); copy.buffer_offset = output_offset; - copy.buffer_row_length = mip_size.width; - copy.buffer_image_height = mip_size.height; const auto recompression_setting = Settings::values.astc_recompression.GetValue(); const bool astc = IsPixelFormatASTC(info.format); @@ -972,16 +970,14 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8 bpp_div; output_offset += static_cast<u32>(copy.buffer_size); } else { - const Extent3D image_extent{ - .width = copy.image_extent.width, - .height = copy.image_extent.height * copy.image_subresource.num_layers, - .depth = copy.image_extent.depth, - }; - DecompressBCn(input_offset, output.subspan(output_offset), image_extent, info.format); + DecompressBCn(input_offset, output.subspan(output_offset), copy, info.format); output_offset += copy.image_extent.width * copy.image_extent.height * copy.image_subresource.num_layers * ConvertedBytesPerBlock(info.format); } + + copy.buffer_row_length = mip_size.width; + copy.buffer_image_height = mip_size.height; } } diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index a6fbca69e..727bbd98d 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -755,10 +755,10 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags // The wanted format is not supported by hardware, search for alternatives const VkFormat* alternatives = GetFormatAlternatives(wanted_format); if (alternatives == nullptr) { - ASSERT_MSG(false, - "Format={} with usage={} and type={} has no defined alternatives and host " - "hardware does not support it", - wanted_format, wanted_usage, format_type); + LOG_ERROR(Render_Vulkan, + "Format={} with usage={} and type={} has no defined alternatives and host " + "hardware does not support it", + wanted_format, wanted_usage, format_type); return wanted_format; } @@ -774,10 +774,10 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags } // No alternatives found, panic - ASSERT_MSG(false, - "Format={} with usage={} and type={} is not supported by the host hardware and " - "doesn't support any of the alternatives", - wanted_format, wanted_usage, format_type); + LOG_ERROR(Render_Vulkan, + "Format={} with usage={} and type={} is not supported by the host hardware and " + "doesn't support any of the alternatives", + wanted_format, wanted_usage, format_type); return wanted_format; } diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 2f78b8af0..074aed964 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -246,7 +246,9 @@ void SetObjectName(const DeviceDispatch* dld, VkDevice device, T handle, VkObjec .objectHandle = reinterpret_cast<u64>(handle), .pObjectName = name, }; - Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info)); + if (dld->vkSetDebugUtilsObjectNameEXT) { + Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info)); + } } } // Anonymous namespace diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 059fcf041..c789c1e59 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -5342,6 +5342,10 @@ int main(int argc, char* argv[]) { if (QString::fromLocal8Bit(qgetenv("DISPLAY")).isEmpty()) { qputenv("DISPLAY", ":0"); } + + // Fix the Wayland appId. This needs to match the name of the .desktop file without the .desktop + // suffix. + QGuiApplication::setDesktopFileName(QStringLiteral("org.yuzu_emu.yuzu")); #endif SetHighDPIAttributes(); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 530e445f9..366e806d5 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -168,14 +168,6 @@ class GMainWindow : public QMainWindow { /// Max number of recently loaded items to keep track of static const int max_recent_files_item = 10; - // TODO: Make use of this! - enum { - UI_IDLE, - UI_EMU_BOOTING, - UI_EMU_RUNNING, - UI_EMU_STOPPING, - }; - enum { CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, CREATE_SHORTCUT_MSGBOX_SUCCESS, diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 5153cdb79..1a35d471c 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp @@ -20,7 +20,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_, Co : input_subsystem{input_subsystem_}, system{system_} { input_subsystem->Initialize(); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) { - LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); + LOG_CRITICAL(Frontend, "Failed to initialize SDL2: {}, Exiting...", SDL_GetError()); exit(1); } SDL_SetMainReady(); diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp index 9ed47d453..8b916f05c 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp @@ -28,7 +28,8 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste SDL_SysWMinfo wm; SDL_VERSION(&wm.version); if (SDL_GetWindowWMInfo(render_window, &wm) == SDL_FALSE) { - LOG_CRITICAL(Frontend, "Failed to get information from the window manager"); + LOG_CRITICAL(Frontend, "Failed to get information from the window manager: {}", + SDL_GetError()); std::exit(EXIT_FAILURE); } |