mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-28 04:54:30 +00:00
Merge branch 'main' into net3
This commit is contained in:
commit
d6758d0662
0
CMakeLists.txt
Executable file → Normal file
0
CMakeLists.txt
Executable file → Normal file
@ -131,9 +131,7 @@ namespace {
|
|||||||
case SeekOrigin::End:
|
case SeekOrigin::End:
|
||||||
return SEEK_END;
|
return SEEK_END;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR(Common_Filesystem, "Unsupported origin {}, defaulting to SEEK_SET",
|
UNREACHABLE_MSG("Impossible SeekOrigin {}", static_cast<u32>(origin));
|
||||||
static_cast<u32>(origin));
|
|
||||||
return SEEK_SET;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,8 +61,6 @@ enum class SeekOrigin : u32 {
|
|||||||
SetOrigin, // Seeks from the start of the file.
|
SetOrigin, // Seeks from the start of the file.
|
||||||
CurrentPosition, // Seeks from the current file pointer position.
|
CurrentPosition, // Seeks from the current file pointer position.
|
||||||
End, // Seeks from the end of the file.
|
End, // Seeks from the end of the file.
|
||||||
SeekHole, // Seeks from the start of the next hole in the file.
|
|
||||||
SeekData, // Seeks from the start of the next non-hole region in the file.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class IOFile final {
|
class IOFile final {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "random_device.h"
|
#include "random_device.h"
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "srandom_device.h"
|
#include "srandom_device.h"
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "urandom_device.h"
|
#include "urandom_device.h"
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <ctime>
|
||||||
#include <fmt/chrono.h>
|
#include <fmt/chrono.h>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <magic_enum/magic_enum.hpp>
|
#include <magic_enum/magic_enum.hpp>
|
||||||
|
@ -67,10 +67,16 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
|
|||||||
bool write = (flags & 0x3) == ORBIS_KERNEL_O_WRONLY;
|
bool write = (flags & 0x3) == ORBIS_KERNEL_O_WRONLY;
|
||||||
bool rdwr = (flags & 0x3) == ORBIS_KERNEL_O_RDWR;
|
bool rdwr = (flags & 0x3) == ORBIS_KERNEL_O_RDWR;
|
||||||
|
|
||||||
|
if (!read && !write && !rdwr) {
|
||||||
|
// Start by checking for invalid flags.
|
||||||
|
*__Error() = POSIX_EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
bool nonblock = (flags & ORBIS_KERNEL_O_NONBLOCK) != 0;
|
bool nonblock = (flags & ORBIS_KERNEL_O_NONBLOCK) != 0;
|
||||||
bool append = (flags & ORBIS_KERNEL_O_APPEND) != 0;
|
bool append = (flags & ORBIS_KERNEL_O_APPEND) != 0;
|
||||||
bool fsync = (flags & ORBIS_KERNEL_O_FSYNC) != 0;
|
// Flags fsync and sync behave the same
|
||||||
bool sync = (flags & ORBIS_KERNEL_O_SYNC) != 0;
|
bool sync = (flags & ORBIS_KERNEL_O_SYNC) != 0 || (flags & ORBIS_KERNEL_O_FSYNC) != 0;
|
||||||
bool create = (flags & ORBIS_KERNEL_O_CREAT) != 0;
|
bool create = (flags & ORBIS_KERNEL_O_CREAT) != 0;
|
||||||
bool truncate = (flags & ORBIS_KERNEL_O_TRUNC) != 0;
|
bool truncate = (flags & ORBIS_KERNEL_O_TRUNC) != 0;
|
||||||
bool excl = (flags & ORBIS_KERNEL_O_EXCL) != 0;
|
bool excl = (flags & ORBIS_KERNEL_O_EXCL) != 0;
|
||||||
@ -78,6 +84,10 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
|
|||||||
bool direct = (flags & ORBIS_KERNEL_O_DIRECT) != 0;
|
bool direct = (flags & ORBIS_KERNEL_O_DIRECT) != 0;
|
||||||
bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0;
|
bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0;
|
||||||
|
|
||||||
|
if (sync || direct || dsync || nonblock) {
|
||||||
|
LOG_WARNING(Kernel_Fs, "flags {:#x} not fully handled", flags);
|
||||||
|
}
|
||||||
|
|
||||||
std::string_view path{raw_path};
|
std::string_view path{raw_path};
|
||||||
u32 handle = h->CreateHandle();
|
u32 handle = h->CreateHandle();
|
||||||
auto* file = h->GetFile(handle);
|
auto* file = h->GetFile(handle);
|
||||||
@ -94,32 +104,11 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (directory) {
|
bool read_only = false;
|
||||||
file->type = Core::FileSys::FileType::Directory;
|
|
||||||
file->m_guest_name = path;
|
file->m_guest_name = path;
|
||||||
file->m_host_name = mnt->GetHostPath(file->m_guest_name);
|
file->m_host_name = mnt->GetHostPath(file->m_guest_name, &read_only);
|
||||||
if (!std::filesystem::is_directory(file->m_host_name)) { // directory doesn't exist
|
|
||||||
h->DeleteHandle(handle);
|
|
||||||
*__Error() = POSIX_ENOENT;
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
if (create) {
|
|
||||||
return handle; // dir already exists
|
|
||||||
} else {
|
|
||||||
mnt->IterateDirectory(file->m_guest_name,
|
|
||||||
[&file](const auto& ent_path, const auto ent_is_file) {
|
|
||||||
auto& dir_entry = file->dirents.emplace_back();
|
|
||||||
dir_entry.name = ent_path.filename().string();
|
|
||||||
dir_entry.isFile = ent_is_file;
|
|
||||||
});
|
|
||||||
file->dirents_index = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
file->m_guest_name = path;
|
|
||||||
file->m_host_name = mnt->GetHostPath(file->m_guest_name);
|
|
||||||
bool exists = std::filesystem::exists(file->m_host_name);
|
bool exists = std::filesystem::exists(file->m_host_name);
|
||||||
int e = 0;
|
s32 e = 0;
|
||||||
|
|
||||||
if (create) {
|
if (create) {
|
||||||
if (excl && exists) {
|
if (excl && exists) {
|
||||||
@ -128,50 +117,113 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
|
|||||||
*__Error() = POSIX_EEXIST;
|
*__Error() = POSIX_EEXIST;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// Create file if it doesn't exist
|
|
||||||
|
if (read_only) {
|
||||||
|
// Can't create files in a read only directory
|
||||||
|
h->DeleteHandle(handle);
|
||||||
|
*__Error() = POSIX_EROFS;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// Create a file if it doesn't exist
|
||||||
Common::FS::IOFile out(file->m_host_name, Common::FS::FileAccessMode::Write);
|
Common::FS::IOFile out(file->m_host_name, Common::FS::FileAccessMode::Write);
|
||||||
} else if (!exists) {
|
} else if (!exists) {
|
||||||
// File to open doesn't exist, return ENOENT
|
// If we're not creating a file, and it doesn't exist, return ENOENT
|
||||||
h->DeleteHandle(handle);
|
h->DeleteHandle(handle);
|
||||||
*__Error() = POSIX_ENOENT;
|
*__Error() = POSIX_ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read) {
|
if (std::filesystem::is_directory(file->m_host_name) || directory) {
|
||||||
// Read only
|
// Directories can be opened even if the directory flag isn't set.
|
||||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read);
|
// In these cases, error behavior is identical to the directory code path.
|
||||||
} else if (write) {
|
directory = true;
|
||||||
// Write only
|
|
||||||
if (append) {
|
|
||||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Append);
|
|
||||||
} else {
|
|
||||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Write);
|
|
||||||
}
|
}
|
||||||
} else if (rdwr) {
|
|
||||||
// Read and write
|
if (directory) {
|
||||||
if (append) {
|
if (!std::filesystem::is_directory(file->m_host_name)) {
|
||||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Append);
|
// If the opened file is not a directory, return ENOTDIR.
|
||||||
} else {
|
// This will trigger when create & directory is specified, this is expected.
|
||||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite);
|
h->DeleteHandle(handle);
|
||||||
}
|
*__Error() = POSIX_ENOTDIR;
|
||||||
} else {
|
|
||||||
// Invalid flags
|
|
||||||
*__Error() = POSIX_EINVAL;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (truncate && e == 0) {
|
file->type = Core::FileSys::FileType::Directory;
|
||||||
|
|
||||||
|
// Populate directory contents
|
||||||
|
mnt->IterateDirectory(file->m_guest_name,
|
||||||
|
[&file](const auto& ent_path, const auto ent_is_file) {
|
||||||
|
auto& dir_entry = file->dirents.emplace_back();
|
||||||
|
dir_entry.name = ent_path.filename().string();
|
||||||
|
dir_entry.isFile = ent_is_file;
|
||||||
|
});
|
||||||
|
file->dirents_index = 0;
|
||||||
|
|
||||||
|
if (read) {
|
||||||
|
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read);
|
||||||
|
} else if (write || rdwr) {
|
||||||
|
// Cannot open directories with any type of write access
|
||||||
|
h->DeleteHandle(handle);
|
||||||
|
*__Error() = POSIX_EISDIR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e == EACCES) {
|
||||||
|
// Hack to bypass some platform limitations, ignore the error and continue as normal.
|
||||||
|
LOG_WARNING(Kernel_Fs, "Opening directories is not fully supported on this platform");
|
||||||
|
e = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (truncate) {
|
||||||
|
// Cannot open directories with truncate
|
||||||
|
h->DeleteHandle(handle);
|
||||||
|
*__Error() = POSIX_EISDIR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Start by opening as read-write so we can truncate regardless of flags.
|
||||||
|
// Since open starts by closing the file, this won't interfere with later open calls.
|
||||||
|
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite);
|
||||||
|
|
||||||
|
file->type = Core::FileSys::FileType::Regular;
|
||||||
|
|
||||||
|
if (truncate && read_only) {
|
||||||
|
// Can't open files with truncate flag in a read only directory
|
||||||
|
h->DeleteHandle(handle);
|
||||||
|
*__Error() = POSIX_EROFS;
|
||||||
|
return -1;
|
||||||
|
} else if (truncate && e == 0) {
|
||||||
// If the file was opened successfully and truncate was enabled, reduce size to 0
|
// If the file was opened successfully and truncate was enabled, reduce size to 0
|
||||||
file->f.SetSize(0);
|
file->f.SetSize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (read) {
|
||||||
|
// Read only
|
||||||
|
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read);
|
||||||
|
} else if (read_only) {
|
||||||
|
// Can't open files with write/read-write access in a read only directory
|
||||||
|
h->DeleteHandle(handle);
|
||||||
|
*__Error() = POSIX_EROFS;
|
||||||
|
return -1;
|
||||||
|
} else if (append) {
|
||||||
|
// Append can be specified with rdwr or write, but we treat it as a separate mode.
|
||||||
|
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Append);
|
||||||
|
} else if (write) {
|
||||||
|
// Write only
|
||||||
|
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Write);
|
||||||
|
} else if (rdwr) {
|
||||||
|
// Read and write
|
||||||
|
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (e != 0) {
|
if (e != 0) {
|
||||||
// Open failed in platform-specific code, errno needs to be converted.
|
// Open failed in platform-specific code, errno needs to be converted.
|
||||||
h->DeleteHandle(handle);
|
h->DeleteHandle(handle);
|
||||||
SetPosixErrno(e);
|
SetPosixErrno(e);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
file->is_opened = true;
|
file->is_opened = true;
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
@ -365,10 +417,10 @@ s64 PS4_SYSV_ABI posix_lseek(s32 fd, s64 offset, s32 whence) {
|
|||||||
origin = Common::FS::SeekOrigin::CurrentPosition;
|
origin = Common::FS::SeekOrigin::CurrentPosition;
|
||||||
} else if (whence == 2) {
|
} else if (whence == 2) {
|
||||||
origin = Common::FS::SeekOrigin::End;
|
origin = Common::FS::SeekOrigin::End;
|
||||||
} else if (whence == 3) {
|
} else if (whence == 3 || whence == 4) {
|
||||||
origin = Common::FS::SeekOrigin::SeekHole;
|
// whence parameter belongs to an unsupported POSIX extension
|
||||||
} else if (whence == 4) {
|
*__Error() = POSIX_ENOTTY;
|
||||||
origin = Common::FS::SeekOrigin::SeekData;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
// whence parameter is invalid
|
// whence parameter is invalid
|
||||||
*__Error() = POSIX_EINVAL;
|
*__Error() = POSIX_EINVAL;
|
||||||
@ -486,13 +538,13 @@ s32 PS4_SYSV_ABI posix_rmdir(const char* path) {
|
|||||||
|
|
||||||
const std::filesystem::path dir_name = mnt->GetHostPath(path, &ro);
|
const std::filesystem::path dir_name = mnt->GetHostPath(path, &ro);
|
||||||
|
|
||||||
if (dir_name.empty() || !std::filesystem::is_directory(dir_name)) {
|
if (ro) {
|
||||||
*__Error() = POSIX_ENOTDIR;
|
*__Error() = POSIX_EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ro) {
|
if (dir_name.empty() || !std::filesystem::is_directory(dir_name)) {
|
||||||
*__Error() = POSIX_EROFS;
|
*__Error() = POSIX_ENOTDIR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,8 +575,7 @@ s32 PS4_SYSV_ABI sceKernelRmdir(const char* path) {
|
|||||||
s32 PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) {
|
s32 PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) {
|
||||||
LOG_INFO(Kernel_Fs, "(PARTIAL) path = {}", path);
|
LOG_INFO(Kernel_Fs, "(PARTIAL) path = {}", path);
|
||||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||||
bool ro = false;
|
const auto path_name = mnt->GetHostPath(path);
|
||||||
const auto path_name = mnt->GetHostPath(path, &ro);
|
|
||||||
std::memset(sb, 0, sizeof(OrbisKernelStat));
|
std::memset(sb, 0, sizeof(OrbisKernelStat));
|
||||||
const bool is_dir = std::filesystem::is_directory(path_name);
|
const bool is_dir = std::filesystem::is_directory(path_name);
|
||||||
const bool is_file = std::filesystem::is_regular_file(path_name);
|
const bool is_file = std::filesystem::is_regular_file(path_name);
|
||||||
@ -545,9 +596,6 @@ s32 PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) {
|
|||||||
sb->st_blocks = (sb->st_size + 511) / 512;
|
sb->st_blocks = (sb->st_size + 511) / 512;
|
||||||
// TODO incomplete
|
// TODO incomplete
|
||||||
}
|
}
|
||||||
if (ro) {
|
|
||||||
sb->st_mode &= ~0000555u;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
@ -98,9 +98,9 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||||||
|
|
||||||
// Applications expect to be run from /app0 so mount the file's parent path as app0.
|
// Applications expect to be run from /app0 so mount the file's parent path as app0.
|
||||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||||
mnt->Mount(game_folder, "/app0");
|
mnt->Mount(game_folder, "/app0", true);
|
||||||
// Certain games may use /hostapp as well such as CUSA001100
|
// Certain games may use /hostapp as well such as CUSA001100
|
||||||
mnt->Mount(game_folder, "/hostapp");
|
mnt->Mount(game_folder, "/hostapp", true);
|
||||||
|
|
||||||
auto& game_info = Common::ElfInfo::Instance();
|
auto& game_info = Common::ElfInfo::Instance();
|
||||||
|
|
||||||
@ -231,11 +231,15 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||||||
std::filesystem::create_directory(mount_data_dir);
|
std::filesystem::create_directory(mount_data_dir);
|
||||||
}
|
}
|
||||||
mnt->Mount(mount_data_dir, "/data"); // should just exist, manually create with game serial
|
mnt->Mount(mount_data_dir, "/data"); // should just exist, manually create with game serial
|
||||||
|
|
||||||
|
// Mounting temp folders
|
||||||
const auto& mount_temp_dir = Common::FS::GetUserPath(Common::FS::PathType::TempDataDir) / id;
|
const auto& mount_temp_dir = Common::FS::GetUserPath(Common::FS::PathType::TempDataDir) / id;
|
||||||
if (!std::filesystem::exists(mount_temp_dir)) {
|
if (std::filesystem::exists(mount_temp_dir)) {
|
||||||
std::filesystem::create_directory(mount_temp_dir);
|
// Temp folder should be cleared on each boot.
|
||||||
|
std::filesystem::remove_all(mount_temp_dir);
|
||||||
}
|
}
|
||||||
mnt->Mount(mount_temp_dir, "/temp0"); // called in app_content ==> stat/mkdir
|
std::filesystem::create_directory(mount_temp_dir);
|
||||||
|
mnt->Mount(mount_temp_dir, "/temp0");
|
||||||
mnt->Mount(mount_temp_dir, "/temp");
|
mnt->Mount(mount_temp_dir, "/temp");
|
||||||
|
|
||||||
const auto& mount_download_dir =
|
const auto& mount_download_dir =
|
||||||
|
@ -206,7 +206,8 @@ static void LowerBufferFormatInst(IR::Block& block, IR::Inst& inst, Info& info)
|
|||||||
.swizzle = is_inst_typed
|
.swizzle = is_inst_typed
|
||||||
? AmdGpu::RemapSwizzle(flags.inst_data_fmt.Value(), AmdGpu::IdentityMapping)
|
? AmdGpu::RemapSwizzle(flags.inst_data_fmt.Value(), AmdGpu::IdentityMapping)
|
||||||
: buffer.DstSelect(),
|
: buffer.DstSelect(),
|
||||||
.num_conversion = is_inst_typed ? AmdGpu::MapNumberConversion(flags.inst_num_fmt.Value())
|
.num_conversion = is_inst_typed ? AmdGpu::MapNumberConversion(flags.inst_num_fmt.Value(),
|
||||||
|
flags.inst_data_fmt.Value())
|
||||||
: buffer.GetNumberConversion(),
|
: buffer.GetNumberConversion(),
|
||||||
.num_components = AmdGpu::NumComponents(data_format),
|
.num_components = AmdGpu::NumComponents(data_format),
|
||||||
};
|
};
|
||||||
|
@ -34,6 +34,18 @@ inline F32 ApplyReadNumberConversion(IREmitter& ir, const F32& value,
|
|||||||
case AmdGpu::NumberConversion::UnormToUbnorm:
|
case AmdGpu::NumberConversion::UnormToUbnorm:
|
||||||
// Convert 0...1 to -1...1
|
// Convert 0...1 to -1...1
|
||||||
return ir.FPSub(ir.FPMul(value, ir.Imm32(2.f)), ir.Imm32(1.f));
|
return ir.FPSub(ir.FPMul(value, ir.Imm32(2.f)), ir.Imm32(1.f));
|
||||||
|
case AmdGpu::NumberConversion::Sint8ToSnormNz: {
|
||||||
|
const IR::U32 additon = ir.IAdd(ir.IMul(ir.BitCast<U32>(value), ir.Imm32(2)), ir.Imm32(1));
|
||||||
|
const IR::F32 left = ir.ConvertSToF(32, 32, additon);
|
||||||
|
const IR::F32 max = ir.Imm32(float(std::numeric_limits<u8>::max()));
|
||||||
|
return ir.FPDiv(left, max);
|
||||||
|
}
|
||||||
|
case AmdGpu::NumberConversion::Sint16ToSnormNz: {
|
||||||
|
const IR::U32 additon = ir.IAdd(ir.IMul(ir.BitCast<U32>(value), ir.Imm32(2)), ir.Imm32(1));
|
||||||
|
const IR::F32 left = ir.ConvertSToF(32, 32, additon);
|
||||||
|
const IR::F32 max = ir.Imm32(float(std::numeric_limits<u16>::max()));
|
||||||
|
return ir.FPDiv(left, max);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
@ -66,6 +78,20 @@ inline F32 ApplyWriteNumberConversion(IREmitter& ir, const F32& value,
|
|||||||
case AmdGpu::NumberConversion::UnormToUbnorm:
|
case AmdGpu::NumberConversion::UnormToUbnorm:
|
||||||
// Convert -1...1 to 0...1
|
// Convert -1...1 to 0...1
|
||||||
return ir.FPDiv(ir.FPAdd(value, ir.Imm32(1.f)), ir.Imm32(2.f));
|
return ir.FPDiv(ir.FPAdd(value, ir.Imm32(1.f)), ir.Imm32(2.f));
|
||||||
|
case AmdGpu::NumberConversion::Sint8ToSnormNz: {
|
||||||
|
const IR::F32 max = ir.Imm32(float(std::numeric_limits<u8>::max()));
|
||||||
|
const IR::F32 mul = ir.FPMul(ir.FPClamp(value, ir.Imm32(-1.f), ir.Imm32(1.f)), max);
|
||||||
|
const IR::F32 left = ir.FPSub(mul, ir.Imm32(1.f));
|
||||||
|
const IR::U32 raw = ir.ConvertFToS(32, ir.FPDiv(left, ir.Imm32(2.f)));
|
||||||
|
return ir.BitCast<F32>(raw);
|
||||||
|
}
|
||||||
|
case AmdGpu::NumberConversion::Sint16ToSnormNz: {
|
||||||
|
const IR::F32 max = ir.Imm32(float(std::numeric_limits<u16>::max()));
|
||||||
|
const IR::F32 mul = ir.FPMul(ir.FPClamp(value, ir.Imm32(-1.f), ir.Imm32(1.f)), max);
|
||||||
|
const IR::F32 left = ir.FPSub(mul, ir.Imm32(1.f));
|
||||||
|
const IR::U32 raw = ir.ConvertFToS(32, ir.FPDiv(left, ir.Imm32(2.f)));
|
||||||
|
return ir.BitCast<F32>(raw);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -928,7 +928,7 @@ struct Liverpool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] NumberConversion GetNumberConversion() const {
|
[[nodiscard]] NumberConversion GetNumberConversion() const {
|
||||||
return MapNumberConversion(GetFixedNumberFormat());
|
return MapNumberConversion(GetFixedNumberFormat(), info.format);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] CompMapping Swizzle() const {
|
[[nodiscard]] CompMapping Swizzle() const {
|
||||||
|
@ -68,7 +68,7 @@ struct Buffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NumberConversion GetNumberConversion() const noexcept {
|
NumberConversion GetNumberConversion() const noexcept {
|
||||||
return MapNumberConversion(NumberFormat(num_format));
|
return MapNumberConversion(NumberFormat(num_format), DataFormat(data_format));
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetStride() const noexcept {
|
u32 GetStride() const noexcept {
|
||||||
@ -292,7 +292,7 @@ struct Image {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NumberConversion GetNumberConversion() const noexcept {
|
NumberConversion GetNumberConversion() const noexcept {
|
||||||
return MapNumberConversion(NumberFormat(num_format));
|
return MapNumberConversion(NumberFormat(num_format), DataFormat(data_format));
|
||||||
}
|
}
|
||||||
|
|
||||||
TilingMode GetTilingMode() const {
|
TilingMode GetTilingMode() const {
|
||||||
|
@ -197,6 +197,8 @@ enum class NumberConversion : u32 {
|
|||||||
UintToUscaled = 1,
|
UintToUscaled = 1,
|
||||||
SintToSscaled = 2,
|
SintToSscaled = 2,
|
||||||
UnormToUbnorm = 3,
|
UnormToUbnorm = 3,
|
||||||
|
Sint8ToSnormNz = 5,
|
||||||
|
Sint16ToSnormNz = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CompMapping {
|
struct CompMapping {
|
||||||
@ -287,6 +289,7 @@ inline NumberFormat RemapNumberFormat(const NumberFormat format, const DataForma
|
|||||||
case NumberFormat::Uscaled:
|
case NumberFormat::Uscaled:
|
||||||
return NumberFormat::Uint;
|
return NumberFormat::Uint;
|
||||||
case NumberFormat::Sscaled:
|
case NumberFormat::Sscaled:
|
||||||
|
case NumberFormat::SnormNz:
|
||||||
return NumberFormat::Sint;
|
return NumberFormat::Sint;
|
||||||
case NumberFormat::Ubnorm:
|
case NumberFormat::Ubnorm:
|
||||||
return NumberFormat::Unorm;
|
return NumberFormat::Unorm;
|
||||||
@ -336,14 +339,28 @@ inline CompMapping RemapSwizzle(const DataFormat format, const CompMapping swizz
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline NumberConversion MapNumberConversion(const NumberFormat format) {
|
inline NumberConversion MapNumberConversion(const NumberFormat num_fmt, const DataFormat data_fmt) {
|
||||||
switch (format) {
|
switch (num_fmt) {
|
||||||
case NumberFormat::Uscaled:
|
case NumberFormat::Uscaled:
|
||||||
return NumberConversion::UintToUscaled;
|
return NumberConversion::UintToUscaled;
|
||||||
case NumberFormat::Sscaled:
|
case NumberFormat::Sscaled:
|
||||||
return NumberConversion::SintToSscaled;
|
return NumberConversion::SintToSscaled;
|
||||||
case NumberFormat::Ubnorm:
|
case NumberFormat::Ubnorm:
|
||||||
return NumberConversion::UnormToUbnorm;
|
return NumberConversion::UnormToUbnorm;
|
||||||
|
case NumberFormat::SnormNz: {
|
||||||
|
switch (data_fmt) {
|
||||||
|
case DataFormat::Format8:
|
||||||
|
case DataFormat::Format8_8:
|
||||||
|
case DataFormat::Format8_8_8_8:
|
||||||
|
return NumberConversion::Sint8ToSnormNz;
|
||||||
|
case DataFormat::Format16:
|
||||||
|
case DataFormat::Format16_16:
|
||||||
|
case DataFormat::Format16_16_16_16:
|
||||||
|
return NumberConversion::Sint16ToSnormNz;
|
||||||
|
default:
|
||||||
|
UNREACHABLE_MSG("data_fmt = {}", u32(data_fmt));
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return NumberConversion::None;
|
return NumberConversion::None;
|
||||||
}
|
}
|
||||||
|
@ -270,7 +270,25 @@ Frame* Presenter::PrepareLastFrame() {
|
|||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame* Presenter::PrepareFrameInternal(VideoCore::ImageId image_id, bool is_eop) {
|
static vk::Format GetFrameViewFormat(const Libraries::VideoOut::PixelFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case Libraries::VideoOut::PixelFormat::A8B8G8R8Srgb:
|
||||||
|
return vk::Format::eR8G8B8A8Srgb;
|
||||||
|
case Libraries::VideoOut::PixelFormat::A8R8G8B8Srgb:
|
||||||
|
return vk::Format::eB8G8R8A8Srgb;
|
||||||
|
case Libraries::VideoOut::PixelFormat::A2R10G10B10:
|
||||||
|
case Libraries::VideoOut::PixelFormat::A2R10G10B10Srgb:
|
||||||
|
case Libraries::VideoOut::PixelFormat::A2R10G10B10Bt2020Pq:
|
||||||
|
return vk::Format::eA2R10G10B10UnormPack32;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
UNREACHABLE_MSG("Unknown format={}", static_cast<u32>(format));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Frame* Presenter::PrepareFrameInternal(VideoCore::ImageId image_id,
|
||||||
|
const Libraries::VideoOut::PixelFormat format, bool is_eop) {
|
||||||
// Request a free presentation frame.
|
// Request a free presentation frame.
|
||||||
Frame* frame = GetRenderFrame();
|
Frame* frame = GetRenderFrame();
|
||||||
|
|
||||||
@ -324,7 +342,7 @@ Frame* Presenter::PrepareFrameInternal(VideoCore::ImageId image_id, bool is_eop)
|
|||||||
cmdbuf);
|
cmdbuf);
|
||||||
|
|
||||||
VideoCore::ImageViewInfo info{};
|
VideoCore::ImageViewInfo info{};
|
||||||
info.format = image.info.pixel_format;
|
info.format = GetFrameViewFormat(format);
|
||||||
// Exclude alpha from output frame to avoid blending with UI.
|
// Exclude alpha from output frame to avoid blending with UI.
|
||||||
info.mapping = vk::ComponentMapping{
|
info.mapping = vk::ComponentMapping{
|
||||||
.r = vk::ComponentSwizzle::eIdentity,
|
.r = vk::ComponentSwizzle::eIdentity,
|
||||||
|
@ -70,11 +70,12 @@ public:
|
|||||||
auto desc = VideoCore::TextureCache::VideoOutDesc{attribute, cpu_address};
|
auto desc = VideoCore::TextureCache::VideoOutDesc{attribute, cpu_address};
|
||||||
const auto image_id = texture_cache.FindImage(desc);
|
const auto image_id = texture_cache.FindImage(desc);
|
||||||
texture_cache.UpdateImage(image_id, is_eop ? nullptr : &flip_scheduler);
|
texture_cache.UpdateImage(image_id, is_eop ? nullptr : &flip_scheduler);
|
||||||
return PrepareFrameInternal(image_id, is_eop);
|
return PrepareFrameInternal(image_id, attribute.attrib.pixel_format, is_eop);
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame* PrepareBlankFrame(bool is_eop) {
|
Frame* PrepareBlankFrame(bool is_eop) {
|
||||||
return PrepareFrameInternal(VideoCore::NULL_IMAGE_ID, is_eop);
|
return PrepareFrameInternal(VideoCore::NULL_IMAGE_ID,
|
||||||
|
Libraries::VideoOut::PixelFormat::Unknown, is_eop);
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoCore::Image& RegisterVideoOutSurface(
|
VideoCore::Image& RegisterVideoOutSurface(
|
||||||
@ -119,7 +120,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Frame* PrepareFrameInternal(VideoCore::ImageId image_id, bool is_eop = true);
|
Frame* PrepareFrameInternal(VideoCore::ImageId image_id,
|
||||||
|
Libraries::VideoOut::PixelFormat format, bool is_eop = true);
|
||||||
Frame* GetRenderFrame();
|
Frame* GetRenderFrame();
|
||||||
|
|
||||||
void SetExpectedGameSize(s32 width, s32 height);
|
void SetExpectedGameSize(s32 width, s32 height);
|
||||||
|
@ -16,14 +16,15 @@ using VideoOutFormat = Libraries::VideoOut::PixelFormat;
|
|||||||
|
|
||||||
static vk::Format ConvertPixelFormat(const VideoOutFormat format) {
|
static vk::Format ConvertPixelFormat(const VideoOutFormat format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case VideoOutFormat::A8R8G8B8Srgb:
|
|
||||||
return vk::Format::eB8G8R8A8Srgb;
|
|
||||||
case VideoOutFormat::A8B8G8R8Srgb:
|
case VideoOutFormat::A8B8G8R8Srgb:
|
||||||
|
// Remaining formats are mapped to RGBA for internal consistency and changed to BGRA in the
|
||||||
|
// frame image view.
|
||||||
|
case VideoOutFormat::A8R8G8B8Srgb:
|
||||||
return vk::Format::eR8G8B8A8Srgb;
|
return vk::Format::eR8G8B8A8Srgb;
|
||||||
case VideoOutFormat::A2R10G10B10:
|
case VideoOutFormat::A2R10G10B10:
|
||||||
case VideoOutFormat::A2R10G10B10Srgb:
|
case VideoOutFormat::A2R10G10B10Srgb:
|
||||||
case VideoOutFormat::A2R10G10B10Bt2020Pq:
|
case VideoOutFormat::A2R10G10B10Bt2020Pq:
|
||||||
return vk::Format::eA2R10G10B10UnormPack32;
|
return vk::Format::eA2B10G10R10UnormPack32;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user