summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x.ci/scripts/android/build.sh9
-rwxr-xr-x.ci/scripts/android/upload.sh13
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt3
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt10
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt1
-rw-r--r--src/android/app/src/main/res/layout/list_item_setting_switch.xml2
-rw-r--r--src/android/app/src/main/res/values/arrays.xml17
-rw-r--r--src/android/app/src/main/res/values/strings.xml8
-rw-r--r--src/common/assert.cpp3
-rw-r--r--src/common/logging/backend.cpp17
-rw-r--r--src/common/logging/backend.h3
-rw-r--r--src/common/ring_buffer.h2
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/file_sys/ips_layer.cpp7
-rw-r--r--src/core/hle/kernel/k_auto_object_container.cpp9
-rw-r--r--src/core/hle/kernel/k_auto_object_container.h31
-rw-r--r--src/core/hle/kernel/k_capabilities.cpp6
-rw-r--r--src/core/hle/kernel/k_handle_table.h7
-rw-r--r--src/core/hle/kernel/k_process.h2
-rw-r--r--src/core/hle/kernel/k_server_session.cpp3
-rw-r--r--src/core/hle/kernel/k_transfer_memory.h1
-rw-r--r--src/core/hle/service/am/am.cpp12
-rw-r--r--src/core/hle/service/audio/audren_u.cpp6
-rw-r--r--src/core/hle/service/audio/hwopus.cpp16
-rw-r--r--src/core/hle/service/hid/hid_server.cpp9
-rw-r--r--src/core/hle/service/hid/hidbus.cpp3
-rw-r--r--src/core/hle/service/hid/irs.cpp6
-rw-r--r--src/core/hle/service/hle_ipc.cpp20
-rw-r--r--src/core/hle/service/hle_ipc.h20
-rw-r--r--src/core/hle/service/jit/jit.cpp69
-rw-r--r--src/core/hle/service/jit/jit_code_memory.cpp54
-rw-r--r--src/core/hle/service/jit/jit_code_memory.h49
-rw-r--r--src/core/hle/service/ro/ro.cpp12
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp60
-rw-r--r--src/video_core/macro/macro_hle.cpp7
-rw-r--r--src/video_core/rasterizer_interface.h8
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp11
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h5
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp11
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h6
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.cpp17
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h27
-rw-r--r--src/video_core/texture_cache/decode_bc.cpp50
-rw-r--r--src/video_core/texture_cache/decode_bc.h2
-rw-r--r--src/video_core/texture_cache/util.cpp16
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp16
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp4
-rw-r--r--src/yuzu/main.cpp4
-rw-r--r--src/yuzu/main.h8
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp2
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp3
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(&params);
PrepareDraw(params.is_indexed, [this, &params](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);
}