Merge branch 'main' into main

This commit is contained in:
DanielSvoboda 2024-11-16 16:56:30 -03:00 committed by GitHub
commit 9fd5a54c42
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 886 additions and 399 deletions

View File

@ -27,7 +27,7 @@ chmod a+x linuxdeploy-plugin-checkrt-x86_64.sh
cp -a "$GITHUB_WORKSPACE/build/translations" AppDir/usr/bin cp -a "$GITHUB_WORKSPACE/build/translations" AppDir/usr/bin
./linuxdeploy-x86_64.AppImage --appdir AppDir -d "$GITHUB_WORKSPACE"/.github/shadps4.desktop -e "$GITHUB_WORKSPACE"/build/shadps4 -i "$GITHUB_WORKSPACE"/.github/shadps4.png --plugin qt ./linuxdeploy-x86_64.AppImage --appdir AppDir -d "$GITHUB_WORKSPACE"/dist/net.shadps4.shadPS4.desktop -e "$GITHUB_WORKSPACE"/build/shadps4 -i "$GITHUB_WORKSPACE"/src/images/net.shadps4.shadPS4.svg --plugin qt
rm AppDir/usr/plugins/multimedia/libgstreamermediaplugin.so rm AppDir/usr/plugins/multimedia/libgstreamermediaplugin.so
./linuxdeploy-x86_64.AppImage --appdir AppDir --output appimage ./linuxdeploy-x86_64.AppImage --appdir AppDir --output appimage
mv shadPS4-x86_64.AppImage Shadps4-qt.AppImage mv shadPS4-x86_64.AppImage Shadps4-qt.AppImage

View File

@ -17,5 +17,5 @@ chmod a+x linuxdeploy-plugin-checkrt-x86_64.sh
# Build AppImage # Build AppImage
./linuxdeploy-x86_64.AppImage --appdir AppDir ./linuxdeploy-x86_64.AppImage --appdir AppDir
./linuxdeploy-plugin-checkrt-x86_64.sh --appdir AppDir ./linuxdeploy-plugin-checkrt-x86_64.sh --appdir AppDir
./linuxdeploy-x86_64.AppImage --appdir AppDir -d "$GITHUB_WORKSPACE"/.github/shadps4.desktop -e "$GITHUB_WORKSPACE"/build/shadps4 -i "$GITHUB_WORKSPACE"/.github/shadps4.png --output appimage ./linuxdeploy-x86_64.AppImage --appdir AppDir -d "$GITHUB_WORKSPACE"/dist/net.shadps4.shadPS4.desktop -e "$GITHUB_WORKSPACE"/build/shadps4 -i "$GITHUB_WORKSPACE"/src/images/net.shadps4.shadPS4.svg --output appimage
mv shadPS4-x86_64.AppImage Shadps4-sdl.AppImage mv shadPS4-x86_64.AppImage Shadps4-sdl.AppImage

View File

