summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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/core/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/k_capabilities.cpp6
-rw-r--r--src/core/hle/service/jit/jit.cpp59
-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/shader_recompiler/backend/spirv/spirv_emit_context.cpp60
-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/yuzu/main.cpp4
-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
18 files changed, 269 insertions, 79 deletions
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 {
18 RENDERER_ANTI_ALIASING("anti_aliasing"), 18 RENDERER_ANTI_ALIASING("anti_aliasing"),
19 RENDERER_SCREEN_LAYOUT("screen_layout"), 19 RENDERER_SCREEN_LAYOUT("screen_layout"),
20 RENDERER_ASPECT_RATIO("aspect_ratio"), 20 RENDERER_ASPECT_RATIO("aspect_ratio"),
21 AUDIO_OUTPUT_ENGINE("output_engine"); 21 AUDIO_OUTPUT_ENGINE("output_engine"),
22 MAX_ANISOTROPY("max_anisotropy");
22 23
23 override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal) 24 override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)
24 25
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(
245 ) 245 )
246 put( 246 put(
247 SingleChoiceSetting( 247 SingleChoiceSetting(
248 IntSetting.MAX_ANISOTROPY,
249 R.string.anisotropic_filtering,
250 R.string.anisotropic_filtering_description,
251 R.array.anisoEntries,
252 R.array.anisoValues
253 )
254 )
255 put(
256 SingleChoiceSetting(
248 IntSetting.AUDIO_OUTPUT_ENGINE, 257 IntSetting.AUDIO_OUTPUT_ENGINE,
249 R.string.audio_output_engine, 258 R.string.audio_output_engine,
250 0, 259 0,
@@ -298,6 +307,7 @@ abstract class SettingsItem(
298 307
299 override val key: String = FASTMEM_COMBINED 308 override val key: String = FASTMEM_COMBINED
300 override val isRuntimeModifiable: Boolean = false 309 override val isRuntimeModifiable: Boolean = false
310 override val pairedSettingKey = BooleanSetting.CPU_DEBUG_MODE.key
301 override val defaultValue: Boolean = true 311 override val defaultValue: Boolean = true
302 override val isSwitchable: Boolean = true 312 override val isSwitchable: Boolean = true
303 override var global: Boolean 313 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(
149 add(IntSetting.RENDERER_VSYNC.key) 149 add(IntSetting.RENDERER_VSYNC.key)
150 add(IntSetting.RENDERER_SCALING_FILTER.key) 150 add(IntSetting.RENDERER_SCALING_FILTER.key)
151 add(IntSetting.RENDERER_ANTI_ALIASING.key) 151 add(IntSetting.RENDERER_ANTI_ALIASING.key)
152 add(IntSetting.MAX_ANISOTROPY.key)
152 add(IntSetting.RENDERER_SCREEN_LAYOUT.key) 153 add(IntSetting.RENDERER_SCREEN_LAYOUT.key)
153 add(IntSetting.RENDERER_ASPECT_RATIO.key) 154 add(IntSetting.RENDERER_ASPECT_RATIO.key)
154 add(BooleanSetting.PICTURE_IN_PICTURE.key) 155 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 @@
24 android:layout_width="0dp" 24 android:layout_width="0dp"
25 android:layout_height="wrap_content" 25 android:layout_height="wrap_content"
26 android:layout_marginEnd="24dp" 26 android:layout_marginEnd="24dp"
27 android:gravity="center_vertical" 27 android:layout_gravity="center_vertical"
28 android:orientation="vertical" 28 android:orientation="vertical"
29 android:layout_weight="1"> 29 android:layout_weight="1">
30 30
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 @@
267 <item>3</item> 267 <item>3</item>
268 </integer-array> 268 </integer-array>
269 269
270 <string-array name="anisoEntries">
271 <item>@string/auto</item>
272 <item>@string/slider_default</item>
273 <item>@string/multiplier_two</item>
274 <item>@string/multiplier_four</item>
275 <item>@string/multiplier_eight</item>
276 <item>@string/multiplier_sixteen</item>
277 </string-array>
278 <integer-array name="anisoValues">
279 <item>0</item>
280 <item>1</item>
281 <item>2</item>
282 <item>3</item>
283 <item>4</item>
284 <item>5</item>
285 </integer-array>
286
270</resources> 287</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 @@
225 <string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string> 225 <string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string>
226 <string name="use_disk_shader_cache">Disk shader cache</string> 226 <string name="use_disk_shader_cache">Disk shader cache</string>
227 <string name="use_disk_shader_cache_description">Reduces stuttering by locally storing and loading generated shaders.</string> 227 <string name="use_disk_shader_cache_description">Reduces stuttering by locally storing and loading generated shaders.</string>
228 <string name="anisotropic_filtering">Anisotropic filtering</string>
229 <string name="anisotropic_filtering_description">Improves the quality of textures when viewed at oblique angles</string>
228 230
229 <!-- Debug settings strings --> 231 <!-- Debug settings strings -->
230 <string name="cpu">CPU</string> 232 <string name="cpu">CPU</string>
@@ -506,6 +508,12 @@
506 <string name="oboe">oboe</string> 508 <string name="oboe">oboe</string>
507 <string name="cubeb">cubeb</string> 509 <string name="cubeb">cubeb</string>
508 510
511 <!-- Anisotropic filtering options -->
512 <string name="multiplier_two">2x</string>
513 <string name="multiplier_four">4x</string>
514 <string name="multiplier_eight">8x</string>
515 <string name="multiplier_sixteen">16x</string>
516
509 <!-- Black backgrounds theme --> 517 <!-- Black backgrounds theme -->
510 <string name="use_black_backgrounds">Black backgrounds</string> 518 <string name="use_black_backgrounds">Black backgrounds</string>
511 <string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string> 519 <string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 96ab39cb8..a8b3d480c 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -987,6 +987,8 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
987 arm/dynarmic/dynarmic_cp15.h 987 arm/dynarmic/dynarmic_cp15.h
988 arm/dynarmic/dynarmic_exclusive_monitor.cpp 988 arm/dynarmic/dynarmic_exclusive_monitor.cpp
989 arm/dynarmic/dynarmic_exclusive_monitor.h 989 arm/dynarmic/dynarmic_exclusive_monitor.h
990 hle/service/jit/jit_code_memory.cpp
991 hle/service/jit/jit_code_memory.h
990 hle/service/jit/jit_context.cpp 992 hle/service/jit/jit_context.cpp
991 hle/service/jit/jit_context.h 993 hle/service/jit/jit_context.h
992 hle/service/jit/jit.cpp 994 hle/service/jit/jit.cpp
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) {
185 case RegionType::NoMapping: 185 case RegionType::NoMapping:
186 break; 186 break;
187 case RegionType::KernelTraceBuffer: 187 case RegionType::KernelTraceBuffer:
188 if constexpr (!IsKTraceEnabled) {
189 break;
190 }
191 [[fallthrough]];
188 case RegionType::OnMemoryBootImage: 192 case RegionType::OnMemoryBootImage:
189 case RegionType::DTB: 193 case RegionType::DTB:
190 R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm)); 194 R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm));
@@ -330,8 +334,6 @@ Result KCapabilities::SetCapabilities(std::span<const u32> caps, KProcessPageTab
330 334
331 // Map the range. 335 // Map the range.
332 R_TRY(this->MapRange_(cap, size_cap, page_table)); 336 R_TRY(this->MapRange_(cap, size_cap, page_table));
333 } else if (GetCapabilityType(cap) == CapabilityType::MapRegion && !IsKTraceEnabled) {
334 continue;
335 } else { 337 } else {
336 R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table)); 338 R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table));
337 } 339 }
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp
index a94d05e19..77aa6d7d1 100644
--- a/src/core/hle/service/jit/jit.cpp
+++ b/src/core/hle/service/jit/jit.cpp
@@ -4,11 +4,11 @@
4#include "core/arm/debug.h" 4#include "core/arm/debug.h"
5#include "core/arm/symbols.h" 5#include "core/arm/symbols.h"
6#include "core/core.h" 6#include "core/core.h"
7#include "core/hle/kernel/k_code_memory.h"
8#include "core/hle/kernel/k_transfer_memory.h" 7#include "core/hle/kernel/k_transfer_memory.h"
9#include "core/hle/result.h" 8#include "core/hle/result.h"
10#include "core/hle/service/ipc_helpers.h" 9#include "core/hle/service/ipc_helpers.h"
11#include "core/hle/service/jit/jit.h" 10#include "core/hle/service/jit/jit.h"
11#include "core/hle/service/jit/jit_code_memory.h"
12#include "core/hle/service/jit/jit_context.h" 12#include "core/hle/service/jit/jit_context.h"
13#include "core/hle/service/server_manager.h" 13#include "core/hle/service/server_manager.h"
14#include "core/hle/service/service.h" 14#include "core/hle/service/service.h"
@@ -23,10 +23,12 @@ struct CodeRange {
23 23
24class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { 24class IJitEnvironment final : public ServiceFramework<IJitEnvironment> {
25public: 25public:
26 explicit IJitEnvironment(Core::System& system_, Kernel::KProcess& process_, CodeRange user_rx, 26 explicit IJitEnvironment(Core::System& system_,
27 CodeRange user_ro) 27 Kernel::KScopedAutoObject<Kernel::KProcess>&& process_,
28 : ServiceFramework{system_, "IJitEnvironment"}, process{&process_}, 28 CodeMemory&& user_rx_, CodeMemory&& user_ro_)
29 context{process->GetMemory()} { 29 : ServiceFramework{system_, "IJitEnvironment"}, process{std::move(process_)},
30 user_rx{std::move(user_rx_)}, user_ro{std::move(user_ro_)},
31 context{system_.ApplicationMemory()} {
30 // clang-format off 32 // clang-format off
31 static const FunctionInfo functions[] = { 33 static const FunctionInfo functions[] = {
32 {0, &IJitEnvironment::GenerateCode, "GenerateCode"}, 34 {0, &IJitEnvironment::GenerateCode, "GenerateCode"},
@@ -39,10 +41,13 @@ public:
39 RegisterHandlers(functions); 41 RegisterHandlers(functions);
40 42
41 // Identity map user code range into sysmodule context 43 // Identity map user code range into sysmodule context
42 configuration.user_ro_memory = user_ro; 44 configuration.user_rx_memory.size = user_rx.GetSize();
43 configuration.user_rx_memory = user_rx; 45 configuration.user_rx_memory.offset = user_rx.GetAddress();
44 configuration.sys_ro_memory = user_ro; 46 configuration.user_ro_memory.size = user_ro.GetSize();
45 configuration.sys_rx_memory = user_rx; 47 configuration.user_ro_memory.offset = user_ro.GetAddress();
48
49 configuration.sys_rx_memory = configuration.user_rx_memory;
50 configuration.sys_ro_memory = configuration.user_ro_memory;
46 } 51 }
47 52
48 void GenerateCode(HLERequestContext& ctx) { 53 void GenerateCode(HLERequestContext& ctx) {
@@ -318,6 +323,8 @@ private:
318 } 323 }
319 324
320 Kernel::KScopedAutoObject<Kernel::KProcess> process; 325 Kernel::KScopedAutoObject<Kernel::KProcess> process;
326 CodeMemory user_rx;
327 CodeMemory user_ro;
321 GuestCallbacks callbacks; 328 GuestCallbacks callbacks;
322 JITConfiguration configuration; 329 JITConfiguration configuration;
323 JITContext context; 330 JITContext context;
@@ -335,6 +342,7 @@ public:
335 RegisterHandlers(functions); 342 RegisterHandlers(functions);
336 } 343 }
337 344
345private:
338 void CreateJitEnvironment(HLERequestContext& ctx) { 346 void CreateJitEnvironment(HLERequestContext& ctx) {
339 LOG_DEBUG(Service_JIT, "called"); 347 LOG_DEBUG(Service_JIT, "called");
340 348
@@ -380,20 +388,35 @@ public:
380 return; 388 return;
381 } 389 }
382 390
383 const CodeRange user_rx{ 391 CodeMemory rx, ro;
384 .offset = GetInteger(rx_mem->GetSourceAddress()), 392 Result res;
385 .size = parameters.rx_size,
386 };
387 393
388 const CodeRange user_ro{ 394 res = rx.Initialize(*process, *rx_mem, parameters.rx_size,
389 .offset = GetInteger(ro_mem->GetSourceAddress()), 395 Kernel::Svc::MemoryPermission::ReadExecute, generate_random);
390 .size = parameters.ro_size, 396 if (R_FAILED(res)) {
391 }; 397 LOG_ERROR(Service_JIT, "rx_mem could not be mapped for handle=0x{:08X}", rx_mem_handle);
398 IPC::ResponseBuilder rb{ctx, 2};
399 rb.Push(res);
400 return;
401 }
402
403 res = ro.Initialize(*process, *ro_mem, parameters.ro_size,
404 Kernel::Svc::MemoryPermission::Read, generate_random);
405 if (R_FAILED(res)) {
406 LOG_ERROR(Service_JIT, "ro_mem could not be mapped for handle=0x{:08X}", ro_mem_handle);
407 IPC::ResponseBuilder rb{ctx, 2};
408 rb.Push(res);
409 return;
410 }
392 411
393 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 412 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
394 rb.Push(ResultSuccess); 413 rb.Push(ResultSuccess);
395 rb.PushIpcInterface<IJitEnvironment>(system, *process, user_rx, user_ro); 414 rb.PushIpcInterface<IJitEnvironment>(system, std::move(process), std::move(rx),
415 std::move(ro));
396 } 416 }
417
418private:
419 std::mt19937_64 generate_random{};
397}; 420};
398 421
399void LoopProcess(Core::System& system) { 422void 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 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/jit/jit_code_memory.h"
5
6namespace Service::JIT {
7
8Result CodeMemory::Initialize(Kernel::KProcess& process, Kernel::KCodeMemory& code_memory,
9 size_t size, Kernel::Svc::MemoryPermission perm,
10 std::mt19937_64& generate_random) {
11 auto& page_table = process.GetPageTable();
12 const u64 alias_code_start =
13 GetInteger(page_table.GetAliasCodeRegionStart()) / Kernel::PageSize;
14 const u64 alias_code_size = page_table.GetAliasCodeRegionSize() / Kernel::PageSize;
15
16 // NOTE: This will retry indefinitely until mapping the code memory succeeds.
17 while (true) {
18 // Generate a new trial address.
19 const u64 mapped_address =
20 (alias_code_start + (generate_random() % alias_code_size)) * Kernel::PageSize;
21
22 // Try to map the address
23 R_TRY_CATCH(code_memory.MapToOwner(mapped_address, size, perm)) {
24 R_CATCH(Kernel::ResultInvalidMemoryRegion) {
25 // If we could not map here, retry.
26 continue;
27 }
28 }
29 R_END_TRY_CATCH;
30
31 // Set members.
32 m_code_memory = std::addressof(code_memory);
33 m_size = size;
34 m_address = mapped_address;
35 m_perm = perm;
36
37 // Open a new reference to the code memory.
38 m_code_memory->Open();
39
40 // We succeeded.
41 R_SUCCEED();
42 }
43}
44
45void CodeMemory::Finalize() {
46 if (m_code_memory) {
47 R_ASSERT(m_code_memory->UnmapFromOwner(m_address, m_size));
48 m_code_memory->Close();
49 }
50
51 m_code_memory = nullptr;
52}
53
54} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <random>
7
8#include "core/hle/kernel/k_code_memory.h"
9
10namespace Service::JIT {
11
12class CodeMemory {
13public:
14 YUZU_NON_COPYABLE(CodeMemory);
15
16 explicit CodeMemory() = default;
17
18 CodeMemory(CodeMemory&& rhs) {
19 std::swap(m_code_memory, rhs.m_code_memory);
20 std::swap(m_size, rhs.m_size);
21 std::swap(m_address, rhs.m_address);
22 std::swap(m_perm, rhs.m_perm);
23 }
24
25 ~CodeMemory() {
26 this->Finalize();
27 }
28
29public:
30 Result Initialize(Kernel::KProcess& process, Kernel::KCodeMemory& code_memory, size_t size,
31 Kernel::Svc::MemoryPermission perm, std::mt19937_64& generate_random);
32 void Finalize();
33
34 size_t GetSize() const {
35 return m_size;
36 }
37
38 u64 GetAddress() const {
39 return m_address;
40 }
41
42private:
43 Kernel::KCodeMemory* m_code_memory{};
44 size_t m_size{};
45 u64 m_address{};
46 Kernel::Svc::MemoryPermission m_perm{};
47};
48
49} // namespace Service::JIT
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) {
96} 96}
97 97
98Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin, 98Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin,
99 spv::StorageClass storage_class) { 99 spv::StorageClass storage_class, std::optional<Id> initializer = std::nullopt) {
100 const Id pointer_type{ctx.TypePointer(storage_class, type)}; 100 const Id pointer_type{ctx.TypePointer(storage_class, type)};
101 const Id id{ctx.AddGlobalVariable(pointer_type, storage_class)}; 101 const Id id{ctx.AddGlobalVariable(pointer_type, storage_class, initializer)};
102 if (builtin) { 102 if (builtin) {
103 ctx.Decorate(id, spv::Decoration::BuiltIn, *builtin); 103 ctx.Decorate(id, spv::Decoration::BuiltIn, *builtin);
104 } 104 }
@@ -144,11 +144,12 @@ Id DefineInput(EmitContext& ctx, Id type, bool per_invocation,
144} 144}
145 145
146Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations, 146Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations,
147 std::optional<spv::BuiltIn> builtin = std::nullopt) { 147 std::optional<spv::BuiltIn> builtin = std::nullopt,
148 std::optional<Id> initializer = std::nullopt) {
148 if (invocations && ctx.stage == Stage::TessellationControl) { 149 if (invocations && ctx.stage == Stage::TessellationControl) {
149 type = ctx.TypeArray(type, ctx.Const(*invocations)); 150 type = ctx.TypeArray(type, ctx.Const(*invocations));
150 } 151 }
151 return DefineVariable(ctx, type, builtin, spv::StorageClass::Output); 152 return DefineVariable(ctx, type, builtin, spv::StorageClass::Output, initializer);
152} 153}
153 154
154void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invocations) { 155void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invocations) {
@@ -811,10 +812,14 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
811 labels.push_back(OpLabel()); 812 labels.push_back(OpLabel());
812 } 813 }
813 if (info.stores.ClipDistances()) { 814 if (info.stores.ClipDistances()) {
814 literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2); 815 if (profile.max_user_clip_distances >= 4) {
815 labels.push_back(OpLabel()); 816 literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2);
816 literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2); 817 labels.push_back(OpLabel());
817 labels.push_back(OpLabel()); 818 }
819 if (profile.max_user_clip_distances >= 8) {
820 literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2);
821 labels.push_back(OpLabel());
822 }
818 } 823 }
819 OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); 824 OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone);
820 OpSwitch(compare_index, default_label, literals, labels); 825 OpSwitch(compare_index, default_label, literals, labels);
@@ -843,17 +848,21 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
843 ++label_index; 848 ++label_index;
844 } 849 }
845 if (info.stores.ClipDistances()) { 850 if (info.stores.ClipDistances()) {
846 AddLabel(labels[label_index]); 851 if (profile.max_user_clip_distances >= 4) {
847 const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)}; 852 AddLabel(labels[label_index]);
848 OpStore(pointer, store_value); 853 const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)};
849 OpReturn(); 854 OpStore(pointer, store_value);
850 ++label_index; 855 OpReturn();
851 AddLabel(labels[label_index]); 856 ++label_index;
852 const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))}; 857 }
853 const Id pointer2{OpAccessChain(output_f32, clip_distances, fixed_index)}; 858 if (profile.max_user_clip_distances >= 8) {
854 OpStore(pointer2, store_value); 859 AddLabel(labels[label_index]);
855 OpReturn(); 860 const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))};
856 ++label_index; 861 const Id pointer{OpAccessChain(output_f32, clip_distances, fixed_index)};
862 OpStore(pointer, store_value);
863 OpReturn();
864 ++label_index;
865 }
857 } 866 }
858 AddLabel(end_block); 867 AddLabel(end_block);
859 OpUnreachable(); 868 OpUnreachable();
@@ -1532,9 +1541,16 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
1532 if (stage == Stage::Fragment) { 1541 if (stage == Stage::Fragment) {
1533 throw NotImplementedException("Storing ClipDistance in fragment stage"); 1542 throw NotImplementedException("Storing ClipDistance in fragment stage");
1534 } 1543 }
1535 const Id type{TypeArray( 1544 if (profile.max_user_clip_distances > 0) {
1536 F32[1], Const(std::min(info.used_clip_distances, profile.max_user_clip_distances)))}; 1545 const u32 used{std::min(profile.max_user_clip_distances, 8u)};
1537 clip_distances = DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance); 1546 const std::array<Id, 8> zero{f32_zero_value, f32_zero_value, f32_zero_value,
1547 f32_zero_value, f32_zero_value, f32_zero_value,
1548 f32_zero_value, f32_zero_value};
1549 const Id type{TypeArray(F32[1], Const(used))};
1550 const Id initializer{ConstantComposite(type, std::span(zero).subspan(0, used))};
1551 clip_distances =
1552 DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance, initializer);
1553 }
1538 } 1554 }
1539 if (info.stores[IR::Attribute::Layer] && 1555 if (info.stores[IR::Attribute::Layer] &&
1540 (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { 1556 (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) {
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) {
60} 60}
61 61
62template <auto decompress, PixelFormat pixel_format> 62template <auto decompress, PixelFormat pixel_format>
63void DecompressBlocks(std::span<const u8> input, std::span<u8> output, Extent3D extent, 63void DecompressBlocks(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
64 bool is_signed = false) { 64 bool is_signed = false) {
65 const u32 out_bpp = ConvertedBytesPerBlock(pixel_format); 65 const u32 out_bpp = ConvertedBytesPerBlock(pixel_format);
66 const u32 block_width = std::min(extent.width, BLOCK_SIZE); 66 const u32 block_size = BlockSize(pixel_format);
67 const u32 block_height = std::min(extent.height, BLOCK_SIZE); 67 const u32 width = copy.image_extent.width;
68 const u32 pitch = extent.width * out_bpp; 68 const u32 height = copy.image_extent.height * copy.image_subresource.num_layers;
69 const u32 depth = copy.image_extent.depth;
70 const u32 block_width = std::min(width, BLOCK_SIZE);
71 const u32 block_height = std::min(height, BLOCK_SIZE);
72 const u32 pitch = width * out_bpp;
69 size_t input_offset = 0; 73 size_t input_offset = 0;
70 size_t output_offset = 0; 74 size_t output_offset = 0;
71 for (u32 slice = 0; slice < extent.depth; ++slice) { 75 for (u32 slice = 0; slice < depth; ++slice) {
72 for (u32 y = 0; y < extent.height; y += block_height) { 76 for (u32 y = 0; y < height; y += block_height) {
73 size_t row_offset = 0; 77 size_t src_offset = input_offset;
74 for (u32 x = 0; x < extent.width; 78 size_t dst_offset = output_offset;
75 x += block_width, row_offset += block_width * out_bpp) { 79 for (u32 x = 0; x < width; x += block_width) {
76 const u8* src = input.data() + input_offset; 80 const u8* src = input.data() + src_offset;
77 u8* const dst = output.data() + output_offset + row_offset; 81 u8* const dst = output.data() + dst_offset;
78 if constexpr (IsSigned(pixel_format)) { 82 if constexpr (IsSigned(pixel_format)) {
79 decompress(src, dst, x, y, extent.width, extent.height, is_signed); 83 decompress(src, dst, x, y, width, height, is_signed);
80 } else { 84 } else {
81 decompress(src, dst, x, y, extent.width, extent.height); 85 decompress(src, dst, x, y, width, height);
82 } 86 }
83 input_offset += BlockSize(pixel_format); 87 src_offset += block_size;
88 dst_offset += block_width * out_bpp;
84 } 89 }
90 input_offset += copy.buffer_row_length * block_size / block_width;
85 output_offset += block_height * pitch; 91 output_offset += block_height * pitch;
86 } 92 }
87 } 93 }
88} 94}
89 95
90void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent, 96void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
91 VideoCore::Surface::PixelFormat pixel_format) { 97 VideoCore::Surface::PixelFormat pixel_format) {
92 switch (pixel_format) { 98 switch (pixel_format) {
93 case PixelFormat::BC1_RGBA_UNORM: 99 case PixelFormat::BC1_RGBA_UNORM:
94 case PixelFormat::BC1_RGBA_SRGB: 100 case PixelFormat::BC1_RGBA_SRGB:
95 DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, extent); 101 DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, copy);
96 break; 102 break;
97 case PixelFormat::BC2_UNORM: 103 case PixelFormat::BC2_UNORM:
98 case PixelFormat::BC2_SRGB: 104 case PixelFormat::BC2_SRGB:
99 DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, extent); 105 DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, copy);
100 break; 106 break;
101 case PixelFormat::BC3_UNORM: 107 case PixelFormat::BC3_UNORM:
102 case PixelFormat::BC3_SRGB: 108 case PixelFormat::BC3_SRGB:
103 DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, extent); 109 DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, copy);
104 break; 110 break;
105 case PixelFormat::BC4_SNORM: 111 case PixelFormat::BC4_SNORM:
106 case PixelFormat::BC4_UNORM: 112 case PixelFormat::BC4_UNORM:
107 DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>( 113 DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>(
108 input, output, extent, pixel_format == PixelFormat::BC4_SNORM); 114 input, output, copy, pixel_format == PixelFormat::BC4_SNORM);
109 break; 115 break;
110 case PixelFormat::BC5_SNORM: 116 case PixelFormat::BC5_SNORM:
111 case PixelFormat::BC5_UNORM: 117 case PixelFormat::BC5_UNORM:
112 DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>( 118 DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>(
113 input, output, extent, pixel_format == PixelFormat::BC5_SNORM); 119 input, output, copy, pixel_format == PixelFormat::BC5_SNORM);
114 break; 120 break;
115 case PixelFormat::BC6H_SFLOAT: 121 case PixelFormat::BC6H_SFLOAT:
116 case PixelFormat::BC6H_UFLOAT: 122 case PixelFormat::BC6H_UFLOAT:
117 DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>( 123 DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>(
118 input, output, extent, pixel_format == PixelFormat::BC6H_SFLOAT); 124 input, output, copy, pixel_format == PixelFormat::BC6H_SFLOAT);
119 break; 125 break;
120 case PixelFormat::BC7_SRGB: 126 case PixelFormat::BC7_SRGB:
121 case PixelFormat::BC7_UNORM: 127 case PixelFormat::BC7_UNORM:
122 DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, extent); 128 DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, copy);
123 break; 129 break;
124 default: 130 default:
125 LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format); 131 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 {
13 13
14[[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format); 14[[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format);
15 15
16void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent, 16void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
17 VideoCore::Surface::PixelFormat pixel_format); 17 VideoCore::Surface::PixelFormat pixel_format);
18 18
19} // namespace VideoCommon 19} // 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
837 std::span<u8> output) { 837 std::span<u8> output) {
838 const size_t guest_size_bytes = input.size_bytes(); 838 const size_t guest_size_bytes = input.size_bytes();
839 const u32 bpp_log2 = BytesPerBlockLog2(info.format); 839 const u32 bpp_log2 = BytesPerBlockLog2(info.format);
840 const Extent2D tile_size = DefaultBlockSize(info.format);
840 const Extent3D size = info.size; 841 const Extent3D size = info.size;
841 842
842 if (info.type == ImageType::Linear) { 843 if (info.type == ImageType::Linear) {
@@ -847,7 +848,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
847 return {{ 848 return {{
848 .buffer_offset = 0, 849 .buffer_offset = 0,
849 .buffer_size = guest_size_bytes, 850 .buffer_size = guest_size_bytes,
850 .buffer_row_length = info.pitch >> bpp_log2, 851 .buffer_row_length = info.pitch * tile_size.width >> bpp_log2,
851 .buffer_image_height = size.height, 852 .buffer_image_height = size.height,
852 .image_subresource = 853 .image_subresource =
853 { 854 {
@@ -862,7 +863,6 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
862 const LevelInfo level_info = MakeLevelInfo(info); 863 const LevelInfo level_info = MakeLevelInfo(info);
863 const s32 num_layers = info.resources.layers; 864 const s32 num_layers = info.resources.layers;
864 const s32 num_levels = info.resources.levels; 865 const s32 num_levels = info.resources.levels;
865 const Extent2D tile_size = DefaultBlockSize(info.format);
866 const std::array level_sizes = CalculateLevelSizes(level_info, num_levels); 866 const std::array level_sizes = CalculateLevelSizes(level_info, num_levels);
867 const Extent2D gob = GobSize(bpp_log2, info.block.height, info.tile_width_spacing); 867 const Extent2D gob = GobSize(bpp_log2, info.block.height, info.tile_width_spacing);
868 const u32 layer_size = CalculateLevelBytes(level_sizes, num_levels); 868 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
926 926
927 const auto input_offset = input.subspan(copy.buffer_offset); 927 const auto input_offset = input.subspan(copy.buffer_offset);
928 copy.buffer_offset = output_offset; 928 copy.buffer_offset = output_offset;
929 copy.buffer_row_length = mip_size.width;
930 copy.buffer_image_height = mip_size.height;
931 929
932 const auto recompression_setting = Settings::values.astc_recompression.GetValue(); 930 const auto recompression_setting = Settings::values.astc_recompression.GetValue();
933 const bool astc = IsPixelFormatASTC(info.format); 931 const bool astc = IsPixelFormatASTC(info.format);
@@ -972,16 +970,14 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
972 bpp_div; 970 bpp_div;
973 output_offset += static_cast<u32>(copy.buffer_size); 971 output_offset += static_cast<u32>(copy.buffer_size);
974 } else { 972 } else {
975 const Extent3D image_extent{ 973 DecompressBCn(input_offset, output.subspan(output_offset), copy, info.format);
976 .width = copy.image_extent.width,
977 .height = copy.image_extent.height * copy.image_subresource.num_layers,
978 .depth = copy.image_extent.depth,
979 };
980 DecompressBCn(input_offset, output.subspan(output_offset), image_extent, info.format);
981 output_offset += copy.image_extent.width * copy.image_extent.height * 974 output_offset += copy.image_extent.width * copy.image_extent.height *
982 copy.image_subresource.num_layers * 975 copy.image_subresource.num_layers *
983 ConvertedBytesPerBlock(info.format); 976 ConvertedBytesPerBlock(info.format);
984 } 977 }
978
979 copy.buffer_row_length = mip_size.width;
980 copy.buffer_image_height = mip_size.height;
985 } 981 }
986} 982}
987 983
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[]) {
5342 if (QString::fromLocal8Bit(qgetenv("DISPLAY")).isEmpty()) { 5342 if (QString::fromLocal8Bit(qgetenv("DISPLAY")).isEmpty()) {
5343 qputenv("DISPLAY", ":0"); 5343 qputenv("DISPLAY", ":0");
5344 } 5344 }
5345
5346 // Fix the Wayland appId. This needs to match the name of the .desktop file without the .desktop
5347 // suffix.
5348 QGuiApplication::setDesktopFileName(QStringLiteral("org.yuzu_emu.yuzu"));
5345#endif 5349#endif
5346 5350
5347 SetHighDPIAttributes(); 5351 SetHighDPIAttributes();
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
20 : input_subsystem{input_subsystem_}, system{system_} { 20 : input_subsystem{input_subsystem_}, system{system_} {
21 input_subsystem->Initialize(); 21 input_subsystem->Initialize();
22 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) { 22 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) {
23 LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); 23 LOG_CRITICAL(Frontend, "Failed to initialize SDL2: {}, Exiting...", SDL_GetError());
24 exit(1); 24 exit(1);
25 } 25 }
26 SDL_SetMainReady(); 26 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
28 SDL_SysWMinfo wm; 28 SDL_SysWMinfo wm;
29 SDL_VERSION(&wm.version); 29 SDL_VERSION(&wm.version);
30 if (SDL_GetWindowWMInfo(render_window, &wm) == SDL_FALSE) { 30 if (SDL_GetWindowWMInfo(render_window, &wm) == SDL_FALSE) {
31 LOG_CRITICAL(Frontend, "Failed to get information from the window manager"); 31 LOG_CRITICAL(Frontend, "Failed to get information from the window manager: {}",
32 SDL_GetError());
32 std::exit(EXIT_FAILURE); 33 std::exit(EXIT_FAILURE);
33 } 34 }
34 35