Compare commits

..

46 Commits

Author SHA1 Message Date
bunnei
c68aa65226 gl_shader_decompiler: Fix GLSL compiler error with KIL instruction. 2018-08-12 00:06:48 -04:00
bunnei
a921d22545 Merge pull request #1022 from bunnei/fix-splat
Several Friend service fixes
2018-08-11 22:42:45 -04:00
bunnei
ee07041b3a Merge pull request #1020 from lioncash/namespace
core: Namespace EmuWindow
2018-08-11 22:40:08 -04:00
bunnei
9c977d2215 Merge pull request #1021 from lioncash/warn
gl_rasterizer: Silence implicit truncation warning in SetupShaders()
2018-08-11 22:39:46 -04:00
bunnei
f2c7b5dcd6 Merge pull request #1024 from Subv/blend_gl
GPU/Maxwell3D: Implemented an alternative set of blend factors.
2018-08-11 22:39:02 -04:00
bunnei
d37da52cb3 Merge pull request #1023 from Subv/invalid_attribs
RasterizerGL: Ignore invalid/unset vertex attributes.
2018-08-11 22:18:40 -04:00
Subv
969326bd58 GPU/Maxwell3D: Implemented an alternative set of blend factors.
These are used by nouveau and some games like SMO.
2018-08-11 20:57:16 -05:00
greggameplayer
224071a652 Implement R8_UINT RenderTargetFormat & PixelFormat (#1014)
- Used by Go Vacation
2018-08-11 21:44:42 -04:00
Subv
2dad1204e8 RasterizerGL: Ignore invalid/unset vertex attributes.
This should make the es2gears example not crash anymore.
2018-08-11 20:36:40 -05:00
bunnei
249341d08f friend: Stub DeclareCloseOnlinePlaySession.
- Used by Splatoon 2.
2018-08-11 21:34:14 -04:00
bunnei
261a4f0311 friend: Fix CreateFriendService to return an IFriendService interface. 2018-08-11 21:29:58 -04:00
bunnei
ca4bf671ce server_session: Provide more useful information and don't crash on bad IPC request. 2018-08-11 21:15:24 -04:00
Lioncash
28e90fa0e0 gl_rasterizer: Silence implicit truncation warning in SetupShaders()
Previously this would warn of truncating a std::size_t to a u32. This is
safe because we'll obviously never have more than UINT32_MAX amount of
uniform buffers.
2018-08-11 20:32:03 -04:00
Lioncash
0a93b45b6a core: Namespace EmuWindow
Gets the class out of the global namespace.
2018-08-11 20:20:21 -04:00
bunnei
403dfd68fc Merge pull request #1010 from bunnei/unk-vert-attrib-shader
gl_shader_decompiler: Improve handling of unknown input/output attributes.
2018-08-11 19:56:28 -04:00
bunnei
c519354506 Merge pull request #1009 from bunnei/rg8-rgba8-snorm
Implement render target formats RGBA8_SNORM and RG8_SNORM.
2018-08-11 19:55:41 -04:00
bunnei
0b668d5ff3 gl_shader_decompiler: Improve handling of unknown input/output attributes. 2018-08-11 19:26:45 -04:00
bunnei
bc286c169f Merge pull request #970 from DarkLordZach/loader-errors
loader: Add more descriptive errors
2018-08-11 19:25:30 -04:00
bunnei
670a2c1f80 Merge pull request #1018 from Subv/ssy_sync
GPU/Shader: Implemented SSY and SYNC as a set_target/jump pair.
2018-08-11 19:10:02 -04:00
bunnei
88ffa422d4 gl_rasterizer: Implement render target format RG8_SNORM.
- Used by Super Mario Odyssey.
2018-08-11 19:06:42 -04:00
bunnei
0471976b48 gl_rasterizer: Implement render target format RGBA8_SNORM.
- Used by Super Mario Odyssey.
2018-08-11 18:59:14 -04:00
Subv
c1ad973881 GPU/Shader: Don't predicate instructions that don't have a predicate field (SSY). 2018-08-11 16:00:14 -05:00
Subv
305a05f820 GPU/Shaders: Implemented SSY and SYNC as a way to modify control flow during shader execution.
SSY sets the target label to jump to when the SYNC instruction is executed.
2018-08-11 15:55:11 -05:00
bunnei
d64303d185 Merge pull request #1016 from lioncash/video
video_core: Get rid of global variable g_toggle_framelimit_enabled
2018-08-11 14:10:55 -04:00
bunnei
b8b9f41b6b Merge pull request #1003 from lioncash/var
video_core: Use variable template variants of type_traits interfaces where applicable
2018-08-11 14:08:12 -04:00
greggameplayer
dfcde52f39 Implement R16S & R16UI & R16I RenderTargetFormats & PixelFormats and more (R16_UNORM needed by Fate Extella) (#848)
* Implement R16S & R16UI & R16I RenderTargetFormats & PixelFormats


Do a separate function in order to get Bytes Per Pixel of DepthFormat


Apply the new function in gpu.h


delete unneeded white space

* correct merging error
2018-08-11 14:01:50 -04:00
James Rowe
4f0818144e Merge pull request #1015 from lioncash/gamelist
qt/gamelist: Minor cleanup-related changes
2018-08-10 20:25:00 -06:00
Lioncash
20c2928c2b video_core; Get rid of global g_toggle_framelimit_enabled variable
Instead, we make a struct for renderer settings and allow the renderer
to update all of these settings, getting rid of the need for
global-scoped variables.

This also uncovered a few indirect inclusions for certain headers, which
this commit also fixes.
2018-08-10 19:00:09 -04:00
Lioncash
f380496728 renderer_base: Remove unused kFramebuffer enumeration
This is entirely unused and can be removed.
2018-08-10 18:31:13 -04:00
Lioncash
2e80e7480d video_core: Remove unused Renderer enumeration
Currently we only have an OpenGL renderer, so this is unused in code
(and occupies the Renderer identifier in the VideoCore namespace).
2018-08-10 18:27:40 -04:00
Lioncash
8eb97706b8 qt/game_list: Resolve truncation warning within GameListItemPath's constructor
Silences a warning about truncating from size_t to u32
2018-08-10 18:19:44 -04:00
Lioncash
aaf671a309 gt/game_list: Use std::array in GameListItemPath's data() function
We don't need to use a heap-allocated std::vector here, given we
explicitly know the bounds.
2018-08-10 18:19:40 -04:00
Lioncash
be53097577 qt/game_list: Remove redundant base class constructor from initializer list
This is called automatically anyways.
2018-08-10 18:17:39 -04:00
bunnei
0a003efde4 Merge pull request #1007 from MerryMage/dynarmic
dynarmic: Update to 0118ee0
2018-08-10 15:57:50 -04:00
bunnei
2e8620c877 Merge pull request #1011 from bunnei/misc-vtx-fmt
Implements VertexAttributes Size_32_32_32 and Size_8_8.
2018-08-10 15:57:28 -04:00
bunnei
6b0bc48a42 maxwell_to_gl: Implement VertexAttribute::Size::Size_8_8.
- Used by Super Mario Odyssey.
2018-08-10 12:47:00 -04:00
bunnei
a5b65df9cf maxwell_to_gl: Implement VertexAttribute::Size::Size_32_32_32.
- Used by Super Mario Odyssey.
2018-08-10 12:46:49 -04:00
bunnei
57626fda7b Merge pull request #1004 from lioncash/unused
gl_rasterizer_cache: Remove unused viewport parameter of GetFramebufferSurfaces()
2018-08-10 12:13:32 -04:00
bunnei
6313d54cef Merge pull request #1008 from yuzu-emu/revert-697-disable-depth-cull
Revert "gl_state: Temporarily disable culling and depth test."
2018-08-10 12:13:09 -04:00
bunnei
7e6a73963e Merge pull request #1002 from bunnei/refactor-tex-fmt
textures: Refactor out for Texture/Depth FormatFromPixelFormat.
2018-08-10 11:06:23 -04:00
bunnei
2156cb3cbe Revert "gl_state: Temporarily disable culling and depth test." 2018-08-10 10:39:46 -04:00
Zach Hilman
8069fbd37f game_list: Reorder error checks
clang-format fix
2018-08-09 21:37:35 -04:00
Zach Hilman
ec3bef7b4c loader: Add more descriptive errors
Full list of new errors and descriptions in core/loader/loader.h
2018-08-09 21:06:59 -04:00
Lioncash
0e1510ac29 gl_rasterizer_cache: Remove unused viewport parameter of GetFramebufferSurfaces() 2018-08-09 20:55:41 -04:00
Lioncash
b8c43b6080 video_core: Use variable template variants of type_traits interfaces where applicable 2018-08-09 20:45:48 -04:00
bunnei
3a67876252 textures: Refactor out for Texture/Depth FormatFromPixelFormat. 2018-08-09 20:36:03 -04:00
46 changed files with 774 additions and 517 deletions

View File

@@ -88,7 +88,7 @@ System::ResultStatus System::SingleStep() {
return RunLoop(false);
}
System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& filepath) {
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
app_loader = Loader::GetLoader(virtual_filesystem->OpenFile(filepath, FileSys::Mode::Read));
if (!app_loader) {
@@ -102,18 +102,8 @@ System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& file
LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
static_cast<int>(system_mode.second));
switch (system_mode.second) {
case Loader::ResultStatus::ErrorMissingKeys:
return ResultStatus::ErrorLoader_ErrorMissingKeys;
case Loader::ResultStatus::ErrorDecrypting:
return ResultStatus::ErrorLoader_ErrorDecrypting;
case Loader::ResultStatus::ErrorInvalidFormat:
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
case Loader::ResultStatus::ErrorUnsupportedArch:
return ResultStatus::ErrorUnsupportedArch;
default:
if (system_mode.second != Loader::ResultStatus::Success)
return ResultStatus::ErrorSystemMode;
}
}
ResultStatus init_result{Init(emu_window)};
@@ -129,17 +119,9 @@ System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& file
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
System::Shutdown();
switch (load_result) {
case Loader::ResultStatus::ErrorMissingKeys:
return ResultStatus::ErrorLoader_ErrorMissingKeys;
case Loader::ResultStatus::ErrorDecrypting:
return ResultStatus::ErrorLoader_ErrorDecrypting;
case Loader::ResultStatus::ErrorInvalidFormat:
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
case Loader::ResultStatus::ErrorUnsupportedArch:
return ResultStatus::ErrorUnsupportedArch;
default:
return ResultStatus::ErrorLoader;
if (load_result != Loader::ResultStatus::Success) {
return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) +
static_cast<u32>(load_result));
}
}
status = ResultStatus::Success;
@@ -169,7 +151,7 @@ Cpu& System::CpuCore(size_t core_index) {
return *cpu_cores[core_index];
}
System::ResultStatus System::Init(EmuWindow& emu_window) {
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
LOG_DEBUG(HW_Memory, "initialized OK");
CoreTiming::Init();

View File

@@ -22,9 +22,12 @@
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/gpu.h"
class EmuWindow;
class ARM_Interface;
namespace Core::Frontend {
class EmuWindow;
}
namespace Service::SM {
class ServiceManager;
}
@@ -49,21 +52,15 @@ public:
/// Enumeration representing the return values of the System Initialize and Load process.
enum class ResultStatus : u32 {
Success, ///< Succeeded
ErrorNotInitialized, ///< Error trying to use core prior to initialization
ErrorGetLoader, ///< Error finding the correct application loader
ErrorSystemMode, ///< Error determining the system mode
ErrorLoader, ///< Error loading the specified application
ErrorLoader_ErrorMissingKeys, ///< Error because the key/keys needed to run could not be
///< found.
ErrorLoader_ErrorDecrypting, ///< Error loading the specified application due to encryption
ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an
/// invalid format
ErrorSystemFiles, ///< Error in finding system files
ErrorSharedFont, ///< Error in finding shared font
ErrorVideoCore, ///< Error in the video core
ErrorUnsupportedArch, ///< Unsupported Architecture (32-Bit ROMs)
ErrorUnknown ///< Any other error
Success, ///< Succeeded
ErrorNotInitialized, ///< Error trying to use core prior to initialization
ErrorGetLoader, ///< Error finding the correct application loader
ErrorSystemMode, ///< Error determining the system mode
ErrorSystemFiles, ///< Error in finding system files
ErrorSharedFont, ///< Error in finding shared font
ErrorVideoCore, ///< Error in the video core
ErrorUnknown, ///< Any other error
ErrorLoader, ///< The base for loader errors (too many to repeat)
};
/**
@@ -105,7 +102,7 @@ public:
* @param filepath String path to the executable application to load on the host file system.
* @returns ResultStatus code, indicating if the operation succeeded.
*/
ResultStatus Load(EmuWindow& emu_window, const std::string& filepath);
ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath);
/**
* Indicates if the emulated system is powered on (all subsystems initialized and able to run an
@@ -233,7 +230,7 @@ private:
* input.
* @return ResultStatus code, indicating if the operation succeeded.
*/
ResultStatus Init(EmuWindow& emu_window);
ResultStatus Init(Frontend::EmuWindow& emu_window);
/// RealVfsFilesystem instance
FileSys::VirtualFilesystem virtual_filesystem;