@ -943,6 +943,9 @@ endif()
install(TARGETS shadps4 BUNDLE DESTINATION .) install(TARGETS shadps4 BUNDLE DESTINATION .)
if (ENABLE_QT_GUI AND CMAKE_SYSTEM_NAME STREQUAL "Linux") if (ENABLE_QT_GUI AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
install(FILES ".github/shadps4.desktop" DESTINATION "share/applications") install(FILES "dist/net.shadps4.shadPS4.desktop" DESTINATION "share/applications")
install(FILES ".github/shadps4.png" DESTINATION "share/icons/hicolor/512x512/apps") install(FILES "dist/net.shadps4.shadPS4.releases.xml" DESTINATION "share/metainfo/releases")
install(FILES "dist/net.shadps4.shadPS4.metainfo.xml" DESTINATION "share/metainfo")
install(FILES ".github/shadps4.png" DESTINATION "share/icons/hicolor/512x512/apps" RENAME "net.shadps4.shadPS4.png")
install(FILES "src/images/net.shadps4.shadPS4.svg" DESTINATION "share/icons/hicolor/scalable/apps")
endif() endif()

View File

@ -5,9 +5,12 @@ path = [
"REUSE.toml", "REUSE.toml",
"CMakeSettings.json", "CMakeSettings.json",
".github/FUNDING.yml", ".github/FUNDING.yml",
".github/shadps4.desktop",
".github/shadps4.png", ".github/shadps4.png",
".gitmodules", ".gitmodules",
"dist/net.shadps4.shadPS4.desktop",
"dist/net.shadps4.shadPS4_metadata.pot",
"dist/net.shadps4.shadPS4.metainfo.xml",
"dist/net.shadps4.shadPS4.releases.xml",
"documents/changelog.md", "documents/changelog.md",
"documents/Quickstart/2.png", "documents/Quickstart/2.png",
"documents/Screenshots/*", "documents/Screenshots/*",
@ -39,6 +42,7 @@ path = [
"src/images/stop_icon.png", "src/images/stop_icon.png",
"src/images/shadPS4.icns", "src/images/shadPS4.icns",
"src/images/shadps4.ico", "src/images/shadps4.ico",
"src/images/net.shadps4.shadPS4.svg",
"src/images/themes_icon.png", "src/images/themes_icon.png",
"src/images/update_icon.png", "src/images/update_icon.png",
"src/images/youtube.png", "src/images/youtube.png",

View File

@ -3,7 +3,7 @@ Name=shadPS4
Exec=shadps4 Exec=shadps4
Terminal=false Terminal=false
Type=Application Type=Application
Icon=shadps4 Icon=net.shadps4.shadPS4
Comment=shadPS4 Emulator Comment=PlayStation 4 emulator
Categories=Game; Categories=Game;
StartupWMClass=shadps4; StartupWMClass=shadps4;

63
dist/net.shadps4.shadPS4.metainfo.xml vendored Normal file
View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id translate="no">net.shadps4.shadPS4</id>
<name translate="no">shadPS4</name>
<developer id="net.shadps4.shadPS4">
<name>shadPS4 Contributors</name>
<url translate="no">https://github.com/shadps4-emu/shadps4/graphs/contributors</url>
</developer>
<summary>PS4 Emulator</summary>
<metadata_license translate="no">CC0-1.0</metadata_license>
<project_license translate="no">GPL-2.0</project_license>
<launchable type="desktop-id" translate="no">net.shadps4.shadPS4.desktop</launchable>
<url type="homepage" translate="no">https://shadps4.net/</url>
<description>
<p>shadPS4 is an early PlayStation 4 emulator for Windows, Linux and macOS written in C++.</p>
<p>The emulator is still early in development, so don't expect a flawless experience. Nonetheless, the emulator can already run a number of commercial games.</p>
</description>
<screenshots>
<screenshot type="default">
<image type="source" translate="no" >https://cdn.jsdelivr.net/gh/shadps4-emu/shadps4@main/documents/Screenshots/1.png</image>
<caption>Bloodborne</caption>
</screenshot>
<screenshot>
<image type="source" translate="no">https://cdn.jsdelivr.net/gh/shadps4-emu/shadps4@main/documents/Screenshots/2.png</image>
<caption>Hatsune Miku: Project DIVA Future Tone</caption>
</screenshot>
<screenshot>
<image type="source" translate="no">https://cdn.jsdelivr.net/gh/shadps4-emu/shadps4@main/documents/Screenshots/3.png</image>
<caption>Yakuza Kiwami</caption>
</screenshot>
<screenshot>
<image type="source" translate="no">https://cdn.jsdelivr.net/gh/shadps4-emu/shadps4@main/documents/Screenshots/4.png</image>
<caption>Persona 4 Golden</caption>
</screenshot>
</screenshots>
<categories>
<category translate="no">Game</category>
</categories>
<releases type="external" url="https://cdn.jsdelivr.net/gh/fpiesche/flatpak-builds/apps/net.shadps4.shadPS4/net.shadps4.shadPS4.releases.xml">
<release version="v.0.4.0" date="2024-11-03">
<description></description>
</release>
</releases>
<content_rating type="oars-1.1"/>
<supports>
<control translate="no">keyboard</control>
</supports>
<recommends>
<control translate="no">gamepad</control>
</recommends>
<requires>
<internet translate="no">offline-only</internet>
</requires>
<provides>
<binary translate="no">shadps4</binary>
</provides>
<keywords>
<keyword>emulator</keyword>
<keyword>emulation</keyword>
<keyword translate="no">playstation</keyword>
<keyword translate="no">ps4</keyword>
</keywords>
</component>

23
dist/net.shadps4.shadPS4.releases.xml vendored Normal file
View File

@ -0,0 +1,23 @@
<releases>
<release version="0.4.0" date="2024-10-31">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.4.0</url>
</release>
<release version="0.3.0" date="2024-09-23">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.3.0</url>
</release>
<release version="0.2.0" date="2024-08-15">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.2.0</url>
</release>
<release version="0.1.0" date="2024-07-01">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/0.1.0</url>
</release>
<release version="0.0.3" date="2024-03-23">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v0.0.3</url>
</release>
<release version="0.0.2" date="2023-10-21">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v0.0.2</url>
</release>
<release version="0.0.1" date="2024-09-29">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v0.0.1</url>
</release>
</releases>

65
dist/net.shadps4.shadPS4_metadata.pot vendored Normal file
View File

@ -0,0 +1,65 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2024-11-08 09:07+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#. (itstool) path: component/name
#: ./net.shadps4.shadPS4.metainfo.xml:4
msgid "shadPS4"
msgstr ""
#. (itstool) path: developer/name
#: ./net.shadps4.shadPS4.metainfo.xml:6
msgid "shadPS4 Contributors"
msgstr ""
#. (itstool) path: component/summary
#: ./net.shadps4.shadPS4.metainfo.xml:9
msgid "PS4 Emulator"
msgstr ""
#. (itstool) path: description/p
#: ./net.shadps4.shadPS4.metainfo.xml:16
msgid "shadPS4 is an early PlayStation 4 emulator for Windows, Linux and macOS written in C++."
msgstr ""
#. (itstool) path: description/p
#: ./net.shadps4.shadPS4.metainfo.xml:17
msgid "The emulator is still early in development, so don't expect a flawless experience. Nonetheless, the emulator can already run a number of commercial games."
msgstr ""
#. (itstool) path: screenshot/caption
#: ./net.shadps4.shadPS4.metainfo.xml:22
msgid "Bloodborne"
msgstr ""
#. (itstool) path: screenshot/caption
#: ./net.shadps4.shadPS4.metainfo.xml:26
msgid "Hatsune Miku: Project DIVA Future Tone"
msgstr ""
#. (itstool) path: screenshot/caption
#: ./net.shadps4.shadPS4.metainfo.xml:30
msgid "Yakuza Kiwami"
msgstr ""
#. (itstool) path: screenshot/caption
#: ./net.shadps4.shadPS4.metainfo.xml:34
msgid "Persona 4 Golden"
msgstr ""
#. (itstool) path: keywords/keyword
#: ./net.shadps4.shadPS4.metainfo.xml:59
msgid "emulator"
msgstr ""
#. (itstool) path: keywords/keyword
#: ./net.shadps4.shadPS4.metainfo.xml:60
msgid "emulation"
msgstr ""

View File

@ -658,7 +658,7 @@ void save(const std::filesystem::path& path) {
// TODO Migration code, after a major release this should be removed. // TODO Migration code, after a major release this should be removed.
data.at("GUI").as_table().erase("installDir"); data.at("GUI").as_table().erase("installDir");
std::ofstream file(path, std::ios::out); std::ofstream file(path, std::ios::binary);
file << data; file << data;
file.close(); file.close();
} }

View File

@ -40,23 +40,11 @@ void AjmAt9Decoder::Initialize(const void* buffer, u32 buffer_size) {
const auto params = reinterpret_cast<const AjmDecAt9InitializeParameters*>(buffer); const auto params = reinterpret_cast<const AjmDecAt9InitializeParameters*>(buffer);
std::memcpy(m_config_data, params->config_data, ORBIS_AT9_CONFIG_DATA_SIZE); std::memcpy(m_config_data, params->config_data, ORBIS_AT9_CONFIG_DATA_SIZE);
AjmAt9Decoder::Reset(); AjmAt9Decoder::Reset();
m_pcm_buffer.resize(m_codec_info.frameSamples * m_codec_info.channels * GetPointCodeSize(), 0); m_pcm_buffer.resize(m_codec_info.frameSamples * m_codec_info.channels * GetPCMSize(m_format),
0);
} }
u8 AjmAt9Decoder::GetPointCodeSize() { void AjmAt9Decoder::GetInfo(void* out_info) const {
switch (m_format) {
case AjmFormatEncoding::S16:
return sizeof(s16);
case AjmFormatEncoding::S32:
return sizeof(s32);
case AjmFormatEncoding::Float:
return sizeof(float);
default:
UNREACHABLE();
}
}
void AjmAt9Decoder::GetInfo(void* out_info) {
auto* info = reinterpret_cast<AjmSidebandDecAt9CodecInfo*>(out_info); auto* info = reinterpret_cast<AjmSidebandDecAt9CodecInfo*>(out_info);
info->super_frame_size = m_codec_info.superframeSize; info->super_frame_size = m_codec_info.superframeSize;
info->frames_in_super_frame = m_codec_info.framesInSuperframe; info->frames_in_super_frame = m_codec_info.framesInSuperframe;
@ -65,8 +53,7 @@ void AjmAt9Decoder::GetInfo(void* out_info) {
} }
std::tuple<u32, u32> AjmAt9Decoder::ProcessData(std::span<u8>& in_buf, SparseOutputBuffer& output, std::tuple<u32, u32> AjmAt9Decoder::ProcessData(std::span<u8>& in_buf, SparseOutputBuffer& output,
AjmSidebandGaplessDecode& gapless, AjmInstanceGapless& gapless) {
std::optional<u32> max_samples_per_channel) {
int ret = 0; int ret = 0;
int bytes_used = 0; int bytes_used = 0;
switch (m_format) { switch (m_format) {
@ -91,32 +78,37 @@ std::tuple<u32, u32> AjmAt9Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
m_superframe_bytes_remain -= bytes_used; m_superframe_bytes_remain -= bytes_used;
u32 skipped_samples = 0; u32 skip_samples = 0;
if (gapless.skipped_samples < gapless.skip_samples) { if (gapless.current.skip_samples > 0) {
skipped_samples = std::min(u32(m_codec_info.frameSamples), skip_samples = std::min(u16(m_codec_info.frameSamples), gapless.current.skip_samples);
u32(gapless.skip_samples - gapless.skipped_samples)); gapless.current.skip_samples -= skip_samples;
gapless.skipped_samples += skipped_samples;
} }
const auto max_samples = max_samples_per_channel.has_value() const auto max_pcm = gapless.init.total_samples != 0
? max_samples_per_channel.value() * m_codec_info.channels ? gapless.current.total_samples * m_codec_info.channels
: std::numeric_limits<u32>::max(); : std::numeric_limits<u32>::max();
size_t samples_written = 0; size_t pcm_written = 0;
switch (m_format) { switch (m_format) {
case AjmFormatEncoding::S16: case AjmFormatEncoding::S16:
samples_written = WriteOutputSamples<s16>(output, skipped_samples, max_samples); pcm_written = WriteOutputSamples<s16>(output, skip_samples, max_pcm);
break; break;
case AjmFormatEncoding::S32: case AjmFormatEncoding::S32:
samples_written = WriteOutputSamples<s32>(output, skipped_samples, max_samples); pcm_written = WriteOutputSamples<s32>(output, skip_samples, max_pcm);
break; break;
case AjmFormatEncoding::Float: case AjmFormatEncoding::Float:
samples_written = WriteOutputSamples<float>(output, skipped_samples, max_samples); pcm_written = WriteOutputSamples<float>(output, skip_samples, max_pcm);
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
const auto samples_written = pcm_written / m_codec_info.channels;
gapless.current.skipped_samples += m_codec_info.frameSamples - samples_written;
if (gapless.init.total_samples != 0) {
gapless.current.total_samples -= samples_written;
}
m_num_frames += 1; m_num_frames += 1;
if ((m_num_frames % m_codec_info.framesInSuperframe) == 0) { if ((m_num_frames % m_codec_info.framesInSuperframe) == 0) {
if (m_superframe_bytes_remain) { if (m_superframe_bytes_remain) {
@ -126,18 +118,28 @@ std::tuple<u32, u32> AjmAt9Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
m_num_frames = 0; m_num_frames = 0;
} }
return {1, samples_written / m_codec_info.channels}; return {1, samples_written};
} }
AjmSidebandFormat AjmAt9Decoder::GetFormat() { AjmSidebandFormat AjmAt9Decoder::GetFormat() const {
return AjmSidebandFormat{ return AjmSidebandFormat{
.num_channels = u32(m_codec_info.channels), .num_channels = u32(m_codec_info.channels),
.channel_mask = GetChannelMask(u32(m_codec_info.channels)), .channel_mask = GetChannelMask(u32(m_codec_info.channels)),
.sampl_freq = u32(m_codec_info.samplingRate), .sampl_freq = u32(m_codec_info.samplingRate),
.sample_encoding = m_format, .sample_encoding = m_format,
.bitrate = u32(m_codec_info.samplingRate * GetPointCodeSize() * 8), .bitrate = u32((m_codec_info.samplingRate * m_codec_info.superframeSize * 8) /
(m_codec_info.framesInSuperframe * m_codec_info.frameSamples)),
.reserved = 0, .reserved = 0,
}; };
} }
u32 AjmAt9Decoder::GetNextFrameSize(const AjmInstanceGapless& gapless) const {
const auto max_samples =
gapless.init.total_samples != 0
? std::min(gapless.current.total_samples, u32(m_codec_info.frameSamples))
: m_codec_info.frameSamples;
const auto skip_samples = std::min(u32(gapless.current.skip_samples), max_samples);
return (max_samples - skip_samples) * m_codec_info.channels * GetPCMSize(m_format);
}
} // namespace Libraries::Ajm } // namespace Libraries::Ajm

View File

@ -33,15 +33,13 @@ struct AjmAt9Decoder final : AjmCodec {
void Reset() override; void Reset() override;
void Initialize(const void* buffer, u32 buffer_size) override; void Initialize(const void* buffer, u32 buffer_size) override;
void GetInfo(void* out_info) override; void GetInfo(void* out_info) const override;
AjmSidebandFormat GetFormat() override; AjmSidebandFormat GetFormat() const override;
u32 GetNextFrameSize(const AjmInstanceGapless& gapless) const override;
std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output, std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
AjmSidebandGaplessDecode& gapless, AjmInstanceGapless& gapless) override;
std::optional<u32> max_samples) override;
private: private:
u8 GetPointCodeSize();
template <class T> template <class T>
size_t WriteOutputSamples(SparseOutputBuffer& output, u32 skipped_samples, u32 max_samples) { size_t WriteOutputSamples(SparseOutputBuffer& output, u32 skipped_samples, u32 max_samples) {
std::span<T> pcm_data{reinterpret_cast<T*>(m_pcm_buffer.data()), std::span<T> pcm_data{reinterpret_cast<T*>(m_pcm_buffer.data()),

View File

@ -135,7 +135,10 @@ AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
case Identifier::AjmIdentInputControlBuf: { case Identifier::AjmIdentInputControlBuf: {
ASSERT_MSG(!input_control_buffer.has_value(), ASSERT_MSG(!input_control_buffer.has_value(),
"Only one instance of input control buffer is allowed per job"); "Only one instance of input control buffer is allowed per job");
input_control_buffer = batch_buffer.Consume<AjmChunkBuffer>(); const auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
if (buffer.p_address != nullptr && buffer.size != 0) {
input_control_buffer = buffer;
}
break; break;
} }
case Identifier::AjmIdentControlFlags: case Identifier::AjmIdentControlFlags:
@ -155,19 +158,27 @@ AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
case Identifier::AjmIdentInlineBuf: { case Identifier::AjmIdentInlineBuf: {
ASSERT_MSG(!output_control_buffer.has_value(), ASSERT_MSG(!output_control_buffer.has_value(),
"Only one instance of inline buffer is allowed per job"); "Only one instance of inline buffer is allowed per job");
inline_buffer = batch_buffer.Consume<AjmChunkBuffer>(); const auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
if (buffer.p_address != nullptr && buffer.size != 0) {
inline_buffer = buffer;
}
break; break;
} }
case Identifier::AjmIdentOutputRunBuf: { case Identifier::AjmIdentOutputRunBuf: {
auto& buffer = batch_buffer.Consume<AjmChunkBuffer>(); auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
u8* p_begin = reinterpret_cast<u8*>(buffer.p_address); u8* p_begin = reinterpret_cast<u8*>(buffer.p_address);
if (p_begin != nullptr && buffer.size != 0) {
job.output.buffers.emplace_back(std::span<u8>(p_begin, p_begin + buffer.size)); job.output.buffers.emplace_back(std::span<u8>(p_begin, p_begin + buffer.size));
}
break; break;
} }
case Identifier::AjmIdentOutputControlBuf: { case Identifier::AjmIdentOutputControlBuf: {
ASSERT_MSG(!output_control_buffer.has_value(), ASSERT_MSG(!output_control_buffer.has_value(),
"Only one instance of output control buffer is allowed per job"); "Only one instance of output control buffer is allowed per job");
output_control_buffer = batch_buffer.Consume<AjmChunkBuffer>(); const auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
if (buffer.p_address != nullptr && buffer.size != 0) {
output_control_buffer = buffer;
}
break; break;
} }
default: default:

View File

@ -22,6 +22,19 @@ constexpr int ORBIS_AJM_RESULT_PRIORITY_PASSED = 0x00000200;
constexpr int ORBIS_AJM_RESULT_CODEC_ERROR = 0x40000000; constexpr int ORBIS_AJM_RESULT_CODEC_ERROR = 0x40000000;
constexpr int ORBIS_AJM_RESULT_FATAL = 0x80000000; constexpr int ORBIS_AJM_RESULT_FATAL = 0x80000000;
u8 GetPCMSize(AjmFormatEncoding format) {
switch (format) {
case AjmFormatEncoding::S16:
return sizeof(s16);
case AjmFormatEncoding::S32:
return sizeof(s32);
case AjmFormatEncoding::Float:
return sizeof(float);
default:
UNREACHABLE();
}
}
AjmInstance::AjmInstance(AjmCodecType codec_type, AjmInstanceFlags flags) : m_flags(flags) { AjmInstance::AjmInstance(AjmCodecType codec_type, AjmInstanceFlags flags) : m_flags(flags) {
switch (codec_type) { switch (codec_type) {
case AjmCodecType::At9Dec: { case AjmCodecType::At9Dec: {
@ -30,7 +43,8 @@ AjmInstance::AjmInstance(AjmCodecType codec_type, AjmInstanceFlags flags) : m_fl
break; break;
} }
case AjmCodecType::Mp3Dec: { case AjmCodecType::Mp3Dec: {
m_codec = std::make_unique<AjmMp3Decoder>(AjmFormatEncoding(flags.format)); m_codec = std::make_unique<AjmMp3Decoder>(AjmFormatEncoding(flags.format),
AjmMp3CodecFlags(flags.codec));
break; break;
} }
default: default:
@ -45,7 +59,6 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
m_format = {}; m_format = {};
m_gapless = {}; m_gapless = {};
m_resample_parameters = {}; m_resample_parameters = {};
m_gapless_samples = 0;
m_total_samples = 0; m_total_samples = 0;
m_codec->Reset(); m_codec->Reset();
} }
@ -64,27 +77,47 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
} }
if (job.input.gapless_decode.has_value()) { if (job.input.gapless_decode.has_value()) {
auto& params = job.input.gapless_decode.value(); auto& params = job.input.gapless_decode.value();
m_gapless.total_samples = params.total_samples; if (params.total_samples != 0) {
m_gapless.skip_samples = params.skip_samples; const auto max = std::max(params.total_samples, m_gapless.init.total_samples);
m_gapless.current.total_samples += max - m_gapless.init.total_samples;
m_gapless.init.total_samples = max;
}
if (params.skip_samples != 0) {
const auto max = std::max(params.skip_samples, m_gapless.init.skip_samples);
m_gapless.current.skip_samples += max - m_gapless.init.skip_samples;
m_gapless.init.skip_samples = max;
}
} }
if (!job.input.buffer.empty() && !job.output.buffers.empty()) { if (!job.input.buffer.empty() && !job.output.buffers.empty()) {
u32 frames_decoded = 0;
std::span<u8> in_buf(job.input.buffer); std::span<u8> in_buf(job.input.buffer);
SparseOutputBuffer out_buf(job.output.buffers); SparseOutputBuffer out_buf(job.output.buffers);
u32 frames_decoded = 0;
auto in_size = in_buf.size(); auto in_size = in_buf.size();
auto out_size = out_buf.Size(); auto out_size = out_buf.Size();
while (!in_buf.empty() && !out_buf.IsEmpty() && !IsGaplessEnd()) { while (!in_buf.empty() && !out_buf.IsEmpty() && !m_gapless.IsEnd()) {
const auto samples_remain = if (!HasEnoughSpace(out_buf)) {
m_gapless.total_samples != 0 if (job.output.p_mframe == nullptr || frames_decoded == 0) {
? std::optional<u32>{m_gapless.total_samples - m_gapless_samples} job.output.p_result->result = ORBIS_AJM_RESULT_NOT_ENOUGH_ROOM;
: std::optional<u32>{}; break;
const auto [nframes, nsamples] = }
m_codec->ProcessData(in_buf, out_buf, m_gapless, samples_remain); }
const auto [nframes, nsamples] = m_codec->ProcessData(in_buf, out_buf, m_gapless);
frames_decoded += nframes; frames_decoded += nframes;
m_total_samples += nsamples; m_total_samples += nsamples;
m_gapless_samples += nsamples;
if (False(job.flags.run_flags & AjmJobRunFlags::MultipleFrames)) {
break;
}
}
if (m_gapless.IsEnd()) {
in_buf = in_buf.subspan(in_buf.size());
m_gapless.current.total_samples = m_gapless.init.total_samples;
m_gapless.current.skip_samples = m_gapless.init.skip_samples;
m_codec->Reset();
} }
if (job.output.p_mframe) { if (job.output.p_mframe) {
job.output.p_mframe->num_frames = frames_decoded; job.output.p_mframe->num_frames = frames_decoded;
@ -96,25 +129,19 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
} }
} }
if (m_flags.gapless_loop && m_gapless.total_samples != 0 &&
m_gapless_samples >= m_gapless.total_samples) {
m_gapless_samples = 0;
m_gapless.skipped_samples = 0;
m_codec->Reset();
}
if (job.output.p_format != nullptr) { if (job.output.p_format != nullptr) {
*job.output.p_format = m_codec->GetFormat(); *job.output.p_format = m_codec->GetFormat();
} }
if (job.output.p_gapless_decode != nullptr) { if (job.output.p_gapless_decode != nullptr) {
*job.output.p_gapless_decode = m_gapless; *job.output.p_gapless_decode = m_gapless.current;
} }
if (job.output.p_codec_info != nullptr) { if (job.output.p_codec_info != nullptr) {
m_codec->GetInfo(job.output.p_codec_info); m_codec->GetInfo(job.output.p_codec_info);
} }
} }
bool AjmInstance::IsGaplessEnd() { bool AjmInstance::HasEnoughSpace(const SparseOutputBuffer& output) const {
return m_gapless.total_samples != 0 && m_gapless_samples >= m_gapless.total_samples; return output.Size() >= m_codec->GetNextFrameSize(m_gapless);
} }
} // namespace Libraries::Ajm } // namespace Libraries::Ajm

View File

@ -14,6 +14,8 @@
namespace Libraries::Ajm { namespace Libraries::Ajm {
u8 GetPCMSize(AjmFormatEncoding format);
class SparseOutputBuffer { class SparseOutputBuffer {
public: public:
SparseOutputBuffer(std::span<std::span<u8>> chunks) SparseOutputBuffer(std::span<std::span<u8>> chunks)
@ -33,14 +35,17 @@ public:
++m_current; ++m_current;
} }
} }
if (!pcm.empty()) {
LOG_ERROR(Lib_Ajm, "Could not write {} samples", pcm.size());
}
return samples_written; return samples_written;
} }
bool IsEmpty() { bool IsEmpty() const {
return m_current == m_chunks.end(); return m_current == m_chunks.end();
} }
size_t Size() { size_t Size() const {
size_t result = 0; size_t result = 0;
for (auto it = m_current; it != m_chunks.end(); ++it) { for (auto it = m_current; it != m_chunks.end(); ++it) {
result += it->size(); result += it->size();
@ -53,17 +58,26 @@ private:
std::span<std::span<u8>>::iterator m_current; std::span<std::span<u8>>::iterator m_current;
}; };
struct AjmInstanceGapless {
AjmSidebandGaplessDecode init{};
AjmSidebandGaplessDecode current{};
bool IsEnd() const {
return init.total_samples != 0 && current.total_samples == 0;
}
};
class AjmCodec { class AjmCodec {
public: public:
virtual ~AjmCodec() = default; virtual ~AjmCodec() = default;
virtual void Initialize(const void* buffer, u32 buffer_size) = 0; virtual void Initialize(const void* buffer, u32 buffer_size) = 0;
virtual void Reset() = 0; virtual void Reset() = 0;
virtual void GetInfo(void* out_info) = 0; virtual void GetInfo(void* out_info) const = 0;
virtual AjmSidebandFormat GetFormat() = 0; virtual AjmSidebandFormat GetFormat() const = 0;
virtual u32 GetNextFrameSize(const AjmInstanceGapless& gapless) const = 0;
virtual std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output, virtual std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
AjmSidebandGaplessDecode& gapless, AjmInstanceGapless& gapless) = 0;
std::optional<u32> max_samples_per_channel) = 0;
}; };
class AjmInstance { class AjmInstance {
@ -73,16 +87,14 @@ public:
void ExecuteJob(AjmJob& job); void ExecuteJob(AjmJob& job);
private: private:
bool IsGaplessEnd(); bool HasEnoughSpace(const SparseOutputBuffer& output) const;
std::optional<u32> GetNumRemainingSamples() const;
AjmInstanceFlags m_flags{}; AjmInstanceFlags m_flags{};
AjmSidebandFormat m_format{}; AjmSidebandFormat m_format{};
AjmSidebandGaplessDecode m_gapless{}; AjmInstanceGapless m_gapless{};
AjmSidebandResampleParameters m_resample_parameters{}; AjmSidebandResampleParameters m_resample_parameters{};
u32 m_gapless_samples{};
u32 m_total_samples{}; u32 m_total_samples{};
std::unique_ptr<AjmCodec> m_codec; std::unique_ptr<AjmCodec> m_codec;
}; };

View File

@ -15,18 +15,50 @@ extern "C" {
namespace Libraries::Ajm { namespace Libraries::Ajm {
// Following tables have been reversed from AJM library // Following tables have been reversed from AJM library
static constexpr std::array<std::array<s32, 3>, 3> SamplerateTable = {{ static constexpr std::array<std::array<s32, 4>, 4> Mp3SampleRateTable = {
{0x5622, 0x5DC0, 0x3E80}, std::array<s32, 4>{11025, 12000, 8000, 0},
{0xAC44, 0xBB80, 0x7D00}, std::array<s32, 4>{0, 0, 0, 0},
{0x2B11, 0x2EE0, 0x1F40}, std::array<s32, 4>{22050, 24000, 16000, 0},
}}; std::array<s32, 4>{44100, 48000, 32000, 0},
};
static constexpr std::array<std::array<s32, 15>, 2> BitrateTable = {{ static constexpr std::array<std::array<s32, 16>, 4> Mp3BitRateTable = {
{0, 0x20, 0x28, 0x30, 0x38, 0x40, 0x50, 0x60, 0x70, 0x80, 0xA0, 0xC0, 0xE0, 0x100, 0x140}, std::array<s32, 16>{0, 8, 16, 24, 32, 40, 48, 56, 64, 0, 0, 0, 0, 0, 0, 0},
{0, 0x8, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0}, std::array<s32, 16>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}}; std::array<s32, 16>{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0},
std::array<s32, 16>{0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0},
};
static constexpr std::array<s32, 2> UnkTable = {0x48, 0x90}; enum class Mp3AudioVersion : u32 {
V2_5 = 0,
Reserved = 1,
V2 = 2,
V1 = 3,
};
enum class Mp3ChannelMode : u32 {
Stereo = 0,
JointStereo = 1,
DualChannel = 2,
SingleChannel = 3,
};
struct Mp3Header {
u32 emphasis : 2;
u32 original : 1;
u32 copyright : 1;
u32 mode_ext_idx : 2;
Mp3ChannelMode channel_mode : 2;
u32 : 1;
u32 padding : 1;
u32 sampling_rate_idx : 2;
u32 bitrate_idx : 4;
u32 protection_type : 1;
u32 layer_type : 2;
Mp3AudioVersion version : 2;
u32 sync : 11;
};
static_assert(sizeof(Mp3Header) == sizeof(u32));
static AVSampleFormat AjmToAVSampleFormat(AjmFormatEncoding format) { static AVSampleFormat AjmToAVSampleFormat(AjmFormatEncoding format) {
switch (format) { switch (format) {
@ -62,7 +94,7 @@ AVFrame* AjmMp3Decoder::ConvertAudioFrame(AVFrame* frame) {
swr_init(m_swr_context); swr_init(m_swr_context);
const auto res = swr_convert_frame(m_swr_context, new_frame, frame); const auto res = swr_convert_frame(m_swr_context, new_frame, frame);
if (res < 0) { if (res < 0) {
LOG_ERROR(Lib_AvPlayer, "Could not convert to S16: {}", av_err2str(res)); LOG_ERROR(Lib_AvPlayer, "Could not convert frame: {}", av_err2str(res));
av_frame_free(&new_frame); av_frame_free(&new_frame);
av_frame_free(&frame); av_frame_free(&frame);
return nullptr; return nullptr;
@ -71,48 +103,57 @@ AVFrame* AjmMp3Decoder::ConvertAudioFrame(AVFrame* frame) {
return new_frame; return new_frame;
} }
AjmMp3Decoder::AjmMp3Decoder(AjmFormatEncoding format) AjmMp3Decoder::AjmMp3Decoder(AjmFormatEncoding format, AjmMp3CodecFlags flags)
: m_format(format), m_codec(avcodec_find_decoder(AV_CODEC_ID_MP3)), : m_format(format), m_flags(flags), m_codec(avcodec_find_decoder(AV_CODEC_ID_MP3)),
m_parser(av_parser_init(m_codec->id)) { m_codec_context(avcodec_alloc_context3(m_codec)), m_parser(av_parser_init(m_codec->id)) {
AjmMp3Decoder::Reset();
}
AjmMp3Decoder::~AjmMp3Decoder() {
swr_free(&m_swr_context);
avcodec_free_context(&m_codec_context);
}
void AjmMp3Decoder::Reset() {
if (m_codec_context) {
avcodec_free_context(&m_codec_context);
}
m_codec_context = avcodec_alloc_context3(m_codec);
ASSERT_MSG(m_codec_context, "Could not allocate audio m_codec context");
int ret = avcodec_open2(m_codec_context, m_codec, nullptr); int ret = avcodec_open2(m_codec_context, m_codec, nullptr);
ASSERT_MSG(ret >= 0, "Could not open m_codec"); ASSERT_MSG(ret >= 0, "Could not open m_codec");
} }
void AjmMp3Decoder::GetInfo(void* out_info) { AjmMp3Decoder::~AjmMp3Decoder() {
swr_free(&m_swr_context);
av_parser_close(m_parser);
avcodec_free_context(&m_codec_context);
}
void AjmMp3Decoder::Reset() {
avcodec_flush_buffers(m_codec_context);
m_header.reset();
m_frame_samples = 0;
}
void AjmMp3Decoder::GetInfo(void* out_info) const {
auto* info = reinterpret_cast<AjmSidebandDecMp3CodecInfo*>(out_info); auto* info = reinterpret_cast<AjmSidebandDecMp3CodecInfo*>(out_info);
if (m_header.has_value()) {
auto* header = reinterpret_cast<const Mp3Header*>(&m_header.value());
info->header = std::byteswap(m_header.value());
info->has_crc = header->protection_type;
info->channel_mode = static_cast<ChannelMode>(header->channel_mode);
info->mode_extension = header->mode_ext_idx;
info->copyright = header->copyright;
info->original = header->original;
info->emphasis = header->emphasis;
}
} }
std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOutputBuffer& output, std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOutputBuffer& output,
AjmSidebandGaplessDecode& gapless, AjmInstanceGapless& gapless) {
std::optional<u32> max_samples_per_channel) {
AVPacket* pkt = av_packet_alloc(); AVPacket* pkt = av_packet_alloc();
if ((!m_header.has_value() || m_frame_samples == 0) && in_buf.size() >= 4) {
m_header = std::byteswap(*reinterpret_cast<u32*>(in_buf.data()));
AjmDecMp3ParseFrame info{};
ParseMp3Header(in_buf.data(), in_buf.size(), false, &info);
m_frame_samples = info.samples_per_channel;
}
int ret = av_parser_parse2(m_parser, m_codec_context, &pkt->data, &pkt->size, in_buf.data(), int ret = av_parser_parse2(m_parser, m_codec_context, &pkt->data, &pkt->size, in_buf.data(),
in_buf.size(), AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0); in_buf.size(), AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
ASSERT_MSG(ret >= 0, "Error while parsing {}", ret); ASSERT_MSG(ret >= 0, "Error while parsing {}", ret);
in_buf = in_buf.subspan(ret); in_buf = in_buf.subspan(ret);
u32 frames_decoded = 0; u32 frames_decoded = 0;
u32 samples_decoded = 0; u32 samples_written = 0;
auto max_samples =
max_samples_per_channel.has_value()
? max_samples_per_channel.value() * m_codec_context->ch_layout.nb_channels
: std::numeric_limits<u32>::max();
if (pkt->size) { if (pkt->size) {
// Send the packet with the compressed data to the decoder // Send the packet with the compressed data to the decoder
@ -135,31 +176,38 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
frame = ConvertAudioFrame(frame); frame = ConvertAudioFrame(frame);
frames_decoded += 1; frames_decoded += 1;
u32 skipped_samples = 0; u32 skip_samples = 0;
if (gapless.skipped_samples < gapless.skip_samples) { if (gapless.current.skip_samples > 0) {
skipped_samples = std::min(u32(frame->nb_samples), skip_samples = std::min(u16(frame->nb_samples), gapless.current.skip_samples);
u32(gapless.skip_samples - gapless.skipped_samples)); gapless.current.skip_samples -= skip_samples;
gapless.skipped_samples += skipped_samples;
} }
const auto max_pcm =
gapless.init.total_samples != 0
? gapless.current.total_samples * m_codec_context->ch_layout.nb_channels
: std::numeric_limits<u32>::max();
u32 pcm_written = 0;
switch (m_format) { switch (m_format) {
case AjmFormatEncoding::S16: case AjmFormatEncoding::S16:
samples_decoded += pcm_written = WriteOutputPCM<s16>(frame, output, skip_samples, max_pcm);
WriteOutputSamples<s16>(frame, output, skipped_samples, max_samples);
break; break;
case AjmFormatEncoding::S32: case AjmFormatEncoding::S32:
samples_decoded += pcm_written = WriteOutputPCM<s32>(frame, output, skip_samples, max_pcm);
WriteOutputSamples<s32>(frame, output, skipped_samples, max_samples);
break; break;
case AjmFormatEncoding::Float: case AjmFormatEncoding::Float:
samples_decoded += pcm_written = WriteOutputPCM<float>(frame, output, skip_samples, max_pcm);
WriteOutputSamples<float>(frame, output, skipped_samples, max_samples);
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
max_samples -= samples_decoded; const auto samples = pcm_written / m_codec_context->ch_layout.nb_channels;
samples_written += samples;
gapless.current.skipped_samples += frame->nb_samples - samples;
if (gapless.init.total_samples != 0) {
gapless.current.total_samples -= samples;
}
av_frame_free(&frame); av_frame_free(&frame);
} }
@ -167,38 +215,221 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
av_packet_free(&pkt); av_packet_free(&pkt);
return {frames_decoded, samples_decoded}; return {frames_decoded, samples_written};
} }
int AjmMp3Decoder::ParseMp3Header(const u8* buf, u32 stream_size, int parse_ofl, u32 AjmMp3Decoder::GetNextFrameSize(const AjmInstanceGapless& gapless) const {
const auto max_samples = gapless.init.total_samples != 0
? std::min(gapless.current.total_samples, m_frame_samples)
: m_frame_samples;
const auto skip_samples = std::min(u32(gapless.current.skip_samples), max_samples);
return (max_samples - skip_samples) * m_codec_context->ch_layout.nb_channels *
GetPCMSize(m_format);
}
class BitReader {
public:
BitReader(const u8* data) : m_data(data) {}
template <class T>
T Read(u32 const nbits) {
T accumulator = 0;
for (unsigned i = 0; i < nbits; ++i) {
accumulator = (accumulator << 1) + GetBit();
}
return accumulator;
}
void Skip(size_t nbits) {
m_bit_offset += nbits;
}
size_t GetCurrentOffset() {
return m_bit_offset;
}
private:
u8 GetBit() {
const auto bit = (m_data[m_bit_offset / 8] >> (7 - (m_bit_offset % 8))) & 1;
m_bit_offset += 1;
return bit;
}
const u8* m_data;
size_t m_bit_offset = 0;
};
int AjmMp3Decoder::ParseMp3Header(const u8* p_begin, u32 stream_size, int parse_ofl,
AjmDecMp3ParseFrame* frame) { AjmDecMp3ParseFrame* frame) {
LOG_INFO(Lib_Ajm, "called stream_size = {} parse_ofl = {}", stream_size, parse_ofl); LOG_INFO(Lib_Ajm, "called stream_size = {} parse_ofl = {}", stream_size, parse_ofl);
if (buf == nullptr || stream_size < 4 || frame == nullptr) {
return ORBIS_AJM_ERROR_INVALID_PARAMETER; if (p_begin == nullptr || stream_size < 4 || frame == nullptr) {
}
if ((buf[0] & SYNCWORDH) != SYNCWORDH || (buf[1] & SYNCWORDL) != SYNCWORDL) {
return ORBIS_AJM_ERROR_INVALID_PARAMETER; return ORBIS_AJM_ERROR_INVALID_PARAMETER;
} }
const u32 unk_idx = buf[1] >> 3 & 1; const auto* p_current = p_begin;
const s32 version_idx = (buf[1] >> 3 & 3) ^ 2;
const s32 sr_idx = buf[2] >> 2 & 3; auto bytes = std::byteswap(*reinterpret_cast<const u32*>(p_current));
const s32 br_idx = (buf[2] >> 4) & 0xf; p_current += 4;
const s32 padding_bit = (buf[2] >> 1) & 0x1; auto header = reinterpret_cast<const Mp3Header*>(&bytes);
if (header->sync != 0x7FF) {
return ORBIS_AJM_ERROR_INVALID_PARAMETER;
}
frame->sample_rate = Mp3SampleRateTable[u32(header->version)][header->sampling_rate_idx];
frame->bitrate = Mp3BitRateTable[u32(header->version)][header->bitrate_idx] * 1000;
frame->num_channels = header->channel_mode == Mp3ChannelMode::SingleChannel ? 1 : 2;
if (header->version == Mp3AudioVersion::V1) {
frame->frame_size = (144 * frame->bitrate) / frame->sample_rate + header->padding;
frame->samples_per_channel = 1152;
} else {
frame->frame_size = (72 * frame->bitrate) / frame->sample_rate + header->padding;
frame->samples_per_channel = 576;
}
frame->sample_rate = SamplerateTable[version_idx][sr_idx];
frame->bitrate = BitrateTable[version_idx != 1][br_idx] * 1000;
frame->num_channels = (buf[3] < 0xc0) + 1;
frame->frame_size = (UnkTable[unk_idx] * frame->bitrate) / frame->sample_rate + padding_bit;
frame->samples_per_channel = UnkTable[unk_idx] * 8;
frame->encoder_delay = 0; frame->encoder_delay = 0;
frame->num_frames = 0;
frame->total_samples = 0;
frame->ofl_type = AjmDecMp3OflType::None;
if (!parse_ofl) {
return ORBIS_OK;
}
BitReader reader(p_current);
if (header->protection_type == 0) {
reader.Skip(16); // crc = reader.Read<u16>(16);
}
if (header->version == Mp3AudioVersion::V1) {
// main_data_begin = reader.Read<u16>(9);
// if (header->channel_mode == Mp3ChannelMode::SingleChannel) {
// private_bits = reader.Read<u8>(5);
// } else {
// private_bits = reader.Read<u8>(3);
// }
// for (u32 ch = 0; ch < frame->num_channels; ++ch) {
// for (u8 band = 0; band < 4; ++band) {
// scfsi[ch][band] = reader.Read<bool>(1);
// }
// }
if (header->channel_mode == Mp3ChannelMode::SingleChannel) {
reader.Skip(18);
} else {
reader.Skip(20);
}
} else {
// main_data_begin = reader.Read<u16>(8);
// if (header->channel_mode == Mp3ChannelMode::SingleChannel) {
// private_bits = reader.Read<u8>(1);
// } else {
// private_bits = reader.Read<u8>(2);
// }
if (header->channel_mode == Mp3ChannelMode::SingleChannel) {
reader.Skip(9);
} else {
reader.Skip(10);
}
}
u32 part2_3_length = 0;
// Number of granules (18x32 sub-band samples)
const u8 ngr = header->version == Mp3AudioVersion::V1 ? 2 : 1;
for (u8 gr = 0; gr < ngr; ++gr) {
for (u32 ch = 0; ch < frame->num_channels; ++ch) {
// part2_3_length[gr][ch] = reader.Read<u16>(12);
part2_3_length += reader.Read<u16>(12);
// big_values[gr][ch] = reader.Read<u16>(9);
// global_main[gr][ch] = reader.Read<u8>(8);
// if (header->version == Mp3AudioVersion::V1) {
// scalefac_compress[gr][ch] = reader.Read<u16>(4);
// } else {
// scalefac_compress[gr][ch] = reader.Read<u16>(9);
// }
// window_switching_flag = reader.Read<bool>(1);
// if (window_switching_flag) {
// block_type[gr][ch] = reader.Read<u8>(2);
// mixed_block_flag[gr][ch] = reader.Read<bool>(1);
// for (u8 region = 0; region < 2; ++region) {
// table_select[gr][ch][region] = reader.Read<u8>(5);
// }
// for (u8 window = 0; window < 3; ++window) {
// subblock_gain[gr][ch][window] = reader.Read<u8>(3);
// }
// } else {
// for (u8 region = 0; region < 3; ++region) {
// table_select[gr][ch][region] = reader.Read<u8>(5);
// }
// region0_count[gr][ch] = reader.Read<u8>(4);
// region1_count[gr][ch] = reader.Read<u8>(3);
// }
// if (header->version == Mp3AudioVersion::V1) {
// preflag[gr][ch] = reader.Read<bool>(1);
// }
// scalefac_scale[gr][ch] = reader.Read<bool>(1);
// count1table_select[gr][ch] = reader.Read<bool>(1);
if (header->version == Mp3AudioVersion::V1) {
reader.Skip(47);
} else {
reader.Skip(51);
}
}
}
reader.Skip(part2_3_length);
p_current += ((reader.GetCurrentOffset() + 7) / 8);
const auto* p_end = p_begin + frame->frame_size;
if (memcmp(p_current, "Xing", 4) == 0 || memcmp(p_current, "Info", 4) == 0) {
// TODO: Parse Xing/Lame header
LOG_ERROR(Lib_Ajm, "Xing/Lame header is not implemented.");
} else if (memcmp(p_current, "VBRI", 4) == 0) {
// TODO: Parse VBRI header
LOG_ERROR(Lib_Ajm, "VBRI header is not implemented.");
} else {
// Parse FGH header
constexpr auto fgh_indicator = 0xB4;
while ((p_current + 9) < p_end && *p_current != fgh_indicator) {
++p_current;
}
auto p_fgh = p_current;
if ((p_current + 9) < p_end && *p_current == fgh_indicator) {
u8 crc = 0xFF;
auto crc_func = [](u8 c, u8 v, u8 s) {
if (((c >> 7) & 1) != ((v >> s) & 1)) {
return c * 2;
}
return (c * 2) ^ 0x45;
};
for (u8 i = 0; i < 9; ++i, ++p_current) {
for (u8 j = 0; j < 8; ++j) {
crc = crc_func(crc, *p_current, 7 - j);
}
}
if (p_fgh[9] == crc) {
frame->encoder_delay = std::byteswap(*reinterpret_cast<const u16*>(p_fgh + 1));
frame->total_samples = std::byteswap(*reinterpret_cast<const u32*>(p_fgh + 3));
frame->ofl_type = AjmDecMp3OflType::Fgh;
} else {
LOG_ERROR(Lib_Ajm, "FGH header CRC is incorrect.");
}
} else {
LOG_ERROR(Lib_Ajm, "Could not find vendor header.");
}
}
return ORBIS_OK; return ORBIS_OK;
} }
AjmSidebandFormat AjmMp3Decoder::GetFormat() { AjmSidebandFormat AjmMp3Decoder::GetFormat() const {
LOG_ERROR(Lib_Ajm, "Unimplemented"); return AjmSidebandFormat{
return AjmSidebandFormat{}; .num_channels = u32(m_codec_context->ch_layout.nb_channels),
.channel_mask = GetChannelMask(u32(m_codec_context->ch_layout.nb_channels)),
.sampl_freq = u32(m_codec_context->sample_rate),
.sample_encoding = m_format,
.bitrate = u32(m_codec_context->bit_rate),
.reserved = 0,
};
}; };
} // namespace Libraries::Ajm } // namespace Libraries::Ajm

View File

@ -13,7 +13,19 @@ struct SwrContext;
namespace Libraries::Ajm { namespace Libraries::Ajm {
enum class AjmDecMp3OflType : u32 { None = 0, Lame = 1, Vbri = 2, Fgh = 3, VbriAndFgh = 4 }; enum class AjmDecMp3OflType : u32 {
None = 0,
Lame = 1,
Vbri = 2,
Fgh = 3,
VbriAndFgh = 4,
};
enum AjmMp3CodecFlags : u32 {
IgnoreOfl = 1 << 0,
VlcRewind = 1 << 8,
};
DECLARE_ENUM_FLAG_OPERATORS(AjmMp3CodecFlags)
// 11-bit syncword if MPEG 2.5 extensions are enabled // 11-bit syncword if MPEG 2.5 extensions are enabled
static constexpr u8 SYNCWORDH = 0xff; static constexpr u8 SYNCWORDH = 0xff;
@ -51,39 +63,40 @@ struct AjmSidebandDecMp3CodecInfo {
class AjmMp3Decoder : public AjmCodec { class AjmMp3Decoder : public AjmCodec {
public: public:
explicit AjmMp3Decoder(AjmFormatEncoding format); explicit AjmMp3Decoder(AjmFormatEncoding format, AjmMp3CodecFlags flags);
~AjmMp3Decoder() override; ~AjmMp3Decoder() override;
void Reset() override; void Reset() override;
void Initialize(const void* buffer, u32 buffer_size) override {} void Initialize(const void* buffer, u32 buffer_size) override {}
void GetInfo(void* out_info) override; void GetInfo(void* out_info) const override;
AjmSidebandFormat GetFormat() override; AjmSidebandFormat GetFormat() const override;
u32 GetNextFrameSize(const AjmInstanceGapless& gapless) const override;
std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output, std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
AjmSidebandGaplessDecode& gapless, AjmInstanceGapless& gapless) override;
std::optional<u32> max_samples_per_channel) override;
static int ParseMp3Header(const u8* buf, u32 stream_size, int parse_ofl, static int ParseMp3Header(const u8* buf, u32 stream_size, int parse_ofl,
AjmDecMp3ParseFrame* frame); AjmDecMp3ParseFrame* frame);
private: private:
template <class T> template <class T>
size_t WriteOutputSamples(AVFrame* frame, SparseOutputBuffer& output, u32 skipped_samples, size_t WriteOutputPCM(AVFrame* frame, SparseOutputBuffer& output, u32 skipped_samples,
u32 max_samples) { u32 max_pcm) {
const auto size = frame->ch_layout.nb_channels * frame->nb_samples * sizeof(T); std::span<T> pcm_data(reinterpret_cast<T*>(frame->data[0]),
std::span<T> pcm_data(reinterpret_cast<T*>(frame->data[0]), size >> 1); frame->nb_samples * frame->ch_layout.nb_channels);
pcm_data = pcm_data.subspan(skipped_samples * frame->ch_layout.nb_channels); pcm_data = pcm_data.subspan(skipped_samples * frame->ch_layout.nb_channels);
const auto pcm_size = std::min(u32(pcm_data.size()), max_samples); return output.Write(pcm_data.subspan(0, std::min(u32(pcm_data.size()), max_pcm)));
const auto samples_written = output.Write(pcm_data.subspan(0, pcm_size));
return samples_written / frame->ch_layout.nb_channels;
} }
AVFrame* ConvertAudioFrame(AVFrame* frame); AVFrame* ConvertAudioFrame(AVFrame* frame);
const AjmFormatEncoding m_format; const AjmFormatEncoding m_format;
const AjmMp3CodecFlags m_flags;
const AVCodec* m_codec = nullptr; const AVCodec* m_codec = nullptr;
AVCodecContext* m_codec_context = nullptr; AVCodecContext* m_codec_context = nullptr;
AVCodecParserContext* m_parser = nullptr; AVCodecParserContext* m_parser = nullptr;
SwrContext* m_swr_context = nullptr; SwrContext* m_swr_context = nullptr;
std::optional<u32> m_header;
u32 m_frame_samples = 0;
}; };
} // namespace Libraries::Ajm } // namespace Libraries::Ajm

View File

@ -237,7 +237,7 @@ s64 PS4_SYSV_ABI sceKernelLseek(int d, s64 offset, int whence) {
} }
s64 PS4_SYSV_ABI posix_lseek(int d, s64 offset, int whence) { s64 PS4_SYSV_ABI posix_lseek(int d, s64 offset, int whence) {
int result = sceKernelLseek(d, offset, whence); s64 result = sceKernelLseek(d, offset, whence);
if (result < 0) { if (result < 0) {
LOG_ERROR(Kernel_Pthread, "posix_lseek: error = {}", result); LOG_ERROR(Kernel_Pthread, "posix_lseek: error = {}", result);
ErrSceToPosix(result); ErrSceToPosix(result);
@ -490,6 +490,16 @@ s32 PS4_SYSV_ABI sceKernelFsync(int fd) {
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI posix_fsync(int fd) {
s32 result = sceKernelFsync(fd);
if (result < 0) {
LOG_ERROR(Kernel_Pthread, "posix_fstat: error = {}", result);
ErrSceToPosix(result);
return -1;
}
return result;
}
int PS4_SYSV_ABI sceKernelFtruncate(int fd, s64 length) { int PS4_SYSV_ABI sceKernelFtruncate(int fd, s64 length) {
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance(); auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(fd); auto* file = h->GetFile(fd);
@ -642,6 +652,8 @@ void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("+r3rMFwItV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPread); LIB_FUNCTION("+r3rMFwItV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPread);
LIB_FUNCTION("uWyW3v98sU4", "libkernel", 1, "libkernel", 1, 1, sceKernelCheckReachability); LIB_FUNCTION("uWyW3v98sU4", "libkernel", 1, "libkernel", 1, 1, sceKernelCheckReachability);
LIB_FUNCTION("fTx66l5iWIA", "libkernel", 1, "libkernel", 1, 1, sceKernelFsync); LIB_FUNCTION("fTx66l5iWIA", "libkernel", 1, "libkernel", 1, 1, sceKernelFsync);
LIB_FUNCTION("juWbTNM+8hw", "libkernel", 1, "libkernel", 1, 1, posix_fsync);
LIB_FUNCTION("juWbTNM+8hw", "libScePosix", 1, "libkernel", 1, 1, posix_fsync);
LIB_FUNCTION("j2AIqSqJP0w", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdents); LIB_FUNCTION("j2AIqSqJP0w", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdents);
LIB_FUNCTION("taRWhTJFTgE", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdirentries); LIB_FUNCTION("taRWhTJFTgE", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdirentries);
LIB_FUNCTION("nKWi-N2HBV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPwrite); LIB_FUNCTION("nKWi-N2HBV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPwrite);

View File

@ -491,6 +491,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("-o5uEDpN+oY", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertUtcToLocaltime); LIB_FUNCTION("-o5uEDpN+oY", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertUtcToLocaltime);
LIB_FUNCTION("WB66evu8bsU", "libkernel", 1, "libkernel", 1, 1, sceKernelGetCompiledSdkVersion); LIB_FUNCTION("WB66evu8bsU", "libkernel", 1, "libkernel", 1, 1, sceKernelGetCompiledSdkVersion);
LIB_FUNCTION("DRuBt2pvICk", "libkernel", 1, "libkernel", 1, 1, ps4__read); LIB_FUNCTION("DRuBt2pvICk", "libkernel", 1, "libkernel", 1, 1, ps4__read);
LIB_FUNCTION("k+AXqu2-eBc", "libkernel", 1, "libkernel", 1, 1, posix_getpagesize);
LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize); LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize);
Libraries::Kernel::fileSystemSymbolsRegister(sym); Libraries::Kernel::fileSystemSymbolsRegister(sym);

View File

@ -477,6 +477,10 @@ int PS4_SYSV_ABI scePthreadMutexDestroy(ScePthreadMutex* mutex) {
return SCE_KERNEL_ERROR_EINVAL; return SCE_KERNEL_ERROR_EINVAL;
} }
if (*mutex == ORBIS_PTHREAD_MUTEX_ADAPTIVE_INITIALIZER) {
return ORBIS_OK;
}
int result = pthread_mutex_destroy(&(*mutex)->pth_mutex); int result = pthread_mutex_destroy(&(*mutex)->pth_mutex);
LOG_DEBUG(Kernel_Pthread, "name={}, result={}", (*mutex)->name, result); LOG_DEBUG(Kernel_Pthread, "name={}, result={}", (*mutex)->name, result);

View File

@ -36,7 +36,7 @@ int PS4_SYSV_ABI sceVideodecDecode(OrbisVideodecCtrl* pCtrlIn,
const OrbisVideodecInputData* pInputDataIn, const OrbisVideodecInputData* pInputDataIn,
OrbisVideodecFrameBuffer* pFrameBufferInOut, OrbisVideodecFrameBuffer* pFrameBufferInOut,
OrbisVideodecPictureInfo* pPictureInfoOut) { OrbisVideodecPictureInfo* pPictureInfoOut) {
LOG_INFO(Lib_Videodec, "called"); LOG_TRACE(Lib_Videodec, "called");
if (!pCtrlIn || !pInputDataIn || !pPictureInfoOut) { if (!pCtrlIn || !pInputDataIn || !pPictureInfoOut) {
return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER;
} }

View File

@ -514,7 +514,8 @@ int MemoryManager::VirtualQuery(VAddr addr, int flags,
info->is_direct.Assign(vma.type == VMAType::Direct); info->is_direct.Assign(vma.type == VMAType::Direct);
info->is_stack.Assign(vma.type == VMAType::Stack); info->is_stack.Assign(vma.type == VMAType::Stack);
info->is_pooled.Assign(vma.type == VMAType::Pooled); info->is_pooled.Assign(vma.type == VMAType::Pooled);
info->is_committed.Assign(vma.type != VMAType::Free && vma.type != VMAType::Reserved); info->is_committed.Assign(vma.type != VMAType::Free && vma.type != VMAType::Reserved &&
vma.type != VMAType::PoolReserved);
vma.name.copy(info->name.data(), std::min(info->name.size(), vma.name.size())); vma.name.copy(info->name.data(), std::min(info->name.size(), vma.name.size()));
if (vma.type == VMAType::Direct) { if (vma.type == VMAType::Direct) {
const auto dmem_it = FindDmemArea(vma.phys_base); const auto dmem_it = FindDmemArea(vma.phys_base);

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" viewBox="0 0 200 200" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient id="linearGradient1"><stop stop-color="#0b034f" offset="0"/><stop stop-color="#4461f2" offset="1"/></linearGradient><linearGradient id="linearGradient2" x1="100" x2="100" y1="185.84" y2="14.157" gradientUnits="userSpaceOnUse" xlink:href="#linearGradient1"/><mask id="mask9" maskUnits="userSpaceOnUse"><path d="m-4.1597 120.43 65.304 22.774-20.899 59.926-65.304-22.774z" fill="none" stroke="#149ffb" stroke-linecap="square" stroke-width="11" style="paint-order:markers fill stroke"/></mask><mask id="mask10" maskUnits="userSpaceOnUse"><path d="m178.79 52.448-45.404 19.386 5.9135-49.014z" fill="none" stroke="#149ffb" stroke-linecap="square" stroke-width="6.75" style="paint-order:markers fill stroke"/></mask></defs><path d="m48.678 14.157h102.64c19.124 0 34.521 15.396 34.521 34.521v102.64c0 19.124-15.396 34.521-34.521 34.521h-102.64c-19.124 0-34.521-15.396-34.521-34.521v-102.64c0-19.124 15.396-34.521 34.521-34.521z" fill="url(#linearGradient2)" stroke="#fff" stroke-linecap="square" stroke-linejoin="round" stroke-width="5" style="paint-order:markers fill stroke"/><path d="m48.678 14.157h102.64c19.124 0 34.521 15.396 34.521 34.521v102.64c0 19.124-15.396 34.521-34.521 34.521h-102.64c-19.124 0-34.521-15.396-34.521-34.521v-102.64c0-19.124 15.396-34.521 34.521-34.521z" fill="url(#linearGradient2)" stroke="#fff" stroke-linecap="square" stroke-linejoin="round" stroke-width="5" style="paint-order:markers fill stroke"/><path d="m50.17 16.403h99.848c18.603 0 33.58 14.977 33.58 33.58v99.848c0 18.603-14.977 33.58-33.58 33.58h-99.848c-18.603 0-33.58-14.977-33.58-33.58v-99.848c0-18.603 14.977-33.58 33.58-33.58z" fill="#0ff" mask="url(#mask9)" style="paint-order:markers fill stroke"/><path d="m50.076 16.496h99.848c18.603 0 33.58 14.977 33.58 33.58v99.848c0 18.603-14.977 33.58-33.58 33.58h-99.848c-18.603 0-33.58-14.977-33.58-33.58v-99.848c0-18.603 14.977-33.58 33.58-33.58z" fill="#0ff" mask="url(#mask10)" style="paint-order:markers fill stroke"/><g fill="none"><path transform="matrix(.91041 .0063593 -.0063593 .91041 28.548 42.178)" d="m166.13 88.68-23.677 14.288 13.949 23.879-14.288-23.677-23.879 13.949 23.677-14.288-13.949-23.879 14.288 23.677z" stroke="#139ffb" stroke-linecap="square" stroke-width="12.43" style="paint-order:markers fill stroke"/><path d="m117.98 135.88v-88.282l-65.093 69.568h83.807" stroke="#fff" stroke-linecap="square" stroke-linejoin="round" stroke-width="10" style="font-variation-settings:normal;paint-order:markers fill stroke"/><path d="m69.923 56.468a20.994 21.009 0 01-20.911 21.009 20.994 21.009 0 01-21.076-20.843 20.994 21.009 0 0120.744-21.174 20.994 21.009 0 0121.24 20.675" stop-color="#000000" stroke="#139ffb" stroke-linecap="round" stroke-width="9.4488" style="paint-order:markers fill stroke"/></g></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -11,6 +11,7 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#if defined(__APPLE__) #if defined(__APPLE__)
#include <TargetConditionals.h> #include <TargetConditionals.h>
#include <dispatch/dispatch.h>
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
@ -71,7 +72,14 @@ static void PlatformSetImeData(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlat
auto window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle; auto window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle;
SDL_Window* window = SDL_GetWindowFromID(window_id); SDL_Window* window = SDL_GetWindowFromID(window_id);
if ((!data->WantVisible || bd->ime_window != window) && bd->ime_window != nullptr) { if ((!data->WantVisible || bd->ime_window != window) && bd->ime_window != nullptr) {
SDL_StopTextInput(bd->ime_window); auto stop_input = [&bd] { SDL_StopTextInput(bd->ime_window); };
#ifdef __APPLE__
dispatch_sync(dispatch_get_main_queue(), ^{
stop_input();
});
#else
stop_input();
#endif
bd->ime_window = nullptr; bd->ime_window = nullptr;
} }
if (data->WantVisible) { if (data->WantVisible) {
@ -80,8 +88,17 @@ static void PlatformSetImeData(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlat
r.y = (int)data->InputPos.y; r.y = (int)data->InputPos.y;
r.w = 1; r.w = 1;
r.h = (int)data->InputLineHeight; r.h = (int)data->InputLineHeight;
const auto start_input = [&window, &r] {
SDL_SetTextInputArea(window, &r, 0); SDL_SetTextInputArea(window, &r, 0);
SDL_StartTextInput(window); SDL_StartTextInput(window);
};
#ifdef __APPLE__
dispatch_sync(dispatch_get_main_queue(), ^{
start_input();
});
#else
start_input();
#endif
bd->ime_window = window; bd->ime_window = window;
} }
} }

View File

@ -31,7 +31,7 @@ QStringList languageNames = {"Arabic",
"Italian", "Italian",
"Japanese", "Japanese",
"Korean", "Korean",
"Norwegian", "Norwegian (Bokmaal)",
"Polish", "Polish",
"Portuguese (Brazil)", "Portuguese (Brazil)",
"Portuguese (Portugal)", "Portuguese (Portugal)",

View File

@ -62,7 +62,7 @@
<message> <message>
<location filename="../install_dir_select.cpp" line="37"/> <location filename="../install_dir_select.cpp" line="37"/>
<source>Select which directory you want to install to.</source> <source>Select which directory you want to install to.</source>
<translation>Select which directory you want to install to.</translation> <translation>Válassza ki a mappát a játékok telepítésére.</translation>
</message> </message>
</context> </context>
<context> <context>
@ -90,7 +90,7 @@
<message> <message>
<location filename="../game_install_dialog.cpp" line="75"/> <location filename="../game_install_dialog.cpp" line="75"/>
<source>The value for location to install games is not valid.</source> <source>The value for location to install games is not valid.</source>
<translation>A játékok telepítéséhez megadott érték nem érvényes.</translation> <translation>A játékok telepítéséhez megadott útvonal nem érvényes.</translation>
</message> </message>
</context> </context>
<context> <context>
@ -108,7 +108,7 @@
<message> <message>
<location filename="../gui_context_menus.h" line="41"/> <location filename="../gui_context_menus.h" line="41"/>
<source>SFO Viewer</source> <source>SFO Viewer</source>
<translation>SFO Néző</translation> <translation>SFO Nézegető</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="42"/> <location filename="../gui_context_menus.h" line="42"/>
@ -158,22 +158,22 @@
<message> <message>
<location filename="../gui_context_menus.h" line="72"/> <location filename="../gui_context_menus.h" line="72"/>
<source>Delete...</source> <source>Delete...</source>
<translation>Delete...</translation> <translation>Törlés...</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="73"/> <location filename="../gui_context_menus.h" line="73"/>
<source>Delete Game</source> <source>Delete Game</source>
<translation>Delete Game</translation> <translation>Játék törlése</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="74"/> <location filename="../gui_context_menus.h" line="74"/>
<source>Delete Update</source> <source>Delete Update</source>
<translation>Delete Update</translation> <translation>Frissítések törlése</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="75"/> <location filename="../gui_context_menus.h" line="75"/>
<source>Delete DLC</source> <source>Delete DLC</source>
<translation>Delete DLC</translation> <translation>DLC-k törlése</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="173"/> <location filename="../gui_context_menus.h" line="173"/>
@ -203,27 +203,27 @@
<message> <message>
<location filename="../gui_context_menus.h" line="299"/> <location filename="../gui_context_menus.h" line="299"/>
<source>Game</source> <source>Game</source>
<translation>Game</translation> <translation>Játék</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="305"/> <location filename="../gui_context_menus.h" line="305"/>
<source>requiresEnableSeparateUpdateFolder_MSG</source> <source>requiresEnableSeparateUpdateFolder_MSG</source>
<translation>This feature requires the 'Enable Separate Update Folder' config option to work. If you want to use this feature, please enable it.</translation> <translation>Ehhez a funkcióhoz szükséges a 'Külön Frissítési Mappa Engedélyezése' opció, hogy működjön. Ha használni akarja, először engedélyezze azt.</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="312"/> <location filename="../gui_context_menus.h" line="312"/>
<source>This game has no update to delete!</source> <source>This game has no update to delete!</source>
<translation>This game has no update to delete!</translation> <translation>Ehhez a játékhoz nem tartozik törlendő frissítés!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="316"/> <location filename="../gui_context_menus.h" line="316"/>
<source>Update</source> <source>Update</source>
<translation>Update</translation> <translation>Frissítés</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="321"/> <location filename="../gui_context_menus.h" line="321"/>
<source>This game has no DLC to delete!</source> <source>This game has no DLC to delete!</source>
<translation>This game has no DLC to delete!</translation> <translation>Ehhez a játékhoz nem tartozik törlendő DLC!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="325"/> <location filename="../gui_context_menus.h" line="325"/>
@ -238,7 +238,7 @@
<message> <message>
<location filename="../gui_context_menus.h" line="333"/> <location filename="../gui_context_menus.h" line="333"/>
<source>Are you sure you want to delete %1's %2 directory?</source> <source>Are you sure you want to delete %1's %2 directory?</source>
<translation>Are you sure you want to delete %1's %2 directory?</translation> <translation>Biztosan törölni akarja a %1's %2 mappát?</translation>
</message> </message>
</context> </context>
<context> <context>
@ -246,7 +246,7 @@
<message> <message>
<location filename="../main_window_ui.h" line="310"/> <location filename="../main_window_ui.h" line="310"/>
<source>Open/Add Elf Folder</source> <source>Open/Add Elf Folder</source>
<translation>Efl Mappa Megnyitása/Hozzáadása</translation> <translation>ELF Mappa Megnyitása/Hozzáadása</translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="312"/> <location filename="../main_window_ui.h" line="312"/>
@ -256,7 +256,7 @@
<message> <message>
<location filename="../main_window_ui.h" line="313"/> <location filename="../main_window_ui.h" line="313"/>
<source>Boot Game</source> <source>Boot Game</source>
<translation>Játék Bootolása</translation> <translation>Játék Indítása</translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="308"/> <location filename="../main_window_ui.h" line="308"/>
@ -291,12 +291,12 @@
<message> <message>
<location filename="../main_window_ui.h" line="323"/> <location filename="../main_window_ui.h" line="323"/>
<source>Exit shadPS4</source> <source>Exit shadPS4</source>
<translation>Kilépés a shadPS4</translation> <translation>Kilépés a shadPS4-ből</translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="327"/> <location filename="../main_window_ui.h" line="327"/>
<source>Exit the application.</source> <source>Exit the application.</source>
<translation>Lépjen ki az programból.</translation> <translation>Lépjen ki a programból.</translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="330"/> <location filename="../main_window_ui.h" line="330"/>
@ -341,7 +341,7 @@
<message> <message>
<location filename="../main_window_ui.h" line="341"/> <location filename="../main_window_ui.h" line="341"/>
<source>Elf Viewer</source> <source>Elf Viewer</source>
<translation>Elf Néző</translation> <translation>Elf Nézegető</translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="343"/> <location filename="../main_window_ui.h" line="343"/>
@ -356,12 +356,12 @@
<message> <message>
<location filename="../main_window_ui.h" line="345"/> <location filename="../main_window_ui.h" line="345"/>
<source>Dump Game List</source> <source>Dump Game List</source>
<translation>Játék Lista Dumpolása</translation> <translation>Játéklista Dumpolása</translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="346"/> <location filename="../main_window_ui.h" line="346"/>
<source>PKG Viewer</source> <source>PKG Viewer</source>
<translation>PKG Néző</translation> <translation>PKG Nézegető</translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="348"/> <location filename="../main_window_ui.h" line="348"/>
@ -376,17 +376,17 @@
<message> <message>
<location filename="../main_window_ui.h" line="350"/> <location filename="../main_window_ui.h" line="350"/>
<source>View</source> <source>View</source>
<translation>Megnézés</translation> <translation>Nézet</translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="352"/> <location filename="../main_window_ui.h" line="352"/>
<source>Game List Icons</source> <source>Game List Icons</source>
<translation>Játék Könyvtár Ikonok</translation> <translation>Játékkönyvtár Ikonok</translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="354"/> <location filename="../main_window_ui.h" line="354"/>
<source>Game List Mode</source> <source>Game List Mode</source>
<translation>Játék Könyvtár Mód</translation> <translation>Játékkönyvtár Nézet</translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="355"/> <location filename="../main_window_ui.h" line="355"/>
@ -490,12 +490,12 @@
<message> <message>
<location filename="../settings_dialog.ui" line="122"/> <location filename="../settings_dialog.ui" line="122"/>
<source>Enable Fullscreen</source> <source>Enable Fullscreen</source>
<translation>Teljesképernyő Engedélyezése</translation> <translation>Teljes Képernyő Engedélyezése</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="140"/> <location filename="../settings_dialog.ui" line="140"/>
<source>Enable Separate Update Folder</source> <source>Enable Separate Update Folder</source>
<translation>Enable Separate Update Folder</translation> <translation>Külön Frissítési Mappa Engedélyezése</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="129"/> <location filename="../settings_dialog.ui" line="129"/>
@ -505,12 +505,12 @@
<message> <message>
<location filename="../settings_dialog.ui" line="136"/> <location filename="../settings_dialog.ui" line="136"/>
<source>Is PS4 Pro</source> <source>Is PS4 Pro</source>
<translation>PS4 Pro</translation> <translation>PS4 Pro mód</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="154"/> <location filename="../settings_dialog.ui" line="154"/>
<source>Enable Discord Rich Presence</source> <source>Enable Discord Rich Presence</source>
<translation>Engedélyezze a Discord Rich Presence-t</translation> <translation>A Discord Rich Presence engedélyezése</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="155"/> <location filename="../settings_dialog.ui" line="155"/>
@ -560,7 +560,7 @@
<message> <message>
<location filename="../settings_dialog.ui" line="797"/> <location filename="../settings_dialog.ui" line="797"/>
<source>Back Button Behavior</source> <source>Back Button Behavior</source>
<translation>Vissza gomb viselkedése</translation> <translation>Vissza gomb Viselkedése</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="272"/> <location filename="../settings_dialog.ui" line="272"/>
@ -693,17 +693,17 @@
<message> <message>
<location filename="../main_window.cpp" line="168"/> <location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source> <source> * Unsupported Vulkan Version</source>
<translation> * Támogatott Vulkan verzió hiányzik</translation> <translation> * Nem támogatott Vulkan verzió</translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="326"/> <location filename="../main_window.cpp" line="326"/>
<source>Download Cheats For All Installed Games</source> <source>Download Cheats For All Installed Games</source>
<translation>Letöltés csalások minden telepített játékhoz</translation> <translation>Csalások letöltése minden telepített játékhoz</translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="328"/> <location filename="../main_window.cpp" line="328"/>
<source>Download Patches For All Games</source> <source>Download Patches For All Games</source>
<translation>Frissítések letöltése minden játékhoz</translation> <translation>Javítások letöltése minden játékhoz</translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="363"/> <location filename="../main_window.cpp" line="363"/>
@ -713,17 +713,17 @@
<message> <message>
<location filename="../main_window.cpp" line="364"/> <location filename="../main_window.cpp" line="364"/>
<source>You have downloaded cheats for all the games you have installed.</source> <source>You have downloaded cheats for all the games you have installed.</source>
<translation>Csalásokat töltöttél le az összes telepített játékhoz.</translation> <translation>Minden elérhető csalás letöltődött az összes telepített játékhoz.</translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="391"/> <location filename="../main_window.cpp" line="391"/>
<source>Patches Downloaded Successfully!</source> <source>Patches Downloaded Successfully!</source>
<translation>Frissítések sikeresen letöltve!</translation> <translation>Javítások sikeresen letöltve!</translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="392"/> <location filename="../main_window.cpp" line="392"/>
<source>All Patches available for all games have been downloaded.</source> <source>All Patches available for all games have been downloaded.</source>
<translation>Az összes játékhoz elérhető frissítés letöltésre került.</translation> <translation>Az összes játékhoz elérhető javítás letöltésre került.</translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="549"/> <location filename="../main_window.cpp" line="549"/>
@ -773,7 +773,7 @@
<message> <message>
<location filename="../main_window.cpp" line="639"/> <location filename="../main_window.cpp" line="639"/>
<source>PKG Version %1 is older than installed version: </source> <source>PKG Version %1 is older than installed version: </source>
<translation>A %1-es PKG verzió régebbi, mint a telepített verzió: </translation> <translation>A(z) %1-es PKG verzió régebbi, mint a telepített verzió: </translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="660"/> <location filename="../main_window.cpp" line="660"/>
@ -793,7 +793,7 @@
<message> <message>
<location filename="../main_window.cpp" line="674"/> <location filename="../main_window.cpp" line="674"/>
<source>Would you like to install DLC: %1?</source> <source>Would you like to install DLC: %1?</source>
<translation>Szeretné telepíteni a DLC-t: %1?</translation> <translation>Szeretné telepíteni a %1 DLC-t?</translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="688"/> <location filename="../main_window.cpp" line="688"/>
@ -846,7 +846,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="50"/> <location filename="../cheats_patches.cpp" line="50"/>
<source>defaultTextEdit_MSG</source> <source>defaultTextEdit_MSG</source>
<translation>A csalások/patchek kísérleti jellegűek.\nHasználja őket óvatosan.\n\nTöltse le a csalásokat egyesével a repository kiválasztásával és a letöltés gombra kattintással.\nA Patches fül alatt egyszerre letöltheti az összes patchet, választhat, melyeket szeretné használni, és elmentheti a választását.\n\nMivel nem fejlesztjük a csalásokat/patch-eket,\nkérjük, jelentse a problémákat a csalás szerzőjének.\n\nKészített egy új csalást? Látogasson el ide:\nhttps://github.com/shadps4-emu/ps4_cheats</translation> <translation>A csalások/javítások kísérleti jellegűek.\nHasználja őket óvatosan.\n\nTöltse le a csalásokat egyesével a tároló kiválasztásával és a letöltés gombra kattintással.\nA Javítások fül alatt egyszerre letöltheti az összes javítást, majd választhat, melyeket szeretné használni, és elmentheti a választását.\n\nMivel nem mi fejlesztjük a csalásokat/patch-eket,\nkérjük, jelentse a problémákat a csalás szerzőjének.\n\nKészített egy új csalást? Látogasson el ide:\nhttps://github.com/shadps4-emu/ps4_cheats</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="69"/> <location filename="../cheats_patches.cpp" line="69"/>
@ -1011,7 +1011,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="556"/> <location filename="../cheats_patches.cpp" line="556"/>
<source>CheatsNotFound_MSG</source> <source>CheatsNotFound_MSG</source>
<translation>Nincs található csalás ezen a játékverzión ebben a kiválasztott tárolóban,próbálj meg egy másik tárolót vagy a játék egy másik verzióját.</translation> <translation>Nincs található csalás ezen a játékverzión ebben a kiválasztott tárolóban, próbálj meg egy másik tárolót vagy a játék egy másik verzióját.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="593"/> <location filename="../cheats_patches.cpp" line="593"/>
@ -1041,7 +1041,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <source>DownloadComplete_MSG</source>
<translation>Frissítések sikeresen letöltve! Minden elérhető frissítés letöltésre került, nem szükséges egyesével letölteni őket minden játékhoz, mint a csalások esetében. Ha a javítás nem jelenik meg, lehet, hogy nem létezik a játék adott sorozatszámához és verziójához.</translation> <translation>Frissítések sikeresen letöltve! Minden elérhető frissítés letöltésre került, nem szükséges egyesével letölteni őket minden játékhoz, mint a csalások esetében. Ha a javítások nem jelennek meg, lehet, hogy nem léteznek a játék adott sorozatszámához és verziójához.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1061,7 +1061,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="851"/> <location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source> <source>The downloaded patch only works on version: %1</source>
<translation>A letöltött javítás csak a(z) %1 verzión működik</translation> <translation>A letöltött javításhoz a(z) %1 verzió működik</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="856"/> <location filename="../cheats_patches.cpp" line="856"/>
@ -1096,7 +1096,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="997"/> <location filename="../cheats_patches.cpp" line="997"/>
<source>Directory does not exist:</source> <source>Directory does not exist:</source>
<translation>A könyvtár nem létezik:</translation> <translation>A mappa nem létezik:</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="1006"/> <location filename="../cheats_patches.cpp" line="1006"/>
@ -1159,22 +1159,22 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="293"/> <location filename="../settings_dialog.cpp" line="293"/>
<source>separateUpdatesCheckBox</source> <source>separateUpdatesCheckBox</source>
<translation>Enable Separate Update Folder:\nEnables installing game updates into a separate folder for easy management.</translation> <translation>Külön Frissítéi Mappa Engedélyezése:\nEngedélyezi a frissítések külön mappába helyezését, a könnyű kezelésük érdekében.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="295"/> <location filename="../settings_dialog.cpp" line="295"/>
<source>showSplashCheckBox</source> <source>showSplashCheckBox</source>
<translation>Indító képernyő megjelenítése:\nMegjeleníti a játék indító képernyőjét (különleges képet) a játék elindításakor.</translation> <translation>Indítóképernyő megjelenítése:\nMegjeleníti a játék indítóképernyőjét (különleges képet) a játék elindításakor.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="297"/> <location filename="../settings_dialog.cpp" line="297"/>
<source>ps4proCheckBox</source> <source>ps4proCheckBox</source>
<translation>PS4 Pro:\nAz emulátort PS4 PRO-ként kezeli, ami engedélyezheti a speciális funkciókat olyan játékokban, amelyek támogatják.</translation> <translation>PS4 Pro:\nAz emulátort PS4 PRO-ként kezeli, ami engedélyezhet speciális funkciókat olyan játékokban, amelyek támogatják azt.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="438"/> <location filename="../settings_dialog.cpp" line="438"/>
<source>discordRPCCheckbox</source> <source>discordRPCCheckbox</source>
<translation>Engedélyezze a Discord Rich Presence-t:\nMegjeleníti az emulator ikonját és a kapcsolódó információkat a Discord profilján.</translation> <translation>A Discord Rich Presence engedélyezése:\nMegjeleníti az emulator ikonját és a kapcsolódó információkat a Discord profilján.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="299"/> <location filename="../settings_dialog.cpp" line="299"/>
@ -1199,17 +1199,17 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="306"/> <location filename="../settings_dialog.cpp" line="306"/>
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Játék címzene lejátszása:\nHa a játék támogatja, engedélyezze a speciális zene lejátszását, amikor a játékot kiválasztja a GUI-ban.</translation> <translation>Játék címzene lejátszása:\nHa a játék támogatja, engedélyezze egy speciális zene lejátszását, amikor a játékot kiválasztja a GUI-ban.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
<translation>Akurátor elrejtése:\nVálassza ki, mikor tűnjön el az egérkurzor:\nSoha: Az egér mindig látható.\nInaktív: Állítson be egy időt, amikor inaktív állapotban eltűnik.\nMindig: soha nem látja az egeret.</translation> <translation>Kurzor elrejtése:\nVálassza ki, mikor tűnjön el az egérmutató:\nSoha: Az egér mindig látható.\nInaktív: Állítson be egy időt, amennyi idő mozdulatlanság után eltűnik.\nMindig: az egér mindig el lesz rejtve.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="452"/> <location filename="../settings_dialog.cpp" line="452"/>
<source>idleTimeoutGroupBox</source> <source>idleTimeoutGroupBox</source>
<translation>Állítson be egy időt, ameddig az egér inaktív állapot után eltűnik.</translation> <translation>Állítson be egy időt, ami után egér inaktív állapotban eltűnik.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="454"/> <location filename="../settings_dialog.cpp" line="454"/>
@ -1234,17 +1234,17 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="101"/> <location filename="../settings_dialog.cpp" line="101"/>
<source>Touchpad Left</source> <source>Touchpad Left</source>
<translation>Érintőpad Balra</translation> <translation>Érintőpad Bal</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="102"/> <location filename="../settings_dialog.cpp" line="102"/>
<source>Touchpad Right</source> <source>Touchpad Right</source>
<translation>Érintőpad Jobbra</translation> <translation>Érintőpad Jobb</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="103"/> <location filename="../settings_dialog.cpp" line="103"/>
<source>Touchpad Center</source> <source>Touchpad Center</source>
<translation>Érintőpad Középen</translation> <translation>Érintőpad Közép</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="104"/> <location filename="../settings_dialog.cpp" line="104"/>
@ -1254,7 +1254,7 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="312"/> <location filename="../settings_dialog.cpp" line="312"/>
<source>graphicsAdapterGroupBox</source> <source>graphicsAdapterGroupBox</source>
<translation>Grafikus eszköz:\nTöbb GPU-s rendszereken válassza ki a GPU-t, amelyet az emulátor használ a legördülő listából,\nvagy válassza az "Auto Select" lehetőséget, hogy automatikusan meghatározza azt.</translation> <translation>Grafikus eszköz:\nTöbb GPU-s rendszereken válassza ki, melyik GPU-t használja az emulátor a legördülő listából,\nvagy válassza az "Auto Select" lehetőséget, hogy automatikusan kiválassza azt.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="314"/> <location filename="../settings_dialog.cpp" line="314"/>
@ -1264,7 +1264,7 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="318"/> <location filename="../settings_dialog.cpp" line="318"/>
<source>heightDivider</source> <source>heightDivider</source>
<translation>Vblank osztó:\nAz emulátor frissítési sebessége e számot megszorozva működik. Ennek megváltoztatása kedvezőtlen hatásokat okozhat, például növelheti a játék sebességét, vagy megszakíthat kritikus játékfunkciókat, amelyek nem számítanak arra, hogy ez megváltozik!</translation> <translation>Vblank elosztó:\nAz emulátor frissítési sebessége e számot megszorozva működik. Ennek megváltoztatása kedvezőtlen hatásokat okozhat, például növelheti a játék sebességét, vagy megszakíthat kritikus játékfunkciókat, amelyek nem számítanak arra, hogy ez megváltozik!</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="320"/> <location filename="../settings_dialog.cpp" line="320"/>
@ -1279,7 +1279,7 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="465"/> <location filename="../settings_dialog.cpp" line="465"/>
<source>gameFoldersBox</source> <source>gameFoldersBox</source>
<translation>Játék mappák:\nA mappák listája az telepített játékok ellenőrzésére.</translation> <translation>Játék mappák:\nA mappák listája, ahol telepített játékok vannak.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="465"/> <location filename="../settings_dialog.cpp" line="465"/>
@ -1420,7 +1420,7 @@
<message> <message>
<location filename="../check_update.cpp" line="178"/> <location filename="../check_update.cpp" line="178"/>
<source>Latest Version</source> <source>Latest Version</source>
<translation>Legújabb verzió</translation> <translation>Új verzió</translation>
</message> </message>
<message> <message>
<location filename="../check_update.cpp" line="179"/> <location filename="../check_update.cpp" line="179"/>
@ -1430,7 +1430,7 @@
<message> <message>
<location filename="../check_update.cpp" line="193"/> <location filename="../check_update.cpp" line="193"/>
<source>Show Changelog</source> <source>Show Changelog</source>
<translation>Módosítások megjelenítése</translation> <translation>Változások megjelenítése</translation>
</message> </message>
<message> <message>
<location filename="../check_update.cpp" line="198"/> <location filename="../check_update.cpp" line="198"/>
@ -1445,17 +1445,17 @@
<message> <message>
<location filename="../check_update.cpp" line="200"/> <location filename="../check_update.cpp" line="200"/>
<source>No</source> <source>No</source>
<translation>Nem</translation> <translation>Mégse</translation>
</message> </message>
<message> <message>
<location filename="../check_update.cpp" line="223"/> <location filename="../check_update.cpp" line="223"/>
<source>Hide Changelog</source> <source>Hide Changelog</source>
<translation>Módosítások elrejtése</translation> <translation>Változások elrejtése</translation>
</message> </message>
<message> <message>
<location filename="../check_update.cpp" line="296"/> <location filename="../check_update.cpp" line="296"/>
<source>Changes</source> <source>Changes</source>
<translation>Módosítások</translation> <translation>Változások</translation>
</message> </message>
<message> <message>
<location filename="../check_update.cpp" line="310"/> <location filename="../check_update.cpp" line="310"/>

View File

@ -690,9 +690,9 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip
IR::Inst* body = inst.Arg(1).InstRecursive(); IR::Inst* body = inst.Arg(1).InstRecursive();
const auto [coords, arg] = [&] -> std::pair<IR::Value, IR::Value> { const auto [coords, arg] = [&] -> std::pair<IR::Value, IR::Value> {
switch (image.GetType()) { switch (image.GetType()) {
case AmdGpu::ImageType::Color1D: // x case AmdGpu::ImageType::Color1D: // x, [lod]
return {body->Arg(0), body->Arg(1)}; return {body->Arg(0), body->Arg(1)};
case AmdGpu::ImageType::Color1DArray: // x, slice case AmdGpu::ImageType::Color1DArray: // x, slice, [lod]
[[fallthrough]]; [[fallthrough]];
case AmdGpu::ImageType::Color2D: // x, y, [lod] case AmdGpu::ImageType::Color2D: // x, y, [lod]
[[fallthrough]]; [[fallthrough]];
@ -703,9 +703,9 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip
case AmdGpu::ImageType::Color2DMsaaArray: // x, y, slice. (sample is passed on different case AmdGpu::ImageType::Color2DMsaaArray: // x, y, slice. (sample is passed on different
// argument) // argument)
[[fallthrough]]; [[fallthrough]];
case AmdGpu::ImageType::Color3D: // x, y, z case AmdGpu::ImageType::Color3D: // x, y, z, [lod]
return {ir.CompositeConstruct(body->Arg(0), body->Arg(1), body->Arg(2)), body->Arg(3)}; return {ir.CompositeConstruct(body->Arg(0), body->Arg(1), body->Arg(2)), body->Arg(3)};
case AmdGpu::ImageType::Cube: // x, y, face case AmdGpu::ImageType::Cube: // x, y, face, [lod]
return {PatchCubeCoord(ir, body->Arg(0), body->Arg(1), body->Arg(2), is_storage, return {PatchCubeCoord(ir, body->Arg(0), body->Arg(1), body->Arg(2), is_storage,
inst_info.is_array), inst_info.is_array),
body->Arg(3)}; body->Arg(3)};
@ -717,8 +717,8 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip
if (inst_info.has_lod) { if (inst_info.has_lod) {
ASSERT(inst.GetOpcode() == IR::Opcode::ImageFetch); ASSERT(inst.GetOpcode() == IR::Opcode::ImageFetch);
ASSERT(image.GetType() == AmdGpu::ImageType::Color2D || ASSERT(image.GetType() != AmdGpu::ImageType::Color2DMsaa &&
image.GetType() == AmdGpu::ImageType::Color2DArray); image.GetType() != AmdGpu::ImageType::Color2DMsaaArray);
inst.SetArg(3, arg); inst.SetArg(3, arg);
} else if (image.GetType() == AmdGpu::ImageType::Color2DMsaa || } else if (image.GetType() == AmdGpu::ImageType::Color2DMsaa ||
image.GetType() == AmdGpu::ImageType::Color2DMsaaArray) { image.GetType() == AmdGpu::ImageType::Color2DMsaaArray) {

View File

@ -393,14 +393,12 @@ void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) {
if (regs.depth_control.depth_bounds_enable) { if (regs.depth_control.depth_bounds_enable) {
cmdbuf.setDepthBounds(regs.depth_bounds_min, regs.depth_bounds_max); cmdbuf.setDepthBounds(regs.depth_bounds_min, regs.depth_bounds_max);
} }
if (regs.polygon_control.NeedsBias()) {
if (regs.polygon_control.enable_polygon_offset_front) { if (regs.polygon_control.enable_polygon_offset_front) {
cmdbuf.setDepthBias(regs.poly_offset.front_offset, regs.poly_offset.depth_bias, cmdbuf.setDepthBias(regs.poly_offset.front_offset, regs.poly_offset.depth_bias,
regs.poly_offset.front_scale); regs.poly_offset.front_scale / 16.f);
} else { } else if (regs.polygon_control.enable_polygon_offset_back) {
cmdbuf.setDepthBias(regs.poly_offset.back_offset, regs.poly_offset.depth_bias, cmdbuf.setDepthBias(regs.poly_offset.back_offset, regs.poly_offset.depth_bias,
regs.poly_offset.back_scale); regs.poly_offset.back_scale / 16.f);
}
} }
if (regs.depth_control.stencil_enable) { if (regs.depth_control.stencil_enable) {
const auto front = regs.stencil_ref_front; const auto front = regs.stencil_ref_front;