mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-27 20:44:28 +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:
|
||||
return SEEK_END;
|
||||
default:
|
||||
LOG_ERROR(Common_Filesystem, "Unsupported origin {}, defaulting to SEEK_SET",
|
||||
static_cast<u32>(origin));
|
||||
return SEEK_SET;
|
||||
UNREACHABLE_MSG("Impossible SeekOrigin {}", static_cast<u32>(origin));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,8 +61,6 @@ enum class SeekOrigin : u32 {
|
||||
SetOrigin, // Seeks from the start of the file.
|
||||
CurrentPosition, // Seeks from the current file pointer position.
|
||||
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 {
|
||||
|
@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include "common/logging/log.h"
|
||||
#include "random_device.h"
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include "common/logging/log.h"
|
||||
#include "srandom_device.h"
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include "common/logging/log.h"
|
||||
#include "urandom_device.h"
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <fmt/chrono.h>
|
||||
#include <imgui.h>
|
||||
#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 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 append = (flags & ORBIS_KERNEL_O_APPEND) != 0;
|
||||
bool fsync = (flags & ORBIS_KERNEL_O_FSYNC) != 0;
|
||||
bool sync = (flags & ORBIS_KERNEL_O_SYNC) != 0;
|
||||
// Flags fsync and sync behave the same
|
||||
bool sync = (flags & ORBIS_KERNEL_O_SYNC) != 0 || (flags & ORBIS_KERNEL_O_FSYNC) != 0;
|
||||
bool create = (flags & ORBIS_KERNEL_O_CREAT) != 0;
|
||||
bool truncate = (flags & ORBIS_KERNEL_O_TRUNC) != 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 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};
|
||||
u32 handle = h->CreateHandle();
|
||||
auto* file = h->GetFile(handle);
|
||||
@ -94,84 +104,126 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
|
||||
}
|
||||
}
|
||||
|
||||
if (directory) {
|
||||
file->type = Core::FileSys::FileType::Directory;
|
||||
file->m_guest_name = path;
|
||||
file->m_host_name = mnt->GetHostPath(file->m_guest_name);
|
||||
if (!std::filesystem::is_directory(file->m_host_name)) { // directory doesn't exist
|
||||
bool read_only = false;
|
||||
file->m_guest_name = path;
|
||||
file->m_host_name = mnt->GetHostPath(file->m_guest_name, &read_only);
|
||||
bool exists = std::filesystem::exists(file->m_host_name);
|
||||
s32 e = 0;
|
||||
|
||||
if (create) {
|
||||
if (excl && exists) {
|
||||
// Error if file exists
|
||||
h->DeleteHandle(handle);
|
||||
*__Error() = POSIX_ENOENT;
|
||||
*__Error() = POSIX_EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
} else if (!exists) {
|
||||
// If we're not creating a file, and it doesn't exist, return ENOENT
|
||||
h->DeleteHandle(handle);
|
||||
*__Error() = POSIX_ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (std::filesystem::is_directory(file->m_host_name) || directory) {
|
||||
// Directories can be opened even if the directory flag isn't set.
|
||||
// In these cases, error behavior is identical to the directory code path.
|
||||
directory = true;
|
||||
}
|
||||
|
||||
if (directory) {
|
||||
if (!std::filesystem::is_directory(file->m_host_name)) {
|
||||
// If the opened file is not a directory, return ENOTDIR.
|
||||
// This will trigger when create & directory is specified, this is expected.
|
||||
h->DeleteHandle(handle);
|
||||
*__Error() = POSIX_ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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 {
|
||||
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);
|
||||
int e = 0;
|
||||
// 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);
|
||||
|
||||
if (create) {
|
||||
if (excl && exists) {
|
||||
// Error if file exists
|
||||
h->DeleteHandle(handle);
|
||||
*__Error() = POSIX_EEXIST;
|
||||
return -1;
|
||||
}
|
||||
// Create file if it doesn't exist
|
||||
Common::FS::IOFile out(file->m_host_name, Common::FS::FileAccessMode::Write);
|
||||
} else if (!exists) {
|
||||
// File to open doesn't exist, return ENOENT
|
||||
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_ENOENT;
|
||||
*__Error() = POSIX_EROFS;
|
||||
return -1;
|
||||
} else if (truncate && e == 0) {
|
||||
// If the file was opened successfully and truncate was enabled, reduce size to 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
|
||||
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);
|
||||
}
|
||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Write);
|
||||
} else if (rdwr) {
|
||||
// Read and write
|
||||
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::ReadWrite);
|
||||
}
|
||||
} else {
|
||||
// Invalid flags
|
||||
*__Error() = POSIX_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (truncate && e == 0) {
|
||||
// If the file was opened successfully and truncate was enabled, reduce size to 0
|
||||
file->f.SetSize(0);
|
||||
}
|
||||
|
||||
if (e != 0) {
|
||||
// Open failed in platform-specific code, errno needs to be converted.
|
||||
h->DeleteHandle(handle);
|
||||
SetPosixErrno(e);
|
||||
return -1;
|
||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite);
|
||||
}
|
||||
}
|
||||
|
||||
if (e != 0) {
|
||||
// Open failed in platform-specific code, errno needs to be converted.
|
||||
h->DeleteHandle(handle);
|
||||
SetPosixErrno(e);
|
||||
return -1;
|
||||
}
|
||||
|
||||
file->is_opened = true;
|
||||
return handle;
|
||||
}
|
||||
@ -365,10 +417,10 @@ s64 PS4_SYSV_ABI posix_lseek(s32 fd, s64 offset, s32 whence) {
|
||||
origin = Common::FS::SeekOrigin::CurrentPosition;
|
||||
} else if (whence == 2) {
|
||||
origin = Common::FS::SeekOrigin::End;
|
||||
} else if (whence == 3) {
|
||||
origin = Common::FS::SeekOrigin::SeekHole;
|
||||
} else if (whence == 4) {
|
||||
origin = Common::FS::SeekOrigin::SeekData;
|
||||
} else if (whence == 3 || whence == 4) {
|
||||
// whence parameter belongs to an unsupported POSIX extension
|
||||
*__Error() = POSIX_ENOTTY;
|
||||
return -1;
|
||||
} else {
|
||||
// whence parameter is invalid
|
||||
*__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);
|
||||
|
||||
if (dir_name.empty() || !std::filesystem::is_directory(dir_name)) {
|
||||
*__Error() = POSIX_ENOTDIR;
|
||||
if (ro) {
|
||||
*__Error() = POSIX_EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ro) {
|
||||
*__Error() = POSIX_EROFS;
|
||||
if (dir_name.empty() || !std::filesystem::is_directory(dir_name)) {
|
||||
*__Error() = POSIX_ENOTDIR;
|
||||
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) {
|
||||
LOG_INFO(Kernel_Fs, "(PARTIAL) path = {}", path);
|
||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
bool ro = false;
|
||||
const auto path_name = mnt->GetHostPath(path, &ro);
|
||||
const auto path_name = mnt->GetHostPath(path);
|
||||
std::memset(sb, 0, sizeof(OrbisKernelStat));
|
||||
const bool is_dir = std::filesystem::is_directory(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;
|
||||
// TODO incomplete
|
||||
}
|
||||
if (ro) {
|
||||
sb->st_mode &= ~0000555u;
|
||||
}
|
||||
|
||||
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.
|
||||
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
|
||||
mnt->Mount(game_folder, "/hostapp");
|
||||
mnt->Mount(game_folder, "/hostapp", true);
|
||||
|
||||
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);
|
||||
}
|
||||
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;
|
||||
if (!std::filesystem::exists(mount_temp_dir)) {
|
||||
std::filesystem::create_directory(mount_temp_dir);
|
||||
if (std::filesystem::exists(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");
|
||||
|
||||
const auto& mount_download_dir =
|
||||
|
@ -206,7 +206,8 @@ static void LowerBufferFormatInst(IR::Block& block, IR::Inst& inst, Info& info)
|
||||
.swizzle = is_inst_typed
|
||||
? AmdGpu::RemapSwizzle(flags.inst_data_fmt.Value(), AmdGpu::IdentityMapping)
|
||||
: 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(),
|
||||
.num_components = AmdGpu::NumComponents(data_format),
|
||||
};
|
||||
|
@ -34,6 +34,18 @@ inline F32 ApplyReadNumberConversion(IREmitter& ir, const F32& value,
|
||||
case AmdGpu::NumberConversion::UnormToUbnorm:
|
||||
// Convert 0...1 to -1...1
|
||||
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:
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -66,6 +78,20 @@ inline F32 ApplyWriteNumberConversion(IREmitter& ir, const F32& value,
|
||||
case AmdGpu::NumberConversion::UnormToUbnorm:
|
||||
// Convert -1...1 to 0...1
|
||||
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:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -928,7 +928,7 @@ struct Liverpool {
|
||||
}
|
||||
|
||||
[[nodiscard]] NumberConversion GetNumberConversion() const {
|
||||
return MapNumberConversion(GetFixedNumberFormat());
|
||||
return MapNumberConversion(GetFixedNumberFormat(), info.format);
|
||||
}
|
||||
|
||||
[[nodiscard]] CompMapping Swizzle() const {
|
||||
|
@ -68,7 +68,7 @@ struct Buffer {
|
||||
}
|
||||
|
||||
NumberConversion GetNumberConversion() const noexcept {
|
||||
return MapNumberConversion(NumberFormat(num_format));
|
||||
return MapNumberConversion(NumberFormat(num_format), DataFormat(data_format));
|
||||
}
|
||||
|
||||
u32 GetStride() const noexcept {
|
||||
@ -292,7 +292,7 @@ struct Image {
|
||||
}
|
||||
|
||||
NumberConversion GetNumberConversion() const noexcept {
|
||||
return MapNumberConversion(NumberFormat(num_format));
|
||||
return MapNumberConversion(NumberFormat(num_format), DataFormat(data_format));
|
||||
}
|
||||
|
||||
TilingMode GetTilingMode() const {
|
||||
|
@ -197,6 +197,8 @@ enum class NumberConversion : u32 {
|
||||
UintToUscaled = 1,
|
||||
SintToSscaled = 2,
|
||||
UnormToUbnorm = 3,
|
||||
Sint8ToSnormNz = 5,
|
||||
Sint16ToSnormNz = 6,
|
||||
};
|
||||
|
||||
struct CompMapping {
|
||||
@ -287,6 +289,7 @@ inline NumberFormat RemapNumberFormat(const NumberFormat format, const DataForma
|
||||
case NumberFormat::Uscaled:
|
||||
return NumberFormat::Uint;
|
||||
case NumberFormat::Sscaled:
|
||||
case NumberFormat::SnormNz:
|
||||
return NumberFormat::Sint;
|
||||
case NumberFormat::Ubnorm:
|
||||
return NumberFormat::Unorm;
|
||||
@ -336,14 +339,28 @@ inline CompMapping RemapSwizzle(const DataFormat format, const CompMapping swizz
|
||||
}
|
||||
}
|
||||
|
||||
inline NumberConversion MapNumberConversion(const NumberFormat format) {
|
||||
switch (format) {
|
||||
inline NumberConversion MapNumberConversion(const NumberFormat num_fmt, const DataFormat data_fmt) {
|
||||
switch (num_fmt) {
|
||||
case NumberFormat::Uscaled:
|
||||
return NumberConversion::UintToUscaled;
|
||||
case NumberFormat::Sscaled:
|
||||
return NumberConversion::SintToSscaled;
|
||||
case NumberFormat::Ubnorm:
|
||||
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:
|
||||
return NumberConversion::None;
|
||||
}
|
||||
|
@ -270,7 +270,25 @@ Frame* Presenter::PrepareLastFrame() {
|
||||
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.
|
||||
Frame* frame = GetRenderFrame();
|
||||
|
||||
@ -324,7 +342,7 @@ Frame* Presenter::PrepareFrameInternal(VideoCore::ImageId image_id, bool is_eop)
|
||||
cmdbuf);
|
||||
|
||||
VideoCore::ImageViewInfo info{};
|
||||
info.format = image.info.pixel_format;
|
||||
info.format = GetFrameViewFormat(format);
|
||||
// Exclude alpha from output frame to avoid blending with UI.
|
||||
info.mapping = vk::ComponentMapping{
|
||||
.r = vk::ComponentSwizzle::eIdentity,
|
||||
|
@ -70,11 +70,12 @@ public:
|
||||
auto desc = VideoCore::TextureCache::VideoOutDesc{attribute, cpu_address};
|
||||
const auto image_id = texture_cache.FindImage(desc);
|
||||
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) {
|
||||
return PrepareFrameInternal(VideoCore::NULL_IMAGE_ID, is_eop);
|
||||
return PrepareFrameInternal(VideoCore::NULL_IMAGE_ID,
|
||||
Libraries::VideoOut::PixelFormat::Unknown, is_eop);
|
||||
}
|
||||
|
||||
VideoCore::Image& RegisterVideoOutSurface(
|
||||
@ -119,7 +120,8 @@ public:
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
void SetExpectedGameSize(s32 width, s32 height);
|
||||
|
@ -16,14 +16,15 @@ using VideoOutFormat = Libraries::VideoOut::PixelFormat;
|
||||
|
||||
static vk::Format ConvertPixelFormat(const VideoOutFormat format) {
|
||||
switch (format) {
|
||||
case VideoOutFormat::A8R8G8B8Srgb:
|
||||
return vk::Format::eB8G8R8A8Srgb;
|
||||
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;
|
||||
case VideoOutFormat::A2R10G10B10:
|
||||
case VideoOutFormat::A2R10G10B10Srgb:
|
||||
case VideoOutFormat::A2R10G10B10Bt2020Pq:
|
||||
return vk::Format::eA2R10G10B10UnormPack32;
|
||||
return vk::Format::eA2B10G10R10UnormPack32;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user