View File

@@ -12,14 +12,16 @@
namespace FileSys {
constexpr std::array<const char*, 0x4> partition_names = {"update", "normal", "secure", "logo"};
XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) {
if (file->ReadObject(&header) != sizeof(GamecardHeader)) {
status = Loader::ResultStatus::ErrorInvalidFormat;
status = Loader::ResultStatus::ErrorBadXCIHeader;
return;
}
if (header.magic != Common::MakeMagic('H', 'E', 'A', 'D')) {
status = Loader::ResultStatus::ErrorInvalidFormat;
status = Loader::ResultStatus::ErrorBadXCIHeader;
return;
}
@@ -31,9 +33,6 @@ XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) {
return;
}
static constexpr std::array<const char*, 0x4> partition_names = {"update", "normal", "secure",
"logo"};
for (XCIPartition partition :
{XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) {
auto raw = main_hfs.GetFile(partition_names[static_cast<size_t>(partition)]);
@@ -130,15 +129,21 @@ bool XCI::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
if (partitions[static_cast<size_t>(part)] == nullptr) {
return Loader::ResultStatus::ErrorInvalidFormat;
return Loader::ResultStatus::ErrorXCIMissingPartition;
}
for (const VirtualFile& file : partitions[static_cast<size_t>(part)]->GetFiles()) {
if (file->GetExtension() != "nca")
continue;
auto nca = std::make_shared<NCA>(file);
if (nca->GetStatus() == Loader::ResultStatus::Success)
if (nca->GetStatus() == Loader::ResultStatus::Success) {
ncas.push_back(std::move(nca));
} else {
const u16 error_id = static_cast<u16>(nca->GetStatus());
LOG_CRITICAL(Loader, "Could not load NCA {}/{}, failed with error code {:04X} ({})",
partition_names[static_cast<size_t>(part)], nca->GetName(), error_id,
Loader::GetMessageForResultStatus(nca->GetStatus()));
}
}
return Loader::ResultStatus::Success;

View File

@@ -113,17 +113,27 @@ boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType ty
return out;
}
boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() const {
boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() {
const auto master_key_id = GetCryptoRevision();
u128 rights_id{};
memcpy(rights_id.data(), header.rights_id.data(), 16);
if (rights_id == u128{})
if (rights_id == u128{}) {
status = Loader::ResultStatus::ErrorInvalidRightsID;
return boost::none;
}
auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]);
if (titlekey == Core::Crypto::Key128{})
if (titlekey == Core::Crypto::Key128{}) {
status = Loader::ResultStatus::ErrorMissingTitlekey;
return boost::none;
}
if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) {
status = Loader::ResultStatus::ErrorMissingTitlekek;
return boost::none;
}
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
keys.GetKey(Core::Crypto::S128KeyType::Titlekek, master_key_id), Core::Crypto::Mode::ECB);
cipher.Transcode(titlekey.data(), titlekey.size(), titlekey.data(), Core::Crypto::Op::Decrypt);
@@ -131,7 +141,7 @@ boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() const {
return titlekey;
}
VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting_offset) const {
VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting_offset) {
if (!encrypted)
return in;
@@ -143,15 +153,22 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting
LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset);
{
boost::optional<Core::Crypto::Key128> key = boost::none;
if (std::find_if_not(header.rights_id.begin(), header.rights_id.end(),
[](char c) { return c == 0; }) == header.rights_id.end()) {
key = GetKeyAreaKey(NCASectionCryptoType::CTR);
} else {
if (has_rights_id) {
status = Loader::ResultStatus::Success;
key = GetTitlekey();
if (key == boost::none) {
if (status == Loader::ResultStatus::Success)
status = Loader::ResultStatus::ErrorMissingTitlekey;
return nullptr;
}
} else {
key = GetKeyAreaKey(NCASectionCryptoType::CTR);
if (key == boost::none) {
status = Loader::ResultStatus::ErrorMissingKeyAreaKey;
return nullptr;
}
}
if (key == boost::none)
return nullptr;
auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(
std::move(in), key.value(), starting_offset);
std::vector<u8> iv(16);
@@ -170,16 +187,31 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting
}
NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
status = Loader::ResultStatus::Success;
if (file == nullptr) {
status = Loader::ResultStatus::ErrorInvalidFormat;
status = Loader::ResultStatus::ErrorNullFile;
return;
}
if (sizeof(NCAHeader) != file->ReadObject(&header))
if (sizeof(NCAHeader) != file->ReadObject(&header)) {
LOG_ERROR(Loader, "File reader errored out during header read.");
status = Loader::ResultStatus::ErrorBadNCAHeader;
return;
}
encrypted = false;
if (!IsValidNCA(header)) {
if (header.magic == Common::MakeMagic('N', 'C', 'A', '2')) {
status = Loader::ResultStatus::ErrorNCA2;
return;
}
if (header.magic == Common::MakeMagic('N', 'C', 'A', '0')) {
status = Loader::ResultStatus::ErrorNCA0;
return;
}
NCAHeader dec_header{};
Core::Crypto::AESCipher<Core::Crypto::Key256> cipher(
keys.GetKey(Core::Crypto::S256KeyType::Header), Core::Crypto::Mode::XTS);
@@ -189,14 +221,26 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
header = dec_header;
encrypted = true;
} else {
if (dec_header.magic == Common::MakeMagic('N', 'C', 'A', '2')) {
status = Loader::ResultStatus::ErrorNCA2;
return;
}
if (dec_header.magic == Common::MakeMagic('N', 'C', 'A', '0')) {
status = Loader::ResultStatus::ErrorNCA0;
return;
}
if (!keys.HasKey(Core::Crypto::S256KeyType::Header))
status = Loader::ResultStatus::ErrorMissingKeys;
status = Loader::ResultStatus::ErrorMissingHeaderKey;
else
status = Loader::ResultStatus::ErrorDecrypting;
status = Loader::ResultStatus::ErrorIncorrectHeaderKey;
return;
}
}
has_rights_id = std::find_if_not(header.rights_id.begin(), header.rights_id.end(),
[](char c) { return c == '\0'; }) != header.rights_id.end();
const std::ptrdiff_t number_sections =
std::count_if(std::begin(header.section_tables), std::end(header.section_tables),
[](NCASectionTableEntry entry) { return entry.media_offset > 0; });
@@ -229,7 +273,12 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
files.push_back(std::move(dec));
romfs = files.back();
} else {
status = Loader::ResultStatus::ErrorMissingKeys;
if (status != Loader::ResultStatus::Success)
return;
if (has_rights_id)
status = Loader::ResultStatus::ErrorIncorrectTitlekeyOrTitlekek;
else
status = Loader::ResultStatus::ErrorIncorrectKeyAreaKey;
return;
}
} else if (section.raw.header.filesystem_type == NCASectionFilesystemType::PFS0) {
@@ -249,7 +298,12 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
exefs = dirs.back();
}
} else {
status = Loader::ResultStatus::ErrorMissingKeys;
if (status != Loader::ResultStatus::Success)
return;
if (has_rights_id)
status = Loader::ResultStatus::ErrorIncorrectTitlekeyOrTitlekek;
else
status = Loader::ResultStatus::ErrorIncorrectKeyAreaKey;
return;
}
}

View File

@@ -98,8 +98,8 @@ protected:
private:
u8 GetCryptoRevision() const;
boost::optional<Core::Crypto::Key128> GetKeyAreaKey(NCASectionCryptoType type) const;
boost::optional<Core::Crypto::Key128> GetTitlekey() const;
VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset) const;
boost::optional<Core::Crypto::Key128> GetTitlekey();
VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset);
std::vector<VirtualDir> dirs;
std::vector<VirtualFile> files;
@@ -109,6 +109,7 @@ private:
VirtualFile file;
NCAHeader header{};
bool has_rights_id{};
Loader::ResultStatus status{};

View File

@@ -24,19 +24,19 @@ bool PartitionFilesystem::Header::HasValidMagicValue() const {
PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
// At least be as large as the header
if (file->GetSize() < sizeof(Header)) {
status = Loader::ResultStatus::Error;
status = Loader::ResultStatus::ErrorBadPFSHeader;
return;
}
// For cartridges, HFSs can get very large, so we need to calculate the size up to
// the actual content itself instead of just blindly reading in the entire file.
if (sizeof(Header) != file->ReadObject(&pfs_header)) {
status = Loader::ResultStatus::Error;
status = Loader::ResultStatus::ErrorBadPFSHeader;
return;
}
if (!pfs_header.HasValidMagicValue()) {
status = Loader::ResultStatus::ErrorInvalidFormat;
status = Loader::ResultStatus::ErrorBadPFSHeader;
return;
}
@@ -51,7 +51,7 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
const size_t total_size = file_data.size();
if (total_size != metadata_size) {
status = Loader::ResultStatus::Error;
status = Loader::ResultStatus::ErrorIncorrectPFSFileSize;
return;
}

View File

@@ -12,26 +12,26 @@ namespace FileSys {
Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
size_t total_size = static_cast<size_t>(file->GetSize());
if (total_size < sizeof(Header))
return Loader::ResultStatus::Error;
return Loader::ResultStatus::ErrorBadNPDMHeader;
// TODO(DarkLordZach): Use ReadObject when Header/AcidHeader becomes trivially copyable.
std::vector<u8> npdm_header_data = file->ReadBytes(sizeof(Header));
if (sizeof(Header) != npdm_header_data.size())
return Loader::ResultStatus::Error;
return Loader::ResultStatus::ErrorBadNPDMHeader;
std::memcpy(&npdm_header, npdm_header_data.data(), sizeof(Header));
std::vector<u8> acid_header_data = file->ReadBytes(sizeof(AcidHeader), npdm_header.acid_offset);
if (sizeof(AcidHeader) != acid_header_data.size())
return Loader::ResultStatus::Error;
return Loader::ResultStatus::ErrorBadACIDHeader;
std::memcpy(&acid_header, acid_header_data.data(), sizeof(AcidHeader));
if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset))
return Loader::ResultStatus::Error;
return Loader::ResultStatus::ErrorBadACIHeader;
if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset))
return Loader::ResultStatus::Error;
return Loader::ResultStatus::ErrorBadFileAccessControl;
if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset))
return Loader::ResultStatus::Error;
return Loader::ResultStatus::ErrorBadFileAccessHeader;
return Loader::ResultStatus::Success;
}

View File

@@ -8,6 +8,8 @@
#include "core/frontend/input.h"
#include "core/settings.h"
namespace Core::Frontend {
class EmuWindow::TouchState : public Input::Factory<Input::TouchDevice>,
public std::enable_shared_from_this<TouchState> {
public:
@@ -108,3 +110,5 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) {
NotifyFramebufferLayoutChanged(Layout::DefaultFrameLayout(width, height));
}
} // namespace Core::Frontend

View File

@@ -10,6 +10,8 @@
#include "common/common_types.h"
#include "core/frontend/framebuffer_layout.h"
namespace Core::Frontend {
/**
* Abstraction class used to provide an interface between emulation code and the frontend
* (e.g. SDL, QGLWidget, GLFW, etc...).
@@ -166,3 +168,5 @@ private:
*/
std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y);
};
} // namespace Core::Frontend

View File

