mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-03-11 07:56:15 +01:00
Compare commits
72 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee01d1186f | ||
|
|
2934641237 | ||
|
|
fecb53f86c | ||
|
|
9811e1cc3b | ||
|
|
234f2b4648 | ||
|
|
9e573a9ff2 | ||
|
|
3803c864f7 | ||
|
|
8afa40eaa7 | ||
|
|
c7a576edce | ||
|
|
c72d54bd6a | ||
|
|
040a79ddd1 | ||
|
|
aa094ca948 | ||
|
|
7917520633 | ||
|
|
8651875e59 | ||
|
|
ef70a6e825 | ||
|
|
0869ef421d | ||
|
|
5f86315ae0 | ||
|
|
ab72ce418e | ||
|
|
36cdaac327 | ||
|
|
6d52415d50 | ||
|
|
0603d24a91 | ||
|
|
71f0d5c602 | ||
|
|
763001ee91 | ||
|
|
0f92ea2578 | ||
|
|
e0a0d736c4 | ||
|
|
65320446f0 | ||
|
|
5f6822042d | ||
|
|
302e87c920 | ||
|
|
77cbdd82ab | ||
|
|
41db06b53f | ||
|
|
eeda9c7738 | ||
|
|
c38bf70464 | ||
|
|
43b295892f | ||
|
|
2573cc5fd0 | ||
|
|
4828d4d2d6 | ||
|
|
c5f278ed37 | ||
|
|
b839d4d1a6 | ||
|
|
3616424b26 | ||
|
|
4d6da6542e | ||
|
|
f2aa347608 | ||
|
|
bd7d5faa9f | ||
|
|
a3d09a7427 | ||
|
|
7dad9663b2 | ||
|
|
cae8ae63e3 | ||
|
|
728d84b1fe | ||
|
|
4a51302c58 | ||
|
|
0ea692e9ab | ||
|
|
1e16b338b4 | ||
|
|
14789b536f | ||
|
|
ac30feeddb | ||
|
|
0d80e300a0 | ||
|
|
69384d7bb4 | ||
|
|
4fd2409b8b | ||
|
|
d97851376d | ||
|
|
1c5e30e83f | ||
|
|
414df8432e | ||
|
|
92f63ccc0b | ||
|
|
d75e8b24f7 | ||
|
|
a1af15b907 | ||
|
|
cf5eb22591 | ||
|
|
2f9f79eea2 | ||
|
|
c57d6110c4 | ||
|
|
2a292d1e2e | ||
|
|
f2c8b157ef | ||
|
|
ec00a06caf | ||
|
|
ae6172d86b | ||
|
|
5605cf2141 | ||
|
|
d46ddcee5d | ||
|
|
3750fb2c1f | ||
|
|
86b2773c28 | ||
|
|
11a9011510 | ||
|
|
e66f1fa306 |
|
|
@ -17,7 +17,7 @@ brew install -f --overwrite --quiet ccache "llvm@$LLVM_COMPILER_VER"
|
|||
brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER"
|
||||
if [ "$AARCH64" -eq 1 ]; then
|
||||
brew install -f --overwrite --quiet googletest opencv@4 sdl3 vulkan-headers vulkan-loader molten-vk
|
||||
brew unlink --quiet ffmpeg fmt qtbase qtsvg qtdeclarative protobuf
|
||||
brew unlink --quiet ffmpeg fmt qtbase qtsvg qtdeclarative
|
||||
else
|
||||
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
arch -x86_64 /usr/local/bin/brew install -f --overwrite --quiet python@3.14 opencv@4 "llvm@$LLVM_COMPILER_VER" sdl3 vulkan-headers vulkan-loader molten-vk
|
||||
|
|
|
|||
2
3rdparty/FAudio
vendored
2
3rdparty/FAudio
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit e67d761ead486de3e69fa11705456bf94df734ca
|
||||
Subproject commit dc034fc671b07bbd14e8410d5dd6be6da38fdf6d
|
||||
2
3rdparty/yaml-cpp/yaml-cpp
vendored
2
3rdparty/yaml-cpp/yaml-cpp
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 05c44fcd18074836e21e1eda9fc02b3a4a1529b5
|
||||
Subproject commit 51a5d623e3fde1f58829a56ba910f1cb33596222
|
||||
|
|
@ -416,7 +416,7 @@ void cfg::encode(YAML::Emitter& out, const cfg::_base& rhs)
|
|||
out << YAML::BeginMap;
|
||||
for (const auto& np : static_cast<const log_entry&>(rhs).get_map())
|
||||
{
|
||||
if (np.second == logs::level::notice) continue;
|
||||
if (np.second == logs::level::_default) continue;
|
||||
out << YAML::Key << np.first;
|
||||
out << YAML::Value << fmt::format("%s", np.second);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@
|
|||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
#elif defined(__clang__)
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,11 @@
|
|||
#include "Emu/CPU/Backends/AArch64/AArch64Signal.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_lib_stacktrace
|
||||
#include "rpcs3_version.h"
|
||||
#include <stacktrace>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <Psapi.h>
|
||||
|
|
@ -2800,6 +2805,16 @@ void thread_base::exec()
|
|||
|
||||
[[noreturn]] void thread_ctrl::emergency_exit(std::string_view reason)
|
||||
{
|
||||
// Print stacktrace
|
||||
#ifdef __cpp_lib_stacktrace
|
||||
if (rpcs3::is_local_build())
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << std::stacktrace::current();
|
||||
sys_log.notice("StackTrace\n\n%s\n", oss.str());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (const std::string info = dump_useful_thread_info(); !info.empty())
|
||||
{
|
||||
sys_log.notice("\n%s", info);
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ if(BUILD_RPCS3_TESTS)
|
|||
tests/test_address_range.cpp
|
||||
tests/test_rsx_cfg.cpp
|
||||
tests/test_rsx_fp_asm.cpp
|
||||
tests/test_dmux_pamf.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(rpcs3_test
|
||||
|
|
@ -202,6 +203,7 @@ if(BUILD_RPCS3_TESTS)
|
|||
rpcs3_lib
|
||||
rpcs3_emu
|
||||
GTest::gtest
|
||||
GTest::gmock
|
||||
)
|
||||
|
||||
target_include_directories(rpcs3_test
|
||||
|
|
|
|||
|
|
@ -500,6 +500,7 @@ target_sources(rpcs3_emu PRIVATE
|
|||
RSX/Overlays/overlays.cpp
|
||||
RSX/Overlays/overlay_animated_icon.cpp
|
||||
RSX/Overlays/overlay_animation.cpp
|
||||
RSX/Overlays/overlay_audio.cpp
|
||||
RSX/Overlays/overlay_compile_notification.cpp
|
||||
RSX/Overlays/overlay_controls.cpp
|
||||
RSX/Overlays/overlay_cursor.cpp
|
||||
|
|
|
|||
|
|
@ -20,19 +20,19 @@ namespace aarch64
|
|||
sp
|
||||
};
|
||||
|
||||
static const char* gpr_names[] =
|
||||
[[maybe_unused]] static const char* gpr_names[] =
|
||||
{
|
||||
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9",
|
||||
"x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19",
|
||||
"x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30"
|
||||
};
|
||||
|
||||
static const char* spr_names[] =
|
||||
[[maybe_unused]] static const char* spr_names[] =
|
||||
{
|
||||
"xzr", "pc", "sp"
|
||||
};
|
||||
|
||||
static const char* spr_asm_names[] =
|
||||
[[maybe_unused]] static const char* spr_asm_names[] =
|
||||
{
|
||||
"xzr", ".", "sp"
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1373,7 +1373,7 @@ std::vector<std::pair<u32, u32>> cpu_thread::dump_callstack_list() const
|
|||
|
||||
std::string cpu_thread::dump_misc() const
|
||||
{
|
||||
return fmt::format("Type: %s; State: %s\n", get_class() == thread_class::ppu ? "PPU" : get_class() == thread_class::spu ? "SPU" : "RSX", state.load());
|
||||
return fmt::format("%s[0x%x]; State: %s\n", get_class() == thread_class::ppu ? "PPU" : get_class() == thread_class::spu ? "SPU" : "RSX", id, state.load());
|
||||
}
|
||||
|
||||
bool cpu_thread::suspend_work::push(cpu_thread* _this) noexcept
|
||||
|
|
|
|||
|
|
@ -3647,7 +3647,14 @@ public:
|
|||
const auto data0 = a.eval(m_ir);
|
||||
const auto data1 = b.eval(m_ir);
|
||||
const auto data2 = c.eval(m_ir);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 22
|
||||
// LLVM 22+ changed the intrinsic signature from v4i32 to v16i8 for operands 2 and 3
|
||||
result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_vpdpbusd_128),
|
||||
{data0, m_ir->CreateBitCast(data1, get_type<u8[16]>()), m_ir->CreateBitCast(data2, get_type<u8[16]>())});
|
||||
#else
|
||||
result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_vpdpbusd_128), {data0, data1, data2});
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -919,7 +919,7 @@ error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm
|
|||
|
||||
if (!check_dev_num(dev_num))
|
||||
{
|
||||
return CELL_CAMERA_ERROR_PARAM;
|
||||
return { CELL_CAMERA_ERROR_PARAM, "dev_num=%d", dev_num };
|
||||
}
|
||||
|
||||
if (g_cfg.io.camera == camera_handler::null)
|
||||
|
|
@ -935,7 +935,7 @@ error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm
|
|||
|
||||
if (!arg1)
|
||||
{
|
||||
return CELL_CAMERA_ERROR_PARAM;
|
||||
return { CELL_CAMERA_ERROR_PARAM, "arg1=null" };
|
||||
}
|
||||
|
||||
if (error_code error = check_resolution(dev_num))
|
||||
|
|
@ -952,7 +952,7 @@ error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm
|
|||
|
||||
if (!attr_name) // invalid attributes don't have a name
|
||||
{
|
||||
return CELL_CAMERA_ERROR_PARAM;
|
||||
return { CELL_CAMERA_ERROR_PARAM, "attrib=0x%x", attrib };
|
||||
}
|
||||
|
||||
if (arg1)
|
||||
|
|
@ -983,7 +983,7 @@ error_code cellCameraSetAttribute(s32 dev_num, s32 attrib, u32 arg1, u32 arg2)
|
|||
|
||||
if (!check_dev_num(dev_num))
|
||||
{
|
||||
return CELL_CAMERA_ERROR_PARAM;
|
||||
return { CELL_CAMERA_ERROR_PARAM, "dev_num=%d", dev_num };
|
||||
}
|
||||
|
||||
if (g_cfg.io.camera == camera_handler::null)
|
||||
|
|
@ -1004,7 +1004,7 @@ error_code cellCameraSetAttribute(s32 dev_num, s32 attrib, u32 arg1, u32 arg2)
|
|||
|
||||
if (!attr_name) // invalid attributes don't have a name
|
||||
{
|
||||
return CELL_CAMERA_ERROR_PARAM;
|
||||
return { CELL_CAMERA_ERROR_PARAM, "attrib=0x%x", attrib };
|
||||
}
|
||||
|
||||
g_camera.set_attr(attrib, arg1, arg2);
|
||||
|
|
|
|||
|
|
@ -169,18 +169,18 @@ public:
|
|||
static const u32 id_count = 1023;
|
||||
SAVESTATE_INIT_POS(34);
|
||||
|
||||
ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec);
|
||||
ElementaryStream(Demuxer* dmux, vm::ptr<void> addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, vm::ptr<void> cbArg, u32 spec);
|
||||
|
||||
Demuxer* dmux;
|
||||
const u32 id = idm::last_id();
|
||||
const u32 memAddr;
|
||||
const vm::ptr<void> memAddr;
|
||||
const u32 memSize;
|
||||
const u32 fidMajor;
|
||||
const u32 fidMinor;
|
||||
const u32 sup1;
|
||||
const u32 sup2;
|
||||
const vm::ptr<CellDmuxCbEsMsg> cbFunc;
|
||||
const u32 cbArg;
|
||||
const vm::ptr<void> cbArg;
|
||||
const u32 spec; //addr
|
||||
|
||||
std::vector<u8> raw_data; // demultiplexed data stream (managed by demuxer thread)
|
||||
|
|
@ -208,13 +208,13 @@ public:
|
|||
const u32 memAddr;
|
||||
const u32 memSize;
|
||||
const vm::ptr<CellDmuxCbMsg> cbFunc;
|
||||
const u32 cbArg;
|
||||
const vm::ptr<void> cbArg;
|
||||
volatile bool is_finished = false;
|
||||
volatile bool is_closed = false;
|
||||
atomic_t<bool> is_running = false;
|
||||
atomic_t<bool> is_working = false;
|
||||
|
||||
Demuxer(u32 addr, u32 size, vm::ptr<CellDmuxCbMsg> func, u32 arg)
|
||||
Demuxer(u32 addr, u32 size, vm::ptr<CellDmuxCbMsg> func, vm::ptr<void> arg)
|
||||
: ppu_thread({}, "", 0)
|
||||
, memAddr(addr)
|
||||
, memSize(size)
|
||||
|
|
@ -755,11 +755,11 @@ PesHeader::PesHeader(DemuxerStream& stream)
|
|||
is_ok = true;
|
||||
}
|
||||
|
||||
ElementaryStream::ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec)
|
||||
: put(utils::align(addr, 128))
|
||||
ElementaryStream::ElementaryStream(Demuxer* dmux, vm::ptr<void> addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, vm::ptr<void> cbArg, u32 spec)
|
||||
: put(utils::align(addr.addr(), 128))
|
||||
, dmux(dmux)
|
||||
, memAddr(utils::align(addr, 128))
|
||||
, memSize(size - (addr - memAddr))
|
||||
, memAddr(vm::ptr<void>::make(utils::align(addr.addr(), 128)))
|
||||
, memSize(size - (addr.addr() - memAddr.addr()))
|
||||
, fidMajor(fidMajor)
|
||||
, fidMinor(fidMinor)
|
||||
, sup1(sup1)
|
||||
|
|
@ -788,9 +788,9 @@ bool ElementaryStream::is_full(u32 space)
|
|||
{
|
||||
return first - put < space + 128;
|
||||
}
|
||||
else if (put + space + 128 > memAddr + memSize)
|
||||
else if (put + space + 128 > memAddr.addr() + memSize)
|
||||
{
|
||||
return first - memAddr < space + 128;
|
||||
return first - memAddr.addr() < space + 128;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -816,35 +816,35 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra
|
|||
std::lock_guard lock(m_mutex);
|
||||
ensure(!is_full(size));
|
||||
|
||||
if (put + size + 128 > memAddr + memSize)
|
||||
if (put + size + 128 > memAddr.addr() + memSize)
|
||||
{
|
||||
put = memAddr;
|
||||
put = memAddr.addr();
|
||||
}
|
||||
|
||||
std::memcpy(vm::base(put + 128), raw_data.data(), size);
|
||||
raw_data.erase(raw_data.begin(), raw_data.begin() + size);
|
||||
|
||||
auto info = vm::ptr<CellDmuxAuInfoEx>::make(put);
|
||||
info->auAddr = put + 128;
|
||||
info->auAddr.set(put + 128);
|
||||
info->auSize = size;
|
||||
info->dts.lower = static_cast<u32>(dts);
|
||||
info->dts.upper = static_cast<u32>(dts >> 32);
|
||||
info->pts.lower = static_cast<u32>(pts);
|
||||
info->pts.upper = static_cast<u32>(pts >> 32);
|
||||
info->isRap = rap;
|
||||
info->reserved = 0;
|
||||
info->auMaxSize = 0;
|
||||
info->userData = userdata;
|
||||
|
||||
auto spec = vm::ptr<u32>::make(put + u32{sizeof(CellDmuxAuInfoEx)});
|
||||
*spec = specific;
|
||||
|
||||
auto inf = vm::ptr<CellDmuxAuInfo>::make(put + 64);
|
||||
inf->auAddr = put + 128;
|
||||
inf->auAddr.set(put + 128);
|
||||
inf->auSize = size;
|
||||
inf->dtsLower = static_cast<u32>(dts);
|
||||
inf->dtsUpper = static_cast<u32>(dts >> 32);
|
||||
inf->ptsLower = static_cast<u32>(pts);
|
||||
inf->ptsUpper = static_cast<u32>(pts >> 32);
|
||||
inf->dts.lower = static_cast<u32>(dts);
|
||||
inf->dts.upper = static_cast<u32>(dts >> 32);
|
||||
inf->pts.lower = static_cast<u32>(pts);
|
||||
inf->pts.upper = static_cast<u32>(pts >> 32);
|
||||
inf->auMaxSize = 0; // ?????
|
||||
inf->userData = userdata;
|
||||
|
||||
|
|
@ -927,7 +927,7 @@ bool ElementaryStream::peek(u32& out_data, bool no_ex, u32& out_spec, bool updat
|
|||
void ElementaryStream::reset()
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
put = memAddr;
|
||||
put = memAddr.addr();
|
||||
entries.clear();
|
||||
put_count = 0;
|
||||
got_count = 0;
|
||||
|
|
|
|||
|
|
@ -33,118 +33,6 @@ enum CellDmuxEsMsgType : s32
|
|||
CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE = 1,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfM2vLevel : s32
|
||||
{
|
||||
CELL_DMUX_PAMF_M2V_MP_LL = 0,
|
||||
CELL_DMUX_PAMF_M2V_MP_ML,
|
||||
CELL_DMUX_PAMF_M2V_MP_H14,
|
||||
CELL_DMUX_PAMF_M2V_MP_HL,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfAvcLevel : s32
|
||||
{
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_2P1 = 21,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_3P0 = 30,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_3P1 = 31,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_3P2 = 32,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_4P1 = 41,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_4P2 = 42,
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoM2v
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoAvc
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoLpcm
|
||||
{
|
||||
u8 channelAssignmentInfo;
|
||||
u8 samplingFreqInfo;
|
||||
u8 bitsPerSample;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoAc3
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoAtrac3plus
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoUserData
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoM2v
|
||||
{
|
||||
be_t<u32> profileLevel;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoAvc
|
||||
{
|
||||
be_t<u32> level;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoLpcm
|
||||
{
|
||||
be_t<u32> samplingFreq;
|
||||
be_t<u32> numOfChannels;
|
||||
be_t<u32> bitsPerSample;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoAc3
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoAtrac3plus
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoUserData
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
enum CellDmuxPamfSamplingFrequency : s32
|
||||
{
|
||||
CELL_DMUX_PAMF_FS_48K = 48000,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfBitsPerSample : s32
|
||||
{
|
||||
CELL_DMUX_PAMF_BITS_PER_SAMPLE_16 = 16,
|
||||
CELL_DMUX_PAMF_BITS_PER_SAMPLE_24 = 24,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfLpcmChannelAssignmentInfo : s32
|
||||
{
|
||||
CELL_DMUX_PAMF_LPCM_CH_M1 = 1,
|
||||
CELL_DMUX_PAMF_LPCM_CH_LR = 3,
|
||||
CELL_DMUX_PAMF_LPCM_CH_LRCLSRSLFE = 9,
|
||||
CELL_DMUX_PAMF_LPCM_CH_LRCLSCS1CS2RSLFE = 11,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfLpcmFs : s32
|
||||
{
|
||||
CELL_DMUX_PAMF_LPCM_FS_48K = 1,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfLpcmBitsPerSamples : s32
|
||||
{
|
||||
CELL_DMUX_PAMF_LPCM_BITS_PER_SAMPLE_16 = 1,
|
||||
CELL_DMUX_PAMF_LPCM_BITS_PER_SAMPLE_24 = 3,
|
||||
};
|
||||
|
||||
struct CellDmuxMsg
|
||||
{
|
||||
be_t<s32> msgType; // CellDmuxMsgType
|
||||
|
|
@ -163,12 +51,6 @@ struct CellDmuxType
|
|||
be_t<u32> reserved[2];
|
||||
};
|
||||
|
||||
struct CellDmuxPamfSpecificInfo
|
||||
{
|
||||
be_t<u32> thisSize;
|
||||
b8 programEndCodeCb;
|
||||
};
|
||||
|
||||
struct CellDmuxType2
|
||||
{
|
||||
be_t<s32> streamType; // CellDmuxStreamType
|
||||
|
|
@ -177,7 +59,7 @@ struct CellDmuxType2
|
|||
|
||||
struct CellDmuxResource
|
||||
{
|
||||
be_t<u32> memAddr;
|
||||
vm::bptr<void> memAddr;
|
||||
be_t<u32> memSize;
|
||||
be_t<u32> ppuThreadPriority;
|
||||
be_t<u32> ppuThreadStackSize;
|
||||
|
|
@ -187,7 +69,7 @@ struct CellDmuxResource
|
|||
|
||||
struct CellDmuxResourceEx
|
||||
{
|
||||
be_t<u32> memAddr;
|
||||
vm::bptr<void> memAddr;
|
||||
be_t<u32> memSize;
|
||||
be_t<u32> ppuThreadPriority;
|
||||
be_t<u32> ppuThreadStackSize;
|
||||
|
|
@ -227,16 +109,16 @@ struct CellDmuxResource2
|
|||
be_t<u32> shit[4];
|
||||
};
|
||||
|
||||
using CellDmuxCbMsg = u32(u32 demuxerHandle, vm::ptr<CellDmuxMsg> demuxerMsg, u32 cbArg);
|
||||
using CellDmuxCbMsg = u32(u32 demuxerHandle, vm::cptr<CellDmuxMsg> demuxerMsg, vm::ptr<void> cbArg);
|
||||
|
||||
using CellDmuxCbEsMsg = u32(u32 demuxerHandle, u32 esHandle, vm::ptr<CellDmuxEsMsg> esMsg, u32 cbArg);
|
||||
using CellDmuxCbEsMsg = u32(u32 demuxerHandle, u32 esHandle, vm::cptr<CellDmuxEsMsg> esMsg, vm::ptr<void> cbArg);
|
||||
|
||||
// Used for internal callbacks as well
|
||||
template <typename F>
|
||||
struct DmuxCb
|
||||
{
|
||||
vm::bptr<F> cbFunc;
|
||||
be_t<u32> cbArg;
|
||||
vm::bptr<void> cbArg;
|
||||
};
|
||||
|
||||
using CellDmuxCb = DmuxCb<CellDmuxCbMsg>;
|
||||
|
|
@ -250,42 +132,50 @@ struct CellDmuxAttr
|
|||
be_t<u32> demuxerVerLower;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAttr
|
||||
{
|
||||
be_t<u32> maxEnabledEsNum;
|
||||
be_t<u32> version;
|
||||
be_t<u32> memSize;
|
||||
};
|
||||
|
||||
struct CellDmuxEsAttr
|
||||
{
|
||||
be_t<u32> memSize;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsAttr
|
||||
{
|
||||
be_t<u32> auQueueMaxSize;
|
||||
be_t<u32> memSize;
|
||||
be_t<u32> specificInfoSize;
|
||||
};
|
||||
|
||||
struct CellDmuxEsResource
|
||||
{
|
||||
be_t<u32> memAddr;
|
||||
vm::bptr<void> memAddr;
|
||||
be_t<u32> memSize;
|
||||
};
|
||||
|
||||
struct CellDmuxAuInfo
|
||||
{
|
||||
be_t<u32> auAddr;
|
||||
vm::bptr<void> auAddr;
|
||||
be_t<u32> auSize;
|
||||
be_t<u32> auMaxSize;
|
||||
be_t<u64> userData;
|
||||
be_t<u32> ptsUpper;
|
||||
be_t<u32> ptsLower;
|
||||
be_t<u32> dtsUpper;
|
||||
be_t<u32> dtsLower;
|
||||
};
|
||||
|
||||
struct CellDmuxAuInfoEx
|
||||
{
|
||||
be_t<u32> auAddr;
|
||||
be_t<u32> auSize;
|
||||
be_t<u32> reserved;
|
||||
b8 isRap;
|
||||
be_t<u64> userData;
|
||||
CellCodecTimeStamp pts;
|
||||
CellCodecTimeStamp dts;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAttr;
|
||||
struct CellDmuxPamfEsAttr;
|
||||
using CellDmuxAuInfoEx = CellDmuxAuInfo;
|
||||
|
||||
struct DmuxAuInfo
|
||||
{
|
||||
CellDmuxAuInfo info;
|
||||
vm::bptr<void> specific_info;
|
||||
be_t<u32> specific_info_size;
|
||||
};
|
||||
|
||||
using DmuxNotifyDemuxDone = error_code(vm::ptr<void>, u32, vm::ptr<void>);
|
||||
using DmuxNotifyFatalErr = error_code(vm::ptr<void>, u32, vm::ptr<void>);
|
||||
|
|
@ -301,7 +191,7 @@ using CellDmuxCoreOpResetStream = error_code(vm::ptr<void>);
|
|||
using CellDmuxCoreOpCreateThread = error_code(vm::ptr<void>);
|
||||
using CellDmuxCoreOpJoinThread = error_code(vm::ptr<void>);
|
||||
using CellDmuxCoreOpSetStream = error_code(vm::ptr<void>, vm::cptr<void>, u32, b8, u64);
|
||||
using CellDmuxCoreOpFreeMemory = error_code(vm::ptr<void>, vm::ptr<void>, u32);
|
||||
using CellDmuxCoreOpReleaseAu = error_code(vm::ptr<void>, vm::ptr<void>, u32);
|
||||
using CellDmuxCoreOpQueryEsAttr = error_code(vm::cptr<void>, vm::cptr<void>, vm::ptr<CellDmuxPamfEsAttr>);
|
||||
using CellDmuxCoreOpEnableEs = error_code(vm::ptr<void>, vm::cptr<void>, vm::cptr<CellDmuxEsResource>, vm::cptr<DmuxCb<DmuxEsNotifyAuFound>>, vm::cptr<DmuxCb<DmuxEsNotifyFlushDone>>, vm::cptr<void>, vm::pptr<void>);
|
||||
using CellDmuxCoreOpDisableEs = u32(vm::ptr<void>);
|
||||
|
|
@ -318,7 +208,7 @@ struct CellDmuxCoreOps
|
|||
vm::bptr<CellDmuxCoreOpCreateThread> createThread;
|
||||
vm::bptr<CellDmuxCoreOpJoinThread> joinThread;
|
||||
vm::bptr<CellDmuxCoreOpSetStream> setStream;
|
||||
vm::bptr<CellDmuxCoreOpFreeMemory> freeMemory;
|
||||
vm::bptr<CellDmuxCoreOpReleaseAu> releaseAu;
|
||||
vm::bptr<CellDmuxCoreOpQueryEsAttr> queryEsAttr;
|
||||
vm::bptr<CellDmuxCoreOpEnableEs> enableEs;
|
||||
vm::bptr<CellDmuxCoreOpDisableEs> disableEs;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -770,8 +770,8 @@ namespace gem
|
|||
if constexpr (use_gain)
|
||||
{
|
||||
dst0[0] = static_cast<u8>(std::clamp(r * gain_r, 0.0f, 255.0f));
|
||||
dst0[1] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
|
||||
dst0[2] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
|
||||
dst0[1] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
|
||||
dst0[2] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -822,8 +822,8 @@ namespace gem
|
|||
if constexpr (use_gain)
|
||||
{
|
||||
dst0[0] = static_cast<u8>(std::clamp(r * gain_r, 0.0f, 255.0f));
|
||||
dst0[1] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
|
||||
dst0[2] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
|
||||
dst0[1] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
|
||||
dst0[2] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -845,6 +845,53 @@ namespace gem
|
|||
debayer_raw8_impl<false>(src, dst, alpha, gain_r, gain_g, gain_b);
|
||||
}
|
||||
|
||||
template <bool use_gain>
|
||||
static inline void debayer_raw8_downscale_impl(const u8* src, u8* dst, u8 alpha, f32 gain_r, f32 gain_g, f32 gain_b)
|
||||
{
|
||||
constexpr u32 in_pitch = 640;
|
||||
constexpr u32 out_pitch = 320 * 4;
|
||||
|
||||
// Simple debayer
|
||||
for (s32 y = 0; y < 240; y++)
|
||||
{
|
||||
const u8* src0 = src + y * 2 * in_pitch;
|
||||
const u8* src1 = src0 + in_pitch;
|
||||
|
||||
u8* dst0 = dst + y * out_pitch;
|
||||
|
||||
for (s32 x = 0; x < 320; x++, dst0 += 4, src0 += 2, src1 += 2)
|
||||
{
|
||||
const u8 b = src0[0];
|
||||
const u8 g0 = src0[1];
|
||||
const u8 g1 = src1[0];
|
||||
const u8 r = src1[1];
|
||||
const u8 g = (g0 + g1) >> 1;
|
||||
|
||||
if constexpr (use_gain)
|
||||
{
|
||||
dst0[0] = static_cast<u8>(std::clamp(r * gain_r, 0.0f, 255.0f));
|
||||
dst0[1] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
|
||||
dst0[2] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
dst0[0] = r;
|
||||
dst0[1] = g;
|
||||
dst0[2] = b;
|
||||
}
|
||||
dst0[3] = alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void debayer_raw8_downscale(const u8* src, u8* dst, u8 alpha, f32 gain_r, f32 gain_g, f32 gain_b)
|
||||
{
|
||||
if (gain_r != 1.0f || gain_g != 1.0f || gain_b != 1.0f)
|
||||
debayer_raw8_downscale_impl<true>(src, dst, alpha, gain_r, gain_g, gain_b);
|
||||
else
|
||||
debayer_raw8_downscale_impl<false>(src, dst, alpha, gain_r, gain_g, gain_b);
|
||||
}
|
||||
|
||||
bool convert_image_format(CellCameraFormat input_format, const CellGemVideoConvertAttribute& vc,
|
||||
const std::vector<u8>& video_data_in, u32 width, u32 height,
|
||||
u8* video_data_out, u32 video_data_out_size, u8* buffer_memory,
|
||||
|
|
@ -881,9 +928,9 @@ namespace gem
|
|||
|
||||
const u8* src_data = video_data_in.data();
|
||||
const u8 alpha = vc.alpha;
|
||||
const f32 gain_r = vc.gain * vc.blue_gain;
|
||||
const f32 gain_r = vc.gain * vc.red_gain;
|
||||
const f32 gain_g = vc.gain * vc.green_gain;
|
||||
const f32 gain_b = vc.gain * vc.red_gain;
|
||||
const f32 gain_b = vc.gain * vc.blue_gain;
|
||||
|
||||
// Only RAW8 should be relevant for cellGem unless I'm mistaken
|
||||
if (input_format == CELL_CAMERA_RAW8)
|
||||
|
|
@ -1183,34 +1230,7 @@ namespace gem
|
|||
{
|
||||
case CELL_CAMERA_RAW8:
|
||||
{
|
||||
const u32 in_pitch = width;
|
||||
const u32 out_pitch = width * 4 / 2;
|
||||
|
||||
for (u32 y = 0; y < height - 1; y += 2)
|
||||
{
|
||||
const u8* src0 = src_data + y * in_pitch;
|
||||
const u8* src1 = src0 + in_pitch;
|
||||
|
||||
u8* dst0 = video_data_out + (y / 2) * out_pitch;
|
||||
u8* dst1 = dst0 + out_pitch;
|
||||
|
||||
for (u32 x = 0; x < width - 1; x += 2, src0 += 2, src1 += 2, dst0 += 4, dst1 += 4)
|
||||
{
|
||||
const u8 b = src0[0];
|
||||
const u8 g0 = src0[1];
|
||||
const u8 g1 = src1[0];
|
||||
const u8 r = src1[1];
|
||||
|
||||
const u8 top[4] = { r, g0, b, alpha };
|
||||
const u8 bottom[4] = { r, g1, b, alpha };
|
||||
|
||||
// Top-Left
|
||||
std::memcpy(dst0, top, 4);
|
||||
|
||||
// Bottom-Left Pixel
|
||||
std::memcpy(dst1, bottom, 4);
|
||||
}
|
||||
}
|
||||
debayer_raw8_downscale(src_data, video_data_out, alpha, gain_r, gain_g, gain_b);
|
||||
break;
|
||||
}
|
||||
case CELL_CAMERA_RGBA:
|
||||
|
|
@ -1609,13 +1629,8 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!m_camera_info.bytesize)
|
||||
{
|
||||
cellGem.error("gem_tracker: unexpected image size: %d", m_camera_info.bytesize);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_tracker.set_image_data(m_camera_info.buffer.get_ptr(), m_camera_info.bytesize, m_camera_info.width, m_camera_info.height, m_camera_info.format);
|
||||
m_framenumber++; // using framenumber instead of timestamp since the timestamp could be identical
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1648,6 +1663,7 @@ public:
|
|||
}
|
||||
|
||||
auto& gem = g_fxo->get<gem_config>();
|
||||
u64 last_framenumber = 0;
|
||||
|
||||
while (thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
|
|
@ -1663,6 +1679,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
if (std::exchange(last_framenumber, m_framenumber.load()) == last_framenumber)
|
||||
{
|
||||
cellGem.warning("Tracker woke up without new frame. Skipping processing (framenumber=%d)", last_framenumber);
|
||||
tracker_done();
|
||||
continue;
|
||||
}
|
||||
|
||||
m_busy.release(true);
|
||||
|
||||
// Update PS Move LED colors
|
||||
|
|
@ -1754,6 +1777,7 @@ public:
|
|||
private:
|
||||
atomic_t<u32> m_wake_up_tracker = 0;
|
||||
atomic_t<u32> m_tracker_done = 0;
|
||||
atomic_t<u64> m_framenumber = 0;
|
||||
atomic_t<bool> m_busy = false;
|
||||
ps_move_tracker<false> m_tracker{};
|
||||
CellCameraInfoEx m_camera_info{};
|
||||
|
|
@ -1873,21 +1897,10 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con
|
|||
gem_state->pos[2] = controller.distance_mm;
|
||||
gem_state->pos[3] = 0.f;
|
||||
|
||||
// TODO: calculate handle position based on our world coordinate and the angles
|
||||
gem_state->handle_pos[0] = camera_x;
|
||||
gem_state->handle_pos[1] = camera_y;
|
||||
gem_state->handle_pos[2] = controller.distance_mm + 10.0f;
|
||||
gem_state->handle_pos[3] = 0.f;
|
||||
|
||||
// Calculate orientation
|
||||
if (g_cfg.io.move == move_handler::real || (g_cfg.io.move == move_handler::fake && move_data.orientation_enabled))
|
||||
{
|
||||
gem_state->quat[0] = move_data.quaternion.x();
|
||||
gem_state->quat[1] = move_data.quaternion.y();
|
||||
gem_state->quat[2] = move_data.quaternion.z();
|
||||
gem_state->quat[3] = move_data.quaternion.w();
|
||||
}
|
||||
else
|
||||
ps_move_data::vect<4> quat = move_data.quaternion;
|
||||
|
||||
if (g_cfg.io.move != move_handler::real && !(g_cfg.io.move == move_handler::fake && move_data.orientation_enabled))
|
||||
{
|
||||
const f32 max_angle_per_side_h = g_cfg.io.fake_move_rotation_cone_h / 2.0f;
|
||||
const f32 max_angle_per_side_v = g_cfg.io.fake_move_rotation_cone_v / 2.0f;
|
||||
|
|
@ -1901,17 +1914,27 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con
|
|||
const f32 cy = std::cos(yaw * 0.5f);
|
||||
const f32 sy = std::sin(yaw * 0.5f);
|
||||
|
||||
const f32 q_x = sr * cp * cy - cr * sp * sy;
|
||||
const f32 q_y = cr * sp * cy + sr * cp * sy;
|
||||
const f32 q_z = cr * cp * sy - sr * sp * cy;
|
||||
const f32 q_w = cr * cp * cy + sr * sp * sy;
|
||||
|
||||
gem_state->quat[0] = q_x;
|
||||
gem_state->quat[1] = q_y;
|
||||
gem_state->quat[2] = q_z;
|
||||
gem_state->quat[3] = q_w;
|
||||
quat.x() = sr * cp * cy - cr * sp * sy;
|
||||
quat.y() = cr * sp * cy + sr * cp * sy;
|
||||
quat.z() = cr * cp * sy - sr * sp * cy;
|
||||
quat.w() = cr * cp * cy + sr * sp * sy;
|
||||
}
|
||||
|
||||
gem_state->quat[0] = quat.x();
|
||||
gem_state->quat[1] = quat.y();
|
||||
gem_state->quat[2] = quat.z();
|
||||
gem_state->quat[3] = quat.w();
|
||||
|
||||
// Calculate handle position based on our world coordinate and the current orientation
|
||||
constexpr ps_move_data::vect<3> offset_local_mm({0.f, 0.f, -45.f}); // handle is ~45 mm below sphere
|
||||
const ps_move_data::vect<3> offset_world = ps_move_data::rotate_vector(quat, offset_local_mm);
|
||||
|
||||
gem_state->handle_pos[0] = gem_state->pos[0] - offset_world.x(); // Flip x offset
|
||||
gem_state->handle_pos[1] = gem_state->pos[1] - offset_world.y(); // Flip y offset
|
||||
gem_state->handle_pos[2] = gem_state->pos[2] + offset_world.z();
|
||||
gem_state->handle_pos[3] = 0.f;
|
||||
|
||||
// Calculate velocity
|
||||
if constexpr (!ps_move_data::use_imu_for_velocity)
|
||||
{
|
||||
move_data.update_velocity(shared_data.frame_timestamp_us, gem_state->pos);
|
||||
|
|
@ -1920,6 +1943,10 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con
|
|||
{
|
||||
gem_state->vel[i] = move_data.vel_world[i];
|
||||
gem_state->accel[i] = move_data.accel_world[i];
|
||||
|
||||
// TODO: maybe this also needs to be adjusted depending on the orientation
|
||||
gem_state->handle_vel[i] = gem_state->vel[i];
|
||||
gem_state->handle_accel[i] = gem_state->accel[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3612,7 +3639,7 @@ error_code cellGemReadExternalPortDeviceInfo(u32 gem_num, vm::ptr<u32> ext_id, v
|
|||
if (!pad->move_data.external_device_read_requested)
|
||||
{
|
||||
*ext_id = controller.ext_id = pad->move_data.external_device_id;
|
||||
std::memcpy(pad->move_data.external_device_read.data(), ext_info.get_ptr(), CELL_GEM_EXTERNAL_PORT_OUTPUT_SIZE);
|
||||
std::memcpy(ext_info.get_ptr(), pad->move_data.external_device_read.data(), CELL_GEM_EXTERNAL_PORT_DEVICE_INFO_SIZE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -3876,13 +3903,15 @@ error_code cellGemUpdateStart(vm::cptr<void> camera_frame, u64 timestamp)
|
|||
|
||||
gem.camera_frame = camera_frame.addr();
|
||||
|
||||
if (!tracker.set_image(gem.camera_frame))
|
||||
const bool image_set = tracker.set_image(gem.camera_frame);
|
||||
|
||||
tracker.wake_up_tracker();
|
||||
|
||||
if (!image_set)
|
||||
{
|
||||
return not_an_error(CELL_GEM_NO_VIDEO);
|
||||
}
|
||||
|
||||
tracker.wake_up_tracker();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Memory/vm_ptr.h"
|
||||
|
||||
// Error Codes
|
||||
|
|
|
|||
|
|
@ -2535,7 +2535,7 @@ bool ppu_module<lv2_obj>::analyse(u32 lib_toc, u32 entry, const u32 sec_end, con
|
|||
// SLDI mnemonic
|
||||
reg_state_t rs = get_reg(op.rs);
|
||||
|
||||
if (!rs.shift_left(op.sh32, reg_tag_allocator))
|
||||
if (!rs.shift_left(sh, reg_tag_allocator))
|
||||
{
|
||||
unmap_reg(op.ra);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1004,7 +1004,7 @@ static import_result_t ppu_load_imports(const ppu_module<lv2_obj>& _module, std:
|
|||
|
||||
// Check address
|
||||
// TODO: The address of use should be extracted from analyser instead
|
||||
if (fstub && fstub >= _module.segs[0].addr && fstub <= _module.segs[0].addr + _module.segs[0].size)
|
||||
if (fstub && fstub >= _module.segs[0].addr && fstub < _module.segs[0].addr + _module.segs[0].size)
|
||||
{
|
||||
nid_to_use_addr.emplace(fnid, fstub);
|
||||
}
|
||||
|
|
@ -1895,7 +1895,7 @@ shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, bool virtual_load, c
|
|||
}
|
||||
else
|
||||
{
|
||||
ppu_loader.error("Library %s: PRX library info not found");
|
||||
ppu_loader.error("Library: PRX library info not found");
|
||||
}
|
||||
|
||||
prx->start.set(prx->specials[0xbc9a0086]);
|
||||
|
|
@ -3192,7 +3192,7 @@ bool ppu_load_rel_exec(const ppu_rel_object& elf)
|
|||
|
||||
for (const auto& s : elf.shdrs)
|
||||
{
|
||||
if (s.sh_type != sec_type::sht_progbits)
|
||||
if (s.sh_type == sec_type::sht_progbits)
|
||||
{
|
||||
memsize = utils::align<u32>(memsize + vm::cast(s.sh_size), 128);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3867,12 +3867,12 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
|
|||
|
||||
if (mself.read(hdr) && hdr.get_count(mself.size()))
|
||||
{
|
||||
std::set<u64> offs;
|
||||
|
||||
for (u32 j = 0; j < hdr.count; j++)
|
||||
{
|
||||
mself_record rec{};
|
||||
|
||||
std::set<u64> offs;
|
||||
|
||||
if (mself.read(rec) && rec.get_pos(mself.size()))
|
||||
{
|
||||
if (rec.size <= 0x20)
|
||||
|
|
|
|||
|
|
@ -550,11 +550,12 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect)
|
|||
else if (_target >= caddr && _target <= cend)
|
||||
{
|
||||
u32 target_last = static_cast<u32>(_target);
|
||||
|
||||
std::unordered_set<u32> passed_targets{target_last};
|
||||
|
||||
// Try to follow unconditional branches as long as there is no infinite loop
|
||||
while (target_last != _target)
|
||||
// !! Triggers compilation issues in Asura's Wrath in other parts of the code
|
||||
// !! See https://github.com/RPCS3/rpcs3/issues/18287
|
||||
while (false)
|
||||
{
|
||||
const ppu_opcode_t op{*ensure(m_info.get_ptr<u32>(target_last))};
|
||||
const ppu_itype::type itype = g_ppu_itype.decode(op.opcode);
|
||||
|
|
@ -1304,7 +1305,7 @@ void PPUTranslator::VMADDFP(ppu_opcode_t op)
|
|||
if (!m_use_fma && data == v128{})
|
||||
{
|
||||
set_vr(op.vd, vec_handle_result(a * c + fsplat<f32[4]>(0.f)));
|
||||
ppu_log.notice("LLVM: VMADDFP with -0 addend at [0x%08x]", m_addr + (m_reloc ? m_reloc->addr : 0));
|
||||
ppu_log.notice("LLVM: VMADDFP with +0 addend at [0x%08x]", m_addr + (m_reloc ? m_reloc->addr : 0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -3680,9 +3681,7 @@ void PPUTranslator::STVLX(ppu_opcode_t op)
|
|||
const auto addr = op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb);
|
||||
const auto data = pshufb(get_vr<u8[16]>(op.vs), build<u8[16]>(127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112) + vsplat<u8[16]>(trunc<u8>(value<u64>(addr) & 0xf)));
|
||||
const auto mask = bitcast<bool[16]>(splat<u16>(0xffff) << trunc<u16>(value<u64>(addr) & 0xf));
|
||||
const auto ptr = value<u8(*)[16]>(GetMemory(m_ir->CreateAnd(addr, ~0xfull)));
|
||||
const auto align = splat<u32>(16);
|
||||
eval(llvm_calli<void, decltype(data), decltype(ptr), decltype(align), decltype(mask)>{"llvm.masked.store.v16i8.p0", {data, ptr, align, mask}});
|
||||
m_ir->CreateMaskedStore(data.eval(m_ir), GetMemory(m_ir->CreateAnd(addr, ~0xfull)), llvm::Align(16), mask.eval(m_ir));
|
||||
}
|
||||
|
||||
void PPUTranslator::STDBRX(ppu_opcode_t op)
|
||||
|
|
@ -3710,9 +3709,7 @@ void PPUTranslator::STVRX(ppu_opcode_t op)
|
|||
const auto addr = op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb);
|
||||
const auto data = pshufb(get_vr<u8[16]>(op.vs), build<u8[16]>(255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240) + vsplat<u8[16]>(trunc<u8>(value<u64>(addr) & 0xf)));
|
||||
const auto mask = bitcast<bool[16]>(trunc<u16>(splat<u64>(0xffff) << (value<u64>(addr) & 0xf) >> 16));
|
||||
const auto ptr = value<u8(*)[16]>(GetMemory(m_ir->CreateAnd(addr, ~0xfull)));
|
||||
const auto align = splat<u32>(16);
|
||||
eval(llvm_calli<void, decltype(data), decltype(ptr), decltype(align), decltype(mask)>{"llvm.masked.store.v16i8.p0", {data, ptr, align, mask}});
|
||||
m_ir->CreateMaskedStore(data.eval(m_ir), GetMemory(m_ir->CreateAnd(addr, ~0xfull)), llvm::Align(16), mask.eval(m_ir));
|
||||
}
|
||||
|
||||
void PPUTranslator::STFSUX(ppu_opcode_t op)
|
||||
|
|
|
|||
|
|
@ -2219,6 +2219,28 @@ void lv2_obj::prepare_for_sleep(cpu_thread& cpu)
|
|||
cpu_counter::remove(&cpu);
|
||||
}
|
||||
|
||||
ppu_thread* lv2_obj::get_running_ppu(u32 index)
|
||||
{
|
||||
usz thread_count = g_cfg.core.ppu_threads;
|
||||
|
||||
if (index >= thread_count)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto target = atomic_storage<ppu_thread*>::load(g_ppu);
|
||||
|
||||
for (usz cur = 0; target; target = atomic_storage<ppu_thread*>::load(target->next_ppu), cur++)
|
||||
{
|
||||
if (cur == index)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void lv2_obj::notify_all() noexcept
|
||||
{
|
||||
for (auto cpu : g_to_notify)
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ u32 sys_gamepad_ycon_is_gem(vm::ptr<u8> in, vm::ptr<u8> out)
|
|||
// syscall(621,packet_id,u8 *in,u8 *out) Talk:LV2_Functions_and_Syscalls#Syscall_621_.280x26D.29 gamepad_if usage
|
||||
u32 sys_gamepad_ycon_if(u8 packet_id, vm::ptr<u8> in, vm::ptr<u8> out)
|
||||
{
|
||||
|
||||
switch (packet_id)
|
||||
{
|
||||
case 0:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,18 @@ LOG_CHANNEL(sys_memory);
|
|||
//
|
||||
static shared_mutex s_memstats_mtx;
|
||||
|
||||
// This struct is for reduced logging repetition
|
||||
struct last_reported_memory_stats
|
||||
{
|
||||
struct inner_body
|
||||
{
|
||||
u32 prev_total = umax;
|
||||
u32 prev_avail = umax;
|
||||
};
|
||||
|
||||
atomic_t<inner_body> body{};
|
||||
};
|
||||
|
||||
lv2_memory_container::lv2_memory_container(u32 size, bool from_idm) noexcept
|
||||
: size(size)
|
||||
, id{from_idm ? idm::last_id() : SYS_MEMORY_CONTAINER_ID_INVALID}
|
||||
|
|
@ -313,8 +325,6 @@ error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr<sys_memory_i
|
|||
{
|
||||
cpu.state += cpu_flag::wait;
|
||||
|
||||
sys_memory.warning("sys_memory_get_user_memory_size(mem_info=*0x%x)", mem_info);
|
||||
|
||||
// Get "default" memory container
|
||||
auto& dct = g_fxo->get<lv2_memory_container>();
|
||||
|
||||
|
|
@ -332,6 +342,22 @@ error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr<sys_memory_i
|
|||
});
|
||||
}
|
||||
|
||||
typename last_reported_memory_stats::inner_body now;
|
||||
now.prev_total = out.total_user_memory;
|
||||
now.prev_avail = out.available_user_memory;
|
||||
|
||||
now = g_fxo->get<last_reported_memory_stats>().body.exchange(now);
|
||||
|
||||
if (now.prev_total != out.total_user_memory || now.prev_avail != out.available_user_memory)
|
||||
{
|
||||
// Log on change
|
||||
sys_memory.warning("sys_memory_get_user_memory_size(mem_info=*0x%x): Avail=0x%x, Total=0x%x", mem_info, out.available_user_memory, out.total_user_memory);
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_memory.trace("sys_memory_get_user_memory_size(mem_info=*0x%x): Avail=0x%x, Total=0x%x", mem_info, out.available_user_memory, out.total_user_memory);
|
||||
}
|
||||
|
||||
cpu.check_state();
|
||||
*mem_info = out;
|
||||
return CELL_OK;
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ extern const std::map<std::string_view, int> g_prx_list
|
|||
{ "libddpdec.sprx", 0 },
|
||||
{ "libdivxdec.sprx", 0 },
|
||||
{ "libdmux.sprx", 0 },
|
||||
{ "libdmuxpamf.sprx", 0 },
|
||||
{ "libdmuxpamf.sprx", 1 },
|
||||
{ "libdtslbrdec.sprx", 0 },
|
||||
{ "libfiber.sprx", 0 },
|
||||
{ "libfont.sprx", 0 },
|
||||
|
|
|
|||
|
|
@ -453,6 +453,7 @@ public:
|
|||
|
||||
// Can be called before the actual sleep call in order to move it out of mutex scope
|
||||
static void prepare_for_sleep(cpu_thread& cpu);
|
||||
static ppu_thread* get_running_ppu(u32 index);
|
||||
|
||||
struct notify_all_t
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ struct GameInfo
|
|||
std::string path;
|
||||
std::string icon_path;
|
||||
std::string movie_path;
|
||||
std::string audio_path;
|
||||
|
||||
std::string name;
|
||||
std::string serial;
|
||||
|
|
|
|||
|
|
@ -945,17 +945,6 @@ static u8 sdl_to_logitech_g27_pedal(std::map<u64, std::vector<SDL_Joystick*>>& j
|
|||
return unsigned_avg * 0xFF / 0xFFFF;
|
||||
}
|
||||
|
||||
static inline void set_bit(u8* buf, int bit_num, bool set)
|
||||
{
|
||||
const int byte_num = bit_num / 8;
|
||||
bit_num %= 8;
|
||||
const u8 mask = 1 << bit_num;
|
||||
if (set)
|
||||
buf[byte_num] = buf[byte_num] | mask;
|
||||
else
|
||||
buf[byte_num] = buf[byte_num] & (~mask);
|
||||
}
|
||||
|
||||
void usb_device_logitech_g27::transfer_dfex(u32 buf_size, u8* buf, UsbTransfer* transfer)
|
||||
{
|
||||
DFEX_data data{};
|
||||
|
|
|
|||
|
|
@ -38,10 +38,7 @@ struct logitech_g27_ffb_slot
|
|||
logitech_g27_ffb_state state = logitech_g27_ffb_state::inactive;
|
||||
u64 last_update = 0;
|
||||
SDL_HapticEffect last_effect {};
|
||||
|
||||
// TODO switch to SDL_HapticEffectID when it becomes available in a future SDL release
|
||||
// Match the return of SDL_CreateHapticEffect for now
|
||||
int effect_id = -1;
|
||||
SDL_HapticEffectID effect_id = -1;
|
||||
};
|
||||
|
||||
struct sdl_mapping
|
||||
|
|
|
|||
|
|
@ -24,13 +24,11 @@ std::set<u32> PadHandlerBase::narrow_set(const std::set<u64>& src)
|
|||
return dst;
|
||||
}
|
||||
|
||||
// Get new multiplied value based on the multiplier
|
||||
s32 PadHandlerBase::MultipliedInput(s32 raw_value, s32 multiplier)
|
||||
{
|
||||
return (multiplier * raw_value) / 100;
|
||||
}
|
||||
|
||||
// Get new scaled value between 0 and range based on its minimum and maximum
|
||||
f32 PadHandlerBase::ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range)
|
||||
{
|
||||
if (deadzone > 0 && deadzone > minimum)
|
||||
|
|
@ -46,7 +44,6 @@ f32 PadHandlerBase::ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 dea
|
|||
return range * val;
|
||||
}
|
||||
|
||||
// Get new scaled value between -range and range based on its minimum and maximum
|
||||
f32 PadHandlerBase::ScaledAxisInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range)
|
||||
{
|
||||
// convert [min, max] to [0, 1]
|
||||
|
|
@ -79,7 +76,6 @@ f32 PadHandlerBase::ScaledAxisInput(f32 raw_value, f32 minimum, f32 maximum, f32
|
|||
return (2.0f * range * val) - range;
|
||||
}
|
||||
|
||||
// Get normalized trigger value based on the range defined by a threshold
|
||||
u16 PadHandlerBase::NormalizeTriggerInput(u16 value, u32 threshold) const
|
||||
{
|
||||
if (value <= threshold || threshold >= trigger_max)
|
||||
|
|
@ -90,8 +86,6 @@ u16 PadHandlerBase::NormalizeTriggerInput(u16 value, u32 threshold) const
|
|||
return static_cast<u16>(ScaledInput(static_cast<f32>(value), static_cast<f32>(trigger_min), static_cast<f32>(trigger_max), static_cast<f32>(threshold)));
|
||||
}
|
||||
|
||||
// normalizes a directed input, meaning it will correspond to a single "button" and not an axis with two directions
|
||||
// the input values must lie in 0+
|
||||
u16 PadHandlerBase::NormalizeDirectedInput(s32 raw_value, s32 threshold, s32 maximum) const
|
||||
{
|
||||
if (threshold >= maximum || maximum <= 0 || raw_value < 0)
|
||||
|
|
@ -114,9 +108,6 @@ u16 PadHandlerBase::NormalizeStickInput(u16 raw_value, s32 threshold, s32 multip
|
|||
return static_cast<u16>(ScaledInput(static_cast<f32>(scaled_value), 0.0f, static_cast<f32>(thumb_max), static_cast<f32>(threshold)));
|
||||
}
|
||||
|
||||
// This function normalizes stick deadzone based on the DS3's deadzone, which is ~13% (default of anti deadzone)
|
||||
// X and Y is expected to be in (-255) to 255 range, deadzone should be in terms of thumb stick range
|
||||
// return is new x and y values in 0-255 range
|
||||
std::tuple<u16, u16> PadHandlerBase::NormalizeStickDeadzone(s32 inX, s32 inY, u32 deadzone, u32 anti_deadzone) const
|
||||
{
|
||||
f32 X = inX / 255.0f;
|
||||
|
|
@ -150,28 +141,21 @@ std::tuple<u16, u16> PadHandlerBase::NormalizeStickDeadzone(s32 inX, s32 inY, u3
|
|||
return std::tuple<u16, u16>(ConvertAxis(X), ConvertAxis(Y));
|
||||
}
|
||||
|
||||
// get clamped value between 0 and 255
|
||||
u16 PadHandlerBase::Clamp0To255(f32 input)
|
||||
{
|
||||
return static_cast<u16>(std::clamp(input, 0.0f, 255.0f));
|
||||
}
|
||||
|
||||
// get clamped value between 0 and 1023
|
||||
u16 PadHandlerBase::Clamp0To1023(f32 input)
|
||||
{
|
||||
return static_cast<u16>(std::clamp(input, 0.0f, 1023.0f));
|
||||
}
|
||||
|
||||
// input has to be [-1,1]. result will be [0,255]
|
||||
u16 PadHandlerBase::ConvertAxis(f32 value)
|
||||
{
|
||||
return static_cast<u16>((value + 1.0) * (255.0 / 2.0));
|
||||
}
|
||||
|
||||
// The DS3, (and i think xbox controllers) give a 'square-ish' type response, so that the corners will give (almost)max x/y instead of the ~30x30 from a perfect circle
|
||||
// using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange
|
||||
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of ~4000
|
||||
// This function assumes inX and inY is already in 0-255
|
||||
void PadHandlerBase::ConvertToSquirclePoint(u16& inX, u16& inY, u32 squircle_factor)
|
||||
{
|
||||
if (!squircle_factor)
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ protected:
|
|||
// the input values must lie in 0+
|
||||
u16 NormalizeDirectedInput(s32 raw_value, s32 threshold, s32 maximum) const;
|
||||
|
||||
// This function normalizes stick deadzone based on the DS3's deadzone, which is ~13%
|
||||
// This function normalizes stick deadzone based on the DS3's deadzone, which is ~13% (default of anti deadzone)
|
||||
// X and Y is expected to be in (-255) to 255 range, deadzone should be in terms of thumb stick range
|
||||
// return is new x and y values in 0-255 range
|
||||
std::tuple<u16, u16> NormalizeStickDeadzone(s32 inX, s32 inY, u32 deadzone, u32 anti_deadzone) const;
|
||||
|
|
@ -284,10 +284,10 @@ public:
|
|||
// Get new multiplied value based on the multiplier
|
||||
static s32 MultipliedInput(s32 raw_value, s32 multiplier);
|
||||
|
||||
// Get new scaled value between 0 and 255 based on its minimum and maximum
|
||||
// Get new scaled value between 0 and range based on its minimum and maximum
|
||||
static f32 ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range = 255.0f);
|
||||
|
||||
// Get new scaled value between -255 and 255 based on its minimum and maximum
|
||||
// Get new scaled value between -range and range based on its minimum and maximum
|
||||
static f32 ScaledAxisInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range = 255.0f);
|
||||
|
||||
// get clamped value between 0 and 255
|
||||
|
|
@ -301,7 +301,7 @@ public:
|
|||
|
||||
// The DS3, (and i think xbox controllers) give a 'square-ish' type response, so that the corners will give (almost)max x/y instead of the ~30x30 from a perfect circle
|
||||
// using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange
|
||||
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of 8000
|
||||
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of ~4000
|
||||
// This function assumes inX and inY is already in 0-255
|
||||
static void ConvertToSquirclePoint(u16& inX, u16& inY, u32 squircle_factor);
|
||||
|
||||
|
|
|
|||
|
|
@ -24,34 +24,34 @@ void ps_move_data::reset_sensors()
|
|||
angaccel_world = {};
|
||||
}
|
||||
|
||||
ps_move_data::vect<3> ps_move_data::rotate_vector(const vect<4>& q, const vect<3>& v)
|
||||
{
|
||||
const auto cross = [](const vect<3>& a, const vect<3>& b)
|
||||
{
|
||||
return vect<3>({
|
||||
a.y() * b.z() - a.z() * b.y(),
|
||||
a.z() * b.x() - a.x() * b.z(),
|
||||
a.x() * b.y() - a.y() * b.x()
|
||||
});
|
||||
};
|
||||
|
||||
// q = (x, y, z, w)
|
||||
const vect<3> q_vec({q.x(), q.y(), q.z()});
|
||||
|
||||
// t = 2 * cross(q_vec, v)
|
||||
const vect<3> t = cross(q_vec, v) * 2.0f;
|
||||
|
||||
// v' = v + w * t + cross(q_vec, t)
|
||||
const vect<3> v_prime = v + t * q.w() + cross(q_vec, t);
|
||||
|
||||
return v_prime;
|
||||
}
|
||||
|
||||
void ps_move_data::update_orientation(f32 delta_time)
|
||||
{
|
||||
if (!delta_time)
|
||||
return;
|
||||
|
||||
// Rotate vector v by quaternion q
|
||||
const auto rotate_vector = [](const vect<4>& q, const vect<3>& v)
|
||||
{
|
||||
const vect<4> qv({0.0f, v.x(), v.y(), v.z()});
|
||||
const vect<4> q_inv({q.w(), -q.x(), -q.y(), -q.z()});
|
||||
|
||||
// t = q * v
|
||||
vect<4> t;
|
||||
t.w() = -q.x() * qv.x() - q.y() * qv.y() - q.z() * qv.z();
|
||||
t.x() = q.w() * qv.x() + q.y() * qv.z() - q.z() * qv.y();
|
||||
t.y() = q.w() * qv.y() - q.x() * qv.z() + q.z() * qv.x();
|
||||
t.z() = q.w() * qv.z() + q.x() * qv.y() - q.y() * qv.x();
|
||||
|
||||
// r = t * q_inv
|
||||
vect<4> r;
|
||||
r.w() = -t.x() * q_inv.x() - t.y() * q_inv.y() - t.z() * q_inv.z();
|
||||
r.x() = t.w() * q_inv.x() + t.y() * q_inv.z() - t.z() * q_inv.y();
|
||||
r.y() = t.w() * q_inv.y() - t.x() * q_inv.z() + t.z() * q_inv.x();
|
||||
r.z() = t.w() * q_inv.z() + t.x() * q_inv.y() - t.y() * q_inv.x();
|
||||
|
||||
return vect<3>({r.x(), r.y(), r.z()});
|
||||
};
|
||||
|
||||
if constexpr (use_imu_for_velocity)
|
||||
{
|
||||
// Gravity in world frame
|
||||
|
|
|
|||
|
|
@ -15,6 +15,26 @@ struct ps_move_data
|
|||
template <typename I>
|
||||
const T& operator[](I i) const { return data[i]; }
|
||||
|
||||
vect<Size, T> operator*(f32 s) const
|
||||
{
|
||||
vect<Size, T> result = *this;
|
||||
for (int i = 0; i < Size; ++i)
|
||||
{
|
||||
result[i] *= s;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vect<Size, T> operator+(const vect<Size, T>& other) const
|
||||
{
|
||||
vect<Size, T> result = *this;
|
||||
for (int i = 0; i < Size; ++i)
|
||||
{
|
||||
result[i] += other[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
T x() const requires (Size >= 1) { return data[0]; }
|
||||
T y() const requires (Size >= 2) { return data[1]; }
|
||||
T z() const requires (Size >= 3) { return data[2]; }
|
||||
|
|
@ -72,4 +92,7 @@ struct ps_move_data
|
|||
void reset_sensors();
|
||||
void update_orientation(f32 delta_time);
|
||||
void update_velocity(u64 timestamp, be_t<f32> pos_world[4]);
|
||||
|
||||
// Rotate vector v by quaternion q
|
||||
static vect<3> rotate_vector(const vect<4>& q, const vect<3>& v);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ void cfg_rpcn::load()
|
|||
{
|
||||
const std::string path = cfg_rpcn::get_path();
|
||||
|
||||
fs::file cfg_file(path, fs::read);
|
||||
if (cfg_file)
|
||||
if (fs::file cfg_file(path, fs::read); cfg_file)
|
||||
{
|
||||
rpcn_log.notice("Loading RPCN config. Path: %s", path);
|
||||
from_string(cfg_file.to_string());
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
struct cfg_rpcn : cfg::node
|
||||
{
|
||||
cfg::uint32 version{this, "Version", 1};
|
||||
cfg::uint32 version{this, "Version", 2};
|
||||
cfg::string host{this, "Host", "np.rpcs3.net"};
|
||||
cfg::string npid{this, "NPID", ""};
|
||||
cfg::string password{this, "Password", ""};
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ struct copy_unmodified_block_swizzled
|
|||
}
|
||||
|
||||
const u32 size_in_block = padded_width * padded_height * depth * 2;
|
||||
rsx::simple_array<U> tmp(size_in_block * words_per_block);
|
||||
rsx::simple_array<U, sizeof(u128)> tmp(size_in_block * words_per_block);
|
||||
|
||||
if (words_per_block == 1) [[likely]]
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ namespace rsx
|
|||
template <typename T>
|
||||
concept SpanLike = requires(T t)
|
||||
{
|
||||
{ t.data() } -> std::convertible_to<void*>;
|
||||
{ t.data() } -> std::convertible_to<const void*>;
|
||||
{ t.size_bytes() } -> std::convertible_to<usz>;
|
||||
};
|
||||
|
||||
|
|
@ -71,9 +71,10 @@ namespace rsx
|
|||
return static_cast<T*>(m_ptr);
|
||||
}
|
||||
|
||||
usz size() const
|
||||
template <Integral T = usz>
|
||||
T size() const
|
||||
{
|
||||
return m_size;
|
||||
return static_cast<T>(m_size);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
|
|
|||
|
|
@ -340,7 +340,8 @@ namespace gl
|
|||
|
||||
void cs_d24x8_to_ssbo::run(gl::command_context& cmd, gl::viewable_image* src, const gl::buffer* dst, u32 out_offset, const coordu& region, const gl::pixel_buffer_layout& layout)
|
||||
{
|
||||
const auto row_pitch = region.width;
|
||||
const auto row_pitch = layout.row_length ? layout.row_length : region.width;
|
||||
ensure(row_pitch >= region.width);
|
||||
|
||||
m_program.uniforms["swap_bytes"] = layout.swap_bytes;
|
||||
m_program.uniforms["output_pitch"] = row_pitch;
|
||||
|
|
@ -390,14 +391,15 @@ namespace gl
|
|||
|
||||
void cs_rgba8_to_ssbo::run(gl::command_context& cmd, gl::viewable_image* src, const gl::buffer* dst, u32 out_offset, const coordu& region, const gl::pixel_buffer_layout& layout)
|
||||
{
|
||||
const auto row_pitch = region.width;
|
||||
const auto row_pitch = layout.row_length ? layout.row_length : region.width;
|
||||
ensure(row_pitch >= region.width);
|
||||
|
||||
m_program.uniforms["swap_bytes"] = layout.swap_bytes;
|
||||
m_program.uniforms["output_pitch"] = row_pitch;
|
||||
m_program.uniforms["region_offset"] = color2i(region.x, region.y);
|
||||
m_program.uniforms["region_size"] = color2i(region.width, region.height);
|
||||
m_program.uniforms["is_bgra"] = (layout.format == static_cast<GLenum>(gl::texture::format::bgra));
|
||||
m_program.uniforms["block_width"] = static_cast<u32>(layout.size);
|
||||
m_program.uniforms["block_width"] = static_cast<u32>(layout.block_size);
|
||||
|
||||
auto data_view = src->get_view(rsx::default_remap_vector.with_encoding(GL_REMAP_IDENTITY), gl::image_aspect::color);
|
||||
|
||||
|
|
@ -441,6 +443,7 @@ namespace gl
|
|||
{
|
||||
const u32 bpp = dst->image()->pitch() / dst->image()->width();
|
||||
const u32 row_length = utils::align(dst_region.width * bpp, std::max<int>(layout.alignment, 1)) / bpp;
|
||||
ensure(row_length >= dst_region.width);
|
||||
|
||||
m_program.uniforms["swap_bytes"] = layout.swap_bytes;
|
||||
m_program.uniforms["src_pitch"] = row_length;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace gl
|
|||
void* userptr = vm::get_super_ptr(base_address);
|
||||
|
||||
m_data = std::make_unique<gl::buffer>();
|
||||
m_data->create(buffer::target::array, block_size, userptr, buffer::memory_type::userptr, 0);
|
||||
m_data->create(buffer::target::copy_dst, block_size, userptr, buffer::memory_type::userptr, 0);
|
||||
m_base_address = base_address;
|
||||
|
||||
// Some drivers may reject userptr input for whatever reason. Check that the state is still valid.
|
||||
|
|
@ -77,7 +77,7 @@ namespace gl
|
|||
{
|
||||
const auto start_block_address = start & s_dma_block_mask;
|
||||
const auto end_block_address = (start + length + s_dma_block_size - 1) & s_dma_block_mask;
|
||||
return utils::address_range32::start_end(start_block_address, end_block_address);
|
||||
return utils::address_range32::start_length(start_block_address, end_block_address - start_block_address);
|
||||
}
|
||||
|
||||
const dma_block& get_block(u32 start, u32 length)
|
||||
|
|
|
|||
|
|
@ -249,22 +249,23 @@ void GLGSRender::on_init_thread()
|
|||
// Fallback null texture instead of relying on texture0
|
||||
{
|
||||
std::array<u32, 8> pixeldata = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
const rsx::io_buffer src_buf = std::span<u32>(pixeldata);
|
||||
|
||||
// 1D
|
||||
auto tex1D = std::make_unique<gl::texture>(GL_TEXTURE_1D, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
|
||||
tex1D->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
tex1D->copy_from(src_buf, gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
|
||||
// 2D
|
||||
auto tex2D = std::make_unique<gl::texture>(GL_TEXTURE_2D, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
|
||||
tex2D->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
tex2D->copy_from(src_buf, gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
|
||||
// 3D
|
||||
auto tex3D = std::make_unique<gl::texture>(GL_TEXTURE_3D, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
|
||||
tex3D->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
tex3D->copy_from(src_buf, gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
|
||||
// CUBE
|
||||
auto texCUBE = std::make_unique<gl::texture>(GL_TEXTURE_CUBE_MAP, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
|
||||
texCUBE->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
texCUBE->copy_from(src_buf, gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
|
||||
m_null_textures[GL_TEXTURE_1D] = std::move(tex1D);
|
||||
m_null_textures[GL_TEXTURE_2D] = std::move(tex2D);
|
||||
|
|
@ -397,6 +398,7 @@ void GLGSRender::on_init_thread()
|
|||
m_ui_renderer.create();
|
||||
m_video_output_pass.create();
|
||||
|
||||
gl::init_global_texture_resources();
|
||||
m_gl_texture_cache.initialize();
|
||||
|
||||
m_prog_buffer.initialize
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ namespace gl
|
|||
gl::texture_view* ui_overlay_renderer::load_simple_image(rsx::overlays::image_info_base* desc, bool temp_resource, u32 owner_uid)
|
||||
{
|
||||
auto tex = std::make_unique<gl::texture>(GL_TEXTURE_2D, desc->w, desc->h, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
|
||||
tex->copy_from(desc->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
tex->copy_from(desc->as_span(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
|
||||
const GLenum remap[] = { GL_RED, GL_ALPHA, GL_BLUE, GL_GREEN };
|
||||
auto view = std::make_unique<gl::texture_view>(tex.get(), remap);
|
||||
|
|
@ -308,7 +308,7 @@ namespace gl
|
|||
const std::vector<u8>& glyph_data = font->get_glyph_data();
|
||||
|
||||
auto tex = std::make_unique<gl::texture>(GL_TEXTURE_2D_ARRAY, font_size.width, font_size.height, font_size.depth, 1, 1, GL_R8, RSX_FORMAT_CLASS_COLOR);
|
||||
tex->copy_from(glyph_data.data(), gl::texture::format::r, gl::texture::type::ubyte, {});
|
||||
tex->copy_from(std::span<const u8>(glyph_data), gl::texture::format::r, gl::texture::type::ubyte, {});
|
||||
|
||||
GLenum remap[] = { GL_RED, GL_RED, GL_RED, GL_RED };
|
||||
auto view = std::make_unique<gl::texture_view>(tex.get(), remap);
|
||||
|
|
@ -332,7 +332,7 @@ namespace gl
|
|||
|
||||
if (dirty)
|
||||
{
|
||||
view->image()->copy_from(desc->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
view->image()->copy_from(desc->as_span(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
}
|
||||
|
||||
return view;
|
||||
|
|
@ -551,7 +551,8 @@ namespace gl
|
|||
const pixel_buffer_layout& layout)
|
||||
{
|
||||
const u32 bpp = dst->image()->pitch() / dst->image()->width();
|
||||
const u32 row_length = utils::align(dst_region.width * bpp, std::max<int>(layout.alignment, 1)) / bpp;
|
||||
const u32 aligned_width = utils::align(dst_region.width * bpp, std::max<int>(layout.alignment, 1)) / bpp;
|
||||
const u32 row_length = layout.row_length ? layout.row_length : aligned_width;
|
||||
|
||||
program_handle.uniforms["src_pitch"] = row_length;
|
||||
program_handle.uniforms["swap_bytes"] = layout.swap_bytes;
|
||||
|
|
|
|||
|
|
@ -132,7 +132,8 @@ gl::texture* GLGSRender::get_present_source(gl::present_surface_info* info, cons
|
|||
const auto range = utils::address_range32::start_length(info->address, info->pitch * info->height);
|
||||
m_gl_texture_cache.invalidate_range(cmd, range, rsx::invalidation_cause::read);
|
||||
|
||||
flip_image->copy_from(vm::base(info->address), static_cast<gl::texture::format>(expected_format), gl::texture::type::uint_8_8_8_8, unpack_settings);
|
||||
const rsx::io_buffer read_buf = { vm::base(info->address), range.length() };
|
||||
flip_image->copy_from(read_buf, static_cast<gl::texture::format>(expected_format), gl::texture::type::uint_8_8_8_8, unpack_settings);
|
||||
image = flip_image.get();
|
||||
}
|
||||
else if (image->get_internal_format() != static_cast<gl::texture::internal_format>(expected_format))
|
||||
|
|
@ -368,7 +369,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
|
|||
std::vector<u8> sshot_frame(buffer_height * buffer_width * 4);
|
||||
glGetError();
|
||||
|
||||
tex->copy_to(sshot_frame.data(), gl::texture::format::rgba, gl::texture::type::ubyte, pack_settings);
|
||||
tex->copy_to(std::span<const u8>(sshot_frame), gl::texture::format::rgba, gl::texture::type::ubyte, pack_settings);
|
||||
|
||||
m_sshot_tex.reset();
|
||||
|
||||
|
|
|
|||
|
|
@ -218,6 +218,9 @@ OPENGL_PROC(PFNGLNAMEDBUFFERDATAEXTPROC, NamedBufferDataEXT);
|
|||
OPENGL_PROC(PFNGLNAMEDBUFFERSUBDATAPROC, NamedBufferSubData);
|
||||
OPENGL_PROC(PFNGLNAMEDBUFFERSUBDATAEXTPROC, NamedBufferSubDataEXT);
|
||||
|
||||
OPENGL_PROC(PFNGLCLEARNAMEDBUFFERSUBDATAPROC, ClearNamedBufferSubData);
|
||||
OPENGL_PROC(PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC, ClearNamedBufferSubDataEXT);
|
||||
|
||||
// ARB_shader_image_load_store
|
||||
OPENGL_PROC(PFNGLBINDIMAGETEXTUREPROC, BindImageTexture);
|
||||
|
||||
|
|
@ -256,6 +259,7 @@ OPENGL_PROC(PFNGLDELETESYNCPROC, DeleteSync);
|
|||
|
||||
// KHR_debug
|
||||
OPENGL_PROC(PFNGLDEBUGMESSAGECALLBACKPROC, DebugMessageCallback);
|
||||
OPENGL_PROC(PFNGLOBJECTLABELPROC, ObjectLabel);
|
||||
|
||||
// Immutable textures
|
||||
OPENGL_PROC(PFNGLTEXSTORAGE1DPROC, TexStorage1D);
|
||||
|
|
|
|||
|
|
@ -689,6 +689,8 @@ gl::viewable_image* gl::render_target::get_resolve_target_safe(gl::command_conte
|
|||
static_cast<GLenum>(get_internal_format()),
|
||||
format_class()
|
||||
));
|
||||
|
||||
resolve_surface->set_name(fmt::format("MSAA_Resolve_%u@0x%x", resolve_surface->id(), base_addr));
|
||||
}
|
||||
|
||||
return static_cast<gl::viewable_image*>(resolve_surface.get());
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@ struct gl_render_target_traits
|
|||
std::unique_ptr<gl::render_target> result(new gl::render_target(width_, height_, samples,
|
||||
static_cast<GLenum>(format.internal_format), RSX_FORMAT_CLASS_COLOR));
|
||||
|
||||
result->set_name(fmt::format("RTV_%u@0x%x", result->id(), address));
|
||||
result->set_aa_mode(antialias);
|
||||
result->set_native_pitch(static_cast<u32>(width) * get_format_block_size_in_bytes(surface_color_format) * result->samples_x);
|
||||
result->set_surface_dimensions(static_cast<u16>(width), static_cast<u16>(height), static_cast<u32>(pitch));
|
||||
|
|
@ -203,6 +204,7 @@ struct gl_render_target_traits
|
|||
std::unique_ptr<gl::render_target> result(new gl::render_target(width_, height_, samples,
|
||||
static_cast<GLenum>(format.internal_format), rsx::classify_format(surface_depth_format)));
|
||||
|
||||
result->set_name(fmt::format("DSV_%u@0x%x", result->id(), address));
|
||||
result->set_aa_mode(antialias);
|
||||
result->set_surface_dimensions(static_cast<u16>(width), static_cast<u16>(height), static_cast<u32>(pitch));
|
||||
result->set_format(surface_depth_format);
|
||||
|
|
@ -238,6 +240,7 @@ struct gl_render_target_traits
|
|||
sink->state_flags = rsx::surface_state_flags::erase_bkgnd;
|
||||
sink->format_info = ref->format_info;
|
||||
|
||||
sink->set_name(fmt::format("SINK_%u@0x%x", sink->id(), address));
|
||||
sink->set_spp(ref->get_spp());
|
||||
sink->set_native_pitch(static_cast<u32>(prev.width) * ref->get_bpp() * ref->samples_x);
|
||||
sink->set_rsx_pitch(ref->get_rsx_pitch());
|
||||
|
|
@ -325,6 +328,7 @@ struct gl_render_target_traits
|
|||
std::array<GLenum, 4> native_layout = { static_cast<GLenum>(fmt.swizzle.a), static_cast<GLenum>(fmt.swizzle.r), static_cast<GLenum>(fmt.swizzle.g), static_cast<GLenum>(fmt.swizzle.b) };
|
||||
surface->set_native_component_layout(native_layout);
|
||||
surface->set_format(format);
|
||||
surface->set_name(fmt::format("RTV_%u@0x%x", surface->id(), address));
|
||||
|
||||
int_invalidate_surface_contents(cmd, surface, address, pitch);
|
||||
}
|
||||
|
|
@ -338,6 +342,7 @@ struct gl_render_target_traits
|
|||
usz pitch)
|
||||
{
|
||||
surface->set_format(format);
|
||||
surface->set_name(fmt::format("DSV_%u@0x%x", surface->id(), address));
|
||||
int_invalidate_surface_contents(cmd, surface, address, pitch);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -300,6 +300,7 @@ namespace gl
|
|||
}
|
||||
|
||||
builder << "\n"
|
||||
"#undef TEX_PARAM\n"
|
||||
"#define TEX_PARAM(index) texture_parameters[index + texture_base_index]\n"
|
||||
"#define IS_TEXTURE_RESIDENT(index) (texture_handles[index] < 0xFF)\n"
|
||||
"#define SAMPLER1D(index) sampler1D_array[texture_handles[index]]\n"
|
||||
|
|
|
|||
|
|
@ -22,6 +22,13 @@ namespace gl
|
|||
legacy_ring_buffer g_upload_transfer_buffer;
|
||||
scratch_ring_buffer g_compute_decode_buffer;
|
||||
scratch_ring_buffer g_deswizzle_scratch_buffer;
|
||||
blitter g_blitter;
|
||||
|
||||
void init_global_texture_resources()
|
||||
{
|
||||
g_blitter.init();
|
||||
g_hw_blitter = &g_blitter;
|
||||
}
|
||||
|
||||
void destroy_global_texture_resources()
|
||||
{
|
||||
|
|
@ -29,6 +36,8 @@ namespace gl
|
|||
g_upload_transfer_buffer.remove();
|
||||
g_compute_decode_buffer.remove();
|
||||
g_deswizzle_scratch_buffer.remove();
|
||||
g_blitter.destroy();
|
||||
g_hw_blitter = nullptr;
|
||||
}
|
||||
|
||||
template <typename WordType, bool SwapBytes>
|
||||
|
|
@ -157,42 +166,42 @@ namespace gl
|
|||
case texture::internal_format::compressed_rgba_s3tc_dxt1:
|
||||
case texture::internal_format::compressed_rgba_s3tc_dxt3:
|
||||
case texture::internal_format::compressed_rgba_s3tc_dxt5:
|
||||
return { GL_RGBA, GL_UNSIGNED_BYTE, 1, false };
|
||||
return { .format = GL_RGBA, .type = GL_UNSIGNED_BYTE, .block_size = 1, .swap_bytes = false };
|
||||
case texture::internal_format::r8:
|
||||
return { GL_RED, GL_UNSIGNED_BYTE, 1, false };
|
||||
return { .format = GL_RED, .type = GL_UNSIGNED_BYTE, .block_size = 1, .swap_bytes = false };
|
||||
case texture::internal_format::r16:
|
||||
return { GL_RED, GL_UNSIGNED_SHORT, 2, true };
|
||||
return { .format = GL_RED, .type = GL_UNSIGNED_SHORT, .block_size = 2, .swap_bytes = true };
|
||||
case texture::internal_format::r32f:
|
||||
return { GL_RED, GL_FLOAT, 4, true };
|
||||
return { .format = GL_RED, .type = GL_FLOAT, .block_size = 4, .swap_bytes = true };
|
||||
case texture::internal_format::rg8:
|
||||
return { GL_RG, GL_UNSIGNED_SHORT, 2, true };
|
||||
return { .format = GL_RG, .type = GL_UNSIGNED_SHORT, .block_size = 2, .swap_bytes = true };
|
||||
case texture::internal_format::rg16:
|
||||
return { GL_RG, GL_UNSIGNED_SHORT, 2, true };
|
||||
return { .format = GL_RG, .type = GL_UNSIGNED_SHORT, .block_size = 2, .swap_bytes = true };
|
||||
case texture::internal_format::rg16f:
|
||||
return { GL_RG, GL_HALF_FLOAT, 2, true };
|
||||
return { .format = GL_RG, .type = GL_HALF_FLOAT, .block_size = 2, .swap_bytes = true };
|
||||
case texture::internal_format::rgb565:
|
||||
return { GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 2, true };
|
||||
return { .format = GL_RGB, .type = GL_UNSIGNED_SHORT_5_6_5, .block_size = 2, .swap_bytes = true };
|
||||
case texture::internal_format::rgb5a1:
|
||||
return { GL_RGB, GL_UNSIGNED_SHORT_5_5_5_1, 2, true };
|
||||
return { .format = GL_RGB, .type = GL_UNSIGNED_SHORT_5_5_5_1, .block_size = 2, .swap_bytes = true };
|
||||
case texture::internal_format::bgr5a1:
|
||||
return { GL_RGB, GL_UNSIGNED_SHORT_1_5_5_5_REV, 2, true };
|
||||
return { .format = GL_RGB, .type = GL_UNSIGNED_SHORT_1_5_5_5_REV, .block_size = 2, .swap_bytes = true };
|
||||
case texture::internal_format::rgba4:
|
||||
return { GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4, 2, false };
|
||||
return { .format = GL_BGRA, .type = GL_UNSIGNED_SHORT_4_4_4_4, .block_size = 2, .swap_bytes = false };
|
||||
case texture::internal_format::rgba8:
|
||||
return { GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 4, true };
|
||||
return { .format = GL_RGBA, .type = GL_UNSIGNED_INT_8_8_8_8_REV, .block_size = 4, .swap_bytes = true };
|
||||
case texture::internal_format::bgra8:
|
||||
return { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 4, true };
|
||||
return { .format = GL_BGRA, .type = GL_UNSIGNED_INT_8_8_8_8_REV, .block_size = 4, .swap_bytes = true };
|
||||
case texture::internal_format::rgba16f:
|
||||
return { GL_RGBA, GL_HALF_FLOAT, 2, true };
|
||||
return { .format = GL_RGBA, .type = GL_HALF_FLOAT, .block_size = 2, .swap_bytes = true };
|
||||
case texture::internal_format::rgba32f:
|
||||
return { GL_RGBA, GL_FLOAT, 4, true };
|
||||
return { .format = GL_RGBA, .type = GL_FLOAT, .block_size = 4, .swap_bytes = true };
|
||||
case texture::internal_format::depth16:
|
||||
return { GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 2, true };
|
||||
return { .format = GL_DEPTH_COMPONENT, .type = GL_UNSIGNED_SHORT, .block_size = 2, .swap_bytes = true };
|
||||
case texture::internal_format::depth32f:
|
||||
return { GL_DEPTH_COMPONENT, GL_FLOAT, 2, true };
|
||||
return { .format = GL_DEPTH_COMPONENT, .type = GL_FLOAT, .block_size = 2, .swap_bytes = true };
|
||||
case texture::internal_format::depth24_stencil8:
|
||||
case texture::internal_format::depth32f_stencil8:
|
||||
return { GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 4, true };
|
||||
return { .format = GL_DEPTH_STENCIL, .type = GL_UNSIGNED_INT_24_8, .block_size = 4, .swap_bytes = true };
|
||||
default:
|
||||
fmt::throw_exception("Unexpected internal format 0x%X", static_cast<u32>(format));
|
||||
}
|
||||
|
|
@ -311,7 +320,7 @@ namespace gl
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
switch (pack_info.size)
|
||||
switch (pack_info.block_size)
|
||||
{
|
||||
case 1:
|
||||
return nullptr;
|
||||
|
|
@ -363,8 +372,10 @@ namespace gl
|
|||
}
|
||||
}
|
||||
|
||||
dst->bind(buffer::target::pixel_pack);
|
||||
src->copy_to(reinterpret_cast<void*>(static_cast<uintptr_t>(dst_offset)), static_cast<texture::format>(pack_info.format), static_cast<texture::type>(pack_info.type), src_level, src_region, {});
|
||||
pixel_pack_settings pack_settings{};
|
||||
if (pack_info.alignment) pack_settings.alignment(pack_info.alignment);
|
||||
if (pack_info.row_length) pack_settings.row_length(pack_info.row_length);
|
||||
src->copy_to(*dst, dst_offset, static_cast<texture::format>(pack_info.format), static_cast<texture::type>(pack_info.type), src_level, src_region, pack_settings);
|
||||
return false;
|
||||
};
|
||||
|
||||
|
|
@ -611,10 +622,12 @@ namespace gl
|
|||
}
|
||||
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, GL_NONE);
|
||||
transfer_buf->bind(buffer::target::pixel_unpack);
|
||||
|
||||
dst->copy_from(reinterpret_cast<void*>(u64(out_offset)), static_cast<texture::format>(unpack_info.format),
|
||||
static_cast<texture::type>(unpack_info.type), dst_level, dst_region, {});
|
||||
pixel_unpack_settings unpack_settings{};
|
||||
if (unpack_info.alignment) unpack_settings.alignment(unpack_info.alignment);
|
||||
if (unpack_info.format) unpack_settings.row_length(unpack_info.row_length);
|
||||
dst->copy_from(*transfer_buf, out_offset, static_cast<texture::format>(unpack_info.format),
|
||||
static_cast<texture::type>(unpack_info.type), dst_level, dst_region, unpack_settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -712,7 +725,6 @@ namespace gl
|
|||
pixel_buffer_layout mem_layout;
|
||||
|
||||
std::span<std::byte> dst_buffer = staging_buffer;
|
||||
void* out_pointer = staging_buffer.data();
|
||||
u8 block_size_in_bytes = rsx::get_format_block_size_in_bytes(format);
|
||||
u64 image_linear_size = staging_buffer.size();
|
||||
|
||||
|
|
@ -731,8 +743,6 @@ namespace gl
|
|||
g_compute_decode_buffer.remove();
|
||||
g_compute_decode_buffer.create(gl::buffer::target::ssbo, min_required_buffer_size);
|
||||
}
|
||||
|
||||
out_pointer = nullptr;
|
||||
}
|
||||
|
||||
for (const rsx::subresource_layout& layout : input_layouts)
|
||||
|
|
@ -776,7 +786,7 @@ namespace gl
|
|||
mem_layout.swap_bytes = op.require_swap;
|
||||
mem_layout.format = gl_format;
|
||||
mem_layout.type = gl_type;
|
||||
mem_layout.size = block_size_in_bytes;
|
||||
mem_layout.block_size = block_size_in_bytes;
|
||||
|
||||
// 2. Upload memory to GPU
|
||||
if (!op.require_deswizzle)
|
||||
|
|
@ -867,7 +877,7 @@ namespace gl
|
|||
else
|
||||
{
|
||||
unpack_settings.swap_bytes(op.require_swap);
|
||||
dst->copy_from(out_pointer, static_cast<texture::format>(gl_format), static_cast<texture::type>(gl_type), layout.level, region, unpack_settings);
|
||||
dst->copy_from(staging_buffer, static_cast<texture::format>(gl_format), static_cast<texture::type>(gl_type), layout.level, region, unpack_settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1057,7 +1067,7 @@ namespace gl
|
|||
skip_transform = (pack_info.format == unpack_info.format &&
|
||||
pack_info.type == unpack_info.type &&
|
||||
pack_info.swap_bytes == unpack_info.swap_bytes &&
|
||||
pack_info.size == unpack_info.size);
|
||||
pack_info.block_size == unpack_info.block_size);
|
||||
}
|
||||
|
||||
if (skip_transform) [[likely]]
|
||||
|
|
@ -1138,7 +1148,7 @@ namespace gl
|
|||
if (src->aspect() & image_aspect::depth)
|
||||
{
|
||||
// Source is depth, modify unpack rule
|
||||
if (pack_info.size == 4 && unpack_info.size == 4)
|
||||
if (pack_info.block_size == 4 && unpack_info.block_size == 4)
|
||||
{
|
||||
unpack_info.swap_bytes = !unpack_info.swap_bytes;
|
||||
}
|
||||
|
|
@ -1146,7 +1156,7 @@ namespace gl
|
|||
else
|
||||
{
|
||||
// Dest is depth, modify pack rule
|
||||
if (pack_info.size == 4 && unpack_info.size == 4)
|
||||
if (pack_info.block_size == 4 && unpack_info.block_size == 4)
|
||||
{
|
||||
pack_info.swap_bytes = !pack_info.swap_bytes;
|
||||
}
|
||||
|
|
@ -1156,9 +1166,7 @@ namespace gl
|
|||
// Start pack operation
|
||||
pixel_pack_settings pack_settings{};
|
||||
pack_settings.swap_bytes(pack_info.swap_bytes);
|
||||
|
||||
g_typeless_transfer_buffer.get().bind(buffer::target::pixel_pack);
|
||||
src->copy_to(nullptr, static_cast<texture::format>(pack_info.format), static_cast<texture::type>(pack_info.type), 0, src_region, pack_settings);
|
||||
src->copy_to(g_typeless_transfer_buffer.get(), 0, static_cast<texture::format>(pack_info.format), static_cast<texture::type>(pack_info.type), 0, src_region, pack_settings);
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE);
|
||||
|
||||
|
|
@ -1166,8 +1174,7 @@ namespace gl
|
|||
pixel_unpack_settings unpack_settings{};
|
||||
unpack_settings.swap_bytes(unpack_info.swap_bytes);
|
||||
|
||||
g_typeless_transfer_buffer.get().bind(buffer::target::pixel_unpack);
|
||||
dst->copy_from(nullptr, static_cast<texture::format>(unpack_info.format), static_cast<texture::type>(unpack_info.type), 0, dst_region, unpack_settings);
|
||||
dst->copy_from(g_typeless_transfer_buffer.get(), 0, static_cast<texture::format>(unpack_info.format), static_cast<texture::type>(unpack_info.type), 0, dst_region, unpack_settings);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, GL_NONE);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,11 @@ namespace gl
|
|||
{
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
u8 size;
|
||||
u32 row_length;
|
||||
u8 block_size;
|
||||
bool swap_bytes;
|
||||
u8 alignment;
|
||||
u8 reserved;
|
||||
};
|
||||
|
||||
struct image_memory_requirements
|
||||
|
|
@ -86,5 +88,6 @@ namespace gl
|
|||
extern std::unique_ptr<texture> g_vis_texture;
|
||||
}
|
||||
|
||||
void init_global_texture_resources();
|
||||
void destroy_global_texture_resources();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,6 +152,8 @@ namespace gl
|
|||
dst = data.get();
|
||||
dst->properties_encoding = match_key;
|
||||
m_temporary_surfaces.emplace_back(std::move(data));
|
||||
|
||||
dst->set_name(fmt::format("[Temp View] id=%u, fmt=0x%x", dst->id(), gcm_format));
|
||||
}
|
||||
|
||||
dst->add_ref();
|
||||
|
|
@ -179,6 +181,10 @@ namespace gl
|
|||
auto components = get_component_mapping(gcm_format, rsx::component_order::default_);
|
||||
dst->set_native_component_layout(components);
|
||||
}
|
||||
else
|
||||
{
|
||||
dst->set_native_component_layout(src->get_native_component_layout());
|
||||
}
|
||||
|
||||
return dst->get_view(remap);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace gl
|
|||
|
||||
void init_buffer(const gl::texture* src)
|
||||
{
|
||||
const u32 vram_size = src->pitch() * src->height();
|
||||
const u32 vram_size = std::max(src->pitch() * src->height(), get_section_size());
|
||||
const u32 buffer_size = utils::align(vram_size, 4096);
|
||||
|
||||
if (pbo)
|
||||
|
|
@ -148,7 +148,7 @@ namespace gl
|
|||
}
|
||||
}
|
||||
|
||||
void dma_transfer(gl::command_context& cmd, gl::texture* src, const areai& /*src_area*/, const utils::address_range32& /*valid_range*/, u32 pitch)
|
||||
void dma_transfer(gl::command_context& cmd, gl::texture* src, const areai& src_area, const utils::address_range32& valid_range, u32 pitch)
|
||||
{
|
||||
init_buffer(src);
|
||||
glGetError();
|
||||
|
|
@ -165,6 +165,20 @@ namespace gl
|
|||
real_pitch = src->pitch();
|
||||
rsx_pitch = pitch;
|
||||
|
||||
const coord3u src_rgn =
|
||||
{
|
||||
{ static_cast<u32>(src_area.x1), static_cast<u32>(src_area.y1), 0 },
|
||||
{ static_cast<u32>(src_area.width()), static_cast<u32>(src_area.height()), 1 }
|
||||
};
|
||||
|
||||
u32 pbo_offset = 0;
|
||||
if (valid_range.valid())
|
||||
{
|
||||
const u32 section_base = get_section_base();
|
||||
pbo_offset = valid_range.start - section_base;
|
||||
ensure(valid_range.start >= section_base && pbo_offset <= pbo.size());
|
||||
}
|
||||
|
||||
bool use_driver_pixel_transform = true;
|
||||
if (get_driver_caps().ARB_compute_shader_supported) [[likely]]
|
||||
{
|
||||
|
|
@ -180,11 +194,12 @@ namespace gl
|
|||
|
||||
pack_info.format = static_cast<GLenum>(format);
|
||||
pack_info.type = static_cast<GLenum>(type);
|
||||
pack_info.size = (src->aspect() & image_aspect::stencil) ? 4 : 2;
|
||||
pack_info.block_size = (src->aspect() & image_aspect::stencil) ? 4 : 2;
|
||||
pack_info.swap_bytes = true;
|
||||
pack_info.row_length = rsx_pitch / pack_info.block_size;
|
||||
|
||||
mem_info.image_size_in_texels = src->width() * src->height();
|
||||
mem_info.image_size_in_bytes = src->pitch() * src->height();
|
||||
mem_info.image_size_in_texels = pack_info.row_length * src_area.height();
|
||||
mem_info.image_size_in_bytes = rsx_pitch * src_area.height();
|
||||
mem_info.memory_required = 0;
|
||||
|
||||
if (pack_info.type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV)
|
||||
|
|
@ -193,14 +208,16 @@ namespace gl
|
|||
mem_info.image_size_in_bytes *= 2;
|
||||
}
|
||||
|
||||
void* out_offset = copy_image_to_buffer(cmd, pack_info, src, &scratch_mem, 0, 0, { {}, src->size3D() }, &mem_info);
|
||||
void* out_offset = copy_image_to_buffer(cmd, pack_info, src, &scratch_mem, 0, 0, src_rgn, &mem_info);
|
||||
real_pitch = rsx_pitch;
|
||||
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, GL_NONE);
|
||||
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
|
||||
|
||||
real_pitch = pack_info.size * src->width();
|
||||
const u64 data_length = pack_info.size * mem_info.image_size_in_texels;
|
||||
scratch_mem.copy_to(&pbo, reinterpret_cast<u64>(out_offset), 0, data_length);
|
||||
const u64 data_length = mem_info.image_size_in_bytes - rsx_pitch + (src_area.width() * pack_info.block_size);
|
||||
ensure(data_length + pbo_offset <= static_cast<u64>(pbo.size()), "Memory allocation cannot fit image contents. Report to developers.");
|
||||
|
||||
scratch_mem.copy_to(&pbo, reinterpret_cast<u64>(out_offset), pbo_offset, data_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -219,13 +236,16 @@ namespace gl
|
|||
pack_unpack_swap_bytes = false;
|
||||
}
|
||||
|
||||
pbo.bind(buffer::target::pixel_pack);
|
||||
const auto bpp = src->pitch() / src->width();
|
||||
real_pitch = rsx_pitch;
|
||||
ensure((real_pitch % bpp) == 0);
|
||||
|
||||
pixel_pack_settings pack_settings;
|
||||
pack_settings.alignment(1);
|
||||
pack_settings.swap_bytes(pack_unpack_swap_bytes);
|
||||
pack_settings.row_length(rsx_pitch / bpp);
|
||||
|
||||
src->copy_to(nullptr, format, type, pack_settings);
|
||||
src->copy_to(pbo, pbo_offset, format, type, 0, src_rgn, pack_settings);
|
||||
}
|
||||
|
||||
if (auto error = glGetError())
|
||||
|
|
@ -266,6 +286,7 @@ namespace gl
|
|||
gl::texture* target_texture = vram_texture;
|
||||
u32 transfer_width = width;
|
||||
u32 transfer_height = height;
|
||||
u32 transfer_x = 0, transfer_y = 0;
|
||||
|
||||
if (context == rsx::texture_upload_context::framebuffer_storage)
|
||||
{
|
||||
|
|
@ -311,7 +332,35 @@ namespace gl
|
|||
}
|
||||
}
|
||||
|
||||
dma_transfer(cmd, target_texture, {}, {}, rsx_pitch);
|
||||
const auto valid_range = get_confirmed_range();
|
||||
if (const auto section_range = get_section_range(); section_range != valid_range)
|
||||
{
|
||||
if (const auto offset = (valid_range.start - get_section_base()))
|
||||
{
|
||||
transfer_y = offset / rsx_pitch;
|
||||
transfer_x = (offset % rsx_pitch) / rsx::get_format_block_size_in_bytes(gcm_format);
|
||||
|
||||
ensure(transfer_width >= transfer_x);
|
||||
ensure(transfer_height >= transfer_y);
|
||||
transfer_width -= transfer_x;
|
||||
transfer_height -= transfer_y;
|
||||
}
|
||||
|
||||
if (const auto tail = (section_range.end - valid_range.end))
|
||||
{
|
||||
const auto row_count = tail / rsx_pitch;
|
||||
|
||||
ensure(transfer_height >= row_count);
|
||||
transfer_height -= row_count;
|
||||
}
|
||||
}
|
||||
|
||||
areai src_area;
|
||||
src_area.x1 = static_cast<s32>(transfer_x);
|
||||
src_area.y1 = static_cast<s32>(transfer_y);
|
||||
src_area.x2 = s32(transfer_x + transfer_width);
|
||||
src_area.y2 = s32(transfer_y + transfer_height);
|
||||
dma_transfer(cmd, target_texture, src_area, valid_range, rsx_pitch);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -427,9 +476,7 @@ namespace gl
|
|||
using gl::viewable_image::viewable_image;
|
||||
};
|
||||
|
||||
blitter m_hw_blitter;
|
||||
std::vector<std::unique_ptr<temporary_image_t>> m_temporary_surfaces;
|
||||
|
||||
const u32 max_cached_image_pool_size = 256;
|
||||
|
||||
private:
|
||||
|
|
@ -733,6 +780,7 @@ namespace gl
|
|||
|
||||
gl::upload_texture(cmd, section->get_raw_texture(), gcm_format, input_swizzled, subresource_layout);
|
||||
|
||||
section->get_raw_texture()->set_name(fmt::format("Raw Texture @0x%x", rsx_range.start));
|
||||
section->last_write_tag = rsx::get_shared_tag();
|
||||
return section;
|
||||
}
|
||||
|
|
@ -810,16 +858,11 @@ namespace gl
|
|||
using baseclass::texture_cache;
|
||||
|
||||
void initialize()
|
||||
{
|
||||
m_hw_blitter.init();
|
||||
g_hw_blitter = &m_hw_blitter;
|
||||
}
|
||||
{}
|
||||
|
||||
void destroy() override
|
||||
{
|
||||
clear();
|
||||
g_hw_blitter = nullptr;
|
||||
m_hw_blitter.destroy();
|
||||
}
|
||||
|
||||
bool is_depth_texture(u32 rsx_address, u32 rsx_size) override
|
||||
|
|
@ -865,7 +908,7 @@ namespace gl
|
|||
|
||||
bool blit(gl::command_context& cmd, const rsx::blit_src_info& src, const rsx::blit_dst_info& dst, bool linear_interpolate, gl_render_targets& m_rtts)
|
||||
{
|
||||
auto result = upload_scaled_image(src, dst, linear_interpolate, cmd, m_rtts, m_hw_blitter);
|
||||
auto result = upload_scaled_image(src, dst, linear_interpolate, cmd, m_rtts, *g_hw_blitter);
|
||||
|
||||
if (result.succeeded)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,18 @@ namespace gl
|
|||
{
|
||||
blitter* g_hw_blitter = nullptr;
|
||||
|
||||
void blitter::init()
|
||||
{
|
||||
blit_src.create();
|
||||
blit_dst.create();
|
||||
}
|
||||
|
||||
void blitter::destroy()
|
||||
{
|
||||
blit_dst.remove();
|
||||
blit_src.remove();
|
||||
}
|
||||
|
||||
void blitter::copy_image(gl::command_context&, const texture* src, const texture* dst, int src_level, int dst_level, const position3i& src_offset, const position3i& dst_offset, const size3i& size) const
|
||||
{
|
||||
ensure(src_level == 0);
|
||||
|
|
@ -147,6 +159,9 @@ namespace gl
|
|||
gl::fbo::attachment dst_att{ blit_dst, static_cast<fbo::attachment::type>(attachment) };
|
||||
dst_att = *real_dst;
|
||||
|
||||
blit_src.check();
|
||||
blit_dst.check();
|
||||
|
||||
blit_src.blit(blit_dst, src_rect, dst_rect, target, interp);
|
||||
|
||||
// Release the attachments explicitly (not doing so causes glitches, e.g Journey Menu)
|
||||
|
|
|
|||
|
|
@ -30,17 +30,9 @@ namespace gl
|
|||
|
||||
public:
|
||||
|
||||
void init()
|
||||
{
|
||||
blit_src.create();
|
||||
blit_dst.create();
|
||||
}
|
||||
void init();
|
||||
|
||||
void destroy()
|
||||
{
|
||||
blit_dst.remove();
|
||||
blit_src.remove();
|
||||
}
|
||||
void destroy();
|
||||
|
||||
void scale_image(gl::command_context& cmd, const texture* src, texture* dst, areai src_rect, areai dst_rect, bool linear_interpolation,
|
||||
const rsx::typeless_xfer& xfer_info);
|
||||
|
|
|
|||
|
|
@ -131,6 +131,11 @@ namespace gl
|
|||
DSA_CALL2(NamedBufferSubData, m_id, offset, length, data);
|
||||
}
|
||||
|
||||
void buffer::fill(GLsizeiptr offset, GLsizeiptr length, GLuint pattern)
|
||||
{
|
||||
DSA_CALL2(ClearNamedBufferSubData, m_id, GL_R32UI, offset, length, GL_RED, GL_UNSIGNED_INT, &pattern);
|
||||
}
|
||||
|
||||
GLubyte* buffer::map(GLsizeiptr offset, GLsizeiptr length, access access_)
|
||||
{
|
||||
ensure(m_memory_type == memory_type::host_visible);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ namespace gl
|
|||
element_array = GL_ELEMENT_ARRAY_BUFFER,
|
||||
uniform = GL_UNIFORM_BUFFER,
|
||||
texture = GL_TEXTURE_BUFFER,
|
||||
ssbo = GL_SHADER_STORAGE_BUFFER
|
||||
ssbo = GL_SHADER_STORAGE_BUFFER,
|
||||
copy_src = GL_COPY_READ_BUFFER,
|
||||
copy_dst = GL_COPY_WRITE_BUFFER
|
||||
};
|
||||
|
||||
enum class access
|
||||
|
|
@ -65,6 +67,8 @@ namespace gl
|
|||
case target::uniform: pname = GL_UNIFORM_BUFFER_BINDING; break;
|
||||
case target::texture: pname = GL_TEXTURE_BUFFER_BINDING; break;
|
||||
case target::ssbo: pname = GL_SHADER_STORAGE_BUFFER_BINDING; break;
|
||||
case target::copy_src: pname = GL_COPY_READ_BUFFER_BINDING; break;
|
||||
case target::copy_dst: pname = GL_COPY_WRITE_BUFFER_BINDING; break;
|
||||
default: fmt::throw_exception("Invalid binding state target (0x%x)", static_cast<int>(target_));
|
||||
}
|
||||
|
||||
|
|
@ -113,6 +117,7 @@ namespace gl
|
|||
|
||||
void data(GLsizeiptr size, const void* data_ = nullptr, GLenum usage = GL_STREAM_DRAW);
|
||||
void sub_data(GLsizeiptr offset, GLsizeiptr length, const GLvoid* data);
|
||||
void fill(GLsizeiptr offset, GLsizeiptr length, GLuint pattern);
|
||||
|
||||
GLubyte* map(GLsizeiptr offset, GLsizeiptr length, access access_);
|
||||
void unmap();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "capabilities.h"
|
||||
|
||||
#include "Utilities/StrUtil.h"
|
||||
#include "Emu/system_config.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
|
|
@ -43,6 +44,8 @@ namespace gl
|
|||
all_extensions.emplace(reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i)));
|
||||
}
|
||||
|
||||
RENDERDOC_debug = !!g_cfg.video.renderdoc_compatiblity;
|
||||
|
||||
#define CHECK_EXTENSION_SUPPORT(extension_short_name)\
|
||||
do {\
|
||||
if (all_extensions.contains("GL_"#extension_short_name)) {\
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ namespace gl
|
|||
bool initialized = false;
|
||||
version_info glsl_version;
|
||||
|
||||
bool RENDERDOC_debug = false;
|
||||
bool EXT_direct_state_access_supported = false;
|
||||
bool EXT_depth_bounds_test_supported = false;
|
||||
bool AMD_pinned_memory_supported = false;
|
||||
|
|
|
|||
|
|
@ -76,10 +76,30 @@ namespace gl
|
|||
}
|
||||
};
|
||||
|
||||
// Very useful util when capturing traces with RenderDoc
|
||||
static inline void push_debug_label(const char* label)
|
||||
template <GLenum Ns>
|
||||
struct named_object
|
||||
{
|
||||
glInsertEventMarkerEXT(static_cast<GLsizei>(strlen(label)), label);
|
||||
protected:
|
||||
GLuint m_id = GL_NONE;
|
||||
std::string m_name = "Unnamed";
|
||||
|
||||
public:
|
||||
void set_name(std::string_view name)
|
||||
{
|
||||
m_name = name.data();
|
||||
glObjectLabel(Ns, m_id, static_cast<GLsizei>(name.length()), name.data());
|
||||
}
|
||||
|
||||
std::string_view name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
};
|
||||
|
||||
// Very useful util when capturing traces with RenderDoc
|
||||
static inline void push_debug_label(std::string_view label)
|
||||
{
|
||||
glInsertEventMarkerEXT(static_cast<GLsizei>(label.size()), label.data());
|
||||
}
|
||||
|
||||
// Checks if GL state is still valid
|
||||
|
|
|
|||
|
|
@ -19,6 +19,54 @@ namespace gl
|
|||
}
|
||||
}
|
||||
|
||||
static const char* gl_type_to_str(texture::type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case texture::type::ubyte: return "GL_UNSIGNED_BYTE";
|
||||
case texture::type::ushort: return "GL_UNSIGNED_SHORT";
|
||||
case texture::type::uint: return "GL_UNSIGNED_INT";
|
||||
case texture::type::ubyte_3_3_2: return "GL_UNSIGNED_BYTE_3_3_2";
|
||||
case texture::type::ubyte_2_3_3_rev: return "GL_UNSIGNED_BYTE_2_3_3_REV";
|
||||
case texture::type::ushort_5_6_5: return "GL_UNSIGNED_SHORT_5_6_5";
|
||||
case texture::type::ushort_5_6_5_rev: return "GL_UNSIGNED_SHORT_5_6_5_REV";
|
||||
case texture::type::ushort_4_4_4_4: return "GL_UNSIGNED_SHORT_4_4_4_4";
|
||||
case texture::type::ushort_4_4_4_4_rev: return "GL_UNSIGNED_SHORT_4_4_4_4_REV";
|
||||
case texture::type::ushort_5_5_5_1: return "GL_UNSIGNED_SHORT_5_5_5_1";
|
||||
case texture::type::ushort_1_5_5_5_rev: return "GL_UNSIGNED_SHORT_1_5_5_5_REV";
|
||||
case texture::type::uint_8_8_8_8: return "GL_UNSIGNED_INT_8_8_8_8";
|
||||
case texture::type::uint_8_8_8_8_rev: return "GL_UNSIGNED_INT_8_8_8_8_REV";
|
||||
case texture::type::uint_10_10_10_2: return "GL_UNSIGNED_INT_10_10_10_2";
|
||||
case texture::type::uint_2_10_10_10_rev: return "GL_UNSIGNED_INT_2_10_10_10_REV";
|
||||
case texture::type::uint_24_8: return "GL_UNSIGNED_INT_24_8";
|
||||
case texture::type::float32_uint8: return "GL_FLOAT_32_UNSIGNED_INT_24_8_REV";
|
||||
case texture::type::sbyte: return "GL_BYTE";
|
||||
case texture::type::sshort: return "GL_SHORT";
|
||||
case texture::type::sint: return "GL_INT";
|
||||
case texture::type::f16: return "GL_HALF_FLOAT";
|
||||
case texture::type::f32: return "GL_FLOAT";
|
||||
case texture::type::f64: return "GL_DOUBLE";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const char* gl_format_to_str(texture::format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case texture::format::r: return "GL_RED";
|
||||
case texture::format::rg: return "GL_RG";
|
||||
case texture::format::rgb: return "GL_RGB";
|
||||
case texture::format::rgba: return "GL_RGBA";
|
||||
case texture::format::bgr: return "GL_BGR";
|
||||
case texture::format::bgra: return "GL_BGRA";
|
||||
case texture::format::stencil: return "GL_STENCIL_INDEX";
|
||||
case texture::format::depth: return "GL_DEPTH_COMPONENT";
|
||||
case texture::format::depth_stencil: return "GL_DEPTH_STENCIL";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
texture::texture(GLenum target, GLuint width, GLuint height, GLuint depth, GLuint mipmaps, GLubyte samples, GLenum sized_format, rsx::format_class format_class)
|
||||
{
|
||||
// Upgrade targets for MSAA
|
||||
|
|
@ -175,7 +223,7 @@ namespace gl
|
|||
m_id = GL_NONE;
|
||||
}
|
||||
|
||||
void texture::copy_from(const void* src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings)
|
||||
void texture::copy_from(const rsx::io_buffer& src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings)
|
||||
{
|
||||
ensure(m_samples <= 1, "Transfer operations are unsupported on multisampled textures.");
|
||||
|
||||
|
|
@ -185,30 +233,30 @@ namespace gl
|
|||
{
|
||||
case GL_TEXTURE_1D:
|
||||
{
|
||||
DSA_CALL(TextureSubImage1D, m_id, GL_TEXTURE_1D, level, region.x, region.width, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
DSA_CALL(TextureSubImage1D, m_id, GL_TEXTURE_1D, level, region.x, region.width, static_cast<GLenum>(format), static_cast<GLenum>(type), src.data());
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_2D:
|
||||
{
|
||||
DSA_CALL(TextureSubImage2D, m_id, GL_TEXTURE_2D, level, region.x, region.y, region.width, region.height, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
DSA_CALL(TextureSubImage2D, m_id, GL_TEXTURE_2D, level, region.x, region.y, region.width, region.height, static_cast<GLenum>(format), static_cast<GLenum>(type), src.data());
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_3D:
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
{
|
||||
DSA_CALL(TextureSubImage3D, m_id, target_, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
DSA_CALL(TextureSubImage3D, m_id, target_, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src.data());
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
{
|
||||
if (get_driver_caps().ARB_direct_state_access_supported)
|
||||
{
|
||||
glTextureSubImage3D(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
glTextureSubImage3D(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
rsx_log.warning("Cubemap upload via texture::copy_from is halfplemented!");
|
||||
auto ptr = static_cast<const u8*>(src);
|
||||
auto ptr = static_cast<const u8*>(src.data());
|
||||
const auto end = std::min(6u, region.z + region.depth);
|
||||
for (unsigned face = region.z; face < end; ++face)
|
||||
{
|
||||
|
|
@ -221,40 +269,51 @@ namespace gl
|
|||
}
|
||||
}
|
||||
|
||||
void texture::copy_from(buffer& buf, u32 gl_format_type, u32 offset, u32 length)
|
||||
void texture::copy_from(buffer& buf, GLsizeiptr offset, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings)
|
||||
{
|
||||
ensure(m_samples <= 1, "Transfer operations are unsupported on multisampled textures.");
|
||||
|
||||
if (get_target() != target::textureBuffer)
|
||||
fmt::throw_exception("OpenGL error: texture cannot copy from buffer");
|
||||
buf.bind(buffer::target::pixel_unpack);
|
||||
|
||||
DSA_CALL(TextureBufferRange, m_id, GL_TEXTURE_BUFFER, gl_format_type, buf.id(), offset, length);
|
||||
const rsx::io_buffer src{ reinterpret_cast<void*>(static_cast<uintptr_t>(offset)), buf.size() - offset };
|
||||
copy_from(src, format, type, level, region, pixel_settings);
|
||||
}
|
||||
|
||||
void texture::copy_from(buffer_view& view)
|
||||
{
|
||||
copy_from(*view.value(), view.format(), view.offset(), view.range());
|
||||
if (get_target() != target::textureBuffer)
|
||||
fmt::throw_exception("OpenGL error: texture cannot copy from buffer");
|
||||
|
||||
DSA_CALL(TextureBufferRange, m_id, GL_TEXTURE_BUFFER, view.format(), view.value()->id(), view.offset(), view.range());
|
||||
}
|
||||
|
||||
void texture::copy_to(void* dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const
|
||||
void texture::copy_to(const rsx::io_buffer& dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const
|
||||
{
|
||||
ensure(m_samples <= 1, "Transfer operations are unsupported on multisampled textures.");
|
||||
|
||||
pixel_settings.apply();
|
||||
const auto& caps = get_driver_caps();
|
||||
|
||||
if (caps.RENDERDOC_debug)
|
||||
{
|
||||
const auto msg = fmt::format("glGetTextureSubImage('[%u] %s', %u, %u, %u, %u, %u, %u, %u, %s, %s, %d, %p)",
|
||||
m_id, m_name.c_str(), level, region.x, region.y, region.z, region.width, region.height, region.depth,
|
||||
gl_format_to_str(format), gl_type_to_str(type), s32{ smax }, dst.data());
|
||||
push_debug_label(msg);
|
||||
}
|
||||
|
||||
if (!region.x && !region.y && !region.z &&
|
||||
region.width == m_width && region.height == m_height && region.depth == m_depth)
|
||||
{
|
||||
if (caps.ARB_direct_state_access_supported)
|
||||
glGetTextureImage(m_id, level, static_cast<GLenum>(format), static_cast<GLenum>(type), s32{ smax }, dst);
|
||||
glGetTextureImage(m_id, level, static_cast<GLenum>(format), static_cast<GLenum>(type), dst.size<GLsizei>(), dst.data());
|
||||
else
|
||||
glGetTextureImageEXT(m_id, static_cast<GLenum>(m_target), level, static_cast<GLenum>(format), static_cast<GLenum>(type), dst);
|
||||
glGetTextureImageEXT(m_id, static_cast<GLenum>(m_target), level, static_cast<GLenum>(format), static_cast<GLenum>(type), dst.data());
|
||||
}
|
||||
else if (caps.ARB_direct_state_access_supported)
|
||||
{
|
||||
glGetTextureSubImage(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth,
|
||||
static_cast<GLenum>(format), static_cast<GLenum>(type), s32{ smax }, dst);
|
||||
static_cast<GLenum>(format), static_cast<GLenum>(type), s32{ smax }, dst.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -269,6 +328,16 @@ namespace gl
|
|||
}
|
||||
}
|
||||
|
||||
void texture::copy_to(buffer& buf, GLsizeiptr offset, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const
|
||||
{
|
||||
ensure(offset < buf.size(), "PBO write is out of range");
|
||||
|
||||
buf.bind(buffer::target::pixel_pack);
|
||||
|
||||
const rsx::io_buffer dst{ reinterpret_cast<void*>(static_cast<uintptr_t>(offset)), buf.size() - offset };
|
||||
copy_to(dst, format, type, level, region, pixel_settings);
|
||||
}
|
||||
|
||||
void texture_view::create(texture* data, GLenum target, GLenum sized_format, const subresource_range& range, const GLenum* argb_swizzle)
|
||||
{
|
||||
m_target = target;
|
||||
|
|
@ -397,6 +466,8 @@ namespace gl
|
|||
auto view = std::make_unique<texture_view>(this, swizzle, aspect_flags);
|
||||
auto result = view.get();
|
||||
views.emplace(key, std::move(view));
|
||||
|
||||
result->set_name(fmt::format("%s, remap=%x", name(), remap.encoded));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "Utilities/geometry.h"
|
||||
#include "Emu/RSX/Common/TextureUtils.h"
|
||||
#include "Emu/RSX/Common/io_buffer.h"
|
||||
|
||||
//using enum rsx::format_class;
|
||||
using namespace ::rsx::format_class_;
|
||||
|
|
@ -58,7 +59,7 @@ namespace gl
|
|||
GLuint num_layers;
|
||||
};
|
||||
|
||||
class texture
|
||||
class texture : public named_object<GL_TEXTURE>
|
||||
{
|
||||
friend class texture_view;
|
||||
|
||||
|
|
@ -180,7 +181,6 @@ namespace gl
|
|||
};
|
||||
|
||||
protected:
|
||||
GLuint m_id = GL_NONE;
|
||||
GLuint m_width = 0;
|
||||
GLuint m_height = 0;
|
||||
GLuint m_depth = 0;
|
||||
|
|
@ -321,32 +321,33 @@ namespace gl
|
|||
}
|
||||
|
||||
// Data management
|
||||
void copy_from(const void* src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings);
|
||||
void copy_from(const rsx::io_buffer& src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings);
|
||||
|
||||
void copy_from(buffer& buf, u32 gl_format_type, u32 offset, u32 length);
|
||||
void copy_from(buffer& buf, GLsizeiptr offset, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings);
|
||||
|
||||
void copy_from(buffer_view& view);
|
||||
|
||||
void copy_to(void* dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const;
|
||||
void copy_to(const rsx::io_buffer& dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const;
|
||||
|
||||
void copy_to(buffer& buf, GLsizeiptr offset, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const;
|
||||
|
||||
// Convenience wrappers
|
||||
void copy_from(const void* src, texture::format format, texture::type type, const pixel_unpack_settings& pixel_settings)
|
||||
void copy_from(const rsx::io_buffer& src, texture::format format, texture::type type, const pixel_unpack_settings& pixel_settings)
|
||||
{
|
||||
const coord3u region = { {}, size3D() };
|
||||
copy_from(src, format, type, 0, region, pixel_settings);
|
||||
}
|
||||
|
||||
void copy_to(void* dst, texture::format format, texture::type type, const pixel_pack_settings& pixel_settings) const
|
||||
void copy_to(const rsx::io_buffer& dst, texture::format format, texture::type type, const pixel_pack_settings& pixel_settings) const
|
||||
{
|
||||
const coord3u region = { {}, size3D() };
|
||||
copy_to(dst, format, type, 0, region, pixel_settings);
|
||||
}
|
||||
};
|
||||
|
||||
class texture_view
|
||||
class texture_view : public named_object<GL_TEXTURE>
|
||||
{
|
||||
protected:
|
||||
GLuint m_id = GL_NONE;
|
||||
GLenum m_target = 0;
|
||||
GLenum m_format = 0;
|
||||
GLenum m_view_format = 0;
|
||||
|
|
@ -462,6 +463,7 @@ namespace gl
|
|||
|
||||
class viewable_image : public texture
|
||||
{
|
||||
protected:
|
||||
std::unordered_map<u64, std::unique_ptr<texture_view>> views;
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ namespace rsx
|
|||
REGS(ctx)->decode(reg, REGS(ctx)->latch);
|
||||
}
|
||||
|
||||
void set_aa_control(context* ctx, u32 reg, u32 arg)
|
||||
void set_aa_control(context* ctx, u32 /*reg*/, u32 arg)
|
||||
{
|
||||
const auto latch = REGS(ctx)->latch;
|
||||
if (arg == latch)
|
||||
|
|
|
|||
30
rpcs3/Emu/RSX/Overlays/overlay_audio.cpp
Normal file
30
rpcs3/Emu/RSX/Overlays/overlay_audio.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include "stdafx.h"
|
||||
#include "overlay_audio.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
audio_player::audio_player(const std::string& audio_path)
|
||||
{
|
||||
init_audio(audio_path);
|
||||
}
|
||||
|
||||
void audio_player::init_audio(const std::string& audio_path)
|
||||
{
|
||||
if (audio_path.empty()) return;
|
||||
|
||||
m_video_source = ensure(Emu.GetCallbacks().make_video_source());
|
||||
m_video_source->set_audio_path(audio_path);
|
||||
}
|
||||
|
||||
void audio_player::set_active(bool active)
|
||||
{
|
||||
if (m_video_source)
|
||||
{
|
||||
m_video_source->set_active(active);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
rpcs3/Emu/RSX/Overlays/overlay_audio.h
Normal file
23
rpcs3/Emu/RSX/Overlays/overlay_audio.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "util/video_source.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
class audio_player
|
||||
{
|
||||
public:
|
||||
audio_player(const std::string& audio_path);
|
||||
~audio_player() = default;
|
||||
|
||||
void set_active(bool active);
|
||||
|
||||
private:
|
||||
void init_audio(const std::string& audio_path);
|
||||
|
||||
std::unique_ptr<video_source> m_video_source;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
#include "Emu/localized_string.h"
|
||||
|
||||
#include <memory>
|
||||
#include <span>
|
||||
|
||||
// Definitions for common UI controls and their routines
|
||||
namespace rsx
|
||||
|
|
@ -39,6 +40,9 @@ namespace rsx
|
|||
image_info_base() {}
|
||||
virtual ~image_info_base() {}
|
||||
virtual const u8* get_data() const = 0;
|
||||
virtual usz size_bytes() const { return static_cast<usz>(w * h * 4); } // UI images get converted to RGBA8
|
||||
|
||||
std::span<const u8> as_span() const { return { get_data(), size_bytes() }; }
|
||||
};
|
||||
|
||||
struct image_info : public image_info_base
|
||||
|
|
|
|||
|
|
@ -167,6 +167,23 @@ namespace rsx
|
|||
}
|
||||
}
|
||||
|
||||
void display_manager::start_audio(const std::string& audio_path)
|
||||
{
|
||||
if (audio_path.empty())
|
||||
{
|
||||
m_audio_player.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
m_audio_player = std::make_unique<audio_player>(audio_path);
|
||||
m_audio_player->set_active(true);
|
||||
}
|
||||
|
||||
void display_manager::stop_audio()
|
||||
{
|
||||
m_audio_player.reset();
|
||||
}
|
||||
|
||||
void display_manager::on_overlay_activated(const std::shared_ptr<overlay>& /*item*/)
|
||||
{
|
||||
// TODO: Internal management, callbacks, etc
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "overlays.h"
|
||||
#include "overlay_audio.h"
|
||||
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Utilities/mutex.h"
|
||||
|
|
@ -25,6 +26,8 @@ namespace rsx
|
|||
lf_queue<u32> m_type_ids_to_remove;
|
||||
atomic_t<u32> m_pending_removals_count = 0;
|
||||
|
||||
std::unique_ptr<audio_player> m_audio_player;
|
||||
|
||||
bool remove_type(u32 type_id);
|
||||
|
||||
bool remove_uid(u32 uid);
|
||||
|
|
@ -167,6 +170,9 @@ namespace rsx
|
|||
std::function<void(s32)> on_input_loop_exit = nullptr, // [optional] What to do with the result if any
|
||||
std::function<s32()> input_loop_override = nullptr); // [optional] What to do during the input loop. By default calls user_interface::run_input_loop
|
||||
|
||||
void start_audio(const std::string& audio_path);
|
||||
void stop_audio();
|
||||
|
||||
private:
|
||||
struct overlay_input_thread
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@ namespace rsx
|
|||
{
|
||||
save_dialog::save_dialog_entry::save_dialog_entry(const std::string& text1, const std::string& text2, const std::string& text3, u8 resource_id, const std::vector<u8>& icon_buf, const std::string& video_path)
|
||||
{
|
||||
const std::string audio_path; // no audio here
|
||||
std::unique_ptr<overlay_element> image = resource_id != image_resource_id::raw_image
|
||||
? std::make_unique<video_view>(video_path, resource_id)
|
||||
: !icon_buf.empty() ? std::make_unique<video_view>(video_path, icon_buf)
|
||||
: std::make_unique<video_view>(video_path, resource_config::standard_image_resource::save); // Fallback
|
||||
? std::make_unique<video_view>(video_path, audio_path, resource_id)
|
||||
: !icon_buf.empty() ? std::make_unique<video_view>(video_path, audio_path, icon_buf)
|
||||
: std::make_unique<video_view>(video_path, audio_path, resource_config::standard_image_resource::save); // Fallback
|
||||
image->set_size(160, 110);
|
||||
image->set_padding(36, 36, 11, 11); // Square image, 88x88
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ namespace rsx
|
|||
{
|
||||
namespace overlays
|
||||
{
|
||||
video_view::video_view(const std::string& video_path, const std::string& thumbnail_path)
|
||||
video_view::video_view(const std::string& video_path, const std::string& audio_path, const std::string& thumbnail_path)
|
||||
{
|
||||
init_video(video_path);
|
||||
init_video(video_path, audio_path);
|
||||
|
||||
if (!thumbnail_path.empty())
|
||||
{
|
||||
|
|
@ -17,9 +17,9 @@ namespace rsx
|
|||
}
|
||||
}
|
||||
|
||||
video_view::video_view(const std::string& video_path, const std::vector<u8>& thumbnail_buf)
|
||||
video_view::video_view(const std::string& video_path, const std::string& audio_path, const std::vector<u8>& thumbnail_buf)
|
||||
{
|
||||
init_video(video_path);
|
||||
init_video(video_path, audio_path);
|
||||
|
||||
if (!thumbnail_buf.empty())
|
||||
{
|
||||
|
|
@ -28,10 +28,10 @@ namespace rsx
|
|||
}
|
||||
}
|
||||
|
||||
video_view::video_view(const std::string& video_path, u8 thumbnail_id)
|
||||
video_view::video_view(const std::string& video_path, const std::string& audio_path, u8 thumbnail_id)
|
||||
: m_thumbnail_id(thumbnail_id)
|
||||
{
|
||||
init_video(video_path);
|
||||
init_video(video_path, audio_path);
|
||||
set_image_resource(thumbnail_id);
|
||||
}
|
||||
|
||||
|
|
@ -39,13 +39,11 @@ namespace rsx
|
|||
{
|
||||
}
|
||||
|
||||
void video_view::init_video(const std::string& video_path)
|
||||
void video_view::init_video(const std::string& video_path, const std::string& audio_path)
|
||||
{
|
||||
if (video_path.empty()) return;
|
||||
|
||||
m_video_source = Emu.GetCallbacks().make_video_source();
|
||||
ensure(!!m_video_source);
|
||||
|
||||
m_video_source = ensure(Emu.GetCallbacks().make_video_source());
|
||||
m_video_source->set_update_callback([this]()
|
||||
{
|
||||
if (m_video_active)
|
||||
|
|
@ -54,6 +52,7 @@ namespace rsx
|
|||
}
|
||||
});
|
||||
m_video_source->set_video_path(video_path);
|
||||
m_video_source->set_audio_path(audio_path);
|
||||
}
|
||||
|
||||
void video_view::set_active(bool active)
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ namespace rsx
|
|||
class video_view final : public image_view
|
||||
{
|
||||
public:
|
||||
video_view(const std::string& video_path, const std::string& thumbnail_path);
|
||||
video_view(const std::string& video_path, const std::vector<u8>& thumbnail_buf);
|
||||
video_view(const std::string& video_path, u8 thumbnail_id);
|
||||
video_view(const std::string& video_path, const std::string& audio_path, const std::string& thumbnail_path);
|
||||
video_view(const std::string& video_path, const std::string& audio_path, const std::vector<u8>& thumbnail_buf);
|
||||
video_view(const std::string& video_path, const std::string& audio_path, u8 thumbnail_id);
|
||||
virtual ~video_view();
|
||||
|
||||
void set_active(bool active);
|
||||
|
|
@ -30,7 +30,7 @@ namespace rsx
|
|||
compiled_resource& get_compiled() override;
|
||||
|
||||
private:
|
||||
void init_video(const std::string& video_path);
|
||||
void init_video(const std::string& video_path, const std::string& audio_path);
|
||||
|
||||
usz m_buffer_index = 0;
|
||||
std::array<std::unique_ptr<video_info>, 2> m_video_info; // double buffer
|
||||
|
|
|
|||
|
|
@ -31,14 +31,14 @@ namespace rsx::assembler::FP
|
|||
switch (dst.prec)
|
||||
{
|
||||
case RSX_FP_PRECISION_REAL:
|
||||
case RSX_FP_PRECISION_UNKNOWN:
|
||||
// case RSX_FP_PRECISION_UNKNOWN: // Unreachable
|
||||
break;
|
||||
case RSX_FP_PRECISION_HALF:
|
||||
if (!src0.fp16) return false;
|
||||
break;
|
||||
case RSX_FP_PRECISION_FIXED12:
|
||||
case RSX_FP_PRECISION_FIXED9:
|
||||
case RSX_FP_PRECISION_SATURATE:
|
||||
// case RSX_FP_PRECISION_SATURATE: // Unreachable
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -868,8 +868,11 @@ std::string FragmentProgramDecompiler::BuildCode()
|
|||
if (!m_is_valid_ucode)
|
||||
{
|
||||
// If the code is broken, do not compile. Simply NOP main and write empty outputs
|
||||
m_parr.params[PF_PARAM_UNIFORM].clear();
|
||||
insertHeader(OS);
|
||||
OS << "\n";
|
||||
insertConstants(OS);
|
||||
OS << "\n";
|
||||
OS << "void main()\n";
|
||||
OS << "{\n";
|
||||
OS << "#if 0\n";
|
||||
|
|
|
|||
|
|
@ -675,6 +675,8 @@ fragment_program_utils::fragment_program_metadata fragment_program_utils::analys
|
|||
// Otherwise we would need to follow the execution chain
|
||||
result.has_branch_instructions = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (rsx::assembler::FP::get_operand_count(opcode) > 0 &&
|
||||
|
|
|
|||
|
|
@ -711,6 +711,11 @@ namespace rsx
|
|||
if (g_cfg.misc.use_native_interface && (g_cfg.video.renderer == video_renderer::opengl || g_cfg.video.renderer == video_renderer::vulkan))
|
||||
{
|
||||
m_overlay_manager = g_fxo->init<rsx::overlays::display_manager>(0);
|
||||
|
||||
if (const std::string audio_path = Emu.GetSfoDir(true) + "/SND0.AT3"; fs::is_file(audio_path))
|
||||
{
|
||||
m_overlay_manager->start_audio(audio_path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_ar)
|
||||
|
|
@ -1101,6 +1106,11 @@ namespace rsx
|
|||
thread_ctrl::set_thread_affinity_mask(thread_ctrl::get_affinity_mask(thread_class::rsx));
|
||||
}
|
||||
|
||||
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
|
||||
{
|
||||
manager->stop_audio();
|
||||
}
|
||||
|
||||
while (!test_stopped())
|
||||
{
|
||||
// Wait for external pause events
|
||||
|
|
|
|||
|
|
@ -635,9 +635,16 @@ bool VKGSRender::bind_texture_env()
|
|||
{
|
||||
if (!(textures_ref & 1))
|
||||
{
|
||||
// Unused TIU
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_fs_binding_table->ftex_location[i] == umax)
|
||||
{
|
||||
// Corrupt shader table
|
||||
break;
|
||||
}
|
||||
|
||||
vk::image_view* view = nullptr;
|
||||
auto sampler_state = static_cast<vk::texture_cache::sampled_image_descriptor*>(fs_sampler_state[i].get());
|
||||
|
||||
|
|
@ -707,9 +714,16 @@ bool VKGSRender::bind_texture_env()
|
|||
{
|
||||
if (!(textures_ref & 1))
|
||||
{
|
||||
// Unused TIU
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_vs_binding_table->vtex_location[i] == umax)
|
||||
{
|
||||
// Corrupt shader
|
||||
break;
|
||||
}
|
||||
|
||||
if (!rsx::method_registers.vertex_textures[i].enabled())
|
||||
{
|
||||
const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i));
|
||||
|
|
|
|||
|
|
@ -264,6 +264,7 @@ namespace vk
|
|||
}
|
||||
|
||||
builder << "\n"
|
||||
"#undef TEX_PARAM\n"
|
||||
"#define TEX_PARAM(index) texture_parameters[index + texture_base_index]\n"
|
||||
"#define IS_TEXTURE_RESIDENT(index) true\n"
|
||||
"#define SAMPLER1D(index) sampler1D_array[index]\n"
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ namespace vk
|
|||
table.add(0x7420, 0x743F, chip_class::AMD_navi2x); // Navi 24 (Beige Goby)
|
||||
table.add(0x163F, chip_class::AMD_navi2x); // Navi 2X (Van Gogh)
|
||||
table.add(0x164D, 0x1681, chip_class::AMD_navi2x); // Navi 2X (Yellow Carp)
|
||||
table.add(0x13C0, chip_class::AMD_navi2x); // Navi 2X (Raphael Mendocino)
|
||||
table.add(0x7440, 0x745F, chip_class::AMD_navi3x); // Navi 31 (Only 744c, NAVI31XTX is confirmed)
|
||||
table.add(0x7460, 0x747F, chip_class::AMD_navi3x); // Navi 32 (Unverified)
|
||||
table.add(0x7480, 0x749F, chip_class::AMD_navi3x); // Navi 33 (Unverified)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "Common/unordered_map.hpp"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/cache_utils.hpp"
|
||||
#include "Emu/Memory/vm.h"
|
||||
#include "Emu/RSX/Program/RSXVertexProgram.h"
|
||||
#include "Emu/RSX/Program/RSXFragmentProgram.h"
|
||||
#include "Overlays/Shaders/shader_loading_dialog.h"
|
||||
|
|
@ -478,6 +479,7 @@ namespace rsx
|
|||
uptr local_address;
|
||||
u32 offset_in_heap;
|
||||
u32 data_length;
|
||||
u64 fingerprint;
|
||||
};
|
||||
|
||||
// A weak vertex cache with no data checks or memory range locks
|
||||
|
|
@ -502,11 +504,20 @@ namespace rsx
|
|||
{
|
||||
const auto key = hash(local_addr, data_length);
|
||||
const auto found = vertex_ranges.find(key);
|
||||
|
||||
if (found == vertex_ranges.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check if data in local_address changed vs what was stored in the vertex_cache
|
||||
if (auto sudo_ptr = vm::get_super_ptr<char>(local_addr);
|
||||
data_length >= 8 && found->second.fingerprint != *utils::bless<u64>(sudo_ptr))
|
||||
{
|
||||
vertex_ranges.erase(key);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::addressof(found->second);
|
||||
}
|
||||
|
||||
|
|
@ -517,6 +528,11 @@ namespace rsx
|
|||
v.local_address = local_addr;
|
||||
v.offset_in_heap = offset_in_heap;
|
||||
|
||||
if (auto sudo_ptr = vm::get_super_ptr<char>(local_addr); data_length >= 8)
|
||||
{
|
||||
v.fingerprint = *utils::bless<u64>(sudo_ptr);
|
||||
}
|
||||
|
||||
const auto key = hash(local_addr, data_length);
|
||||
vertex_ranges[key] = v;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ struct serial_ver_t
|
|||
std::set<u16> compatible_versions;
|
||||
};
|
||||
|
||||
static std::array<serial_ver_t, 27> s_serial_versions;
|
||||
static std::array<serial_ver_t, 34> s_serial_versions;
|
||||
|
||||
#define SERIALIZATION_VER(name, identifier, ...) \
|
||||
\
|
||||
|
|
@ -40,7 +40,7 @@ static std::array<serial_ver_t, 27> s_serial_versions;
|
|||
return ::s_serial_versions[identifier].current_version;\
|
||||
}
|
||||
|
||||
SERIALIZATION_VER(global_version, 0, 19) // For stuff not listed here
|
||||
SERIALIZATION_VER(global_version, 0, 20) // For stuff not listed here
|
||||
SERIALIZATION_VER(ppu, 1, 1, 2/*PPU sleep order*/, 3/*PPU FNID and module*/)
|
||||
SERIALIZATION_VER(spu, 2, 1)
|
||||
SERIALIZATION_VER(lv2_sync, 3, 1)
|
||||
|
|
@ -85,6 +85,16 @@ SERIALIZATION_VER(LLE, 24, 1)
|
|||
SERIALIZATION_VER(HLE, 25, 1)
|
||||
|
||||
SERIALIZATION_VER(cellSysutil, 26, 1, 2/*AVC2 Muting,Volume*/)
|
||||
SERIALIZATION_VER(cellDmuxPamf, 27, 1)
|
||||
|
||||
// For future modules
|
||||
SERIALIZATION_VER(cellReserved1, 27, 1)
|
||||
SERIALIZATION_VER(cellReserved2, 28, 1)
|
||||
SERIALIZATION_VER(cellReserved3, 29, 1)
|
||||
SERIALIZATION_VER(cellReserved4, 30, 1)
|
||||
SERIALIZATION_VER(cellReserved6, 31, 1)
|
||||
SERIALIZATION_VER(cellReserved7, 32, 1)
|
||||
SERIALIZATION_VER(cellReserved8, 33, 1)
|
||||
|
||||
template <>
|
||||
void fmt_class_string<std::remove_cvref_t<decltype(s_serial_versions)>>::format(std::string& out, u64 arg)
|
||||
|
|
|
|||
|
|
@ -10,15 +10,6 @@
|
|||
|
||||
LOG_CHANNEL(camera_log, "Camera");
|
||||
|
||||
#if !(SDL_VERSION_ATLEAST(3, 4, 0))
|
||||
namespace SDL_CameraPermissionState
|
||||
{
|
||||
constexpr int SDL_CAMERA_PERMISSION_STATE_DENIED = -1;
|
||||
constexpr int SDL_CAMERA_PERMISSION_STATE_PENDING = 0;
|
||||
constexpr int SDL_CAMERA_PERMISSION_STATE_APPROVED = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <>
|
||||
void fmt_class_string<SDL_CameraSpec>::format(std::string& out, u64 arg)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -102,8 +102,8 @@ bool sdl_instance::initialize_impl()
|
|||
set_hint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1");
|
||||
#endif
|
||||
|
||||
// Disable LG4FF driver on windows (only needed for SDL 3.4.0)
|
||||
#if _WIN32 && SDL_VERSION_ATLEAST(3, 4, 0)
|
||||
// Disable LG4FF driver on windows
|
||||
#if _WIN32
|
||||
set_hint(SDL_HINT_JOYSTICK_HIDAPI_LG4FF, "0");
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -569,7 +569,7 @@ std::unique_ptr<fs::file_base> iso_device::open(const std::string& path, bs_t<fs
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<iso_file>(fs::file(iso_path), *node);
|
||||
return std::make_unique<iso_file>(fs::file(iso_path, mode), *node);
|
||||
}
|
||||
|
||||
std::unique_ptr<fs::dir_base> iso_device::open_dir(const std::string& path)
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@
|
|||
<ClCompile Include="Emu\RSX\Overlays\Network\overlay_recvmessage_dialog.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\Network\overlay_sendmessage_dialog.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_animated_icon.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_audio.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_controls.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_cursor.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_debug_overlay.cpp" />
|
||||
|
|
@ -704,6 +705,7 @@
|
|||
<ClInclude Include="Emu\RSX\Overlays\Network\overlay_recvmessage_dialog.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\Network\overlay_sendmessage_dialog.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_animated_icon.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_audio.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_cursor.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_debug_overlay.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_edit_text.hpp" />
|
||||
|
|
@ -1103,4 +1105,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
@ -1411,6 +1411,9 @@
|
|||
<ClCompile Include="Loader\ISO.cpp">
|
||||
<Filter>Loader</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_audio.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Crypto\aes.h">
|
||||
|
|
@ -2833,6 +2836,9 @@
|
|||
<ClInclude Include="Loader\ISO.h">
|
||||
<Filter>Loader</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_audio.h">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl">
|
||||
|
|
|
|||
|
|
@ -826,6 +826,7 @@
|
|||
<ClCompile Include="rpcs3qt\call_stack_list.cpp" />
|
||||
<ClCompile Include="rpcs3qt\camera_settings_dialog.cpp" />
|
||||
<ClCompile Include="rpcs3qt\gui_game_info.cpp" />
|
||||
<ClCompile Include="rpcs3qt\log_level_dialog.cpp" />
|
||||
<ClCompile Include="rpcs3qt\permissions.cpp" />
|
||||
<ClCompile Include="rpcs3qt\ps_move_tracker_dialog.cpp" />
|
||||
<ClCompile Include="rpcs3qt\cheat_manager.cpp" />
|
||||
|
|
@ -1578,6 +1579,7 @@
|
|||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\protobuf\protobuf\src" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg"</Command>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="rpcs3qt\hex_validator.h" />
|
||||
<ClInclude Include="rpcs3qt\log_level_dialog.h" />
|
||||
<ClInclude Include="rpcs3qt\movie_item.h" />
|
||||
<ClInclude Include="rpcs3qt\movie_item_base.h" />
|
||||
<ClInclude Include="rpcs3qt\numbered_widget_item.h" />
|
||||
|
|
|
|||
|
|
@ -1275,6 +1275,9 @@
|
|||
<ClCompile Include="Input\mouse_gyro_handler.cpp">
|
||||
<Filter>Io</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="rpcs3qt\log_level_dialog.cpp">
|
||||
<Filter>Gui\settings</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Input\ds4_pad_handler.h">
|
||||
|
|
@ -1517,6 +1520,9 @@
|
|||
<ClInclude Include="Input\mouse_gyro_handler.h">
|
||||
<Filter>Io</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="rpcs3qt\log_level_dialog.h">
|
||||
<Filter>Gui\settings</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="resource.h">
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ add_library(rpcs3_ui STATIC
|
|||
localized.cpp
|
||||
localized_emu.cpp
|
||||
log_frame.cpp
|
||||
log_level_dialog.cpp
|
||||
log_viewer.cpp
|
||||
main_window.cpp
|
||||
memory_string_searcher.cpp
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "Emu/IdManager.h"
|
||||
#include "Emu/RSX/RSXThread.h"
|
||||
#include "Emu/RSX/RSXDisAsm.h"
|
||||
#include "Emu/Cell/lv2/sys_sync.h"
|
||||
#include "Emu/Cell/PPUAnalyser.h"
|
||||
#include "Emu/Cell/PPUDisAsm.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
|
|
@ -804,12 +805,47 @@ cpu_thread* debugger_frame::get_cpu()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (u32 cur = m_choice_units->currentIndex(); cur >= m_hw_ppu_idx && cur < g_cfg.core.ppu_threads + m_hw_ppu_idx)
|
||||
{
|
||||
reader_lock lock(lv2_obj::g_mutex);
|
||||
|
||||
const auto ppu = lv2_obj::get_running_ppu(cur - m_hw_ppu_idx);
|
||||
|
||||
if (ppu == m_cpu.get())
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
else if (ppu)
|
||||
{
|
||||
m_cpu = idm::get_unlocked<named_thread<ppu_thread>>(ppu->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cpu.reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (!!m_disasm != !!m_cpu)
|
||||
{
|
||||
// Fixup for HW PPU viewer
|
||||
if (m_cpu)
|
||||
{
|
||||
m_disasm = make_disasm(m_cpu.get(), m_cpu);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_disasm.reset();
|
||||
}
|
||||
|
||||
m_debugger_list->UpdateCPUData(m_disasm);
|
||||
m_breakpoint_list->UpdateCPUData(m_disasm);
|
||||
}
|
||||
|
||||
// Wait flag is raised by the thread itself, acknowledging exit
|
||||
if (m_cpu)
|
||||
{
|
||||
if (m_cpu->state.all_of(cpu_flag::wait + cpu_flag::exit))
|
||||
{
|
||||
m_cpu.reset();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -823,12 +859,13 @@ cpu_thread* debugger_frame::get_cpu()
|
|||
{
|
||||
if (g_fxo->try_get<rsx::thread>() != m_rsx || !m_rsx->ctrl || m_rsx->state.all_of(cpu_flag::wait + cpu_flag::exit))
|
||||
{
|
||||
m_rsx = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_rsx;
|
||||
}
|
||||
|
||||
return m_rsx;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::function<cpu_thread*()> debugger_frame::make_check_cpu(cpu_thread* cpu, bool unlocked)
|
||||
|
|
@ -922,19 +959,20 @@ std::function<cpu_thread*()> debugger_frame::make_check_cpu(cpu_thread* cpu, boo
|
|||
|
||||
void debugger_frame::UpdateUI()
|
||||
{
|
||||
const auto cpu = get_cpu();
|
||||
auto cpu = get_cpu();
|
||||
|
||||
// Refresh at a high rate during initialization (looks weird otherwise)
|
||||
if (m_ui_update_ctr % (cpu || m_ui_update_ctr < 200 || m_debugger_list->m_dirty_flag ? 5 : 50) == 0)
|
||||
{
|
||||
// If no change to instruction position happened, update instruction list at 20hz
|
||||
ShowPC();
|
||||
ShowPC(false, cpu);
|
||||
}
|
||||
|
||||
if (m_ui_update_ctr % 20 == 0 && !m_thread_list_pending_update)
|
||||
{
|
||||
// Update threads list at 5hz (low priority)
|
||||
UpdateUnitList();
|
||||
cpu = get_cpu();
|
||||
}
|
||||
|
||||
if (!cpu)
|
||||
|
|
@ -945,12 +983,13 @@ void debugger_frame::UpdateUI()
|
|||
{
|
||||
// Update threads list (thread exited)
|
||||
UpdateUnitList();
|
||||
cpu = get_cpu();
|
||||
}
|
||||
|
||||
ShowPC();
|
||||
ShowPC(false, cpu);
|
||||
m_last_query_state.clear();
|
||||
m_last_pc = -1;
|
||||
DoUpdate();
|
||||
DoUpdate(cpu);
|
||||
}
|
||||
}
|
||||
else if (m_ui_update_ctr % 5 == 0 || m_ui_update_ctr < m_ui_fast_update_permission_deadline)
|
||||
|
|
@ -966,7 +1005,7 @@ void debugger_frame::UpdateUI()
|
|||
std::memcpy(m_last_query_state.data(), static_cast<void *>(cpu), size_context);
|
||||
|
||||
m_last_pc = cia;
|
||||
DoUpdate();
|
||||
DoUpdate(cpu);
|
||||
|
||||
const bool paused = !!(cpu->state & s_pause_flags);
|
||||
|
||||
|
|
@ -982,7 +1021,7 @@ void debugger_frame::UpdateUI()
|
|||
if (m_ui_update_ctr % 5)
|
||||
{
|
||||
// Call if it hasn't been called before
|
||||
ShowPC();
|
||||
ShowPC(false, cpu);
|
||||
}
|
||||
|
||||
if (is_using_interpreter(cpu->get_class()))
|
||||
|
|
@ -1022,9 +1061,17 @@ void debugger_frame::UpdateUnitList()
|
|||
}
|
||||
|
||||
std::vector<std::pair<QString, std::function<cpu_thread*()>>> cpu_list;
|
||||
cpu_list.reserve(threads_created >= threads_deleted ? 0 : threads_created - threads_deleted);
|
||||
cpu_list.reserve(threads_created >= threads_deleted ? threads_created - threads_deleted : 0);
|
||||
|
||||
usz reselected_index = umax;
|
||||
usz hw_ppu_idx = umax;
|
||||
|
||||
if (u32 cur = m_choice_units->currentIndex(); cur >= m_hw_ppu_idx && cur < g_cfg.core.ppu_threads + m_hw_ppu_idx)
|
||||
{
|
||||
hw_ppu_idx = cur - m_hw_ppu_idx;
|
||||
}
|
||||
|
||||
m_hw_ppu_idx = umax;
|
||||
|
||||
const auto on_select = [&](u32 id, cpu_thread& cpu)
|
||||
{
|
||||
|
|
@ -1033,7 +1080,7 @@ void debugger_frame::UpdateUnitList()
|
|||
// Space at the end is to pad a gap on the right
|
||||
cpu_list.emplace_back(QString::fromStdString((id >> 24 == 0x55 ? "RSX[0x55555555]" : cpu.get_name()) + ' '), std::move(func_cpu));
|
||||
|
||||
if (old_cpu_ptr == std::addressof(cpu))
|
||||
if (old_cpu_ptr == std::addressof(cpu) && hw_ppu_idx == umax)
|
||||
{
|
||||
reselected_index = cpu_list.size() - 1;
|
||||
}
|
||||
|
|
@ -1046,6 +1093,40 @@ void debugger_frame::UpdateUnitList()
|
|||
idm::select<named_thread<ppu_thread>>(on_select, idm::unlocked);
|
||||
}
|
||||
|
||||
m_hw_ppu_idx = cpu_list.size() + 1; // Account for NoThreadString thread
|
||||
|
||||
for (u32 i = 0; i < g_cfg.core.ppu_threads + 0u; i++)
|
||||
{
|
||||
std::function<cpu_thread*()> get_ppu_at = [index = i, cpu_storage = shared_ptr<named_thread<ppu_thread>>()]() mutable
|
||||
{
|
||||
reader_lock lock(lv2_obj::g_mutex);
|
||||
|
||||
const auto ppu = lv2_obj::get_running_ppu(index);
|
||||
|
||||
if (ppu == cpu_storage.get())
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
else if (ppu)
|
||||
{
|
||||
cpu_storage = idm::get_unlocked<named_thread<ppu_thread>>(ppu->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu_storage.reset();
|
||||
}
|
||||
|
||||
return cpu_storage.get();
|
||||
};
|
||||
|
||||
if (hw_ppu_idx == i)
|
||||
{
|
||||
reselected_index = cpu_list.size();
|
||||
}
|
||||
|
||||
cpu_list.emplace_back(tr("HwPPU[%0]: Hardware PPU Thread #%1").arg(i + 1).arg(i + 1), std::move(get_ppu_at));
|
||||
}
|
||||
|
||||
if (g_fxo->is_init<id_manager::id_map<named_thread<spu_thread>>>())
|
||||
{
|
||||
idm::select<named_thread<spu_thread>>(on_select, idm::unlocked);
|
||||
|
|
@ -1114,6 +1195,7 @@ void debugger_frame::OnSelectUnit()
|
|||
}
|
||||
|
||||
cpu_thread* selected = nullptr;
|
||||
usz hw_ppu_idx = umax;
|
||||
|
||||
if (m_emu_state != system_state::stopped)
|
||||
{
|
||||
|
|
@ -1135,7 +1217,14 @@ void debugger_frame::OnSelectUnit()
|
|||
|
||||
if (!selected && !m_rsx && !m_cpu)
|
||||
{
|
||||
return;
|
||||
if (u32 cur = m_choice_units->currentIndex(); cur >= m_hw_ppu_idx && cur < g_cfg.core.ppu_threads + m_hw_ppu_idx)
|
||||
{
|
||||
hw_ppu_idx = cur - m_hw_ppu_idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1144,6 +1233,15 @@ void debugger_frame::OnSelectUnit()
|
|||
m_rsx = nullptr;
|
||||
m_spu_disasm_memory.reset();
|
||||
|
||||
if (hw_ppu_idx != umax)
|
||||
{
|
||||
if (hw_ppu_idx > 1)
|
||||
{
|
||||
// Sample PPU
|
||||
selected = ::at32(m_threads_info, 1)();
|
||||
}
|
||||
}
|
||||
|
||||
if (selected)
|
||||
{
|
||||
const u32 cpu_id = selected->id;
|
||||
|
|
@ -1198,8 +1296,8 @@ void debugger_frame::OnSelectUnit()
|
|||
m_debugger_list->UpdateCPUData(m_disasm);
|
||||
m_breakpoint_list->UpdateCPUData(m_disasm);
|
||||
|
||||
ShowPC(true);
|
||||
DoUpdate();
|
||||
ShowPC(true, selected);
|
||||
DoUpdate(selected);
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
|
|
@ -1339,30 +1437,28 @@ void debugger_frame::OnSelectSPUDisassembler()
|
|||
|
||||
m_debugger_list->UpdateCPUData(m_disasm);
|
||||
m_breakpoint_list->UpdateCPUData(m_disasm);
|
||||
ShowPC(true);
|
||||
DoUpdate();
|
||||
ShowPC(true, nullptr);
|
||||
DoUpdate(nullptr);
|
||||
UpdateUI();
|
||||
});
|
||||
|
||||
m_spu_disasm_dialog->show();
|
||||
}
|
||||
|
||||
void debugger_frame::DoUpdate()
|
||||
void debugger_frame::DoUpdate(cpu_thread* cpu0)
|
||||
{
|
||||
// Check if we need to disable a step over bp
|
||||
if (const auto cpu0 = get_cpu(); cpu0 && m_last_step_over_breakpoint != umax && cpu0->get_pc() == m_last_step_over_breakpoint)
|
||||
if (cpu0 && m_last_step_over_breakpoint != umax && cpu0->get_pc() == m_last_step_over_breakpoint)
|
||||
{
|
||||
m_ppu_breakpoint_handler->RemoveBreakpoint(m_last_step_over_breakpoint);
|
||||
m_last_step_over_breakpoint = -1;
|
||||
}
|
||||
|
||||
WritePanels();
|
||||
WritePanels(cpu0);
|
||||
}
|
||||
|
||||
void debugger_frame::WritePanels()
|
||||
void debugger_frame::WritePanels(cpu_thread* cpu)
|
||||
{
|
||||
const auto cpu = get_cpu();
|
||||
|
||||
if (!cpu)
|
||||
{
|
||||
m_misc_state->clear();
|
||||
|
|
@ -1412,7 +1508,9 @@ void debugger_frame::ShowGotoAddressDialog()
|
|||
QLineEdit* expression_input(new QLineEdit(m_goto_dialog));
|
||||
expression_input->setFont(m_mono);
|
||||
|
||||
if (const auto thread = get_cpu(); !thread || thread->get_class() != thread_class::spu)
|
||||
const auto thread = get_cpu();
|
||||
|
||||
if (!thread || thread->get_class() != thread_class::spu)
|
||||
{
|
||||
expression_input->setValidator(new HexValidator(expression_input));
|
||||
}
|
||||
|
|
@ -1436,8 +1534,8 @@ void debugger_frame::ShowGotoAddressDialog()
|
|||
|
||||
m_goto_dialog->setLayout(vbox_panel);
|
||||
|
||||
const auto cpu_check = make_check_cpu(get_cpu());
|
||||
const auto cpu = cpu_check();
|
||||
const auto cpu_check = make_check_cpu(thread);
|
||||
const auto cpu = thread;
|
||||
const QFont font = expression_input->font();
|
||||
|
||||
// -1 from get_pc() turns into 0
|
||||
|
|
@ -1544,9 +1642,12 @@ void debugger_frame::ClearCallStack()
|
|||
Q_EMIT CallStackUpdateRequested({});
|
||||
}
|
||||
|
||||
void debugger_frame::ShowPC(bool user_requested)
|
||||
void debugger_frame::ShowPC(bool user_requested, cpu_thread* cpu0)
|
||||
{
|
||||
const auto cpu0 = get_cpu();
|
||||
if (!cpu0)
|
||||
{
|
||||
cpu0 = get_cpu();
|
||||
}
|
||||
|
||||
const u32 pc = (cpu0 ? cpu0->get_pc() : (m_is_spu_disasm_mode ? m_spu_disasm_pc : 0));
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ class debugger_frame : public custom_dock_widget
|
|||
std::shared_ptr<CPUDisAsm> m_disasm; // Only shared to allow base/derived functionality
|
||||
shared_ptr<cpu_thread> m_cpu;
|
||||
rsx::thread* m_rsx = nullptr;
|
||||
u32 m_hw_ppu_idx = umax;
|
||||
std::shared_ptr<utils::shm> m_spu_disasm_memory;
|
||||
u32 m_spu_disasm_origin_eal = 0;
|
||||
u32 m_spu_disasm_pc = 0;
|
||||
|
|
@ -107,8 +108,8 @@ public:
|
|||
void UpdateUI();
|
||||
void UpdateUnitList();
|
||||
|
||||
void DoUpdate();
|
||||
void WritePanels();
|
||||
void DoUpdate(cpu_thread* cpu0);
|
||||
void WritePanels(cpu_thread* cpu);
|
||||
void EnableButtons(bool enable);
|
||||
void ShowGotoAddressDialog();
|
||||
void PerformGoToRequest(const QString& text_argument);
|
||||
|
|
@ -138,7 +139,7 @@ private Q_SLOTS:
|
|||
void OnSelectUnit();
|
||||
void OnSelectSPUDisassembler();
|
||||
void OnRegsContextMenu(const QPoint& pos);
|
||||
void ShowPC(bool user_requested = false);
|
||||
void ShowPC(bool user_requested = false, cpu_thread* cpu = nullptr);
|
||||
void EnableUpdateTimer(bool enable) const;
|
||||
void RunBtnPress();
|
||||
void RegsShowMemoryViewerAction();
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ downloader::~downloader()
|
|||
}
|
||||
}
|
||||
|
||||
void downloader::start(const std::string& url, bool follow_location, bool show_progress_dialog, const QString& progress_dialog_title, bool keep_progress_dialog_open, int expected_size, bool check_return_code, bool again)
|
||||
void downloader::start(const std::string& url, bool follow_location, bool show_progress_dialog, bool check_return_code, const QString& progress_dialog_title, bool keep_progress_dialog_open, int expected_size, bool again)
|
||||
{
|
||||
network_log.notice("Starting download from URL: %s", url);
|
||||
|
||||
|
|
@ -121,7 +121,7 @@ void downloader::start(const std::string& url, bool follow_location, bool show_p
|
|||
{
|
||||
network_log.error("Error during download. Trying to download again (attempts=%d, return_code=%d)", m_download_attempts, return_code);
|
||||
std::this_thread::sleep_for(500ms); // Wait for a little while
|
||||
start(url, follow_location, show_progress_dialog, progress_dialog_title, keep_progress_dialog_open, expected_size, check_return_code, true);
|
||||
start(url, follow_location, show_progress_dialog, check_return_code, progress_dialog_title, keep_progress_dialog_open, expected_size, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public:
|
|||
explicit downloader(QWidget* parent = nullptr);
|
||||
~downloader();
|
||||
|
||||
void start(const std::string& url, bool follow_location, bool show_progress_dialog, const QString& progress_dialog_title = "", bool keep_progress_dialog_open = false, int expected_size = -1, bool check_return_code = true, bool again = false);
|
||||
void start(const std::string& url, bool follow_location, bool show_progress_dialog, bool check_return_code, const QString& progress_dialog_title = "", bool keep_progress_dialog_open = false, int expected_size = -1, bool again = false);
|
||||
usz update_buffer(char* data, usz size);
|
||||
|
||||
void update_progress_dialog(const QString& title) const;
|
||||
|
|
|
|||
|
|
@ -31,18 +31,20 @@ namespace
|
|||
out << YAML::Null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.IsMap())
|
||||
{
|
||||
std::vector<std::string> keys;
|
||||
keys.reserve(node.size());
|
||||
|
||||
// generate vector of strings to be sorted using the as function from YAML documentation
|
||||
for (const auto& pair : node)
|
||||
{
|
||||
keys.push_back(pair.first.as<std::string>());
|
||||
keys.push_back(pair.first.Scalar());
|
||||
}
|
||||
std::sort(keys.begin(), keys.end());
|
||||
|
||||
// recursively generate sorted maps
|
||||
// alternative implementations could have stops at specified recursion levels or maybe just the first two levels would be sorted
|
||||
out << YAML::BeginMap;
|
||||
for (const std::string& key : keys)
|
||||
{
|
||||
|
|
@ -51,15 +53,10 @@ namespace
|
|||
emit_data(out, node[key]);
|
||||
}
|
||||
out << YAML::EndMap;
|
||||
return;
|
||||
}
|
||||
// alternatively: an else statement could be used however I wanted to follow a similar format to the += operator so the YAML Undefined class can be ignored
|
||||
else if (node.IsScalar() || node.IsSequence())
|
||||
{
|
||||
out << node;
|
||||
}
|
||||
// this exists to preserve the same functionality as before where Undefined nodes would still be output, can be removed or consolidated with the else if branch
|
||||
else
|
||||
out << node;
|
||||
|
||||
out << node;
|
||||
}
|
||||
|
||||
// Incrementally load YAML
|
||||
|
|
@ -910,11 +907,38 @@ std::string emu_settings::GetSetting(emu_settings_type type) const
|
|||
return "";
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> emu_settings::GetMapSettingDefault(emu_settings_type type) const
|
||||
{
|
||||
if (const auto node = cfg_adapter::get_node(m_default_settings, ::at32(settings_location, type)); node && node.IsMap())
|
||||
{
|
||||
return node.as<std::map<std::string, std::string>>();
|
||||
}
|
||||
|
||||
cfg_log.fatal("GetMapSettingDefault(type=%d) could not retrieve the requested node", static_cast<int>(type));
|
||||
return {};
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> emu_settings::GetMapSetting(emu_settings_type type) const
|
||||
{
|
||||
if (const auto node = cfg_adapter::get_node(m_current_settings, ::at32(settings_location, type)); node && node.IsMap())
|
||||
{
|
||||
return node.as<std::map<std::string, std::string>>();
|
||||
}
|
||||
|
||||
cfg_log.fatal("GetMapSetting(type=%d) could not retrieve the requested node", static_cast<int>(type));
|
||||
return {};
|
||||
}
|
||||
|
||||
void emu_settings::SetSetting(emu_settings_type type, const std::string& val) const
|
||||
{
|
||||
cfg_adapter::get_node(m_current_settings, ::at32(settings_location, type)) = val;
|
||||
}
|
||||
|
||||
void emu_settings::SetMapSetting(emu_settings_type type, const std::map<std::string, std::string>& val) const
|
||||
{
|
||||
cfg_adapter::get_node(m_current_settings, ::at32(settings_location, type)) = val;
|
||||
}
|
||||
|
||||
emu_settings_type emu_settings::FindSettingsType(const cfg::_base* node) const
|
||||
{
|
||||
// Add key and value to static map on first use
|
||||
|
|
|
|||
|
|
@ -78,9 +78,18 @@ public:
|
|||
/** Returns the value of the setting type.*/
|
||||
std::string GetSetting(emu_settings_type type) const;
|
||||
|
||||
/** Returns the default map value of the setting type.*/
|
||||
std::map<std::string, std::string> GetMapSettingDefault(emu_settings_type type) const;
|
||||
|
||||
/** Returns the value of the setting type as map.*/
|
||||
std::map<std::string, std::string> GetMapSetting(emu_settings_type type) const;
|
||||
|
||||
/** Sets the setting type to a given value.*/
|
||||
void SetSetting(emu_settings_type type, const std::string& val) const;
|
||||
|
||||
/** Sets the setting type to a given map value.*/
|
||||
void SetMapSetting(emu_settings_type type, const std::map<std::string, std::string>& val) const;
|
||||
|
||||
/** Try to find the settings type for a given string.*/
|
||||
emu_settings_type FindSettingsType(const cfg::_base* node) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -217,6 +217,9 @@ enum class emu_settings_type
|
|||
EmptyHdd0Tmp,
|
||||
LimitCacheSize,
|
||||
MaximumCacheSize,
|
||||
|
||||
// Log
|
||||
Log,
|
||||
};
|
||||
|
||||
/** A helper map that keeps track of where a given setting type is located*/
|
||||
|
|
@ -434,4 +437,7 @@ inline static const std::map<emu_settings_type, cfg_location> settings_location
|
|||
{ emu_settings_type::SuspendEmulationSavestateMode, { "Savestate", "Suspend Emulation Savestate Mode" }},
|
||||
{ emu_settings_type::CompatibleEmulationSavestateMode, { "Savestate", "Compatible Savestate Mode" }},
|
||||
{ emu_settings_type::StartSavestatePaused, { "Savestate", "Start Paused" }},
|
||||
|
||||
// Logs
|
||||
{ emu_settings_type::Log, { "Log" }},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ void game_compatibility::handle_download_finished(const QByteArray& content)
|
|||
compat_log.notice("Database download finished");
|
||||
|
||||
// Create new map from database and write database to file if database was valid
|
||||
if (ReadJSON(QJsonDocument::fromJson(content).object(), true))
|
||||
if (handle_json(content, true))
|
||||
{
|
||||
// Write database to file
|
||||
QFile file(m_filepath);
|
||||
|
|
@ -67,8 +67,9 @@ void game_compatibility::handle_download_canceled()
|
|||
Q_EMIT DownloadCanceled();
|
||||
}
|
||||
|
||||
bool game_compatibility::ReadJSON(const QJsonObject& json_data, bool after_download)
|
||||
bool game_compatibility::handle_json(const QByteArray& data, bool after_download)
|
||||
{
|
||||
const QJsonObject json_data = QJsonDocument::fromJson(data).object();
|
||||
const int return_code = json_data["return_code"].toInt(-255);
|
||||
|
||||
if (return_code < 0)
|
||||
|
|
@ -101,7 +102,7 @@ bool game_compatibility::ReadJSON(const QJsonObject& json_data, bool after_downl
|
|||
|
||||
m_compat_database.clear();
|
||||
|
||||
QJsonObject json_results = json_data["results"].toObject();
|
||||
const QJsonObject json_results = json_data["results"].toObject();
|
||||
|
||||
// Retrieve status data for every valid entry
|
||||
for (const auto& key : json_results.keys())
|
||||
|
|
@ -112,7 +113,7 @@ bool game_compatibility::ReadJSON(const QJsonObject& json_data, bool after_downl
|
|||
continue;
|
||||
}
|
||||
|
||||
QJsonObject json_result = json_results[key].toObject();
|
||||
const QJsonObject json_result = json_results[key].toObject();
|
||||
|
||||
// Retrieve compatibility information from json
|
||||
compat::status status = ::at32(Status_Data, json_result.value("status").toString("NoResult"));
|
||||
|
|
@ -210,15 +211,14 @@ void game_compatibility::RequestCompatibility(bool online)
|
|||
compat_log.notice("Finished reading database from file: %s", m_filepath);
|
||||
|
||||
// Create new map from database
|
||||
ReadJSON(QJsonDocument::fromJson(content).object(), online);
|
||||
|
||||
handle_json(content, online);
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string url = "https://rpcs3.net/compatibility?api=v1&export";
|
||||
compat_log.notice("Beginning compatibility database download from: %s", url);
|
||||
|
||||
m_downloader->start(url, true, true, tr("Downloading Database"));
|
||||
m_downloader->start(url, true, true, true, tr("Downloading Database"));
|
||||
|
||||
// We want to retrieve a new database, therefore refresh gamelist and indicate that
|
||||
Q_EMIT DownloadStarted();
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ private:
|
|||
std::map<std::string, compat::status> m_compat_database;
|
||||
|
||||
/** Creates new map from the database */
|
||||
bool ReadJSON(const QJsonObject& json_data, bool after_download);
|
||||
bool handle_json(const QByteArray& data, bool after_download);
|
||||
|
||||
public:
|
||||
/** Handles reads, writes and downloads for the compatibility database */
|
||||
|
|
|
|||
|
|
@ -637,6 +637,12 @@ void game_list_frame::OnParsingFinished()
|
|||
game.has_hover_pam = true;
|
||||
}
|
||||
|
||||
if (std::string audio_path = sfo_dir + "/SND0.AT3"; file_exists(audio_path))
|
||||
{
|
||||
game.info.audio_path = std::move(audio_path);
|
||||
game.has_audio_file = true;
|
||||
}
|
||||
|
||||
const QString serial = QString::fromStdString(game.info.serial);
|
||||
|
||||
m_games_mutex.lock();
|
||||
|
|
|
|||
|
|
@ -109,11 +109,23 @@ void game_list_grid::populate(
|
|||
}
|
||||
});
|
||||
|
||||
if (play_hover_movies && (game->has_hover_gif || game->has_hover_pam))
|
||||
if (play_hover_movies && (game->has_hover_gif || game->has_hover_pam || game->has_audio_file))
|
||||
{
|
||||
item->set_video_path(game->info.movie_path);
|
||||
bool check_iso = false;
|
||||
|
||||
if (!fs::exists(game->info.movie_path) && is_file_iso(game->info.path))
|
||||
if (game->has_hover_gif || game->has_hover_pam)
|
||||
{
|
||||
item->set_video_path(game->info.movie_path);
|
||||
check_iso |= !fs::exists(game->info.movie_path);
|
||||
}
|
||||
|
||||
if (game->has_audio_file)
|
||||
{
|
||||
item->set_audio_path(game->info.audio_path);
|
||||
check_iso |= !fs::exists(game->info.audio_path);
|
||||
}
|
||||
|
||||
if (check_iso && is_file_iso(game->info.path))
|
||||
{
|
||||
item->set_iso_path(game->info.path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -299,11 +299,23 @@ void game_list_table::populate(
|
|||
}
|
||||
});
|
||||
|
||||
if (play_hover_movies && (game->has_hover_gif || game->has_hover_pam))
|
||||
if (play_hover_movies && (game->has_hover_gif || game->has_hover_pam || game->has_audio_file))
|
||||
{
|
||||
icon_item->set_video_path(game->info.movie_path);
|
||||
bool check_iso = false;
|
||||
|
||||
if (!fs::exists(game->info.movie_path) && is_file_iso(game->info.path))
|
||||
if (game->has_hover_gif || game->has_hover_pam)
|
||||
{
|
||||
icon_item->set_video_path(game->info.movie_path);
|
||||
check_iso |= !fs::exists(game->info.movie_path);
|
||||
}
|
||||
|
||||
if (game->has_audio_file)
|
||||
{
|
||||
icon_item->set_audio_path(game->info.audio_path);
|
||||
check_iso |= !fs::exists(game->info.audio_path);
|
||||
}
|
||||
|
||||
if (check_iso && is_file_iso(game->info.path))
|
||||
{
|
||||
icon_item->set_iso_path(game->info.path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ struct gui_game_info
|
|||
bool has_custom_icon = false;
|
||||
bool has_hover_gif = false;
|
||||
bool has_hover_pam = false;
|
||||
bool has_audio_file = false;
|
||||
bool icon_in_archive = false;
|
||||
movie_item_base* item = nullptr;
|
||||
|
||||
|
|
|
|||
155
rpcs3/rpcs3qt/log_level_dialog.cpp
Normal file
155
rpcs3/rpcs3qt/log_level_dialog.cpp
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
#include "stdafx.h"
|
||||
#include "log_level_dialog.h"
|
||||
#include "emu_settings.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QHeaderView>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
LOG_CHANNEL(cfg_log, "CFG");
|
||||
|
||||
log_level_dialog::log_level_dialog(QWidget* parent, std::shared_ptr<emu_settings> emu_settings)
|
||||
: QDialog(parent), m_emu_settings(emu_settings)
|
||||
{
|
||||
setWindowTitle(tr("Configure minimum log levels"));
|
||||
setObjectName("log_level_dialog");
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
setMinimumSize(QSize(700, 400));
|
||||
|
||||
const std::set<std::string> channels = logs::get_channels();
|
||||
std::vector<std::pair<std::string, QString>> levels;
|
||||
|
||||
const auto add_level = [&levels](logs::level level, const QString& localized)
|
||||
{
|
||||
levels.push_back(std::pair<std::string, QString>(fmt::format("%s", level), localized));
|
||||
};
|
||||
|
||||
add_level(logs::level::always, tr("Always"));
|
||||
add_level(logs::level::fatal, tr("Fatal"));
|
||||
add_level(logs::level::error, tr("Error"));
|
||||
add_level(logs::level::todo, tr("Todo"));
|
||||
add_level(logs::level::success, tr("Success"));
|
||||
add_level(logs::level::warning, tr("Warning"));
|
||||
add_level(logs::level::notice, tr("Notice"));
|
||||
add_level(logs::level::trace, tr("Trace"));
|
||||
|
||||
const std::map<std::string, std::string> current_settings = m_emu_settings->GetMapSetting(emu_settings_type::Log);
|
||||
for (const auto& [channel, level] : current_settings)
|
||||
{
|
||||
if (!channels.contains(channel))
|
||||
{
|
||||
cfg_log.warning("log_level_dialog: Ignoring unknown channel '%s' found in config file.", channel);
|
||||
}
|
||||
}
|
||||
|
||||
m_table = new QTableWidget(static_cast<int>(channels.size()), 2, this);
|
||||
m_table->setHorizontalHeaderLabels({ tr("Channel"), tr("Level") });
|
||||
|
||||
int i = 0;
|
||||
for (const std::string& channel : channels)
|
||||
{
|
||||
QComboBox* combo = new QComboBox();
|
||||
|
||||
for (const auto& [level, localized] : levels)
|
||||
{
|
||||
combo->addItem(localized, QString::fromStdString(level));
|
||||
}
|
||||
|
||||
connect(combo, &QComboBox::currentIndexChanged, combo, [this, combo, ch = channel](int index)
|
||||
{
|
||||
if (index < 0) return;
|
||||
|
||||
const QVariant var = combo->itemData(index);
|
||||
if (!var.canConvert<QString>()) return;
|
||||
|
||||
std::map<std::string, std::string> settings = m_emu_settings->GetMapSetting(emu_settings_type::Log);
|
||||
|
||||
settings[ch] = var.toString().toStdString();
|
||||
|
||||
m_emu_settings->SetMapSetting(emu_settings_type::Log, settings);
|
||||
});
|
||||
|
||||
m_table->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(channel)));
|
||||
m_table->setCellWidget(i, 1, combo);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
QLineEdit* filter_edit = new QLineEdit(this);
|
||||
filter_edit->setPlaceholderText(tr("Filter channels"));
|
||||
connect(filter_edit, &QLineEdit::textChanged, this, [this](const QString& text)
|
||||
{
|
||||
for (int i = 0; i < m_table->rowCount(); i++)
|
||||
{
|
||||
if (QTableWidgetItem* item = m_table->item(i, 0))
|
||||
{
|
||||
m_table->setRowHidden(i, !text.isEmpty() && !item->text().contains(text, Qt::CaseInsensitive));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults);
|
||||
connect(button_box, &QDialogButtonBox::clicked, this, [this, button_box, old_settings = m_emu_settings->GetMapSetting(emu_settings_type::Log)](QAbstractButton* button)
|
||||
{
|
||||
if (button == button_box->button(QDialogButtonBox::Ok))
|
||||
{
|
||||
accept();
|
||||
}
|
||||
else if (button == button_box->button(QDialogButtonBox::Cancel))
|
||||
{
|
||||
m_emu_settings->SetMapSetting(emu_settings_type::Log, old_settings);
|
||||
reject();
|
||||
}
|
||||
else if (button == button_box->button(QDialogButtonBox::RestoreDefaults))
|
||||
{
|
||||
m_emu_settings->SetMapSetting(emu_settings_type::Log, m_emu_settings->GetMapSettingDefault(emu_settings_type::Log));
|
||||
reload_page();
|
||||
}
|
||||
});
|
||||
|
||||
reload_page();
|
||||
|
||||
m_table->resizeColumnsToContents();
|
||||
m_table->horizontalHeader()->stretchLastSection();
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->addWidget(filter_edit);
|
||||
layout->addWidget(m_table);
|
||||
layout->addWidget(button_box);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
log_level_dialog::~log_level_dialog()
|
||||
{
|
||||
}
|
||||
|
||||
void log_level_dialog::reload_page()
|
||||
{
|
||||
const std::map<std::string, std::string> settings = m_emu_settings->GetMapSetting(emu_settings_type::Log);
|
||||
const QString def_str = QString::fromStdString(fmt::format("%s", logs::level::_default));
|
||||
|
||||
for (int i = 0; i < m_table->rowCount(); i++)
|
||||
{
|
||||
QTableWidgetItem* item = m_table->item(i, 0);
|
||||
if (!item) continue;
|
||||
|
||||
const std::string channel = item->text().toStdString();
|
||||
|
||||
if (QComboBox* combo = static_cast<QComboBox*>(m_table->cellWidget(i, 1)))
|
||||
{
|
||||
combo->blockSignals(true);
|
||||
combo->setCurrentIndex(combo->findData(def_str));
|
||||
if (settings.contains(channel))
|
||||
{
|
||||
if (const int index = combo->findData(QString::fromStdString(settings.at(channel))); index >= 0)
|
||||
{
|
||||
combo->setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
combo->blockSignals(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue