Merge branch 'shadps4-emu:main' into Fix_PromoteFormatToDepth

This commit is contained in:
¥IGA 2025-01-03 17:54:35 +01:00 committed by GitHub
commit 7d02688f96
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
82 changed files with 1795 additions and 955 deletions

View File

@ -13,7 +13,11 @@ body:
**Please do not make support requests on GitHub. Our issue tracker is for tracking bugs and feature requests only. **Please do not make support requests on GitHub. Our issue tracker is for tracking bugs and feature requests only.
If you have a support request or are unsure about the nature of your issue please contact us on [discord](https://discord.gg/bFJxfftGW6).** If you have a support request or are unsure about the nature of your issue please contact us on [discord](https://discord.gg/bFJxfftGW6).**
You can also check the [Game Compatibility Repository](https://github.com/shadps4-emu/shadps4-game-compatibility) for the information about the status of the game. This repository does not provide support for modded games. You should perform and test a clean game installation before submitting an issue.
This repository does not provide support for game patches. If you are having issues with patches please refer to [Cheats and Patches Repository](https://github.com/shadps4-emu/ps4_cheats).
Before submitting an issue please check [Game Compatibility Repository](https://github.com/shadps4-emu/shadps4-game-compatibility) for the information about the status of the game.
Please make an effort to make sure your issue isn't already reported. Please make an effort to make sure your issue isn't already reported.
@ -21,15 +25,15 @@ body:
- type: checkboxes - type: checkboxes
id: checklist id: checklist
attributes: attributes:
label: Checklist label: Checklist (we expect you to perform these steps before opening the issue)
options: options:
- label: I have searched for a similar issue in this repository and did not find one. - label: I have searched for a similar issue in this repository and did not find one.
required: true required: true
- label: I am using an official build obtained from [releases](https://github.com/shadps4-emu/shadPS4/releases) or updated one of those builds using its in-app updater. - label: I am using an official build obtained from [releases](https://github.com/shadps4-emu/shadPS4/releases) or updated one of those builds using its in-app updater.
required: true required: true
- label: I have re-dumped the game and performed a clean install without mods. - label: I have re-dumped the game and performed a clean install without mods and the issue is still present.
required: true required: true
- label: I have disabled all patches and cheats. - label: I have disabled all patches and cheats and the issue is still present.
required: true required: true
- label: I have all the required [system modules](https://github.com/shadps4-emu/shadps4-game-compatibility?tab=readme-ov-file#informations) installed. - label: I have all the required [system modules](https://github.com/shadps4-emu/shadps4-game-compatibility?tab=readme-ov-file#informations) installed.
required: true required: true

View File

@ -67,6 +67,7 @@ static int cursorHideTimeout = 5; // 5 seconds (default)
static bool separateupdatefolder = false; static bool separateupdatefolder = false;
static bool compatibilityData = false; static bool compatibilityData = false;
static bool checkCompatibilityOnStartup = false; static bool checkCompatibilityOnStartup = false;
static std::string trophyKey;
// Gui // Gui
std::vector<std::filesystem::path> settings_install_dirs = {}; std::vector<std::filesystem::path> settings_install_dirs = {};
@ -91,6 +92,14 @@ std::string emulator_language = "en";
// Language // Language
u32 m_language = 1; // english u32 m_language = 1; // english
std::string getTrophyKey() {
return trophyKey;
}
void setTrophyKey(std::string key) {
trophyKey = key;
}
bool isNeoMode() { bool isNeoMode() {
return isNeo; return isNeo;
} }
@ -652,6 +661,11 @@ void load(const std::filesystem::path& path) {
m_language = toml::find_or<int>(settings, "consoleLanguage", 1); m_language = toml::find_or<int>(settings, "consoleLanguage", 1);
} }
if (data.contains("Keys")) {
const toml::value& keys = data.at("Keys");
trophyKey = toml::find_or<std::string>(keys, "TrophyKey", "");
}
} }
void save(const std::filesystem::path& path) { void save(const std::filesystem::path& path) {
@ -712,6 +726,8 @@ void save(const std::filesystem::path& path) {
data["Debug"]["DebugDump"] = isDebugDump; data["Debug"]["DebugDump"] = isDebugDump;
data["Debug"]["CollectShader"] = isShaderDebug; data["Debug"]["CollectShader"] = isShaderDebug;
data["Keys"]["TrophyKey"] = trophyKey;
std::vector<std::string> install_dirs; std::vector<std::string> install_dirs;
for (const auto& dirString : settings_install_dirs) { for (const auto& dirString : settings_install_dirs) {
install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data}); install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data});

View File

@ -15,6 +15,9 @@ void load(const std::filesystem::path& path);
void save(const std::filesystem::path& path); void save(const std::filesystem::path& path);
void saveMainWindow(const std::filesystem::path& path); void saveMainWindow(const std::filesystem::path& path);
std::string getTrophyKey();
void setTrophyKey(std::string key);
bool isNeoMode(); bool isNeoMode();
bool isFullscreenMode(); bool isFullscreenMode();
bool getPlayBGM(); bool getPlayBGM();

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <array> #include <array>
#include "crypto.h" #include "crypto.h"
CryptoPP::RSA::PrivateKey Crypto::key_pkg_derived_key3_keyset_init() { CryptoPP::RSA::PrivateKey Crypto::key_pkg_derived_key3_keyset_init() {
@ -137,17 +138,20 @@ void Crypto::aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
} }
} }
void Crypto::decryptEFSM(std::span<CryptoPP::byte, 16> NPcommID, void Crypto::decryptEFSM(std::span<CryptoPP::byte, 16> trophyKey,
std::span<CryptoPP::byte, 16> NPcommID,
std::span<CryptoPP::byte, 16> efsmIv, std::span<CryptoPP::byte> ciphertext, std::span<CryptoPP::byte, 16> efsmIv, std::span<CryptoPP::byte> ciphertext,
std::span<CryptoPP::byte> decrypted) { std::span<CryptoPP::byte> decrypted) {
std::vector<CryptoPP::byte> TrophyIV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// step 1: Encrypt NPcommID // step 1: Encrypt NPcommID
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt; CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt;
std::vector<CryptoPP::byte> trophyIv(16, 0);
std::vector<CryptoPP::byte> trpKey(16); std::vector<CryptoPP::byte> trpKey(16);
encrypt.SetKeyWithIV(trophyKey.data(), trophyKey.size(), trophyIv.data());
encrypt.ProcessData(trpKey.data(), NPcommID.data(), 16); encrypt.ProcessData(trpKey.data(), NPcommID.data(), 16);
// step 2: decrypt efsm. // step 2: decrypt efsm.
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decrypt; CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decrypt;
decrypt.SetKeyWithIV(trpKey.data(), trpKey.size(), efsmIv.data()); decrypt.SetKeyWithIV(trpKey.data(), trpKey.size(), efsmIv.data());

View File

@ -32,7 +32,8 @@ public:
void aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey, void aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
std::span<CryptoPP::byte> ciphertext, std::span<CryptoPP::byte> ciphertext,
std::span<CryptoPP::byte> decrypted); std::span<CryptoPP::byte> decrypted);
void decryptEFSM(std::span<CryptoPP::byte, 16>, std::span<CryptoPP::byte, 16> efsmIv, void decryptEFSM(std::span<CryptoPP::byte, 16> trophyKey,
std::span<CryptoPP::byte, 16> NPcommID, std::span<CryptoPP::byte, 16> efsmIv,
std::span<CryptoPP::byte> ciphertext, std::span<CryptoPP::byte> decrypted); std::span<CryptoPP::byte> ciphertext, std::span<CryptoPP::byte> decrypted);
void PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs, void PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
std::span<const CryptoPP::byte, 16> seed, std::span<const CryptoPP::byte, 16> seed,

View File

@ -66,7 +66,7 @@ void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
"GetColorSliceSize()", buffer.GetColorSliceSize(), "GetColorSliceSize()", buffer.GetColorSliceSize(),
"GetTilingMode()", buffer.GetTilingMode(), "GetTilingMode()", buffer.GetTilingMode(),
"IsTiled()", buffer.IsTiled(), "IsTiled()", buffer.IsTiled(),
"NumFormat()", buffer.NumFormat() "NumFormat()", buffer.GetNumberFmt()
); );
// clang-format on // clang-format on

View File

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/config.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/path_util.h" #include "common/path_util.h"
#include "trp.h" #include "trp.h"
@ -33,12 +34,29 @@ static void removePadding(std::vector<u8>& vec) {
} }
} }
static void hexToBytes(const char* hex, unsigned char* dst) {
for (size_t i = 0; hex[i] != 0; i++) {
const unsigned char value = (hex[i] < 0x3A) ? (hex[i] - 0x30) : (hex[i] - 0x37);
dst[i / 2] |= ((i % 2) == 0) ? (value << 4) : (value);
}
}
bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string titleId) { bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string titleId) {
std::filesystem::path gameSysDir = trophyPath / "sce_sys/trophy/"; std::filesystem::path gameSysDir = trophyPath / "sce_sys/trophy/";
if (!std::filesystem::exists(gameSysDir)) { if (!std::filesystem::exists(gameSysDir)) {
LOG_CRITICAL(Common_Filesystem, "Game sce_sys directory doesn't exist"); LOG_CRITICAL(Common_Filesystem, "Game sce_sys directory doesn't exist");
return false; return false;
} }
const auto user_key_str = Config::getTrophyKey();
if (user_key_str.size() != 32) {
LOG_CRITICAL(Common_Filesystem, "Trophy decryption key is not specified");
return false;
}
std::array<CryptoPP::byte, 16> user_key{};
hexToBytes(user_key_str.c_str(), user_key.data());
for (int index = 0; const auto& it : std::filesystem::directory_iterator(gameSysDir)) { for (int index = 0; const auto& it : std::filesystem::directory_iterator(gameSysDir)) {
if (it.is_regular_file()) { if (it.is_regular_file()) {
GetNPcommID(trophyPath, index); GetNPcommID(trophyPath, index);
@ -97,7 +115,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string tit
return false; return false;
} }
file.Read(ESFM); file.Read(ESFM);
crypto.decryptEFSM(np_comm_id, esfmIv, ESFM, XML); // decrypt crypto.decryptEFSM(user_key, np_comm_id, esfmIv, ESFM, XML); // decrypt
removePadding(XML); removePadding(XML);
std::string xml_name = entry.entry_name; std::string xml_name = entry.entry_name;
size_t pos = xml_name.find("ESFM"); size_t pos = xml_name.find("ESFM");

View File

@ -3,13 +3,13 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <shared_mutex> #include <stop_token>
#include <thread>
#include <magic_enum/magic_enum.hpp> #include <magic_enum/magic_enum.hpp>
#include "common/assert.h" #include "common/assert.h"
#include "common/config.h" #include "common/config.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/polyfill_thread.h"
#include "common/thread.h" #include "common/thread.h"
#include "core/libraries/audio/audioout.h" #include "core/libraries/audio/audioout.h"
#include "core/libraries/audio/audioout_backend.h" #include "core/libraries/audio/audioout_backend.h"
@ -18,7 +18,7 @@
namespace Libraries::AudioOut { namespace Libraries::AudioOut {
std::shared_mutex ports_mutex; std::mutex port_open_mutex{};
std::array<PortOut, SCE_AUDIO_OUT_NUM_PORTS> ports_out{}; std::array<PortOut, SCE_AUDIO_OUT_NUM_PORTS> ports_out{};
static std::unique_ptr<AudioOutBackend> audio; static std::unique_ptr<AudioOutBackend> audio;
@ -93,17 +93,20 @@ int PS4_SYSV_ABI sceAudioOutClose(s32 handle) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
} }
std::scoped_lock lock(ports_mutex); std::unique_lock open_lock{port_open_mutex};
auto& port = ports_out.at(handle - 1); auto& port = ports_out.at(handle - 1);
if (!port.impl) { {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; std::unique_lock lock{port.mutex};
if (!port.IsOpen()) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
}
std::free(port.output_buffer);
port.output_buffer = nullptr;
port.output_ready = false;
port.impl = nullptr;
} }
// Stop outside of port lock scope to prevent deadlocks.
port.output_thread.Stop(); port.output_thread.Stop();
std::free(port.output_buffer);
port.output_buffer = nullptr;
port.output_ready = false;
port.impl = nullptr;
return ORBIS_OK; return ORBIS_OK;
} }
@ -172,35 +175,34 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
} }
std::scoped_lock lock(ports_mutex); auto& port = ports_out.at(handle - 1);
const auto& port = ports_out.at(handle - 1); {
if (!port.impl) { std::unique_lock lock{port.mutex};
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; if (!port.IsOpen()) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
}
switch (port.type) {
case OrbisAudioOutPort::Main:
case OrbisAudioOutPort::Bgm:
case OrbisAudioOutPort::Voice:
state->output = 1;
state->channel = port.format_info.num_channels > 2 ? 2 : port.format_info.num_channels;
break;
case OrbisAudioOutPort::Personal:
case OrbisAudioOutPort::Padspk:
state->output = 4;
state->channel = 1;
break;
case OrbisAudioOutPort::Aux:
state->output = 0;
state->channel = 0;
break;
default:
UNREACHABLE();
}
state->rerouteCounter = 0;
state->volume = 127;
} }
state->rerouteCounter = 0;
state->volume = 127;
switch (port.type) {
case OrbisAudioOutPort::Main:
case OrbisAudioOutPort::Bgm:
case OrbisAudioOutPort::Voice:
state->output = 1;
state->channel = port.format_info.num_channels > 2 ? 2 : port.format_info.num_channels;
break;
case OrbisAudioOutPort::Personal:
case OrbisAudioOutPort::Padspk:
state->output = 4;
state->channel = 1;
break;
case OrbisAudioOutPort::Aux:
state->output = 0;
state->channel = 0;
break;
default:
UNREACHABLE();
}
return ORBIS_OK; return ORBIS_OK;
} }
@ -279,15 +281,16 @@ static void AudioOutputThread(PortOut* port, const std::stop_token& stop) {
while (true) { while (true) {
timer.Start(); timer.Start();
{ {
std::unique_lock lock{port->output_mutex}; std::unique_lock lock{port->mutex};
Common::CondvarWait(port->output_cv, lock, stop, [&] { return port->output_ready; }); if (port->output_cv.wait(lock, stop, [&] { return port->output_ready; })) {
if (stop.stop_requested()) { port->impl->Output(port->output_buffer);
break; port->output_ready = false;
} }
port->impl->Output(port->output_buffer);
port->output_ready = false;
} }
port->output_cv.notify_one(); port->output_cv.notify_one();
if (stop.stop_requested()) {
break;
}
timer.End(); timer.End();
} }
} }
@ -332,27 +335,30 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
return ORBIS_AUDIO_OUT_ERROR_INVALID_FORMAT; return ORBIS_AUDIO_OUT_ERROR_INVALID_FORMAT;
} }
std::scoped_lock lock{ports_mutex}; std::unique_lock open_lock{port_open_mutex};
const auto port = const auto port =
std::ranges::find_if(ports_out, [&](const PortOut& p) { return p.impl == nullptr; }); std::ranges::find_if(ports_out, [&](const PortOut& p) { return !p.IsOpen(); });
if (port == ports_out.end()) { if (port == ports_out.end()) {
LOG_ERROR(Lib_AudioOut, "Audio ports are full"); LOG_ERROR(Lib_AudioOut, "Audio ports are full");
return ORBIS_AUDIO_OUT_ERROR_PORT_FULL; return ORBIS_AUDIO_OUT_ERROR_PORT_FULL;
} }
port->type = port_type; {
port->format_info = GetFormatInfo(format); std::unique_lock port_lock(port->mutex);
port->sample_rate = sample_rate;
port->buffer_frames = length;
port->volume.fill(SCE_AUDIO_OUT_VOLUME_0DB);
port->impl = audio->Open(*port); port->type = port_type;
port->format_info = GetFormatInfo(format);
port->sample_rate = sample_rate;
port->buffer_frames = length;
port->volume.fill(SCE_AUDIO_OUT_VOLUME_0DB);
port->output_buffer = std::malloc(port->BufferSize()); port->impl = audio->Open(*port);
port->output_ready = false;
port->output_thread.Run(
[port](const std::stop_token& stop) { AudioOutputThread(&*port, stop); });
port->output_buffer = std::malloc(port->BufferSize());
port->output_ready = false;
port->output_thread.Run(
[port](const std::stop_token& stop) { AudioOutputThread(&*port, stop); });
}
return std::distance(ports_out.begin(), port) + 1; return std::distance(ports_out.begin(), port) + 1;
} }
@ -367,14 +373,13 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr) {
} }
auto& port = ports_out.at(handle - 1); auto& port = ports_out.at(handle - 1);
if (!port.impl) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
}
{ {
std::unique_lock lock{port.output_mutex}; std::unique_lock lock{port.mutex};
if (!port.IsOpen()) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
}
port.output_cv.wait(lock, [&] { return !port.output_ready; }); port.output_cv.wait(lock, [&] { return !port.output_ready; });
if (ptr != nullptr) { if (ptr != nullptr && port.IsOpen()) {
std::memcpy(port.output_buffer, ptr, port.BufferSize()); std::memcpy(port.output_buffer, ptr, port.BufferSize());
port.output_ready = true; port.output_ready = true;
} }
@ -488,19 +493,19 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
} }
std::scoped_lock lock(ports_mutex);
auto& port = ports_out.at(handle - 1); auto& port = ports_out.at(handle - 1);
if (!port.impl) { {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; std::unique_lock lock{port.mutex};
} if (!port.IsOpen()) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
for (int i = 0; i < port.format_info.num_channels; i++, flag >>= 1u) {
if (flag & 0x1u) {
port.volume[i] = vol[i];
} }
for (int i = 0; i < port.format_info.num_channels; i++, flag >>= 1u) {
if (flag & 0x1u) {
port.volume[i] = vol[i];
}
}
port.impl->SetVolume(port.volume);
} }
port.impl->SetVolume(port.volume);
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -3,7 +3,9 @@
#pragma once #pragma once
#include <condition_variable>
#include <memory> #include <memory>
#include <mutex>
#include "common/bit_field.h" #include "common/bit_field.h"
#include "core/libraries/kernel/threads.h" #include "core/libraries/kernel/threads.h"
@ -74,10 +76,10 @@ struct AudioFormatInfo {
}; };
struct PortOut { struct PortOut {
std::mutex mutex;
std::unique_ptr<PortBackend> impl{}; std::unique_ptr<PortBackend> impl{};
void* output_buffer; void* output_buffer;
std::mutex output_mutex;
std::condition_variable_any output_cv; std::condition_variable_any output_cv;
bool output_ready; bool output_ready;
Kernel::Thread output_thread{}; Kernel::Thread output_thread{};
@ -88,6 +90,10 @@ struct PortOut {
u32 buffer_frames; u32 buffer_frames;
std::array<s32, 8> volume; std::array<s32, 8> volume;
[[nodiscard]] bool IsOpen() const {
return impl != nullptr;
}
[[nodiscard]] u32 BufferSize() const { [[nodiscard]] u32 BufferSize() const {
return buffer_frames * format_info.FrameSize(); return buffer_frames * format_info.FrameSize();
} }

View File

@ -14,7 +14,7 @@ namespace Libraries::AudioOut {
class SDLPortBackend : public PortBackend { class SDLPortBackend : public PortBackend {
public: public:
explicit SDLPortBackend(const PortOut& port) explicit SDLPortBackend(const PortOut& port)
: frame_size(port.format_info.FrameSize()), buffer_size(port.BufferSize()) { : frame_size(port.format_info.FrameSize()), guest_buffer_size(port.BufferSize()) {
// We want the latency for delivering frames out to be as small as possible, // We want the latency for delivering frames out to be as small as possible,
// so set the sample frames hint to the number of frames per buffer. // so set the sample frames hint to the number of frames per buffer.
const auto samples_num_str = std::to_string(port.buffer_frames); const auto samples_num_str = std::to_string(port.buffer_frames);
@ -33,7 +33,7 @@ public:
LOG_ERROR(Lib_AudioOut, "Failed to create SDL audio stream: {}", SDL_GetError()); LOG_ERROR(Lib_AudioOut, "Failed to create SDL audio stream: {}", SDL_GetError());
return; return;
} }
queue_threshold = CalculateQueueThreshold(); CalculateQueueThreshold();
if (!SDL_SetAudioStreamInputChannelMap(stream, port.format_info.channel_layout.data(), if (!SDL_SetAudioStreamInputChannelMap(stream, port.format_info.channel_layout.data(),
port.format_info.num_channels)) { port.format_info.num_channels)) {
LOG_ERROR(Lib_AudioOut, "Failed to configure SDL audio stream channel map: {}", LOG_ERROR(Lib_AudioOut, "Failed to configure SDL audio stream channel map: {}",
@ -71,9 +71,9 @@ public:
queue_threshold); queue_threshold);
SDL_ClearAudioStream(stream); SDL_ClearAudioStream(stream);
// Recalculate the threshold in case this happened because of a device change. // Recalculate the threshold in case this happened because of a device change.
queue_threshold = CalculateQueueThreshold(); CalculateQueueThreshold();
} }
if (!SDL_PutAudioStreamData(stream, ptr, static_cast<int>(buffer_size))) { if (!SDL_PutAudioStreamData(stream, ptr, static_cast<int>(guest_buffer_size))) {
LOG_ERROR(Lib_AudioOut, "Failed to output to SDL audio stream: {}", SDL_GetError()); LOG_ERROR(Lib_AudioOut, "Failed to output to SDL audio stream: {}", SDL_GetError());
} }
} }
@ -91,7 +91,7 @@ public:
} }
private: private:
[[nodiscard]] u32 CalculateQueueThreshold() const { void CalculateQueueThreshold() {
SDL_AudioSpec discard; SDL_AudioSpec discard;
int sdl_buffer_frames; int sdl_buffer_frames;
if (!SDL_GetAudioDeviceFormat(SDL_GetAudioStreamDevice(stream), &discard, if (!SDL_GetAudioDeviceFormat(SDL_GetAudioStreamDevice(stream), &discard,
@ -100,13 +100,22 @@ private:
SDL_GetError()); SDL_GetError());
sdl_buffer_frames = 0; sdl_buffer_frames = 0;
} }
return std::max<u32>(buffer_size, sdl_buffer_frames * frame_size) * 4; const auto sdl_buffer_size = sdl_buffer_frames * frame_size;
const auto new_threshold = std::max(guest_buffer_size, sdl_buffer_size) * 4;
if (host_buffer_size != sdl_buffer_size || queue_threshold != new_threshold) {
host_buffer_size = sdl_buffer_size;
queue_threshold = new_threshold;
LOG_INFO(Lib_AudioOut,
"SDL audio buffers: guest = {} bytes, host = {} bytes, threshold = {} bytes",
guest_buffer_size, host_buffer_size, queue_threshold);
}
} }
u32 frame_size; u32 frame_size;
u32 buffer_size; u32 guest_buffer_size;
u32 queue_threshold; u32 host_buffer_size{};
SDL_AudioStream* stream; u32 queue_threshold{};
SDL_AudioStream* stream{};
}; };
std::unique_ptr<PortBackend> SDLAudioOut::Open(PortOut& port) { std::unique_ptr<PortBackend> SDLAudioOut::Open(PortOut& port) {

View File

@ -505,6 +505,41 @@ int PS4_SYSV_ABI posix_munmap(void* addr, size_t len) {
return result; return result;
} }
static constexpr int MAX_PRT_APERTURES = 3;
static constexpr VAddr PRT_AREA_START_ADDR = 0x1000000000;
static constexpr size_t PRT_AREA_SIZE = 0xec00000000;
static std::array<std::pair<VAddr, size_t>, MAX_PRT_APERTURES> PrtApertures{};
int PS4_SYSV_ABI sceKernelSetPrtAperture(int id, VAddr address, size_t size) {
if (id < 0 || id >= MAX_PRT_APERTURES) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
if (address < PRT_AREA_START_ADDR || address + size > PRT_AREA_START_ADDR + PRT_AREA_SIZE) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
if (address % 4096 != 0) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
LOG_WARNING(Kernel_Vmm,
"PRT aperture id = {}, address = {:#x}, size = {:#x} is set but not used", id,
address, size);
PrtApertures[id] = {address, size};
return ORBIS_OK;
}
int PS4_SYSV_ABI sceKernelGetPrtAperture(int id, VAddr* address, size_t* size) {
if (id < 0 || id >= MAX_PRT_APERTURES) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
std::tie(*address, *size) = PrtApertures[id];
return ORBIS_OK;
}
void RegisterMemory(Core::Loader::SymbolsResolver* sym) { void RegisterMemory(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, sceKernelAllocateDirectMemory); LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, sceKernelAllocateDirectMemory);
LIB_FUNCTION("B+vc2AO2Zrc", "libkernel", 1, "libkernel", 1, 1, LIB_FUNCTION("B+vc2AO2Zrc", "libkernel", 1, "libkernel", 1, 1,
@ -551,6 +586,10 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("BPE9s9vQQXo", "libScePosix", 1, "libkernel", 1, 1, posix_mmap); LIB_FUNCTION("BPE9s9vQQXo", "libScePosix", 1, "libkernel", 1, 1, posix_mmap);
LIB_FUNCTION("UqDGjXA5yUM", "libkernel", 1, "libkernel", 1, 1, posix_munmap); LIB_FUNCTION("UqDGjXA5yUM", "libkernel", 1, "libkernel", 1, 1, posix_munmap);
LIB_FUNCTION("UqDGjXA5yUM", "libScePosix", 1, "libkernel", 1, 1, posix_munmap); LIB_FUNCTION("UqDGjXA5yUM", "libScePosix", 1, "libkernel", 1, 1, posix_munmap);
// PRT memory management
LIB_FUNCTION("BohYr-F7-is", "libkernel", 1, "libkernel", 1, 1, sceKernelSetPrtAperture);
LIB_FUNCTION("L0v2Go5jOuM", "libkernel", 1, "libkernel", 1, 1, sceKernelGetPrtAperture);
} }
} // namespace Libraries::Kernel } // namespace Libraries::Kernel