@@ -71,6 +71,14 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
const u32 object_id{context.GetDomainMessageHeader()->object_id};
switch (domain_message_header->command) {
case IPC::DomainMessageHeader::CommandType::SendMessage:
if (object_id > domain_request_handlers.size()) {
LOG_CRITICAL(IPC,
"object_id {} is too big! This probably means a recent service call "
"to {} needed to return a new interface!",
object_id, name);
UNREACHABLE();
return RESULT_SUCCESS; // Ignore error if asserts are off
}
return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {

View File

@@ -9,10 +9,103 @@
namespace Service::Friend {
class IFriendService final : public ServiceFramework<IFriendService> {
public:
IFriendService() : ServiceFramework("IFriendService") {
static const FunctionInfo functions[] = {
{0, nullptr, "GetCompletionEvent"},
{1, nullptr, "Cancel"},
{10100, nullptr, "GetFriendListIds"},
{10101, nullptr, "GetFriendList"},
{10102, nullptr, "UpdateFriendInfo"},
{10110, nullptr, "GetFriendProfileImage"},
{10200, nullptr, "SendFriendRequestForApplication"},
{10211, nullptr, "AddFacedFriendRequestForApplication"},
{10400, nullptr, "GetBlockedUserListIds"},
{10500, nullptr, "GetProfileList"},
{10600, nullptr, "DeclareOpenOnlinePlaySession"},
{10601, &IFriendService::DeclareCloseOnlinePlaySession,
"DeclareCloseOnlinePlaySession"},
{10610, nullptr, "UpdateUserPresence"},
{10700, nullptr, "GetPlayHistoryRegistrationKey"},
{10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
{10702, nullptr, "AddPlayHistory"},
{11000, nullptr, "GetProfileImageUrl"},
{20100, nullptr, "GetFriendCount"},
{20101, nullptr, "GetNewlyFriendCount"},
{20102, nullptr, "GetFriendDetailedInfo"},
{20103, nullptr, "SyncFriendList"},
{20104, nullptr, "RequestSyncFriendList"},
{20110, nullptr, "LoadFriendSetting"},
{20200, nullptr, "GetReceivedFriendRequestCount"},
{20201, nullptr, "GetFriendRequestList"},
{20300, nullptr, "GetFriendCandidateList"},
{20301, nullptr, "GetNintendoNetworkIdInfo"},
{20302, nullptr, "GetSnsAccountLinkage"},
{20303, nullptr, "GetSnsAccountProfile"},
{20304, nullptr, "GetSnsAccountFriendList"},
{20400, nullptr, "GetBlockedUserList"},
{20401, nullptr, "SyncBlockedUserList"},
{20500, nullptr, "GetProfileExtraList"},
{20501, nullptr, "GetRelationship"},
{20600, nullptr, "GetUserPresenceView"},
{20700, nullptr, "GetPlayHistoryList"},
{20701, nullptr, "GetPlayHistoryStatistics"},
{20800, nullptr, "LoadUserSetting"},
{20801, nullptr, "SyncUserSetting"},
{20900, nullptr, "RequestListSummaryOverlayNotification"},
{21000, nullptr, "GetExternalApplicationCatalog"},
{30100, nullptr, "DropFriendNewlyFlags"},
{30101, nullptr, "DeleteFriend"},
{30110, nullptr, "DropFriendNewlyFlag"},
{30120, nullptr, "ChangeFriendFavoriteFlag"},
{30121, nullptr, "ChangeFriendOnlineNotificationFlag"},
{30200, nullptr, "SendFriendRequest"},
{30201, nullptr, "SendFriendRequestWithApplicationInfo"},
{30202, nullptr, "CancelFriendRequest"},
{30203, nullptr, "AcceptFriendRequest"},
{30204, nullptr, "RejectFriendRequest"},
{30205, nullptr, "ReadFriendRequest"},
{30210, nullptr, "GetFacedFriendRequestRegistrationKey"},
{30211, nullptr, "AddFacedFriendRequest"},
{30212, nullptr, "CancelFacedFriendRequest"},
{30213, nullptr, "GetFacedFriendRequestProfileImage"},
{30214, nullptr, "GetFacedFriendRequestProfileImageFromPath"},
{30215, nullptr, "SendFriendRequestWithExternalApplicationCatalogId"},
{30216, nullptr, "ResendFacedFriendRequest"},
{30217, nullptr, "SendFriendRequestWithNintendoNetworkIdInfo"},
{30300, nullptr, "GetSnsAccountLinkPageUrl"},
{30301, nullptr, "UnlinkSnsAccount"},
{30400, nullptr, "BlockUser"},
{30401, nullptr, "BlockUserWithApplicationInfo"},
{30402, nullptr, "UnblockUser"},
{30500, nullptr, "GetProfileExtraFromFriendCode"},
{30700, nullptr, "DeletePlayHistory"},
{30810, nullptr, "ChangePresencePermission"},
{30811, nullptr, "ChangeFriendRequestReception"},
{30812, nullptr, "ChangePlayLogPermission"},
{30820, nullptr, "IssueFriendCode"},
{30830, nullptr, "ClearPlayLog"},
{49900, nullptr, "DeleteNetworkServiceAccountCache"},
};
RegisterHandlers(functions);
}
private:
void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) {
// Stub used by Splatoon 2
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
};
void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_Friend, "(STUBBED) called");
rb.PushIpcInterface<IFriendService>();
LOG_DEBUG(Service_ACC, "called");
}
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)

View File

@@ -6,6 +6,7 @@
#include <vector>
#include <boost/optional.hpp>
#include "common/common_funcs.h"
#include "common/math_util.h"
#include "common/swap.h"
#include "core/hle/kernel/event.h"

View File

@@ -83,13 +83,13 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
if (dir == nullptr) {
if (file == nullptr)
return ResultStatus::ErrorInvalidFormat;
return ResultStatus::ErrorNullFile;
dir = file->GetContainingDirectory();
}
const FileSys::VirtualFile npdm = dir->GetFile("main.npdm");
if (npdm == nullptr)
return ResultStatus::ErrorInvalidFormat;
return ResultStatus::ErrorMissingNPDM;
ResultStatus result = metadata.Load(npdm);
if (result != ResultStatus::Success) {
@@ -99,7 +99,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) {
return ResultStatus::ErrorUnsupportedArch;
return ResultStatus::Error32BitISA;
}
// Load NSO modules
@@ -143,28 +143,28 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& dir) {
if (romfs == nullptr)
return ResultStatus::ErrorNotUsed;
return ResultStatus::ErrorNoRomFS;
dir = romfs;
return ResultStatus::Success;
}
ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) {
if (icon_data.empty())
return ResultStatus::ErrorNotUsed;
return ResultStatus::ErrorNoIcon;
buffer = icon_data;
return ResultStatus::Success;
}
ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) {
if (name.empty())
return ResultStatus::ErrorNotUsed;
return ResultStatus::ErrorNoControl;
out_program_id = title_id;
return ResultStatus::Success;
}
ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) {
if (name.empty())
return ResultStatus::ErrorNotUsed;
return ResultStatus::ErrorNoControl;
title = name;
return ResultStatus::Success;
}

View File

@@ -390,7 +390,7 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
std::vector<u8> buffer = file->ReadAllBytes();
if (buffer.size() != file->GetSize())
return ResultStatus::Error;
return ResultStatus::ErrorIncorrectELFFileSize;
ElfReader elf_reader(&buffer[0]);
SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);

View File

