summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/assert.h8
-rw-r--r--src/common/uuid.cpp54
-rw-r--r--src/common/uuid.h30
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp58
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h45
-rw-r--r--src/input_common/main.cpp8
-rw-r--r--src/input_common/mouse/mouse_poller.cpp1
-rw-r--r--src/input_common/sdl/sdl_impl.cpp87
-rw-r--r--src/video_core/command_classes/codecs/vp9.cpp136
-rw-r--r--src/video_core/command_classes/codecs/vp9.h14
-rw-r--r--src/video_core/command_classes/codecs/vp9_types.h8
-rw-r--r--src/video_core/command_classes/nvdec.cpp2
-rw-r--r--src/video_core/host_shaders/astc_decoder.comp271
-rw-r--r--src/video_core/renderer_opengl/util_shaders.cpp31
-rw-r--r--src/video_core/renderer_opengl/util_shaders.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp97
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.h5
-rw-r--r--src/video_core/textures/astc.cpp156
-rw-r--r--src/video_core/textures/astc.h111
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.cpp8
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.h2
-rw-r--r--src/yuzu/configuration/configure_general.ui60
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui7
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp13
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp61
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.h6
-rw-r--r--src/yuzu_cmd/CMakeLists.txt1
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp5
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h3
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp1
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp1
31 files changed, 572 insertions, 719 deletions
diff --git a/src/common/assert.h b/src/common/assert.h
index b3ba35c0f..33060d865 100644
--- a/src/common/assert.h
+++ b/src/common/assert.h
@@ -52,8 +52,12 @@ assert_noinline_call(const Fn& fn) {
52#define DEBUG_ASSERT(_a_) ASSERT(_a_) 52#define DEBUG_ASSERT(_a_) ASSERT(_a_)
53#define DEBUG_ASSERT_MSG(_a_, ...) ASSERT_MSG(_a_, __VA_ARGS__) 53#define DEBUG_ASSERT_MSG(_a_, ...) ASSERT_MSG(_a_, __VA_ARGS__)
54#else // not debug 54#else // not debug
55#define DEBUG_ASSERT(_a_) 55#define DEBUG_ASSERT(_a_) \
56#define DEBUG_ASSERT_MSG(_a_, _desc_, ...) 56 do { \
57 } while (0)
58#define DEBUG_ASSERT_MSG(_a_, _desc_, ...) \
59 do { \
60 } while (0)
57#endif 61#endif
58 62
59#define UNIMPLEMENTED() ASSERT_MSG(false, "Unimplemented code!") 63#define UNIMPLEMENTED() ASSERT_MSG(false, "Unimplemented code!")
diff --git a/src/common/uuid.cpp b/src/common/uuid.cpp
index 18303a1e3..d7435a6e9 100644
--- a/src/common/uuid.cpp
+++ b/src/common/uuid.cpp
@@ -6,10 +6,64 @@
6 6
7#include <fmt/format.h> 7#include <fmt/format.h>
8 8
9#include "common/assert.h"
9#include "common/uuid.h" 10#include "common/uuid.h"
10 11
11namespace Common { 12namespace Common {
12 13
14namespace {
15
16bool IsHexDigit(char c) {
17 return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
18}
19
20u8 HexCharToByte(char c) {
21 if (c >= '0' && c <= '9') {
22 return static_cast<u8>(c - '0');
23 }
24 if (c >= 'a' && c <= 'f') {
25 return static_cast<u8>(c - 'a' + 10);
26 }
27 if (c >= 'A' && c <= 'F') {
28 return static_cast<u8>(c - 'A' + 10);
29 }
30 ASSERT_MSG(false, "{} is not a hexadecimal digit!", c);
31 return u8{0};
32}
33
34} // Anonymous namespace
35
36u128 HexStringToU128(std::string_view hex_string) {
37 const size_t length = hex_string.length();
38
39 // Detect "0x" prefix.
40 const bool has_0x_prefix = length > 2 && hex_string[0] == '0' && hex_string[1] == 'x';
41 const size_t offset = has_0x_prefix ? 2 : 0;
42
43 // Check length.
44 if (length > 32 + offset) {
45 ASSERT_MSG(false, "hex_string has more than 32 hexadecimal characters!");
46 return INVALID_UUID;
47 }
48
49 u64 lo = 0;
50 u64 hi = 0;
51 for (size_t i = 0; i < length - offset; ++i) {
52 const char c = hex_string[length - 1 - i];
53 if (!IsHexDigit(c)) {
54 ASSERT_MSG(false, "{} is not a hexadecimal digit!", c);
55 return INVALID_UUID;
56 }
57 if (i < 16) {
58 lo |= u64{HexCharToByte(c)} << (i * 4);
59 }
60 if (i >= 16) {
61 hi |= u64{HexCharToByte(c)} << ((i - 16) * 4);
62 }
63 }
64 return u128{lo, hi};
65}
66
13UUID UUID::Generate() { 67UUID UUID::Generate() {
14 std::random_device device; 68 std::random_device device;
15 std::mt19937 gen(device()); 69 std::mt19937 gen(device());
diff --git a/src/common/uuid.h b/src/common/uuid.h
index 0ffa37e7c..2353179d8 100644
--- a/src/common/uuid.h
+++ b/src/common/uuid.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <string> 7#include <string>
8#include <string_view>
8 9
9#include "common/common_types.h" 10#include "common/common_types.h"
10 11
@@ -12,12 +13,30 @@ namespace Common {
12 13
13constexpr u128 INVALID_UUID{{0, 0}}; 14constexpr u128 INVALID_UUID{{0, 0}};
14 15
16/**
17 * Converts a hex string to a 128-bit unsigned integer.
18 *
19 * The hex string can be formatted in lowercase or uppercase, with or without the "0x" prefix.
20 *
21 * This function will assert and return INVALID_UUID under the following conditions:
22 * - If the hex string is more than 32 characters long
23 * - If the hex string contains non-hexadecimal characters
24 *
25 * @param hex_string Hexadecimal string
26 *
27 * @returns A 128-bit unsigned integer if successfully converted, INVALID_UUID otherwise.
28 */
29[[nodiscard]] u128 HexStringToU128(std::string_view hex_string);
30
15struct UUID { 31struct UUID {
16 // UUIDs which are 0 are considered invalid! 32 // UUIDs which are 0 are considered invalid!
17 u128 uuid; 33 u128 uuid;
18 UUID() = default; 34 UUID() = default;
19 constexpr explicit UUID(const u128& id) : uuid{id} {} 35 constexpr explicit UUID(const u128& id) : uuid{id} {}
20 constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {} 36 constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {}
37 explicit UUID(std::string_view hex_string) {
38 uuid = HexStringToU128(hex_string);
39 }
21 40
22 [[nodiscard]] constexpr explicit operator bool() const { 41 [[nodiscard]] constexpr explicit operator bool() const {
23 return uuid != INVALID_UUID; 42 return uuid != INVALID_UUID;
@@ -50,3 +69,14 @@ struct UUID {
50static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); 69static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
51 70
52} // namespace Common 71} // namespace Common
72
73namespace std {
74
75template <>
76struct hash<Common::UUID> {
77 size_t operator()(const Common::UUID& uuid) const noexcept {
78 return uuid.uuid[1] ^ uuid.uuid[0];
79 }
80};
81
82} // namespace std
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
index 1403a39d0..845de724d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -166,8 +166,6 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto
166 LOG_ERROR(Service_NVDRV, "failed to map size={}", object->size); 166 LOG_ERROR(Service_NVDRV, "failed to map size={}", object->size);
167 } else { 167 } else {
168 cmd_buffer.map_address = object->dma_map_addr; 168 cmd_buffer.map_address = object->dma_map_addr;
169 AddBufferMap(object->dma_map_addr, object->size, object->addr,
170 object->status == nvmap::Object::Status::Allocated);
171 } 169 }
172 } 170 }
173 std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer)); 171 std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
@@ -178,30 +176,11 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto
178} 176}
179 177
180NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { 178NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
181 IoctlMapBuffer params{}; 179 // This is intntionally stubbed.
182 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer)); 180 // Skip unmapping buffers here, as to not break the continuity of the VP9 reference frame
183 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); 181 // addresses, and risk invalidating data before the async GPU thread is done with it
184 SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
185
186 auto& gpu = system.GPU();
187
188 for (auto& cmd_buffer : cmd_buffer_handles) {
189 const auto object{nvmap_dev->GetObject(cmd_buffer.map_handle)};
190 if (!object) {
191 LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmd_buffer.map_handle);
192 std::memcpy(output.data(), &params, output.size());
193 return NvResult::InvalidState;
194 }
195 if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
196 gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
197 } else {
198 // This occurs quite frequently, however does not seem to impact functionality
199 LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr,
200 object->dma_map_addr);
201 }
202 object->dma_map_addr = 0;
203 }
204 std::memset(output.data(), 0, output.size()); 182 std::memset(output.data(), 0, output.size());
183 LOG_DEBUG(Service_NVDRV, "(STUBBED) called");
205 return NvResult::Success; 184 return NvResult::Success;
206} 185}
207 186
@@ -212,33 +191,4 @@ NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input,
212 return NvResult::Success; 191 return NvResult::Success;
213} 192}
214 193
215std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap(
216 GPUVAddr gpu_addr) const {
217 const auto it = std::find_if(
218 buffer_mappings.begin(), buffer_mappings.upper_bound(gpu_addr), [&](const auto& entry) {
219 return (gpu_addr >= entry.second.StartAddr() && gpu_addr < entry.second.EndAddr());
220 });
221
222 ASSERT(it != buffer_mappings.end());
223 return it->second;
224}
225
226void nvhost_nvdec_common::AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr,
227 bool is_allocated) {
228 buffer_mappings.insert_or_assign(gpu_addr, BufferMap{gpu_addr, size, cpu_addr, is_allocated});
229}
230
231std::optional<std::size_t> nvhost_nvdec_common::RemoveBufferMap(GPUVAddr gpu_addr) {
232 const auto iter{buffer_mappings.find(gpu_addr)};
233 if (iter == buffer_mappings.end()) {
234 return std::nullopt;
235 }
236 std::size_t size = 0;
237 if (iter->second.IsAllocated()) {
238 size = iter->second.Size();
239 }
240 buffer_mappings.erase(iter);
241 return size;
242}
243
244} // namespace Service::Nvidia::Devices 194} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
index da10f5f41..af59f00d2 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -23,45 +23,6 @@ public:
23 ~nvhost_nvdec_common() override; 23 ~nvhost_nvdec_common() override;
24 24
25protected: 25protected:
26 class BufferMap final {
27 public:
28 constexpr BufferMap() = default;
29
30 constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_)
31 : start_addr{start_addr_}, end_addr{start_addr_ + size_} {}
32
33 constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_, VAddr cpu_addr_,
34 bool is_allocated_)
35 : start_addr{start_addr_}, end_addr{start_addr_ + size_}, cpu_addr{cpu_addr_},
36 is_allocated{is_allocated_} {}
37
38 constexpr VAddr StartAddr() const {
39 return start_addr;
40 }
41
42 constexpr VAddr EndAddr() const {
43 return end_addr;
44 }
45
46 constexpr std::size_t Size() const {
47 return end_addr - start_addr;
48 }
49
50 constexpr VAddr CpuAddr() const {
51 return cpu_addr;
52 }
53
54 constexpr bool IsAllocated() const {
55 return is_allocated;
56 }
57
58 private:
59 GPUVAddr start_addr{};
60 GPUVAddr end_addr{};
61 VAddr cpu_addr{};
62 bool is_allocated{};
63 };
64
65 struct IoctlSetNvmapFD { 26 struct IoctlSetNvmapFD {
66 s32_le nvmap_fd{}; 27 s32_le nvmap_fd{};
67 }; 28 };
@@ -154,17 +115,11 @@ protected:
154 NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); 115 NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
155 NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output); 116 NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
156 117
157 std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
158 void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
159 std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr);
160
161 s32_le nvmap_fd{}; 118 s32_le nvmap_fd{};
162 u32_le submit_timeout{}; 119 u32_le submit_timeout{};
163 std::shared_ptr<nvmap> nvmap_dev; 120 std::shared_ptr<nvmap> nvmap_dev;
164 SyncpointManager& syncpoint_manager; 121 SyncpointManager& syncpoint_manager;
165 std::array<u32, MaxSyncPoints> device_syncpoints{}; 122 std::array<u32, MaxSyncPoints> device_syncpoints{};
166 // This is expected to be ordered, therefore we must use a map, not unordered_map
167 std::map<GPUVAddr, BufferMap> buffer_mappings;
168}; 123};
169}; // namespace Devices 124}; // namespace Devices
170} // namespace Service::Nvidia 125} // namespace Service::Nvidia
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 8de3d4520..ff23230f0 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -304,10 +304,10 @@ std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers([
304} 304}
305 305
306std::string GenerateKeyboardParam(int key_code) { 306std::string GenerateKeyboardParam(int key_code) {
307 Common::ParamPackage param{ 307 Common::ParamPackage param;
308 {"engine", "keyboard"}, 308 param.Set("engine", "keyboard");
309 {"code", std::to_string(key_code)}, 309 param.Set("code", key_code);
310 }; 310 param.Set("toggle", false);
311 return param.Serialize(); 311 return param.Serialize();
312} 312}
313 313
diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp
index efcdd85d2..090b26972 100644
--- a/src/input_common/mouse/mouse_poller.cpp
+++ b/src/input_common/mouse/mouse_poller.cpp
@@ -57,6 +57,7 @@ Common::ParamPackage MouseButtonFactory::GetNextInput() const {
57 if (pad.button != MouseInput::MouseButton::Undefined) { 57 if (pad.button != MouseInput::MouseButton::Undefined) {
58 params.Set("engine", "mouse"); 58 params.Set("engine", "mouse");
59 params.Set("button", static_cast<u16>(pad.button)); 59 params.Set("button", static_cast<u16>(pad.button));
60 params.Set("toggle", false);
60 return params; 61 return params;
61 } 62 }
62 } 63 }
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 70a0ba09c..f1f950d8a 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -82,6 +82,12 @@ public:
82 state.buttons.insert_or_assign(button, value); 82 state.buttons.insert_or_assign(button, value);
83 } 83 }
84 84
85 void PreSetButton(int button) {
86 if (!state.buttons.contains(button)) {
87 SetButton(button, false);
88 }
89 }
90
85 void SetMotion(SDL_ControllerSensorEvent event) { 91 void SetMotion(SDL_ControllerSensorEvent event) {
86 constexpr float gravity_constant = 9.80665f; 92 constexpr float gravity_constant = 9.80665f;
87 std::lock_guard lock{mutex}; 93 std::lock_guard lock{mutex};
@@ -155,9 +161,16 @@ public:
155 state.axes.insert_or_assign(axis, value); 161 state.axes.insert_or_assign(axis, value);
156 } 162 }
157 163
158 float GetAxis(int axis, float range) const { 164 void PreSetAxis(int axis) {
165 if (!state.axes.contains(axis)) {
166 SetAxis(axis, 0);
167 }
168 }
169
170 float GetAxis(int axis, float range, float offset) const {
159 std::lock_guard lock{mutex}; 171 std::lock_guard lock{mutex};
160 return static_cast<float>(state.axes.at(axis)) / (32767.0f * range); 172 const float value = static_cast<float>(state.axes.at(axis)) / 32767.0f;
173 return (value + offset) / range;
161 } 174 }
162 175
163 bool RumblePlay(u16 amp_low, u16 amp_high) { 176 bool RumblePlay(u16 amp_low, u16 amp_high) {
@@ -174,9 +187,10 @@ public:
174 return false; 187 return false;
175 } 188 }
176 189
177 std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const { 190 std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range, float offset_x,
178 float x = GetAxis(axis_x, range); 191 float offset_y) const {
179 float y = GetAxis(axis_y, range); 192 float x = GetAxis(axis_x, range, offset_x);
193 float y = GetAxis(axis_y, range, offset_y);
180 y = -y; // 3DS uses an y-axis inverse from SDL 194 y = -y; // 3DS uses an y-axis inverse from SDL
181 195
182 // Make sure the coordinates are in the unit circle, 196 // Make sure the coordinates are in the unit circle,
@@ -483,7 +497,7 @@ public:
483 trigger_if_greater(trigger_if_greater_) {} 497 trigger_if_greater(trigger_if_greater_) {}
484 498
485 bool GetStatus() const override { 499 bool GetStatus() const override {
486 const float axis_value = joystick->GetAxis(axis, 1.0f); 500 const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f);
487 if (trigger_if_greater) { 501 if (trigger_if_greater) {
488 return axis_value > threshold; 502 return axis_value > threshold;
489 } 503 }
@@ -500,12 +514,14 @@ private:
500class SDLAnalog final : public Input::AnalogDevice { 514class SDLAnalog final : public Input::AnalogDevice {
501public: 515public:
502 explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, 516 explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_,
503 bool invert_x_, bool invert_y_, float deadzone_, float range_) 517 bool invert_x_, bool invert_y_, float deadzone_, float range_,
518 float offset_x_, float offset_y_)
504 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), 519 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_),
505 invert_y(invert_y_), deadzone(deadzone_), range(range_) {} 520 invert_y(invert_y_), deadzone(deadzone_), range(range_), offset_x(offset_x_),
521 offset_y(offset_y_) {}
506 522
507 std::tuple<float, float> GetStatus() const override { 523 std::tuple<float, float> GetStatus() const override {
508 auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range); 524 auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range, offset_x, offset_y);
509 const float r = std::sqrt((x * x) + (y * y)); 525 const float r = std::sqrt((x * x) + (y * y));
510 if (invert_x) { 526 if (invert_x) {
511 x = -x; 527 x = -x;
@@ -522,8 +538,8 @@ public:
522 } 538 }
523 539
524 std::tuple<float, float> GetRawStatus() const override { 540 std::tuple<float, float> GetRawStatus() const override {
525 const float x = joystick->GetAxis(axis_x, range); 541 const float x = joystick->GetAxis(axis_x, range, offset_x);
526 const float y = joystick->GetAxis(axis_y, range); 542 const float y = joystick->GetAxis(axis_y, range, offset_y);
527 return {x, -y}; 543 return {x, -y};
528 } 544 }
529 545
@@ -555,6 +571,8 @@ private:
555 const bool invert_y; 571 const bool invert_y;
556 const float deadzone; 572 const float deadzone;
557 const float range; 573 const float range;
574 const float offset_x;
575 const float offset_y;
558}; 576};
559 577
560class SDLVibration final : public Input::VibrationDevice { 578class SDLVibration final : public Input::VibrationDevice {
@@ -621,7 +639,7 @@ public:
621 trigger_if_greater(trigger_if_greater_) {} 639 trigger_if_greater(trigger_if_greater_) {}
622 640
623 Input::MotionStatus GetStatus() const override { 641 Input::MotionStatus GetStatus() const override {
624 const float axis_value = joystick->GetAxis(axis, 1.0f); 642 const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f);
625 bool trigger = axis_value < threshold; 643 bool trigger = axis_value < threshold;
626 if (trigger_if_greater) { 644 if (trigger_if_greater) {
627 trigger = axis_value > threshold; 645 trigger = axis_value > threshold;
@@ -720,13 +738,13 @@ public:
720 LOG_ERROR(Input, "Unknown direction {}", direction_name); 738 LOG_ERROR(Input, "Unknown direction {}", direction_name);
721 } 739 }
722 // This is necessary so accessing GetAxis with axis won't crash 740 // This is necessary so accessing GetAxis with axis won't crash
723 joystick->SetAxis(axis, 0); 741 joystick->PreSetAxis(axis);
724 return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater); 742 return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater);
725 } 743 }
726 744
727 const int button = params.Get("button", 0); 745 const int button = params.Get("button", 0);
728 // This is necessary so accessing GetButton with button won't crash 746 // This is necessary so accessing GetButton with button won't crash
729 joystick->SetButton(button, false); 747 joystick->PreSetButton(button);
730 return std::make_unique<SDLButton>(joystick, button, toggle); 748 return std::make_unique<SDLButton>(joystick, button, toggle);
731 } 749 }
732 750
@@ -757,13 +775,15 @@ public:
757 const std::string invert_y_value = params.Get("invert_y", "+"); 775 const std::string invert_y_value = params.Get("invert_y", "+");
758 const bool invert_x = invert_x_value == "-"; 776 const bool invert_x = invert_x_value == "-";
759 const bool invert_y = invert_y_value == "-"; 777 const bool invert_y = invert_y_value == "-";
778 const float offset_x = params.Get("offset_x", 0.0f);
779 const float offset_y = params.Get("offset_y", 0.0f);
760 auto joystick = state.GetSDLJoystickByGUID(guid, port); 780 auto joystick = state.GetSDLJoystickByGUID(guid, port);
761 781
762 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash 782 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash
763 joystick->SetAxis(axis_x, 0); 783 joystick->PreSetAxis(axis_x);
764 joystick->SetAxis(axis_y, 0); 784 joystick->PreSetAxis(axis_y);
765 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, invert_x, invert_y, deadzone, 785 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, invert_x, invert_y, deadzone,
766 range); 786 range, offset_x, offset_y);
767 } 787 }
768 788
769private: 789private:
@@ -844,13 +864,13 @@ public:
844 LOG_ERROR(Input, "Unknown direction {}", direction_name); 864 LOG_ERROR(Input, "Unknown direction {}", direction_name);
845 } 865 }
846 // This is necessary so accessing GetAxis with axis won't crash 866 // This is necessary so accessing GetAxis with axis won't crash
847 joystick->SetAxis(axis, 0); 867 joystick->PreSetAxis(axis);
848 return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater); 868 return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater);
849 } 869 }
850 870
851 const int button = params.Get("button", 0); 871 const int button = params.Get("button", 0);
852 // This is necessary so accessing GetButton with button won't crash 872 // This is necessary so accessing GetButton with button won't crash
853 joystick->SetButton(button, false); 873 joystick->PreSetButton(button);
854 return std::make_unique<SDLButtonMotion>(joystick, button); 874 return std::make_unique<SDLButtonMotion>(joystick, button);
855 } 875 }
856 876
@@ -995,6 +1015,7 @@ Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid
995 params.Set("port", port); 1015 params.Set("port", port);
996 params.Set("guid", std::move(guid)); 1016 params.Set("guid", std::move(guid));
997 params.Set("button", button); 1017 params.Set("button", button);
1018 params.Set("toggle", false);
998 return params; 1019 return params;
999} 1020}
1000 1021
@@ -1134,13 +1155,15 @@ Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& gu
1134} 1155}
1135 1156
1136Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x, 1157Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x,
1137 int axis_y) { 1158 int axis_y, float offset_x, float offset_y) {
1138 Common::ParamPackage params; 1159 Common::ParamPackage params;
1139 params.Set("engine", "sdl"); 1160 params.Set("engine", "sdl");
1140 params.Set("port", port); 1161 params.Set("port", port);
1141 params.Set("guid", guid); 1162 params.Set("guid", guid);
1142 params.Set("axis_x", axis_x); 1163 params.Set("axis_x", axis_x);
1143 params.Set("axis_y", axis_y); 1164 params.Set("axis_y", axis_y);
1165 params.Set("offset_x", offset_x);
1166 params.Set("offset_y", offset_y);
1144 params.Set("invert_x", "+"); 1167 params.Set("invert_x", "+");
1145 params.Set("invert_y", "+"); 1168 params.Set("invert_y", "+");
1146 return params; 1169 return params;
@@ -1342,24 +1365,39 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa
1342 const auto& binding_left_y = 1365 const auto& binding_left_y =
1343 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); 1366 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
1344 if (params.Has("guid2")) { 1367 if (params.Has("guid2")) {
1368 joystick2->PreSetAxis(binding_left_x.value.axis);
1369 joystick2->PreSetAxis(binding_left_y.value.axis);
1370 const auto left_offset_x = -joystick2->GetAxis(binding_left_x.value.axis, 1.0f, 0);
1371 const auto left_offset_y = -joystick2->GetAxis(binding_left_y.value.axis, 1.0f, 0);
1345 mapping.insert_or_assign( 1372 mapping.insert_or_assign(
1346 Settings::NativeAnalog::LStick, 1373 Settings::NativeAnalog::LStick,
1347 BuildParamPackageForAnalog(joystick2->GetPort(), joystick2->GetGUID(), 1374 BuildParamPackageForAnalog(joystick2->GetPort(), joystick2->GetGUID(),
1348 binding_left_x.value.axis, binding_left_y.value.axis)); 1375 binding_left_x.value.axis, binding_left_y.value.axis,
1376 left_offset_x, left_offset_y));
1349 } else { 1377 } else {
1378 joystick->PreSetAxis(binding_left_x.value.axis);
1379 joystick->PreSetAxis(binding_left_y.value.axis);
1380 const auto left_offset_x = -joystick->GetAxis(binding_left_x.value.axis, 1.0f, 0);
1381 const auto left_offset_y = -joystick->GetAxis(binding_left_y.value.axis, 1.0f, 0);
1350 mapping.insert_or_assign( 1382 mapping.insert_or_assign(
1351 Settings::NativeAnalog::LStick, 1383 Settings::NativeAnalog::LStick,
1352 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), 1384 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
1353 binding_left_x.value.axis, binding_left_y.value.axis)); 1385 binding_left_x.value.axis, binding_left_y.value.axis,
1386 left_offset_x, left_offset_y));
1354 } 1387 }
1355 const auto& binding_right_x = 1388 const auto& binding_right_x =
1356 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); 1389 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
1357 const auto& binding_right_y = 1390 const auto& binding_right_y =
1358 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); 1391 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
1392 joystick->PreSetAxis(binding_right_x.value.axis);
1393 joystick->PreSetAxis(binding_right_y.value.axis);
1394 const auto right_offset_x = -joystick->GetAxis(binding_right_x.value.axis, 1.0f, 0);
1395 const auto right_offset_y = -joystick->GetAxis(binding_right_y.value.axis, 1.0f, 0);
1359 mapping.insert_or_assign(Settings::NativeAnalog::RStick, 1396 mapping.insert_or_assign(Settings::NativeAnalog::RStick,
1360 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), 1397 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
1361 binding_right_x.value.axis, 1398 binding_right_x.value.axis,
1362 binding_right_y.value.axis)); 1399 binding_right_y.value.axis, right_offset_x,
1400 right_offset_y));
1363 return mapping; 1401 return mapping;
1364} 1402}
1365 1403
@@ -1563,8 +1601,9 @@ public:
1563 } 1601 }
1564 1602
1565 if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) { 1603 if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
1604 // Set offset to zero since the joystick is not on center
1566 auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), 1605 auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
1567 first_axis, axis); 1606 first_axis, axis, 0, 0);
1568 first_axis = -1; 1607 first_axis = -1;
1569 return params; 1608 return params;
1570 } 1609 }
diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp
index 902bc2a98..70030066a 100644
--- a/src/video_core/command_classes/codecs/vp9.cpp
+++ b/src/video_core/command_classes/codecs/vp9.cpp
@@ -11,6 +11,9 @@
11 11
12namespace Tegra::Decoder { 12namespace Tegra::Decoder {
13namespace { 13namespace {
14constexpr u32 diff_update_probability = 252;
15constexpr u32 frame_sync_code = 0x498342;
16
14// Default compressed header probabilities once frame context resets 17// Default compressed header probabilities once frame context resets
15constexpr Vp9EntropyProbs default_probs{ 18constexpr Vp9EntropyProbs default_probs{
16 .y_mode_prob{ 19 .y_mode_prob{
@@ -361,8 +364,7 @@ Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state)
361 InsertEntropy(state.vp9_entropy_probs_offset, vp9_info.entropy); 364 InsertEntropy(state.vp9_entropy_probs_offset, vp9_info.entropy);
362 365
363 // surface_luma_offset[0:3] contains the address of the reference frame offsets in the following 366 // surface_luma_offset[0:3] contains the address of the reference frame offsets in the following
364 // order: last, golden, altref, current. It may be worthwhile to track the updates done here 367 // order: last, golden, altref, current.
365 // to avoid buffering frame data needed for reference frame updating in the header composition.
366 std::copy(state.surface_luma_offset.begin(), state.surface_luma_offset.begin() + 4, 368 std::copy(state.surface_luma_offset.begin(), state.surface_luma_offset.begin() + 4,
367 vp9_info.frame_offsets.begin()); 369 vp9_info.frame_offsets.begin());
368 370
@@ -384,40 +386,25 @@ Vp9FrameContainer VP9::GetCurrentFrame(const NvdecCommon::NvdecRegisters& state)
384 gpu.MemoryManager().ReadBlock(state.frame_bitstream_offset, current_frame.bit_stream.data(), 386 gpu.MemoryManager().ReadBlock(state.frame_bitstream_offset, current_frame.bit_stream.data(),
385 current_frame.info.bitstream_size); 387 current_frame.info.bitstream_size);
386 } 388 }
387 // Buffer two frames, saving the last show frame info 389 if (!next_frame.bit_stream.empty()) {
388 if (!next_next_frame.bit_stream.empty()) {
389 Vp9FrameContainer temp{ 390 Vp9FrameContainer temp{
390 .info = current_frame.info, 391 .info = current_frame.info,
391 .bit_stream = std::move(current_frame.bit_stream), 392 .bit_stream = std::move(current_frame.bit_stream),
392 }; 393 };
393 next_next_frame.info.show_frame = current_frame.info.last_frame_shown; 394 next_frame.info.show_frame = current_frame.info.last_frame_shown;
394 current_frame.info = next_next_frame.info; 395 current_frame.info = next_frame.info;
395 current_frame.bit_stream = std::move(next_next_frame.bit_stream); 396 current_frame.bit_stream = std::move(next_frame.bit_stream);
396 next_next_frame = std::move(temp); 397 next_frame = std::move(temp);
397
398 if (!next_frame.bit_stream.empty()) {
399 Vp9FrameContainer temp2{
400 .info = current_frame.info,
401 .bit_stream = std::move(current_frame.bit_stream),
402 };
403 next_frame.info.show_frame = current_frame.info.last_frame_shown;
404 current_frame.info = next_frame.info;
405 current_frame.bit_stream = std::move(next_frame.bit_stream);
406 next_frame = std::move(temp2);
407 } else {
408 next_frame.info = current_frame.info;
409 next_frame.bit_stream = std::move(current_frame.bit_stream);
410 }
411 } else { 398 } else {
412 next_next_frame.info = current_frame.info; 399 next_frame.info = current_frame.info;
413 next_next_frame.bit_stream = std::move(current_frame.bit_stream); 400 next_frame.bit_stream = current_frame.bit_stream;
414 } 401 }
415 return current_frame; 402 return current_frame;
416} 403}
417 404
418std::vector<u8> VP9::ComposeCompressedHeader() { 405std::vector<u8> VP9::ComposeCompressedHeader() {
419 VpxRangeEncoder writer{}; 406 VpxRangeEncoder writer{};
420 const bool update_probs = current_frame_info.show_frame && !current_frame_info.is_key_frame; 407 const bool update_probs = !current_frame_info.is_key_frame && current_frame_info.show_frame;
421 if (!current_frame_info.lossless) { 408 if (!current_frame_info.lossless) {
422 if (static_cast<u32>(current_frame_info.transform_mode) >= 3) { 409 if (static_cast<u32>(current_frame_info.transform_mode) >= 3) {
423 writer.Write(3, 2); 410 writer.Write(3, 2);
@@ -613,86 +600,64 @@ VpxBitStreamWriter VP9::ComposeUncompressedHeader() {
613 600
614 // Reset context 601 // Reset context
615 prev_frame_probs = default_probs; 602 prev_frame_probs = default_probs;
616 swap_next_golden = false; 603 swap_ref_indices = false;
617 loop_filter_ref_deltas.fill(0); 604 loop_filter_ref_deltas.fill(0);
618 loop_filter_mode_deltas.fill(0); 605 loop_filter_mode_deltas.fill(0);
619 606 frame_ctxs.fill(default_probs);
620 // allow frames offsets to stabilize before checking for golden frames
621 grace_period = 4;
622
623 // On key frames, all frame slots are set to the current frame,
624 // so the value of the selected slot doesn't really matter.
625 frame_ctxs.fill({current_frame_number, false, default_probs});
626 607
627 // intra only, meaning the frame can be recreated with no other references 608 // intra only, meaning the frame can be recreated with no other references
628 current_frame_info.intra_only = true; 609 current_frame_info.intra_only = true;
629
630 } else { 610 } else {
631
632 if (!current_frame_info.show_frame) { 611 if (!current_frame_info.show_frame) {
633 uncomp_writer.WriteBit(current_frame_info.intra_only); 612 uncomp_writer.WriteBit(current_frame_info.intra_only);
634 if (!current_frame_info.last_frame_was_key) {
635 swap_next_golden = !swap_next_golden;
636 }
637 } else { 613 } else {
638 current_frame_info.intra_only = false; 614 current_frame_info.intra_only = false;
639 } 615 }
640 if (!current_frame_info.error_resilient_mode) { 616 if (!current_frame_info.error_resilient_mode) {
641 uncomp_writer.WriteU(0, 2); // Reset frame context. 617 uncomp_writer.WriteU(0, 2); // Reset frame context.
642 } 618 }
643 619 const auto& curr_offsets = current_frame_info.frame_offsets;
644 // Last, Golden, Altref frames 620 const auto& next_offsets = next_frame.info.frame_offsets;
645 std::array<s32, 3> ref_frame_index{0, 1, 2}; 621 const bool ref_frames_different = curr_offsets[1] != curr_offsets[2];
646 622 const bool next_references_swap =
647 // Set when next frame is hidden 623 (next_offsets[1] == curr_offsets[2]) || (next_offsets[2] == curr_offsets[1]);
648 // altref and golden references are swapped 624 const bool needs_ref_swap = ref_frames_different && next_references_swap;
649 if (swap_next_golden) { 625 if (needs_ref_swap) {
650 ref_frame_index = std::array<s32, 3>{0, 2, 1}; 626 swap_ref_indices = !swap_ref_indices;
651 } 627 }
652 628 union {
653 // update Last Frame 629 u32 raw;
654 u64 refresh_frame_flags = 1; 630 BitField<0, 1, u32> refresh_last;
655 631 BitField<1, 2, u32> refresh_golden;
656 // golden frame may refresh, determined if the next golden frame offset is changed 632 BitField<2, 1, u32> refresh_alt;
657 bool golden_refresh = false; 633 } refresh_frame_flags;
658 if (grace_period <= 0) { 634
659 for (s32 index = 1; index < 3; ++index) { 635 refresh_frame_flags.raw = 0;
660 if (current_frame_info.frame_offsets[index] != 636 for (u32 index = 0; index < 3; ++index) {
661 next_frame.info.frame_offsets[index]) { 637 // Refresh indices that use the current frame as an index
662 current_frame_info.refresh_frame[index] = true; 638 if (curr_offsets[3] == next_offsets[index]) {
663 golden_refresh = true; 639 refresh_frame_flags.raw |= 1u << index;
664 grace_period = 3;
665 }
666 } 640 }
667 } 641 }
668 642 if (swap_ref_indices) {
669 if (current_frame_info.show_frame && 643 const u32 temp = refresh_frame_flags.refresh_golden;
670 (!next_frame.info.show_frame || next_frame.info.is_key_frame)) { 644 refresh_frame_flags.refresh_golden.Assign(refresh_frame_flags.refresh_alt.Value());
671 // Update golden frame 645 refresh_frame_flags.refresh_alt.Assign(temp);
672 refresh_frame_flags = swap_next_golden ? 2 : 4;
673 }
674
675 if (!current_frame_info.show_frame) {
676 // Update altref
677 refresh_frame_flags = swap_next_golden ? 2 : 4;
678 } else if (golden_refresh) {
679 refresh_frame_flags = 3;
680 } 646 }
681
682 if (current_frame_info.intra_only) { 647 if (current_frame_info.intra_only) {
683 uncomp_writer.WriteU(frame_sync_code, 24); 648 uncomp_writer.WriteU(frame_sync_code, 24);
684 uncomp_writer.WriteU(static_cast<s32>(refresh_frame_flags), 8); 649 uncomp_writer.WriteU(refresh_frame_flags.raw, 8);
685 uncomp_writer.WriteU(current_frame_info.frame_size.width - 1, 16); 650 uncomp_writer.WriteU(current_frame_info.frame_size.width - 1, 16);
686 uncomp_writer.WriteU(current_frame_info.frame_size.height - 1, 16); 651 uncomp_writer.WriteU(current_frame_info.frame_size.height - 1, 16);
687 uncomp_writer.WriteBit(false); // Render and frame size different. 652 uncomp_writer.WriteBit(false); // Render and frame size different.
688 } else { 653 } else {
689 uncomp_writer.WriteU(static_cast<s32>(refresh_frame_flags), 8); 654 const bool swap_indices = needs_ref_swap ^ swap_ref_indices;
690 655 const auto ref_frame_index = swap_indices ? std::array{0, 2, 1} : std::array{0, 1, 2};
691 for (s32 index = 1; index < 4; index++) { 656 uncomp_writer.WriteU(refresh_frame_flags.raw, 8);
657 for (size_t index = 1; index < 4; index++) {
692 uncomp_writer.WriteU(ref_frame_index[index - 1], 3); 658 uncomp_writer.WriteU(ref_frame_index[index - 1], 3);
693 uncomp_writer.WriteU(current_frame_info.ref_frame_sign_bias[index], 1); 659 uncomp_writer.WriteU(current_frame_info.ref_frame_sign_bias[index], 1);
694 } 660 }
695
696 uncomp_writer.WriteBit(true); // Frame size with refs. 661 uncomp_writer.WriteBit(true); // Frame size with refs.
697 uncomp_writer.WriteBit(false); // Render and frame size different. 662 uncomp_writer.WriteBit(false); // Render and frame size different.
698 uncomp_writer.WriteBit(current_frame_info.allow_high_precision_mv); 663 uncomp_writer.WriteBit(current_frame_info.allow_high_precision_mv);
@@ -714,10 +679,9 @@ VpxBitStreamWriter VP9::ComposeUncompressedHeader() {
714 frame_ctx_idx = 1; 679 frame_ctx_idx = 1;
715 } 680 }
716 681
717 uncomp_writer.WriteU(frame_ctx_idx, 2); // Frame context index. 682 uncomp_writer.WriteU(frame_ctx_idx, 2); // Frame context index.
718 prev_frame_probs = 683 prev_frame_probs = frame_ctxs[frame_ctx_idx]; // reference probabilities for compressed header
719 frame_ctxs[frame_ctx_idx].probs; // reference probabilities for compressed header 684 frame_ctxs[frame_ctx_idx] = current_frame_info.entropy;
720 frame_ctxs[frame_ctx_idx] = {current_frame_number, false, current_frame_info.entropy};
721 685
722 uncomp_writer.WriteU(current_frame_info.first_level, 6); 686 uncomp_writer.WriteU(current_frame_info.first_level, 6);
723 uncomp_writer.WriteU(current_frame_info.sharpness_level, 3); 687 uncomp_writer.WriteU(current_frame_info.sharpness_level, 3);
@@ -812,7 +776,6 @@ const std::vector<u8>& VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters
812 current_frame_info = curr_frame.info; 776 current_frame_info = curr_frame.info;
813 bitstream = std::move(curr_frame.bit_stream); 777 bitstream = std::move(curr_frame.bit_stream);
814 } 778 }
815
816 // The uncompressed header routine sets PrevProb parameters needed for the compressed header 779 // The uncompressed header routine sets PrevProb parameters needed for the compressed header
817 auto uncomp_writer = ComposeUncompressedHeader(); 780 auto uncomp_writer = ComposeUncompressedHeader();
818 std::vector<u8> compressed_header = ComposeCompressedHeader(); 781 std::vector<u8> compressed_header = ComposeCompressedHeader();
@@ -828,13 +791,6 @@ const std::vector<u8>& VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters
828 frame.begin() + uncompressed_header.size()); 791 frame.begin() + uncompressed_header.size());
829 std::copy(bitstream.begin(), bitstream.end(), 792 std::copy(bitstream.begin(), bitstream.end(),
830 frame.begin() + uncompressed_header.size() + compressed_header.size()); 793 frame.begin() + uncompressed_header.size() + compressed_header.size());
831
832 // keep track of frame number
833 current_frame_number++;
834 grace_period--;
835
836 // don't display hidden frames
837 hidden = !current_frame_info.show_frame;
838 return frame; 794 return frame;
839} 795}
840 796
diff --git a/src/video_core/command_classes/codecs/vp9.h b/src/video_core/command_classes/codecs/vp9.h
index 8396c8105..e6e9fc17e 100644
--- a/src/video_core/command_classes/codecs/vp9.h
+++ b/src/video_core/command_classes/codecs/vp9.h
@@ -14,7 +14,6 @@
14 14
15namespace Tegra { 15namespace Tegra {
16class GPU; 16class GPU;
17enum class FrameType { KeyFrame = 0, InterFrame = 1 };
18namespace Decoder { 17namespace Decoder {
19 18
20/// The VpxRangeEncoder, and VpxBitStreamWriter classes are used to compose the 19/// The VpxRangeEncoder, and VpxBitStreamWriter classes are used to compose the
@@ -124,7 +123,7 @@ public:
124 123
125 /// Returns true if the most recent frame was a hidden frame. 124 /// Returns true if the most recent frame was a hidden frame.
126 [[nodiscard]] bool WasFrameHidden() const { 125 [[nodiscard]] bool WasFrameHidden() const {
127 return hidden; 126 return !current_frame_info.show_frame;
128 } 127 }
129 128
130private: 129private:
@@ -178,19 +177,12 @@ private:
178 std::array<s8, 4> loop_filter_ref_deltas{}; 177 std::array<s8, 4> loop_filter_ref_deltas{};
179 std::array<s8, 2> loop_filter_mode_deltas{}; 178 std::array<s8, 2> loop_filter_mode_deltas{};
180 179
181 bool hidden = false;
182 s64 current_frame_number = -2; // since we buffer 2 frames
183 s32 grace_period = 6; // frame offsets need to stabilize
184 std::array<FrameContexts, 4> frame_ctxs{};
185 Vp9FrameContainer next_frame{}; 180 Vp9FrameContainer next_frame{};
186 Vp9FrameContainer next_next_frame{}; 181 std::array<Vp9EntropyProbs, 4> frame_ctxs{};
187 bool swap_next_golden{}; 182 bool swap_ref_indices{};
188 183
189 Vp9PictureInfo current_frame_info{}; 184 Vp9PictureInfo current_frame_info{};
190 Vp9EntropyProbs prev_frame_probs{}; 185 Vp9EntropyProbs prev_frame_probs{};
191
192 s32 diff_update_probability = 252;
193 s32 frame_sync_code = 0x498342;
194}; 186};
195 187
196} // namespace Decoder 188} // namespace Decoder
diff --git a/src/video_core/command_classes/codecs/vp9_types.h b/src/video_core/command_classes/codecs/vp9_types.h
index 2da14f3ca..87eafdb03 100644
--- a/src/video_core/command_classes/codecs/vp9_types.h
+++ b/src/video_core/command_classes/codecs/vp9_types.h
@@ -176,7 +176,7 @@ struct PictureInfo {
176 .frame_size_changed = (vp9_flags & FrameFlags::FrameSizeChanged) != 0, 176 .frame_size_changed = (vp9_flags & FrameFlags::FrameSizeChanged) != 0,
177 .error_resilient_mode = (vp9_flags & FrameFlags::ErrorResilientMode) != 0, 177 .error_resilient_mode = (vp9_flags & FrameFlags::ErrorResilientMode) != 0,
178 .last_frame_shown = (vp9_flags & FrameFlags::LastShowFrame) != 0, 178 .last_frame_shown = (vp9_flags & FrameFlags::LastShowFrame) != 0,
179 .show_frame = false, 179 .show_frame = true,
180 .ref_frame_sign_bias = ref_frame_sign_bias, 180 .ref_frame_sign_bias = ref_frame_sign_bias,
181 .base_q_index = base_q_index, 181 .base_q_index = base_q_index,
182 .y_dc_delta_q = y_dc_delta_q, 182 .y_dc_delta_q = y_dc_delta_q,
@@ -296,12 +296,6 @@ struct RefPoolElement {
296 bool refresh{}; 296 bool refresh{};
297}; 297};
298 298
299struct FrameContexts {
300 s64 from;
301 bool adapted;
302 Vp9EntropyProbs probs;
303};
304
305#define ASSERT_POSITION(field_name, position) \ 299#define ASSERT_POSITION(field_name, position) \
306 static_assert(offsetof(Vp9EntropyProbs, field_name) == position, \ 300 static_assert(offsetof(Vp9EntropyProbs, field_name) == position, \
307 "Field " #field_name " has invalid position") 301 "Field " #field_name " has invalid position")
diff --git a/src/video_core/command_classes/nvdec.cpp b/src/video_core/command_classes/nvdec.cpp
index b5e3b70fc..b5c55f14a 100644
--- a/src/video_core/command_classes/nvdec.cpp
+++ b/src/video_core/command_classes/nvdec.cpp
@@ -39,7 +39,7 @@ void Nvdec::Execute() {
39 codec->Decode(); 39 codec->Decode();
40 break; 40 break;
41 default: 41 default:
42 UNIMPLEMENTED_MSG("Unknown codec {}", static_cast<u32>(codec->GetCurrentCodec())); 42 UNIMPLEMENTED_MSG("Codec {}", codec->GetCurrentCodecName());
43 break; 43 break;
44 } 44 }
45} 45}
diff --git a/src/video_core/host_shaders/astc_decoder.comp b/src/video_core/host_shaders/astc_decoder.comp
index c37f15bfd..f34c5f5d9 100644
--- a/src/video_core/host_shaders/astc_decoder.comp
+++ b/src/video_core/host_shaders/astc_decoder.comp
@@ -10,33 +10,27 @@
10#define END_PUSH_CONSTANTS }; 10#define END_PUSH_CONSTANTS };
11#define UNIFORM(n) 11#define UNIFORM(n)
12#define BINDING_INPUT_BUFFER 0 12#define BINDING_INPUT_BUFFER 0
13#define BINDING_ENC_BUFFER 1 13#define BINDING_OUTPUT_IMAGE 1
14#define BINDING_SWIZZLE_BUFFER 2
15#define BINDING_OUTPUT_IMAGE 3
16 14
17#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv 15#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
18 16
19#define BEGIN_PUSH_CONSTANTS 17#define BEGIN_PUSH_CONSTANTS
20#define END_PUSH_CONSTANTS 18#define END_PUSH_CONSTANTS
21#define UNIFORM(n) layout(location = n) uniform 19#define UNIFORM(n) layout(location = n) uniform
22#define BINDING_SWIZZLE_BUFFER 0 20#define BINDING_INPUT_BUFFER 0
23#define BINDING_INPUT_BUFFER 1
24#define BINDING_ENC_BUFFER 2
25#define BINDING_OUTPUT_IMAGE 0 21#define BINDING_OUTPUT_IMAGE 0
26 22
27#endif 23#endif
28 24
29layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in; 25layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
30 26
31BEGIN_PUSH_CONSTANTS 27BEGIN_PUSH_CONSTANTS
32UNIFORM(1) uvec2 block_dims; 28UNIFORM(1) uvec2 block_dims;
33 29UNIFORM(2) uint layer_stride;
34UNIFORM(2) uint bytes_per_block_log2; 30UNIFORM(3) uint block_size;
35UNIFORM(3) uint layer_stride; 31UNIFORM(4) uint x_shift;
36UNIFORM(4) uint block_size; 32UNIFORM(5) uint block_height;
37UNIFORM(5) uint x_shift; 33UNIFORM(6) uint block_height_mask;
38UNIFORM(6) uint block_height;
39UNIFORM(7) uint block_height_mask;
40END_PUSH_CONSTANTS 34END_PUSH_CONSTANTS
41 35
42struct EncodingData { 36struct EncodingData {
@@ -55,45 +49,35 @@ struct TexelWeightParams {
55 bool void_extent_hdr; 49 bool void_extent_hdr;
56}; 50};
57 51
58// Swizzle data
59layout(binding = BINDING_SWIZZLE_BUFFER, std430) readonly buffer SwizzleTable {
60 uint swizzle_table[];
61};
62
63layout(binding = BINDING_INPUT_BUFFER, std430) readonly buffer InputBufferU32 { 52layout(binding = BINDING_INPUT_BUFFER, std430) readonly buffer InputBufferU32 {
64 uint astc_data[]; 53 uvec4 astc_data[];
65};
66
67// ASTC Encodings data
68layout(binding = BINDING_ENC_BUFFER, std430) readonly buffer EncodingsValues {
69 EncodingData encoding_values[];
70}; 54};
71 55
72layout(binding = BINDING_OUTPUT_IMAGE, rgba8) uniform writeonly image2DArray dest_image; 56layout(binding = BINDING_OUTPUT_IMAGE, rgba8) uniform writeonly image2DArray dest_image;
73 57
74const uint GOB_SIZE_X = 64;
75const uint GOB_SIZE_Y = 8;
76const uint GOB_SIZE_Z = 1;
77const uint GOB_SIZE = GOB_SIZE_X * GOB_SIZE_Y * GOB_SIZE_Z;
78
79const uint GOB_SIZE_X_SHIFT = 6; 58const uint GOB_SIZE_X_SHIFT = 6;
80const uint GOB_SIZE_Y_SHIFT = 3; 59const uint GOB_SIZE_Y_SHIFT = 3;
81const uint GOB_SIZE_Z_SHIFT = 0; 60const uint GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT;
82const uint GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT + GOB_SIZE_Z_SHIFT;
83
84const uvec2 SWIZZLE_MASK = uvec2(GOB_SIZE_X - 1, GOB_SIZE_Y - 1);
85 61
86const int BLOCK_SIZE_IN_BYTES = 16; 62const uint BYTES_PER_BLOCK_LOG2 = 4;
87
88const int BLOCK_INFO_ERROR = 0;
89const int BLOCK_INFO_VOID_EXTENT_HDR = 1;
90const int BLOCK_INFO_VOID_EXTENT_LDR = 2;
91const int BLOCK_INFO_NORMAL = 3;
92 63
93const int JUST_BITS = 0; 64const int JUST_BITS = 0;
94const int QUINT = 1; 65const int QUINT = 1;
95const int TRIT = 2; 66const int TRIT = 2;
96 67
68// ASTC Encodings data, sorted in ascending order based on their BitLength value
69// (see GetBitLength() function)
70EncodingData encoding_values[22] = EncodingData[](
71 EncodingData(JUST_BITS, 0, 0, 0), EncodingData(JUST_BITS, 1, 0, 0), EncodingData(TRIT, 0, 0, 0),
72 EncodingData(JUST_BITS, 2, 0, 0), EncodingData(QUINT, 0, 0, 0), EncodingData(TRIT, 1, 0, 0),
73 EncodingData(JUST_BITS, 3, 0, 0), EncodingData(QUINT, 1, 0, 0), EncodingData(TRIT, 2, 0, 0),
74 EncodingData(JUST_BITS, 4, 0, 0), EncodingData(QUINT, 2, 0, 0), EncodingData(TRIT, 3, 0, 0),
75 EncodingData(JUST_BITS, 5, 0, 0), EncodingData(QUINT, 3, 0, 0), EncodingData(TRIT, 4, 0, 0),
76 EncodingData(JUST_BITS, 6, 0, 0), EncodingData(QUINT, 4, 0, 0), EncodingData(TRIT, 5, 0, 0),
77 EncodingData(JUST_BITS, 7, 0, 0), EncodingData(QUINT, 5, 0, 0), EncodingData(TRIT, 6, 0, 0),
78 EncodingData(JUST_BITS, 8, 0, 0)
79);
80
97// The following constants are expanded variants of the Replicate() 81// The following constants are expanded variants of the Replicate()
98// function calls corresponding to the following arguments: 82// function calls corresponding to the following arguments:
99// value: index into the generated table 83// value: index into the generated table
@@ -135,44 +119,37 @@ const uint REPLICATE_7_BIT_TO_8_TABLE[128] =
135// Input ASTC texture globals 119// Input ASTC texture globals
136uint current_index = 0; 120uint current_index = 0;
137int bitsread = 0; 121int bitsread = 0;
138uint total_bitsread = 0; 122int total_bitsread = 0;
139uint local_buff[16]; 123uvec4 local_buff;
140 124
141// Color data globals 125// Color data globals
142uint color_endpoint_data[16]; 126uvec4 color_endpoint_data;
143int color_bitsread = 0; 127int color_bitsread = 0;
144uint total_color_bitsread = 0;
145int color_index = 0;
146 128
147// Four values, two endpoints, four maximum paritions 129// Four values, two endpoints, four maximum paritions
148uint color_values[32]; 130uint color_values[32];
149int colvals_index = 0; 131int colvals_index = 0;
150 132
151// Weight data globals 133// Weight data globals
152uint texel_weight_data[16]; 134uvec4 texel_weight_data;
153int texel_bitsread = 0; 135int texel_bitsread = 0;
154uint total_texel_bitsread = 0;
155int texel_index = 0;
156 136
157bool texel_flag = false; 137bool texel_flag = false;
158 138
159// Global "vectors" to be pushed into when decoding 139// Global "vectors" to be pushed into when decoding
160EncodingData result_vector[100]; 140EncodingData result_vector[144];
161int result_index = 0; 141int result_index = 0;
162 142
163EncodingData texel_vector[100]; 143EncodingData texel_vector[144];
164int texel_vector_index = 0; 144int texel_vector_index = 0;
165 145
166uint unquantized_texel_weights[2][144]; 146uint unquantized_texel_weights[2][144];
167 147
168uint SwizzleOffset(uvec2 pos) { 148uint SwizzleOffset(uvec2 pos) {
169 pos = pos & SWIZZLE_MASK; 149 uint x = pos.x;
170 return swizzle_table[pos.y * 64 + pos.x]; 150 uint y = pos.y;
171} 151 return ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 +
172 152 (y % 2) * 16 + (x % 16);
173uint ReadTexel(uint offset) {
174 // extract the 8-bit value from the 32-bit packed data.
175 return bitfieldExtract(astc_data[offset / 4], int((offset * 8) & 24), 8);
176} 153}
177 154
178// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)] 155// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
@@ -278,14 +255,10 @@ uint Hash52(uint p) {
278 return p; 255 return p;
279} 256}
280 257
281uint SelectPartition(uint seed, uint x, uint y, uint z, uint partition_count, bool small_block) { 258uint Select2DPartition(uint seed, uint x, uint y, uint partition_count, bool small_block) {
282 if (partition_count == 1) {
283 return 0;
284 }
285 if (small_block) { 259 if (small_block) {
286 x <<= 1; 260 x <<= 1;
287 y <<= 1; 261 y <<= 1;
288 z <<= 1;
289 } 262 }
290 263
291 seed += (partition_count - 1) * 1024; 264 seed += (partition_count - 1) * 1024;
@@ -299,10 +272,6 @@ uint SelectPartition(uint seed, uint x, uint y, uint z, uint partition_count, bo
299 uint seed6 = uint((rnum >> 20) & 0xF); 272 uint seed6 = uint((rnum >> 20) & 0xF);
300 uint seed7 = uint((rnum >> 24) & 0xF); 273 uint seed7 = uint((rnum >> 24) & 0xF);
301 uint seed8 = uint((rnum >> 28) & 0xF); 274 uint seed8 = uint((rnum >> 28) & 0xF);
302 uint seed9 = uint((rnum >> 18) & 0xF);
303 uint seed10 = uint((rnum >> 22) & 0xF);
304 uint seed11 = uint((rnum >> 26) & 0xF);
305 uint seed12 = uint(((rnum >> 30) | (rnum << 2)) & 0xF);
306 275
307 seed1 = (seed1 * seed1); 276 seed1 = (seed1 * seed1);
308 seed2 = (seed2 * seed2); 277 seed2 = (seed2 * seed2);
@@ -312,12 +281,8 @@ uint SelectPartition(uint seed, uint x, uint y, uint z, uint partition_count, bo
312 seed6 = (seed6 * seed6); 281 seed6 = (seed6 * seed6);
313 seed7 = (seed7 * seed7); 282 seed7 = (seed7 * seed7);
314 seed8 = (seed8 * seed8); 283 seed8 = (seed8 * seed8);
315 seed9 = (seed9 * seed9);
316 seed10 = (seed10 * seed10);
317 seed11 = (seed11 * seed11);
318 seed12 = (seed12 * seed12);
319 284
320 int sh1, sh2, sh3; 285 uint sh1, sh2;
321 if ((seed & 1) > 0) { 286 if ((seed & 1) > 0) {
322 sh1 = (seed & 2) > 0 ? 4 : 5; 287 sh1 = (seed & 2) > 0 ? 4 : 5;
323 sh2 = (partition_count == 3) ? 6 : 5; 288 sh2 = (partition_count == 3) ? 6 : 5;
@@ -325,25 +290,19 @@ uint SelectPartition(uint seed, uint x, uint y, uint z, uint partition_count, bo
325 sh1 = (partition_count == 3) ? 6 : 5; 290 sh1 = (partition_count == 3) ? 6 : 5;
326 sh2 = (seed & 2) > 0 ? 4 : 5; 291 sh2 = (seed & 2) > 0 ? 4 : 5;
327 } 292 }
328 sh3 = (seed & 0x10) > 0 ? sh1 : sh2; 293 seed1 >>= sh1;
329 294 seed2 >>= sh2;
330 seed1 = (seed1 >> sh1); 295 seed3 >>= sh1;
331 seed2 = (seed2 >> sh2); 296 seed4 >>= sh2;
332 seed3 = (seed3 >> sh1); 297 seed5 >>= sh1;
333 seed4 = (seed4 >> sh2); 298 seed6 >>= sh2;
334 seed5 = (seed5 >> sh1); 299 seed7 >>= sh1;
335 seed6 = (seed6 >> sh2); 300 seed8 >>= sh2;
336 seed7 = (seed7 >> sh1); 301
337 seed8 = (seed8 >> sh2); 302 uint a = seed1 * x + seed2 * y + (rnum >> 14);
338 seed9 = (seed9 >> sh3); 303 uint b = seed3 * x + seed4 * y + (rnum >> 10);
339 seed10 = (seed10 >> sh3); 304 uint c = seed5 * x + seed6 * y + (rnum >> 6);
340 seed11 = (seed11 >> sh3); 305 uint d = seed7 * x + seed8 * y + (rnum >> 2);
341 seed12 = (seed12 >> sh3);
342
343 uint a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14);
344 uint b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10);
345 uint c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6);
346 uint d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2);
347 306
348 a &= 0x3F; 307 a &= 0x3F;
349 b &= 0x3F; 308 b &= 0x3F;
@@ -368,58 +327,37 @@ uint SelectPartition(uint seed, uint x, uint y, uint z, uint partition_count, bo
368 } 327 }
369} 328}
370 329
371uint Select2DPartition(uint seed, uint x, uint y, uint partition_count, bool small_block) { 330uint ExtractBits(uvec4 payload, int offset, int bits) {
372 return SelectPartition(seed, x, y, 0, partition_count, small_block); 331 if (bits <= 0) {
373}
374
375uint ReadBit() {
376 if (current_index >= local_buff.length()) {
377 return 0; 332 return 0;
378 } 333 }
379 uint bit = bitfieldExtract(local_buff[current_index], bitsread, 1); 334 int last_offset = offset + bits - 1;
380 ++bitsread; 335 int shifted_offset = offset >> 5;
381 ++total_bitsread; 336 if ((last_offset >> 5) == shifted_offset) {
382 if (bitsread == 8) { 337 return bitfieldExtract(payload[shifted_offset], offset & 31, bits);
383 ++current_index;
384 bitsread = 0;
385 } 338 }
386 return bit; 339 int first_bits = 32 - (offset & 31);
340 int result_first = int(bitfieldExtract(payload[shifted_offset], offset & 31, first_bits));
341 int result_second = int(bitfieldExtract(payload[shifted_offset + 1], 0, bits - first_bits));
342 return result_first | (result_second << first_bits);
387} 343}
388 344
389uint StreamBits(uint num_bits) { 345uint StreamBits(uint num_bits) {
390 uint ret = 0; 346 int int_bits = int(num_bits);
391 for (uint i = 0; i < num_bits; i++) { 347 uint ret = ExtractBits(local_buff, total_bitsread, int_bits);
392 ret |= ((ReadBit() & 1) << i); 348 total_bitsread += int_bits;
393 }
394 return ret; 349 return ret;
395} 350}
396 351
397uint ReadColorBit() {
398 uint bit = 0;
399 if (texel_flag) {
400 bit = bitfieldExtract(texel_weight_data[texel_index], texel_bitsread, 1);
401 ++texel_bitsread;
402 ++total_texel_bitsread;
403 if (texel_bitsread == 8) {
404 ++texel_index;
405 texel_bitsread = 0;
406 }
407 } else {
408 bit = bitfieldExtract(color_endpoint_data[color_index], color_bitsread, 1);
409 ++color_bitsread;
410 ++total_color_bitsread;
411 if (color_bitsread == 8) {
412 ++color_index;
413 color_bitsread = 0;
414 }
415 }
416 return bit;
417}
418
419uint StreamColorBits(uint num_bits) { 352uint StreamColorBits(uint num_bits) {
420 uint ret = 0; 353 uint ret = 0;
421 for (uint i = 0; i < num_bits; i++) { 354 int int_bits = int(num_bits);
422 ret |= ((ReadColorBit() & 1) << i); 355 if (texel_flag) {
356 ret = ExtractBits(texel_weight_data, texel_bitsread, int_bits);
357 texel_bitsread += int_bits;
358 } else {
359 ret = ExtractBits(color_endpoint_data, color_bitsread, int_bits);
360 color_bitsread += int_bits;
423 } 361 }
424 return ret; 362 return ret;
425} 363}
@@ -596,22 +534,16 @@ void DecodeColorValues(uvec4 modes, uint num_partitions, uint color_data_bits) {
596 for (uint i = 0; i < num_partitions; i++) { 534 for (uint i = 0; i < num_partitions; i++) {
597 num_values += ((modes[i] >> 2) + 1) << 1; 535 num_values += ((modes[i] >> 2) + 1) << 1;
598 } 536 }
599 int range = 256; 537 // Find the largest encoding that's within color_data_bits
600 while (--range > 0) { 538 // TODO(ameerj): profile with binary search
601 EncodingData val = encoding_values[range]; 539 int range = 0;
540 while (++range < encoding_values.length()) {
602 uint bit_length = GetBitLength(num_values, range); 541 uint bit_length = GetBitLength(num_values, range);
603 if (bit_length <= color_data_bits) { 542 if (bit_length > color_data_bits) {
604 while (--range > 0) {
605 EncodingData newval = encoding_values[range];
606 if (newval.encoding != val.encoding && newval.num_bits != val.num_bits) {
607 break;
608 }
609 }
610 ++range;
611 break; 543 break;
612 } 544 }
613 } 545 }
614 DecodeIntegerSequence(range, num_values); 546 DecodeIntegerSequence(range - 1, num_values);
615 uint out_index = 0; 547 uint out_index = 0;
616 for (int itr = 0; itr < result_index; ++itr) { 548 for (int itr = 0; itr < result_index; ++itr) {
617 if (out_index >= num_values) { 549 if (out_index >= num_values) {
@@ -1028,7 +960,7 @@ int FindLayout(uint mode) {
1028 return 5; 960 return 5;
1029} 961}
1030 962
1031TexelWeightParams DecodeBlockInfo(uint block_index) { 963TexelWeightParams DecodeBlockInfo() {
1032 TexelWeightParams params = TexelWeightParams(uvec2(0), 0, false, false, false, false); 964 TexelWeightParams params = TexelWeightParams(uvec2(0), 0, false, false, false, false);
1033 uint mode = StreamBits(11); 965 uint mode = StreamBits(11);
1034 if ((mode & 0x1ff) == 0x1fc) { 966 if ((mode & 0x1ff) == 0x1fc) {
@@ -1110,10 +1042,10 @@ TexelWeightParams DecodeBlockInfo(uint block_index) {
1110 } 1042 }
1111 weight_index -= 2; 1043 weight_index -= 2;
1112 if ((mode_layout != 9) && ((mode & 0x200) != 0)) { 1044 if ((mode_layout != 9) && ((mode & 0x200) != 0)) {
1113 const int max_weights[6] = int[6](9, 11, 15, 19, 23, 31); 1045 const int max_weights[6] = int[6](7, 8, 9, 10, 11, 12);
1114 params.max_weight = max_weights[weight_index]; 1046 params.max_weight = max_weights[weight_index];
1115 } else { 1047 } else {
1116 const int max_weights[6] = int[6](1, 2, 3, 4, 5, 7); 1048 const int max_weights[6] = int[6](1, 2, 3, 4, 5, 6);
1117 params.max_weight = max_weights[weight_index]; 1049 params.max_weight = max_weights[weight_index];
1118 } 1050 }
1119 return params; 1051 return params;
@@ -1144,8 +1076,8 @@ void FillVoidExtentLDR(ivec3 coord) {
1144 } 1076 }
1145} 1077}
1146 1078
1147void DecompressBlock(ivec3 coord, uint block_index) { 1079void DecompressBlock(ivec3 coord) {
1148 TexelWeightParams params = DecodeBlockInfo(block_index); 1080 TexelWeightParams params = DecodeBlockInfo();
1149 if (params.error_state) { 1081 if (params.error_state) {
1150 FillError(coord); 1082 FillError(coord);
1151 return; 1083 return;
@@ -1212,7 +1144,7 @@ void DecompressBlock(ivec3 coord, uint block_index) {
1212 // Read color data... 1144 // Read color data...
1213 uint color_data_bits = remaining_bits; 1145 uint color_data_bits = remaining_bits;
1214 while (remaining_bits > 0) { 1146 while (remaining_bits > 0) {
1215 int nb = int(min(remaining_bits, 8U)); 1147 int nb = int(min(remaining_bits, 32U));
1216 uint b = StreamBits(nb); 1148 uint b = StreamBits(nb);
1217 color_endpoint_data[ced_pointer] = uint(bitfieldExtract(b, 0, nb)); 1149 color_endpoint_data[ced_pointer] = uint(bitfieldExtract(b, 0, nb));
1218 ++ced_pointer; 1150 ++ced_pointer;
@@ -1254,25 +1186,20 @@ void DecompressBlock(ivec3 coord, uint block_index) {
1254 ComputeEndpoints(endpoints[i][0], endpoints[i][1], color_endpoint_mode[i]); 1186 ComputeEndpoints(endpoints[i][0], endpoints[i][1], color_endpoint_mode[i]);
1255 } 1187 }
1256 1188
1257 for (uint i = 0; i < 16; i++) { 1189 texel_weight_data = local_buff;
1258 texel_weight_data[i] = local_buff[i]; 1190 texel_weight_data = bitfieldReverse(texel_weight_data).wzyx;
1259 }
1260 for (uint i = 0; i < 8; i++) {
1261#define REVERSE_BYTE(b) ((b * 0x0802U & 0x22110U) | (b * 0x8020U & 0x88440U)) * 0x10101U >> 16
1262 uint a = REVERSE_BYTE(texel_weight_data[i]);
1263 uint b = REVERSE_BYTE(texel_weight_data[15 - i]);
1264#undef REVERSE_BYTE
1265 texel_weight_data[i] = uint(bitfieldExtract(b, 0, 8));
1266 texel_weight_data[15 - i] = uint(bitfieldExtract(a, 0, 8));
1267 }
1268 uint clear_byte_start = 1191 uint clear_byte_start =
1269 (GetPackedBitSize(params.size, params.dual_plane, params.max_weight) >> 3) + 1; 1192 (GetPackedBitSize(params.size, params.dual_plane, params.max_weight) >> 3) + 1;
1270 texel_weight_data[clear_byte_start - 1] = 1193
1271 texel_weight_data[clear_byte_start - 1] & 1194 uint byte_insert = ExtractBits(texel_weight_data, int(clear_byte_start - 1) * 8, 8) &
1272 uint( 1195 uint(
1273 ((1 << (GetPackedBitSize(params.size, params.dual_plane, params.max_weight) % 8)) - 1)); 1196 ((1 << (GetPackedBitSize(params.size, params.dual_plane, params.max_weight) % 8)) - 1));
1274 for (uint i = 0; i < 16 - clear_byte_start; i++) { 1197 uint vec_index = (clear_byte_start - 1) >> 2;
1275 texel_weight_data[clear_byte_start + i] = 0U; 1198 texel_weight_data[vec_index] =
1199 bitfieldInsert(texel_weight_data[vec_index], byte_insert, int((clear_byte_start - 1) % 4) * 8, 8);
1200 for (uint i = clear_byte_start; i < 16; ++i) {
1201 uint idx = i >> 2;
1202 texel_weight_data[idx] = bitfieldInsert(texel_weight_data[idx], 0, int(i % 4) * 8, 8);
1276 } 1203 }
1277 texel_flag = true; // use texel "vector" and bit stream in integer decoding 1204 texel_flag = true; // use texel "vector" and bit stream in integer decoding
1278 DecodeIntegerSequence(params.max_weight, GetNumWeightValues(params.size, params.dual_plane)); 1205 DecodeIntegerSequence(params.max_weight, GetNumWeightValues(params.size, params.dual_plane));
@@ -1281,8 +1208,11 @@ void DecompressBlock(ivec3 coord, uint block_index) {
1281 1208
1282 for (uint j = 0; j < block_dims.y; j++) { 1209 for (uint j = 0; j < block_dims.y; j++) {
1283 for (uint i = 0; i < block_dims.x; i++) { 1210 for (uint i = 0; i < block_dims.x; i++) {
1284 uint local_partition = Select2DPartition(partition_index, i, j, num_partitions, 1211 uint local_partition = 0;
1212 if (num_partitions > 1) {
1213 local_partition = Select2DPartition(partition_index, i, j, num_partitions,
1285 (block_dims.y * block_dims.x) < 32); 1214 (block_dims.y * block_dims.x) < 32);
1215 }
1286 vec4 p; 1216 vec4 p;
1287 uvec4 C0 = ReplicateByteTo16(endpoints[local_partition][0]); 1217 uvec4 C0 = ReplicateByteTo16(endpoints[local_partition][0]);
1288 uvec4 C1 = ReplicateByteTo16(endpoints[local_partition][1]); 1218 uvec4 C1 = ReplicateByteTo16(endpoints[local_partition][1]);
@@ -1303,7 +1233,7 @@ void DecompressBlock(ivec3 coord, uint block_index) {
1303 1233
1304void main() { 1234void main() {
1305 uvec3 pos = gl_GlobalInvocationID; 1235 uvec3 pos = gl_GlobalInvocationID;
1306 pos.x <<= bytes_per_block_log2; 1236 pos.x <<= BYTES_PER_BLOCK_LOG2;
1307 1237
1308 // Read as soon as possible due to its latency 1238 // Read as soon as possible due to its latency
1309 const uint swizzle = SwizzleOffset(pos.xy); 1239 const uint swizzle = SwizzleOffset(pos.xy);
@@ -1321,13 +1251,8 @@ void main() {
1321 if (any(greaterThanEqual(coord, imageSize(dest_image)))) { 1251 if (any(greaterThanEqual(coord, imageSize(dest_image)))) {
1322 return; 1252 return;
1323 } 1253 }
1324 uint block_index =
1325 pos.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y + pos.y * gl_WorkGroupSize.x + pos.x;
1326
1327 current_index = 0; 1254 current_index = 0;
1328 bitsread = 0; 1255 bitsread = 0;
1329 for (int i = 0; i < 16; i++) { 1256 local_buff = astc_data[offset / 16];
1330 local_buff[i] = ReadTexel(offset + i); 1257 DecompressBlock(coord);
1331 }
1332 DecompressBlock(coord, block_index);
1333} 1258}
diff --git a/src/video_core/renderer_opengl/util_shaders.cpp b/src/video_core/renderer_opengl/util_shaders.cpp
index 37a4d1d9d..333f35a1c 100644
--- a/src/video_core/renderer_opengl/util_shaders.cpp
+++ b/src/video_core/renderer_opengl/util_shaders.cpp
@@ -60,19 +60,14 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_)
60 copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) { 60 copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) {
61 const auto swizzle_table = Tegra::Texture::MakeSwizzleTable(); 61 const auto swizzle_table = Tegra::Texture::MakeSwizzleTable();
62 swizzle_table_buffer.Create(); 62 swizzle_table_buffer.Create();
63 astc_buffer.Create();
64 glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0); 63 glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0);
65 glNamedBufferStorage(astc_buffer.handle, sizeof(ASTC_ENCODINGS_VALUES), &ASTC_ENCODINGS_VALUES,
66 0);
67} 64}
68 65
69UtilShaders::~UtilShaders() = default; 66UtilShaders::~UtilShaders() = default;
70 67
71void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map, 68void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
72 std::span<const VideoCommon::SwizzleParameters> swizzles) { 69 std::span<const VideoCommon::SwizzleParameters> swizzles) {
73 static constexpr GLuint BINDING_SWIZZLE_BUFFER = 0; 70 static constexpr GLuint BINDING_INPUT_BUFFER = 0;
74 static constexpr GLuint BINDING_INPUT_BUFFER = 1;
75 static constexpr GLuint BINDING_ENC_BUFFER = 2;
76 static constexpr GLuint BINDING_OUTPUT_IMAGE = 0; 71 static constexpr GLuint BINDING_OUTPUT_IMAGE = 0;
77 72
78 const Extent2D tile_size{ 73 const Extent2D tile_size{
@@ -80,34 +75,32 @@ void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
80 .height = VideoCore::Surface::DefaultBlockHeight(image.info.format), 75 .height = VideoCore::Surface::DefaultBlockHeight(image.info.format),
81 }; 76 };
82 program_manager.BindComputeProgram(astc_decoder_program.handle); 77 program_manager.BindComputeProgram(astc_decoder_program.handle);
83 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, BINDING_SWIZZLE_BUFFER, swizzle_table_buffer.handle);
84 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, BINDING_ENC_BUFFER, astc_buffer.handle);
85
86 glFlushMappedNamedBufferRange(map.buffer, map.offset, image.guest_size_bytes); 78 glFlushMappedNamedBufferRange(map.buffer, map.offset, image.guest_size_bytes);
87 glUniform2ui(1, tile_size.width, tile_size.height); 79 glUniform2ui(1, tile_size.width, tile_size.height);
80
88 // Ensure buffer data is valid before dispatching 81 // Ensure buffer data is valid before dispatching
89 glFlush(); 82 glFlush();
90 for (const SwizzleParameters& swizzle : swizzles) { 83 for (const SwizzleParameters& swizzle : swizzles) {
91 const size_t input_offset = swizzle.buffer_offset + map.offset; 84 const size_t input_offset = swizzle.buffer_offset + map.offset;
92 const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U); 85 const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 8U);
93 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U); 86 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 8U);
94 87
95 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info); 88 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
96 ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0})); 89 ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0}));
97 ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0})); 90 ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0}));
91 ASSERT(params.bytes_per_block_log2 == 4);
98 92
99 glUniform1ui(2, params.bytes_per_block_log2); 93 glUniform1ui(2, params.layer_stride);
100 glUniform1ui(3, params.layer_stride); 94 glUniform1ui(3, params.block_size);
101 glUniform1ui(4, params.block_size); 95 glUniform1ui(4, params.x_shift);
102 glUniform1ui(5, params.x_shift); 96 glUniform1ui(5, params.block_height);
103 glUniform1ui(6, params.block_height); 97 glUniform1ui(6, params.block_height_mask);
104 glUniform1ui(7, params.block_height_mask);
105 98
106 glBindImageTexture(BINDING_OUTPUT_IMAGE, image.StorageHandle(), swizzle.level, GL_TRUE, 0,
107 GL_WRITE_ONLY, GL_RGBA8);
108 // ASTC texture data 99 // ASTC texture data
109 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_INPUT_BUFFER, map.buffer, input_offset, 100 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_INPUT_BUFFER, map.buffer, input_offset,
110 image.guest_size_bytes - swizzle.buffer_offset); 101 image.guest_size_bytes - swizzle.buffer_offset);
102 glBindImageTexture(BINDING_OUTPUT_IMAGE, image.StorageHandle(), swizzle.level, GL_TRUE, 0,
103 GL_WRITE_ONLY, GL_RGBA8);
111 104
112 glDispatchCompute(num_dispatches_x, num_dispatches_y, image.info.resources.layers); 105 glDispatchCompute(num_dispatches_x, num_dispatches_y, image.info.resources.layers);
113 } 106 }
diff --git a/src/video_core/renderer_opengl/util_shaders.h b/src/video_core/renderer_opengl/util_shaders.h
index 53d65f368..ef881e35f 100644
--- a/src/video_core/renderer_opengl/util_shaders.h
+++ b/src/video_core/renderer_opengl/util_shaders.h
@@ -62,7 +62,6 @@ private:
62 ProgramManager& program_manager; 62 ProgramManager& program_manager;
63 63
64 OGLBuffer swizzle_table_buffer; 64 OGLBuffer swizzle_table_buffer;
65 OGLBuffer astc_buffer;
66 65
67 OGLProgram astc_decoder_program; 66 OGLProgram astc_decoder_program;
68 OGLProgram block_linear_unswizzle_2d_program; 67 OGLProgram block_linear_unswizzle_2d_program;
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index 561cf5e11..3e96c0f60 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -30,16 +30,12 @@
30namespace Vulkan { 30namespace Vulkan {
31 31
32using Tegra::Texture::SWIZZLE_TABLE; 32using Tegra::Texture::SWIZZLE_TABLE;
33using Tegra::Texture::ASTC::ASTC_ENCODINGS_VALUES;
34using namespace Tegra::Texture::ASTC;
35 33
36namespace { 34namespace {
37 35
38constexpr u32 ASTC_BINDING_INPUT_BUFFER = 0; 36constexpr u32 ASTC_BINDING_INPUT_BUFFER = 0;
39constexpr u32 ASTC_BINDING_ENC_BUFFER = 1; 37constexpr u32 ASTC_BINDING_OUTPUT_IMAGE = 1;
40constexpr u32 ASTC_BINDING_SWIZZLE_BUFFER = 2; 38constexpr size_t ASTC_NUM_BINDINGS = 2;
41constexpr u32 ASTC_BINDING_OUTPUT_IMAGE = 3;
42constexpr size_t ASTC_NUM_BINDINGS = 4;
43 39
44template <size_t size> 40template <size_t size>
45inline constexpr VkPushConstantRange COMPUTE_PUSH_CONSTANT_RANGE{ 41inline constexpr VkPushConstantRange COMPUTE_PUSH_CONSTANT_RANGE{
@@ -75,7 +71,7 @@ constexpr DescriptorBankInfo INPUT_OUTPUT_BANK_INFO{
75 .score = 2, 71 .score = 2,
76}; 72};
77 73
78constexpr std::array<VkDescriptorSetLayoutBinding, 4> ASTC_DESCRIPTOR_SET_BINDINGS{{ 74constexpr std::array<VkDescriptorSetLayoutBinding, ASTC_NUM_BINDINGS> ASTC_DESCRIPTOR_SET_BINDINGS{{
79 { 75 {
80 .binding = ASTC_BINDING_INPUT_BUFFER, 76 .binding = ASTC_BINDING_INPUT_BUFFER,
81 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 77 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
@@ -84,20 +80,6 @@ constexpr std::array<VkDescriptorSetLayoutBinding, 4> ASTC_DESCRIPTOR_SET_BINDIN
84 .pImmutableSamplers = nullptr, 80 .pImmutableSamplers = nullptr,
85 }, 81 },
86 { 82 {
87 .binding = ASTC_BINDING_ENC_BUFFER,
88 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
89 .descriptorCount = 1,
90 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
91 .pImmutableSamplers = nullptr,
92 },
93 {
94 .binding = ASTC_BINDING_SWIZZLE_BUFFER,
95 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
96 .descriptorCount = 1,
97 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
98 .pImmutableSamplers = nullptr,
99 },
100 {
101 .binding = ASTC_BINDING_OUTPUT_IMAGE, 83 .binding = ASTC_BINDING_OUTPUT_IMAGE,
102 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 84 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
103 .descriptorCount = 1, 85 .descriptorCount = 1,
@@ -108,12 +90,12 @@ constexpr std::array<VkDescriptorSetLayoutBinding, 4> ASTC_DESCRIPTOR_SET_BINDIN
108 90
109constexpr DescriptorBankInfo ASTC_BANK_INFO{ 91constexpr DescriptorBankInfo ASTC_BANK_INFO{
110 .uniform_buffers = 0, 92 .uniform_buffers = 0,
111 .storage_buffers = 3, 93 .storage_buffers = 1,
112 .texture_buffers = 0, 94 .texture_buffers = 0,
113 .image_buffers = 0, 95 .image_buffers = 0,
114 .textures = 0, 96 .textures = 0,
115 .images = 1, 97 .images = 1,
116 .score = 4, 98 .score = 2,
117}; 99};
118 100
119constexpr VkDescriptorUpdateTemplateEntryKHR INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE{ 101constexpr VkDescriptorUpdateTemplateEntryKHR INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE{
@@ -136,22 +118,6 @@ constexpr std::array<VkDescriptorUpdateTemplateEntryKHR, ASTC_NUM_BINDINGS>
136 .stride = sizeof(DescriptorUpdateEntry), 118 .stride = sizeof(DescriptorUpdateEntry),
137 }, 119 },
138 { 120 {
139 .dstBinding = ASTC_BINDING_ENC_BUFFER,
140 .dstArrayElement = 0,
141 .descriptorCount = 1,
142 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
143 .offset = ASTC_BINDING_ENC_BUFFER * sizeof(DescriptorUpdateEntry),
144 .stride = sizeof(DescriptorUpdateEntry),
145 },
146 {
147 .dstBinding = ASTC_BINDING_SWIZZLE_BUFFER,
148 .dstArrayElement = 0,
149 .descriptorCount = 1,
150 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
151 .offset = ASTC_BINDING_SWIZZLE_BUFFER * sizeof(DescriptorUpdateEntry),
152 .stride = sizeof(DescriptorUpdateEntry),
153 },
154 {
155 .dstBinding = ASTC_BINDING_OUTPUT_IMAGE, 121 .dstBinding = ASTC_BINDING_OUTPUT_IMAGE,
156 .dstArrayElement = 0, 122 .dstArrayElement = 0,
157 .descriptorCount = 1, 123 .descriptorCount = 1,
@@ -163,7 +129,6 @@ constexpr std::array<VkDescriptorUpdateTemplateEntryKHR, ASTC_NUM_BINDINGS>
163 129
164struct AstcPushConstants { 130struct AstcPushConstants {
165 std::array<u32, 2> blocks_dims; 131 std::array<u32, 2> blocks_dims;
166 u32 bytes_per_block_log2;
167 u32 layer_stride; 132 u32 layer_stride;
168 u32 block_size; 133 u32 block_size;
169 u32 x_shift; 134 u32 x_shift;
@@ -354,46 +319,6 @@ ASTCDecoderPass::ASTCDecoderPass(const Device& device_, VKScheduler& scheduler_,
354 319
355ASTCDecoderPass::~ASTCDecoderPass() = default; 320ASTCDecoderPass::~ASTCDecoderPass() = default;
356 321
357void ASTCDecoderPass::MakeDataBuffer() {
358 constexpr size_t TOTAL_BUFFER_SIZE = sizeof(ASTC_ENCODINGS_VALUES) + sizeof(SWIZZLE_TABLE);
359 data_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
360 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
361 .pNext = nullptr,
362 .flags = 0,
363 .size = TOTAL_BUFFER_SIZE,
364 .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
365 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
366 .queueFamilyIndexCount = 0,
367 .pQueueFamilyIndices = nullptr,
368 });
369 data_buffer_commit = memory_allocator.Commit(data_buffer, MemoryUsage::Upload);
370
371 const auto staging_ref = staging_buffer_pool.Request(TOTAL_BUFFER_SIZE, MemoryUsage::Upload);
372 std::memcpy(staging_ref.mapped_span.data(), &ASTC_ENCODINGS_VALUES,
373 sizeof(ASTC_ENCODINGS_VALUES));
374 // Tack on the swizzle table at the end of the buffer
375 std::memcpy(staging_ref.mapped_span.data() + sizeof(ASTC_ENCODINGS_VALUES), &SWIZZLE_TABLE,
376 sizeof(SWIZZLE_TABLE));
377
378 scheduler.Record([src = staging_ref.buffer, offset = staging_ref.offset, dst = *data_buffer,
379 TOTAL_BUFFER_SIZE](vk::CommandBuffer cmdbuf) {
380 static constexpr VkMemoryBarrier write_barrier{
381 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
382 .pNext = nullptr,
383 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
384 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
385 };
386 const VkBufferCopy copy{
387 .srcOffset = offset,
388 .dstOffset = 0,
389 .size = TOTAL_BUFFER_SIZE,
390 };
391 cmdbuf.CopyBuffer(src, dst, copy);
392 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
393 0, write_barrier);
394 });
395}
396
397void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map, 322void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
398 std::span<const VideoCommon::SwizzleParameters> swizzles) { 323 std::span<const VideoCommon::SwizzleParameters> swizzles) {
399 using namespace VideoCommon::Accelerated; 324 using namespace VideoCommon::Accelerated;
@@ -402,9 +327,6 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
402 VideoCore::Surface::DefaultBlockHeight(image.info.format), 327 VideoCore::Surface::DefaultBlockHeight(image.info.format),
403 }; 328 };
404 scheduler.RequestOutsideRenderPassOperationContext(); 329 scheduler.RequestOutsideRenderPassOperationContext();
405 if (!data_buffer) {
406 MakeDataBuffer();
407 }
408 const VkPipeline vk_pipeline = *pipeline; 330 const VkPipeline vk_pipeline = *pipeline;
409 const VkImageAspectFlags aspect_mask = image.AspectMask(); 331 const VkImageAspectFlags aspect_mask = image.AspectMask();
410 const VkImage vk_image = image.Handle(); 332 const VkImage vk_image = image.Handle();
@@ -436,16 +358,13 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
436 }); 358 });
437 for (const VideoCommon::SwizzleParameters& swizzle : swizzles) { 359 for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
438 const size_t input_offset = swizzle.buffer_offset + map.offset; 360 const size_t input_offset = swizzle.buffer_offset + map.offset;
439 const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U); 361 const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 8U);
440 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U); 362 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 8U);
441 const u32 num_dispatches_z = image.info.resources.layers; 363 const u32 num_dispatches_z = image.info.resources.layers;
442 364
443 update_descriptor_queue.Acquire(); 365 update_descriptor_queue.Acquire();
444 update_descriptor_queue.AddBuffer(map.buffer, input_offset, 366 update_descriptor_queue.AddBuffer(map.buffer, input_offset,
445 image.guest_size_bytes - swizzle.buffer_offset); 367 image.guest_size_bytes - swizzle.buffer_offset);
446 update_descriptor_queue.AddBuffer(*data_buffer, 0, sizeof(ASTC_ENCODINGS_VALUES));
447 update_descriptor_queue.AddBuffer(*data_buffer, sizeof(ASTC_ENCODINGS_VALUES),
448 sizeof(SWIZZLE_TABLE));
449 update_descriptor_queue.AddImage(image.StorageImageView(swizzle.level)); 368 update_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
450 const void* const descriptor_data{update_descriptor_queue.UpdateData()}; 369 const void* const descriptor_data{update_descriptor_queue.UpdateData()};
451 370
@@ -453,11 +372,11 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
453 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info); 372 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
454 ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0})); 373 ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0}));
455 ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0})); 374 ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0}));
375 ASSERT(params.bytes_per_block_log2 == 4);
456 scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_dispatches_z, block_dims, 376 scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_dispatches_z, block_dims,
457 params, descriptor_data](vk::CommandBuffer cmdbuf) { 377 params, descriptor_data](vk::CommandBuffer cmdbuf) {
458 const AstcPushConstants uniforms{ 378 const AstcPushConstants uniforms{
459 .blocks_dims = block_dims, 379 .blocks_dims = block_dims,
460 .bytes_per_block_log2 = params.bytes_per_block_log2,
461 .layer_stride = params.layer_stride, 380 .layer_stride = params.layer_stride,
462 .block_size = params.block_size, 381 .block_size = params.block_size,
463 .x_shift = params.x_shift, 382 .x_shift = params.x_shift,
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h
index 114aef2bd..c7b92cce0 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.h
@@ -96,15 +96,10 @@ public:
96 std::span<const VideoCommon::SwizzleParameters> swizzles); 96 std::span<const VideoCommon::SwizzleParameters> swizzles);
97 97
98private: 98private:
99 void MakeDataBuffer();
100
101 VKScheduler& scheduler; 99 VKScheduler& scheduler;
102 StagingBufferPool& staging_buffer_pool; 100 StagingBufferPool& staging_buffer_pool;
103 VKUpdateDescriptorQueue& update_descriptor_queue; 101 VKUpdateDescriptorQueue& update_descriptor_queue;
104 MemoryAllocator& memory_allocator; 102 MemoryAllocator& memory_allocator;
105
106 vk::Buffer data_buffer;
107 MemoryCommit data_buffer_commit;
108}; 103};
109 104
110} // namespace Vulkan 105} // namespace Vulkan
diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp
index 3ab500760..25161df1f 100644
--- a/src/video_core/textures/astc.cpp
+++ b/src/video_core/textures/astc.cpp
@@ -151,6 +151,76 @@ private:
151 const IntType& m_Bits; 151 const IntType& m_Bits;
152}; 152};
153 153
154enum class IntegerEncoding { JustBits, Quint, Trit };
155
156struct IntegerEncodedValue {
157 constexpr IntegerEncodedValue() = default;
158
159 constexpr IntegerEncodedValue(IntegerEncoding encoding_, u32 num_bits_)
160 : encoding{encoding_}, num_bits{num_bits_} {}
161
162 constexpr bool MatchesEncoding(const IntegerEncodedValue& other) const {
163 return encoding == other.encoding && num_bits == other.num_bits;
164 }
165
166 // Returns the number of bits required to encode num_vals values.
167 u32 GetBitLength(u32 num_vals) const {
168 u32 total_bits = num_bits * num_vals;
169 if (encoding == IntegerEncoding::Trit) {
170 total_bits += (num_vals * 8 + 4) / 5;
171 } else if (encoding == IntegerEncoding::Quint) {
172 total_bits += (num_vals * 7 + 2) / 3;
173 }
174 return total_bits;
175 }
176
177 IntegerEncoding encoding{};
178 u32 num_bits = 0;
179 u32 bit_value = 0;
180 union {
181 u32 quint_value = 0;
182 u32 trit_value;
183 };
184};
185
186// Returns a new instance of this struct that corresponds to the
187// can take no more than mav_value values
188static constexpr IntegerEncodedValue CreateEncoding(u32 mav_value) {
189 while (mav_value > 0) {
190 u32 check = mav_value + 1;
191
192 // Is mav_value a power of two?
193 if (!(check & (check - 1))) {
194 return IntegerEncodedValue(IntegerEncoding::JustBits, std::popcount(mav_value));
195 }
196
197 // Is mav_value of the type 3*2^n - 1?
198 if ((check % 3 == 0) && !((check / 3) & ((check / 3) - 1))) {
199 return IntegerEncodedValue(IntegerEncoding::Trit, std::popcount(check / 3 - 1));
200 }
201
202 // Is mav_value of the type 5*2^n - 1?
203 if ((check % 5 == 0) && !((check / 5) & ((check / 5) - 1))) {
204 return IntegerEncodedValue(IntegerEncoding::Quint, std::popcount(check / 5 - 1));
205 }
206
207 // Apparently it can't be represented with a bounded integer sequence...
208 // just iterate.
209 mav_value--;
210 }
211 return IntegerEncodedValue(IntegerEncoding::JustBits, 0);
212}
213
214static constexpr std::array<IntegerEncodedValue, 256> MakeEncodedValues() {
215 std::array<IntegerEncodedValue, 256> encodings{};
216 for (std::size_t i = 0; i < encodings.size(); ++i) {
217 encodings[i] = CreateEncoding(static_cast<u32>(i));
218 }
219 return encodings;
220}
221
222static constexpr std::array<IntegerEncodedValue, 256> ASTC_ENCODINGS_VALUES = MakeEncodedValues();
223
154namespace Tegra::Texture::ASTC { 224namespace Tegra::Texture::ASTC {
155using IntegerEncodedVector = boost::container::static_vector< 225using IntegerEncodedVector = boost::container::static_vector<
156 IntegerEncodedValue, 256, 226 IntegerEncodedValue, 256,
@@ -521,35 +591,41 @@ static TexelWeightParams DecodeBlockInfo(InputBitStream& strm) {
521 return params; 591 return params;
522} 592}
523 593
524static void FillVoidExtentLDR(InputBitStream& strm, std::span<u32> outBuf, u32 blockWidth, 594// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
525 u32 blockHeight) { 595// is the same as [(num_bits - 1):0] and repeats all the way down.
526 // Don't actually care about the void extent, just read the bits... 596template <typename IntType>
527 for (s32 i = 0; i < 4; ++i) { 597static constexpr IntType Replicate(IntType val, u32 num_bits, u32 to_bit) {
528 strm.ReadBits<13>(); 598 if (num_bits == 0 || to_bit == 0) {
599 return 0;
529 } 600 }
530 601 const IntType v = val & static_cast<IntType>((1 << num_bits) - 1);
531 // Decode the RGBA components and renormalize them to the range [0, 255] 602 IntType res = v;
532 u16 r = static_cast<u16>(strm.ReadBits<16>()); 603 u32 reslen = num_bits;
533 u16 g = static_cast<u16>(strm.ReadBits<16>()); 604 while (reslen < to_bit) {
534 u16 b = static_cast<u16>(strm.ReadBits<16>()); 605 u32 comp = 0;
535 u16 a = static_cast<u16>(strm.ReadBits<16>()); 606 if (num_bits > to_bit - reslen) {
536 607 u32 newshift = to_bit - reslen;
537 u32 rgba = (r >> 8) | (g & 0xFF00) | (static_cast<u32>(b) & 0xFF00) << 8 | 608 comp = num_bits - newshift;
538 (static_cast<u32>(a) & 0xFF00) << 16; 609 num_bits = newshift;
539
540 for (u32 j = 0; j < blockHeight; j++) {
541 for (u32 i = 0; i < blockWidth; i++) {
542 outBuf[j * blockWidth + i] = rgba;
543 } 610 }
611 res = static_cast<IntType>(res << num_bits);
612 res = static_cast<IntType>(res | (v >> comp));
613 reslen += num_bits;
544 } 614 }
615 return res;
545} 616}
546 617
547static void FillError(std::span<u32> outBuf, u32 blockWidth, u32 blockHeight) { 618static constexpr std::size_t NumReplicateEntries(u32 num_bits) {
548 for (u32 j = 0; j < blockHeight; j++) { 619 return std::size_t(1) << num_bits;
549 for (u32 i = 0; i < blockWidth; i++) { 620}
550 outBuf[j * blockWidth + i] = 0xFFFF00FF; 621
551 } 622template <typename IntType, u32 num_bits, u32 to_bit>
623static constexpr auto MakeReplicateTable() {
624 std::array<IntType, NumReplicateEntries(num_bits)> table{};
625 for (IntType value = 0; value < static_cast<IntType>(std::size(table)); ++value) {
626 table[value] = Replicate(value, num_bits, to_bit);
552 } 627 }
628 return table;
553} 629}
554 630
555static constexpr auto REPLICATE_BYTE_TO_16_TABLE = MakeReplicateTable<u32, 8, 16>(); 631static constexpr auto REPLICATE_BYTE_TO_16_TABLE = MakeReplicateTable<u32, 8, 16>();
@@ -572,6 +648,9 @@ static constexpr auto REPLICATE_2_BIT_TO_8_TABLE = MakeReplicateTable<u32, 2, 8>
572static constexpr auto REPLICATE_3_BIT_TO_8_TABLE = MakeReplicateTable<u32, 3, 8>(); 648static constexpr auto REPLICATE_3_BIT_TO_8_TABLE = MakeReplicateTable<u32, 3, 8>();
573static constexpr auto REPLICATE_4_BIT_TO_8_TABLE = MakeReplicateTable<u32, 4, 8>(); 649static constexpr auto REPLICATE_4_BIT_TO_8_TABLE = MakeReplicateTable<u32, 4, 8>();
574static constexpr auto REPLICATE_5_BIT_TO_8_TABLE = MakeReplicateTable<u32, 5, 8>(); 650static constexpr auto REPLICATE_5_BIT_TO_8_TABLE = MakeReplicateTable<u32, 5, 8>();
651static constexpr auto REPLICATE_6_BIT_TO_8_TABLE = MakeReplicateTable<u32, 6, 8>();
652static constexpr auto REPLICATE_7_BIT_TO_8_TABLE = MakeReplicateTable<u32, 7, 8>();
653static constexpr auto REPLICATE_8_BIT_TO_8_TABLE = MakeReplicateTable<u32, 8, 8>();
575/// Use a precompiled table with the most common usages, if it's not in the expected range, fallback 654/// Use a precompiled table with the most common usages, if it's not in the expected range, fallback
576/// to the runtime implementation 655/// to the runtime implementation
577static constexpr u32 FastReplicateTo8(u32 value, u32 num_bits) { 656static constexpr u32 FastReplicateTo8(u32 value, u32 num_bits) {
@@ -1316,6 +1395,37 @@ static void ComputeEndpoints(Pixel& ep1, Pixel& ep2, const u32*& colorValues,
1316#undef READ_INT_VALUES 1395#undef READ_INT_VALUES
1317} 1396}
1318 1397
1398static void FillVoidExtentLDR(InputBitStream& strm, std::span<u32> outBuf, u32 blockWidth,
1399 u32 blockHeight) {
1400 // Don't actually care about the void extent, just read the bits...
1401 for (s32 i = 0; i < 4; ++i) {
1402 strm.ReadBits<13>();
1403 }
1404
1405 // Decode the RGBA components and renormalize them to the range [0, 255]
1406 u16 r = static_cast<u16>(strm.ReadBits<16>());
1407 u16 g = static_cast<u16>(strm.ReadBits<16>());
1408 u16 b = static_cast<u16>(strm.ReadBits<16>());
1409 u16 a = static_cast<u16>(strm.ReadBits<16>());
1410
1411 u32 rgba = (r >> 8) | (g & 0xFF00) | (static_cast<u32>(b) & 0xFF00) << 8 |
1412 (static_cast<u32>(a) & 0xFF00) << 16;
1413
1414 for (u32 j = 0; j < blockHeight; j++) {
1415 for (u32 i = 0; i < blockWidth; i++) {
1416 outBuf[j * blockWidth + i] = rgba;
1417 }
1418 }
1419}
1420
1421static void FillError(std::span<u32> outBuf, u32 blockWidth, u32 blockHeight) {
1422 for (u32 j = 0; j < blockHeight; j++) {
1423 for (u32 i = 0; i < blockWidth; i++) {
1424 outBuf[j * blockWidth + i] = 0xFFFF00FF;
1425 }
1426 }
1427}
1428
1319static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth, 1429static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth,
1320 const u32 blockHeight, std::span<u32, 12 * 12> outBuf) { 1430 const u32 blockHeight, std::span<u32, 12 * 12> outBuf) {
1321 InputBitStream strm(inBuf); 1431 InputBitStream strm(inBuf);
diff --git a/src/video_core/textures/astc.h b/src/video_core/textures/astc.h
index 0229ae122..14d2beec0 100644
--- a/src/video_core/textures/astc.h
+++ b/src/video_core/textures/astc.h
@@ -9,117 +9,6 @@
9 9
10namespace Tegra::Texture::ASTC { 10namespace Tegra::Texture::ASTC {
11 11
12enum class IntegerEncoding { JustBits, Quint, Trit };
13
14struct IntegerEncodedValue {
15 constexpr IntegerEncodedValue() = default;
16
17 constexpr IntegerEncodedValue(IntegerEncoding encoding_, u32 num_bits_)
18 : encoding{encoding_}, num_bits{num_bits_} {}
19
20 constexpr bool MatchesEncoding(const IntegerEncodedValue& other) const {
21 return encoding == other.encoding && num_bits == other.num_bits;
22 }
23
24 // Returns the number of bits required to encode num_vals values.
25 u32 GetBitLength(u32 num_vals) const {
26 u32 total_bits = num_bits * num_vals;
27 if (encoding == IntegerEncoding::Trit) {
28 total_bits += (num_vals * 8 + 4) / 5;
29 } else if (encoding == IntegerEncoding::Quint) {
30 total_bits += (num_vals * 7 + 2) / 3;
31 }
32 return total_bits;
33 }
34
35 IntegerEncoding encoding{};
36 u32 num_bits = 0;
37 u32 bit_value = 0;
38 union {
39 u32 quint_value = 0;
40 u32 trit_value;
41 };
42};
43
44// Returns a new instance of this struct that corresponds to the
45// can take no more than mav_value values
46constexpr IntegerEncodedValue CreateEncoding(u32 mav_value) {
47 while (mav_value > 0) {
48 u32 check = mav_value + 1;
49
50 // Is mav_value a power of two?
51 if (!(check & (check - 1))) {
52 return IntegerEncodedValue(IntegerEncoding::JustBits, std::popcount(mav_value));
53 }
54
55 // Is mav_value of the type 3*2^n - 1?
56 if ((check % 3 == 0) && !((check / 3) & ((check / 3) - 1))) {
57 return IntegerEncodedValue(IntegerEncoding::Trit, std::popcount(check / 3 - 1));
58 }
59
60 // Is mav_value of the type 5*2^n - 1?
61 if ((check % 5 == 0) && !((check / 5) & ((check / 5) - 1))) {
62 return IntegerEncodedValue(IntegerEncoding::Quint, std::popcount(check / 5 - 1));
63 }
64
65 // Apparently it can't be represented with a bounded integer sequence...
66 // just iterate.
67 mav_value--;
68 }
69 return IntegerEncodedValue(IntegerEncoding::JustBits, 0);
70}
71
72constexpr std::array<IntegerEncodedValue, 256> MakeEncodedValues() {
73 std::array<IntegerEncodedValue, 256> encodings{};
74 for (std::size_t i = 0; i < encodings.size(); ++i) {
75 encodings[i] = CreateEncoding(static_cast<u32>(i));
76 }
77 return encodings;
78}
79
80constexpr std::array<IntegerEncodedValue, 256> ASTC_ENCODINGS_VALUES = MakeEncodedValues();
81
82// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
83// is the same as [(num_bits - 1):0] and repeats all the way down.
84template <typename IntType>
85constexpr IntType Replicate(IntType val, u32 num_bits, u32 to_bit) {
86 if (num_bits == 0 || to_bit == 0) {
87 return 0;
88 }
89 const IntType v = val & static_cast<IntType>((1 << num_bits) - 1);
90 IntType res = v;
91 u32 reslen = num_bits;
92 while (reslen < to_bit) {
93 u32 comp = 0;
94 if (num_bits > to_bit - reslen) {
95 u32 newshift = to_bit - reslen;
96 comp = num_bits - newshift;
97 num_bits = newshift;
98 }
99 res = static_cast<IntType>(res << num_bits);
100 res = static_cast<IntType>(res | (v >> comp));
101 reslen += num_bits;
102 }
103 return res;
104}
105
106constexpr std::size_t NumReplicateEntries(u32 num_bits) {
107 return std::size_t(1) << num_bits;
108}
109
110template <typename IntType, u32 num_bits, u32 to_bit>
111constexpr auto MakeReplicateTable() {
112 std::array<IntType, NumReplicateEntries(num_bits)> table{};
113 for (IntType value = 0; value < static_cast<IntType>(std::size(table)); ++value) {
114 table[value] = Replicate(value, num_bits, to_bit);
115 }
116 return table;
117}
118
119constexpr auto REPLICATE_6_BIT_TO_8_TABLE = MakeReplicateTable<u32, 6, 8>();
120constexpr auto REPLICATE_7_BIT_TO_8_TABLE = MakeReplicateTable<u32, 7, 8>();
121constexpr auto REPLICATE_8_BIT_TO_8_TABLE = MakeReplicateTable<u32, 8, 8>();
122
123void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, 12void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
124 uint32_t block_width, uint32_t block_height, std::span<uint8_t> output); 13 uint32_t block_width, uint32_t block_height, std::span<uint8_t> output);
125 14
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
index aa173d19e..300a61205 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
@@ -228,7 +228,9 @@ void MemoryCommit::Release() {
228 228
229MemoryAllocator::MemoryAllocator(const Device& device_, bool export_allocations_) 229MemoryAllocator::MemoryAllocator(const Device& device_, bool export_allocations_)
230 : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()}, 230 : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()},
231 export_allocations{export_allocations_} {} 231 export_allocations{export_allocations_},
232 buffer_image_granularity{
233 device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {}
232 234
233MemoryAllocator::~MemoryAllocator() = default; 235MemoryAllocator::~MemoryAllocator() = default;
234 236
@@ -258,7 +260,9 @@ MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage
258} 260}
259 261
260MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) { 262MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) {
261 auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), usage); 263 VkMemoryRequirements requirements = device.GetLogical().GetImageMemoryRequirements(*image);
264 requirements.size = Common::AlignUp(requirements.size, buffer_image_granularity);
265 auto commit = Commit(requirements, usage);
262 image.BindMemory(commit.Memory(), commit.Offset()); 266 image.BindMemory(commit.Memory(), commit.Offset());
263 return commit; 267 return commit;
264} 268}
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h
index b61e931e0..86e8ed119 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.h
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h
@@ -123,6 +123,8 @@ private:
123 const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. 123 const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties.
124 const bool export_allocations; ///< True when memory allocations have to be exported. 124 const bool export_allocations; ///< True when memory allocations have to be exported.
125 std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. 125 std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations.
126 VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers
127 // and optimal images
126}; 128};
127 129
128/// Returns true when a memory usage is guaranteed to be host visible. 130/// Returns true when a memory usage is guaranteed to be host visible.
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index 8ce97edec..69b6c2d66 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -25,6 +25,36 @@
25 <item> 25 <item>
26 <layout class="QVBoxLayout" name="GeneralVerticalLayout"> 26 <layout class="QVBoxLayout" name="GeneralVerticalLayout">
27 <item> 27 <item>
28 <layout class="QHBoxLayout" name="horizontalLayout_2">
29 <item>
30 <widget class="QLabel" name="fps_cap_label">
31 <property name="text">
32 <string>Framerate Cap</string>
33 </property>
34 <property name="toolTip">
35 <string>Requires the use of the FPS Limiter Toggle hotkey to take effect.</string>
36 </property>
37 </widget>
38 </item>
39 <item>
40 <widget class="QSpinBox" name="fps_cap">
41 <property name="suffix">
42 <string>x</string>
43 </property>
44 <property name="minimum">
45 <number>1</number>
46 </property>
47 <property name="maximum">
48 <number>1000</number>
49 </property>
50 <property name="value">
51 <number>500</number>
52 </property>
53 </widget>
54 </item>
55 </layout>
56 </item>
57 <item>
28 <layout class="QHBoxLayout" name="horizontalLayout_2"> 58 <layout class="QHBoxLayout" name="horizontalLayout_2">
29 <item> 59 <item>
30 <widget class="QCheckBox" name="toggle_speed_limit"> 60 <widget class="QCheckBox" name="toggle_speed_limit">
@@ -52,36 +82,6 @@
52 </layout> 82 </layout>
53 </item> 83 </item>
54 <item> 84 <item>
55 <layout class="QHBoxLayout" name="horizontalLayout_2">
56 <item>
57 <widget class="QLabel" name="fps_cap_label">
58 <property name="text">
59 <string>Framerate Cap</string>
60 </property>
61 <property name="toolTip">
62 <string>Requires the use of the FPS Limiter Toggle hotkey to take effect.</string>
63 </property>
64 </widget>
65 </item>
66 <item>
67 <widget class="QSpinBox" name="fps_cap">
68 <property name="suffix">
69 <string>x</string>
70 </property>
71 <property name="minimum">
72 <number>1</number>
73 </property>
74 <property name="maximum">
75 <number>1000</number>
76 </property>
77 <property name="value">
78 <number>500</number>
79 </property>
80 </widget>
81 </item>
82 </layout>
83 </item>
84 <item>
85 <widget class="QCheckBox" name="use_multi_core"> 85 <widget class="QCheckBox" name="use_multi_core">
86 <property name="text"> 86 <property name="text">
87 <string>Multicore CPU Emulation</string> 87 <string>Multicore CPU Emulation</string>
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index 379dc5d2e..4fe6b86ae 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -82,14 +82,17 @@
82 <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string> 82 <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string>
83 </property> 83 </property>
84 <property name="text"> 84 <property name="text">
85 <string>Use asynchronous shader building</string> 85 <string>Use asynchronous shader building (hack)</string>
86 </property> 86 </property>
87 </widget> 87 </widget>
88 </item> 88 </item>
89 <item> 89 <item>
90 <widget class="QCheckBox" name="use_fast_gpu_time"> 90 <widget class="QCheckBox" name="use_fast_gpu_time">
91 <property name="toolTip">
92 <string>Enables Fast GPU Time. This option will force most games to run at their highest native resolution.</string>
93 </property>
91 <property name="text"> 94 <property name="text">
92 <string>Use Fast GPU Time</string> 95 <string>Use Fast GPU Time (hack)</string>
93 </property> 96 </property>
94 </widget> 97 </widget>
95 </item> 98 </item>
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 6b9bd05f1..7527c068b 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -309,11 +309,14 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
309 buttons_param[button_id].Clear(); 309 buttons_param[button_id].Clear();
310 button_map[button_id]->setText(tr("[not set]")); 310 button_map[button_id]->setText(tr("[not set]"));
311 }); 311 });
312 context_menu.addAction(tr("Toggle button"), [&] { 312 if (buttons_param[button_id].Has("toggle")) {
313 const bool toggle_value = !buttons_param[button_id].Get("toggle", false); 313 context_menu.addAction(tr("Toggle button"), [&] {
314 buttons_param[button_id].Set("toggle", toggle_value); 314 const bool toggle_value =
315 button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); 315 !buttons_param[button_id].Get("toggle", false);
316 }); 316 buttons_param[button_id].Set("toggle", toggle_value);
317 button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
318 });
319 }
317 if (buttons_param[button_id].Has("threshold")) { 320 if (buttons_param[button_id].Has("threshold")) {
318 context_menu.addAction(tr("Set threshold"), [&] { 321 context_menu.addAction(tr("Set threshold"), [&] {
319 const int button_threshold = static_cast<int>( 322 const int button_threshold = static_cast<int>(
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index f50cda2f3..cd633e45f 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -122,6 +122,7 @@ void PlayerControlPreview::UpdateColors() {
122 colors.slider_arrow = QColor(14, 15, 18); 122 colors.slider_arrow = QColor(14, 15, 18);
123 colors.font2 = QColor(255, 255, 255); 123 colors.font2 = QColor(255, 255, 255);
124 colors.indicator = QColor(170, 238, 255); 124 colors.indicator = QColor(170, 238, 255);
125 colors.indicator2 = QColor(100, 255, 100);
125 colors.deadzone = QColor(204, 136, 136); 126 colors.deadzone = QColor(204, 136, 136);
126 colors.slider_button = colors.button; 127 colors.slider_button = colors.button;
127 } 128 }
@@ -139,6 +140,7 @@ void PlayerControlPreview::UpdateColors() {
139 colors.slider_arrow = QColor(65, 68, 73); 140 colors.slider_arrow = QColor(65, 68, 73);
140 colors.font2 = QColor(0, 0, 0); 141 colors.font2 = QColor(0, 0, 0);
141 colors.indicator = QColor(0, 0, 200); 142 colors.indicator = QColor(0, 0, 200);
143 colors.indicator2 = QColor(0, 150, 0);
142 colors.deadzone = QColor(170, 0, 0); 144 colors.deadzone = QColor(170, 0, 0);
143 colors.slider_button = QColor(153, 149, 149); 145 colors.slider_button = QColor(153, 149, 149);
144 } 146 }
@@ -317,8 +319,7 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center)
317 using namespace Settings::NativeAnalog; 319 using namespace Settings::NativeAnalog;
318 DrawJoystick(p, center + QPointF(9, -69) + (axis_values[LStick].value * 8), 1.8f, 320 DrawJoystick(p, center + QPointF(9, -69) + (axis_values[LStick].value * 8), 1.8f,
319 button_values[Settings::NativeButton::LStick]); 321 button_values[Settings::NativeButton::LStick]);
320 DrawRawJoystick(p, center + QPointF(-140, 90), axis_values[LStick].raw_value, 322 DrawRawJoystick(p, center + QPointF(-140, 90), QPointF(0, 0));
321 axis_values[LStick].properties);
322 } 323 }
323 324
324 using namespace Settings::NativeButton; 325 using namespace Settings::NativeButton;
@@ -432,8 +433,7 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
432 using namespace Settings::NativeAnalog; 433 using namespace Settings::NativeAnalog;
433 DrawJoystick(p, center + QPointF(-9, 11) + (axis_values[RStick].value * 8), 1.8f, 434 DrawJoystick(p, center + QPointF(-9, 11) + (axis_values[RStick].value * 8), 1.8f,
434 button_values[Settings::NativeButton::RStick]); 435 button_values[Settings::NativeButton::RStick]);
435 DrawRawJoystick(p, center + QPointF(140, 90), axis_values[RStick].raw_value, 436 DrawRawJoystick(p, QPointF(0, 0), center + QPointF(140, 90));
436 axis_values[RStick].properties);
437 } 437 }
438 438
439 using namespace Settings::NativeButton; 439 using namespace Settings::NativeButton;
@@ -547,8 +547,7 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
547 547
548 DrawJoystick(p, center + QPointF(-65, -65) + (l_stick.value * 7), 1.62f, l_button); 548 DrawJoystick(p, center + QPointF(-65, -65) + (l_stick.value * 7), 1.62f, l_button);
549 DrawJoystick(p, center + QPointF(65, 12) + (r_stick.value * 7), 1.62f, r_button); 549 DrawJoystick(p, center + QPointF(65, 12) + (r_stick.value * 7), 1.62f, r_button);
550 DrawRawJoystick(p, center + QPointF(-180, 90), l_stick.raw_value, l_stick.properties); 550 DrawRawJoystick(p, center + QPointF(-180, 90), center + QPointF(180, 90));
551 DrawRawJoystick(p, center + QPointF(180, 90), r_stick.raw_value, r_stick.properties);
552 } 551 }
553 552
554 using namespace Settings::NativeButton; 553 using namespace Settings::NativeButton;
@@ -634,8 +633,7 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
634 633
635 DrawJoystick(p, center + QPointF(-171, -41) + (l_stick.value * 4), 1.0f, l_button); 634 DrawJoystick(p, center + QPointF(-171, -41) + (l_stick.value * 4), 1.0f, l_button);
636 DrawJoystick(p, center + QPointF(171, 8) + (r_stick.value * 4), 1.0f, r_button); 635 DrawJoystick(p, center + QPointF(171, 8) + (r_stick.value * 4), 1.0f, r_button);
637 DrawRawJoystick(p, center + QPointF(-50, 0), l_stick.raw_value, l_stick.properties); 636 DrawRawJoystick(p, center + QPointF(-50, 0), center + QPointF(50, 0));
638 DrawRawJoystick(p, center + QPointF(50, 0), r_stick.raw_value, r_stick.properties);
639 } 637 }
640 638
641 using namespace Settings::NativeButton; 639 using namespace Settings::NativeButton;
@@ -728,10 +726,7 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
728 button_values[Settings::NativeButton::LStick]); 726 button_values[Settings::NativeButton::LStick]);
729 DrawProJoystick(p, center + QPointF(51, 0), axis_values[RStick].value, 11, 727 DrawProJoystick(p, center + QPointF(51, 0), axis_values[RStick].value, 11,
730 button_values[Settings::NativeButton::RStick]); 728 button_values[Settings::NativeButton::RStick]);
731 DrawRawJoystick(p, center + QPointF(-50, 105), axis_values[LStick].raw_value, 729 DrawRawJoystick(p, center + QPointF(-50, 105), center + QPointF(50, 105));
732 axis_values[LStick].properties);
733 DrawRawJoystick(p, center + QPointF(50, 105), axis_values[RStick].raw_value,
734 axis_values[RStick].properties);
735 } 730 }
736 731
737 using namespace Settings::NativeButton; 732 using namespace Settings::NativeButton;
@@ -821,10 +816,7 @@ void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) {
821 p.setBrush(colors.font); 816 p.setBrush(colors.font);
822 DrawSymbol(p, center + QPointF(61, 37) + (axis_values[RStick].value * 9.5f), Symbol::C, 817 DrawSymbol(p, center + QPointF(61, 37) + (axis_values[RStick].value * 9.5f), Symbol::C,
823 1.0f); 818 1.0f);
824 DrawRawJoystick(p, center + QPointF(-198, -125), axis_values[LStick].raw_value, 819 DrawRawJoystick(p, center + QPointF(-198, -125), center + QPointF(198, -125));
825 axis_values[LStick].properties);
826 DrawRawJoystick(p, center + QPointF(198, -125), axis_values[RStick].raw_value,
827 axis_values[RStick].properties);
828 } 820 }
829 821
830 using namespace Settings::NativeButton; 822 using namespace Settings::NativeButton;
@@ -2358,8 +2350,33 @@ void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, boo
2358 DrawCircle(p, center, 7.5f); 2350 DrawCircle(p, center, 7.5f);
2359} 2351}
2360 2352
2361void PlayerControlPreview::DrawRawJoystick(QPainter& p, const QPointF center, const QPointF value, 2353void PlayerControlPreview::DrawRawJoystick(QPainter& p, QPointF center_left, QPointF center_right) {
2362 const Input::AnalogProperties& properties) { 2354 using namespace Settings::NativeAnalog;
2355 if (controller_type != Settings::ControllerType::LeftJoycon) {
2356 DrawJoystickProperties(p, center_right, axis_values[RStick].properties);
2357 p.setPen(colors.indicator);
2358 p.setBrush(colors.indicator);
2359 DrawJoystickDot(p, center_right, axis_values[RStick].raw_value,
2360 axis_values[RStick].properties);
2361 p.setPen(colors.indicator2);
2362 p.setBrush(colors.indicator2);
2363 DrawJoystickDot(p, center_right, axis_values[RStick].value, axis_values[RStick].properties);
2364 }
2365
2366 if (controller_type != Settings::ControllerType::RightJoycon) {
2367 DrawJoystickProperties(p, center_left, axis_values[LStick].properties);
2368 p.setPen(colors.indicator);
2369 p.setBrush(colors.indicator);
2370 DrawJoystickDot(p, center_left, axis_values[LStick].raw_value,
2371 axis_values[LStick].properties);
2372 p.setPen(colors.indicator2);
2373 p.setBrush(colors.indicator2);
2374 DrawJoystickDot(p, center_left, axis_values[LStick].value, axis_values[LStick].properties);
2375 }
2376}
2377
2378void PlayerControlPreview::DrawJoystickProperties(QPainter& p, const QPointF center,
2379 const Input::AnalogProperties& properties) {
2363 constexpr float size = 45.0f; 2380 constexpr float size = 45.0f;
2364 const float range = size * properties.range; 2381 const float range = size * properties.range;
2365 const float deadzone = size * properties.deadzone; 2382 const float deadzone = size * properties.deadzone;
@@ -2376,10 +2393,14 @@ void PlayerControlPreview::DrawRawJoystick(QPainter& p, const QPointF center, co
2376 pen.setColor(colors.deadzone); 2393 pen.setColor(colors.deadzone);
2377 p.setPen(pen); 2394 p.setPen(pen);
2378 DrawCircle(p, center, deadzone); 2395 DrawCircle(p, center, deadzone);
2396}
2397
2398void PlayerControlPreview::DrawJoystickDot(QPainter& p, const QPointF center, const QPointF value,
2399 const Input::AnalogProperties& properties) {
2400 constexpr float size = 45.0f;
2401 const float range = size * properties.range;
2379 2402
2380 // Dot pointer 2403 // Dot pointer
2381 p.setPen(colors.indicator);
2382 p.setBrush(colors.indicator);
2383 DrawCircle(p, center + (value * range), 2); 2404 DrawCircle(p, center + (value * range), 2);
2384} 2405}
2385 2406
diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h
index 5fc16d8af..f4a6a5e1b 100644
--- a/src/yuzu/configuration/configure_input_player_widget.h
+++ b/src/yuzu/configuration/configure_input_player_widget.h
@@ -90,6 +90,7 @@ private:
90 QColor highlight2{}; 90 QColor highlight2{};
91 QColor transparent{}; 91 QColor transparent{};
92 QColor indicator{}; 92 QColor indicator{};
93 QColor indicator2{};
93 QColor led_on{}; 94 QColor led_on{};
94 QColor led_off{}; 95 QColor led_off{};
95 QColor slider{}; 96 QColor slider{};
@@ -139,7 +140,10 @@ private:
139 // Draw joystick functions 140 // Draw joystick functions
140 void DrawJoystick(QPainter& p, QPointF center, float size, bool pressed); 141 void DrawJoystick(QPainter& p, QPointF center, float size, bool pressed);
141 void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, bool pressed); 142 void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, bool pressed);
142 void DrawRawJoystick(QPainter& p, QPointF center, QPointF value, 143 void DrawRawJoystick(QPainter& p, QPointF center_left, QPointF center_right);
144 void DrawJoystickProperties(QPainter& p, QPointF center,
145 const Input::AnalogProperties& properties);
146 void DrawJoystickDot(QPainter& p, QPointF center, QPointF value,
143 const Input::AnalogProperties& properties); 147 const Input::AnalogProperties& properties);
144 void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar, bool pressed); 148 void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar, bool pressed);
145 void DrawGCJoystick(QPainter& p, QPointF center, bool pressed); 149 void DrawGCJoystick(QPainter& p, QPointF center, bool pressed);
diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt
index e55a19649..74fc24972 100644
--- a/src/yuzu_cmd/CMakeLists.txt
+++ b/src/yuzu_cmd/CMakeLists.txt
@@ -1,5 +1,6 @@
1set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) 1set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
2 2
3# Credits to Samantas5855 and others for this function.
3function(create_resource file output filename) 4function(create_resource file output filename)
4 # Read hex data from file 5 # Read hex data from file
5 file(READ ${file} filedata HEX) 6 file(READ ${file} filedata HEX)
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index f643a4b0b..87fce0c23 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -122,6 +122,10 @@ void EmuWindow_SDL2::OnResize() {
122 UpdateCurrentFramebufferLayout(width, height); 122 UpdateCurrentFramebufferLayout(width, height);
123} 123}
124 124
125void EmuWindow_SDL2::ShowCursor(bool show_cursor) {
126 SDL_ShowCursor(show_cursor ? SDL_ENABLE : SDL_DISABLE);
127}
128
125void EmuWindow_SDL2::Fullscreen() { 129void EmuWindow_SDL2::Fullscreen() {
126 switch (Settings::values.fullscreen_mode.GetValue()) { 130 switch (Settings::values.fullscreen_mode.GetValue()) {
127 case Settings::FullscreenMode::Exclusive: 131 case Settings::FullscreenMode::Exclusive:
@@ -228,6 +232,7 @@ void EmuWindow_SDL2::WaitEvent() {
228 } 232 }
229} 233}
230 234
235// Credits to Samantas5855 and others for this function.
231void EmuWindow_SDL2::SetWindowIcon() { 236void EmuWindow_SDL2::SetWindowIcon() {
232 SDL_RWops* const yuzu_icon_stream = SDL_RWFromConstMem((void*)yuzu_icon, yuzu_icon_size); 237 SDL_RWops* const yuzu_icon_stream = SDL_RWFromConstMem((void*)yuzu_icon, yuzu_icon_size);
233 if (yuzu_icon_stream == nullptr) { 238 if (yuzu_icon_stream == nullptr) {
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
index aa0d52ae4..4810f8775 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
@@ -67,6 +67,9 @@ protected:
67 /// Called by WaitEvent when any event that may cause the window to be resized occurs 67 /// Called by WaitEvent when any event that may cause the window to be resized occurs
68 void OnResize(); 68 void OnResize();
69 69
70 /// Called when users want to hide the mouse cursor
71 void ShowCursor(bool show_cursor);
72
70 /// Called when user passes the fullscreen parameter flag 73 /// Called when user passes the fullscreen parameter flag
71 void Fullscreen(); 74 void Fullscreen();
72 75
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
index 5b98c255b..a075ad08a 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
@@ -111,6 +111,7 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsyste
111 111
112 if (fullscreen) { 112 if (fullscreen) {
113 Fullscreen(); 113 Fullscreen();
114 ShowCursor(false);
114 } 115 }
115 116
116 window_context = SDL_GL_CreateContext(render_window); 117 window_context = SDL_GL_CreateContext(render_window);
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 cdda375d8..de40b76bf 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
@@ -45,6 +45,7 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste
45 45
46 if (fullscreen) { 46 if (fullscreen) {
47 Fullscreen(); 47 Fullscreen();
48 ShowCursor(false);
48 } 49 }
49 50
50 switch (wm.subsystem) { 51 switch (wm.subsystem) {