mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-05 17:02:40 +00:00
Merge branch 'shadps4-emu:main' into Fix_PromoteFormatToDepth
This commit is contained in:
commit
7d02688f96
12
.github/ISSUE_TEMPLATE/game-bug-report.yaml
vendored
12
.github/ISSUE_TEMPLATE/game-bug-report.yaml
vendored
@ -13,7 +13,11 @@ body:
|
||||
**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).**
|
||||
|
||||
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.
|
||||
|
||||
@ -21,15 +25,15 @@ body:
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist
|
||||
label: Checklist (we expect you to perform these steps before opening the issue)
|
||||
options:
|
||||
- label: I have searched for a similar issue in this repository and did not find one.
|
||||
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.
|
||||
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
|
||||
- label: I have disabled all patches and cheats.
|
||||
- label: I have disabled all patches and cheats and the issue is still present.
|
||||
required: true
|
||||
- label: I have all the required [system modules](https://github.com/shadps4-emu/shadps4-game-compatibility?tab=readme-ov-file#informations) installed.
|
||||
required: true
|
||||
|
@ -67,6 +67,7 @@ static int cursorHideTimeout = 5; // 5 seconds (default)
|
||||
static bool separateupdatefolder = false;
|
||||
static bool compatibilityData = false;
|
||||
static bool checkCompatibilityOnStartup = false;
|
||||
static std::string trophyKey;
|
||||
|
||||
// Gui
|
||||
std::vector<std::filesystem::path> settings_install_dirs = {};
|
||||
@ -91,6 +92,14 @@ std::string emulator_language = "en";
|
||||
// Language
|
||||
u32 m_language = 1; // english
|
||||
|
||||
std::string getTrophyKey() {
|
||||
return trophyKey;
|
||||
}
|
||||
|
||||
void setTrophyKey(std::string key) {
|
||||
trophyKey = key;
|
||||
}
|
||||
|
||||
bool isNeoMode() {
|
||||
return isNeo;
|
||||
}
|
||||
@ -652,6 +661,11 @@ void load(const std::filesystem::path& path) {
|
||||
|
||||
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) {
|
||||
@ -712,6 +726,8 @@ void save(const std::filesystem::path& path) {
|
||||
data["Debug"]["DebugDump"] = isDebugDump;
|
||||
data["Debug"]["CollectShader"] = isShaderDebug;
|
||||
|
||||
data["Keys"]["TrophyKey"] = trophyKey;
|
||||
|
||||
std::vector<std::string> install_dirs;
|
||||
for (const auto& dirString : settings_install_dirs) {
|
||||
install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data});
|
||||
|
@ -15,6 +15,9 @@ void load(const std::filesystem::path& path);
|
||||
void save(const std::filesystem::path& path);
|
||||
void saveMainWindow(const std::filesystem::path& path);
|
||||
|
||||
std::string getTrophyKey();
|
||||
void setTrophyKey(std::string key);
|
||||
|
||||
bool isNeoMode();
|
||||
bool isFullscreenMode();
|
||||
bool getPlayBGM();
|
||||
|
@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
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> 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
|
||||
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt;
|
||||
|
||||
std::vector<CryptoPP::byte> trophyIv(16, 0);
|
||||
std::vector<CryptoPP::byte> trpKey(16);
|
||||
|
||||
encrypt.SetKeyWithIV(trophyKey.data(), trophyKey.size(), trophyIv.data());
|
||||
encrypt.ProcessData(trpKey.data(), NPcommID.data(), 16);
|
||||
|
||||
// step 2: decrypt efsm.
|
||||
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decrypt;
|
||||
decrypt.SetKeyWithIV(trpKey.data(), trpKey.size(), efsmIv.data());
|
||||
|
@ -32,7 +32,8 @@ public:
|
||||
void aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
|
||||
std::span<CryptoPP::byte> ciphertext,
|
||||
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);
|
||||
void PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
|
||||
std::span<const CryptoPP::byte, 16> seed,
|
||||
|
@ -66,7 +66,7 @@ void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
|
||||
"GetColorSliceSize()", buffer.GetColorSliceSize(),
|
||||
"GetTilingMode()", buffer.GetTilingMode(),
|
||||
"IsTiled()", buffer.IsTiled(),
|
||||
"NumFormat()", buffer.NumFormat()
|
||||
"NumFormat()", buffer.GetNumberFmt()
|
||||
);
|
||||
|
||||
// clang-format on
|
||||
|
@ -1,6 +1,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/path_util.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) {
|
||||
std::filesystem::path gameSysDir = trophyPath / "sce_sys/trophy/";
|
||||
if (!std::filesystem::exists(gameSysDir)) {
|
||||
LOG_CRITICAL(Common_Filesystem, "Game sce_sys directory doesn't exist");
|
||||
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)) {
|
||||
if (it.is_regular_file()) {
|
||||
GetNPcommID(trophyPath, index);
|
||||
@ -97,7 +115,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string tit
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
std::string xml_name = entry.entry_name;
|
||||
size_t pos = xml_name.find("ESFM");
|
||||
|
@ -3,13 +3,13 @@
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <stop_token>
|
||||
#include <thread>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/config.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/libraries/audio/audioout.h"
|
||||
#include "core/libraries/audio/audioout_backend.h"
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
namespace Libraries::AudioOut {
|
||||
|
||||
std::shared_mutex ports_mutex;
|
||||
std::mutex port_open_mutex{};
|
||||
std::array<PortOut, SCE_AUDIO_OUT_NUM_PORTS> ports_out{};
|
||||
|
||||
static std::unique_ptr<AudioOutBackend> audio;
|
||||
@ -93,17 +93,20 @@ int PS4_SYSV_ABI sceAudioOutClose(s32 handle) {
|
||||
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);
|
||||
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();
|
||||
std::free(port.output_buffer);
|
||||
port.output_buffer = nullptr;
|
||||
port.output_ready = false;
|
||||
port.impl = nullptr;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
@ -172,35 +175,34 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
std::scoped_lock lock(ports_mutex);
|
||||
const auto& port = ports_out.at(handle - 1);
|
||||
if (!port.impl) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
auto& port = ports_out.at(handle - 1);
|
||||
{
|
||||
std::unique_lock lock{port.mutex};
|
||||
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;
|
||||
}
|
||||
|
||||
@ -279,15 +281,16 @@ static void AudioOutputThread(PortOut* port, const std::stop_token& stop) {
|
||||
while (true) {
|
||||
timer.Start();
|
||||
{
|
||||
std::unique_lock lock{port->output_mutex};
|
||||
Common::CondvarWait(port->output_cv, lock, stop, [&] { return port->output_ready; });
|
||||
if (stop.stop_requested()) {
|
||||
break;
|
||||
std::unique_lock lock{port->mutex};
|
||||
if (port->output_cv.wait(lock, stop, [&] { return port->output_ready; })) {
|
||||
port->impl->Output(port->output_buffer);
|
||||
port->output_ready = false;
|
||||
}
|
||||
port->impl->Output(port->output_buffer);
|
||||
port->output_ready = false;
|
||||
}
|
||||
port->output_cv.notify_one();
|
||||
if (stop.stop_requested()) {
|
||||
break;
|
||||
}
|
||||
timer.End();
|
||||
}
|
||||
}
|
||||
@ -332,27 +335,30 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
std::scoped_lock lock{ports_mutex};
|
||||
std::unique_lock open_lock{port_open_mutex};
|
||||
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()) {
|
||||
LOG_ERROR(Lib_AudioOut, "Audio ports are full");
|
||||
return ORBIS_AUDIO_OUT_ERROR_PORT_FULL;
|
||||
}
|
||||
|
||||
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);
|
||||
{
|
||||
std::unique_lock port_lock(port->mutex);
|
||||
|
||||
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->output_ready = false;
|
||||
port->output_thread.Run(
|
||||
[port](const std::stop_token& stop) { AudioOutputThread(&*port, stop); });
|
||||
port->impl = audio->Open(*port);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -367,14 +373,13 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr) {
|
||||
}
|
||||
|
||||
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; });
|
||||
if (ptr != nullptr) {
|
||||
if (ptr != nullptr && port.IsOpen()) {
|
||||
std::memcpy(port.output_buffer, ptr, port.BufferSize());
|
||||
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;
|
||||
}
|
||||
|
||||
std::scoped_lock lock(ports_mutex);
|
||||
auto& port = ports_out.at(handle - 1);
|
||||
if (!port.impl) {
|
||||
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];
|
||||
{
|
||||
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];
|
||||
}
|
||||
}
|
||||
port.impl->SetVolume(port.volume);
|
||||
}
|
||||
|
||||
port.impl->SetVolume(port.volume);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "core/libraries/kernel/threads.h"
|
||||
@ -74,10 +76,10 @@ struct AudioFormatInfo {
|
||||
};
|
||||
|
||||
struct PortOut {
|
||||
std::mutex mutex;
|
||||
std::unique_ptr<PortBackend> impl{};
|
||||
|
||||
void* output_buffer;
|
||||
std::mutex output_mutex;
|
||||
std::condition_variable_any output_cv;
|
||||
bool output_ready;
|
||||
Kernel::Thread output_thread{};
|
||||
@ -88,6 +90,10 @@ struct PortOut {
|
||||
u32 buffer_frames;
|
||||
std::array<s32, 8> volume;
|
||||
|
||||
[[nodiscard]] bool IsOpen() const {
|
||||
return impl != nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 BufferSize() const {
|
||||
return buffer_frames * format_info.FrameSize();
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace Libraries::AudioOut {
|
||||
class SDLPortBackend : public PortBackend {
|
||||
public:
|
||||
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,
|
||||
// so set the sample frames hint to the number of frames per buffer.
|
||||
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());
|
||||
return;
|
||||
}
|
||||
queue_threshold = CalculateQueueThreshold();
|
||||
CalculateQueueThreshold();
|
||||
if (!SDL_SetAudioStreamInputChannelMap(stream, port.format_info.channel_layout.data(),
|
||||
port.format_info.num_channels)) {
|
||||
LOG_ERROR(Lib_AudioOut, "Failed to configure SDL audio stream channel map: {}",
|
||||
@ -71,9 +71,9 @@ public:
|
||||
queue_threshold);
|
||||
SDL_ClearAudioStream(stream);
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
@ -91,7 +91,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] u32 CalculateQueueThreshold() const {
|
||||
void CalculateQueueThreshold() {
|
||||
SDL_AudioSpec discard;
|
||||
int sdl_buffer_frames;
|
||||
if (!SDL_GetAudioDeviceFormat(SDL_GetAudioStreamDevice(stream), &discard,
|
||||
@ -100,13 +100,22 @@ private:
|
||||
SDL_GetError());
|
||||
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 buffer_size;
|
||||
u32 queue_threshold;
|
||||
SDL_AudioStream* stream;
|
||||
u32 guest_buffer_size;
|
||||
u32 host_buffer_size{};
|
||||
u32 queue_threshold{};
|
||||
SDL_AudioStream* stream{};
|
||||
};
|
||||
|
||||
std::unique_ptr<PortBackend> SDLAudioOut::Open(PortOut& port) {
|
||||
|
@ -505,6 +505,41 @@ int PS4_SYSV_ABI posix_munmap(void* addr, size_t len) {
|
||||
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) {
|
||||
LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, sceKernelAllocateDirectMemory);
|
||||
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("UqDGjXA5yUM", "libkernel", 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
|
||||
|
@ -55,6 +55,9 @@ public:
|
||||
stop.request_stop();
|
||||
Join();
|
||||
}
|
||||
thread = nullptr;
|
||||
func = nullptr;
|
||||
stop = std::stop_source{};
|
||||
}
|
||||
|
||||
static void* PS4_SYSV_ABI RunWrapper(void* arg) {
|
||||
|
@ -47,6 +47,8 @@
|
||||
#include "core/libraries/videodec/videodec.h"
|
||||
#include "core/libraries/videodec/videodec2.h"
|
||||
#include "core/libraries/videoout/video_out.h"
|
||||
#include "fiber/fiber.h"
|
||||
#include "jpeg/jpegenc.h"
|
||||
|
||||
namespace Libraries {
|
||||
|
||||
@ -93,6 +95,8 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
|
||||
Libraries::Videodec::RegisterlibSceVideodec(sym);
|
||||
Libraries::RazorCpu::RegisterlibSceRazorCpu(sym);
|
||||
Libraries::Move::RegisterlibSceMove(sym);
|
||||
Libraries::Fiber::RegisterlibSceFiber(sym);
|
||||
Libraries::JpegEnc::RegisterlibSceJpegEnc(sym);
|
||||
}
|
||||
|
||||
} // namespace Libraries
|
||||
|
@ -972,11 +972,8 @@ int PS4_SYSV_ABI sceNpGetGamePresenceStatusA() {
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetNpId(OrbisUserServiceUserId user_id, OrbisNpId* np_id) {
|
||||
LOG_INFO(Lib_NpManager, "user_id {}", user_id);
|
||||
const auto name = Config::getUserName();
|
||||
std::memset(np_id, 0, sizeof(OrbisNpId));
|
||||
name.copy(np_id->handle.data, sizeof(np_id->handle.data));
|
||||
return ORBIS_OK;
|
||||
LOG_DEBUG(Lib_NpManager, "user_id {}", user_id);
|
||||
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||
}
|
||||
|
||||
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) {
|
||||
LOG_DEBUG(Lib_NpManager, "user_id {}", user_id);
|
||||
const auto name = Config::getUserName();
|
||||
std::memset(online_id, 0, sizeof(OrbisNpOnlineId));
|
||||
name.copy(online_id->data, sizeof(online_id->data));
|
||||
return ORBIS_OK;
|
||||
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetParentalControlInfo() {
|
||||
|
@ -286,6 +286,7 @@ int PS4_SYSV_ABI scePadOutputReport() {
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
|
||||
LOG_TRACE(Lib_Pad, "called");
|
||||
int connected_count = 0;
|
||||
bool connected = false;
|
||||
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].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].orientation.x = 0.0f;
|
||||
pData[i].orientation.y = 0.0f;
|
||||
pData[i].orientation.z = 0.0f;
|
||||
pData[i].orientation.w = 1.0f;
|
||||
pData[i].acceleration.x = 0.0f;
|
||||
pData[i].acceleration.y = 0.0f;
|
||||
pData[i].acceleration.z = 0.0f;
|
||||
pData[i].angularVelocity.x = 0.0f;
|
||||
pData[i].angularVelocity.y = 0.0f;
|
||||
pData[i].angularVelocity.z = 0.0f;
|
||||
pData[i].acceleration.x = states[i].acceleration.x;
|
||||
pData[i].acceleration.y = states[i].acceleration.y;
|
||||
pData[i].acceleration.z = states[i].acceleration.z;
|
||||
pData[i].angularVelocity.x = states[i].angularVelocity.x;
|
||||
pData[i].angularVelocity.y = states[i].angularVelocity.y;
|
||||
pData[i].angularVelocity.z = states[i].angularVelocity.z;
|
||||
Input::GameController::CalculateOrientation(pData[i].acceleration, pData[i].angularVelocity,
|
||||
1.0f / controller->accel_poll_rate,
|
||||
pData[i].orientation);
|
||||
pData[i].touchData.touchNum =
|
||||
(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;
|
||||
@ -352,6 +352,7 @@ int PS4_SYSV_ABI scePadReadHistory() {
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
|
||||
LOG_TRACE(Lib_Pad, "called");
|
||||
if (handle == ORBIS_PAD_ERROR_DEVICE_NO_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->analogButtons.l2 = state.axes[static_cast<int>(Input::Axis::TriggerLeft)];
|
||||
pData->analogButtons.r2 = state.axes[static_cast<int>(Input::Axis::TriggerRight)];
|
||||
pData->orientation.x = 0;
|
||||
pData->orientation.y = 0;
|
||||
pData->orientation.z = 0;
|
||||
pData->orientation.w = 1;
|
||||
pData->acceleration.x = 0.0f;
|
||||
pData->acceleration.y = 0.0f;
|
||||
pData->acceleration.z = 0.0f;
|
||||
pData->angularVelocity.x = 0.0f;
|
||||
pData->angularVelocity.y = 0.0f;
|
||||
pData->angularVelocity.z = 0.0f;
|
||||
pData->acceleration.x = state.acceleration.x;
|
||||
pData->acceleration.y = state.acceleration.y;
|
||||
pData->acceleration.z = state.acceleration.z;
|
||||
pData->angularVelocity.x = state.angularVelocity.x;
|
||||
pData->angularVelocity.y = state.angularVelocity.y;
|
||||
pData->angularVelocity.z = state.angularVelocity.z;
|
||||
Input::GameController::CalculateOrientation(pData->acceleration, pData->angularVelocity,
|
||||
1.0f / controller->accel_poll_rate,
|
||||
pData->orientation);
|
||||
pData->touchData.touchNum =
|
||||
(state.touchpad[0].state ? 1 : 0) + (state.touchpad[1].state ? 1 : 0);
|
||||
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) {
|
||||
LOG_ERROR(Lib_Pad, "(STUBBED) called");
|
||||
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() {
|
||||
|
@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <span>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#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");
|
||||
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");
|
||||
auto data = getParam->data;
|
||||
if (data != nullptr) {
|
||||
@ -1502,8 +1499,14 @@ Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2*
|
||||
return Error::MEMORY_NOT_READY;
|
||||
}
|
||||
if (SaveMemory::IsSaving()) {
|
||||
LOG_TRACE(Lib_SaveData, "called while saving");
|
||||
return Error::BUSY_FOR_SAVING;
|
||||
int count = 0;
|
||||
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");
|
||||
auto data = setParam->data;
|
||||
@ -1584,8 +1587,8 @@ Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetu
|
||||
} else {
|
||||
SaveMemory::SetIcon(nullptr, 0);
|
||||
}
|
||||
SaveMemory::TriggerSaveWithoutEvent();
|
||||
}
|
||||
SaveMemory::TriggerSaveWithoutEvent();
|
||||
if (g_fw_ver >= ElfInfo::FW_45 && result != nullptr) {
|
||||
result->existedMemorySize = existed_size;
|
||||
}
|
||||
|
@ -10,327 +10,327 @@
|
||||
namespace Libraries::Usbd {
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdAllocTransfer() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdAttachKernelDriver() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdBulkTransfer() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdCancelTransfer() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdCheckConnected() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdClaimInterface() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdClearHalt() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdClose() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdControlTransfer() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdControlTransferGetData() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdControlTransferGetSetup() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdDetachKernelDriver() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdEventHandlerActive() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdEventHandlingOk() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdExit() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdFillBulkTransfer() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdFillControlSetup() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdFillControlTransfer() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdFillInterruptTransfer() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdFillIsoTransfer() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdFreeConfigDescriptor() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdFreeDeviceList() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdFreeTransfer() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetActiveConfigDescriptor() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetBusNumber() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetConfigDescriptor() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetConfigDescriptorByValue() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetConfiguration() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetDescriptor() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetDevice() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetDeviceAddress() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetDeviceDescriptor() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetDeviceList() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetDeviceSpeed() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetIsoPacketBuffer() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetMaxIsoPacketSize() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetMaxPacketSize() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetStringDescriptor() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdGetStringDescriptorAscii() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdHandleEvents() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdHandleEventsLocked() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdHandleEventsTimeout() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_DEBUG(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdInit() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return 0x80240005; // Skip
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdInterruptTransfer() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdKernelDriverActive() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdLockEvents() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdLockEventWaiters() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdOpen() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdOpenDeviceWithVidPid() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdRefDevice() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdReleaseInterface() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdResetDevice() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdSetConfiguration() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdSetInterfaceAltSetting() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdSetIsoPacketLengths() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdSubmitTransfer() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdTryLockEvents() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdUnlockEvents() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdUnlockEventWaiters() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdUnrefDevice() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceUsbdWaitForEvent() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI Func_65F6EF33E38FFF50() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI Func_97F056BAD90AADE7() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI Func_C55104A33B35B264() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI Func_D56B43060720B1E0() {
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
||||
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -52,8 +52,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle,
|
||||
Kernel::EqueueEvent event{};
|
||||
event.event.ident = u64(OrbisVideoOutEventId::Flip);
|
||||
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::Clear;
|
||||
event.event.flags = Kernel::SceKernelEvent::Flags::Add;
|
||||
event.event.udata = udata;
|
||||
event.event.fflags = 0;
|
||||
event.event.data = 0;
|
||||
@ -79,8 +78,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handl
|
||||
Kernel::EqueueEvent event{};
|
||||
event.event.ident = u64(OrbisVideoOutEventId::Vblank);
|
||||
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::Clear;
|
||||
event.event.flags = Kernel::SceKernelEvent::Flags::Add;
|
||||
event.event.udata = udata;
|
||||
event.event.fflags = 0;
|
||||
event.event.data = 0;
|
||||
|
@ -282,16 +282,14 @@ void Emulator::Run(const std::filesystem::path& file) {
|
||||
}
|
||||
|
||||
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},
|
||||
{"libSceFiber.sprx", &Libraries::Fiber::RegisterlibSceFiber},
|
||||
{"libSceUlt.sprx", nullptr},
|
||||
{"libSceJson.sprx", nullptr},
|
||||
{"libSceJson2.sprx", nullptr},
|
||||
{"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterlibSceLibcInternal},
|
||||
{"libSceDiscMap.sprx", &Libraries::DiscMap::RegisterlibSceDiscMap},
|
||||
{"libSceRtc.sprx", &Libraries::Rtc::RegisterlibSceRtc},
|
||||
{"libSceJpegEnc.sprx", &Libraries::JpegEnc::RegisterlibSceJpegEnc},
|
||||
{"libSceCesCs.sprx", nullptr},
|
||||
{"libSceFont.sprx", nullptr},
|
||||
{"libSceFontFt.sprx", nullptr},
|
||||
|
@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/kernel/time.h"
|
||||
#include "core/libraries/pad/pad.h"
|
||||
#include "input/controller.h"
|
||||
@ -116,6 +117,103 @@ void GameController::Axis(int id, Input::Axis axis, int value) {
|
||||
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) {
|
||||
if (m_sdl_gamepad != nullptr) {
|
||||
SDL_SetGamepadLED(m_sdl_gamepad, r, g, b);
|
||||
@ -149,6 +247,18 @@ void GameController::TryOpenSDLController() {
|
||||
int gamepad_count;
|
||||
SDL_JoystickID* gamepads = SDL_GetGamepads(&gamepad_count);
|
||||
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);
|
||||
|
||||
SetLightBarRGB(0, 0, 255);
|
||||
|
@ -33,6 +33,9 @@ struct State {
|
||||
u64 time = 0;
|
||||
int axes[static_cast<int>(Axis::AxisMax)] = {128, 128, 128, 128, 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) {
|
||||
@ -53,12 +56,21 @@ public:
|
||||
void CheckButton(int id, Libraries::Pad::OrbisPadButtonDataOffset button, bool isPressed);
|
||||
void AddState(const State& state);
|
||||
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);
|
||||
bool SetVibration(u8 smallMotor, u8 largeMotor);
|
||||
void SetTouchpadState(int touchIndex, bool touchDown, float x, float y);
|
||||
void TryOpenSDLController();
|
||||
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:
|
||||
struct StateInternal {
|
||||
bool obtained = false;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QProcess>
|
||||
#include <QProgressBar>
|
||||
#include <QPushButton>
|
||||
#include <QStandardPaths>
|
||||
#include <QString>
|
||||
@ -24,11 +25,9 @@
|
||||
#include <common/path_util.h>
|
||||
#include <common/scm_rev.h>
|
||||
#include <common/version.h>
|
||||
#include <qprogressbar.h>
|
||||
#include "check_update.h"
|
||||
|
||||
using namespace Common::FS;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
CheckUpdate::CheckUpdate(const bool showMessage, QWidget* parent)
|
||||
: 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(); });
|
||||
|
||||
autoUpdateCheckBox->setChecked(Config::autoUpdate());
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0))
|
||||
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);
|
||||
Config::setAutoUpdate(state == Qt::Checked);
|
||||
Config::save(user_dir / "config.toml");
|
||||
|
@ -3,22 +3,24 @@
|
||||
|
||||
#include <QCompleter>
|
||||
#include <QDirIterator>
|
||||
#include <QFileDialog>
|
||||
#include <QHoverEvent>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <common/version.h>
|
||||
#include "common/config.h"
|
||||
#include "common/version.h"
|
||||
#include "qt_gui/compatibility_info.h"
|
||||
#ifdef ENABLE_DISCORD_RPC
|
||||
#include "common/discord_rpc_handler.h"
|
||||
#include "common/singleton.h"
|
||||
#endif
|
||||
#ifdef ENABLE_UPDATER
|
||||
#include "check_update.h"
|
||||
#endif
|
||||
#include <toml.hpp>
|
||||
#include "background_music_player.h"
|
||||
#include "common/logging/backend.h"
|
||||
#include "common/logging/filter.h"
|
||||
#include "common/logging/formatter.h"
|
||||
#include "main_window.h"
|
||||
#include "settings_dialog.h"
|
||||
#include "ui_settings_dialog.h"
|
||||
QStringList languageNames = {"Arabic",
|
||||
@ -130,8 +132,13 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
||||
// GENERAL TAB
|
||||
{
|
||||
#ifdef ENABLE_UPDATER
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0))
|
||||
connect(ui->updateCheckBox, &QCheckBox::stateChanged, this,
|
||||
[](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,
|
||||
[](const QString& channel) { Config::setUpdateChannel(channel.toStdString()); });
|
||||
@ -150,7 +157,12 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
||||
emit CompatibilityChanged();
|
||||
});
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0))
|
||||
connect(ui->enableCompatibilityCheckBox, &QCheckBox::stateChanged, this, [this](int state) {
|
||||
#else
|
||||
connect(ui->enableCompatibilityCheckBox, &QCheckBox::checkStateChanged, this,
|
||||
[this](Qt::CheckState state) {
|
||||
#endif
|
||||
Config::setCompatibilityEnabled(state);
|
||||
emit CompatibilityChanged();
|
||||
});
|
||||
@ -201,6 +213,8 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
||||
ui->showSplashCheckBox->installEventFilter(this);
|
||||
ui->discordRPCCheckbox->installEventFilter(this);
|
||||
ui->userName->installEventFilter(this);
|
||||
ui->label_Trophy->installEventFilter(this);
|
||||
ui->trophyKeyLineEdit->installEventFilter(this);
|
||||
ui->logTypeGroupBox->installEventFilter(this);
|
||||
ui->logFilter->installEventFilter(this);
|
||||
#ifdef ENABLE_UPDATER
|
||||
@ -295,6 +309,9 @@ void SettingsDialog::LoadValuesFromConfig() {
|
||||
QString::fromStdString(toml::find_or<std::string>(data, "General", "logFilter", "")));
|
||||
ui->userNameLineEdit->setText(
|
||||
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->vkValidationCheckBox->setChecked(toml::find_or<bool>(data, "Vulkan", "validation", false));
|
||||
ui->vkSyncValidationCheckBox->setChecked(
|
||||
@ -358,7 +375,7 @@ void SettingsDialog::InitializeEmulatorLanguages() {
|
||||
idx++;
|
||||
}
|
||||
|
||||
connect(ui->emulatorLanguageComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
connect(ui->emulatorLanguageComboBox, &QComboBox::currentIndexChanged, this,
|
||||
&SettingsDialog::OnLanguageChanged);
|
||||
}
|
||||
|
||||
@ -407,6 +424,10 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
|
||||
text = tr("discordRPCCheckbox");
|
||||
} else if (elementName == "userName") {
|
||||
text = tr("userName");
|
||||
} else if (elementName == "label_Trophy") {
|
||||
text = tr("TrophyKey");
|
||||
} else if (elementName == "trophyKeyLineEdit") {
|
||||
text = tr("TrophyKey");
|
||||
} else if (elementName == "logTypeGroupBox") {
|
||||
text = tr("logTypeGroupBox");
|
||||
} else if (elementName == "logFilter") {
|
||||
@ -517,6 +538,7 @@ void SettingsDialog::UpdateSettings() {
|
||||
Config::setLogType(ui->logTypeComboBox->currentText().toStdString());
|
||||
Config::setLogFilter(ui->logFilterLineEdit->text().toStdString());
|
||||
Config::setUserName(ui->userNameLineEdit->text().toStdString());
|
||||
Config::setTrophyKey(ui->trophyKeyLineEdit->text().toStdString());
|
||||
Config::setCursorState(ui->hideCursorComboBox->currentIndex());
|
||||
Config::setCursorHideTimeout(ui->idleTimeoutSpinBox->value());
|
||||
Config::setGpuId(ui->graphicsAdapterBox->currentIndex() - 1);
|
||||
@ -578,4 +600,4 @@ void SettingsDialog::ResetInstallFolders() {
|
||||
}
|
||||
Config::setGameInstallDirs(settings_install_dirs_config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>950</width>
|
||||
<height>780</height>
|
||||
<width>970</width>
|
||||
<height>670</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -67,8 +67,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>822</width>
|
||||
<height>487</height>
|
||||
<width>946</width>
|
||||
<height>536</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="generalTabVLayout" stretch="0">
|
||||
@ -77,87 +77,7 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="2">
|
||||
<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">
|
||||
<item row="1" column="0">
|
||||
<layout class="QVBoxLayout" name="systemTabLayoutLeft">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="SystemSettings">
|
||||
@ -194,7 +114,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="emulatorTabLayoutMiddle">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="emulatorSettingsGroupBox">
|
||||
@ -268,10 +188,10 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="1" column="2">
|
||||
<layout class="QVBoxLayout" name="updaterTabLayoutLeft">
|
||||
<property name="spacing">
|
||||
<number>-1</number>
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
|
||||
@ -436,138 +356,8 @@
|
||||
</layout>
|
||||
</item>
|
||||
<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">
|
||||
<item alignment="Qt::AlignmentFlag::AlignTop">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="CompatgroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
@ -638,6 +428,160 @@
|
||||
</item>
|
||||
</layout>
|
||||
</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>
|
||||
</item>
|
||||
</layout>
|
||||
@ -655,8 +599,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>396</width>
|
||||
<height>222</height>
|
||||
<width>926</width>
|
||||
<height>536</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="inputTabVLayout" stretch="0,0">
|
||||
@ -946,8 +890,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>536</width>
|
||||
<height>192</height>
|
||||
<width>926</width>
|
||||
<height>536</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="graphicsTabVLayout" stretch="0,0">
|
||||
@ -1197,8 +1141,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>146</width>
|
||||
<height>215</height>
|
||||
<width>926</width>
|
||||
<height>536</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="pathsTabLayout" stretch="0">
|
||||
@ -1211,18 +1155,25 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeFolderButton">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addFolderButton">
|
||||
<property name="text">
|
||||
<string>Add...</string>
|
||||
</property>
|
||||
</widget>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addFolderButton">
|
||||
<property name="text">
|
||||
<string>Add...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeFolderButton">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="gameFoldersListWidget"/>
|
||||
@ -1263,71 +1214,145 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>288</width>
|
||||
<height>163</height>
|
||||
<width>926</width>
|
||||
<height>536</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="debugTabVLayout" stretch="0,1">
|
||||
<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>
|
||||
<widget class="QGroupBox" name="debugTabGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>General</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="debugTabLayout">
|
||||
<item alignment="Qt::AlignmentFlag::AlignTop">
|
||||
<widget class="QCheckBox" name="debugDump">
|
||||
<property name="text">
|
||||
<string>Enable Debug Dumping</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="vkValidationCheckBox">
|
||||
<property name="text">
|
||||
<string>Enable Vulkan Validation Layers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="vkSyncValidationCheckBox">
|
||||
<property name="text">
|
||||
<string>Enable Vulkan Synchronization Validation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="rdocCheckBox">
|
||||
<property name="text">
|
||||
<string>Enable RenderDoc Debugging</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="debugTabHLayout" stretch="1">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="debugTabGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>General</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="debugTabLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="debugDump">
|
||||
<property name="text">
|
||||
<string>Enable Debug Dumping</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="vkValidationCheckBox">
|
||||
<property name="text">
|
||||
<string>Enable Vulkan Validation Layers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="vkSyncValidationCheckBox">
|
||||
<property name="text">
|
||||
<string>Enable Vulkan Synchronization Validation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="rdocCheckBox">
|
||||
<property name="text">
|
||||
<string>Enable RenderDoc Debugging</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
</layout>
|
||||
</item>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>اسم المستخدم</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>اسم المستخدم:\nيضبط اسم حساب PS4، الذي قد يتم عرضه في بعض الألعاب.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Username</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Brugernavn:\nIndstiller PS4-kontoens navn, som kan blive vist i nogle spil.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Benutzername</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Benutzername:\nLegt den Namen des PS4-Kontos fest, der in einigen Spielen angezeigt werden kann.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Username</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Όνομα Χρήστη:\nΟρίζει το όνομα του λογαριασμού PS4, το οποίο μπορεί να εμφανιστεί σε ορισμένα παιχνίδια.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Username</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Username:\nSets the PS4's account username, which may be displayed by some games.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Nombre de usuario</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>نام کاربری</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>نام کاربری:\nنام کاربری حساب PS4 را تنظیم میکند که ممکن است توسط برخی بازیها نمایش داده شود.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Username</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Käyttäjänimi:\nAsettaa PS4-tilin käyttäjänimen, joka voi näkyä joissakin peleissä.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Nom d'utilisateur</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Nom d'utilisateur:\nDéfinit le nom d'utilisateur du compte PS4, qui peut être affiché par certains jeux.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Felhasználónév</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Username</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Nama Pengguna:\nMenetapkan nama pengguna akun PS4, yang mungkin ditampilkan oleh beberapa permainan.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Nome Utente</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Nome Utente:\nImposta il nome utente dell'account PS4, che potrebbe essere visualizzato da alcuni giochi.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>ユーザー名</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>ユーザー名:\nPS4のアカウントユーザー名を設定します。これは、一部のゲームで表示される場合があります。</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Username</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Username:\nSets the PS4's account username, which may be displayed by some games.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Username</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Vartotojo vardas:\nNustato PS4 paskyros vartotojo vardą, kuris gali būti rodomas kai kuriuose žaidimuose.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Brukernavn</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Brukernavn:\nAngir brukernavnet for PS4-kontoen, som kan vises av enkelte spill.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Username</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Gebruikersnaam:\nStelt de gebruikersnaam van het PS4-account in, die door sommige games kan worden weergegeven.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Nazwa użytkownika</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Nome de usuário</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Username</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Nume utilizator:\nSetează numele de utilizator al contului PS4, care poate fi afișat de unele jocuri.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Имя пользователя</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Имя пользователя:\nУстановите имя пользователя аккаунта PS4. Это может отображаться в некоторых играх.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Përdoruesi</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Përdoruesi:\nPërcakton emrin e përdoruesit të llogarisë PS4, i cili mund të shfaqet nga disa lojra.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Kullanıcı Adı</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Kullanıcı Adı:\nBazı oyunlar tarafından gösterilebilen PS4 hesabının kullanıcı adını ayarlar.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Ім'я користувача</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>Ім'я користувача:\nВстановіть ім'я користувача акаунта PS4. Це може відображатися в деяких іграх.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Username</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<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, có thể được một số trò chơi hiển thị.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>用户名</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>用户名:\n设置 PS4 帐户的用户名,某些游戏中可能会显示此名称。</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -537,6 +537,16 @@
|
||||
<source>Username</source>
|
||||
<translation>Username</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="178"/>
|
||||
<source>Logger</source>
|
||||
@ -1236,6 +1246,11 @@
|
||||
<source>userName</source>
|
||||
<translation>用戶名:\n設定PS4帳號的用戶名,某些遊戲中可能會顯示。</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="301"/>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -161,6 +161,20 @@ void WindowSDL::WaitEvent() {
|
||||
case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
|
||||
OnGamepadEvent(&event);
|
||||
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:
|
||||
is_open = false;
|
||||
break;
|
||||
|
@ -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)));
|
||||
ir.WriteShared(bit_size, ir.GetVectorReg(data0), addr0);
|
||||
}
|
||||
emit_ds_read_barrier = true;
|
||||
}
|
||||
|
||||
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,
|
||||
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))};
|
||||
IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
if (is_pair) {
|
||||
|
@ -308,7 +308,6 @@ private:
|
||||
const RuntimeInfo& runtime_info;
|
||||
const Profile& profile;
|
||||
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,
|
||||
|
@ -8,6 +8,54 @@
|
||||
|
||||
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) {
|
||||
if (!program.info.uses_shared || !profile.needs_lds_barriers) {
|
||||
return;
|
||||
@ -19,27 +67,12 @@ void SharedMemoryBarrierPass(IR::Program& program, const Profile& profile) {
|
||||
--branch_depth;
|
||||
continue;
|
||||
}
|
||||
if (node.type != Type::If) {
|
||||
if (node.type == Type::If && branch_depth++ == 0) {
|
||||
EmitBarrierInMergeBlock(node.data);
|
||||
continue;
|
||||
}
|
||||
u32 curr_depth = branch_depth++;
|
||||
if (curr_depth != 0) {
|
||||
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();
|
||||
if (node.type == Type::Block && branch_depth == 0) {
|
||||
EmitBarrierInBlock(node.data.block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -815,7 +815,8 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb, u32 vqid) {
|
||||
}
|
||||
if (rasterizer && (cs_program.dispatch_initiator & 1)) {
|
||||
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->ScopeMarkerEnd();
|
||||
}
|
||||
|
@ -889,11 +889,11 @@ struct Liverpool {
|
||||
return !info.linear_general;
|
||||
}
|
||||
|
||||
[[nodiscard]] DataFormat DataFormat() const {
|
||||
[[nodiscard]] DataFormat GetDataFmt() const {
|
||||
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.
|
||||
return RemapNumberFormat(info.number_type == NumberFormat::SnormNz
|
||||
? NumberFormat::Srgb
|
||||
|
@ -79,21 +79,23 @@ inline NumberFormat RemapNumberFormat(const NumberFormat format) {
|
||||
|
||||
inline CompMapping RemapComponents(const DataFormat format, const CompMapping components) {
|
||||
switch (format) {
|
||||
case DataFormat::Format11_11_10:
|
||||
return {
|
||||
.r = components.b,
|
||||
.g = components.g,
|
||||
.b = components.r,
|
||||
.a = components.a,
|
||||
};
|
||||
case DataFormat::Format11_11_10: {
|
||||
CompMapping result;
|
||||
result.r = components.b;
|
||||
result.g = components.g;
|
||||
result.b = components.r;
|
||||
result.a = components.a;
|
||||
return result;
|
||||
}
|
||||
case DataFormat::Format10_10_10_2:
|
||||
case DataFormat::Format5_5_5_1:
|
||||
return {
|
||||
.r = components.a,
|
||||
.g = components.b,
|
||||
.b = components.g,
|
||||
.a = components.r,
|
||||
};
|
||||
case DataFormat::Format5_5_5_1: {
|
||||
CompMapping result;
|
||||
result.r = components.a;
|
||||
result.g = components.b;
|
||||
result.b = components.g;
|
||||
result.a = components.r;
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
return components;
|
||||
}
|
||||
|
@ -54,18 +54,10 @@ BufferCache::BufferCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& s
|
||||
BufferCache::~BufferCache() = default;
|
||||
|
||||
void BufferCache::InvalidateMemory(VAddr device_addr, u64 size) {
|
||||
std::scoped_lock lk{mutex};
|
||||
const bool is_tracked = IsRegionRegistered(device_addr, size);
|
||||
if (!is_tracked) {
|
||||
return;
|
||||
}
|
||||
// Mark the page as CPU modified to stop tracking writes.
|
||||
SCOPE_EXIT {
|
||||
if (is_tracked) {
|
||||
// Mark the page as CPU modified to stop tracking writes.
|
||||
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);
|
||||
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,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eAllCommands,
|
||||
@ -279,9 +280,14 @@ void BufferCache::InlineData(VAddr address, const void* value, u32 num_bytes, bo
|
||||
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
|
||||
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
|
||||
.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) {
|
||||
@ -346,6 +352,7 @@ bool BufferCache::IsRegionRegistered(VAddr addr, size_t size) {
|
||||
++page;
|
||||
continue;
|
||||
}
|
||||
std::shared_lock lk{mutex};
|
||||
Buffer& buffer = slot_buffers[buffer_id];
|
||||
const VAddr buf_start_addr = buffer.CpuAddr();
|
||||
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();
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
static constexpr vk::MemoryBarrier READ_BARRIER{
|
||||
.srcAccessMask = vk::AccessFlagBits::eMemoryWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eTransferRead | vk::AccessFlagBits::eTransferWrite,
|
||||
const std::array pre_barriers = {
|
||||
vk::BufferMemoryBarrier2{
|
||||
.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{
|
||||
.srcAccessMask = vk::AccessFlagBits::eTransferWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
|
||||
const std::array post_barriers = {
|
||||
vk::BufferMemoryBarrier2{
|
||||
.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,
|
||||
vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits::eByRegion,
|
||||
READ_BARRIER, {}, {});
|
||||
cmdbuf.copyBuffer(overlap.buffer, new_buffer.buffer, copy);
|
||||
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::PipelineStageFlagBits::eAllCommands,
|
||||
vk::DependencyFlagBits::eByRegion, WRITE_BARRIER, {}, {});
|
||||
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
|
||||
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
|
||||
.bufferMemoryBarrierCount = 1,
|
||||
.pBufferMemoryBarriers = pre_barriers.data(),
|
||||
});
|
||||
cmdbuf.copyBuffer(overlap.Handle(), new_buffer.Handle(), copy);
|
||||
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
|
||||
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
|
||||
.bufferMemoryBarrierCount = static_cast<u32>(post_barriers.size()),
|
||||
.pBufferMemoryBarriers = post_barriers.data(),
|
||||
});
|
||||
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);
|
||||
const OverlapResult overlap = ResolveOverlaps(device_addr, wanted_size);
|
||||
const u32 size = static_cast<u32>(overlap.end - overlap.begin);
|
||||
const BufferId new_buffer_id = slot_buffers.insert(
|
||||
instance, scheduler, MemoryUsage::DeviceLocal, overlap.begin, AllFlags, size);
|
||||
const BufferId new_buffer_id = [&] {
|
||||
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];
|
||||
const size_t size_bytes = new_buffer.SizeBytes();
|
||||
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,
|
||||
bool is_texel_buffer) {
|
||||
std::scoped_lock lk{mutex};
|
||||
boost::container::small_vector<vk::BufferCopy, 4> copies;
|
||||
u64 total_size_bytes = 0;
|
||||
u64 largest_copy = 0;
|
||||
VAddr buffer_start = buffer.CpuAddr();
|
||||
memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) {
|
||||
copies.push_back(vk::BufferCopy{
|
||||
@ -549,7 +584,6 @@ void BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size,
|
||||
.size = range_size,
|
||||
});
|
||||
total_size_bytes += range_size;
|
||||
largest_copy = std::max(largest_copy, range_size);
|
||||
});
|
||||
SCOPE_EXIT {
|
||||
if (is_texel_buffer) {
|
||||
@ -590,21 +624,35 @@ void BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size,
|
||||
}
|
||||
scheduler.EndRendering();
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
static constexpr vk::MemoryBarrier READ_BARRIER{
|
||||
.srcAccessMask = vk::AccessFlagBits::eMemoryWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eTransferRead | vk::AccessFlagBits::eTransferWrite,
|
||||
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 = 0,
|
||||
.size = buffer.SizeBytes(),
|
||||
};
|
||||
static constexpr vk::MemoryBarrier WRITE_BARRIER{
|
||||
.srcAccessMask = vk::AccessFlagBits::eTransferWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
|
||||
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.Handle(),
|
||||
.offset = 0,
|
||||
.size = buffer.SizeBytes(),
|
||||
};
|
||||
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
|
||||
vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits::eByRegion,
|
||||
READ_BARRIER, {}, {});
|
||||
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
|
||||
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
|
||||
.bufferMemoryBarrierCount = 1,
|
||||
.pBufferMemoryBarriers = &pre_barrier,
|
||||
});
|
||||
cmdbuf.copyBuffer(src_buffer, buffer.buffer, copies);
|
||||
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::PipelineStageFlagBits::eAllCommands,
|
||||
vk::DependencyFlagBits::eByRegion, WRITE_BARRIER, {}, {});
|
||||
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
|
||||
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
|
||||
.bufferMemoryBarrierCount = 1,
|
||||
.pBufferMemoryBarriers = &post_barrier,
|
||||
});
|
||||
}
|
||||
|
||||
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()) {
|
||||
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();
|
||||
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);
|
||||
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
|
||||
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
|
||||
.bufferMemoryBarrierCount = 1,
|
||||
.pBufferMemoryBarriers = &post_barrier,
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <boost/icl/interval_map.hpp>
|
||||
#include <tsl/robin_map.h>
|
||||
@ -157,7 +157,7 @@ private:
|
||||
StreamBuffer staging_buffer;
|
||||
StreamBuffer stream_buffer;
|
||||
Buffer gds_buffer;
|
||||
std::mutex mutex;
|
||||
std::shared_mutex mutex;
|
||||
Common::SlotVector<Buffer> slot_buffers;
|
||||
RangeSet gpu_modified_ranges;
|
||||
vk::BufferView null_buffer_view;
|
||||
|
@ -15,13 +15,8 @@ namespace VideoCore {
|
||||
class MemoryTracker {
|
||||
public:
|
||||
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 MANAGER_POOL_SIZE = 32;
|
||||
static constexpr size_t WORDS_STACK_NEEDED = HIGHER_PAGE_SIZE / BYTES_PER_WORD;
|
||||
using Manager = WordManager<WORDS_STACK_NEEDED>;
|
||||
|
||||
public:
|
||||
explicit MemoryTracker(PageManager* tracker_) : tracker{tracker_} {}
|
||||
@ -30,7 +25,7 @@ public:
|
||||
/// Returns true if a region has been modified from the CPU
|
||||
[[nodiscard]] bool IsRegionCpuModified(VAddr query_cpu_addr, u64 query_size) noexcept {
|
||||
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);
|
||||
});
|
||||
}
|
||||
@ -38,52 +33,34 @@ public:
|
||||
/// Returns true if a region has been modified from the GPU
|
||||
[[nodiscard]] bool IsRegionGpuModified(VAddr query_cpu_addr, u64 query_size) noexcept {
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
/// Mark region as CPU modified, notifying the device_tracker about this change
|
||||
void MarkRegionAsCpuModified(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, true>(
|
||||
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);
|
||||
});
|
||||
IteratePages<false>(dirty_cpu_addr, query_size,
|
||||
[](RegionManager* manager, u64 offset, size_t size) {
|
||||
manager->template ChangeRegionState<Type::CPU, true>(
|
||||
manager->GetCpuAddr() + offset, size);
|
||||
});
|
||||
}
|
||||
|
||||
/// Mark region as modified from the host GPU
|
||||
void MarkRegionAsGpuModified(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, true>(
|
||||
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);
|
||||
});
|
||||
IteratePages<false>(dirty_cpu_addr, query_size,
|
||||
[](RegionManager* manager, u64 offset, size_t size) {
|
||||
manager->template ChangeRegionState<Type::GPU, true>(
|
||||
manager->GetCpuAddr() + offset, size);
|
||||
});
|
||||
}
|
||||
|
||||
/// Call 'func' for each CPU modified range and unmark those pages as CPU modified
|
||||
template <typename Func>
|
||||
void ForEachUploadRange(VAddr query_cpu_range, u64 query_size, Func&& func) {
|
||||
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->GetCpuAddr() + offset, size, func);
|
||||
});
|
||||
@ -93,7 +70,7 @@ public:
|
||||
template <bool clear, typename Func>
|
||||
void ForEachDownloadRange(VAddr query_cpu_range, u64 query_size, Func&& func) {
|
||||
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) {
|
||||
manager->template ForEachModifiedRange<Type::GPU, true>(
|
||||
manager->GetCpuAddr() + offset, size, func);
|
||||
@ -114,7 +91,7 @@ private:
|
||||
*/
|
||||
template <bool create_region_on_fail, typename 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>;
|
||||
std::size_t remaining_size{size};
|
||||
std::size_t page_index{cpu_address >> HIGHER_PAGE_BITS};
|
||||
@ -155,7 +132,7 @@ private:
|
||||
manager_pool.emplace_back();
|
||||
auto& last_pool = manager_pool.back();
|
||||
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]);
|
||||
}
|
||||
}
|
||||
@ -167,9 +144,9 @@ private:
|
||||
}
|
||||
|
||||
PageManager* tracker;
|
||||
std::deque<std::array<Manager, MANAGER_POOL_SIZE>> manager_pool;
|
||||
std::vector<Manager*> free_managers;
|
||||
std::array<Manager*, NUM_HIGH_PAGES> top_tier{};
|
||||
std::deque<std::array<RegionManager, MANAGER_POOL_SIZE>> manager_pool;
|
||||
std::vector<RegionManager*> free_managers;
|
||||
std::array<RegionManager*, NUM_HIGH_PAGES> top_tier{};
|
||||
};
|
||||
|
||||
} // namespace VideoCore
|
||||
|
@ -3,10 +3,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
#include <utility>
|
||||
#include "common/div_ceil.h"
|
||||
|
||||
#include "common/spin_lock.h"
|
||||
#include "common/types.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_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 {
|
||||
CPU,
|
||||
GPU,
|
||||
Untracked,
|
||||
};
|
||||
|
||||
/// Vector tracking modified pages tightly packed with small vector optimization
|
||||
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;
|
||||
}
|
||||
using WordsArray = std::array<u64, NUM_REGION_WORDS>;
|
||||
|
||||
/// Returns the pointer to the words state
|
||||
[[nodiscard]] u64* Pointer(bool is_short) noexcept {
|
||||
return is_short ? stack.data() : heap;
|
||||
}
|
||||
|
||||
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 {
|
||||
/**
|
||||
* Allows tracking CPU and GPU modification of pages in a contigious 4MB virtual address region.
|
||||
* Information is stored in bitsets for spacial locality and fast update of single pages.
|
||||
*/
|
||||
class RegionManager {
|
||||
public:
|
||||
explicit WordManager(PageManager* tracker_, VAddr cpu_addr_, u64 size_bytes)
|
||||
: tracker{tracker_}, cpu_addr{cpu_addr_}, words{size_bytes} {}
|
||||
|
||||
explicit WordManager() = default;
|
||||
explicit RegionManager(PageManager* tracker_, VAddr cpu_addr_)
|
||||
: tracker{tracker_}, cpu_addr{cpu_addr_} {
|
||||
cpu.fill(~u64{0});
|
||||
gpu.fill(0);
|
||||
untracked.fill(~u64{0});
|
||||
}
|
||||
explicit RegionManager() = default;
|
||||
|
||||
void SetCpuAddress(VAddr new_cpu_addr) {
|
||||
cpu_addr = new_cpu_addr;
|
||||
@ -175,12 +74,12 @@ public:
|
||||
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 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;
|
||||
}
|
||||
auto [start_word, start_page] = GetWordPage(start);
|
||||
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);
|
||||
end_word = std::min(end_word, num_words);
|
||||
const size_t diff = end_word - start_word;
|
||||
@ -225,21 +124,21 @@ public:
|
||||
*/
|
||||
template <Type type, bool enable>
|
||||
void ChangeRegionState(u64 dirty_addr, u64 size) noexcept(type == Type::GPU) {
|
||||
std::span<u64> state_words = words.template Span<type>();
|
||||
[[maybe_unused]] std::span<u64> untracked_words = words.template Span<Type::Untracked>();
|
||||
std::scoped_lock lk{lock};
|
||||
std::span<u64> state_words = Span<type>();
|
||||
IterateWords(dirty_addr - cpu_addr, size, [&](size_t index, u64 mask) {
|
||||
if constexpr (type == Type::CPU) {
|
||||
NotifyPageTracker<!enable>(index, untracked_words[index], mask);
|
||||
UpdateProtection<!enable>(index, untracked[index], mask);
|
||||
}
|
||||
if constexpr (enable) {
|
||||
state_words[index] |= mask;
|
||||
if constexpr (type == Type::CPU) {
|
||||
untracked_words[index] |= mask;
|
||||
untracked[index] |= mask;
|
||||
}
|
||||
} else {
|
||||
state_words[index] &= ~mask;
|
||||
if constexpr (type == Type::CPU) {
|
||||
untracked_words[index] &= ~mask;
|
||||
untracked[index] &= ~mask;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -255,10 +154,10 @@ public:
|
||||
*/
|
||||
template <Type type, bool clear, typename Func>
|
||||
void ForEachModifiedRange(VAddr query_cpu_range, s64 size, Func&& func) {
|
||||
std::scoped_lock lk{lock};
|
||||
static_assert(type != Type::Untracked);
|
||||
|
||||
std::span<u64> state_words = words.template Span<type>();
|
||||
[[maybe_unused]] std::span<u64> untracked_words = words.template Span<Type::Untracked>();
|
||||
std::span<u64> state_words = Span<type>();
|
||||
const size_t offset = query_cpu_range - cpu_addr;
|
||||
bool pending = false;
|
||||
size_t pending_offset{};
|
||||
@ -269,16 +168,16 @@ public:
|
||||
};
|
||||
IterateWords(offset, size, [&](size_t index, u64 mask) {
|
||||
if constexpr (type == Type::GPU) {
|
||||
mask &= ~untracked_words[index];
|
||||
mask &= ~untracked[index];
|
||||
}
|
||||
const u64 word = state_words[index] & mask;
|
||||
if constexpr (clear) {
|
||||
if constexpr (type == Type::CPU) {
|
||||
NotifyPageTracker<true>(index, untracked_words[index], mask);
|
||||
UpdateProtection<true>(index, untracked[index], mask);
|
||||
}
|
||||
state_words[index] &= ~mask;
|
||||
if constexpr (type == Type::CPU) {
|
||||
untracked_words[index] &= ~mask;
|
||||
untracked[index] &= ~mask;
|
||||
}
|
||||
}
|
||||
const size_t base_offset = index * PAGES_PER_WORD;
|
||||
@ -315,13 +214,11 @@ public:
|
||||
[[nodiscard]] bool IsRegionModified(u64 offset, u64 size) const noexcept {
|
||||
static_assert(type != Type::Untracked);
|
||||
|
||||
const std::span<const u64> state_words = words.template Span<type>();
|
||||
[[maybe_unused]] const std::span<const u64> untracked_words =
|
||||
words.template Span<Type::Untracked>();
|
||||
const std::span<const u64> state_words = Span<type>();
|
||||
bool result = false;
|
||||
IterateWords(offset, size, [&](size_t index, u64 mask) {
|
||||
if constexpr (type == Type::GPU) {
|
||||
mask &= ~untracked_words[index];
|
||||
mask &= ~untracked[index];
|
||||
}
|
||||
const u64 word = state_words[index] & mask;
|
||||
if (word != 0) {
|
||||
@ -333,44 +230,7 @@ public:
|
||||
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:
|
||||
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
|
||||
*
|
||||
@ -381,7 +241,7 @@ private:
|
||||
* @tparam add_to_tracker True when the tracker should start tracking the new pages
|
||||
*/
|
||||
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;
|
||||
VAddr addr = cpu_addr + word_index * BYTES_PER_WORD;
|
||||
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;
|
||||
VAddr cpu_addr = 0;
|
||||
Words<stack_words> words;
|
||||
WordsArray cpu;
|
||||
WordsArray gpu;
|
||||
WordsArray untracked;
|
||||
};
|
||||
|
||||
} // namespace VideoCore
|
||||
|
@ -7,6 +7,7 @@ set(SHADER_FILES
|
||||
detile_m32x1.comp
|
||||
detile_m32x2.comp
|
||||
detile_m32x4.comp
|
||||
detile_macro8x1.comp
|
||||
detile_macro32x1.comp
|
||||
detile_macro32x2.comp
|
||||
fs_tri.vert
|
||||
|
@ -20,7 +20,7 @@ layout(push_constant) uniform image_info {
|
||||
} info;
|
||||
|
||||
// Inverse morton LUT, small enough to fit into K$
|
||||
uint rmort[16] = {
|
||||
const uint rmort[16] = {
|
||||
0x11011000, 0x31213020,
|
||||
0x13031202, 0x33233222,
|
||||
0x51415040, 0x71617060,
|
||||
|
@ -20,7 +20,7 @@ layout(push_constant) uniform image_info {
|
||||
} info;
|
||||
|
||||
// Inverse morton LUT, small enough to fit into K$
|
||||
uint rmort[16] = {
|
||||
const uint rmort[16] = {
|
||||
0x11011000, 0x31213020,
|
||||
0x13031202, 0x33233222,
|
||||
0x51415040, 0x71617060,
|
||||
|
@ -20,7 +20,7 @@ layout(push_constant) uniform image_info {
|
||||
} info;
|
||||
|
||||
// Inverse morton LUT, small enough to fit into K$
|
||||
uint rmort[16] = {
|
||||
const uint rmort[16] = {
|
||||
0x11011000, 0x31213020,
|
||||
0x13031202, 0x33233222,
|
||||
0x51415040, 0x71617060,
|
||||
|
@ -48,4 +48,4 @@ void main() {
|
||||
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
|
||||
out_data[dw_ofs_x + dw_ofs_y] = dst_tx;
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ layout(push_constant) uniform image_info {
|
||||
#define TEXELS_PER_ELEMENT 2
|
||||
|
||||
// Inverse morton LUT, small enough to fit into K$
|
||||
uint rmort[16] = {
|
||||
const uint rmort[16] = {
|
||||
0x11011000, 0x31213020,
|
||||
0x13031202, 0x33233222,
|
||||
0x51415040, 0x71617060,
|
||||
|
@ -21,46 +21,46 @@ layout(push_constant) uniform image_info {
|
||||
} info;
|
||||
|
||||
// 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,
|
||||
0x02, 0x03, 0x06, 0x07, 0x42, 0x43, 0x46, 0x47,
|
||||
0x10, 0x11, 0x14, 0x15, 0x50, 0x51, 0x54, 0x55,
|
||||
0x12, 0x13, 0x16, 0x17, 0x52, 0x53, 0x56, 0x57,
|
||||
0x80, 0x81, 0x84, 0x85, 0xc0, 0xc1, 0xc4, 0xc5,
|
||||
0x82, 0x83, 0x86, 0x87, 0xc2, 0xc3, 0xc6, 0xc7,
|
||||
0x90, 0x91, 0x94, 0x95, 0xd0, 0xd1, 0xd4, 0xd5,
|
||||
0x92, 0x93, 0x96, 0x97, 0xd2, 0xd3, 0xd6, 0xd7,
|
||||
0x05040100, 0x45444140,
|
||||
0x07060302, 0x47464342,
|
||||
0x15141110, 0x55545150,
|
||||
0x17161312, 0x57565352,
|
||||
0x85848180, 0xc5c4c1c0,
|
||||
0x87868382, 0xc7c6c3c2,
|
||||
0x95949190, 0xd5d4d1d0,
|
||||
0x97969392, 0xd7d6d3d2,
|
||||
},
|
||||
{
|
||||
0x08, 0x09, 0x0c, 0x0d, 0x48, 0x49, 0x4c, 0x4d,
|
||||
0x0a, 0x0b, 0x0e, 0x0f, 0x4a, 0x4b, 0x4e, 0x4f,
|
||||
0x18, 0x19, 0x1c, 0x1d, 0x58, 0x59, 0x5c, 0x5d,
|
||||
0x1a, 0x1b, 0x1e, 0x1f, 0x5a, 0x5b, 0x5e, 0x5f,
|
||||
0x88, 0x89, 0x8c, 0x8d, 0xc8, 0xc9, 0xcc, 0xcd,
|
||||
0x8a, 0x8b, 0x8e, 0x8f, 0xca, 0xcb, 0xce, 0xcf,
|
||||
0x98, 0x99, 0x9c, 0x9d, 0xd8, 0xd9, 0xdc, 0xdd,
|
||||
0x9a, 0x9b, 0x9e, 0x9f, 0xda, 0xdb, 0xde, 0xdf,
|
||||
0x0d0c0908, 0x4d4c4948,
|
||||
0x0f0e0b0a, 0x4f4e4b4a,
|
||||
0x1d1c1918, 0x5d5c5958,
|
||||
0x1f1e1b1a, 0x5f5e5b5a,
|
||||
0x8d8c8988, 0xcdccc9c8,
|
||||
0x8f8e8b8a, 0xcfcecbca,
|
||||
0x9d9c9998, 0xdddcd9d8,
|
||||
0x9f9e9b9a, 0xdfdedbda,
|
||||
},
|
||||
{
|
||||
0x20, 0x21, 0x24, 0x25, 0x60, 0x61, 0x64, 0x65,
|
||||
0x22, 0x23, 0x26, 0x27, 0x62, 0x63, 0x66, 0x67,
|
||||
0x30, 0x31, 0x34, 0x35, 0x70, 0x71, 0x74, 0x75,
|
||||
0x32, 0x33, 0x36, 0x37, 0x72, 0x73, 0x76, 0x77,
|
||||
0xa0, 0xa1, 0xa4, 0xa5, 0xe0, 0xe1, 0xe4, 0xe5,
|
||||
0xa2, 0xa3, 0xa6, 0xa7, 0xe2, 0xe3, 0xe6, 0xe7,
|
||||
0xb0, 0xb1, 0xb4, 0xb5, 0xf0, 0xf1, 0xf4, 0xf5,
|
||||
0xb2, 0xb3, 0xb6, 0xb7, 0xf2, 0xf3, 0xf6, 0xf7,
|
||||
0x25242120, 0x65646160,
|
||||
0x27262322, 0x67666362,
|
||||
0x35343130, 0x75747170,
|
||||
0x37363332, 0x77767372,
|
||||
0xa5a4a1a0, 0xe5e4e1e0,
|
||||
0xa7a6a3a2, 0xe7e6e3e2,
|
||||
0xb5b4b1b0, 0xf5f4f1f0,
|
||||
0xb7b6b3b2, 0xf7f6f3f2,
|
||||
},
|
||||
{
|
||||
0x28, 0x29, 0x2c, 0x2d, 0x68, 0x69, 0x6c, 0x6d,
|
||||
0x2a, 0x2b, 0x2e, 0x2f, 0x6a, 0x6b, 0x6e, 0x6f,
|
||||
0x38, 0x39, 0x3c, 0x3d, 0x78, 0x79, 0x7c, 0x7d,
|
||||
0x3a, 0x3b, 0x3e, 0x3f, 0x7a, 0x7b, 0x7e, 0x7f,
|
||||
0xa8, 0xa9, 0xac, 0xad, 0xe8, 0xe9, 0xec, 0xed,
|
||||
0xaa, 0xab, 0xae, 0xaf, 0xea, 0xeb, 0xee, 0xef,
|
||||
0xb8, 0xb9, 0xbc, 0xbd, 0xf8, 0xf9, 0xfc, 0xfd,
|
||||
0xba, 0xbb, 0xbe, 0xbf, 0xfa, 0xfb, 0xfe, 0xff,
|
||||
0x2d2c2928, 0x6d6c6968,
|
||||
0x2f2e2b2a, 0x6f6e6b6a,
|
||||
0x3d3c3938, 0x7d7c7978,
|
||||
0x3f3e3b3a, 0x7f7e7b7a,
|
||||
0xadaca9a8, 0xedece9e8,
|
||||
0xafaeabaa, 0xefeeebea,
|
||||
0xbdbcb9b8, 0xfdfcf9f8,
|
||||
0xbfbebbba, 0xfffefbfa,
|
||||
}
|
||||
};
|
||||
|
||||
@ -77,7 +77,9 @@ void main() {
|
||||
uint col = bitfieldExtract(x, 0, 3);
|
||||
uint row = bitfieldExtract(y, 0, 3);
|
||||
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 tile_row = y / MICRO_TILE_DIM;
|
||||
|
@ -20,46 +20,46 @@ layout(push_constant) uniform image_info {
|
||||
uint c1;
|
||||
} info;
|
||||
|
||||
const uint lut_64bpp[][64] = {
|
||||
const uint lut_64bpp[][16] = {
|
||||
{
|
||||
0x00, 0x01, 0x08, 0x09, 0x40, 0x41, 0x48, 0x49,
|
||||
0x02, 0x03, 0x0a, 0x0b, 0x42, 0x43, 0x4a, 0x4b,
|
||||
0x10, 0x11, 0x18, 0x19, 0x50, 0x51, 0x58, 0x59,
|
||||
0x12, 0x13, 0x1a, 0x1b, 0x52, 0x53, 0x5a, 0x5b,
|
||||
0x80, 0x81, 0x88, 0x89, 0xc0, 0xc1, 0xc8, 0xc9,
|
||||
0x82, 0x83, 0x8a, 0x8b, 0xc2, 0xc3, 0xca, 0xcb,
|
||||
0x90, 0x91, 0x98, 0x99, 0xd0, 0xd1, 0xd8, 0xd9,
|
||||
0x92, 0x93, 0x9a, 0x9b, 0xd2, 0xd3, 0xda, 0xdb,
|
||||
0x09080100, 0x49484140,
|
||||
0x0b0a0302, 0x4a4b4342,
|
||||
0x19181110, 0x59585150,
|
||||
0x1b1a1312, 0x5a5b5352,
|
||||
0x89888180, 0xc9c8c1c0,
|
||||
0x8b8a8382, 0xcacbc3c2,
|
||||
0x99989190, 0xd9d8d1d0,
|
||||
0x9b9a9392, 0xdbdad3d2,
|
||||
},
|
||||
{
|
||||
0x04, 0x05, 0x0c, 0x0d, 0x44, 0x45, 0x4c, 0x4d,
|
||||
0x06, 0x07, 0x0e, 0x0f, 0x46, 0x47, 0x4e, 0x4f,
|
||||
0x14, 0x15, 0x1c, 0x1d, 0x54, 0x55, 0x5c, 0x5d,
|
||||
0x16, 0x17, 0x1e, 0x1f, 0x56, 0x57, 0x5e, 0x5f,
|
||||
0x84, 0x85, 0x8c, 0x8d, 0xc4, 0xc5, 0xcc, 0xcd,
|
||||
0x86, 0x87, 0x8e, 0x8f, 0xc6, 0xc7, 0xce, 0xcf,
|
||||
0x94, 0x95, 0x9c, 0x9d, 0xd4, 0xd5, 0xdc, 0xdd,
|
||||
0x96, 0x97, 0x9e, 0x9f, 0xd6, 0xd7, 0xde, 0xdf,
|
||||
0x0d0c0504, 0x4d4c4544,
|
||||
0x0f0e0706, 0x4f4e4746,
|
||||
0x1d1c1514, 0x5d5c5554,
|
||||
0x1f1e1716, 0x5f5e5756,
|
||||
0x8d8c8584, 0xcdccc5c4,
|
||||
0x8f8e8786, 0xcfcec7c6,
|
||||
0x9d9c9594, 0xdddcd5d4,
|
||||
0x9f9e9796, 0xdfded7d6,
|
||||
},
|
||||
{
|
||||
0x20, 0x21, 0x28, 0x29, 0x60, 0x61, 0x68, 0x69,
|
||||
0x22, 0x23, 0x2a, 0x2b, 0x62, 0x63, 0x6a, 0x6b,
|
||||
0x30, 0x31, 0x38, 0x39, 0x70, 0x71, 0x78, 0x79,
|
||||
0x32, 0x33, 0x3a, 0x3b, 0x72, 0x73, 0x7a, 0x7b,
|
||||
0xa0, 0xa1, 0xa8, 0xa9, 0xe0, 0xe1, 0xe8, 0xe9,
|
||||
0xa2, 0xa3, 0xaa, 0xab, 0xe2, 0xe3, 0xea, 0xeb,
|
||||
0xb0, 0xb1, 0xb8, 0xb9, 0xf0, 0xf1, 0xf8, 0xf9,
|
||||
0xb2, 0xb3, 0xba, 0xbb, 0xf2, 0xf3, 0xfa, 0xfb,
|
||||
0x29282120, 0x69686160,
|
||||
0x2b2a2322, 0x6b6a6362,
|
||||
0x39383130, 0x79787170,
|
||||
0x3b3a3332, 0x7b7a7372,
|
||||
0xa9a8a1a0, 0xe9e8e1e0,
|
||||
0xabaaa3a2, 0xebeae3e2,
|
||||
0xb9b8b1b0, 0xf9f8f1f0,
|
||||
0xbbbab3b2, 0xfbfaf3f2,
|
||||
},
|
||||
{
|
||||
0x24, 0x25, 0x2c, 0x2d, 0x64, 0x65, 0x6c, 0x6d,
|
||||
0x26, 0x27, 0x2e, 0x2f, 0x66, 0x67, 0x6e, 0x6f,
|
||||
0x34, 0x35, 0x3c, 0x3d, 0x74, 0x75, 0x7c, 0x7d,
|
||||
0x36, 0x37, 0x3e, 0x3f, 0x76, 0x77, 0x7e, 0x7f,
|
||||
0xa4, 0xa5, 0xac, 0xad, 0xe4, 0xe5, 0xec, 0xed,
|
||||
0xa6, 0xa7, 0xae, 0xaf, 0xe6, 0xe7, 0xee, 0xef,
|
||||
0xb4, 0xb5, 0xbc, 0xbd, 0xf4, 0xf5, 0xfc, 0xfd,
|
||||
0xb6, 0xb7, 0xbe, 0xbf, 0xf6, 0xf7, 0xfe, 0xff,
|
||||
0x2d2c2524, 0x6d6c6564,
|
||||
0x2f2e2726, 0x6f6e6766,
|
||||
0x3d3c3534, 0x7d7c7574,
|
||||
0x3f3e3736, 0x7f7e7776,
|
||||
0xadaca5a4, 0xedece5e4,
|
||||
0xafaea7a6, 0xefeee7e6,
|
||||
0xbdbcb5b4, 0xfdfcf5f4,
|
||||
0xbfbeb7b6, 0xfffef7f6,
|
||||
},
|
||||
};
|
||||
|
||||
@ -76,7 +76,9 @@ void main() {
|
||||
uint col = bitfieldExtract(x, 0, 3);
|
||||
uint row = bitfieldExtract(y, 0, 3);
|
||||
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 tile_row = y / MICRO_TILE_DIM;
|
||||
@ -85,7 +87,7 @@ void main() {
|
||||
uint offs = slice_offs + tile_offs + (idx * BPP / 8);
|
||||
|
||||
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 + 1] = p1;
|
||||
out_data[2 * gl_GlobalInvocationID.x + 1] = p1;
|
||||
}
|
||||
|
101
src/video_core/host_shaders/detile_macro8x1.comp
Normal file
101
src/video_core/host_shaders/detile_macro8x1.comp
Normal 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];
|
||||
}
|
||||
}
|
@ -39,6 +39,15 @@ public:
|
||||
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 {
|
||||
const size_t l1_page = page >> SecondLevelBits;
|
||||
const size_t l2_page = page & (NumEntriesPerL1Page - 1);
|
||||
|
@ -185,7 +185,7 @@ void PageManager::OnGpuUnmap(VAddr address, size_t size) {
|
||||
void PageManager::UpdatePagesCachedCount(VAddr addr, u64 size, s32 delta) {
|
||||
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 page_start = addr >> PageShift;
|
||||
const u64 page_end = page_start + num_pages;
|
||||
|
@ -4,8 +4,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <boost/icl/interval_map.hpp>
|
||||
#include "common/spin_lock.h"
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Vulkan {
|
||||
@ -35,8 +35,8 @@ private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
Vulkan::Rasterizer* rasterizer;
|
||||
std::mutex mutex;
|
||||
boost::icl::interval_map<VAddr, s32> cached_pages;
|
||||
Common::SpinLock lock;
|
||||
};
|
||||
|
||||
} // namespace VideoCore
|
||||
|
@ -691,16 +691,40 @@ std::span<const SurfaceFormatInfo> SurfaceFormats() {
|
||||
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) {
|
||||
const auto& formats = SurfaceFormats();
|
||||
const auto format =
|
||||
std::find_if(formats.begin(), formats.end(), [&](const SurfaceFormatInfo& format_info) {
|
||||
return format_info.data_format == data_format &&
|
||||
format_info.number_format == num_format;
|
||||
});
|
||||
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;
|
||||
vk::Format result = surface_format_table[GetSurfaceFormatTableIndex(data_format, num_format)];
|
||||
bool found =
|
||||
result != vk::Format::eUndefined || data_format == AmdGpu::DataFormat::FormatInvalid;
|
||||
ASSERT_MSG(found, "Unknown data_format={} and num_format={}", static_cast<u32>(data_format),
|
||||
static_cast<u32>(num_format));
|
||||
return result;
|
||||
}
|
||||
|
||||
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) {
|
||||
const auto comp_swizzle = color_buffer.Swizzle();
|
||||
const auto format = color_buffer.DataFormat();
|
||||
const auto number_type = color_buffer.NumFormat();
|
||||
const auto format = color_buffer.GetDataFmt();
|
||||
const auto number_type = color_buffer.GetNumberFmt();
|
||||
|
||||
const auto& c0 = color_buffer.clear_word0;
|
||||
const auto& c1 = color_buffer.clear_word1;
|
||||
|
@ -328,8 +328,8 @@ bool PipelineCache::RefreshGraphicsKey() {
|
||||
}
|
||||
|
||||
key.color_formats[remapped_cb] =
|
||||
LiverpoolToVK::SurfaceFormat(col_buf.DataFormat(), col_buf.NumFormat());
|
||||
key.color_num_formats[remapped_cb] = col_buf.NumFormat();
|
||||
LiverpoolToVK::SurfaceFormat(col_buf.GetDataFmt(), col_buf.GetNumberFmt());
|
||||
key.color_num_formats[remapped_cb] = col_buf.GetNumberFmt();
|
||||
key.color_swizzles[remapped_cb] = col_buf.Swizzle();
|
||||
}
|
||||
|
||||
|
@ -562,6 +562,12 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding
|
||||
push_data.AddOffset(binding.buffer, adjust);
|
||||
buffer_infos.emplace_back(vk_buffer->Handle(), offset_aligned,
|
||||
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({
|
||||
@ -600,7 +606,7 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding
|
||||
if (auto barrier =
|
||||
vk_buffer->GetBarrier(desc.is_written ? vk::AccessFlagBits2::eShaderWrite
|
||||
: vk::AccessFlagBits2::eShaderRead,
|
||||
vk::PipelineStageFlagBits2::eComputeShader)) {
|
||||
vk::PipelineStageFlagBits2::eAllCommands)) {
|
||||
buffer_barriers.emplace_back(*barrier);
|
||||
}
|
||||
if (desc.is_written) {
|
||||
|
@ -265,9 +265,9 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer,
|
||||
const AmdGpu::Liverpool::CbDbExtent& hint /*= {}*/) noexcept {
|
||||
props.is_tiled = buffer.IsTiled();
|
||||
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_bits = NumBits(buffer.DataFormat());
|
||||
num_bits = NumBits(buffer.GetDataFmt());
|
||||
type = vk::ImageType::e2D;
|
||||
size.width = hint.Valid() ? hint.width : buffer.Pitch();
|
||||
size.height = hint.Valid() ? hint.height : buffer.Height();
|
||||
|
@ -76,7 +76,8 @@ ImageViewInfo::ImageViewInfo(const AmdGpu::Liverpool::ColorBuffer& col_buffer) n
|
||||
range.base.layer = col_buffer.view.slice_start;
|
||||
range.extent.layers = col_buffer.NumSlices() - range.base.layer;
|
||||
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,
|
||||
|
@ -542,31 +542,62 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
|
||||
sched_ptr->EndRendering();
|
||||
|
||||
const auto cmdbuf = sched_ptr->CommandBuffer();
|
||||
image.Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite, {},
|
||||
cmdbuf);
|
||||
|
||||
const VAddr image_addr = image.info.guest_address;
|
||||
const size_t image_size = image.info.guest_size_bytes;
|
||||
const auto [vk_buffer, buf_offset] =
|
||||
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
|
||||
// hazard
|
||||
if (auto barrier = vk_buffer->GetBarrier(vk::AccessFlagBits2::eTransferRead,
|
||||
vk::PipelineStageFlagBits2::eTransfer)) {
|
||||
const auto dependencies = vk::DependencyInfo{
|
||||
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
|
||||
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
|
||||
.bufferMemoryBarrierCount = 1,
|
||||
.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) {
|
||||
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.pipelineBarrier2(vk::DependencyInfo{
|
||||
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
|
||||
.bufferMemoryBarrierCount = 1,
|
||||
.pBufferMemoryBarriers = &post_barrier,
|
||||
});
|
||||
image.flags &= ~ImageFlagBits::Dirty;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
#include "video_core/renderer_vulkan/vk_scheduler.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/tile_manager.h"
|
||||
|
||||
@ -14,6 +15,7 @@
|
||||
#include "video_core/host_shaders/detile_m8x2_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_macro8x1_comp.h"
|
||||
|
||||
#include <boost/container/static_vector.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::eR8G8Unorm:
|
||||
case vk::Format::eR16Sfloat:
|
||||
case vk::Format::eR16Uint:
|
||||
case vk::Format::eR16Unorm:
|
||||
case vk::Format::eD16Unorm:
|
||||
return vk::Format::eR8G8Uint;
|
||||
@ -85,10 +88,10 @@ static vk::Format DemoteImageFormatForDetiling(vk::Format format) {
|
||||
return format;
|
||||
}
|
||||
|
||||
const DetilerContext* TileManager::GetDetiler(const Image& image) const {
|
||||
const auto format = DemoteImageFormatForDetiling(image.info.pixel_format);
|
||||
const DetilerContext* TileManager::GetDetiler(const ImageInfo& info) const {
|
||||
const auto format = DemoteImageFormatForDetiling(info.pixel_format);
|
||||
|
||||
switch (image.info.tiling_mode) {
|
||||
switch (info.tiling_mode) {
|
||||
case AmdGpu::TilingMode::Texture_MicroTiled:
|
||||
switch (format) {
|
||||
case vk::Format::eR8Uint:
|
||||
@ -106,6 +109,8 @@ const DetilerContext* TileManager::GetDetiler(const Image& image) const {
|
||||
}
|
||||
case AmdGpu::TilingMode::Texture_Volume:
|
||||
switch (format) {
|
||||
case vk::Format::eR8Uint:
|
||||
return &detilers[DetilerType::Macro8x1];
|
||||
case vk::Format::eR32Uint:
|
||||
return &detilers[DetilerType::Macro32x1];
|
||||
case vk::Format::eR32G32Uint:
|
||||
@ -131,8 +136,8 @@ TileManager::TileManager(const Vulkan::Instance& instance, Vulkan::Scheduler& sc
|
||||
static const std::array detiler_shaders{
|
||||
HostShaders::DETILE_M8X1_COMP, HostShaders::DETILE_M8X2_COMP,
|
||||
HostShaders::DETILE_M32X1_COMP, HostShaders::DETILE_M32X2_COMP,
|
||||
HostShaders::DETILE_M32X4_COMP, HostShaders::DETILE_MACRO32X1_COMP,
|
||||
HostShaders::DETILE_MACRO32X2_COMP,
|
||||
HostShaders::DETILE_M32X4_COMP, HostShaders::DETILE_MACRO8X1_COMP,
|
||||
HostShaders::DETILE_MACRO32X1_COMP, HostShaders::DETILE_MACRO32X2_COMP,
|
||||
};
|
||||
|
||||
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,
|
||||
Image& image) {
|
||||
if (!image.info.props.is_tiled) {
|
||||
const ImageInfo& info) {
|
||||
if (!info.props.is_tiled) {
|
||||
return {in_buffer, in_offset};
|
||||
}
|
||||
|
||||
const auto* detiler = GetDetiler(image);
|
||||
const auto* detiler = GetDetiler(info);
|
||||
if (!detiler) {
|
||||
if (image.info.tiling_mode != AmdGpu::TilingMode::Texture_MacroTiled &&
|
||||
image.info.tiling_mode != AmdGpu::TilingMode::Display_MacroTiled &&
|
||||
image.info.tiling_mode != AmdGpu::TilingMode::Depth_MacroTiled) {
|
||||
if (info.tiling_mode != AmdGpu::TilingMode::Texture_MacroTiled &&
|
||||
info.tiling_mode != AmdGpu::TilingMode::Display_MacroTiled &&
|
||||
info.tiling_mode != AmdGpu::TilingMode::Depth_MacroTiled) {
|
||||
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};
|
||||
}
|
||||
|
||||
const u32 image_size = image.info.guest_size_bytes;
|
||||
const u32 image_size = info.guest_size_bytes;
|
||||
|
||||
// Prepare output buffer
|
||||
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);
|
||||
|
||||
DetilerParams params;
|
||||
params.num_levels = image.info.resources.levels;
|
||||
params.pitch0 = image.info.pitch >> (image.info.props.is_block ? 2u : 0u);
|
||||
params.height = image.info.size.height;
|
||||
if (image.info.tiling_mode == AmdGpu::TilingMode::Texture_Volume) {
|
||||
ASSERT(image.info.resources.levels == 1);
|
||||
ASSERT(image.info.num_bits >= 32);
|
||||
const auto tiles_per_row = image.info.pitch / 8u;
|
||||
const auto tiles_per_slice = tiles_per_row * ((image.info.size.height + 7u) / 8u);
|
||||
params.num_levels = info.resources.levels;
|
||||
params.pitch0 = info.pitch >> (info.props.is_block ? 2u : 0u);
|
||||
params.height = info.size.height;
|
||||
if (info.tiling_mode == AmdGpu::TilingMode::Texture_Volume) {
|
||||
ASSERT(info.resources.levels == 1);
|
||||
const auto tiles_per_row = info.pitch / 8u;
|
||||
const auto tiles_per_slice = tiles_per_row * ((info.size.height + 7u) / 8u);
|
||||
params.sizes[0] = tiles_per_row;
|
||||
params.sizes[1] = tiles_per_slice;
|
||||
} else {
|
||||
|
||||
ASSERT(image.info.resources.levels <= 14);
|
||||
ASSERT(info.resources.levels <= 14);
|
||||
std::memset(¶ms.sizes, 0, sizeof(params.sizes));
|
||||
for (int m = 0; m < image.info.resources.levels; ++m) {
|
||||
params.sizes[m] = image.info.mips_layout[m].size * image.info.resources.layers +
|
||||
for (int m = 0; m < info.resources.levels; ++m) {
|
||||
params.sizes[m] = info.mips_layout[m].size * info.resources.layers +
|
||||
(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
|
||||
¶ms);
|
||||
|
||||
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));
|
||||
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};
|
||||
}
|
||||
|
||||
|
@ -5,11 +5,11 @@
|
||||
|
||||
#include "common/types.h"
|
||||
#include "video_core/buffer_cache/buffer.h"
|
||||
#include "video_core/texture_cache/image.h"
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
class TextureCache;
|
||||
struct ImageInfo;
|
||||
|
||||
enum DetilerType : u32 {
|
||||
Micro8x1,
|
||||
@ -18,6 +18,7 @@ enum DetilerType : u32 {
|
||||
Micro32x2,
|
||||
Micro32x4,
|
||||
|
||||
Macro8x1,
|
||||
Macro32x1,
|
||||
Macro32x2,
|
||||
|
||||
@ -36,14 +37,15 @@ public:
|
||||
TileManager(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler);
|
||||
~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);
|
||||
void Upload(ScratchBuffer buffer, const void* data, size_t size);
|
||||
void FreeBuffer(ScratchBuffer buffer);
|
||||
|
||||
private:
|
||||
const DetilerContext* GetDetiler(const Image& image) const;
|
||||
const DetilerContext* GetDetiler(const ImageInfo& info) const;
|
||||
|
||||
private:
|
||||
const Vulkan::Instance& instance;
|
||||
|
Loading…
Reference in New Issue
Block a user