@@ -86,6 +86,55 @@ std::string GetFileTypeString(FileType type) {
return "unknown";
}
constexpr std::array<const char*, 36> RESULT_MESSAGES{
"The operation completed successfully.",
"The loader requested to load is already loaded.",
"The operation is not implemented.",
"The loader is not initialized properly.",
"The NPDM file has a bad header.",
"The NPDM has a bad ACID header.",
"The NPDM has a bad ACI header,",
"The NPDM file has a bad file access control.",
"The NPDM has a bad file access header.",
"The PFS/HFS partition has a bad header.",
"The PFS/HFS partition has incorrect size as determined by the header.",
"The NCA file has a bad header.",
"The general keyfile could not be found.",
"The NCA Header key could not be found.",
"The NCA Header key is incorrect or the header is invalid.",
"Support for NCA2-type NCAs is not implemented.",
"Support for NCA0-type NCAs is not implemented.",
"The titlekey for this Rights ID could not be found.",
"The titlekek for this crypto revision could not be found.",
"The Rights ID in the header is invalid.",
"The key area key for this application type and crypto revision could not be found.",
"The key area key is incorrect or the section header is invalid.",
"The titlekey and/or titlekek is incorrect or the section header is invalid.",
"The XCI file is missing a Program-type NCA.",
"The NCA file is not an application.",
"The ExeFS partition could not be found.",
"The XCI file has a bad header.",
"The XCI file is missing a partition.",
"The file could not be found or does not exist.",
"The game is missing a program metadata file (main.npdm).",
"The game uses the currently-unimplemented 32-bit architecture.",
"The RomFS could not be found.",
"The ELF file has incorrect size as determined by the header.",
"There was a general error loading the NRO into emulated memory.",
"There is no icon available.",
"There is no control data available.",
};
std::string GetMessageForResultStatus(ResultStatus status) {
return GetMessageForResultStatus(static_cast<size_t>(status));
}
std::string GetMessageForResultStatus(u16 status) {
if (status >= 36)
return "";
return RESULT_MESSAGES[status];
}
/**
* Get a loader for a file with a specific type
* @param file The file to load

View File

@@ -58,18 +58,46 @@ std::string GetFileTypeString(FileType type);
/// Return type for functions in Loader namespace
enum class ResultStatus {
Success,
Error,
ErrorInvalidFormat,
ErrorNotImplemented,
ErrorNotLoaded,
ErrorNotUsed,
ErrorAlreadyLoaded,
ErrorMemoryAllocationFailed,
ErrorMissingKeys,
ErrorDecrypting,
ErrorUnsupportedArch,
ErrorNotImplemented,
ErrorNotInitialized,
ErrorBadNPDMHeader,
ErrorBadACIDHeader,
ErrorBadACIHeader,
ErrorBadFileAccessControl,
ErrorBadFileAccessHeader,
ErrorBadPFSHeader,
ErrorIncorrectPFSFileSize,
ErrorBadNCAHeader,
ErrorMissingProductionKeyFile,
ErrorMissingHeaderKey,
ErrorIncorrectHeaderKey,
ErrorNCA2,
ErrorNCA0,
ErrorMissingTitlekey,
ErrorMissingTitlekek,
ErrorInvalidRightsID,
ErrorMissingKeyAreaKey,
ErrorIncorrectKeyAreaKey,
ErrorIncorrectTitlekeyOrTitlekek,
ErrorXCIMissingProgramNCA,
ErrorNCANotProgram,
ErrorNoExeFS,
ErrorBadXCIHeader,
ErrorXCIMissingPartition,
ErrorNullFile,
ErrorMissingNPDM,
Error32BitISA,
ErrorNoRomFS,
ErrorIncorrectELFFileSize,
ErrorLoadingNRO,
ErrorNoIcon,
ErrorNoControl,
};
std::string GetMessageForResultStatus(ResultStatus status);
std::string GetMessageForResultStatus(u16 status);
/// Interface for loading an application
class AppLoader : NonCopyable {
public:

View File

@@ -46,12 +46,12 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
}
if (nca->GetType() != FileSys::NCAContentType::Program)
return ResultStatus::ErrorInvalidFormat;
return ResultStatus::ErrorNCANotProgram;
const auto exefs = nca->GetExeFS();
if (exefs == nullptr)
return ResultStatus::ErrorInvalidFormat;
return ResultStatus::ErrorNoExeFS;
directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs);
@@ -69,16 +69,16 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {
if (nca == nullptr)
return ResultStatus::ErrorNotLoaded;
return ResultStatus::ErrorNotInitialized;
if (nca->GetRomFS() == nullptr || nca->GetRomFS()->GetSize() == 0)
return ResultStatus::ErrorNotUsed;
return ResultStatus::ErrorNoRomFS;
dir = nca->GetRomFS();
return ResultStatus::Success;
}
ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
return ResultStatus::ErrorInvalidFormat;
return ResultStatus::ErrorNotInitialized;
out_program_id = nca->GetTitleId();
return ResultStatus::Success;
}

View File

@@ -182,7 +182,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR};
if (!LoadNro(file, base_addr)) {
return ResultStatus::ErrorInvalidFormat;
return ResultStatus::ErrorLoadingNRO;
}
process->svc_access_mask.set();
@@ -197,7 +197,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {
if (icon_data.empty()) {
return ResultStatus::ErrorNotUsed;
return ResultStatus::ErrorNoIcon;
}
buffer = icon_data;
@@ -206,7 +206,7 @@ ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {
ResultStatus AppLoader_NRO::ReadProgramId(u64& out_program_id) {
if (nacp == nullptr) {
return ResultStatus::ErrorNotUsed;
return ResultStatus::ErrorNoControl;
}
out_program_id = nacp->GetTitleId();
@@ -215,7 +215,7 @@ ResultStatus AppLoader_NRO::ReadProgramId(u64& out_program_id) {
ResultStatus AppLoader_NRO::ReadRomFS(FileSys::VirtualFile& dir) {
if (romfs == nullptr) {
return ResultStatus::ErrorNotUsed;
return ResultStatus::ErrorNoRomFS;
}
dir = romfs;
@@ -224,7 +224,7 @@ ResultStatus AppLoader_NRO::ReadRomFS(FileSys::VirtualFile& dir) {
ResultStatus AppLoader_NRO::ReadTitle(std::string& title) {
if (nacp == nullptr) {
return ResultStatus::ErrorNotUsed;
return ResultStatus::ErrorNoControl;
}
title = nacp->GetApplicationName();

View File

@@ -66,10 +66,13 @@ ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr<Kernel::Process>& process) {
return ResultStatus::ErrorAlreadyLoaded;
}
if (xci->GetStatus() != ResultStatus::Success)
return xci->GetStatus();
if (xci->GetNCAFileByType(FileSys::NCAContentType::Program) == nullptr) {
if (!Core::Crypto::KeyManager::KeyFileExists(false))
return ResultStatus::ErrorMissingKeys;
return ResultStatus::ErrorDecrypting;
return ResultStatus::ErrorMissingProductionKeyFile;
return ResultStatus::ErrorXCIMissingProgramNCA;
}
auto result = nca_loader->Load(process);
@@ -91,14 +94,14 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) {
if (icon_file == nullptr)
return ResultStatus::ErrorInvalidFormat;
return ResultStatus::ErrorNoControl;
buffer = icon_file->ReadAllBytes();
return ResultStatus::Success;
}
ResultStatus AppLoader_XCI::ReadTitle(std::string& title) {
if (nacp_file == nullptr)
return ResultStatus::ErrorInvalidFormat;
return ResultStatus::ErrorNoControl;
title = nacp_file->GetApplicationName();
return ResultStatus::Success;
}

View File

@@ -7,22 +7,18 @@
#include "core/hle/service/hid/hid.h"
#include "core/settings.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
namespace Settings {
Values values = {};
void Apply() {
GDBStub::SetServerPort(values.gdbstub_port);
GDBStub::ToggleServer(values.use_gdbstub);
VideoCore::g_toggle_framelimit_enabled = values.toggle_framelimit;
auto& system_instance = Core::System::GetInstance();
if (system_instance.IsPoweredOn()) {
system_instance.Renderer().UpdateCurrentFramebufferLayout();
system_instance.Renderer().RefreshBaseSettings();
}
Service::HID::ReloadInputDevices();

View File

@@ -30,8 +30,7 @@ union CommandHeader {
BitField<29, 3, SubmissionMode> mode;
};
static_assert(std::is_standard_layout<CommandHeader>::value == true,
"CommandHeader does not use standard layout");
static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout");
static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!");
} // namespace Tegra

View File

@@ -93,6 +93,7 @@ public:
struct VertexAttribute {
enum class Size : u32 {
Invalid = 0x0,
Size_32_32_32_32 = 0x01,
Size_32_32_32 = 0x02,
Size_16_16_16_16 = 0x03,
@@ -257,6 +258,10 @@ public:
bool IsNormalized() const {
return (type == Type::SignedNorm) || (type == Type::UnsignedNorm);
}
bool IsValid() const {
return size != Size::Invalid;
}
};
enum class PrimitiveTopology : u32 {
@@ -352,6 +357,27 @@ public:
OneMinusConstantColor = 0x62,
ConstantAlpha = 0x63,
OneMinusConstantAlpha = 0x64,
// These values are used by Nouveau and some games.
ZeroGL = 0x4000,
OneGL = 0x4001,
SourceColorGL = 0x4300,
OneMinusSourceColorGL = 0x4301,
SourceAlphaGL = 0x4302,
OneMinusSourceAlphaGL = 0x4303,
DestAlphaGL = 0x4304,
OneMinusDestAlphaGL = 0x4305,
DestColorGL = 0x4306,
OneMinusDestColorGL = 0x4307,
SourceAlphaSaturateGL = 0x4308,
ConstantColorGL = 0xc001,
OneMinusConstantColorGL = 0xc002,
ConstantAlphaGL = 0xc003,
OneMinusConstantAlphaGL = 0xc004,
Source1ColorGL = 0xc900,
OneMinusSource1ColorGL = 0xc901,
Source1AlphaGL = 0xc902,
OneMinusSource1AlphaGL = 0xc903,
};
u32 separate_alpha;

View File

@@ -74,12 +74,11 @@ union Attribute {
enum class Index : u64 {
Position = 7,
Attribute_0 = 8,
Attribute_31 = 39,
// This attribute contains a tuple of (~, ~, InstanceId, VertexId) when inside a vertex
// shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval
// shader.
TessCoordInstanceIDVertexID = 47,
// TODO(bunnei): Figure out what this is used for. Super Mario Odyssey uses this.
Unknown_63 = 63,
};
union {
@@ -477,8 +476,7 @@ union Instruction {
u64 value;
};
static_assert(sizeof(Instruction) == 0x8, "Incorrect structure size");
static_assert(std::is_standard_layout<Instruction>::value,
"Structure does not have standard layout");
static_assert(std::is_standard_layout_v<Instruction>, "Instruction is not standard layout");
class OpCode {
public:
@@ -598,6 +596,13 @@ public:
Unknown,
};
/// Returns whether an opcode has an execution predicate field or not (ie, whether it can be
/// conditionally executed).
static bool IsPredicatedInstruction(Id opcode) {
// TODO(Subv): Add the rest of unpredicated instructions.
return opcode != Id::SSY;
}
class Matcher {
public:
Matcher(const char* const name, u16 mask, u16 expected, OpCode::Id id, OpCode::Type type)

View File

@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/assert.h"
#include "video_core/engines/fermi_2d.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/engines/maxwell_compute.h"
@@ -11,6 +12,15 @@
namespace Tegra {
u32 FramebufferConfig::BytesPerPixel(PixelFormat format) {
switch (format) {
case PixelFormat::ABGR8:
return 4;
}
UNREACHABLE();
}
GPU::GPU(VideoCore::RasterizerInterface& rasterizer) {
memory_manager = std::make_unique<MemoryManager>();
maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager);
@@ -34,19 +44,54 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) {
switch (format) {
case RenderTargetFormat::RGBA32_FLOAT:
case RenderTargetFormat::RGBA32_UINT:
return 16;
case RenderTargetFormat::RGBA16_FLOAT:
case RenderTargetFormat::RG32_FLOAT:
return 8;
case RenderTargetFormat::RGBA8_UNORM:
case RenderTargetFormat::RGBA8_SNORM:
case RenderTargetFormat::RGBA8_SRGB:
case RenderTargetFormat::RGB10_A2_UNORM:
case RenderTargetFormat::BGRA8_UNORM:
case RenderTargetFormat::RG16_UNORM:
case RenderTargetFormat::RG16_SNORM:
case RenderTargetFormat::RG16_UINT:
case RenderTargetFormat::RG16_SINT:
case RenderTargetFormat::RG16_FLOAT:
case RenderTargetFormat::R32_FLOAT:
case RenderTargetFormat::R11G11B10_FLOAT:
return 4;
case RenderTargetFormat::R16_UNORM:
case RenderTargetFormat::R16_SNORM:
case RenderTargetFormat::R16_UINT:
case RenderTargetFormat::R16_SINT:
case RenderTargetFormat::R16_FLOAT:
case RenderTargetFormat::RG8_SNORM:
return 2;
case RenderTargetFormat::R8_UNORM:
case RenderTargetFormat::R8_UINT:
return 1;
default:
UNIMPLEMENTED_MSG("Unimplemented render target format {}", static_cast<u32>(format));
}
}
u32 DepthFormatBytesPerPixel(DepthFormat format) {
switch (format) {
case DepthFormat::Z32_S8_X24_FLOAT:
return 8;
case DepthFormat::Z32_FLOAT:
case DepthFormat::S8_Z24_UNORM:
case DepthFormat::Z24_X8_UNORM:
case DepthFormat::Z24_S8_UNORM:
case DepthFormat::Z24_C8_UNORM:
return 4;
case DepthFormat::Z16_UNORM:
return 2;
default:
UNIMPLEMENTED_MSG("Unimplemented Depth format {}", static_cast<u32>(format));
}
}
} // namespace Tegra

View File

@@ -6,7 +6,6 @@
#include <memory>
#include <unordered_map>
#include <vector>
#include "common/common_types.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
#include "video_core/memory_manager.h"
@@ -27,6 +26,7 @@ enum class RenderTargetFormat : u32 {
RGB10_A2_UNORM = 0xD1,
RGBA8_UNORM = 0xD5,
RGBA8_SRGB = 0xD6,
RGBA8_SNORM = 0xD7,
RG16_UNORM = 0xDA,
RG16_SNORM = 0xDB,
RG16_SINT = 0xDC,
@@ -35,8 +35,14 @@ enum class RenderTargetFormat : u32 {
R11G11B10_FLOAT = 0xE0,
R32_FLOAT = 0xE5,
B5G6R5_UNORM = 0xE8,
RG8_SNORM = 0xEB,
R16_UNORM = 0xEE,
R16_SNORM = 0xEF,
R16_SINT = 0xF0,
R16_UINT = 0xF1,
R16_FLOAT = 0xF2,
R8_UNORM = 0xF3,
R8_UINT = 0xF6,
};
enum class DepthFormat : u32 {
@@ -52,6 +58,9 @@ enum class DepthFormat : u32 {
/// Returns the number of bytes per pixel of each rendertarget format.
u32 RenderTargetBytesPerPixel(RenderTargetFormat format);
/// Returns the number of bytes per pixel of each depth format.
u32 DepthFormatBytesPerPixel(DepthFormat format);
class DebugContext;
/**
@@ -65,14 +74,7 @@ struct FramebufferConfig {
/**
* Returns the number of bytes per pixel.
*/
static u32 BytesPerPixel(PixelFormat format) {
switch (format) {
case PixelFormat::ABGR8:
return 4;
}
UNREACHABLE();
}
static u32 BytesPerPixel(PixelFormat format);
VAddr address;
u32 offset;

View File

@@ -4,18 +4,23 @@
#include <memory>
#include "core/frontend/emu_window.h"
#include "core/settings.h"
#include "video_core/renderer_base.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
namespace VideoCore {
RendererBase::RendererBase(EmuWindow& window) : render_window{window} {}
RendererBase::RendererBase(Core::Frontend::EmuWindow& window) : render_window{window} {
RefreshBaseSettings();
}
RendererBase::~RendererBase() = default;
void RendererBase::UpdateCurrentFramebufferLayout() {
const Layout::FramebufferLayout& layout = render_window.GetFramebufferLayout();
void RendererBase::RefreshBaseSettings() {
RefreshRasterizerSetting();
UpdateCurrentFramebufferLayout();
render_window.UpdateCurrentFramebufferLayout(layout.width, layout.height);
renderer_settings.use_framelimiter = Settings::values.toggle_framelimit;
}
void RendererBase::RefreshRasterizerSetting() {
@@ -24,4 +29,10 @@ void RendererBase::RefreshRasterizerSetting() {
}
}
void RendererBase::UpdateCurrentFramebufferLayout() {
const Layout::FramebufferLayout& layout = render_window.GetFramebufferLayout();
render_window.UpdateCurrentFramebufferLayout(layout.width, layout.height);
}
} // namespace VideoCore

View File

@@ -4,23 +4,26 @@
#pragma once
#include <atomic>
#include <memory>
#include <boost/optional.hpp>
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/gpu.h"
#include "video_core/rasterizer_interface.h"
namespace Core::Frontend {
class EmuWindow;
}
namespace VideoCore {
struct RendererSettings {
std::atomic_bool use_framelimiter{false};
};
class RendererBase : NonCopyable {
public:
/// Used to reference a framebuffer
enum kFramebuffer { kFramebuffer_VirtualXFB = 0, kFramebuffer_EFB, kFramebuffer_Texture };
explicit RendererBase(EmuWindow& window);
explicit RendererBase(Core::Frontend::EmuWindow& window);
virtual ~RendererBase();
/// Swap buffers (render frame)
@@ -32,9 +35,6 @@ public:
/// Shutdown the renderer
virtual void ShutDown() = 0;
/// Updates the framebuffer layout of the contained render window handle.
void UpdateCurrentFramebufferLayout();
// Getter/setter functions:
// ------------------------
@@ -54,13 +54,23 @@ public:
return *rasterizer;
}
void RefreshRasterizerSetting();
/// Refreshes the settings common to all renderers
void RefreshBaseSettings();
protected:
EmuWindow& render_window; ///< Reference to the render window handle.
/// Refreshes settings specific to the rasterizer.
void RefreshRasterizerSetting();
Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
std::unique_ptr<RasterizerInterface> rasterizer;
f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer
int m_current_frame = 0; ///< Current frame, should be set by the renderer
RendererSettings renderer_settings;
private:
/// Updates the framebuffer layout of the contained render window handle.
void UpdateCurrentFramebufferLayout();
};
} // namespace VideoCore