View File

@ -55,6 +55,9 @@ public:
stop.request_stop(); stop.request_stop();
Join(); Join();
} }
thread = nullptr;
func = nullptr;
stop = std::stop_source{};
} }
static void* PS4_SYSV_ABI RunWrapper(void* arg) { static void* PS4_SYSV_ABI RunWrapper(void* arg) {

View File

@ -47,6 +47,8 @@
#include "core/libraries/videodec/videodec.h" #include "core/libraries/videodec/videodec.h"
#include "core/libraries/videodec/videodec2.h" #include "core/libraries/videodec/videodec2.h"
#include "core/libraries/videoout/video_out.h" #include "core/libraries/videoout/video_out.h"
#include "fiber/fiber.h"
#include "jpeg/jpegenc.h"
namespace Libraries { namespace Libraries {
@ -93,6 +95,8 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
Libraries::Videodec::RegisterlibSceVideodec(sym); Libraries::Videodec::RegisterlibSceVideodec(sym);
Libraries::RazorCpu::RegisterlibSceRazorCpu(sym); Libraries::RazorCpu::RegisterlibSceRazorCpu(sym);
Libraries::Move::RegisterlibSceMove(sym); Libraries::Move::RegisterlibSceMove(sym);
Libraries::Fiber::RegisterlibSceFiber(sym);
Libraries::JpegEnc::RegisterlibSceJpegEnc(sym);
} }
} // namespace Libraries } // namespace Libraries

View File

@ -972,11 +972,8 @@ int PS4_SYSV_ABI sceNpGetGamePresenceStatusA() {
} }
int PS4_SYSV_ABI sceNpGetNpId(OrbisUserServiceUserId user_id, OrbisNpId* np_id) { int PS4_SYSV_ABI sceNpGetNpId(OrbisUserServiceUserId user_id, OrbisNpId* np_id) {
LOG_INFO(Lib_NpManager, "user_id {}", user_id); LOG_DEBUG(Lib_NpManager, "user_id {}", user_id);
const auto name = Config::getUserName(); return ORBIS_NP_ERROR_SIGNED_OUT;
std::memset(np_id, 0, sizeof(OrbisNpId));
name.copy(np_id->handle.data, sizeof(np_id->handle.data));
return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNpGetNpReachabilityState() { int PS4_SYSV_ABI sceNpGetNpReachabilityState() {
@ -986,10 +983,7 @@ int PS4_SYSV_ABI sceNpGetNpReachabilityState() {
int PS4_SYSV_ABI sceNpGetOnlineId(s32 user_id, OrbisNpOnlineId* online_id) { int PS4_SYSV_ABI sceNpGetOnlineId(s32 user_id, OrbisNpOnlineId* online_id) {
LOG_DEBUG(Lib_NpManager, "user_id {}", user_id); LOG_DEBUG(Lib_NpManager, "user_id {}", user_id);
const auto name = Config::getUserName(); return ORBIS_NP_ERROR_SIGNED_OUT;
std::memset(online_id, 0, sizeof(OrbisNpOnlineId));
name.copy(online_id->data, sizeof(online_id->data));
return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNpGetParentalControlInfo() { int PS4_SYSV_ABI sceNpGetParentalControlInfo() {

View File

@ -286,6 +286,7 @@ int PS4_SYSV_ABI scePadOutputReport() {
} }
int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) { int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
LOG_TRACE(Lib_Pad, "called");
int connected_count = 0; int connected_count = 0;
bool connected = false; bool connected = false;
Input::State states[64]; Input::State states[64];
@ -304,16 +305,15 @@ int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
pData[i].rightStick.y = states[i].axes[static_cast<int>(Input::Axis::RightY)]; pData[i].rightStick.y = states[i].axes[static_cast<int>(Input::Axis::RightY)];
pData[i].analogButtons.l2 = states[i].axes[static_cast<int>(Input::Axis::TriggerLeft)]; pData[i].analogButtons.l2 = states[i].axes[static_cast<int>(Input::Axis::TriggerLeft)];
pData[i].analogButtons.r2 = states[i].axes[static_cast<int>(Input::Axis::TriggerRight)]; pData[i].analogButtons.r2 = states[i].axes[static_cast<int>(Input::Axis::TriggerRight)];
pData[i].orientation.x = 0.0f; pData[i].acceleration.x = states[i].acceleration.x;
pData[i].orientation.y = 0.0f; pData[i].acceleration.y = states[i].acceleration.y;
pData[i].orientation.z = 0.0f; pData[i].acceleration.z = states[i].acceleration.z;
pData[i].orientation.w = 1.0f; pData[i].angularVelocity.x = states[i].angularVelocity.x;
pData[i].acceleration.x = 0.0f; pData[i].angularVelocity.y = states[i].angularVelocity.y;
pData[i].acceleration.y = 0.0f; pData[i].angularVelocity.z = states[i].angularVelocity.z;
pData[i].acceleration.z = 0.0f; Input::GameController::CalculateOrientation(pData[i].acceleration, pData[i].angularVelocity,
pData[i].angularVelocity.x = 0.0f; 1.0f / controller->accel_poll_rate,
pData[i].angularVelocity.y = 0.0f; pData[i].orientation);
pData[i].angularVelocity.z = 0.0f;
pData[i].touchData.touchNum = pData[i].touchData.touchNum =
(states[i].touchpad[0].state ? 1 : 0) + (states[i].touchpad[1].state ? 1 : 0); (states[i].touchpad[0].state ? 1 : 0) + (states[i].touchpad[1].state ? 1 : 0);
pData[i].touchData.touch[0].x = states[i].touchpad[0].x; pData[i].touchData.touch[0].x = states[i].touchpad[0].x;
@ -352,6 +352,7 @@ int PS4_SYSV_ABI scePadReadHistory() {
} }
int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) { int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
LOG_TRACE(Lib_Pad, "called");
if (handle == ORBIS_PAD_ERROR_DEVICE_NO_HANDLE) { if (handle == ORBIS_PAD_ERROR_DEVICE_NO_HANDLE) {
return ORBIS_PAD_ERROR_INVALID_HANDLE; return ORBIS_PAD_ERROR_INVALID_HANDLE;
} }
@ -367,16 +368,15 @@ int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
pData->rightStick.y = state.axes[static_cast<int>(Input::Axis::RightY)]; pData->rightStick.y = state.axes[static_cast<int>(Input::Axis::RightY)];
pData->analogButtons.l2 = state.axes[static_cast<int>(Input::Axis::TriggerLeft)]; pData->analogButtons.l2 = state.axes[static_cast<int>(Input::Axis::TriggerLeft)];
pData->analogButtons.r2 = state.axes[static_cast<int>(Input::Axis::TriggerRight)]; pData->analogButtons.r2 = state.axes[static_cast<int>(Input::Axis::TriggerRight)];
pData->orientation.x = 0; pData->acceleration.x = state.acceleration.x;
pData->orientation.y = 0; pData->acceleration.y = state.acceleration.y;
pData->orientation.z = 0; pData->acceleration.z = state.acceleration.z;
pData->orientation.w = 1; pData->angularVelocity.x = state.angularVelocity.x;
pData->acceleration.x = 0.0f; pData->angularVelocity.y = state.angularVelocity.y;
pData->acceleration.y = 0.0f; pData->angularVelocity.z = state.angularVelocity.z;
pData->acceleration.z = 0.0f; Input::GameController::CalculateOrientation(pData->acceleration, pData->angularVelocity,
pData->angularVelocity.x = 0.0f; 1.0f / controller->accel_poll_rate,
pData->angularVelocity.y = 0.0f; pData->orientation);
pData->angularVelocity.z = 0.0f;
pData->touchData.touchNum = pData->touchData.touchNum =
(state.touchpad[0].state ? 1 : 0) + (state.touchpad[1].state ? 1 : 0); (state.touchpad[0].state ? 1 : 0) + (state.touchpad[1].state ? 1 : 0);
pData->touchData.touch[0].x = state.touchpad[0].x; pData->touchData.touch[0].x = state.touchpad[0].x;
@ -498,6 +498,8 @@ int PS4_SYSV_ABI scePadSetLoginUserNumber() {
int PS4_SYSV_ABI scePadSetMotionSensorState(s32 handle, bool bEnable) { int PS4_SYSV_ABI scePadSetMotionSensorState(s32 handle, bool bEnable) {
LOG_ERROR(Lib_Pad, "(STUBBED) called"); LOG_ERROR(Lib_Pad, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
// it's already handled by the SDL backend and will be on no matter what
// (assuming the controller supports it)
} }
int PS4_SYSV_ABI scePadSetProcessFocus() { int PS4_SYSV_ABI scePadSetProcessFocus() {

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <span> #include <span>
#include <thread>
#include <vector> #include <vector>
#include <core/libraries/system/msgdialog_ui.h> #include <core/libraries/system/msgdialog_ui.h>
@ -1139,10 +1140,6 @@ Error PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2(OrbisSaveDataMemoryGet2* getPar
LOG_INFO(Lib_SaveData, "called without save memory initialized"); LOG_INFO(Lib_SaveData, "called without save memory initialized");
return Error::MEMORY_NOT_READY; return Error::MEMORY_NOT_READY;
} }
if (SaveMemory::IsSaving()) {
LOG_TRACE(Lib_SaveData, "called while saving");
return Error::BUSY_FOR_SAVING;
}
LOG_DEBUG(Lib_SaveData, "called"); LOG_DEBUG(Lib_SaveData, "called");
auto data = getParam->data; auto data = getParam->data;
if (data != nullptr) { if (data != nullptr) {
@ -1502,8 +1499,14 @@ Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2*
return Error::MEMORY_NOT_READY; return Error::MEMORY_NOT_READY;
} }
if (SaveMemory::IsSaving()) { if (SaveMemory::IsSaving()) {
LOG_TRACE(Lib_SaveData, "called while saving"); int count = 0;
return Error::BUSY_FOR_SAVING; while (++count < 100 && SaveMemory::IsSaving()) { // try for more 10 seconds
std::this_thread::sleep_for(chrono::milliseconds(100));
}
if (SaveMemory::IsSaving()) {
LOG_TRACE(Lib_SaveData, "called while saving");
return Error::BUSY_FOR_SAVING;
}
} }
LOG_DEBUG(Lib_SaveData, "called"); LOG_DEBUG(Lib_SaveData, "called");
auto data = setParam->data; auto data = setParam->data;
@ -1584,8 +1587,8 @@ Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetu
} else { } else {
SaveMemory::SetIcon(nullptr, 0); SaveMemory::SetIcon(nullptr, 0);
} }
SaveMemory::TriggerSaveWithoutEvent();
} }
SaveMemory::TriggerSaveWithoutEvent();
if (g_fw_ver >= ElfInfo::FW_45 && result != nullptr) { if (g_fw_ver >= ElfInfo::FW_45 && result != nullptr) {
result->existedMemorySize = existed_size; result->existedMemorySize = existed_size;
} }

View File

@ -10,327 +10,327 @@
namespace Libraries::Usbd { namespace Libraries::Usbd {
int PS4_SYSV_ABI sceUsbdAllocTransfer() { int PS4_SYSV_ABI sceUsbdAllocTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdAttachKernelDriver() { int PS4_SYSV_ABI sceUsbdAttachKernelDriver() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdBulkTransfer() { int PS4_SYSV_ABI sceUsbdBulkTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdCancelTransfer() { int PS4_SYSV_ABI sceUsbdCancelTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdCheckConnected() { int PS4_SYSV_ABI sceUsbdCheckConnected() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdClaimInterface() { int PS4_SYSV_ABI sceUsbdClaimInterface() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdClearHalt() { int PS4_SYSV_ABI sceUsbdClearHalt() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdClose() { int PS4_SYSV_ABI sceUsbdClose() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdControlTransfer() { int PS4_SYSV_ABI sceUsbdControlTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdControlTransferGetData() { int PS4_SYSV_ABI sceUsbdControlTransferGetData() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdControlTransferGetSetup() { int PS4_SYSV_ABI sceUsbdControlTransferGetSetup() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdDetachKernelDriver() { int PS4_SYSV_ABI sceUsbdDetachKernelDriver() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdEventHandlerActive() { int PS4_SYSV_ABI sceUsbdEventHandlerActive() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdEventHandlingOk() { int PS4_SYSV_ABI sceUsbdEventHandlingOk() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdExit() { int PS4_SYSV_ABI sceUsbdExit() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdFillBulkTransfer() { int PS4_SYSV_ABI sceUsbdFillBulkTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdFillControlSetup() { int PS4_SYSV_ABI sceUsbdFillControlSetup() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdFillControlTransfer() { int PS4_SYSV_ABI sceUsbdFillControlTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdFillInterruptTransfer() { int PS4_SYSV_ABI sceUsbdFillInterruptTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdFillIsoTransfer() { int PS4_SYSV_ABI sceUsbdFillIsoTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdFreeConfigDescriptor() { int PS4_SYSV_ABI sceUsbdFreeConfigDescriptor() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdFreeDeviceList() { int PS4_SYSV_ABI sceUsbdFreeDeviceList() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdFreeTransfer() { int PS4_SYSV_ABI sceUsbdFreeTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetActiveConfigDescriptor() { int PS4_SYSV_ABI sceUsbdGetActiveConfigDescriptor() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetBusNumber() { int PS4_SYSV_ABI sceUsbdGetBusNumber() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetConfigDescriptor() { int PS4_SYSV_ABI sceUsbdGetConfigDescriptor() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetConfigDescriptorByValue() { int PS4_SYSV_ABI sceUsbdGetConfigDescriptorByValue() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetConfiguration() { int PS4_SYSV_ABI sceUsbdGetConfiguration() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetDescriptor() { int PS4_SYSV_ABI sceUsbdGetDescriptor() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetDevice() { int PS4_SYSV_ABI sceUsbdGetDevice() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetDeviceAddress() { int PS4_SYSV_ABI sceUsbdGetDeviceAddress() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetDeviceDescriptor() { int PS4_SYSV_ABI sceUsbdGetDeviceDescriptor() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetDeviceList() { int PS4_SYSV_ABI sceUsbdGetDeviceList() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetDeviceSpeed() { int PS4_SYSV_ABI sceUsbdGetDeviceSpeed() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetIsoPacketBuffer() { int PS4_SYSV_ABI sceUsbdGetIsoPacketBuffer() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetMaxIsoPacketSize() { int PS4_SYSV_ABI sceUsbdGetMaxIsoPacketSize() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetMaxPacketSize() { int PS4_SYSV_ABI sceUsbdGetMaxPacketSize() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetStringDescriptor() { int PS4_SYSV_ABI sceUsbdGetStringDescriptor() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdGetStringDescriptorAscii() { int PS4_SYSV_ABI sceUsbdGetStringDescriptorAscii() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdHandleEvents() { int PS4_SYSV_ABI sceUsbdHandleEvents() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdHandleEventsLocked() { int PS4_SYSV_ABI sceUsbdHandleEventsLocked() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdHandleEventsTimeout() { int PS4_SYSV_ABI sceUsbdHandleEventsTimeout() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_DEBUG(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdInit() { int PS4_SYSV_ABI sceUsbdInit() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return 0x80240005; // Skip return 0x80240005; // Skip
} }
int PS4_SYSV_ABI sceUsbdInterruptTransfer() { int PS4_SYSV_ABI sceUsbdInterruptTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdKernelDriverActive() { int PS4_SYSV_ABI sceUsbdKernelDriverActive() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdLockEvents() { int PS4_SYSV_ABI sceUsbdLockEvents() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdLockEventWaiters() { int PS4_SYSV_ABI sceUsbdLockEventWaiters() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdOpen() { int PS4_SYSV_ABI sceUsbdOpen() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdOpenDeviceWithVidPid() { int PS4_SYSV_ABI sceUsbdOpenDeviceWithVidPid() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdRefDevice() { int PS4_SYSV_ABI sceUsbdRefDevice() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdReleaseInterface() { int PS4_SYSV_ABI sceUsbdReleaseInterface() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdResetDevice() { int PS4_SYSV_ABI sceUsbdResetDevice() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdSetConfiguration() { int PS4_SYSV_ABI sceUsbdSetConfiguration() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdSetInterfaceAltSetting() { int PS4_SYSV_ABI sceUsbdSetInterfaceAltSetting() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdSetIsoPacketLengths() { int PS4_SYSV_ABI sceUsbdSetIsoPacketLengths() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdSubmitTransfer() { int PS4_SYSV_ABI sceUsbdSubmitTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdTryLockEvents() { int PS4_SYSV_ABI sceUsbdTryLockEvents() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdUnlockEvents() { int PS4_SYSV_ABI sceUsbdUnlockEvents() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdUnlockEventWaiters() { int PS4_SYSV_ABI sceUsbdUnlockEventWaiters() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdUnrefDevice() { int PS4_SYSV_ABI sceUsbdUnrefDevice() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceUsbdWaitForEvent() { int PS4_SYSV_ABI sceUsbdWaitForEvent() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI Func_65F6EF33E38FFF50() { int PS4_SYSV_ABI Func_65F6EF33E38FFF50() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI Func_97F056BAD90AADE7() { int PS4_SYSV_ABI Func_97F056BAD90AADE7() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI Func_C55104A33B35B264() { int PS4_SYSV_ABI Func_C55104A33B35B264() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI Func_D56B43060720B1E0() { int PS4_SYSV_ABI Func_D56B43060720B1E0() {
LOG_ERROR(Lib_Usbd, "(STUBBED)called"); LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -52,8 +52,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle,
Kernel::EqueueEvent event{}; Kernel::EqueueEvent event{};
event.event.ident = u64(OrbisVideoOutEventId::Flip); event.event.ident = u64(OrbisVideoOutEventId::Flip);
event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut; event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut;
// The library only sets EV_ADD but kernel driver forces EV_CLEAR event.event.flags = Kernel::SceKernelEvent::Flags::Add;
event.event.flags = Kernel::SceKernelEvent::Flags::Clear;
event.event.udata = udata; event.event.udata = udata;
event.event.fflags = 0; event.event.fflags = 0;
event.event.data = 0; event.event.data = 0;
@ -79,8 +78,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handl
Kernel::EqueueEvent event{}; Kernel::EqueueEvent event{};
event.event.ident = u64(OrbisVideoOutEventId::Vblank); event.event.ident = u64(OrbisVideoOutEventId::Vblank);
event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut; event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut;
// The library only sets EV_ADD but kernel driver forces EV_CLEAR event.event.flags = Kernel::SceKernelEvent::Flags::Add;
event.event.flags = Kernel::SceKernelEvent::Flags::Clear;
event.event.udata = udata; event.event.udata = udata;
event.event.fflags = 0; event.event.fflags = 0;
event.event.data = 0; event.event.data = 0;

View File

@ -282,16 +282,14 @@ void Emulator::Run(const std::filesystem::path& file) {
} }
void Emulator::LoadSystemModules(const std::filesystem::path& file, std::string game_serial) { void Emulator::LoadSystemModules(const std::filesystem::path& file, std::string game_serial) {
constexpr std::array<SysModules, 13> ModulesToLoad{ constexpr std::array<SysModules, 11> ModulesToLoad{
{{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2}, {{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2},
{"libSceFiber.sprx", &Libraries::Fiber::RegisterlibSceFiber},
{"libSceUlt.sprx", nullptr}, {"libSceUlt.sprx", nullptr},
{"libSceJson.sprx", nullptr}, {"libSceJson.sprx", nullptr},
{"libSceJson2.sprx", nullptr}, {"libSceJson2.sprx", nullptr},
{"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterlibSceLibcInternal}, {"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterlibSceLibcInternal},
{"libSceDiscMap.sprx", &Libraries::DiscMap::RegisterlibSceDiscMap}, {"libSceDiscMap.sprx", &Libraries::DiscMap::RegisterlibSceDiscMap},
{"libSceRtc.sprx", &Libraries::Rtc::RegisterlibSceRtc}, {"libSceRtc.sprx", &Libraries::Rtc::RegisterlibSceRtc},
{"libSceJpegEnc.sprx", &Libraries::JpegEnc::RegisterlibSceJpegEnc},
{"libSceCesCs.sprx", nullptr}, {"libSceCesCs.sprx", nullptr},
{"libSceFont.sprx", nullptr}, {"libSceFont.sprx", nullptr},
{"libSceFontFt.sprx", nullptr}, {"libSceFontFt.sprx", nullptr},

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include "common/logging/log.h"
#include "core/libraries/kernel/time.h" #include "core/libraries/kernel/time.h"
#include "core/libraries/pad/pad.h" #include "core/libraries/pad/pad.h"
#include "input/controller.h" #include "input/controller.h"
@ -116,6 +117,103 @@ void GameController::Axis(int id, Input::Axis axis, int value) {
AddState(state); AddState(state);
} }
void GameController::Gyro(int id, const float gyro[3]) {
std::scoped_lock lock{m_mutex};
auto state = GetLastState();
state.time = Libraries::Kernel::sceKernelGetProcessTime();
// Update the angular velocity (gyro data)
state.angularVelocity.x = gyro[0]; // X-axis
state.angularVelocity.y = gyro[1]; // Y-axis
state.angularVelocity.z = gyro[2]; // Z-axis
AddState(state);
}
void GameController::Acceleration(int id, const float acceleration[3]) {
std::scoped_lock lock{m_mutex};
auto state = GetLastState();
state.time = Libraries::Kernel::sceKernelGetProcessTime();
// Update the acceleration values
state.acceleration.x = acceleration[0]; // X-axis
state.acceleration.y = acceleration[1]; // Y-axis
state.acceleration.z = acceleration[2]; // Z-axis
AddState(state);
}
// Stolen from
// https://github.com/xioTechnologies/Open-Source-AHRS-With-x-IMU/blob/master/x-IMU%20IMU%20and%20AHRS%20Algorithms/x-IMU%20IMU%20and%20AHRS%20Algorithms/AHRS/MahonyAHRS.cs
float eInt[3] = {0.0f, 0.0f, 0.0f}; // Integral error terms
const float Kp = 50.0f; // Proportional gain
const float Ki = 1.0f; // Integral gain
Libraries::Pad::OrbisFQuaternion o = {1, 0, 0, 0};
void GameController::CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
Libraries::Pad::OrbisFVector3& angularVelocity,
float deltaTime,
Libraries::Pad::OrbisFQuaternion& orientation) {
float ax = acceleration.x, ay = acceleration.y, az = acceleration.z;
float gx = angularVelocity.x, gy = angularVelocity.y, gz = angularVelocity.z;
float q1 = o.w, q2 = o.x, q3 = o.y, q4 = o.z;
// Normalize accelerometer measurement
float norm = std::sqrt(ax * ax + ay * ay + az * az);
if (norm == 0.0f)
return; // Handle NaN
norm = 1.0f / norm;
ax *= norm;
ay *= norm;
az *= norm;
// Estimated direction of gravity
float vx = 2.0f * (q2 * q4 - q1 * q3);
float vy = 2.0f * (q1 * q2 + q3 * q4);
float vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
// Error is cross product between estimated direction and measured direction of gravity
float ex = (ay * vz - az * vy);
float ey = (az * vx - ax * vz);
float ez = (ax * vy - ay * vx);
if (Ki > 0.0f) {
eInt[0] += ex * deltaTime; // Accumulate integral error
eInt[1] += ey * deltaTime;
eInt[2] += ez * deltaTime;
} else {
eInt[0] = eInt[1] = eInt[2] = 0.0f; // Prevent integral wind-up
}
// Apply feedback terms
gx += Kp * ex + Ki * eInt[0];
gy += Kp * ey + Ki * eInt[1];
gz += Kp * ez + Ki * eInt[2];
//// Integrate rate of change of quaternion
// float pa = q2, pb = q3, pc = q4;
// q1 += (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * deltaTime);
// q2 += (pa * gx + pb * gz - pc * gy) * (0.5f * deltaTime);
// q3 += (pb * gy - pa * gz + pc * gx) * (0.5f * deltaTime);
// q4 += (pc * gz + pa * gy - pb * gx) * (0.5f * deltaTime);
q1 += (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * deltaTime);
q2 += (q1 * gx + q3 * gz - q4 * gy) * (0.5f * deltaTime);
q3 += (q1 * gy - q2 * gz + q4 * gx) * (0.5f * deltaTime);
q4 += (q1 * gz + q2 * gy - q3 * gx) * (0.5f * deltaTime);
// Normalize quaternion
norm = std::sqrt(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4);
norm = 1.0f / norm;
orientation.w = q1 * norm;
orientation.x = q2 * norm;
orientation.y = q3 * norm;
orientation.z = q4 * norm;
o.w = q1 * norm;
o.x = q2 * norm;
o.y = q3 * norm;
o.z = q4 * norm;
LOG_DEBUG(Lib_Pad, "Calculated orientation: {:.2f} {:.2f} {:.2f} {:.2f}", orientation.x,
orientation.y, orientation.z, orientation.w);
}
void GameController::SetLightBarRGB(u8 r, u8 g, u8 b) { void GameController::SetLightBarRGB(u8 r, u8 g, u8 b) {
if (m_sdl_gamepad != nullptr) { if (m_sdl_gamepad != nullptr) {
SDL_SetGamepadLED(m_sdl_gamepad, r, g, b); SDL_SetGamepadLED(m_sdl_gamepad, r, g, b);
@ -149,6 +247,18 @@ void GameController::TryOpenSDLController() {
int gamepad_count; int gamepad_count;
SDL_JoystickID* gamepads = SDL_GetGamepads(&gamepad_count); SDL_JoystickID* gamepads = SDL_GetGamepads(&gamepad_count);
m_sdl_gamepad = gamepad_count > 0 ? SDL_OpenGamepad(gamepads[0]) : nullptr; m_sdl_gamepad = gamepad_count > 0 ? SDL_OpenGamepad(gamepads[0]) : nullptr;
if (SDL_SetGamepadSensorEnabled(m_sdl_gamepad, SDL_SENSOR_GYRO, true)) {
gyro_poll_rate = SDL_GetGamepadSensorDataRate(m_sdl_gamepad, SDL_SENSOR_GYRO);
LOG_INFO(Input, "Gyro initialized, poll rate: {}", gyro_poll_rate);
} else {
LOG_ERROR(Input, "Failed to initialize gyro controls for gamepad");
}
if (SDL_SetGamepadSensorEnabled(m_sdl_gamepad, SDL_SENSOR_ACCEL, true)) {
accel_poll_rate = SDL_GetGamepadSensorDataRate(m_sdl_gamepad, SDL_SENSOR_ACCEL);
LOG_INFO(Input, "Accel initialized, poll rate: {}", accel_poll_rate);
} else {
LOG_ERROR(Input, "Failed to initialize accel controls for gamepad");
}
SDL_free(gamepads); SDL_free(gamepads);
SetLightBarRGB(0, 0, 255); SetLightBarRGB(0, 0, 255);

View File

@ -33,6 +33,9 @@ struct State {
u64 time = 0; u64 time = 0;
int axes[static_cast<int>(Axis::AxisMax)] = {128, 128, 128, 128, 0, 0}; int axes[static_cast<int>(Axis::AxisMax)] = {128, 128, 128, 128, 0, 0};
TouchpadEntry touchpad[2] = {{false, 0, 0}, {false, 0, 0}}; TouchpadEntry touchpad[2] = {{false, 0, 0}, {false, 0, 0}};
Libraries::Pad::OrbisFVector3 acceleration = {0.0f, 0.0f, 0.0f};
Libraries::Pad::OrbisFVector3 angularVelocity = {0.0f, 0.0f, 0.0f};
Libraries::Pad::OrbisFQuaternion orientation = {0.0f, 0.0f, 0.0f, 1.0f};
}; };
inline int GetAxis(int min, int max, int value) { inline int GetAxis(int min, int max, int value) {
@ -53,12 +56,21 @@ public:
void CheckButton(int id, Libraries::Pad::OrbisPadButtonDataOffset button, bool isPressed); void CheckButton(int id, Libraries::Pad::OrbisPadButtonDataOffset button, bool isPressed);
void AddState(const State& state); void AddState(const State& state);
void Axis(int id, Input::Axis axis, int value); void Axis(int id, Input::Axis axis, int value);
void Gyro(int id, const float gyro[3]);
void Acceleration(int id, const float acceleration[3]);
void SetLightBarRGB(u8 r, u8 g, u8 b); void SetLightBarRGB(u8 r, u8 g, u8 b);
bool SetVibration(u8 smallMotor, u8 largeMotor); bool SetVibration(u8 smallMotor, u8 largeMotor);
void SetTouchpadState(int touchIndex, bool touchDown, float x, float y); void SetTouchpadState(int touchIndex, bool touchDown, float x, float y);
void TryOpenSDLController(); void TryOpenSDLController();
u32 Poll(); u32 Poll();
float gyro_poll_rate;
float accel_poll_rate;
static void CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
Libraries::Pad::OrbisFVector3& angularVelocity,
float deltaTime,
Libraries::Pad::OrbisFQuaternion& orientation);
private: private:
struct StateInternal { struct StateInternal {
bool obtained = false; bool obtained = false;

View File

@ -14,6 +14,7 @@
#include <QNetworkReply> #include <QNetworkReply>
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QProcess> #include <QProcess>
#include <QProgressBar>
#include <QPushButton> #include <QPushButton>
#include <QStandardPaths> #include <QStandardPaths>
#include <QString> #include <QString>
@ -24,11 +25,9 @@
#include <common/path_util.h> #include <common/path_util.h>
#include <common/scm_rev.h> #include <common/scm_rev.h>
#include <common/version.h> #include <common/version.h>
#include <qprogressbar.h>
#include "check_update.h" #include "check_update.h"
using namespace Common::FS; using namespace Common::FS;
namespace fs = std::filesystem;
CheckUpdate::CheckUpdate(const bool showMessage, QWidget* parent) CheckUpdate::CheckUpdate(const bool showMessage, QWidget* parent)
: QDialog(parent), networkManager(new QNetworkAccessManager(this)) { : QDialog(parent), networkManager(new QNetworkAccessManager(this)) {
@ -254,7 +253,11 @@ void CheckUpdate::setupUI(const QString& downloadUrl, const QString& latestDate,
connect(noButton, &QPushButton::clicked, this, [this]() { close(); }); connect(noButton, &QPushButton::clicked, this, [this]() { close(); });
autoUpdateCheckBox->setChecked(Config::autoUpdate()); autoUpdateCheckBox->setChecked(Config::autoUpdate());
#if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0))
connect(autoUpdateCheckBox, &QCheckBox::stateChanged, this, [](int state) { connect(autoUpdateCheckBox, &QCheckBox::stateChanged, this, [](int state) {
#else
connect(autoUpdateCheckBox, &QCheckBox::checkStateChanged, this, [](Qt::CheckState state) {
#endif
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
Config::setAutoUpdate(state == Qt::Checked); Config::setAutoUpdate(state == Qt::Checked);
Config::save(user_dir / "config.toml"); Config::save(user_dir / "config.toml");

View File

@ -3,22 +3,24 @@
#include <QCompleter> #include <QCompleter>
#include <QDirIterator> #include <QDirIterator>
#include <QFileDialog>
#include <QHoverEvent> #include <QHoverEvent>
#include <fmt/format.h>
#include <common/version.h>
#include "common/config.h" #include "common/config.h"
#include "common/version.h"
#include "qt_gui/compatibility_info.h" #include "qt_gui/compatibility_info.h"
#ifdef ENABLE_DISCORD_RPC #ifdef ENABLE_DISCORD_RPC
#include "common/discord_rpc_handler.h" #include "common/discord_rpc_handler.h"
#include "common/singleton.h"
#endif #endif
#ifdef ENABLE_UPDATER #ifdef ENABLE_UPDATER
#include "check_update.h" #include "check_update.h"
#endif #endif
#include <toml.hpp> #include <toml.hpp>
#include "background_music_player.h"
#include "common/logging/backend.h" #include "common/logging/backend.h"
#include "common/logging/filter.h" #include "common/logging/filter.h"
#include "common/logging/formatter.h"
#include "main_window.h"
#include "settings_dialog.h" #include "settings_dialog.h"
#include "ui_settings_dialog.h" #include "ui_settings_dialog.h"
QStringList languageNames = {"Arabic", QStringList languageNames = {"Arabic",
@ -130,8 +132,13 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
// GENERAL TAB // GENERAL TAB
{ {
#ifdef ENABLE_UPDATER #ifdef ENABLE_UPDATER
#if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0))
connect(ui->updateCheckBox, &QCheckBox::stateChanged, this, connect(ui->updateCheckBox, &QCheckBox::stateChanged, this,
[](int state) { Config::setAutoUpdate(state == Qt::Checked); }); [](int state) { Config::setAutoUpdate(state == Qt::Checked); });
#else
connect(ui->updateCheckBox, &QCheckBox::checkStateChanged, this,
[](Qt::CheckState state) { Config::setAutoUpdate(state == Qt::Checked); });
#endif
connect(ui->updateComboBox, &QComboBox::currentTextChanged, this, connect(ui->updateComboBox, &QComboBox::currentTextChanged, this,
[](const QString& channel) { Config::setUpdateChannel(channel.toStdString()); }); [](const QString& channel) { Config::setUpdateChannel(channel.toStdString()); });
@ -150,7 +157,12 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
emit CompatibilityChanged(); emit CompatibilityChanged();
}); });
#if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0))
connect(ui->enableCompatibilityCheckBox, &QCheckBox::stateChanged, this, [this](int state) { connect(ui->enableCompatibilityCheckBox, &QCheckBox::stateChanged, this, [this](int state) {
#else
connect(ui->enableCompatibilityCheckBox, &QCheckBox::checkStateChanged, this,
[this](Qt::CheckState state) {
#endif
Config::setCompatibilityEnabled(state); Config::setCompatibilityEnabled(state);
emit CompatibilityChanged(); emit CompatibilityChanged();
}); });
@ -201,6 +213,8 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
ui->showSplashCheckBox->installEventFilter(this); ui->showSplashCheckBox->installEventFilter(this);
ui->discordRPCCheckbox->installEventFilter(this); ui->discordRPCCheckbox->installEventFilter(this);
ui->userName->installEventFilter(this); ui->userName->installEventFilter(this);
ui->label_Trophy->installEventFilter(this);
ui->trophyKeyLineEdit->installEventFilter(this);
ui->logTypeGroupBox->installEventFilter(this); ui->logTypeGroupBox->installEventFilter(this);
ui->logFilter->installEventFilter(this); ui->logFilter->installEventFilter(this);
#ifdef ENABLE_UPDATER #ifdef ENABLE_UPDATER
@ -295,6 +309,9 @@ void SettingsDialog::LoadValuesFromConfig() {
QString::fromStdString(toml::find_or<std::string>(data, "General", "logFilter", ""))); QString::fromStdString(toml::find_or<std::string>(data, "General", "logFilter", "")));
ui->userNameLineEdit->setText( ui->userNameLineEdit->setText(
QString::fromStdString(toml::find_or<std::string>(data, "General", "userName", "shadPS4"))); QString::fromStdString(toml::find_or<std::string>(data, "General", "userName", "shadPS4")));
ui->trophyKeyLineEdit->setText(
QString::fromStdString(toml::find_or<std::string>(data, "Keys", "TrophyKey", "")));
ui->trophyKeyLineEdit->setEchoMode(QLineEdit::Password);
ui->debugDump->setChecked(toml::find_or<bool>(data, "Debug", "DebugDump", false)); ui->debugDump->setChecked(toml::find_or<bool>(data, "Debug", "DebugDump", false));
ui->vkValidationCheckBox->setChecked(toml::find_or<bool>(data, "Vulkan", "validation", false)); ui->vkValidationCheckBox->setChecked(toml::find_or<bool>(data, "Vulkan", "validation", false));
ui->vkSyncValidationCheckBox->setChecked( ui->vkSyncValidationCheckBox->setChecked(
@ -358,7 +375,7 @@ void SettingsDialog::InitializeEmulatorLanguages() {
idx++; idx++;
} }
connect(ui->emulatorLanguageComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this, connect(ui->emulatorLanguageComboBox, &QComboBox::currentIndexChanged, this,
&SettingsDialog::OnLanguageChanged); &SettingsDialog::OnLanguageChanged);
} }
@ -407,6 +424,10 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
text = tr("discordRPCCheckbox"); text = tr("discordRPCCheckbox");
} else if (elementName == "userName") { } else if (elementName == "userName") {
text = tr("userName"); text = tr("userName");
} else if (elementName == "label_Trophy") {
text = tr("TrophyKey");
} else if (elementName == "trophyKeyLineEdit") {
text = tr("TrophyKey");
} else if (elementName == "logTypeGroupBox") { } else if (elementName == "logTypeGroupBox") {
text = tr("logTypeGroupBox"); text = tr("logTypeGroupBox");
} else if (elementName == "logFilter") { } else if (elementName == "logFilter") {
@ -517,6 +538,7 @@ void SettingsDialog::UpdateSettings() {
Config::setLogType(ui->logTypeComboBox->currentText().toStdString()); Config::setLogType(ui->logTypeComboBox->currentText().toStdString());
Config::setLogFilter(ui->logFilterLineEdit->text().toStdString()); Config::setLogFilter(ui->logFilterLineEdit->text().toStdString());
Config::setUserName(ui->userNameLineEdit->text().toStdString()); Config::setUserName(ui->userNameLineEdit->text().toStdString());
Config::setTrophyKey(ui->trophyKeyLineEdit->text().toStdString());
Config::setCursorState(ui->hideCursorComboBox->currentIndex()); Config::setCursorState(ui->hideCursorComboBox->currentIndex());
Config::setCursorHideTimeout(ui->idleTimeoutSpinBox->value()); Config::setCursorHideTimeout(ui->idleTimeoutSpinBox->value());
Config::setGpuId(ui->graphicsAdapterBox->currentIndex() - 1); Config::setGpuId(ui->graphicsAdapterBox->currentIndex() - 1);
@ -578,4 +600,4 @@ void SettingsDialog::ResetInstallFolders() {
} }
Config::setGameInstallDirs(settings_install_dirs_config); Config::setGameInstallDirs(settings_install_dirs_config);
} }
} }

View File

@ -11,8 +11,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>950</width> <width>970</width>
<height>780</height> <height>670</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -67,8 +67,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>822</width> <width>946</width>
<height>487</height> <height>536</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="generalTabVLayout" stretch="0"> <layout class="QVBoxLayout" name="generalTabVLayout" stretch="0">
@ -77,87 +77,7 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item row="0" column="2"> <item row="1" column="0">
<layout class="QVBoxLayout" name="loggerTabLayoutRight">
<item>
<widget class="QGroupBox" name="loggerGroupBox">
<property name="title">
<string>Logger</string>
</property>
<layout class="QVBoxLayout" name="loggerLayout">
<item>
<widget class="QWidget" name="LogTypeWidget" native="true">
<layout class="QVBoxLayout" name="LogTypeLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="logTypeGroupBox">
<property name="title">
<string>Log Type</string>
</property>
<layout class="QVBoxLayout" name="logTypeBoxLayout">
<item>
<widget class="QComboBox" name="logTypeComboBox">
<item>
<property name="text">
<string>async</string>
</property>
</item>
<item>
<property name="text">
<string>sync</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="vLayoutLogFilter">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="hLayoutLogFilter">
<item>
<widget class="QGroupBox" name="logFilter">
<property name="title">
<string>Log Filter</string>
</property>
<layout class="QVBoxLayout" name="logFilterLayout">
<item>
<widget class="QLineEdit" name="logFilterLineEdit"/>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QVBoxLayout" name="systemTabLayoutLeft"> <layout class="QVBoxLayout" name="systemTabLayoutLeft">
<item> <item>
<widget class="QGroupBox" name="SystemSettings"> <widget class="QGroupBox" name="SystemSettings">
@ -194,7 +114,7 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="0" column="1"> <item row="0" column="0">
<layout class="QVBoxLayout" name="emulatorTabLayoutMiddle"> <layout class="QVBoxLayout" name="emulatorTabLayoutMiddle">
<item> <item>
<widget class="QGroupBox" name="emulatorSettingsGroupBox"> <widget class="QGroupBox" name="emulatorSettingsGroupBox">
@ -268,10 +188,10 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="1" column="0"> <item row="1" column="2">
<layout class="QVBoxLayout" name="updaterTabLayoutLeft"> <layout class="QVBoxLayout" name="updaterTabLayoutLeft">
<property name="spacing"> <property name="spacing">
<number>-1</number> <number>6</number>
</property> </property>
<property name="sizeConstraint"> <property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum> <enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
@ -436,138 +356,8 @@
</layout> </layout>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<layout class="QVBoxLayout" name="GUITabLayoutMiddle" stretch="0">
<item alignment="Qt::AlignmentFlag::AlignTop">
<widget class="QGroupBox" name="GUIgroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="title">
<string>GUI Settings</string>
</property>
<layout class="QVBoxLayout" name="GUILayout">
<property name="topMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>11</number>
</property>
<item>
<widget class="QCheckBox" name="disableTrophycheckBox">
<property name="text">
<string>Disable Trophy Pop-ups</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="playBGMCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Play title music</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="GUIMusicLayout">
<property name="topMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="GUIverticalSpacer_3">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>13</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Volume</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="BGMVolumeSlider">
<property name="toolTip">
<string>Set the volume of the background music.</string>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="singleStep">
<number>10</number>
</property>
<property name="pageStep">
<number>20</number>
</property>
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="invertedControls">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::TickPosition::NoTicks</enum>
</property>
<property name="tickInterval">
<number>10</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="1" column="2">
<layout class="QVBoxLayout" name="CompatTabLayoutRight" stretch="0"> <layout class="QVBoxLayout" name="CompatTabLayoutRight" stretch="0">
<item alignment="Qt::AlignmentFlag::AlignTop"> <item>
<widget class="QGroupBox" name="CompatgroupBox"> <widget class="QGroupBox" name="CompatgroupBox">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -638,6 +428,160 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="GUITabLayoutMiddle" stretch="0">
<item>
<widget class="QGroupBox" name="GUIgroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="title">
<string>GUI Settings</string>
</property>
<layout class="QVBoxLayout" name="GUILayout">
<property name="topMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>11</number>
</property>
<item>
<widget class="QCheckBox" name="playBGMCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Play title music</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="GUIMusicLayout">
<property name="topMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_Volume">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Volume</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="BGMVolumeSlider">
<property name="toolTip">
<string>Set the volume of the background music.</string>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="singleStep">
<number>10</number>
</property>
<property name="pageStep">
<number>20</number>
</property>
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="invertedControls">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::TickPosition::NoTicks</enum>
</property>
<property name="tickInterval">
<number>10</number>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="vLayoutTrophy">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="hLayoutTrophy">
<item>
<widget class="QGroupBox" name="trophyGroupBox">
<property name="title">
<string>Trophy</string>
</property>
<layout class="QVBoxLayout" name="userNameLayout">
<item>
<widget class="QCheckBox" name="disableTrophycheckBox">
<property name="text">
<string>Disable Trophy Pop-ups</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_Trophy">
<property name="text">
<string>Trophy Key</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="trophyKeyLineEdit">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>
@ -655,8 +599,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>396</width> <width>926</width>
<height>222</height> <height>536</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="inputTabVLayout" stretch="0,0"> <layout class="QVBoxLayout" name="inputTabVLayout" stretch="0,0">
@ -946,8 +890,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>536</width> <width>926</width>
<height>192</height> <height>536</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="graphicsTabVLayout" stretch="0,0"> <layout class="QVBoxLayout" name="graphicsTabVLayout" stretch="0,0">
@ -1197,8 +1141,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>146</width> <width>926</width>
<height>215</height> <height>536</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="pathsTabLayout" stretch="0"> <layout class="QVBoxLayout" name="pathsTabLayout" stretch="0">
@ -1211,18 +1155,25 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QPushButton" name="removeFolderButton"> <layout class="QHBoxLayout" name="horizontalLayout">
<property name="text"> <property name="topMargin">
<string>Remove</string> <number>0</number>
</property> </property>
</widget> <item>
</item> <widget class="QPushButton" name="addFolderButton">
<item> <property name="text">
<widget class="QPushButton" name="addFolderButton"> <string>Add...</string>
<property name="text"> </property>
<string>Add...</string> </widget>
</property> </item>
</widget> <item>
<widget class="QPushButton" name="removeFolderButton">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item>
<widget class="QListWidget" name="gameFoldersListWidget"/> <widget class="QListWidget" name="gameFoldersListWidget"/>
@ -1263,71 +1214,145 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>288</width> <width>926</width>
<height>163</height> <height>536</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="debugTabVLayout" stretch="0,1"> <layout class="QVBoxLayout" name="debugTabVLayout" stretch="0,1">
<item> <item>
<layout class="QHBoxLayout" name="debugTabHLayout" stretch="1"> <layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item> <item>
<widget class="QGroupBox" name="debugTabGroupBox"> <layout class="QHBoxLayout" name="debugTabHLayout" stretch="1">
<property name="enabled"> <item>
<bool>true</bool> <widget class="QGroupBox" name="debugTabGroupBox">
</property> <property name="enabled">
<property name="title"> <bool>true</bool>
<string>General</string> </property>
</property> <property name="title">
<property name="alignment"> <string>General</string>
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set> </property>
</property> <property name="alignment">
<layout class="QVBoxLayout" name="debugTabLayout"> <set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
<item alignment="Qt::AlignmentFlag::AlignTop"> </property>
<widget class="QCheckBox" name="debugDump"> <layout class="QVBoxLayout" name="debugTabLayout">
<property name="text"> <item>
<string>Enable Debug Dumping</string> <widget class="QCheckBox" name="debugDump">
</property> <property name="text">
</widget> <string>Enable Debug Dumping</string>
</item> </property>
<item> </widget>
<spacer name="verticalSpacer"> </item>
<property name="orientation"> <item>
<enum>Qt::Orientation::Vertical</enum> <widget class="QCheckBox" name="vkValidationCheckBox">
</property> <property name="text">
<property name="sizeType"> <string>Enable Vulkan Validation Layers</string>
<enum>QSizePolicy::Policy::MinimumExpanding</enum> </property>
</property> </widget>
<property name="sizeHint" stdset="0"> </item>
<size> <item>
<width>0</width> <widget class="QCheckBox" name="vkSyncValidationCheckBox">
<height>0</height> <property name="text">
</size> <string>Enable Vulkan Synchronization Validation</string>
</property> </property>
</spacer> </widget>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="vkValidationCheckBox"> <widget class="QCheckBox" name="rdocCheckBox">
<property name="text"> <property name="text">
<string>Enable Vulkan Validation Layers</string> <string>Enable RenderDoc Debugging</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> </layout>
<widget class="QCheckBox" name="vkSyncValidationCheckBox"> </widget>
<property name="text"> </item>
<string>Enable Vulkan Synchronization Validation</string> </layout>
</property> </item>
</widget> <item>
</item> <layout class="QVBoxLayout" name="loggerTabLayoutRight">
<item> <item>
<widget class="QCheckBox" name="rdocCheckBox"> <widget class="QGroupBox" name="loggerGroupBox">
<property name="text"> <property name="title">
<string>Enable RenderDoc Debugging</string> <string>Logger</string>
</property> </property>
</widget> <layout class="QVBoxLayout" name="loggerLayout">
</item> <item>
</layout> <widget class="QWidget" name="LogTypeWidget" native="true">
</widget> <layout class="QVBoxLayout" name="LogTypeLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="logTypeGroupBox">
<property name="title">
<string>Log Type</string>
</property>
<layout class="QVBoxLayout" name="logTypeBoxLayout">
<item>
<widget class="QComboBox" name="logTypeComboBox">
<item>
<property name="text">
<string>async</string>
</property>
</item>
<item>
<property name="text">
<string>sync</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="vLayoutLogFilter">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="hLayoutLogFilter">
<item>
<widget class="QGroupBox" name="logFilter">
<property name="title">
<string>Log Filter</string>
</property>
<layout class="QVBoxLayout" name="logFilterLayout">
<item>
<widget class="QLineEdit" name="logFilterLineEdit"/>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item> </item>
</layout> </layout>
</item> </item>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>اسم المستخدم</translation> <translation>اسم المستخدم</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>اسم المستخدم:\nيضبط اسم حساب PS4، الذي قد يتم عرضه في بعض الألعاب.</translation> <translation>اسم المستخدم:\nيضبط اسم حساب PS4، الذي قد يتم عرضه في بعض الألعاب.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Username</translation> <translation>Username</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Brugernavn:\nIndstiller PS4-kontoens navn, som kan blive vist i nogle spil.</translation> <translation>Brugernavn:\nIndstiller PS4-kontoens navn, som kan blive vist i nogle spil.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Benutzername</translation> <translation>Benutzername</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Benutzername:\nLegt den Namen des PS4-Kontos fest, der in einigen Spielen angezeigt werden kann.</translation> <translation>Benutzername:\nLegt den Namen des PS4-Kontos fest, der in einigen Spielen angezeigt werden kann.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Username</translation> <translation>Username</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Όνομα Χρήστη:\nΟρίζει το όνομα του λογαριασμού PS4, το οποίο μπορεί να εμφανιστεί σε ορισμένα παιχνίδια.</translation> <translation>Όνομα Χρήστη:\nΟρίζει το όνομα του λογαριασμού PS4, το οποίο μπορεί να εμφανιστεί σε ορισμένα παιχνίδια.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Username</translation> <translation>Username</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Username:\nSets the PS4's account username, which may be displayed by some games.</translation> <translation>Username:\nSets the PS4's account username, which may be displayed by some games.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Nombre de usuario</translation> <translation>Nombre de usuario</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Nombre de Usuario:\nEstablece el nombre de usuario de la cuenta de PS4, que puede ser mostrado por algunos juegos.</translation> <translation>Nombre de Usuario:\nEstablece el nombre de usuario de la cuenta de PS4, que puede ser mostrado por algunos juegos.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>نام کاربری</translation> <translation>نام کاربری</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>نام کاربری:\ام کاربری حساب PS4 را تنظیم میکند که ممکن است توسط برخی بازیها نمایش داده شود.</translation> <translation>نام کاربری:\ام کاربری حساب PS4 را تنظیم میکند که ممکن است توسط برخی بازیها نمایش داده شود.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Username</translation> <translation>Username</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Käyttäjänimi:\nAsettaa PS4-tilin käyttäjänimen, joka voi näkyä joissakin peleissä.</translation> <translation>Käyttäjänimi:\nAsettaa PS4-tilin käyttäjänimen, joka voi näkyä joissakin peleissä.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Nom d'utilisateur</translation> <translation>Nom d'utilisateur</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Nom d'utilisateur:\nDéfinit le nom d'utilisateur du compte PS4, qui peut être affiché par certains jeux.</translation> <translation>Nom d'utilisateur:\nDéfinit le nom d'utilisateur du compte PS4, qui peut être affiché par certains jeux.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Felhasználónév</translation> <translation>Felhasználónév</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Felhasználónév:\nBeállítja a PS4 fiók felhasználónevét, amelyet egyes játékok megjeleníthetnek.</translation> <translation>Felhasználónév:\nBeállítja a PS4 fiók felhasználónevét, amelyet egyes játékok megjeleníthetnek.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Username</translation> <translation>Username</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Nama Pengguna:\nMenetapkan nama pengguna akun PS4, yang mungkin ditampilkan oleh beberapa permainan.</translation> <translation>Nama Pengguna:\nMenetapkan nama pengguna akun PS4, yang mungkin ditampilkan oleh beberapa permainan.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Nome Utente</translation> <translation>Nome Utente</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Nome Utente:\nImposta il nome utente dell'account PS4, che potrebbe essere visualizzato da alcuni giochi.</translation> <translation>Nome Utente:\nImposta il nome utente dell'account PS4, che potrebbe essere visualizzato da alcuni giochi.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>:\nPS4のアカウントユーザー名を設定します</translation> <translation>:\nPS4のアカウントユーザー名を設定します</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Username</translation> <translation>Username</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Username:\nSets the PS4's account username, which may be displayed by some games.</translation> <translation>Username:\nSets the PS4's account username, which may be displayed by some games.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Username</translation> <translation>Username</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Vartotojo vardas:\nNustato PS4 paskyros vartotojo vardą, kuris gali būti rodomas kai kuriuose žaidimuose.</translation> <translation>Vartotojo vardas:\nNustato PS4 paskyros vartotojo vardą, kuris gali būti rodomas kai kuriuose žaidimuose.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Brukernavn</translation> <translation>Brukernavn</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Brukernavn:\nAngir brukernavnet for PS4-kontoen, som kan vises av enkelte spill.</translation> <translation>Brukernavn:\nAngir brukernavnet for PS4-kontoen, som kan vises av enkelte spill.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Username</translation> <translation>Username</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Gebruikersnaam:\nStelt de gebruikersnaam van het PS4-account in, die door sommige games kan worden weergegeven.</translation> <translation>Gebruikersnaam:\nStelt de gebruikersnaam van het PS4-account in, die door sommige games kan worden weergegeven.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Nazwa użytkownika</translation> <translation>Nazwa użytkownika</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Nazwa użytkownika:\nUstala nazwę użytkownika konta PS4, która może być wyświetlana w niektórych grach.</translation> <translation>Nazwa użytkownika:\nUstala nazwę użytkownika konta PS4, która może być wyświetlana w niektórych grach.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Nome de usuário</translation> <translation>Nome de usuário</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Troféus</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Nome de usuário:\nDefine o nome de usuário da conta PS4 que pode ser exibido por alguns jogos.</translation> <translation>Nome de usuário:\nDefine o nome de usuário da conta PS4 que pode ser exibido por alguns jogos.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Username</translation> <translation>Username</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Nume utilizator:\nSetează numele de utilizator al contului PS4, care poate fi afișat de unele jocuri.</translation> <translation>Nume utilizator:\nSetează numele de utilizator al contului PS4, care poate fi afișat de unele jocuri.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Имя пользователя</translation> <translation>Имя пользователя</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Имя пользователя:\nУстановите имя пользователя аккаунта PS4. Это может отображаться в некоторых играх.</translation> <translation>Имя пользователя:\nУстановите имя пользователя аккаунта PS4. Это может отображаться в некоторых играх.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Përdoruesi</translation> <translation>Përdoruesi</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Përdoruesi:\nPërcakton emrin e përdoruesit llogarisë PS4, i cili mund shfaqet nga disa lojra.</translation> <translation>Përdoruesi:\nPërcakton emrin e përdoruesit llogarisë PS4, i cili mund shfaqet nga disa lojra.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Kullanıcı Adı</translation> <translation>Kullanıcı Adı</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Kullanıcı Adı:\nBazı oyunlar tarafından gösterilebilen PS4 hesabının kullanıcı adını ayarlar.</translation> <translation>Kullanıcı Adı:\nBazı oyunlar tarafından gösterilebilen PS4 hesabının kullanıcı adını ayarlar.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Ім'я користувача</translation> <translation>Ім'я користувача</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Ім'я користувача:\nВстановіть ім'я користувача акаунта PS4. Це може відображатися в деяких іграх.</translation> <translation>Ім'я користувача:\nВстановіть ім'я користувача акаунта PS4. Це може відображатися в деяких іграх.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Username</translation> <translation>Username</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>Tên người dùng:\nChọn tên người dùng của tài khoản PS4, thể đưc một số trò chơi hiển thị.</translation> <translation>Tên người dùng:\nChọn tên người dùng của tài khoản PS4, thể đưc một số trò chơi hiển thị.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>\n设置 PS4 </translation> <translation>\n设置 PS4 </translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -537,6 +537,16 @@
<source>Username</source> <source>Username</source>
<translation>Username</translation> <translation>Username</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Trophy</source>
<translation>Trophy</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="178"/> <location filename="../settings_dialog.ui" line="178"/>
<source>Logger</source> <source>Logger</source>
@ -1236,6 +1246,11 @@
<source>userName</source> <source>userName</source>
<translation>:\n設定PS4帳號的用戶名</translation> <translation>:\n設定PS4帳號的用戶名</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>

View File

@ -161,6 +161,20 @@ void WindowSDL::WaitEvent() {
case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
OnGamepadEvent(&event); OnGamepadEvent(&event);
break; break;
// i really would have appreciated ANY KIND OF DOCUMENTATION ON THIS
// AND IT DOESN'T EVEN USE PROPER ENUMS
case SDL_EVENT_GAMEPAD_SENSOR_UPDATE:
switch ((SDL_SensorType)event.gsensor.sensor) {
case SDL_SENSOR_GYRO:
controller->Gyro(0, event.gsensor.data);
break;
case SDL_SENSOR_ACCEL:
controller->Acceleration(0, event.gsensor.data);
break;
default:
break;
}
break;
case SDL_EVENT_QUIT: case SDL_EVENT_QUIT:
is_open = false; is_open = false;
break; break;

View File

@ -205,7 +205,6 @@ void Translator::DS_WRITE(int bit_size, bool is_signed, bool is_pair, bool strid
addr, ir.Imm32((u32(inst.control.ds.offset1) << 8u) + u32(inst.control.ds.offset0))); addr, ir.Imm32((u32(inst.control.ds.offset1) << 8u) + u32(inst.control.ds.offset0)));
ir.WriteShared(bit_size, ir.GetVectorReg(data0), addr0); ir.WriteShared(bit_size, ir.GetVectorReg(data0), addr0);
} }
emit_ds_read_barrier = true;
} }
void Translator::DS_SWIZZLE_B32(const GcnInst& inst) { void Translator::DS_SWIZZLE_B32(const GcnInst& inst) {
@ -222,11 +221,6 @@ void Translator::DS_SWIZZLE_B32(const GcnInst& inst) {
void Translator::DS_READ(int bit_size, bool is_signed, bool is_pair, bool stride64, void Translator::DS_READ(int bit_size, bool is_signed, bool is_pair, bool stride64,
const GcnInst& inst) { const GcnInst& inst) {
if (emit_ds_read_barrier && profile.needs_lds_barriers) {
ir.Barrier();
emit_ds_read_barrier = false;
}
const IR::U32 addr{ir.GetVectorReg(IR::VectorReg(inst.src[0].code))}; const IR::U32 addr{ir.GetVectorReg(IR::VectorReg(inst.src[0].code))};
IR::VectorReg dst_reg{inst.dst[0].code}; IR::VectorReg dst_reg{inst.dst[0].code};
if (is_pair) { if (is_pair) {

View File

@ -308,7 +308,6 @@ private:
const RuntimeInfo& runtime_info; const RuntimeInfo& runtime_info;
const Profile& profile; const Profile& profile;
bool opcode_missing = false; bool opcode_missing = false;
bool emit_ds_read_barrier = false;
}; };
void Translate(IR::Block* block, u32 block_base, std::span<const GcnInst> inst_list, Info& info, void Translate(IR::Block* block, u32 block_base, std::span<const GcnInst> inst_list, Info& info,

View File

@ -8,6 +8,54 @@
namespace Shader::Optimization { namespace Shader::Optimization {
static void EmitBarrierInBlock(IR::Block* block) {
// This is inteded to insert a barrier when shared memory write and read
// occur in the same basic block. Also checks if branch depth is zero as
// we don't want to insert barrier in potentially divergent code.
bool emit_barrier_on_write = false;
bool emit_barrier_on_read = false;
const auto emit_barrier = [block](bool& emit_cond, IR::Inst& inst) {
if (emit_cond) {
IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)};
ir.Barrier();
emit_cond = false;
}
};
for (IR::Inst& inst : block->Instructions()) {
if (inst.GetOpcode() == IR::Opcode::LoadSharedU32 ||
inst.GetOpcode() == IR::Opcode::LoadSharedU64) {
emit_barrier(emit_barrier_on_read, inst);
emit_barrier_on_write = true;
}
if (inst.GetOpcode() == IR::Opcode::WriteSharedU32 ||
inst.GetOpcode() == IR::Opcode::WriteSharedU64) {
emit_barrier(emit_barrier_on_write, inst);
emit_barrier_on_read = true;
}
}
}
static void EmitBarrierInMergeBlock(const IR::AbstractSyntaxNode::Data& data) {
// Insert a barrier after divergent conditional blocks.
// This avoids potential softlocks and crashes when some threads
// initialize shared memory and others read from it.
const IR::U1 cond = data.if_node.cond;
const auto insert_barrier =
IR::BreadthFirstSearch(cond, [](IR::Inst* inst) -> std::optional<bool> {
if (inst->GetOpcode() == IR::Opcode::GetAttributeU32 &&
inst->Arg(0).Attribute() == IR::Attribute::LocalInvocationId) {
return true;
}
return std::nullopt;
});
if (insert_barrier) {
IR::Block* const merge = data.if_node.merge;
auto insert_point = std::ranges::find_if_not(merge->Instructions(), IR::IsPhi);
IR::IREmitter ir{*merge, insert_point};
ir.Barrier();
}
}
void SharedMemoryBarrierPass(IR::Program& program, const Profile& profile) { void SharedMemoryBarrierPass(IR::Program& program, const Profile& profile) {
if (!program.info.uses_shared || !profile.needs_lds_barriers) { if (!program.info.uses_shared || !profile.needs_lds_barriers) {
return; return;
@ -19,27 +67,12 @@ void SharedMemoryBarrierPass(IR::Program& program, const Profile& profile) {
--branch_depth; --branch_depth;
continue; continue;
} }
if (node.type != Type::If) { if (node.type == Type::If && branch_depth++ == 0) {
EmitBarrierInMergeBlock(node.data);
continue; continue;
} }
u32 curr_depth = branch_depth++; if (node.type == Type::Block && branch_depth == 0) {
if (curr_depth != 0) { EmitBarrierInBlock(node.data.block);
continue;
}
const IR::U1 cond = node.data.if_node.cond;
const auto insert_barrier =
IR::BreadthFirstSearch(cond, [](IR::Inst* inst) -> std::optional<bool> {
if (inst->GetOpcode() == IR::Opcode::GetAttributeU32 &&
inst->Arg(0).Attribute() == IR::Attribute::LocalInvocationId) {
return true;
}
return std::nullopt;
});
if (insert_barrier) {
IR::Block* const merge = node.data.if_node.merge;
auto insert_point = std::ranges::find_if_not(merge->Instructions(), IR::IsPhi);
IR::IREmitter ir{*merge, insert_point};
ir.Barrier();
} }
} }
} }

View File

@ -815,7 +815,8 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb, u32 vqid) {
} }
if (rasterizer && (cs_program.dispatch_initiator & 1)) { if (rasterizer && (cs_program.dispatch_initiator & 1)) {
const auto cmd_address = reinterpret_cast<const void*>(header); const auto cmd_address = reinterpret_cast<const void*>(header);
rasterizer->ScopeMarkerBegin(fmt::format("acb[{}]:{}:Dispatch", vqid, cmd_address)); rasterizer->ScopeMarkerBegin(
fmt::format("acb[{}]:{}:DispatchIndirect", vqid, cmd_address));
rasterizer->DispatchDirect(); rasterizer->DispatchDirect();
rasterizer->ScopeMarkerEnd(); rasterizer->ScopeMarkerEnd();
} }

View File

@ -889,11 +889,11 @@ struct Liverpool {
return !info.linear_general; return !info.linear_general;
} }
[[nodiscard]] DataFormat DataFormat() const { [[nodiscard]] DataFormat GetDataFmt() const {
return RemapDataFormat(info.format); return RemapDataFormat(info.format);
} }
[[nodiscard]] NumberFormat NumFormat() const { [[nodiscard]] NumberFormat GetNumberFmt() const {
// There is a small difference between T# and CB number types, account for it. // There is a small difference between T# and CB number types, account for it.
return RemapNumberFormat(info.number_type == NumberFormat::SnormNz return RemapNumberFormat(info.number_type == NumberFormat::SnormNz
? NumberFormat::Srgb ? NumberFormat::Srgb

View File

@ -79,21 +79,23 @@ inline NumberFormat RemapNumberFormat(const NumberFormat format) {
inline CompMapping RemapComponents(const DataFormat format, const CompMapping components) { inline CompMapping RemapComponents(const DataFormat format, const CompMapping components) {
switch (format) { switch (format) {
case DataFormat::Format11_11_10: case DataFormat::Format11_11_10: {
return { CompMapping result;
.r = components.b, result.r = components.b;
.g = components.g, result.g = components.g;
.b = components.r, result.b = components.r;
.a = components.a, result.a = components.a;
}; return result;
}
case DataFormat::Format10_10_10_2: case DataFormat::Format10_10_10_2:
case DataFormat::Format5_5_5_1: case DataFormat::Format5_5_5_1: {
return { CompMapping result;
.r = components.a, result.r = components.a;
.g = components.b, result.g = components.b;
.b = components.g, result.b = components.g;
.a = components.r, result.a = components.r;
}; return result;
}
default: default:
return components; return components;
} }

View File

@ -54,18 +54,10 @@ BufferCache::BufferCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& s
BufferCache::~BufferCache() = default; BufferCache::~BufferCache() = default;
void BufferCache::InvalidateMemory(VAddr device_addr, u64 size) { void BufferCache::InvalidateMemory(VAddr device_addr, u64 size) {
std::scoped_lock lk{mutex};
const bool is_tracked = IsRegionRegistered(device_addr, size); const bool is_tracked = IsRegionRegistered(device_addr, size);
if (!is_tracked) { if (is_tracked) {
return; // Mark the page as CPU modified to stop tracking writes.
}
// Mark the page as CPU modified to stop tracking writes.
SCOPE_EXIT {
memory_tracker.MarkRegionAsCpuModified(device_addr, size); memory_tracker.MarkRegionAsCpuModified(device_addr, size);
};
if (!memory_tracker.IsRegionGpuModified(device_addr, size)) {
// Page has not been modified by the GPU, nothing to do.
return;
} }
} }
@ -267,7 +259,16 @@ void BufferCache::InlineData(VAddr address, const void* value, u32 num_bytes, bo
const BufferId buffer_id = FindBuffer(address, num_bytes); const BufferId buffer_id = FindBuffer(address, num_bytes);
return &slot_buffers[buffer_id]; return &slot_buffers[buffer_id];
}(); }();
const vk::BufferMemoryBarrier2 buf_barrier = { const vk::BufferMemoryBarrier2 pre_barrier = {
.srcStageMask = vk::PipelineStageFlagBits2::eAllCommands,
.srcAccessMask = vk::AccessFlagBits2::eMemoryRead,
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
.dstAccessMask = vk::AccessFlagBits2::eTransferWrite,
.buffer = buffer->Handle(),
.offset = buffer->Offset(address),
.size = num_bytes,
};
const vk::BufferMemoryBarrier2 post_barrier = {
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer, .srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite, .srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
.dstStageMask = vk::PipelineStageFlagBits2::eAllCommands, .dstStageMask = vk::PipelineStageFlagBits2::eAllCommands,
@ -279,9 +280,14 @@ void BufferCache::InlineData(VAddr address, const void* value, u32 num_bytes, bo
cmdbuf.pipelineBarrier2(vk::DependencyInfo{ cmdbuf.pipelineBarrier2(vk::DependencyInfo{
.dependencyFlags = vk::DependencyFlagBits::eByRegion, .dependencyFlags = vk::DependencyFlagBits::eByRegion,
.bufferMemoryBarrierCount = 1, .bufferMemoryBarrierCount = 1,
.pBufferMemoryBarriers = &buf_barrier, .pBufferMemoryBarriers = &pre_barrier,
});
cmdbuf.updateBuffer(buffer->Handle(), buffer->Offset(address), num_bytes, value);
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
.bufferMemoryBarrierCount = 1,
.pBufferMemoryBarriers = &post_barrier,
}); });
cmdbuf.updateBuffer(buffer->Handle(), buf_barrier.offset, num_bytes, value);
} }
std::pair<Buffer*, u32> BufferCache::ObtainHostUBO(std::span<const u32> data) { std::pair<Buffer*, u32> BufferCache::ObtainHostUBO(std::span<const u32> data) {
@ -346,6 +352,7 @@ bool BufferCache::IsRegionRegistered(VAddr addr, size_t size) {
++page; ++page;
continue; continue;
} }
std::shared_lock lk{mutex};
Buffer& buffer = slot_buffers[buffer_id]; Buffer& buffer = slot_buffers[buffer_id];
const VAddr buf_start_addr = buffer.CpuAddr(); const VAddr buf_start_addr = buffer.CpuAddr();
const VAddr buf_end_addr = buf_start_addr + buffer.SizeBytes(); const VAddr buf_end_addr = buf_start_addr + buffer.SizeBytes();
@ -472,21 +479,48 @@ void BufferCache::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id,
}; };
scheduler.EndRendering(); scheduler.EndRendering();
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
static constexpr vk::MemoryBarrier READ_BARRIER{ const std::array pre_barriers = {
.srcAccessMask = vk::AccessFlagBits::eMemoryWrite, vk::BufferMemoryBarrier2{
.dstAccessMask = vk::AccessFlagBits::eTransferRead | vk::AccessFlagBits::eTransferWrite, .srcStageMask = vk::PipelineStageFlagBits2::eAllCommands,
.srcAccessMask = vk::AccessFlagBits2::eMemoryRead | vk::AccessFlagBits2::eMemoryWrite,
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
.dstAccessMask = vk::AccessFlagBits2::eTransferRead,
.buffer = overlap.Handle(),
.offset = 0,
.size = overlap.SizeBytes(),
},
}; };
static constexpr vk::MemoryBarrier WRITE_BARRIER{ const std::array post_barriers = {
.srcAccessMask = vk::AccessFlagBits::eTransferWrite, vk::BufferMemoryBarrier2{
.dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite, .srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
.srcAccessMask = vk::AccessFlagBits2::eTransferRead,
.dstStageMask = vk::PipelineStageFlagBits2::eAllCommands,
.dstAccessMask = vk::AccessFlagBits2::eMemoryWrite,
.buffer = overlap.Handle(),
.offset = 0,
.size = overlap.SizeBytes(),
},
vk::BufferMemoryBarrier2{
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
.dstStageMask = vk::PipelineStageFlagBits2::eAllCommands,
.dstAccessMask = vk::AccessFlagBits2::eMemoryRead | vk::AccessFlagBits2::eMemoryWrite,
.buffer = new_buffer.Handle(),
.offset = dst_base_offset,
.size = overlap.SizeBytes(),
},
}; };
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, cmdbuf.pipelineBarrier2(vk::DependencyInfo{
vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits::eByRegion, .dependencyFlags = vk::DependencyFlagBits::eByRegion,
READ_BARRIER, {}, {}); .bufferMemoryBarrierCount = 1,
cmdbuf.copyBuffer(overlap.buffer, new_buffer.buffer, copy); .pBufferMemoryBarriers = pre_barriers.data(),
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, });
vk::PipelineStageFlagBits::eAllCommands, cmdbuf.copyBuffer(overlap.Handle(), new_buffer.Handle(), copy);
vk::DependencyFlagBits::eByRegion, WRITE_BARRIER, {}, {}); cmdbuf.pipelineBarrier2(vk::DependencyInfo{
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
.bufferMemoryBarrierCount = static_cast<u32>(post_barriers.size()),
.pBufferMemoryBarriers = post_barriers.data(),
});
DeleteBuffer(overlap_id); DeleteBuffer(overlap_id);
} }
@ -496,8 +530,11 @@ BufferId BufferCache::CreateBuffer(VAddr device_addr, u32 wanted_size) {
wanted_size = static_cast<u32>(device_addr_end - device_addr); wanted_size = static_cast<u32>(device_addr_end - device_addr);
const OverlapResult overlap = ResolveOverlaps(device_addr, wanted_size); const OverlapResult overlap = ResolveOverlaps(device_addr, wanted_size);
const u32 size = static_cast<u32>(overlap.end - overlap.begin); const u32 size = static_cast<u32>(overlap.end - overlap.begin);
const BufferId new_buffer_id = slot_buffers.insert( const BufferId new_buffer_id = [&] {
instance, scheduler, MemoryUsage::DeviceLocal, overlap.begin, AllFlags, size); std::scoped_lock lk{mutex};
return slot_buffers.insert(instance, scheduler, MemoryUsage::DeviceLocal, overlap.begin,
AllFlags, size);
}();
auto& new_buffer = slot_buffers[new_buffer_id]; auto& new_buffer = slot_buffers[new_buffer_id];
const size_t size_bytes = new_buffer.SizeBytes(); const size_t size_bytes = new_buffer.SizeBytes();
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
@ -537,10 +574,8 @@ void BufferCache::ChangeRegister(BufferId buffer_id) {
void BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size, void BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size,
bool is_texel_buffer) { bool is_texel_buffer) {
std::scoped_lock lk{mutex};
boost::container::small_vector<vk::BufferCopy, 4> copies; boost::container::small_vector<vk::BufferCopy, 4> copies;
u64 total_size_bytes = 0; u64 total_size_bytes = 0;
u64 largest_copy = 0;
VAddr buffer_start = buffer.CpuAddr(); VAddr buffer_start = buffer.CpuAddr();
memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) { memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) {
copies.push_back(vk::BufferCopy{ copies.push_back(vk::BufferCopy{
@ -549,7 +584,6 @@ void BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size,
.size = range_size, .size = range_size,
}); });
total_size_bytes += range_size; total_size_bytes += range_size;
largest_copy = std::max(largest_copy, range_size);
}); });
SCOPE_EXIT { SCOPE_EXIT {
if (is_texel_buffer) { if (is_texel_buffer) {
@ -590,21 +624,35 @@ void BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size,
} }
scheduler.EndRendering(); scheduler.EndRendering();
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
static constexpr vk::MemoryBarrier READ_BARRIER{ const vk::BufferMemoryBarrier2 pre_barrier = {
.srcAccessMask = vk::AccessFlagBits::eMemoryWrite, .srcStageMask = vk::PipelineStageFlagBits2::eAllCommands,
.dstAccessMask = vk::AccessFlagBits::eTransferRead | vk::AccessFlagBits::eTransferWrite, .srcAccessMask = vk::AccessFlagBits2::eMemoryRead,
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
.dstAccessMask = vk::AccessFlagBits2::eTransferWrite,
.buffer = buffer.Handle(),
.offset = 0,
.size = buffer.SizeBytes(),
}; };
static constexpr vk::MemoryBarrier WRITE_BARRIER{ const vk::BufferMemoryBarrier2 post_barrier = {
.srcAccessMask = vk::AccessFlagBits::eTransferWrite, .srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
.dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite, .srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
.dstStageMask = vk::PipelineStageFlagBits2::eAllCommands,
.dstAccessMask = vk::AccessFlagBits2::eMemoryRead | vk::AccessFlagBits2::eMemoryWrite,
.buffer = buffer.Handle(),
.offset = 0,
.size = buffer.SizeBytes(),
}; };
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, cmdbuf.pipelineBarrier2(vk::DependencyInfo{
vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits::eByRegion, .dependencyFlags = vk::DependencyFlagBits::eByRegion,
READ_BARRIER, {}, {}); .bufferMemoryBarrierCount = 1,
.pBufferMemoryBarriers = &pre_barrier,
});
cmdbuf.copyBuffer(src_buffer, buffer.buffer, copies); cmdbuf.copyBuffer(src_buffer, buffer.buffer, copies);
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, cmdbuf.pipelineBarrier2(vk::DependencyInfo{
vk::PipelineStageFlagBits::eAllCommands, .dependencyFlags = vk::DependencyFlagBits::eByRegion,
vk::DependencyFlagBits::eByRegion, WRITE_BARRIER, {}, {}); .bufferMemoryBarrierCount = 1,
.pBufferMemoryBarriers = &post_barrier,
});
} }
bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, u32 size) { bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, u32 size) {
@ -654,10 +702,42 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr,
} }
if (!copies.empty()) { if (!copies.empty()) {
scheduler.EndRendering(); scheduler.EndRendering();
image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead, {}); const vk::BufferMemoryBarrier2 pre_barrier = {
.srcStageMask = vk::PipelineStageFlagBits2::eAllCommands,
.srcAccessMask = vk::AccessFlagBits2::eMemoryRead,
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
.dstAccessMask = vk::AccessFlagBits2::eTransferWrite,
.buffer = buffer.Handle(),
.offset = max_offset - size,
.size = size,
};
const vk::BufferMemoryBarrier2 post_barrier = {
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
.dstStageMask = vk::PipelineStageFlagBits2::eAllCommands,
.dstAccessMask = vk::AccessFlagBits2::eMemoryRead,
.buffer = buffer.Handle(),
.offset = max_offset - size,
.size = size,
};
auto barriers = image.GetBarriers(vk::ImageLayout::eTransferSrcOptimal,
vk::AccessFlagBits2::eTransferRead,
vk::PipelineStageFlagBits2::eTransfer, {});
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
cmdbuf.copyImageToBuffer(image.image, vk::ImageLayout::eTransferSrcOptimal, buffer.buffer, cmdbuf.pipelineBarrier2(vk::DependencyInfo{
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
.bufferMemoryBarrierCount = 1,
.pBufferMemoryBarriers = &pre_barrier,
.imageMemoryBarrierCount = static_cast<u32>(barriers.size()),
.pImageMemoryBarriers = barriers.data(),
});
cmdbuf.copyImageToBuffer(image.image, vk::ImageLayout::eTransferSrcOptimal, buffer.Handle(),
copies); copies);
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
.bufferMemoryBarrierCount = 1,
.pBufferMemoryBarriers = &post_barrier,
});
} }
return true; return true;
} }

View File

@ -3,7 +3,7 @@
#pragma once #pragma once
#include <mutex> #include <shared_mutex>
#include <boost/container/small_vector.hpp> #include <boost/container/small_vector.hpp>
#include <boost/icl/interval_map.hpp> #include <boost/icl/interval_map.hpp>
#include <tsl/robin_map.h> #include <tsl/robin_map.h>
@ -157,7 +157,7 @@ private:
StreamBuffer staging_buffer; StreamBuffer staging_buffer;
StreamBuffer stream_buffer; StreamBuffer stream_buffer;
Buffer gds_buffer; Buffer gds_buffer;
std::mutex mutex; std::shared_mutex mutex;
Common::SlotVector<Buffer> slot_buffers; Common::SlotVector<Buffer> slot_buffers;
RangeSet gpu_modified_ranges; RangeSet gpu_modified_ranges;
vk::BufferView null_buffer_view; vk::BufferView null_buffer_view;

View File

@ -15,13 +15,8 @@ namespace VideoCore {
class MemoryTracker { class MemoryTracker {
public: public:
static constexpr size_t MAX_CPU_PAGE_BITS = 40; static constexpr size_t MAX_CPU_PAGE_BITS = 40;
static constexpr size_t HIGHER_PAGE_BITS = 22;
static constexpr size_t HIGHER_PAGE_SIZE = 1ULL << HIGHER_PAGE_BITS;
static constexpr size_t HIGHER_PAGE_MASK = HIGHER_PAGE_SIZE - 1ULL;
static constexpr size_t NUM_HIGH_PAGES = 1ULL << (MAX_CPU_PAGE_BITS - HIGHER_PAGE_BITS); static constexpr size_t NUM_HIGH_PAGES = 1ULL << (MAX_CPU_PAGE_BITS - HIGHER_PAGE_BITS);
static constexpr size_t MANAGER_POOL_SIZE = 32; static constexpr size_t MANAGER_POOL_SIZE = 32;
static constexpr size_t WORDS_STACK_NEEDED = HIGHER_PAGE_SIZE / BYTES_PER_WORD;
using Manager = WordManager<WORDS_STACK_NEEDED>;
public: public:
explicit MemoryTracker(PageManager* tracker_) : tracker{tracker_} {} explicit MemoryTracker(PageManager* tracker_) : tracker{tracker_} {}
@ -30,7 +25,7 @@ public:
/// Returns true if a region has been modified from the CPU /// Returns true if a region has been modified from the CPU
[[nodiscard]] bool IsRegionCpuModified(VAddr query_cpu_addr, u64 query_size) noexcept { [[nodiscard]] bool IsRegionCpuModified(VAddr query_cpu_addr, u64 query_size) noexcept {
return IteratePages<true>( return IteratePages<true>(
query_cpu_addr, query_size, [](Manager* manager, u64 offset, size_t size) { query_cpu_addr, query_size, [](RegionManager* manager, u64 offset, size_t size) {
return manager->template IsRegionModified<Type::CPU>(offset, size); return manager->template IsRegionModified<Type::CPU>(offset, size);
}); });
} }
@ -38,52 +33,34 @@ public:
/// Returns true if a region has been modified from the GPU /// Returns true if a region has been modified from the GPU
[[nodiscard]] bool IsRegionGpuModified(VAddr query_cpu_addr, u64 query_size) noexcept { [[nodiscard]] bool IsRegionGpuModified(VAddr query_cpu_addr, u64 query_size) noexcept {
return IteratePages<false>( return IteratePages<false>(
query_cpu_addr, query_size, [](Manager* manager, u64 offset, size_t size) { query_cpu_addr, query_size, [](RegionManager* manager, u64 offset, size_t size) {
return manager->template IsRegionModified<Type::GPU>(offset, size); return manager->template IsRegionModified<Type::GPU>(offset, size);
}); });
} }
/// Mark region as CPU modified, notifying the device_tracker about this change /// Mark region as CPU modified, notifying the device_tracker about this change
void MarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_size) { void MarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_size) {
IteratePages<true>(dirty_cpu_addr, query_size, IteratePages<false>(dirty_cpu_addr, query_size,
[](Manager* manager, u64 offset, size_t size) { [](RegionManager* manager, u64 offset, size_t size) {
manager->template ChangeRegionState<Type::CPU, true>( manager->template ChangeRegionState<Type::CPU, true>(
manager->GetCpuAddr() + offset, size); manager->GetCpuAddr() + offset, size);
}); });
}
/// Unmark region as CPU modified, notifying the device_tracker about this change
void UnmarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_size) {
IteratePages<true>(dirty_cpu_addr, query_size,
[](Manager* manager, u64 offset, size_t size) {
manager->template ChangeRegionState<Type::CPU, false>(
manager->GetCpuAddr() + offset, size);
});
} }
/// Mark region as modified from the host GPU /// Mark region as modified from the host GPU
void MarkRegionAsGpuModified(VAddr dirty_cpu_addr, u64 query_size) noexcept { void MarkRegionAsGpuModified(VAddr dirty_cpu_addr, u64 query_size) noexcept {
IteratePages<true>(dirty_cpu_addr, query_size, IteratePages<false>(dirty_cpu_addr, query_size,
[](Manager* manager, u64 offset, size_t size) { [](RegionManager* manager, u64 offset, size_t size) {
manager->template ChangeRegionState<Type::GPU, true>( manager->template ChangeRegionState<Type::GPU, true>(
manager->GetCpuAddr() + offset, size); manager->GetCpuAddr() + offset, size);
}); });
}
/// Unmark region as modified from the host GPU
void UnmarkRegionAsGpuModified(VAddr dirty_cpu_addr, u64 query_size) noexcept {
IteratePages<true>(dirty_cpu_addr, query_size,
[](Manager* manager, u64 offset, size_t size) {
manager->template ChangeRegionState<Type::GPU, false>(
manager->GetCpuAddr() + offset, size);
});
} }
/// Call 'func' for each CPU modified range and unmark those pages as CPU modified /// Call 'func' for each CPU modified range and unmark those pages as CPU modified
template <typename Func> template <typename Func>
void ForEachUploadRange(VAddr query_cpu_range, u64 query_size, Func&& func) { void ForEachUploadRange(VAddr query_cpu_range, u64 query_size, Func&& func) {
IteratePages<true>(query_cpu_range, query_size, IteratePages<true>(query_cpu_range, query_size,
[&func](Manager* manager, u64 offset, size_t size) { [&func](RegionManager* manager, u64 offset, size_t size) {
manager->template ForEachModifiedRange<Type::CPU, true>( manager->template ForEachModifiedRange<Type::CPU, true>(
manager->GetCpuAddr() + offset, size, func); manager->GetCpuAddr() + offset, size, func);
}); });
@ -93,7 +70,7 @@ public:
template <bool clear, typename Func> template <bool clear, typename Func>
void ForEachDownloadRange(VAddr query_cpu_range, u64 query_size, Func&& func) { void ForEachDownloadRange(VAddr query_cpu_range, u64 query_size, Func&& func) {
IteratePages<false>(query_cpu_range, query_size, IteratePages<false>(query_cpu_range, query_size,
[&func](Manager* manager, u64 offset, size_t size) { [&func](RegionManager* manager, u64 offset, size_t size) {
if constexpr (clear) { if constexpr (clear) {
manager->template ForEachModifiedRange<Type::GPU, true>( manager->template ForEachModifiedRange<Type::GPU, true>(
manager->GetCpuAddr() + offset, size, func); manager->GetCpuAddr() + offset, size, func);
@ -114,7 +91,7 @@ private:
*/ */
template <bool create_region_on_fail, typename Func> template <bool create_region_on_fail, typename Func>
bool IteratePages(VAddr cpu_address, size_t size, Func&& func) { bool IteratePages(VAddr cpu_address, size_t size, Func&& func) {
using FuncReturn = typename std::invoke_result<Func, Manager*, u64, size_t>::type; using FuncReturn = typename std::invoke_result<Func, RegionManager*, u64, size_t>::type;
static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>; static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
std::size_t remaining_size{size}; std::size_t remaining_size{size};
std::size_t page_index{cpu_address >> HIGHER_PAGE_BITS}; std::size_t page_index{cpu_address >> HIGHER_PAGE_BITS};
@ -155,7 +132,7 @@ private:
manager_pool.emplace_back(); manager_pool.emplace_back();
auto& last_pool = manager_pool.back(); auto& last_pool = manager_pool.back();
for (size_t i = 0; i < MANAGER_POOL_SIZE; i++) { for (size_t i = 0; i < MANAGER_POOL_SIZE; i++) {
std::construct_at(&last_pool[i], tracker, 0, HIGHER_PAGE_SIZE); std::construct_at(&last_pool[i], tracker, 0);
free_managers.push_back(&last_pool[i]); free_managers.push_back(&last_pool[i]);
} }
} }
@ -167,9 +144,9 @@ private:
} }
PageManager* tracker; PageManager* tracker;
std::deque<std::array<Manager, MANAGER_POOL_SIZE>> manager_pool; std::deque<std::array<RegionManager, MANAGER_POOL_SIZE>> manager_pool;
std::vector<Manager*> free_managers; std::vector<RegionManager*> free_managers;
std::array<Manager*, NUM_HIGH_PAGES> top_tier{}; std::array<RegionManager*, NUM_HIGH_PAGES> top_tier{};
}; };
} // namespace VideoCore } // namespace VideoCore

View File

@ -3,10 +3,12 @@
#pragma once #pragma once
#include <algorithm> #include <array>
#include <mutex>
#include <span> #include <span>
#include <utility> #include <utility>
#include "common/div_ceil.h"
#include "common/spin_lock.h"
#include "common/types.h" #include "common/types.h"
#include "video_core/page_manager.h" #include "video_core/page_manager.h"
@ -16,135 +18,32 @@ constexpr u64 PAGES_PER_WORD = 64;
constexpr u64 BYTES_PER_PAGE = 4_KB; constexpr u64 BYTES_PER_PAGE = 4_KB;
constexpr u64 BYTES_PER_WORD = PAGES_PER_WORD * BYTES_PER_PAGE; constexpr u64 BYTES_PER_WORD = PAGES_PER_WORD * BYTES_PER_PAGE;
constexpr u64 HIGHER_PAGE_BITS = 22;
constexpr u64 HIGHER_PAGE_SIZE = 1ULL << HIGHER_PAGE_BITS;
constexpr u64 HIGHER_PAGE_MASK = HIGHER_PAGE_SIZE - 1ULL;
constexpr u64 NUM_REGION_WORDS = HIGHER_PAGE_SIZE / BYTES_PER_WORD;
enum class Type { enum class Type {
CPU, CPU,
GPU, GPU,
Untracked, Untracked,
}; };
/// Vector tracking modified pages tightly packed with small vector optimization using WordsArray = std::array<u64, NUM_REGION_WORDS>;
template <size_t stack_words = 1>
struct WordsArray {
/// Returns the pointer to the words state
[[nodiscard]] const u64* Pointer(bool is_short) const noexcept {
return is_short ? stack.data() : heap;
}
/// Returns the pointer to the words state /**
[[nodiscard]] u64* Pointer(bool is_short) noexcept { * Allows tracking CPU and GPU modification of pages in a contigious 4MB virtual address region.
return is_short ? stack.data() : heap; * Information is stored in bitsets for spacial locality and fast update of single pages.
} */
class RegionManager {
std::array<u64, stack_words> stack{}; ///< Small buffers storage
u64* heap; ///< Not-small buffers pointer to the storage
};
template <size_t stack_words = 1>
struct Words {
explicit Words() = default;
explicit Words(u64 size_bytes_) : size_bytes{size_bytes_} {
num_words = Common::DivCeil(size_bytes, BYTES_PER_WORD);
if (IsShort()) {
cpu.stack.fill(~u64{0});
gpu.stack.fill(0);
untracked.stack.fill(~u64{0});
} else {
// Share allocation between CPU and GPU pages and set their default values
u64* const alloc = new u64[num_words * 3];
cpu.heap = alloc;
gpu.heap = alloc + num_words;
untracked.heap = alloc + num_words * 2;
std::fill_n(cpu.heap, num_words, ~u64{0});
std::fill_n(gpu.heap, num_words, 0);
std::fill_n(untracked.heap, num_words, ~u64{0});
}
// Clean up tailing bits
const u64 last_word_size = size_bytes % BYTES_PER_WORD;
const u64 last_local_page = Common::DivCeil(last_word_size, BYTES_PER_PAGE);
const u64 shift = (PAGES_PER_WORD - last_local_page) % PAGES_PER_WORD;
const u64 last_word = (~u64{0} << shift) >> shift;
cpu.Pointer(IsShort())[NumWords() - 1] = last_word;
untracked.Pointer(IsShort())[NumWords() - 1] = last_word;
}
~Words() {
Release();
}
Words& operator=(Words&& rhs) noexcept {
Release();
size_bytes = rhs.size_bytes;
num_words = rhs.num_words;
cpu = rhs.cpu;
gpu = rhs.gpu;
untracked = rhs.untracked;
rhs.cpu.heap = nullptr;
return *this;
}
Words(Words&& rhs) noexcept
: size_bytes{rhs.size_bytes}, num_words{rhs.num_words}, cpu{rhs.cpu}, gpu{rhs.gpu},
untracked{rhs.untracked} {
rhs.cpu.heap = nullptr;
}
Words& operator=(const Words&) = delete;
Words(const Words&) = delete;
/// Returns true when the buffer fits in the small vector optimization
[[nodiscard]] bool IsShort() const noexcept {
return num_words <= stack_words;
}
/// Returns the number of words of the buffer
[[nodiscard]] size_t NumWords() const noexcept {
return num_words;
}
/// Release buffer resources
void Release() {
if (!IsShort()) {
// CPU written words is the base for the heap allocation
delete[] cpu.heap;
}
}
template <Type type>
std::span<u64> Span() noexcept {
if constexpr (type == Type::CPU) {
return std::span<u64>(cpu.Pointer(IsShort()), num_words);
} else if constexpr (type == Type::GPU) {
return std::span<u64>(gpu.Pointer(IsShort()), num_words);
} else if constexpr (type == Type::Untracked) {
return std::span<u64>(untracked.Pointer(IsShort()), num_words);
}
}
template <Type type>
std::span<const u64> Span() const noexcept {
if constexpr (type == Type::CPU) {
return std::span<const u64>(cpu.Pointer(IsShort()), num_words);
} else if constexpr (type == Type::GPU) {
return std::span<const u64>(gpu.Pointer(IsShort()), num_words);
} else if constexpr (type == Type::Untracked) {
return std::span<const u64>(untracked.Pointer(IsShort()), num_words);
}
}
u64 size_bytes = 0;
size_t num_words = 0;
WordsArray<stack_words> cpu;
WordsArray<stack_words> gpu;
WordsArray<stack_words> untracked;
};
template <size_t stack_words = 1>
class WordManager {
public: public:
explicit WordManager(PageManager* tracker_, VAddr cpu_addr_, u64 size_bytes) explicit RegionManager(PageManager* tracker_, VAddr cpu_addr_)
: tracker{tracker_}, cpu_addr{cpu_addr_}, words{size_bytes} {} : tracker{tracker_}, cpu_addr{cpu_addr_} {
cpu.fill(~u64{0});
explicit WordManager() = default; gpu.fill(0);
untracked.fill(~u64{0});
}
explicit RegionManager() = default;
void SetCpuAddress(VAddr new_cpu_addr) { void SetCpuAddress(VAddr new_cpu_addr) {
cpu_addr = new_cpu_addr; cpu_addr = new_cpu_addr;
@ -175,12 +74,12 @@ public:
static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>; static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
const size_t start = static_cast<size_t>(std::max<s64>(static_cast<s64>(offset), 0LL)); const size_t start = static_cast<size_t>(std::max<s64>(static_cast<s64>(offset), 0LL));
const size_t end = static_cast<size_t>(std::max<s64>(static_cast<s64>(offset + size), 0LL)); const size_t end = static_cast<size_t>(std::max<s64>(static_cast<s64>(offset + size), 0LL));
if (start >= SizeBytes() || end <= start) { if (start >= HIGHER_PAGE_SIZE || end <= start) {
return; return;
} }
auto [start_word, start_page] = GetWordPage(start); auto [start_word, start_page] = GetWordPage(start);
auto [end_word, end_page] = GetWordPage(end + BYTES_PER_PAGE - 1ULL); auto [end_word, end_page] = GetWordPage(end + BYTES_PER_PAGE - 1ULL);
const size_t num_words = NumWords(); constexpr size_t num_words = NUM_REGION_WORDS;
start_word = std::min(start_word, num_words); start_word = std::min(start_word, num_words);
end_word = std::min(end_word, num_words); end_word = std::min(end_word, num_words);
const size_t diff = end_word - start_word; const size_t diff = end_word - start_word;
@ -225,21 +124,21 @@ public:
*/ */
template <Type type, bool enable> template <Type type, bool enable>
void ChangeRegionState(u64 dirty_addr, u64 size) noexcept(type == Type::GPU) { void ChangeRegionState(u64 dirty_addr, u64 size) noexcept(type == Type::GPU) {
std::span<u64> state_words = words.template Span<type>(); std::scoped_lock lk{lock};
[[maybe_unused]] std::span<u64> untracked_words = words.template Span<Type::Untracked>(); std::span<u64> state_words = Span<type>();
IterateWords(dirty_addr - cpu_addr, size, [&](size_t index, u64 mask) { IterateWords(dirty_addr - cpu_addr, size, [&](size_t index, u64 mask) {
if constexpr (type == Type::CPU) { if constexpr (type == Type::CPU) {
NotifyPageTracker<!enable>(index, untracked_words[index], mask); UpdateProtection<!enable>(index, untracked[index], mask);
} }
if constexpr (enable) { if constexpr (enable) {
state_words[index] |= mask; state_words[index] |= mask;
if constexpr (type == Type::CPU) { if constexpr (type == Type::CPU) {
untracked_words[index] |= mask; untracked[index] |= mask;
} }
} else { } else {
state_words[index] &= ~mask; state_words[index] &= ~mask;
if constexpr (type == Type::CPU) { if constexpr (type == Type::CPU) {
untracked_words[index] &= ~mask; untracked[index] &= ~mask;
} }
} }
}); });
@ -255,10 +154,10 @@ public:
*/ */
template <Type type, bool clear, typename Func> template <Type type, bool clear, typename Func>
void ForEachModifiedRange(VAddr query_cpu_range, s64 size, Func&& func) { void ForEachModifiedRange(VAddr query_cpu_range, s64 size, Func&& func) {
std::scoped_lock lk{lock};
static_assert(type != Type::Untracked); static_assert(type != Type::Untracked);
std::span<u64> state_words = words.template Span<type>(); std::span<u64> state_words = Span<type>();
[[maybe_unused]] std::span<u64> untracked_words = words.template Span<Type::Untracked>();
const size_t offset = query_cpu_range - cpu_addr; const size_t offset = query_cpu_range - cpu_addr;
bool pending = false; bool pending = false;
size_t pending_offset{}; size_t pending_offset{};
@ -269,16 +168,16 @@ public:
}; };
IterateWords(offset, size, [&](size_t index, u64 mask) { IterateWords(offset, size, [&](size_t index, u64 mask) {
if constexpr (type == Type::GPU) { if constexpr (type == Type::GPU) {
mask &= ~untracked_words[index]; mask &= ~untracked[index];
} }
const u64 word = state_words[index] & mask; const u64 word = state_words[index] & mask;
if constexpr (clear) { if constexpr (clear) {
if constexpr (type == Type::CPU) { if constexpr (type == Type::CPU) {
NotifyPageTracker<true>(index, untracked_words[index], mask); UpdateProtection<true>(index, untracked[index], mask);
} }
state_words[index] &= ~mask; state_words[index] &= ~mask;
if constexpr (type == Type::CPU) { if constexpr (type == Type::CPU) {
untracked_words[index] &= ~mask; untracked[index] &= ~mask;
} }
} }
const size_t base_offset = index * PAGES_PER_WORD; const size_t base_offset = index * PAGES_PER_WORD;
@ -315,13 +214,11 @@ public:
[[nodiscard]] bool IsRegionModified(u64 offset, u64 size) const noexcept { [[nodiscard]] bool IsRegionModified(u64 offset, u64 size) const noexcept {
static_assert(type != Type::Untracked); static_assert(type != Type::Untracked);
const std::span<const u64> state_words = words.template Span<type>(); const std::span<const u64> state_words = Span<type>();
[[maybe_unused]] const std::span<const u64> untracked_words =
words.template Span<Type::Untracked>();
bool result = false; bool result = false;
IterateWords(offset, size, [&](size_t index, u64 mask) { IterateWords(offset, size, [&](size_t index, u64 mask) {
if constexpr (type == Type::GPU) { if constexpr (type == Type::GPU) {
mask &= ~untracked_words[index]; mask &= ~untracked[index];
} }
const u64 word = state_words[index] & mask; const u64 word = state_words[index] & mask;
if (word != 0) { if (word != 0) {
@ -333,44 +230,7 @@ public:
return result; return result;
} }
/// Returns the number of words of the manager
[[nodiscard]] size_t NumWords() const noexcept {
return words.NumWords();
}
/// Returns the size in bytes of the manager
[[nodiscard]] u64 SizeBytes() const noexcept {
return words.size_bytes;
}
/// Returns true when the buffer fits in the small vector optimization
[[nodiscard]] bool IsShort() const noexcept {
return words.IsShort();
}
private: private:
template <Type type>
u64* Array() noexcept {
if constexpr (type == Type::CPU) {
return words.cpu.Pointer(IsShort());
} else if constexpr (type == Type::GPU) {
return words.gpu.Pointer(IsShort());
} else if constexpr (type == Type::Untracked) {
return words.untracked.Pointer(IsShort());
}
}
template <Type type>
const u64* Array() const noexcept {
if constexpr (type == Type::CPU) {
return words.cpu.Pointer(IsShort());
} else if constexpr (type == Type::GPU) {
return words.gpu.Pointer(IsShort());
} else if constexpr (type == Type::Untracked) {
return words.untracked.Pointer(IsShort());
}
}
/** /**
* Notify tracker about changes in the CPU tracking state of a word in the buffer * Notify tracker about changes in the CPU tracking state of a word in the buffer
* *
@ -381,7 +241,7 @@ private:
* @tparam add_to_tracker True when the tracker should start tracking the new pages * @tparam add_to_tracker True when the tracker should start tracking the new pages
*/ */
template <bool add_to_tracker> template <bool add_to_tracker>
void NotifyPageTracker(u64 word_index, u64 current_bits, u64 new_bits) const { void UpdateProtection(u64 word_index, u64 current_bits, u64 new_bits) const {
u64 changed_bits = (add_to_tracker ? current_bits : ~current_bits) & new_bits; u64 changed_bits = (add_to_tracker ? current_bits : ~current_bits) & new_bits;
VAddr addr = cpu_addr + word_index * BYTES_PER_WORD; VAddr addr = cpu_addr + word_index * BYTES_PER_WORD;
IteratePages(changed_bits, [&](size_t offset, size_t size) { IteratePages(changed_bits, [&](size_t offset, size_t size) {
@ -390,9 +250,34 @@ private:
}); });
} }
template <Type type>
std::span<u64> Span() noexcept {
if constexpr (type == Type::CPU) {
return cpu;
} else if constexpr (type == Type::GPU) {
return gpu;
} else if constexpr (type == Type::Untracked) {
return untracked;
}
}
template <Type type>
std::span<const u64> Span() const noexcept {
if constexpr (type == Type::CPU) {
return cpu;
} else if constexpr (type == Type::GPU) {
return gpu;
} else if constexpr (type == Type::Untracked) {
return untracked;
}
}
Common::SpinLock lock;
PageManager* tracker; PageManager* tracker;
VAddr cpu_addr = 0; VAddr cpu_addr = 0;
Words<stack_words> words; WordsArray cpu;
WordsArray gpu;
WordsArray untracked;
}; };
} // namespace VideoCore } // namespace VideoCore

View File

@ -7,6 +7,7 @@ set(SHADER_FILES
detile_m32x1.comp detile_m32x1.comp
detile_m32x2.comp detile_m32x2.comp
detile_m32x4.comp detile_m32x4.comp
detile_macro8x1.comp
detile_macro32x1.comp detile_macro32x1.comp
detile_macro32x2.comp detile_macro32x2.comp
fs_tri.vert fs_tri.vert

View File

@ -20,7 +20,7 @@ layout(push_constant) uniform image_info {
} info; } info;
// Inverse morton LUT, small enough to fit into K$ // Inverse morton LUT, small enough to fit into K$
uint rmort[16] = { const uint rmort[16] = {
0x11011000, 0x31213020, 0x11011000, 0x31213020,
0x13031202, 0x33233222, 0x13031202, 0x33233222,
0x51415040, 0x71617060, 0x51415040, 0x71617060,

View File

@ -20,7 +20,7 @@ layout(push_constant) uniform image_info {
} info; } info;
// Inverse morton LUT, small enough to fit into K$ // Inverse morton LUT, small enough to fit into K$
uint rmort[16] = { const uint rmort[16] = {
0x11011000, 0x31213020, 0x11011000, 0x31213020,
0x13031202, 0x33233222, 0x13031202, 0x33233222,
0x51415040, 0x71617060, 0x51415040, 0x71617060,

View File

@ -20,7 +20,7 @@ layout(push_constant) uniform image_info {
} info; } info;
// Inverse morton LUT, small enough to fit into K$ // Inverse morton LUT, small enough to fit into K$
uint rmort[16] = { const uint rmort[16] = {
0x11011000, 0x31213020, 0x11011000, 0x31213020,
0x13031202, 0x33233222, 0x13031202, 0x33233222,
0x51415040, 0x71617060, 0x51415040, 0x71617060,

View File

@ -48,4 +48,4 @@ void main() {
uint dw_ofs_x = target_tile_x * 2 + col; // 2 = uints uint dw_ofs_x = target_tile_x * 2 + col; // 2 = uints
uint dw_ofs_y = (target_tile_y * MICRO_TILE_DIM + row) * tiles_per_pitch * 2; // 2 = uints uint dw_ofs_y = (target_tile_y * MICRO_TILE_DIM + row) * tiles_per_pitch * 2; // 2 = uints
out_data[dw_ofs_x + dw_ofs_y] = dst_tx; out_data[dw_ofs_x + dw_ofs_y] = dst_tx;
} }

View File

@ -25,7 +25,7 @@ layout(push_constant) uniform image_info {
#define TEXELS_PER_ELEMENT 2 #define TEXELS_PER_ELEMENT 2
// Inverse morton LUT, small enough to fit into K$ // Inverse morton LUT, small enough to fit into K$
uint rmort[16] = { const uint rmort[16] = {
0x11011000, 0x31213020, 0x11011000, 0x31213020,
0x13031202, 0x33233222, 0x13031202, 0x33233222,
0x51415040, 0x71617060, 0x51415040, 0x71617060,

View File

@ -21,46 +21,46 @@ layout(push_constant) uniform image_info {
} info; } info;
// Each LUT is 64 bytes, so should fit into K$ given tiled slices locality // Each LUT is 64 bytes, so should fit into K$ given tiled slices locality
const uint lut_32bpp[][64] = { const uint lut_32bpp[][16] = {
{ {
0x00, 0x01, 0x04, 0x05, 0x40, 0x41, 0x44, 0x45, 0x05040100, 0x45444140,
0x02, 0x03, 0x06, 0x07, 0x42, 0x43, 0x46, 0x47, 0x07060302, 0x47464342,
0x10, 0x11, 0x14, 0x15, 0x50, 0x51, 0x54, 0x55, 0x15141110, 0x55545150,
0x12, 0x13, 0x16, 0x17, 0x52, 0x53, 0x56, 0x57, 0x17161312, 0x57565352,
0x80, 0x81, 0x84, 0x85, 0xc0, 0xc1, 0xc4, 0xc5, 0x85848180, 0xc5c4c1c0,
0x82, 0x83, 0x86, 0x87, 0xc2, 0xc3, 0xc6, 0xc7, 0x87868382, 0xc7c6c3c2,
0x90, 0x91, 0x94, 0x95, 0xd0, 0xd1, 0xd4, 0xd5, 0x95949190, 0xd5d4d1d0,
0x92, 0x93, 0x96, 0x97, 0xd2, 0xd3, 0xd6, 0xd7, 0x97969392, 0xd7d6d3d2,
}, },
{ {
0x08, 0x09, 0x0c, 0x0d, 0x48, 0x49, 0x4c, 0x4d, 0x0d0c0908, 0x4d4c4948,
0x0a, 0x0b, 0x0e, 0x0f, 0x4a, 0x4b, 0x4e, 0x4f, 0x0f0e0b0a, 0x4f4e4b4a,
0x18, 0x19, 0x1c, 0x1d, 0x58, 0x59, 0x5c, 0x5d, 0x1d1c1918, 0x5d5c5958,
0x1a, 0x1b, 0x1e, 0x1f, 0x5a, 0x5b, 0x5e, 0x5f, 0x1f1e1b1a, 0x5f5e5b5a,
0x88, 0x89, 0x8c, 0x8d, 0xc8, 0xc9, 0xcc, 0xcd, 0x8d8c8988, 0xcdccc9c8,
0x8a, 0x8b, 0x8e, 0x8f, 0xca, 0xcb, 0xce, 0xcf, 0x8f8e8b8a, 0xcfcecbca,
0x98, 0x99, 0x9c, 0x9d, 0xd8, 0xd9, 0xdc, 0xdd, 0x9d9c9998, 0xdddcd9d8,
0x9a, 0x9b, 0x9e, 0x9f, 0xda, 0xdb, 0xde, 0xdf, 0x9f9e9b9a, 0xdfdedbda,
}, },
{ {
0x20, 0x21, 0x24, 0x25, 0x60, 0x61, 0x64, 0x65, 0x25242120, 0x65646160,
0x22, 0x23, 0x26, 0x27, 0x62, 0x63, 0x66, 0x67, 0x27262322, 0x67666362,
0x30, 0x31, 0x34, 0x35, 0x70, 0x71, 0x74, 0x75, 0x35343130, 0x75747170,
0x32, 0x33, 0x36, 0x37, 0x72, 0x73, 0x76, 0x77, 0x37363332, 0x77767372,
0xa0, 0xa1, 0xa4, 0xa5, 0xe0, 0xe1, 0xe4, 0xe5, 0xa5a4a1a0, 0xe5e4e1e0,
0xa2, 0xa3, 0xa6, 0xa7, 0xe2, 0xe3, 0xe6, 0xe7, 0xa7a6a3a2, 0xe7e6e3e2,
0xb0, 0xb1, 0xb4, 0xb5, 0xf0, 0xf1, 0xf4, 0xf5, 0xb5b4b1b0, 0xf5f4f1f0,
0xb2, 0xb3, 0xb6, 0xb7, 0xf2, 0xf3, 0xf6, 0xf7, 0xb7b6b3b2, 0xf7f6f3f2,
}, },
{ {
0x28, 0x29, 0x2c, 0x2d, 0x68, 0x69, 0x6c, 0x6d, 0x2d2c2928, 0x6d6c6968,
0x2a, 0x2b, 0x2e, 0x2f, 0x6a, 0x6b, 0x6e, 0x6f, 0x2f2e2b2a, 0x6f6e6b6a,
0x38, 0x39, 0x3c, 0x3d, 0x78, 0x79, 0x7c, 0x7d, 0x3d3c3938, 0x7d7c7978,
0x3a, 0x3b, 0x3e, 0x3f, 0x7a, 0x7b, 0x7e, 0x7f, 0x3f3e3b3a, 0x7f7e7b7a,
0xa8, 0xa9, 0xac, 0xad, 0xe8, 0xe9, 0xec, 0xed, 0xadaca9a8, 0xedece9e8,
0xaa, 0xab, 0xae, 0xaf, 0xea, 0xeb, 0xee, 0xef, 0xafaeabaa, 0xefeeebea,
0xb8, 0xb9, 0xbc, 0xbd, 0xf8, 0xf9, 0xfc, 0xfd, 0xbdbcb9b8, 0xfdfcf9f8,
0xba, 0xbb, 0xbe, 0xbf, 0xfa, 0xfb, 0xfe, 0xff, 0xbfbebbba, 0xfffefbfa,
} }
}; };
@ -77,7 +77,9 @@ void main() {
uint col = bitfieldExtract(x, 0, 3); uint col = bitfieldExtract(x, 0, 3);
uint row = bitfieldExtract(y, 0, 3); uint row = bitfieldExtract(y, 0, 3);
uint lut = bitfieldExtract(z, 0, 2); uint lut = bitfieldExtract(z, 0, 2);
uint idx = lut_32bpp[lut][col + row * MICRO_TILE_DIM]; uint idx_dw = lut_32bpp[lut][(col + row * MICRO_TILE_DIM) >> 2u];
uint byte_ofs = gl_LocalInvocationID.x & 3u;
uint idx = bitfieldExtract(idx_dw >> (8 * byte_ofs), 0, 8);
uint slice_offs = (z >> 2u) * info.c1 * MICRO_TILE_SZ; uint slice_offs = (z >> 2u) * info.c1 * MICRO_TILE_SZ;
uint tile_row = y / MICRO_TILE_DIM; uint tile_row = y / MICRO_TILE_DIM;

View File

@ -20,46 +20,46 @@ layout(push_constant) uniform image_info {
uint c1; uint c1;
} info; } info;
const uint lut_64bpp[][64] = { const uint lut_64bpp[][16] = {
{ {
0x00, 0x01, 0x08, 0x09, 0x40, 0x41, 0x48, 0x49, 0x09080100, 0x49484140,
0x02, 0x03, 0x0a, 0x0b, 0x42, 0x43, 0x4a, 0x4b, 0x0b0a0302, 0x4a4b4342,
0x10, 0x11, 0x18, 0x19, 0x50, 0x51, 0x58, 0x59, 0x19181110, 0x59585150,
0x12, 0x13, 0x1a, 0x1b, 0x52, 0x53, 0x5a, 0x5b, 0x1b1a1312, 0x5a5b5352,
0x80, 0x81, 0x88, 0x89, 0xc0, 0xc1, 0xc8, 0xc9, 0x89888180, 0xc9c8c1c0,
0x82, 0x83, 0x8a, 0x8b, 0xc2, 0xc3, 0xca, 0xcb, 0x8b8a8382, 0xcacbc3c2,
0x90, 0x91, 0x98, 0x99, 0xd0, 0xd1, 0xd8, 0xd9, 0x99989190, 0xd9d8d1d0,
0x92, 0x93, 0x9a, 0x9b, 0xd2, 0xd3, 0xda, 0xdb, 0x9b9a9392, 0xdbdad3d2,
}, },
{ {
0x04, 0x05, 0x0c, 0x0d, 0x44, 0x45, 0x4c, 0x4d, 0x0d0c0504, 0x4d4c4544,
0x06, 0x07, 0x0e, 0x0f, 0x46, 0x47, 0x4e, 0x4f, 0x0f0e0706, 0x4f4e4746,
0x14, 0x15, 0x1c, 0x1d, 0x54, 0x55, 0x5c, 0x5d, 0x1d1c1514, 0x5d5c5554,
0x16, 0x17, 0x1e, 0x1f, 0x56, 0x57, 0x5e, 0x5f, 0x1f1e1716, 0x5f5e5756,
0x84, 0x85, 0x8c, 0x8d, 0xc4, 0xc5, 0xcc, 0xcd, 0x8d8c8584, 0xcdccc5c4,
0x86, 0x87, 0x8e, 0x8f, 0xc6, 0xc7, 0xce, 0xcf, 0x8f8e8786, 0xcfcec7c6,
0x94, 0x95, 0x9c, 0x9d, 0xd4, 0xd5, 0xdc, 0xdd, 0x9d9c9594, 0xdddcd5d4,
0x96, 0x97, 0x9e, 0x9f, 0xd6, 0xd7, 0xde, 0xdf, 0x9f9e9796, 0xdfded7d6,
}, },
{ {
0x20, 0x21, 0x28, 0x29, 0x60, 0x61, 0x68, 0x69, 0x29282120, 0x69686160,
0x22, 0x23, 0x2a, 0x2b, 0x62, 0x63, 0x6a, 0x6b, 0x2b2a2322, 0x6b6a6362,
0x30, 0x31, 0x38, 0x39, 0x70, 0x71, 0x78, 0x79, 0x39383130, 0x79787170,
0x32, 0x33, 0x3a, 0x3b, 0x72, 0x73, 0x7a, 0x7b, 0x3b3a3332, 0x7b7a7372,
0xa0, 0xa1, 0xa8, 0xa9, 0xe0, 0xe1, 0xe8, 0xe9, 0xa9a8a1a0, 0xe9e8e1e0,
0xa2, 0xa3, 0xaa, 0xab, 0xe2, 0xe3, 0xea, 0xeb, 0xabaaa3a2, 0xebeae3e2,
0xb0, 0xb1, 0xb8, 0xb9, 0xf0, 0xf1, 0xf8, 0xf9, 0xb9b8b1b0, 0xf9f8f1f0,
0xb2, 0xb3, 0xba, 0xbb, 0xf2, 0xf3, 0xfa, 0xfb, 0xbbbab3b2, 0xfbfaf3f2,
}, },
{ {
0x24, 0x25, 0x2c, 0x2d, 0x64, 0x65, 0x6c, 0x6d, 0x2d2c2524, 0x6d6c6564,
0x26, 0x27, 0x2e, 0x2f, 0x66, 0x67, 0x6e, 0x6f, 0x2f2e2726, 0x6f6e6766,
0x34, 0x35, 0x3c, 0x3d, 0x74, 0x75, 0x7c, 0x7d, 0x3d3c3534, 0x7d7c7574,
0x36, 0x37, 0x3e, 0x3f, 0x76, 0x77, 0x7e, 0x7f, 0x3f3e3736, 0x7f7e7776,
0xa4, 0xa5, 0xac, 0xad, 0xe4, 0xe5, 0xec, 0xed, 0xadaca5a4, 0xedece5e4,
0xa6, 0xa7, 0xae, 0xaf, 0xe6, 0xe7, 0xee, 0xef, 0xafaea7a6, 0xefeee7e6,
0xb4, 0xb5, 0xbc, 0xbd, 0xf4, 0xf5, 0xfc, 0xfd, 0xbdbcb5b4, 0xfdfcf5f4,
0xb6, 0xb7, 0xbe, 0xbf, 0xf6, 0xf7, 0xfe, 0xff, 0xbfbeb7b6, 0xfffef7f6,
}, },
}; };
@ -76,7 +76,9 @@ void main() {
uint col = bitfieldExtract(x, 0, 3); uint col = bitfieldExtract(x, 0, 3);
uint row = bitfieldExtract(y, 0, 3); uint row = bitfieldExtract(y, 0, 3);
uint lut = bitfieldExtract(z, 0, 2); uint lut = bitfieldExtract(z, 0, 2);
uint idx = lut_64bpp[lut][col + row * MICRO_TILE_DIM]; uint idx_dw = lut_64bpp[lut][(col + row * MICRO_TILE_DIM) >> 2u];
uint byte_ofs = gl_LocalInvocationID.x & 3u;
uint idx = bitfieldExtract(idx_dw >> (8 * byte_ofs), 0, 8);
uint slice_offs = (z >> 2u) * info.c1 * MICRO_TILE_SZ; uint slice_offs = (z >> 2u) * info.c1 * MICRO_TILE_SZ;
uint tile_row = y / MICRO_TILE_DIM; uint tile_row = y / MICRO_TILE_DIM;
@ -85,7 +87,7 @@ void main() {
uint offs = slice_offs + tile_offs + (idx * BPP / 8); uint offs = slice_offs + tile_offs + (idx * BPP / 8);
uint p0 = in_data[(offs >> 2) + 0]; uint p0 = in_data[(offs >> 2) + 0];
uint p1 = in_data[(offs >> 2) + 1]; uint p1 = in_data[(offs >> 2) + 1];
out_data[2 * gl_GlobalInvocationID.x + 0] = p0; out_data[2 * gl_GlobalInvocationID.x + 0] = p0;
out_data[2 * gl_GlobalInvocationID.x + 1] = p1; out_data[2 * gl_GlobalInvocationID.x + 1] = p1;
} }

View File

@ -0,0 +1,101 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#version 450
layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
layout(std430, binding = 0) buffer input_buf {
uint in_data[];
};
layout(std430, binding = 1) buffer output_buf {
uint out_data[];
};
layout(push_constant) uniform image_info {
uint num_levels;
uint pitch;
uint height;
uint c0;
uint c1;
} info;
const uint lut_8bpp[][16] = {
{
0x05040100, 0x45444140,
0x07060302, 0x47464342,
0x0d0c0908, 0x4d4c4948,
0x0f0e0b0a, 0x4f4e4b4a,
0x85848180, 0xc5c4c1c0,
0x87868382, 0xc7c6c3c2,
0x8d8c8988, 0xcdccc9c8,
0x8f8e8b8a, 0xcfcecbca,
},
{
0x15141110, 0x55545150,
0x17161312, 0x57565352,
0x1d1c1918, 0x5d5c5958,
0x1f1e1b1a, 0x5f5e5b5a,
0x95949190, 0xd5d4d1d0,
0x97969392, 0xd7d6d3d2,
0x9d9c9998, 0xdddcd9d8,
0x9f9e9b9a, 0xdfdedbda,
},
{
0x25242120, 0x65646160,
0x27262322, 0x67666362,
0x2d2c2928, 0x6d6c6968,
0x2f2e2b2a, 0x6f6e6b6a,
0xa5a4a1a0, 0xe5e4e1e0,
0xa7a6a3a2, 0xe7e6e3e2,
0xadaca9a8, 0xedece9e8,
0xafaeabaa, 0xefeeebea,
},
{
0x35343130, 0x75747170,
0x37363332, 0x77767372,
0x3d3c3938, 0x7d7c7978,
0x3f3e3b3a, 0x7f7e7b7a,
0xb5b4b1b0, 0xf5f4f1f0,
0xb7b6b3b2, 0xf7f6f3f2,
0xbdbcb9b8, 0xfdfcf9f8,
0xbfbebbba, 0xfffefbfa,
},
};
#define MICRO_TILE_DIM (8)
#define MICRO_TILE_SZ (256)
#define TEXELS_PER_ELEMENT (1)
#define BPP (8)
shared uint scratch[16];
void main() {
uint slot = gl_LocalInvocationID.x >> 2u;
atomicAnd(scratch[slot], 0);
uint x = gl_GlobalInvocationID.x % info.pitch;
uint y = (gl_GlobalInvocationID.x / info.pitch) % info.height;
uint z = gl_GlobalInvocationID.x / (info.pitch * info.height);
uint col = bitfieldExtract(x, 0, 3);
uint row = bitfieldExtract(y, 0, 3);
uint lut = bitfieldExtract(z, 0, 2);
uint idx_dw = lut_8bpp[lut][(col + row * MICRO_TILE_DIM) >> 2u];
uint byte_ofs = (gl_LocalInvocationID.x & 3u) * 8;
uint idx = bitfieldExtract(idx_dw >> byte_ofs, 0, 8);
uint slice_offs = (z >> 2u) * info.c1 * MICRO_TILE_SZ;
uint tile_row = y / MICRO_TILE_DIM;
uint tile_column = x / MICRO_TILE_DIM;
uint tile_offs = ((tile_row * info.c0) + tile_column) * MICRO_TILE_SZ;
uint offs = (slice_offs + tile_offs) + (idx * BPP / 8);
uint p0 = in_data[offs >> 2u];
uint byte = bitfieldExtract(p0 >> (offs * 8), 0, 8);
atomicOr(scratch[slot], byte << byte_ofs);
if (byte_ofs == 0) {
out_data[gl_GlobalInvocationID.x >> 2u] = scratch[slot];
}
}

View File

@ -39,6 +39,15 @@ public:
return &(*first_level_map[l1_page])[l2_page]; return &(*first_level_map[l1_page])[l2_page];
} }
[[nodiscard]] const Entry* find(size_t page) const {
const size_t l1_page = page >> SecondLevelBits;
const size_t l2_page = page & (NumEntriesPerL1Page - 1);
if (!first_level_map[l1_page]) {
return nullptr;
}
return &(*first_level_map[l1_page])[l2_page];
}
[[nodiscard]] const Entry& operator[](size_t page) const { [[nodiscard]] const Entry& operator[](size_t page) const {
const size_t l1_page = page >> SecondLevelBits; const size_t l1_page = page >> SecondLevelBits;
const size_t l2_page = page & (NumEntriesPerL1Page - 1); const size_t l2_page = page & (NumEntriesPerL1Page - 1);

View File

@ -185,7 +185,7 @@ void PageManager::OnGpuUnmap(VAddr address, size_t size) {
void PageManager::UpdatePagesCachedCount(VAddr addr, u64 size, s32 delta) { void PageManager::UpdatePagesCachedCount(VAddr addr, u64 size, s32 delta) {
static constexpr u64 PageShift = 12; static constexpr u64 PageShift = 12;
std::scoped_lock lk{mutex}; std::scoped_lock lk{lock};
const u64 num_pages = ((addr + size - 1) >> PageShift) - (addr >> PageShift) + 1; const u64 num_pages = ((addr + size - 1) >> PageShift) - (addr >> PageShift) + 1;
const u64 page_start = addr >> PageShift; const u64 page_start = addr >> PageShift;
const u64 page_end = page_start + num_pages; const u64 page_end = page_start + num_pages;

View File

@ -4,8 +4,8 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <mutex>
#include <boost/icl/interval_map.hpp> #include <boost/icl/interval_map.hpp>
#include "common/spin_lock.h"
#include "common/types.h" #include "common/types.h"
namespace Vulkan { namespace Vulkan {
@ -35,8 +35,8 @@ private:
struct Impl; struct Impl;
std::unique_ptr<Impl> impl; std::unique_ptr<Impl> impl;
Vulkan::Rasterizer* rasterizer; Vulkan::Rasterizer* rasterizer;
std::mutex mutex;
boost::icl::interval_map<VAddr, s32> cached_pages; boost::icl::interval_map<VAddr, s32> cached_pages;
Common::SpinLock lock;
}; };
} // namespace VideoCore } // namespace VideoCore

View File

@ -691,16 +691,40 @@ std::span<const SurfaceFormatInfo> SurfaceFormats() {
return formats; return formats;
} }
// Table 8.13 Data and Image Formats [Sea Islands Series Instruction Set Architecture]
static const size_t amd_gpu_data_format_bit_size = 6; // All values are under 64
static const size_t amd_gpu_number_format_bit_size = 4; // All values are under 16
static size_t GetSurfaceFormatTableIndex(AmdGpu::DataFormat data_format,
AmdGpu::NumberFormat num_format) {
DEBUG_ASSERT(u32(data_format) < 1 << amd_gpu_data_format_bit_size);
DEBUG_ASSERT(u32(num_format) < 1 << amd_gpu_number_format_bit_size);
size_t result = static_cast<size_t>(num_format) |
(static_cast<size_t>(data_format) << amd_gpu_number_format_bit_size);
return result;
}
static auto surface_format_table = []() constexpr {
std::array<vk::Format, 1 << amd_gpu_data_format_bit_size * 1 << amd_gpu_number_format_bit_size>
result;
for (auto& entry : result) {
entry = vk::Format::eUndefined;
}
for (const auto& supported_format : SurfaceFormats()) {
result[GetSurfaceFormatTableIndex(supported_format.data_format,
supported_format.number_format)] =
supported_format.vk_format;
}
return result;
}();
vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat num_format) { vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat num_format) {
const auto& formats = SurfaceFormats(); vk::Format result = surface_format_table[GetSurfaceFormatTableIndex(data_format, num_format)];
const auto format = bool found =
std::find_if(formats.begin(), formats.end(), [&](const SurfaceFormatInfo& format_info) { result != vk::Format::eUndefined || data_format == AmdGpu::DataFormat::FormatInvalid;
return format_info.data_format == data_format && ASSERT_MSG(found, "Unknown data_format={} and num_format={}", static_cast<u32>(data_format),
format_info.number_format == num_format; static_cast<u32>(num_format));
}); return result;
ASSERT_MSG(format != formats.end(), "Unknown data_format={} and num_format={}",
static_cast<u32>(data_format), static_cast<u32>(num_format));
return format->vk_format;
} }
static constexpr DepthFormatInfo CreateDepthFormatInfo( static constexpr DepthFormatInfo CreateDepthFormatInfo(
@ -746,8 +770,8 @@ vk::Format DepthFormat(DepthBuffer::ZFormat z_format, DepthBuffer::StencilFormat
vk::ClearValue ColorBufferClearValue(const AmdGpu::Liverpool::ColorBuffer& color_buffer) { vk::ClearValue ColorBufferClearValue(const AmdGpu::Liverpool::ColorBuffer& color_buffer) {
const auto comp_swizzle = color_buffer.Swizzle(); const auto comp_swizzle = color_buffer.Swizzle();
const auto format = color_buffer.DataFormat(); const auto format = color_buffer.GetDataFmt();
const auto number_type = color_buffer.NumFormat(); const auto number_type = color_buffer.GetNumberFmt();
const auto& c0 = color_buffer.clear_word0; const auto& c0 = color_buffer.clear_word0;
const auto& c1 = color_buffer.clear_word1; const auto& c1 = color_buffer.clear_word1;

View File

@ -328,8 +328,8 @@ bool PipelineCache::RefreshGraphicsKey() {
} }
key.color_formats[remapped_cb] = key.color_formats[remapped_cb] =
LiverpoolToVK::SurfaceFormat(col_buf.DataFormat(), col_buf.NumFormat()); LiverpoolToVK::SurfaceFormat(col_buf.GetDataFmt(), col_buf.GetNumberFmt());
key.color_num_formats[remapped_cb] = col_buf.NumFormat(); key.color_num_formats[remapped_cb] = col_buf.GetNumberFmt();
key.color_swizzles[remapped_cb] = col_buf.Swizzle(); key.color_swizzles[remapped_cb] = col_buf.Swizzle();
} }

View File

@ -562,6 +562,12 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding
push_data.AddOffset(binding.buffer, adjust); push_data.AddOffset(binding.buffer, adjust);
buffer_infos.emplace_back(vk_buffer->Handle(), offset_aligned, buffer_infos.emplace_back(vk_buffer->Handle(), offset_aligned,
vsharp.GetSize() + adjust); vsharp.GetSize() + adjust);
if (auto barrier =
vk_buffer->GetBarrier(desc.is_written ? vk::AccessFlagBits2::eShaderWrite
: vk::AccessFlagBits2::eShaderRead,
vk::PipelineStageFlagBits2::eAllCommands)) {
buffer_barriers.emplace_back(*barrier);
}
} }
set_writes.push_back({ set_writes.push_back({
@ -600,7 +606,7 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding
if (auto barrier = if (auto barrier =
vk_buffer->GetBarrier(desc.is_written ? vk::AccessFlagBits2::eShaderWrite vk_buffer->GetBarrier(desc.is_written ? vk::AccessFlagBits2::eShaderWrite
: vk::AccessFlagBits2::eShaderRead, : vk::AccessFlagBits2::eShaderRead,
vk::PipelineStageFlagBits2::eComputeShader)) { vk::PipelineStageFlagBits2::eAllCommands)) {
buffer_barriers.emplace_back(*barrier); buffer_barriers.emplace_back(*barrier);
} }
if (desc.is_written) { if (desc.is_written) {

View File

@ -265,9 +265,9 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer,
const AmdGpu::Liverpool::CbDbExtent& hint /*= {}*/) noexcept { const AmdGpu::Liverpool::CbDbExtent& hint /*= {}*/) noexcept {
props.is_tiled = buffer.IsTiled(); props.is_tiled = buffer.IsTiled();
tiling_mode = buffer.GetTilingMode(); tiling_mode = buffer.GetTilingMode();
pixel_format = LiverpoolToVK::SurfaceFormat(buffer.DataFormat(), buffer.NumFormat()); pixel_format = LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt());
num_samples = buffer.NumSamples(); num_samples = buffer.NumSamples();
num_bits = NumBits(buffer.DataFormat()); num_bits = NumBits(buffer.GetDataFmt());
type = vk::ImageType::e2D; type = vk::ImageType::e2D;
size.width = hint.Valid() ? hint.width : buffer.Pitch(); size.width = hint.Valid() ? hint.width : buffer.Pitch();
size.height = hint.Valid() ? hint.height : buffer.Height(); size.height = hint.Valid() ? hint.height : buffer.Height();

View File

@ -76,7 +76,8 @@ ImageViewInfo::ImageViewInfo(const AmdGpu::Liverpool::ColorBuffer& col_buffer) n
range.base.layer = col_buffer.view.slice_start; range.base.layer = col_buffer.view.slice_start;
range.extent.layers = col_buffer.NumSlices() - range.base.layer; range.extent.layers = col_buffer.NumSlices() - range.base.layer;
type = range.extent.layers > 1 ? vk::ImageViewType::e2DArray : vk::ImageViewType::e2D; type = range.extent.layers > 1 ? vk::ImageViewType::e2DArray : vk::ImageViewType::e2D;
format = Vulkan::LiverpoolToVK::SurfaceFormat(col_buffer.DataFormat(), col_buffer.NumFormat()); format =
Vulkan::LiverpoolToVK::SurfaceFormat(col_buffer.GetDataFmt(), col_buffer.GetNumberFmt());
} }
ImageViewInfo::ImageViewInfo(const AmdGpu::Liverpool::DepthBuffer& depth_buffer, ImageViewInfo::ImageViewInfo(const AmdGpu::Liverpool::DepthBuffer& depth_buffer,

View File

@ -542,31 +542,62 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
sched_ptr->EndRendering(); sched_ptr->EndRendering();
const auto cmdbuf = sched_ptr->CommandBuffer(); const auto cmdbuf = sched_ptr->CommandBuffer();
image.Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite, {},
cmdbuf);
const VAddr image_addr = image.info.guest_address; const VAddr image_addr = image.info.guest_address;
const size_t image_size = image.info.guest_size_bytes; const size_t image_size = image.info.guest_size_bytes;
const auto [vk_buffer, buf_offset] = const auto [vk_buffer, buf_offset] =
buffer_cache.ObtainViewBuffer(image_addr, image_size, is_gpu_dirty); buffer_cache.ObtainViewBuffer(image_addr, image_size, is_gpu_dirty);
// The obtained buffer may be written by a shader so we need to emit a barrier to prevent RAW // The obtained buffer may be written by a shader so we need to emit a barrier to prevent RAW
// hazard // hazard
if (auto barrier = vk_buffer->GetBarrier(vk::AccessFlagBits2::eTransferRead, if (auto barrier = vk_buffer->GetBarrier(vk::AccessFlagBits2::eTransferRead,
vk::PipelineStageFlagBits2::eTransfer)) { vk::PipelineStageFlagBits2::eTransfer)) {
const auto dependencies = vk::DependencyInfo{ cmdbuf.pipelineBarrier2(vk::DependencyInfo{
.dependencyFlags = vk::DependencyFlagBits::eByRegion, .dependencyFlags = vk::DependencyFlagBits::eByRegion,
.bufferMemoryBarrierCount = 1, .bufferMemoryBarrierCount = 1,
.pBufferMemoryBarriers = &barrier.value(), .pBufferMemoryBarriers = &barrier.value(),
}; });
cmdbuf.pipelineBarrier2(dependencies);
} }
const auto [buffer, offset] = tile_manager.TryDetile(vk_buffer->Handle(), buf_offset, image); const auto [buffer, offset] =
tile_manager.TryDetile(vk_buffer->Handle(), buf_offset, image.info);
for (auto& copy : image_copy) { for (auto& copy : image_copy) {
copy.bufferOffset += offset; copy.bufferOffset += offset;
} }
const vk::BufferMemoryBarrier2 pre_barrier{
.srcStageMask = vk::PipelineStageFlagBits2::eAllCommands,
.srcAccessMask = vk::AccessFlagBits2::eMemoryWrite,
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
.dstAccessMask = vk::AccessFlagBits2::eTransferRead,
.buffer = buffer,
.offset = offset,
.size = image_size,
};
const vk::BufferMemoryBarrier2 post_barrier{
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
.dstStageMask = vk::PipelineStageFlagBits2::eAllCommands,
.dstAccessMask = vk::AccessFlagBits2::eMemoryRead | vk::AccessFlagBits2::eMemoryWrite,
.buffer = buffer,
.offset = offset,
.size = image_size,
};
const auto image_barriers =
image.GetBarriers(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite,
vk::PipelineStageFlagBits2::eTransfer, {});
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
.bufferMemoryBarrierCount = 1,
.pBufferMemoryBarriers = &pre_barrier,
.imageMemoryBarrierCount = static_cast<u32>(image_barriers.size()),
.pImageMemoryBarriers = image_barriers.data(),
});
cmdbuf.copyBufferToImage(buffer, image.image, vk::ImageLayout::eTransferDstOptimal, image_copy); cmdbuf.copyBufferToImage(buffer, image.image, vk::ImageLayout::eTransferDstOptimal, image_copy);
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
.bufferMemoryBarrierCount = 1,
.pBufferMemoryBarriers = &post_barrier,
});
image.flags &= ~ImageFlagBits::Dirty; image.flags &= ~ImageFlagBits::Dirty;
} }

View File

@ -4,6 +4,7 @@
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/texture_cache/image_info.h"
#include "video_core/texture_cache/image_view.h" #include "video_core/texture_cache/image_view.h"
#include "video_core/texture_cache/tile_manager.h" #include "video_core/texture_cache/tile_manager.h"
@ -14,6 +15,7 @@
#include "video_core/host_shaders/detile_m8x2_comp.h" #include "video_core/host_shaders/detile_m8x2_comp.h"
#include "video_core/host_shaders/detile_macro32x1_comp.h" #include "video_core/host_shaders/detile_macro32x1_comp.h"
#include "video_core/host_shaders/detile_macro32x2_comp.h" #include "video_core/host_shaders/detile_macro32x2_comp.h"
#include "video_core/host_shaders/detile_macro8x1_comp.h"
#include <boost/container/static_vector.hpp> #include <boost/container/static_vector.hpp>
#include <magic_enum/magic_enum.hpp> #include <magic_enum/magic_enum.hpp>
@ -32,6 +34,7 @@ static vk::Format DemoteImageFormatForDetiling(vk::Format format) {
case vk::Format::eR5G5B5A1UnormPack16: case vk::Format::eR5G5B5A1UnormPack16:
case vk::Format::eR8G8Unorm: case vk::Format::eR8G8Unorm:
case vk::Format::eR16Sfloat: case vk::Format::eR16Sfloat:
case vk::Format::eR16Uint:
case vk::Format::eR16Unorm: case vk::Format::eR16Unorm:
case vk::Format::eD16Unorm: case vk::Format::eD16Unorm:
return vk::Format::eR8G8Uint; return vk::Format::eR8G8Uint;
@ -85,10 +88,10 @@ static vk::Format DemoteImageFormatForDetiling(vk::Format format) {
return format; return format;
} }
const DetilerContext* TileManager::GetDetiler(const Image& image) const { const DetilerContext* TileManager::GetDetiler(const ImageInfo& info) const {
const auto format = DemoteImageFormatForDetiling(image.info.pixel_format); const auto format = DemoteImageFormatForDetiling(info.pixel_format);
switch (image.info.tiling_mode) { switch (info.tiling_mode) {
case AmdGpu::TilingMode::Texture_MicroTiled: case AmdGpu::TilingMode::Texture_MicroTiled:
switch (format) { switch (format) {
case vk::Format::eR8Uint: case vk::Format::eR8Uint:
@ -106,6 +109,8 @@ const DetilerContext* TileManager::GetDetiler(const Image& image) const {
} }
case AmdGpu::TilingMode::Texture_Volume: case AmdGpu::TilingMode::Texture_Volume:
switch (format) { switch (format) {
case vk::Format::eR8Uint:
return &detilers[DetilerType::Macro8x1];
case vk::Format::eR32Uint: case vk::Format::eR32Uint:
return &detilers[DetilerType::Macro32x1]; return &detilers[DetilerType::Macro32x1];
case vk::Format::eR32G32Uint: case vk::Format::eR32G32Uint:
@ -131,8 +136,8 @@ TileManager::TileManager(const Vulkan::Instance& instance, Vulkan::Scheduler& sc
static const std::array detiler_shaders{ static const std::array detiler_shaders{
HostShaders::DETILE_M8X1_COMP, HostShaders::DETILE_M8X2_COMP, HostShaders::DETILE_M8X1_COMP, HostShaders::DETILE_M8X2_COMP,
HostShaders::DETILE_M32X1_COMP, HostShaders::DETILE_M32X2_COMP, HostShaders::DETILE_M32X1_COMP, HostShaders::DETILE_M32X2_COMP,
HostShaders::DETILE_M32X4_COMP, HostShaders::DETILE_MACRO32X1_COMP, HostShaders::DETILE_M32X4_COMP, HostShaders::DETILE_MACRO8X1_COMP,
HostShaders::DETILE_MACRO32X2_COMP, HostShaders::DETILE_MACRO32X1_COMP, HostShaders::DETILE_MACRO32X2_COMP,
}; };
boost::container::static_vector<vk::DescriptorSetLayoutBinding, 2> bindings{ boost::container::static_vector<vk::DescriptorSetLayoutBinding, 2> bindings{
@ -257,23 +262,23 @@ void TileManager::FreeBuffer(ScratchBuffer buffer) {
} }
std::pair<vk::Buffer, u32> TileManager::TryDetile(vk::Buffer in_buffer, u32 in_offset, std::pair<vk::Buffer, u32> TileManager::TryDetile(vk::Buffer in_buffer, u32 in_offset,
Image& image) { const ImageInfo& info) {
if (!image.info.props.is_tiled) { if (!info.props.is_tiled) {
return {in_buffer, in_offset}; return {in_buffer, in_offset};
} }
const auto* detiler = GetDetiler(image); const auto* detiler = GetDetiler(info);
if (!detiler) { if (!detiler) {
if (image.info.tiling_mode != AmdGpu::TilingMode::Texture_MacroTiled && if (info.tiling_mode != AmdGpu::TilingMode::Texture_MacroTiled &&
image.info.tiling_mode != AmdGpu::TilingMode::Display_MacroTiled && info.tiling_mode != AmdGpu::TilingMode::Display_MacroTiled &&
image.info.tiling_mode != AmdGpu::TilingMode::Depth_MacroTiled) { info.tiling_mode != AmdGpu::TilingMode::Depth_MacroTiled) {
LOG_ERROR(Render_Vulkan, "Unsupported tiled image: {} ({})", LOG_ERROR(Render_Vulkan, "Unsupported tiled image: {} ({})",
vk::to_string(image.info.pixel_format), NameOf(image.info.tiling_mode)); vk::to_string(info.pixel_format), NameOf(info.tiling_mode));
} }
return {in_buffer, in_offset}; return {in_buffer, in_offset};
} }
const u32 image_size = image.info.guest_size_bytes; const u32 image_size = info.guest_size_bytes;
// Prepare output buffer // Prepare output buffer
auto out_buffer = AllocBuffer(image_size, true); auto out_buffer = AllocBuffer(image_size, true);
@ -316,22 +321,20 @@ std::pair<vk::Buffer, u32> TileManager::TryDetile(vk::Buffer in_buffer, u32 in_o
set_writes); set_writes);
DetilerParams params; DetilerParams params;
params.num_levels = image.info.resources.levels; params.num_levels = info.resources.levels;
params.pitch0 = image.info.pitch >> (image.info.props.is_block ? 2u : 0u); params.pitch0 = info.pitch >> (info.props.is_block ? 2u : 0u);
params.height = image.info.size.height; params.height = info.size.height;
if (image.info.tiling_mode == AmdGpu::TilingMode::Texture_Volume) { if (info.tiling_mode == AmdGpu::TilingMode::Texture_Volume) {
ASSERT(image.info.resources.levels == 1); ASSERT(info.resources.levels == 1);
ASSERT(image.info.num_bits >= 32); const auto tiles_per_row = info.pitch / 8u;
const auto tiles_per_row = image.info.pitch / 8u; const auto tiles_per_slice = tiles_per_row * ((info.size.height + 7u) / 8u);
const auto tiles_per_slice = tiles_per_row * ((image.info.size.height + 7u) / 8u);
params.sizes[0] = tiles_per_row; params.sizes[0] = tiles_per_row;
params.sizes[1] = tiles_per_slice; params.sizes[1] = tiles_per_slice;
} else { } else {
ASSERT(info.resources.levels <= 14);
ASSERT(image.info.resources.levels <= 14);
std::memset(&params.sizes, 0, sizeof(params.sizes)); std::memset(&params.sizes, 0, sizeof(params.sizes));
for (int m = 0; m < image.info.resources.levels; ++m) { for (int m = 0; m < info.resources.levels; ++m) {
params.sizes[m] = image.info.mips_layout[m].size * image.info.resources.layers + params.sizes[m] = info.mips_layout[m].size * info.resources.layers +
(m > 0 ? params.sizes[m - 1] : 0); (m > 0 ? params.sizes[m - 1] : 0);
} }
} }
@ -340,20 +343,9 @@ std::pair<vk::Buffer, u32> TileManager::TryDetile(vk::Buffer in_buffer, u32 in_o
&params); &params);
ASSERT((image_size % 64) == 0); ASSERT((image_size % 64) == 0);
const auto bpp = image.info.num_bits * (image.info.props.is_block ? 16u : 1u); const auto bpp = info.num_bits * (info.props.is_block ? 16u : 1u);
const auto num_tiles = image_size / (64 * (bpp / 8)); const auto num_tiles = image_size / (64 * (bpp / 8));
cmdbuf.dispatch(num_tiles, 1, 1); cmdbuf.dispatch(num_tiles, 1, 1);
const vk::BufferMemoryBarrier post_barrier{
.srcAccessMask = vk::AccessFlagBits::eShaderWrite,
.dstAccessMask = vk::AccessFlagBits::eTransferRead,
.buffer = out_buffer.first,
.size = image_size,
};
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits::eByRegion,
{}, post_barrier, {});
return {out_buffer.first, 0}; return {out_buffer.first, 0};
} }

View File

@ -5,11 +5,11 @@
#include "common/types.h" #include "common/types.h"
#include "video_core/buffer_cache/buffer.h" #include "video_core/buffer_cache/buffer.h"
#include "video_core/texture_cache/image.h"
namespace VideoCore { namespace VideoCore {
class TextureCache; class TextureCache;
struct ImageInfo;
enum DetilerType : u32 { enum DetilerType : u32 {
Micro8x1, Micro8x1,
@ -18,6 +18,7 @@ enum DetilerType : u32 {
Micro32x2, Micro32x2,
Micro32x4, Micro32x4,
Macro8x1,
Macro32x1, Macro32x1,
Macro32x2, Macro32x2,
@ -36,14 +37,15 @@ public:
TileManager(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler); TileManager(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler);
~TileManager(); ~TileManager();
std::pair<vk::Buffer, u32> TryDetile(vk::Buffer in_buffer, u32 in_offset, Image& image); std::pair<vk::Buffer, u32> TryDetile(vk::Buffer in_buffer, u32 in_offset,
const ImageInfo& info);
ScratchBuffer AllocBuffer(u32 size, bool is_storage = false); ScratchBuffer AllocBuffer(u32 size, bool is_storage = false);
void Upload(ScratchBuffer buffer, const void* data, size_t size); void Upload(ScratchBuffer buffer, const void* data, size_t size);
void FreeBuffer(ScratchBuffer buffer); void FreeBuffer(ScratchBuffer buffer);
private: private:
const DetilerContext* GetDetiler(const Image& image) const; const DetilerContext* GetDetiler(const ImageInfo& info) const;
private: private:
const Vulkan::Instance& instance; const Vulkan::Instance& instance;