View File

@@ -36,7 +36,7 @@ MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192));
MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
RasterizerOpenGL::RasterizerOpenGL(EmuWindow& window) : emu_window{window} {
RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window) : emu_window{window} {
// Create sampler objects
for (size_t i = 0; i < texture_samplers.size(); ++i) {
texture_samplers[i].Create();
@@ -161,11 +161,16 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr,
// assume every shader uses them all.
for (unsigned index = 0; index < 16; ++index) {
auto& attrib = regs.vertex_attrib_format[index];
// Ignore invalid attributes.
if (!attrib.IsValid())
continue;
auto& buffer = regs.vertex_array[attrib.buffer];
LOG_TRACE(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}",
index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(),
attrib.offset.Value(), attrib.IsNormalized());
auto& buffer = regs.vertex_array[attrib.buffer];
ASSERT(buffer.IsEnabled());
glEnableVertexAttribArray(index);
@@ -211,7 +216,7 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
// Next available bindpoints to use when uploading the const buffers and textures to the GLSL
// shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
u32 current_constbuffer_bindpoint = uniform_buffers.size();
u32 current_constbuffer_bindpoint = static_cast<u32>(uniform_buffers.size());
u32 current_texture_bindpoint = 0;
for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
@@ -332,8 +337,6 @@ std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_c
// TODO(bunnei): Implement this
const bool has_stencil = false;
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
const bool write_color_fb =
state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE ||
state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE;
@@ -346,9 +349,10 @@ std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_c
Surface depth_surface;
MathUtil::Rectangle<u32> surfaces_rect;
std::tie(color_surface, depth_surface, surfaces_rect) =
res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, viewport_rect);
res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb);
MathUtil::Rectangle<u32> draw_rect{
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
const MathUtil::Rectangle<u32> draw_rect{
static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.left,
surfaces_rect.left, surfaces_rect.right)), // Left
static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.top,
@@ -812,9 +816,7 @@ void RasterizerOpenGL::SyncClipCoef() {
void RasterizerOpenGL::SyncCullMode() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
// TODO(bunnei): Enable the below once more things work - until then, this may hide regressions
// state.cull.enabled = regs.cull.enabled != 0;
state.cull.enabled = false;
state.cull.enabled = regs.cull.enabled != 0;
if (state.cull.enabled) {
state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face);

View File

@@ -21,12 +21,15 @@
#include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_stream_buffer.h"
class EmuWindow;
struct ScreenInfo;
namespace Core::Frontend {
class EmuWindow;
}
class RasterizerOpenGL : public VideoCore::RasterizerInterface {
public:
explicit RasterizerOpenGL(EmuWindow& renderer);
explicit RasterizerOpenGL(Core::Frontend::EmuWindow& renderer);
~RasterizerOpenGL() override;
void DrawArrays() override;
@@ -145,7 +148,7 @@ private:
RasterizerCacheOpenGL res_cache;
EmuWindow& emu_window;
Core::Frontend::EmuWindow& emu_window;
std::unique_ptr<GLShader::ProgramManager> shader_program_manager;
OGLVertexArray sw_vao;

View File

@@ -92,12 +92,14 @@ struct FormatTuple {
}
static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U
{GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S
{GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5
{GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm,
false}, // A2B10G10R10
{GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5
{GL_R8, GL_RED, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // R8
{GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // R8UI
{GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, ComponentType::Float, false}, // RGBA16F
{GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float,
false}, // R11FG11FB10F
@@ -122,6 +124,9 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
{GL_R32F, GL_RED, GL_FLOAT, ComponentType::Float, false}, // R32F
{GL_R16F, GL_RED, GL_HALF_FLOAT, ComponentType::Float, false}, // R16F
{GL_R16, GL_RED, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // R16UNORM
{GL_R16_SNORM, GL_RED, GL_SHORT, ComponentType::SNorm, false}, // R16S
{GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // R16UI
{GL_R16I, GL_RED_INTEGER, GL_SHORT, ComponentType::SInt, false}, // R16I
{GL_RG16, GL_RG, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // RG16
{GL_RG16F, GL_RG, GL_HALF_FLOAT, ComponentType::Float, false}, // RG16F
{GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // RG16UI
@@ -129,6 +134,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
{GL_RG16_SNORM, GL_RG, GL_SHORT, ComponentType::SNorm, false}, // RG16S
{GL_RGB32F, GL_RGB, GL_FLOAT, ComponentType::Float, false}, // RGB32F
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // SRGBA8
{GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S
// DepthStencil formats
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm,
@@ -183,6 +189,21 @@ MathUtil::Rectangle<u32> SurfaceParams::GetRect() const {
return {0, actual_height, width, 0};
}
/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
static bool IsFormatBCn(PixelFormat format) {
switch (format) {
case PixelFormat::DXT1:
case PixelFormat::DXT23:
case PixelFormat::DXT45:
case PixelFormat::DXN1:
case PixelFormat::DXN2SNORM:
case PixelFormat::DXN2UNORM:
case PixelFormat::BC7U:
return true;
}
return false;
}
template <bool morton_to_gl, PixelFormat format>
void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_buffer,
Tegra::GPUVAddr addr) {
@@ -191,16 +212,12 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_bu
const auto& gpu = Core::System::GetInstance().GPU();
if (morton_to_gl) {
std::vector<u8> data;
if (SurfaceParams::GetFormatType(format) == SurfaceType::ColorTexture) {
data = Tegra::Texture::UnswizzleTexture(
*gpu.memory_manager->GpuToCpuAddress(addr),
SurfaceParams::TextureFormatFromPixelFormat(format), stride, height, block_height);
} else {
data = Tegra::Texture::UnswizzleDepthTexture(
*gpu.memory_manager->GpuToCpuAddress(addr),
SurfaceParams::DepthFormatFromPixelFormat(format), stride, height, block_height);
}
// With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
// pixel values.
const u32 tile_size{IsFormatBCn(format) ? 4U : 1U};
const std::vector<u8> data =
Tegra::Texture::UnswizzleTexture(*gpu.memory_manager->GpuToCpuAddress(addr), tile_size,
bytes_per_pixel, stride, height, block_height);
const size_t size_to_copy{std::min(gl_buffer.size(), data.size())};
gl_buffer.assign(data.begin(), data.begin() + size_to_copy);
} else {
@@ -217,9 +234,10 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_bu
static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr),
SurfaceParams::MaxPixelFormat>
morton_to_gl_fns = {
MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>,
MortonCopy<true, PixelFormat::A2B10G10R10>, MortonCopy<true, PixelFormat::A1B5G5R5>,
MortonCopy<true, PixelFormat::R8>, MortonCopy<true, PixelFormat::RGBA16F>,
MortonCopy<true, PixelFormat::ABGR8U>, MortonCopy<true, PixelFormat::ABGR8S>,
MortonCopy<true, PixelFormat::B5G6R5>, MortonCopy<true, PixelFormat::A2B10G10R10>,
MortonCopy<true, PixelFormat::A1B5G5R5>, MortonCopy<true, PixelFormat::R8>,
MortonCopy<true, PixelFormat::R8UI>, MortonCopy<true, PixelFormat::RGBA16F>,
MortonCopy<true, PixelFormat::R11FG11FB10F>, MortonCopy<true, PixelFormat::RGBA32UI>,
MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>,
MortonCopy<true, PixelFormat::DXT45>, MortonCopy<true, PixelFormat::DXN1>,
@@ -228,10 +246,12 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPU
MortonCopy<true, PixelFormat::G8R8>, MortonCopy<true, PixelFormat::BGRA8>,
MortonCopy<true, PixelFormat::RGBA32F>, MortonCopy<true, PixelFormat::RG32F>,
MortonCopy<true, PixelFormat::R32F>, MortonCopy<true, PixelFormat::R16F>,
MortonCopy<true, PixelFormat::R16UNORM>, MortonCopy<true, PixelFormat::RG16>,
MortonCopy<true, PixelFormat::RG16F>, MortonCopy<true, PixelFormat::RG16UI>,
MortonCopy<true, PixelFormat::RG16I>, MortonCopy<true, PixelFormat::RG16S>,
MortonCopy<true, PixelFormat::RGB32F>, MortonCopy<true, PixelFormat::SRGBA8>,
MortonCopy<true, PixelFormat::R16UNORM>, MortonCopy<true, PixelFormat::R16S>,
MortonCopy<true, PixelFormat::R16UI>, MortonCopy<true, PixelFormat::R16I>,
MortonCopy<true, PixelFormat::RG16>, MortonCopy<true, PixelFormat::RG16F>,
MortonCopy<true, PixelFormat::RG16UI>, MortonCopy<true, PixelFormat::RG16I>,
MortonCopy<true, PixelFormat::RG16S>, MortonCopy<true, PixelFormat::RGB32F>,
MortonCopy<true, PixelFormat::SRGBA8>, MortonCopy<true, PixelFormat::RG8S>,
MortonCopy<true, PixelFormat::Z24S8>, MortonCopy<true, PixelFormat::S8Z24>,
MortonCopy<true, PixelFormat::Z32F>, MortonCopy<true, PixelFormat::Z16>,
MortonCopy<true, PixelFormat::Z32FS8>,
@@ -240,11 +260,13 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPU
static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr),
SurfaceParams::MaxPixelFormat>
gl_to_morton_fns = {
MortonCopy<false, PixelFormat::ABGR8>,
MortonCopy<false, PixelFormat::ABGR8U>,
MortonCopy<false, PixelFormat::ABGR8S>,
MortonCopy<false, PixelFormat::B5G6R5>,
MortonCopy<false, PixelFormat::A2B10G10R10>,
MortonCopy<false, PixelFormat::A1B5G5R5>,
MortonCopy<false, PixelFormat::R8>,
MortonCopy<false, PixelFormat::R8UI>,
MortonCopy<false, PixelFormat::RGBA16F>,
MortonCopy<false, PixelFormat::R11FG11FB10F>,
MortonCopy<false, PixelFormat::RGBA32UI>,
@@ -265,6 +287,9 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPU
MortonCopy<false, PixelFormat::R32F>,
MortonCopy<false, PixelFormat::R16F>,
MortonCopy<false, PixelFormat::R16UNORM>,
MortonCopy<false, PixelFormat::R16S>,
MortonCopy<false, PixelFormat::R16UI>,
MortonCopy<false, PixelFormat::R16I>,
MortonCopy<false, PixelFormat::RG16>,
MortonCopy<false, PixelFormat::RG16F>,
MortonCopy<false, PixelFormat::RG16UI>,
@@ -272,6 +297,7 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPU
MortonCopy<false, PixelFormat::RG16S>,
MortonCopy<false, PixelFormat::RGB32F>,
MortonCopy<false, PixelFormat::SRGBA8>,
MortonCopy<false, PixelFormat::RG8S>,
MortonCopy<false, PixelFormat::Z24S8>,
MortonCopy<false, PixelFormat::S8Z24>,
MortonCopy<false, PixelFormat::Z32F>,
@@ -611,8 +637,8 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu
return GetSurface(SurfaceParams::CreateForTexture(config));
}
SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle<s32>& viewport) {
SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(bool using_color_fb,
bool using_depth_fb) {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
// TODO(bunnei): This is hard corded to use just the first render buffer

View File

@@ -23,45 +23,51 @@ using PageMap = boost::icl::interval_map<u64, int>;
struct SurfaceParams {
enum class PixelFormat {
ABGR8 = 0,
B5G6R5 = 1,
A2B10G10R10 = 2,
A1B5G5R5 = 3,
R8 = 4,
RGBA16F = 5,
R11FG11FB10F = 6,
RGBA32UI = 7,
DXT1 = 8,
DXT23 = 9,
DXT45 = 10,
DXN1 = 11, // This is also known as BC4
DXN2UNORM = 12,
DXN2SNORM = 13,
BC7U = 14,
ASTC_2D_4X4 = 15,
G8R8 = 16,
BGRA8 = 17,
RGBA32F = 18,
RG32F = 19,
R32F = 20,
R16F = 21,
R16UNORM = 22,
RG16 = 23,
RG16F = 24,
RG16UI = 25,
RG16I = 26,
RG16S = 27,
RGB32F = 28,
SRGBA8 = 29,
ABGR8U = 0,
ABGR8S = 1,
B5G6R5 = 2,
A2B10G10R10 = 3,
A1B5G5R5 = 4,
R8 = 5,
R8UI = 6,
RGBA16F = 7,
R11FG11FB10F = 8,
RGBA32UI = 9,
DXT1 = 10,
DXT23 = 11,
DXT45 = 12,
DXN1 = 13, // This is also known as BC4
DXN2UNORM = 14,
DXN2SNORM = 15,
BC7U = 16,
ASTC_2D_4X4 = 17,
G8R8 = 18,
BGRA8 = 19,
RGBA32F = 20,
RG32F = 21,
R32F = 22,
R16F = 23,
R16UNORM = 24,
R16S = 25,
R16UI = 26,
R16I = 27,
RG16 = 28,
RG16F = 29,
RG16UI = 30,
RG16I = 31,
RG16S = 32,
RGB32F = 33,
SRGBA8 = 34,
RG8S = 35,
MaxColorFormat,
// DepthStencil formats
Z24S8 = 30,
S8Z24 = 31,
Z32F = 32,
Z16 = 33,
Z32FS8 = 34,
Z24S8 = 36,
S8Z24 = 37,
Z32F = 38,
Z16 = 39,
Z32FS8 = 40,
MaxDepthStencilFormat,
@@ -99,11 +105,13 @@ struct SurfaceParams {
return 0;
constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
1, // ABGR8
1, // ABGR8U
1, // ABGR8S
1, // B5G6R5
1, // A2B10G10R10
1, // A1B5G5R5
1, // R8
1, // R8UI
1, // RGBA16F
1, // R11FG11FB10F
1, // RGBA32UI
@@ -122,6 +130,9 @@ struct SurfaceParams {
1, // R32F
1, // R16F
1, // R16UNORM
1, // R16S
1, // R16UI
1, // R16I
1, // RG16
1, // RG16F
1, // RG16UI
@@ -129,6 +140,7 @@ struct SurfaceParams {
1, // RG16S
1, // RGB32F
1, // SRGBA8
1, // RG8S
1, // Z24S8
1, // S8Z24
1, // Z32F
@@ -145,11 +157,13 @@ struct SurfaceParams {
return 0;
constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
32, // ABGR8
32, // ABGR8U
32, // ABGR8S
16, // B5G6R5
32, // A2B10G10R10
16, // A1B5G5R5
8, // R8
8, // R8UI
64, // RGBA16F
32, // R11FG11FB10F
128, // RGBA32UI
@@ -168,6 +182,9 @@ struct SurfaceParams {
32, // R32F
16, // R16F
16, // R16UNORM
16, // R16S
16, // R16UI
16, // R16I
32, // RG16
32, // RG16F
32, // RG16UI
@@ -175,6 +192,7 @@ struct SurfaceParams {
32, // RG16S
96, // RGB32F
32, // SRGBA8
16, // RG8S
32, // Z24S8
32, // S8Z24
32, // Z32F
@@ -214,7 +232,9 @@ struct SurfaceParams {
// gamma.
case Tegra::RenderTargetFormat::RGBA8_SRGB:
case Tegra::RenderTargetFormat::RGBA8_UNORM:
return PixelFormat::ABGR8;
return PixelFormat::ABGR8U;
case Tegra::RenderTargetFormat::RGBA8_SNORM:
return PixelFormat::ABGR8S;
case Tegra::RenderTargetFormat::BGRA8_UNORM:
return PixelFormat::BGRA8;
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
@@ -233,6 +253,8 @@ struct SurfaceParams {
return PixelFormat::RGBA32UI;
case Tegra::RenderTargetFormat::R8_UNORM:
return PixelFormat::R8;
case Tegra::RenderTargetFormat::R8_UINT:
return PixelFormat::R8UI;
case Tegra::RenderTargetFormat::RG16_FLOAT:
return PixelFormat::RG16F;
case Tegra::RenderTargetFormat::RG16_UINT:
@@ -243,8 +265,18 @@ struct SurfaceParams {
return PixelFormat::RG16;
case Tegra::RenderTargetFormat::RG16_SNORM:
return PixelFormat::RG16S;
case Tegra::RenderTargetFormat::RG8_SNORM:
return PixelFormat::RG8S;
case Tegra::RenderTargetFormat::R16_FLOAT:
return PixelFormat::R16F;
case Tegra::RenderTargetFormat::R16_UNORM:
return PixelFormat::R16UNORM;
case Tegra::RenderTargetFormat::R16_SNORM:
return PixelFormat::R16S;
case Tegra::RenderTargetFormat::R16_UINT:
return PixelFormat::R16UI;
case Tegra::RenderTargetFormat::R16_SINT:
return PixelFormat::R16I;
case Tegra::RenderTargetFormat::R32_FLOAT:
return PixelFormat::R32F;
default:
@@ -258,7 +290,15 @@ struct SurfaceParams {
// TODO(Subv): Properly implement this
switch (format) {
case Tegra::Texture::TextureFormat::A8R8G8B8:
return PixelFormat::ABGR8;
switch (component_type) {
case Tegra::Texture::ComponentType::UNORM:
return PixelFormat::ABGR8U;
case Tegra::Texture::ComponentType::SNORM:
return PixelFormat::ABGR8S;
}
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
static_cast<u32>(component_type));
UNREACHABLE();
case Tegra::Texture::TextureFormat::B5G6R5:
return PixelFormat::B5G6R5;
case Tegra::Texture::TextureFormat::A2B10G10R10:
@@ -266,7 +306,15 @@ struct SurfaceParams {
case Tegra::Texture::TextureFormat::A1B5G5R5:
return PixelFormat::A1B5G5R5;
case Tegra::Texture::TextureFormat::R8:
return PixelFormat::R8;
switch (component_type) {
case Tegra::Texture::ComponentType::UNORM:
return PixelFormat::R8;
case Tegra::Texture::ComponentType::UINT:
return PixelFormat::R8UI;
}
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
static_cast<u32>(component_type));
UNREACHABLE();
case Tegra::Texture::TextureFormat::G8R8:
return PixelFormat::G8R8;
case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
@@ -293,6 +341,12 @@ struct SurfaceParams {
return PixelFormat::R16F;
case Tegra::Texture::ComponentType::UNORM:
return PixelFormat::R16UNORM;
case Tegra::Texture::ComponentType::SNORM:
return PixelFormat::R16S;
case Tegra::Texture::ComponentType::UINT:
return PixelFormat::R16UI;
case Tegra::Texture::ComponentType::SINT:
return PixelFormat::R16I;
}
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
static_cast<u32>(component_type));
@@ -348,92 +402,6 @@ struct SurfaceParams {
}
}
static Tegra::Texture::TextureFormat TextureFormatFromPixelFormat(PixelFormat format) {
// TODO(Subv): Properly implement this
switch (format) {
case PixelFormat::ABGR8:
case PixelFormat::SRGBA8:
return Tegra::Texture::TextureFormat::A8R8G8B8;
case PixelFormat::B5G6R5:
return Tegra::Texture::TextureFormat::B5G6R5;
case PixelFormat::A2B10G10R10:
return Tegra::Texture::TextureFormat::A2B10G10R10;
case PixelFormat::A1B5G5R5:
return Tegra::Texture::TextureFormat::A1B5G5R5;
case PixelFormat::R8:
return Tegra::Texture::TextureFormat::R8;
case PixelFormat::G8R8:
return Tegra::Texture::TextureFormat::G8R8;
case PixelFormat::RGBA16F:
return Tegra::Texture::TextureFormat::R16_G16_B16_A16;
case PixelFormat::R11FG11FB10F:
return Tegra::Texture::TextureFormat::BF10GF11RF11;
case PixelFormat::RGBA32UI:
return Tegra::Texture::TextureFormat::R32_G32_B32_A32;
case PixelFormat::DXT1:
return Tegra::Texture::TextureFormat::DXT1;
case PixelFormat::DXT23:
return Tegra::Texture::TextureFormat::DXT23;
case PixelFormat::DXT45:
return Tegra::Texture::TextureFormat::DXT45;
case PixelFormat::DXN1:
return Tegra::Texture::TextureFormat::DXN1;
case PixelFormat::DXN2UNORM:
case PixelFormat::DXN2SNORM:
return Tegra::Texture::TextureFormat::DXN2;
case PixelFormat::BC7U:
return Tegra::Texture::TextureFormat::BC7U;
case PixelFormat::ASTC_2D_4X4:
return Tegra::Texture::TextureFormat::ASTC_2D_4X4;
case PixelFormat::BGRA8:
// TODO(bunnei): This is fine for unswizzling (since we just need the right component
// sizes), but could be a bug if we used this function in different ways.
return Tegra::Texture::TextureFormat::A8R8G8B8;
case PixelFormat::RGBA32F:
return Tegra::Texture::TextureFormat::R32_G32_B32_A32;
case PixelFormat::RGB32F:
return Tegra::Texture::TextureFormat::R32_G32_B32;
case PixelFormat::RG32F:
return Tegra::Texture::TextureFormat::R32_G32;
case PixelFormat::R32F:
return Tegra::Texture::TextureFormat::R32;
case PixelFormat::R16F:
case PixelFormat::R16UNORM:
return Tegra::Texture::TextureFormat::R16;
case PixelFormat::Z32F:
return Tegra::Texture::TextureFormat::ZF32;
case PixelFormat::Z24S8:
return Tegra::Texture::TextureFormat::Z24S8;
case PixelFormat::RG16F:
case PixelFormat::RG16:
case PixelFormat::RG16UI:
case PixelFormat::RG16I:
case PixelFormat::RG16S:
return Tegra::Texture::TextureFormat::R16_G16;
default:
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
}
}
static Tegra::DepthFormat DepthFormatFromPixelFormat(PixelFormat format) {
switch (format) {
case PixelFormat::S8Z24:
return Tegra::DepthFormat::S8_Z24_UNORM;
case PixelFormat::Z24S8:
return Tegra::DepthFormat::Z24_S8_UNORM;
case PixelFormat::Z32F:
return Tegra::DepthFormat::Z32_FLOAT;
case PixelFormat::Z16:
return Tegra::DepthFormat::Z16_UNORM;
case PixelFormat::Z32FS8:
return Tegra::DepthFormat::Z32_S8_X24_FLOAT;
default:
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
}
}
static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
// TODO(Subv): Implement more component types
switch (type) {
@@ -462,9 +430,13 @@ struct SurfaceParams {
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
case Tegra::RenderTargetFormat::R8_UNORM:
case Tegra::RenderTargetFormat::RG16_UNORM:
case Tegra::RenderTargetFormat::R16_UNORM:
case Tegra::RenderTargetFormat::B5G6R5_UNORM:
return ComponentType::UNorm;
case Tegra::RenderTargetFormat::RGBA8_SNORM:
case Tegra::RenderTargetFormat::RG16_SNORM:
case Tegra::RenderTargetFormat::R16_SNORM:
case Tegra::RenderTargetFormat::RG8_SNORM:
return ComponentType::SNorm;
case Tegra::RenderTargetFormat::RGBA16_FLOAT:
case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
@@ -476,8 +448,11 @@ struct SurfaceParams {
return ComponentType::Float;
case Tegra::RenderTargetFormat::RGBA32_UINT:
case Tegra::RenderTargetFormat::RG16_UINT:
case Tegra::RenderTargetFormat::R8_UINT:
case Tegra::RenderTargetFormat::R16_UINT:
return ComponentType::UInt;
case Tegra::RenderTargetFormat::RG16_SINT:
case Tegra::RenderTargetFormat::R16_SINT:
return ComponentType::SInt;
default:
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
@@ -488,7 +463,7 @@ struct SurfaceParams {
static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
switch (format) {
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
return PixelFormat::ABGR8;
return PixelFormat::ABGR8U;
default:
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
@@ -634,8 +609,7 @@ public:
Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config);
/// Get the color and depth surfaces based on the framebuffer configuration
SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb,
const MathUtil::Rectangle<s32>& viewport);
SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb);
/// Flushes the surface to Switch memory
void FlushSurface(const Surface& surface);

View File

@@ -141,6 +141,15 @@ private:
ExitMethod jmp = Scan(target, end, labels);
return exit_method = ParallelExit(no_jmp, jmp);
}
case OpCode::Id::SSY: {
// The SSY instruction uses a similar encoding as the BRA instruction.
ASSERT_MSG(instr.bra.constant_buffer == 0,
"Constant buffer SSY is not supported");
u32 target = offset + instr.bra.GetBranchTarget();
labels.insert(target);
// Continue scanning for an exit method.
break;
}
}
}
}
@@ -349,7 +358,12 @@ public:
void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) {
std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem);
std::string src = GetRegisterAsFloat(reg);
shader.AddLine(dest + " = " + src + ';');
if (!dest.empty()) {
// Can happen with unknown/unimplemented output attributes, in which case we ignore the
// instruction for now.
shader.AddLine(dest + " = " + src + ';');
}
}
/// Generates code representing a uniform (C buffer) register, interpreted as the input type.
@@ -525,20 +539,16 @@ private:
// shader.
ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex);
return "vec4(0, 0, uintBitsToFloat(gl_InstanceID), uintBitsToFloat(gl_VertexID))";
case Attribute::Index::Unknown_63:
// TODO(bunnei): Figure out what this is used for. Super Mario Odyssey uses this.
LOG_CRITICAL(HW_GPU, "Unhandled input attribute Unknown_63");
UNREACHABLE();
break;
default:
const u32 index{static_cast<u32>(attribute) -
static_cast<u32>(Attribute::Index::Attribute_0)};
if (attribute >= Attribute::Index::Attribute_0) {
if (attribute >= Attribute::Index::Attribute_0 &&
attribute <= Attribute::Index::Attribute_31) {
declr_input_attribute.insert(attribute);
return "input_attribute_" + std::to_string(index);
}
LOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", index);
LOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", static_cast<u32>(attribute));
UNREACHABLE();
}
@@ -560,6 +570,7 @@ private:
LOG_CRITICAL(HW_GPU, "Unhandled output attribute: {}", index);
UNREACHABLE();
return {};
}
}
@@ -828,7 +839,11 @@ private:
ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute,
"NeverExecute predicate not implemented");
if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
// Some instructions (like SSY) don't have a predicate field, they are always
// unconditionally executed.
bool can_be_predicated = OpCode::IsPredicatedInstruction(opcode->GetId());
if (can_be_predicated && instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
shader.AddLine("if (" +
GetPredicateCondition(instr.pred.pred_index, instr.negate_pred != 0) +
')');
@@ -1652,7 +1667,15 @@ private:
}
case OpCode::Id::KIL: {
ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
// Enclose "discard" in a conditional, so that GLSL compilation does not complain
// about unexecuted instructions that may follow this.
shader.AddLine("if (true) {");
++shader.scope;
shader.AddLine("discard;");
--shader.scope;
shader.AddLine("}");
break;
}
case OpCode::Id::BRA: {
@@ -1668,16 +1691,25 @@ private:
break;
}
case OpCode::Id::SSY: {
// The SSY opcode tells the GPU where to re-converge divergent execution paths, we
// can ignore this when generating GLSL code.
// The SSY opcode tells the GPU where to re-converge divergent execution paths, it
// sets the target of the jump that the SYNC instruction will make. The SSY opcode
// has a similar structure to the BRA opcode.
ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer SSY is not supported");
u32 target = offset + instr.bra.GetBranchTarget();
shader.AddLine("ssy_target = " + std::to_string(target) + "u;");
break;
}
case OpCode::Id::SYNC:
case OpCode::Id::SYNC: {
// The SYNC opcode jumps to the address previously set by the SSY opcode
ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
shader.AddLine("{ jmp_to = ssy_target; break; }");
break;
}
case OpCode::Id::DEPBAR: {
// TODO(Subv): Find out if we actually have to care about these instructions or if
// TODO(Subv): Find out if we actually have to care about this instruction or if
// the GLSL compiler takes care of that for us.
LOG_WARNING(HW_GPU, "DEPBAR/SYNC instruction is stubbed");
LOG_WARNING(HW_GPU, "DEPBAR instruction is stubbed");
break;
}
default: {
@@ -1691,7 +1723,7 @@ private:
}
// Close the predicate condition scope.
if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
if (can_be_predicated && instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
--shader.scope;
shader.AddLine('}');
}
@@ -1742,6 +1774,7 @@ private:
} else {
labels.insert(subroutine.begin);
shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;");
shader.AddLine("uint ssy_target = 0u;");
shader.AddLine("while (true) {");
++shader.scope;
@@ -1757,7 +1790,7 @@ private:
u32 compile_end = CompileRange(label, next_label);
if (compile_end > next_label && compile_end != PROGRAM_END) {
// This happens only when there is a label inside a IF/LOOP block
shader.AddLine("{ jmp_to = " + std::to_string(compile_end) + "u; break; }");
shader.AddLine(" jmp_to = " + std::to_string(compile_end) + "u; break; }");
labels.emplace(compile_end);
}

View File

@@ -45,6 +45,9 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
case Maxwell::VertexAttribute::Type::SignedNorm: {
switch (attrib.size) {
case Maxwell::VertexAttribute::Size::Size_32_32_32:
return GL_INT;
case Maxwell::VertexAttribute::Size::Size_8_8:
case Maxwell::VertexAttribute::Size::Size_8_8_8_8:
return GL_BYTE;
case Maxwell::VertexAttribute::Size::Size_16_16:
@@ -153,42 +156,61 @@ inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
inline GLenum BlendFunc(Maxwell::Blend::Factor factor) {
switch (factor) {
case Maxwell::Blend::Factor::Zero:
case Maxwell::Blend::Factor::ZeroGL:
return GL_ZERO;
case Maxwell::Blend::Factor::One:
case Maxwell::Blend::Factor::OneGL:
return GL_ONE;
case Maxwell::Blend::Factor::SourceColor:
case Maxwell::Blend::Factor::SourceColorGL:
return GL_SRC_COLOR;
case Maxwell::Blend::Factor::OneMinusSourceColor:
case Maxwell::Blend::Factor::OneMinusSourceColorGL:
return GL_ONE_MINUS_SRC_COLOR;
case Maxwell::Blend::Factor::SourceAlpha:
case Maxwell::Blend::Factor::SourceAlphaGL:
return GL_SRC_ALPHA;
case Maxwell::Blend::Factor::OneMinusSourceAlpha:
case Maxwell::Blend::Factor::OneMinusSourceAlphaGL:
return GL_ONE_MINUS_SRC_ALPHA;
case Maxwell::Blend::Factor::DestAlpha:
case Maxwell::Blend::Factor::DestAlphaGL:
return GL_DST_ALPHA;
case Maxwell::Blend::Factor::OneMinusDestAlpha:
case Maxwell::Blend::Factor::OneMinusDestAlphaGL:
return GL_ONE_MINUS_DST_ALPHA;
case Maxwell::Blend::Factor::DestColor:
case Maxwell::Blend::Factor::DestColorGL:
return GL_DST_COLOR;
case Maxwell::Blend::Factor::OneMinusDestColor:
case Maxwell::Blend::Factor::OneMinusDestColorGL:
return GL_ONE_MINUS_DST_COLOR;
case Maxwell::Blend::Factor::SourceAlphaSaturate:
case Maxwell::Blend::Factor::SourceAlphaSaturateGL:
return GL_SRC_ALPHA_SATURATE;
case Maxwell::Blend::Factor::Source1Color:
case Maxwell::Blend::Factor::Source1ColorGL:
return GL_SRC1_COLOR;
case Maxwell::Blend::Factor::OneMinusSource1Color:
case Maxwell::Blend::Factor::OneMinusSource1ColorGL:
return GL_ONE_MINUS_SRC1_COLOR;
case Maxwell::Blend::Factor::Source1Alpha:
case Maxwell::Blend::Factor::Source1AlphaGL:
return GL_SRC1_ALPHA;
case Maxwell::Blend::Factor::OneMinusSource1Alpha:
case Maxwell::Blend::Factor::OneMinusSource1AlphaGL:
return GL_ONE_MINUS_SRC1_ALPHA;
case Maxwell::Blend::Factor::ConstantColor:
case Maxwell::Blend::Factor::ConstantColorGL:
return GL_CONSTANT_COLOR;
case Maxwell::Blend::Factor::OneMinusConstantColor:
case Maxwell::Blend::Factor::OneMinusConstantColorGL:
return GL_ONE_MINUS_CONSTANT_COLOR;
case Maxwell::Blend::Factor::ConstantAlpha:
case Maxwell::Blend::Factor::ConstantAlphaGL:
return GL_CONSTANT_ALPHA;
case Maxwell::Blend::Factor::OneMinusConstantAlpha:
case Maxwell::Blend::Factor::OneMinusConstantAlphaGL:
return GL_ONE_MINUS_CONSTANT_ALPHA;
}
LOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor));

View File

@@ -18,7 +18,6 @@
#include "core/tracer/recorder.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
#include "video_core/utils.h"
#include "video_core/video_core.h"
static const char vertex_shader[] = R"(
#version 150 core
@@ -92,7 +91,8 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons
return matrix;
}
ScopeAcquireGLContext::ScopeAcquireGLContext(EmuWindow& emu_window_) : emu_window{emu_window_} {
ScopeAcquireGLContext::ScopeAcquireGLContext(Core::Frontend::EmuWindow& emu_window_)
: emu_window{emu_window_} {
if (Settings::values.use_multi_core) {
emu_window.MakeCurrent();
}
@@ -103,7 +103,9 @@ ScopeAcquireGLContext::~ScopeAcquireGLContext() {
}
}
RendererOpenGL::RendererOpenGL(EmuWindow& window) : VideoCore::RendererBase{window} {}
RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& window)
: VideoCore::RendererBase{window} {}
RendererOpenGL::~RendererOpenGL() = default;
/// Swap buffers (render frame)

View File

@@ -12,7 +12,9 @@
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_state.h"
namespace Core::Frontend {
class EmuWindow;
}
/// Structure used for storing information about the textures for the Switch screen
struct TextureInfo {
@@ -34,16 +36,16 @@ struct ScreenInfo {
/// Helper class to acquire/release OpenGL context within a given scope
class ScopeAcquireGLContext : NonCopyable {
public:
explicit ScopeAcquireGLContext(EmuWindow& window);
explicit ScopeAcquireGLContext(Core::Frontend::EmuWindow& window);
~ScopeAcquireGLContext();
private:
EmuWindow& emu_window;
Core::Frontend::EmuWindow& emu_window;
};
class RendererOpenGL : public VideoCore::RendererBase {
public:
explicit RendererOpenGL(EmuWindow& window);
explicit RendererOpenGL(Core::Frontend::EmuWindow& window);
~RendererOpenGL() override;
/// Swap buffers (render frame)

View File

@@ -86,88 +86,11 @@ u32 BytesPerPixel(TextureFormat format) {
}
}
static u32 DepthBytesPerPixel(DepthFormat format) {
switch (format) {
case DepthFormat::Z16_UNORM:
return 2;
case DepthFormat::S8_Z24_UNORM:
case DepthFormat::Z24_S8_UNORM:
case DepthFormat::Z32_FLOAT:
return 4;
case DepthFormat::Z32_S8_X24_FLOAT:
return 8;
default:
UNIMPLEMENTED_MSG("Format not implemented");
break;
}
}
std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height,
u32 block_height) {
u8* data = Memory::GetPointer(address);
u32 bytes_per_pixel = BytesPerPixel(format);
std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width,
u32 height, u32 block_height) {
std::vector<u8> unswizzled_data(width * height * bytes_per_pixel);
switch (format) {
case TextureFormat::DXT1:
case TextureFormat::DXT23:
case TextureFormat::DXT45:
case TextureFormat::DXN1:
case TextureFormat::DXN2:
case TextureFormat::BC7U:
// In the DXT and DXN formats, each 4x4 tile is swizzled instead of just individual pixel
// values.
CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data,
unswizzled_data.data(), true, block_height);
break;
case TextureFormat::A8R8G8B8:
case TextureFormat::A2B10G10R10:
case TextureFormat::A1B5G5R5:
case TextureFormat::B5G6R5:
case TextureFormat::R8:
case TextureFormat::G8R8:
case TextureFormat::R16_G16_B16_A16:
case TextureFormat::R32_G32_B32_A32:
case TextureFormat::R32_G32:
case TextureFormat::R32:
case TextureFormat::R16:
case TextureFormat::R16_G16:
case TextureFormat::BF10GF11RF11:
case TextureFormat::ASTC_2D_4X4:
case TextureFormat::R32_G32_B32:
CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data,
unswizzled_data.data(), true, block_height);
break;
default:
UNIMPLEMENTED_MSG("Format not implemented");
break;
}
return unswizzled_data;
}
std::vector<u8> UnswizzleDepthTexture(VAddr address, DepthFormat format, u32 width, u32 height,
u32 block_height) {
u8* data = Memory::GetPointer(address);
u32 bytes_per_pixel = DepthBytesPerPixel(format);
std::vector<u8> unswizzled_data(width * height * bytes_per_pixel);
switch (format) {
case DepthFormat::Z16_UNORM:
case DepthFormat::S8_Z24_UNORM:
case DepthFormat::Z24_S8_UNORM:
case DepthFormat::Z32_FLOAT:
case DepthFormat::Z32_S8_X24_FLOAT:
CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data,
unswizzled_data.data(), true, block_height);
break;
default:
UNIMPLEMENTED_MSG("Format not implemented");
break;
}
CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel,
Memory::GetPointer(address), unswizzled_data.data(), true, block_height);
return unswizzled_data;
}

View File

@@ -13,8 +13,8 @@ namespace Tegra::Texture {
/**
* Unswizzles a swizzled texture without changing its format.
*/
std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height,
u32 block_height = TICEntry::DefaultBlockHeight);
std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width,
u32 height, u32 block_height = TICEntry::DefaultBlockHeight);
/**
* Unswizzles a swizzled depth texture without changing its format.

View File

@@ -9,9 +9,7 @@
namespace VideoCore {
std::atomic<bool> g_toggle_framelimit_enabled;
std::unique_ptr<RendererBase> CreateRenderer(EmuWindow& emu_window) {
std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window) {
return std::make_unique<RendererOpenGL>(emu_window);
}

View File

@@ -4,27 +4,22 @@
#pragma once
#include <atomic>
#include <memory>
namespace Core::Frontend {
class EmuWindow;
}
namespace VideoCore {
class RendererBase;
enum class Renderer { Software, OpenGL };
// TODO: Wrap these in a user settings struct along with any other graphics settings (often set from
// qt ui)
extern std::atomic<bool> g_toggle_framelimit_enabled;
/**
* Creates a renderer instance.
*
* @note The returned renderer instance is simply allocated. Its Init()
* function still needs to be called to fully complete its setup.
*/
std::unique_ptr<RendererBase> CreateRenderer(EmuWindow& emu_window);
std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window);
} // namespace VideoCore

View File

@@ -101,7 +101,7 @@ signals:
void ErrorThrown(Core::System::ResultStatus, std::string);
};
class GRenderWindow : public QWidget, public EmuWindow {
class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow {
Q_OBJECT
public:

View File

@@ -383,8 +383,10 @@ void GraphicsSurfaceWidget::OnUpdate() {
QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32);
boost::optional<VAddr> address = gpu.memory_manager->GpuToCpuAddress(surface_address);
auto unswizzled_data =
Tegra::Texture::UnswizzleTexture(*address, surface_format, surface_width, surface_height);
// TODO(bunnei): Will not work with BCn formats that swizzle 4x4 tiles.
// Needs to be fixed if we plan to use this feature more, otherwise we may remove it.
auto unswizzled_data = Tegra::Texture::UnswizzleTexture(
*address, 1, Tegra::Texture::BytesPerPixel(surface_format), surface_width, surface_height);
auto texture_data = Tegra::Texture::DecodeTexture(unswizzled_data, surface_format,
surface_width, surface_height);

View File

@@ -453,10 +453,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
std::string name = " ";
const auto res3 = loader->ReadTitle(name);
if ((res1 == Loader::ResultStatus::ErrorNotUsed ||
res1 == Loader::ResultStatus::ErrorNotImplemented) &&
(res3 == Loader::ResultStatus::ErrorNotUsed ||
res3 == Loader::ResultStatus::ErrorNotImplemented) &&
if (res1 != Loader::ResultStatus::Success && res3 != Loader::ResultStatus::Success &&
res2 == Loader::ResultStatus::Success) {
// Use from metadata pool.
if (nca_control_map.find(program_id) != nca_control_map.end()) {

View File

@@ -4,6 +4,7 @@
#pragma once
#include <array>
#include <atomic>
#include <utility>
#include <QImage>
@@ -39,7 +40,6 @@ public:
* If this class receives valid SMDH data, it will also display game icons and titles.
*/
class GameListItemPath : public GameListItem {
public:
static const int FullPathRole = Qt::UserRole + 1;
static const int TitleRole = Qt::UserRole + 2;
@@ -48,18 +48,18 @@ public:
GameListItemPath() = default;
GameListItemPath(const QString& game_path, const std::vector<u8>& picture_data,
const QString& game_name, const QString& game_type, u64 program_id)
: GameListItem() {
const QString& game_name, const QString& game_type, u64 program_id) {
setData(game_path, FullPathRole);
setData(game_name, TitleRole);
setData(qulonglong(program_id), ProgramIdRole);
setData(game_type, FileTypeRole);
QPixmap picture;
u32 size = UISettings::values.icon_size;
if (!picture.loadFromData(picture_data.data(), picture_data.size()))
picture = GetDefaultIcon(size);
const u32 size = UISettings::values.icon_size;
QPixmap picture;
if (!picture.loadFromData(picture_data.data(), static_cast<u32>(picture_data.size()))) {
picture = GetDefaultIcon(size);
}
picture = picture.scaled(size, size);
setData(picture, Qt::DecorationRole);
@@ -70,17 +70,16 @@ public:
std::string filename;
Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename,
nullptr);
QString title = data(TitleRole).toString();
std::vector<QString> row_data{
const std::array<QString, 4> row_data{{
QString::fromStdString(filename),
data(FileTypeRole).toString(),
QString::fromStdString(fmt::format("0x{:016X}", data(ProgramIdRole).toULongLong())),
data(TitleRole).toString(),
};
}};
auto row1 = row_data.at(UISettings::values.row_1_text_id);
auto row2 = row_data.at(UISettings::values.row_2_text_id);
const auto& row1 = row_data.at(UISettings::values.row_1_text_id);
const auto& row2 = row_data.at(UISettings::values.row_2_text_id);
if (row1.isEmpty() || row1 == row2)
return row2;
@@ -88,9 +87,9 @@ public:
return row1;
return row1 + "\n " + row2;
} else {
return GameListItem::data(role);
}
return GameListItem::data(role);
}
};

View File

@@ -424,67 +424,11 @@ bool GMainWindow::LoadROM(const QString& filename) {
QMessageBox::critical(this, tr("Error while loading ROM!"),
tr("The ROM format is not supported."));
break;
case Core::System::ResultStatus::ErrorUnsupportedArch:
LOG_CRITICAL(Frontend, "Unsupported architecture detected!", filename.toStdString());
QMessageBox::critical(this, tr("Error while loading ROM!"),
tr("The ROM uses currently unusable 32-bit architecture"));
break;
case Core::System::ResultStatus::ErrorSystemMode:
LOG_CRITICAL(Frontend, "Failed to load ROM!");
QMessageBox::critical(this, tr("Error while loading ROM!"),
tr("Could not determine the system mode."));
break;
case Core::System::ResultStatus::ErrorLoader_ErrorMissingKeys: {
const auto reg_found = Core::Crypto::KeyManager::KeyFileExists(false);
const auto title_found = Core::Crypto::KeyManager::KeyFileExists(true);
std::string file_text;
if (!reg_found && !title_found) {
file_text = "A proper key file (prod.keys, dev.keys, or title.keys) could not be "
"found. You will need to dump your keys from your switch to continue.";
} else if (reg_found && title_found) {
file_text =
"Both key files were found in your config directory, but the correct key could"
"not be found. You may be missing a titlekey or general key, depending on "
"the game.";
} else if (reg_found) {
file_text =
"The regular keys file (prod.keys/dev.keys) was found in your config, but the "
"titlekeys file (title.keys) was not. You are either missing the correct "
"titlekey or missing a general key required to decrypt the game.";
} else {
file_text = "The title keys file (title.keys) was found in your config, but "
"the regular keys file (prod.keys/dev.keys) was not. Unfortunately, "
"having the titlekey is not enough, you need additional general keys "
"to properly decrypt the game. You should double-check to make sure "
"your keys are correct.";
}
QMessageBox::critical(
this, tr("Error while loading ROM!"),
tr(("The game you are trying to load is encrypted and the required keys to load "
"the game could not be found in your configuration. " +
file_text + " Please refer to the yuzu wiki for help.")
.c_str()));
break;
}
case Core::System::ResultStatus::ErrorLoader_ErrorDecrypting: {
QMessageBox::critical(
this, tr("Error while loading ROM!"),
tr("There was a general error while decrypting the game. This means that the keys "
"necessary were found, but were either incorrect, the game itself was not a "
"valid game or the game uses an unhandled cryptographic scheme. Please double "
"check that you have the correct "
"keys."));
break;
}
case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
QMessageBox::critical(this, tr("Error while loading ROM!"),
tr("The ROM format is not supported."));
break;
case Core::System::ResultStatus::ErrorVideoCore:
QMessageBox::critical(
this, tr("An error occurred initializing the video core."),
@@ -499,9 +443,23 @@ bool GMainWindow::LoadROM(const QString& filename) {
break;
default:
QMessageBox::critical(
this, tr("Error while loading ROM!"),
tr("An unknown error occurred. Please see the log for more details."));
if (static_cast<u32>(result) >
static_cast<u32>(Core::System::ResultStatus::ErrorLoader)) {
LOG_CRITICAL(Frontend, "Failed to load ROM!");
const u16 loader_id = static_cast<u16>(Core::System::ResultStatus::ErrorLoader);
const u16 error_id = static_cast<u16>(result) - loader_id;
QMessageBox::critical(
this, tr("Error while loading ROM!"),
QString::fromStdString(fmt::format(
"While attempting to load the ROM requested, an error occured. Please "
"refer to the yuzu wiki for more information or the yuzu discord for "
"additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
loader_id, error_id, Loader::GetMessageForResultStatus(error_id))));
} else {
QMessageBox::critical(
this, tr("Error while loading ROM!"),
tr("An unknown error occurred. Please see the log for more details."));
}
break;
}
return false;

View File

@@ -10,7 +10,7 @@
struct SDL_Window;
class EmuWindow_SDL2 : public EmuWindow {
class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
public:
explicit EmuWindow_SDL2(bool fullscreen);
~EmuWindow_SDL2();

View File

@@ -174,19 +174,6 @@ int main(int argc, char** argv) {
case Core::System::ResultStatus::ErrorLoader:
LOG_CRITICAL(Frontend, "Failed to load ROM!");
return -1;
case Core::System::ResultStatus::ErrorLoader_ErrorMissingKeys:
LOG_CRITICAL(Frontend, "The game you are trying to load is encrypted and the keys required "
"could not be found. Please refer to the yuzu wiki for help");
return -1;
case Core::System::ResultStatus::ErrorLoader_ErrorDecrypting:
LOG_CRITICAL(Frontend, "The game you are trying to load is encrypted and there was a "
"general error while decrypting. This could mean that the keys are "
"incorrect, game is invalid or game uses an unsupported method of "
"crypto. Please double-check your keys");
return -1;
case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
LOG_CRITICAL(Frontend, "Error while loading ROM: The ROM format is not supported.");
return -1;
case Core::System::ResultStatus::ErrorNotInitialized:
LOG_CRITICAL(Frontend, "CPUCore not initialized");
return -1;
@@ -198,6 +185,17 @@ int main(int argc, char** argv) {
return -1;
case Core::System::ResultStatus::Success:
break; // Expected case
default:
if (static_cast<u32>(load_result) >
static_cast<u32>(Core::System::ResultStatus::ErrorLoader)) {
const u16 loader_id = static_cast<u16>(Core::System::ResultStatus::ErrorLoader);
const u16 error_id = static_cast<u16>(load_result) - loader_id;
LOG_CRITICAL(Frontend,
"While attempting to load the ROM requested, an error occured. Please "
"refer to the yuzu wiki for more information or the yuzu discord for "
"additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
loader_id, error_id, Loader::GetMessageForResultStatus(error_id));
}
}
Core::Telemetry().AddField(Telemetry::FieldType::App, "Frontend", "SDL");