Compare commits

...

47 Commits

Author SHA1 Message Date
fearlessTobi
3dd8175238 Fix compilation 2018-08-23 15:57:41 +02:00
fearlessTobi
44a4fd4d37 Port #4013 from Citra: "Init logging sooner so we dont miss some logs on startup" 2018-08-21 13:36:43 +02:00
bunnei
bf89a99839 Merge pull request #1123 from lioncash/screen
rasterizer_interface: Remove renderer-specific ScreenInfo type from AccelerateDraw() in RasterizerInterface
2018-08-21 01:18:34 -04:00
bunnei
79243b6fa0 Merge pull request #1129 from lioncash/header
romfs_factory, service/filesystem: Use forward declarations where applicable
2018-08-21 01:18:04 -04:00
bunnei
b0f7713fce Merge pull request #1132 from Subv/gl_FragDepth
Shaders: Implement depth writing in fragment shaders.
2018-08-21 01:17:53 -04:00
bunnei
8c9abe1d41 Merge pull request #1134 from lioncash/log
renderer_opengl: Use LOG_DEBUG for GL_DEBUG_SEVERITY_NOTIFICATION and GL_DEBUG_SEVERITY_LOW logs
2018-08-21 01:17:31 -04:00
bunnei
ca58929eb0 Merge pull request #1121 from Subv/tex_reinterpret
Rasterizer: Use PBOs to reinterpret texture formats when games re-use the same memory.
2018-08-21 01:06:40 -04:00
Lioncash
523e4be02c renderer_opengl: Use LOG_DEBUG for GL_DEBUG_SEVERITY_NOTIFICATION and GL_DEBUG_SEVERITY_LOW logs
LOG_TRACE is only enabled on debug builds which can be quite slow when
trying to debug graphics issues. Instead we can log the messages to the
debug log, which is available on both release and debug builds.
2018-08-21 00:23:09 -04:00
bunnei
fde3b1b6f2 Merge pull request #1133 from lioncash/guard
gl_stream_buffer: Add missing header guard
2018-08-20 23:37:55 -04:00
Lioncash
477eee3993 service/filesystem: Use forward declarations where applicable
Avoids the need to rebuild multiple source files if the filesystem code
headers change.

This also gets rid of a few instances of indirect inclusions being
relied upon
2018-08-20 23:28:46 -04:00
Lioncash
93a4097e9d gl_stream_buffer: Add missing header guard
Prevents potential compilation errors from occuring due to multiple
inclusions
2018-08-20 23:25:08 -04:00
Subv
e3bddf8137 Shaders: Implement depth writing in fragment shaders.
We'll write <last color output reg + 2> to gl_FragDepth.
2018-08-20 21:57:56 -05:00
bunnei
c4ce7e456a Merge pull request #1126 from lioncash/telem
telemetry_session: Don't allocate std::string instances for program lifetime in GetTelemetryId() and RegenerateTelemetryId()
2018-08-20 22:15:56 -04:00
bunnei
e33452f7e8 Merge pull request #1131 from bunnei/impl-tex3d-texcube
gl_shader_decompiler: Implement TextureCube/Texture3D for TEX/TEXS.
2018-08-20 22:15:18 -04:00
bunnei
5aaee2ff8d Merge pull request #1106 from Subv/multiple_rendertargets
Shaders: Write all the enabled color outputs when a fragment shader exits.
2018-08-20 21:56:06 -04:00
bunnei
2ae88feea7 shader_bytecode: Replace some UNIMPLEMENTED logs. 2018-08-20 21:53:49 -04:00
bunnei
16db8b9d9f gl_shader_decompiler: Implement Texture3D for TEXS. 2018-08-20 21:53:18 -04:00
bunnei
948002635f gl_shader_decompiler: Implement TextureCube for TEX. 2018-08-20 21:53:00 -04:00
bunnei
ea99819f37 Merge pull request #1130 from Subv/tex_2d
Shaders: Fixed texture coordinates in TEX with Texture2D
2018-08-20 21:49:47 -04:00
bunnei
19b05c3f55 Merge pull request #1122 from lioncash/acc
acc/profile_manager: General cleanup
2018-08-20 20:54:34 -04:00
bunnei
2788144f46 Merge pull request #1125 from bunnei/update-dynarmic
externals: Update dynarmic to a42f301c.
2018-08-20 20:46:16 -04:00
Lioncash
96463d0a55 romfs_factory: Remove unnecessary includes and use forward declarations where applicable
Avoids the need to rebuild whatever includes the romfs factory header if
the loader header ever changes. We also don't need to include the main
core header. We can instead include the headers we specifically need.
2018-08-20 20:27:00 -04:00
bunnei
dd70ddad7e Merge pull request #1095 from DarkLordZach/sysarchives
filesystem: Add support for loading of system archives
2018-08-20 20:17:57 -04:00
James Rowe
c0fb321935 Merge pull request #1127 from yuzu-emu/revert-838-port-3616
Revert "Port #3616 from Citra: "appveyor: set jobs to 4 for mingw""
2018-08-20 18:14:54 -06:00
Zach Hilman
34f3d58470 Revert "Port #3616 from Citra: "appveyor: set jobs to 4 for mingw"" 2018-08-20 20:13:28 -04:00
Lioncash
b5fb246a99 telemetry_session: Don't allocate std::string instances for program lifetime in GetTelemetryId() and RegenerateTelemetryId()
Given these functions aren't intended to be used frequently, there's no
need to keep the std::string instances allocated for the whole lifetime
of the program. It's just a waste of memory.
2018-08-20 20:06:25 -04:00
bunnei
c6fda4c758 externals: Update dynarmic to a42f301c. 2018-08-20 19:50:49 -04:00
Lioncash
609cb04f3f acc: Replace profile_manager include with a forward declaration
This is only used in a shared_ptr, so we can forward declare it.
2018-08-20 19:48:57 -04:00
Lioncash
eb88fedc5d acc: Simplify WriteBuffer call within LoadImage()
We have an overload of WriteBuffer that accepts containers that satisfy
the ContiguousContainer concept, which std::array does, so we only need
to pass in the array itself.
2018-08-20 19:48:57 -04:00
Lioncash
f5b132676f acc: Correct IProfile's constructor initializer list order
Arranges them in the order the members would be initialized
2018-08-20 19:48:57 -04:00
Lioncash
0fcdf37917 acc: Remove unused DEFAULT_USER_ID
This is no longer used, so it can be removed.
2018-08-20 19:48:57 -04:00
Lioncash
350f6e0aa4 profile_manager: Use INVALID_UUID in the initializer of last_opened_user
Makes it a little bit more self-documenting.
2018-08-20 19:48:57 -04:00
Lioncash
9d8f19d7bf profile_manager: Remove unnecessary memcpy in GetProfileBaseAndData()
Given the source and destination types are the same std::array type, we
can simply use regular assignment to perform the same behavior.
2018-08-20 19:48:57 -04:00
Lioncash
38cd4e9c61 profile_manager: Use type aliases for username data, profile data, and user arrays
Avoids the need to repeatedly specify the whole array type in multiple
places.
2018-08-20 19:48:57 -04:00
Lioncash
f9a26d468c profile_manager: Take ProfileInfo by const reference where applicable
ProfileInfo is quite a large struct in terms of data, and we don't need
to perform a copy in these instances, so we can just pass constant
references instead.
2018-08-20 19:48:57 -04:00
Lioncash
1277556c69 profile_manager: Make array parameter to CreateNewUser a const reference
This doesn't modify the passed in array, so this can be a const
reference.
2018-08-20 19:48:57 -04:00
Lioncash
dfdf4a46fe profile_manager: Remove unnecessary static
This can just be constexpr like the others
2018-08-20 19:48:57 -04:00
Lioncash
69dd37d874 profile_manager: Simplify UUID's two param constructor, operator==, and operator bool
We can use the constructor initializer list and just compare the
contained u128's together instead of comparing each element
individually. Ditto for comparing against an invalid UUID.
2018-08-20 19:48:57 -04:00
Lioncash
f13a66b963 profile_manager: Move UUID generation function to the cpp file
This avoids needing to dump the contents of <random> into other files
that include the profile manager header.
2018-08-20 19:48:53 -04:00
Lioncash
46ef072cf9 rasterizer_interface: Remove ScreenInfo from AccelerateDraw()'s signature
This is an OpenGL renderer-specific data type. Given that, this type
shouldn't be used within the base interface for the rasterizer. Instead,
we can pass this information to the rasterizer via reference.
2018-08-20 19:43:05 -04:00
Lioncash
bc16f7f3cc renderer_base: Make creation of the rasterizer, the responsibility of the renderers themselves
Given we use a base-class type within the renderer for the rasterizer
(RasterizerInterface), we want to allow renderers to perform more
complex initialization if they need to do such a thing. This makes it
important to reserve type information.

Given the OpenGL renderer is quite simple settings-wise, this is just a
simple shuffling of the initialization code. For something like Vulkan
however this might involve doing something like:

// Initialize and call rasterizer-specific function that requires
// the full type of the instance created.
auto raster = std::make_unique<VulkanRasterizer>(some, params);
raster->CallSomeVulkanRasterizerSpecificFunction();

// Assign to base class variable
rasterizer = std::move(raster)
2018-08-20 19:28:00 -04:00
Subv
7784ce1854 Shaders: Write all the enabled color outputs when a fragment shader exits.
We were only writing to the first render target before.
Note that this is only the GLSL side of the implementation, supporting multiple render targets requires more changes in the OpenGL renderer.

Dual Source blending is not implemented and stuff that uses it might not work at all.
2018-08-20 17:31:25 -05:00
Zach Hilman
e8cb6f5c9b registration: Add Data_Unknown5 NCAContentType 2018-08-20 17:34:18 -04:00
Lioncash
9e9a4bb3a7 profile_manager: Remove unnecessary std::move in AddToProfiles() and CreateNewUser()
Moving a const reference isn't possible, so this just results in a copy
(and given ProfileInfo is composed of trivial types and aggregates, a
move wouldn't really do anything).
2018-08-20 17:18:31 -04:00
Subv
d7c68fbb12 Rasterizer: Reinterpret the raw texture bytes instead of blitting (and thus doing format conversion) to a new texture when a game requests an old texture address with a different format. 2018-08-20 15:20:35 -05:00
Subv
3fe77be392 Rasterizer: Don't attempt to copy over the old texture's data when doing a format reinterpretation if we're only going to clear the framebuffer. 2018-08-20 15:20:35 -05:00
Zach Hilman
27da7bc9da filesystem: Add support for loading of system archives 2018-08-18 21:28:23 -04:00
34 changed files with 386 additions and 156 deletions

View File

@@ -53,7 +53,7 @@ build_script:
# https://www.appveyor.com/docs/build-phase
msbuild msvc_build/yuzu.sln /maxcpucount /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
} else {
C:\msys64\usr\bin\bash.exe -lc 'mingw32-make -j4 -C mingw_build/ 2>&1'
C:\msys64\usr\bin\bash.exe -lc 'mingw32-make -C mingw_build/ 2>&1'
}
after_build:

View File

@@ -27,6 +27,7 @@ enum class NCAContentType : u8 {
Control = 2,
Manual = 3,
Data = 4,
Data_Unknown5 = 5, ///< Seems to be used on some system archives
};
enum class NCASectionCryptoType : u8 {

View File

@@ -7,6 +7,7 @@
#include <cstring>
#include <memory>
#include <vector>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
#include "core/file_sys/vfs.h"

View File

@@ -77,12 +77,13 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
case NCAContentType::Control:
return ContentRecordType::Control;
case NCAContentType::Data:
case NCAContentType::Data_Unknown5:
return ContentRecordType::Data;
case NCAContentType::Manual:
// TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal.
return ContentRecordType::Manual;
default:
UNREACHABLE();
UNREACHABLE_MSG("Invalid NCAContentType={:02X}", static_cast<u8>(type));
}
}

View File

@@ -6,20 +6,57 @@
#include <memory>
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs_factory.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
namespace FileSys {
RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) {
// Load the RomFS from the app
if (Loader::ResultStatus::Success != app_loader.ReadRomFS(file)) {
if (app_loader.ReadRomFS(file) != Loader::ResultStatus::Success) {
LOG_ERROR(Service_FS, "Unable to read RomFS!");
}
}
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id) {
// TODO(DarkLordZach): Use title id.
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
return MakeResult<VirtualFile>(file);
}
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) {
switch (storage) {
case StorageId::NandSystem: {
const auto res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type);
if (res == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return ResultCode(-1);
}
const auto romfs = res->GetRomFS();
if (romfs == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return ResultCode(-1);
}
return MakeResult<VirtualFile>(romfs);
}
case StorageId::NandUser: {
const auto res = Service::FileSystem::GetUserNANDContents()->GetEntry(title_id, type);
if (res == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return ResultCode(-1);
}
const auto romfs = res->GetRomFS();
if (romfs == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return ResultCode(-1);
}
return MakeResult<VirtualFile>(romfs);
}
default:
UNIMPLEMENTED_MSG("Unimplemented storage_id={:02X}", static_cast<u8>(storage));
}
}
} // namespace FileSys

View File

@@ -6,17 +6,33 @@
#include <memory>
#include "common/common_types.h"
#include "core/file_sys/vfs.h"
#include "core/hle/result.h"
#include "core/loader/loader.h"
namespace Loader {
class AppLoader;
} // namespace Loader
namespace FileSys {
enum class ContentRecordType : u8;
enum class StorageId : u8 {
None = 0,
Host = 1,
GameCard = 2,
NandSystem = 3,
NandUser = 4,
SdCard = 5,
};
/// File system interface to the RomFS archive
class RomFSFactory {
public:
explicit RomFSFactory(Loader::AppLoader& app_loader);
ResultVal<VirtualFile> Open(u64 title_id);
ResultVal<VirtualFile> OpenCurrentProcess();
ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type);
private:
VirtualFile file;

View File

@@ -13,7 +13,7 @@
#include "core/hle/service/acc/acc_su.h"
#include "core/hle/service/acc/acc_u0.h"
#include "core/hle/service/acc/acc_u1.h"
#include "core/settings.h"
#include "core/hle/service/acc/profile_manager.h"
namespace Service::Account {
// TODO: RE this structure
@@ -27,13 +27,10 @@ struct UserData {
};
static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size");
// TODO(ogniK): Generate a real user id based on username, md5(username) maybe?
static UUID DEFAULT_USER_ID{1ull, 0ull};
class IProfile final : public ServiceFramework<IProfile> {
public:
explicit IProfile(UUID user_id, ProfileManager& profile_manager)
: ServiceFramework("IProfile"), user_id(user_id), profile_manager(profile_manager) {
: ServiceFramework("IProfile"), profile_manager(profile_manager), user_id(user_id) {
static const FunctionInfo functions[] = {
{0, &IProfile::Get, "Get"},
{1, &IProfile::GetBase, "GetBase"},
@@ -79,8 +76,8 @@ private:
LOG_WARNING(Service_ACC, "(STUBBED) called");
// smallest jpeg https://github.com/mathiasbynens/small/blob/master/jpeg.jpg
// TODO(mailwl): load actual profile image from disk, width 256px, max size 0x20000
const u32 jpeg_size = 107;
static const std::array<u8, jpeg_size> jpeg{
constexpr u32 jpeg_size = 107;
static constexpr std::array<u8, jpeg_size> jpeg{
0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03,
0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04,
0x08, 0x06, 0x06, 0x05, 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a,
@@ -90,7 +87,7 @@ private:
0xff, 0xcc, 0x00, 0x06, 0x00, 0x10, 0x10, 0x05, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01,
0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9,
};
ctx.WriteBuffer(jpeg.data(), jpeg_size);
ctx.WriteBuffer(jpeg);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(jpeg_size);
@@ -205,6 +202,8 @@ Module::Interface::Interface(std::shared_ptr<Module> module,
: ServiceFramework(name), module(std::move(module)),
profile_manager(std::move(profile_manager)) {}
Module::Interface::~Interface() = default;
void InstallInterfaces(SM::ServiceManager& service_manager) {
auto module = std::make_shared<Module>();
auto profile_manager = std::make_shared<ProfileManager>();

View File

@@ -4,17 +4,19 @@
#pragma once
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/service.h"
namespace Service::Account {
class ProfileManager;
class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(std::shared_ptr<Module> module,
std::shared_ptr<ProfileManager> profile_manager, const char* name);
~Interface() override;
void GetUserCount(Kernel::HLERequestContext& ctx);
void GetUserExistence(Kernel::HLERequestContext& ctx);

View File

@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <random>
#include <boost/optional.hpp>
#include "core/hle/service/acc/profile_manager.h"
#include "core/settings.h"
@@ -12,6 +13,15 @@ constexpr ResultCode ERROR_TOO_MANY_USERS(ErrorModule::Account, -1);
constexpr ResultCode ERROR_USER_ALREADY_EXISTS(ErrorModule::Account, -2);
constexpr ResultCode ERROR_ARGUMENT_IS_NULL(ErrorModule::Account, 20);
const UUID& UUID::Generate() {
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
uuid[0] = distribution(gen);
uuid[1] = distribution(gen);
return *this;
}
ProfileManager::ProfileManager() {
// TODO(ogniK): Create the default user we have for now until loading/saving users is added
auto user_uuid = UUID{1, 0};
@@ -25,7 +35,7 @@ boost::optional<size_t> ProfileManager::AddToProfiles(const ProfileInfo& user) {
if (user_count >= MAX_USERS) {
return boost::none;
}
profiles[user_count] = std::move(user);
profiles[user_count] = user;
return user_count++;
}
@@ -43,7 +53,7 @@ bool ProfileManager::RemoveProfileAtIndex(size_t index) {
}
/// Helper function to register a user to the system
ResultCode ProfileManager::AddUser(ProfileInfo user) {
ResultCode ProfileManager::AddUser(const ProfileInfo& user) {
if (AddToProfiles(user) == boost::none) {
return ERROR_TOO_MANY_USERS;
}
@@ -52,7 +62,7 @@ ResultCode ProfileManager::AddUser(ProfileInfo user) {
/// Create a new user on the system. If the uuid of the user already exists, the user is not
/// created.
ResultCode ProfileManager::CreateNewUser(UUID uuid, std::array<u8, 0x20>& username) {
ResultCode ProfileManager::CreateNewUser(UUID uuid, const ProfileUsername& username) {
if (user_count == MAX_USERS) {
return ERROR_TOO_MANY_USERS;
}
@@ -67,7 +77,7 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, std::array<u8, 0x20>& userna
return ERROR_USER_ALREADY_EXISTS;
}
ProfileInfo profile;
profile.user_uuid = std::move(uuid);
profile.user_uuid = uuid;
profile.username = username;
profile.data = {};
profile.creation_time = 0x0;
@@ -79,7 +89,7 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, std::array<u8, 0x20>& userna
/// specifically by allowing an std::string for the username. This is required specifically since
/// we're loading a string straight from the config
ResultCode ProfileManager::CreateNewUser(UUID uuid, const std::string& username) {
std::array<u8, 0x20> username_output;
ProfileUsername username_output;
if (username.size() > username_output.size()) {
std::copy_n(username.begin(), username_output.size(), username_output.begin());
} else {
@@ -102,7 +112,7 @@ boost::optional<size_t> ProfileManager::GetUserIndex(const UUID& uuid) const {
}
/// Returns a users profile index based on their profile
boost::optional<size_t> ProfileManager::GetUserIndex(ProfileInfo user) const {
boost::optional<size_t> ProfileManager::GetUserIndex(const ProfileInfo& user) const {
return GetUserIndex(user.user_uuid);
}
@@ -125,7 +135,7 @@ bool ProfileManager::GetProfileBase(UUID uuid, ProfileBase& profile) const {
}
/// Returns the data structure used by the switch when GetProfileBase is called on acc:*
bool ProfileManager::GetProfileBase(ProfileInfo user, ProfileBase& profile) const {
bool ProfileManager::GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const {
return GetProfileBase(user.user_uuid, profile);
}
@@ -168,8 +178,8 @@ void ProfileManager::CloseUser(UUID uuid) {
}
/// Gets all valid user ids on the system
std::array<UUID, MAX_USERS> ProfileManager::GetAllUsers() const {
std::array<UUID, MAX_USERS> output;
UserIDArray ProfileManager::GetAllUsers() const {
UserIDArray output;
std::transform(profiles.begin(), profiles.end(), output.begin(),
[](const ProfileInfo& p) { return p.user_uuid; });
return output;
@@ -177,8 +187,8 @@ std::array<UUID, MAX_USERS> ProfileManager::GetAllUsers() const {
/// Get all the open users on the system and zero out the rest of the data. This is specifically
/// needed for GetOpenUsers and we need to ensure the rest of the output buffer is zero'd out
std::array<UUID, MAX_USERS> ProfileManager::GetOpenUsers() const {
std::array<UUID, MAX_USERS> output;
UserIDArray ProfileManager::GetOpenUsers() const {
UserIDArray output;
std::transform(profiles.begin(), profiles.end(), output.begin(), [](const ProfileInfo& p) {
if (p.is_open)
return p.user_uuid;
@@ -195,9 +205,9 @@ UUID ProfileManager::GetLastOpenedUser() const {
/// Return the users profile base and the unknown arbitary data.
bool ProfileManager::GetProfileBaseAndData(boost::optional<size_t> index, ProfileBase& profile,
std::array<u8, MAX_DATA>& data) const {
ProfileData& data) const {
if (GetProfileBase(index, profile)) {
std::memcpy(data.data(), profiles[index.get()].data.data(), MAX_DATA);
data = profiles[index.get()].data;
return true;
}
return false;
@@ -205,14 +215,14 @@ bool ProfileManager::GetProfileBaseAndData(boost::optional<size_t> index, Profil
/// Return the users profile base and the unknown arbitary data.
bool ProfileManager::GetProfileBaseAndData(UUID uuid, ProfileBase& profile,
std::array<u8, MAX_DATA>& data) const {
ProfileData& data) const {
auto idx = GetUserIndex(uuid);
return GetProfileBaseAndData(idx, profile, data);
}
/// Return the users profile base and the unknown arbitary data.
bool ProfileManager::GetProfileBaseAndData(ProfileInfo user, ProfileBase& profile,
std::array<u8, MAX_DATA>& data) const {
bool ProfileManager::GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile,
ProfileData& data) const {
return GetProfileBaseAndData(user.user_uuid, profile, data);
}

View File

@@ -5,7 +5,7 @@
#pragma once
#include <array>
#include <random>
#include "boost/optional.hpp"
#include "common/common_types.h"
#include "common/swap.h"
@@ -14,23 +14,21 @@
namespace Service::Account {
constexpr size_t MAX_USERS = 8;
constexpr size_t MAX_DATA = 128;
static const u128 INVALID_UUID = {0, 0};
constexpr u128 INVALID_UUID{{0, 0}};
struct UUID {
// UUIDs which are 0 are considered invalid!
u128 uuid = INVALID_UUID;
UUID() = default;
explicit UUID(const u128& id) : uuid{id} {}
explicit UUID(const u64 lo, const u64 hi) {
uuid[0] = lo;
uuid[1] = hi;
};
explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {}
explicit operator bool() const {
return uuid[0] != INVALID_UUID[0] || uuid[1] != INVALID_UUID[1];
return uuid != INVALID_UUID;
}
bool operator==(const UUID& rhs) const {
return std::tie(uuid[0], uuid[1]) == std::tie(rhs.uuid[0], rhs.uuid[1]);
return uuid == rhs.uuid;
}
bool operator!=(const UUID& rhs) const {
@@ -38,15 +36,7 @@ struct UUID {
}
// TODO(ogniK): Properly generate uuids based on RFC-4122
const UUID& Generate() {
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<uint64_t> distribution(1,
std::numeric_limits<uint64_t>::max());
uuid[0] = distribution(gen);
uuid[1] = distribution(gen);
return *this;
}
const UUID& Generate();
// Set the UUID to {0,0} to be considered an invalid user
void Invalidate() {
@@ -58,20 +48,24 @@ struct UUID {
};
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
using ProfileUsername = std::array<u8, 0x20>;
using ProfileData = std::array<u8, MAX_DATA>;
using UserIDArray = std::array<UUID, MAX_USERS>;
/// This holds general information about a users profile. This is where we store all the information
/// based on a specific user
struct ProfileInfo {
UUID user_uuid;
std::array<u8, 0x20> username;
ProfileUsername username;
u64 creation_time;
std::array<u8, MAX_DATA> data; // TODO(ognik): Work out what this is
ProfileData data; // TODO(ognik): Work out what this is
bool is_open;
};
struct ProfileBase {
UUID user_uuid;
u64_le timestamp;
std::array<u8, 0x20> username;
ProfileUsername username;
// Zero out all the fields to make the profile slot considered "Empty"
void Invalidate() {
@@ -88,27 +82,26 @@ static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase is an invalid size");
class ProfileManager {
public:
ProfileManager(); // TODO(ogniK): Load from system save
ResultCode AddUser(ProfileInfo user);
ResultCode CreateNewUser(UUID uuid, std::array<u8, 0x20>& username);
ResultCode AddUser(const ProfileInfo& user);
ResultCode CreateNewUser(UUID uuid, const ProfileUsername& username);
ResultCode CreateNewUser(UUID uuid, const std::string& username);
boost::optional<size_t> GetUserIndex(const UUID& uuid) const;
boost::optional<size_t> GetUserIndex(ProfileInfo user) const;
boost::optional<size_t> GetUserIndex(const ProfileInfo& user) const;
bool GetProfileBase(boost::optional<size_t> index, ProfileBase& profile) const;
bool GetProfileBase(UUID uuid, ProfileBase& profile) const;
bool GetProfileBase(ProfileInfo user, ProfileBase& profile) const;
bool GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const;
bool GetProfileBaseAndData(boost::optional<size_t> index, ProfileBase& profile,
std::array<u8, MAX_DATA>& data) const;
bool GetProfileBaseAndData(UUID uuid, ProfileBase& profile,
std::array<u8, MAX_DATA>& data) const;
bool GetProfileBaseAndData(ProfileInfo user, ProfileBase& profile,
std::array<u8, MAX_DATA>& data) const;
ProfileData& data) const;
bool GetProfileBaseAndData(UUID uuid, ProfileBase& profile, ProfileData& data) const;
bool GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile,
ProfileData& data) const;
size_t GetUserCount() const;
size_t GetOpenUserCount() const;
bool UserExists(UUID uuid) const;
void OpenUser(UUID uuid);
void CloseUser(UUID uuid);
std::array<UUID, MAX_USERS> GetOpenUsers() const;
std::array<UUID, MAX_USERS> GetAllUsers() const;
UserIDArray GetOpenUsers() const;
UserIDArray GetAllUsers() const;
UUID GetLastOpenedUser() const;
bool CanSystemRegisterUser() const;
@@ -118,7 +111,7 @@ private:
size_t user_count = 0;
boost::optional<size_t> AddToProfiles(const ProfileInfo& profile);
bool RemoveProfileAtIndex(size_t index);
UUID last_opened_user{0, 0};
UUID last_opened_user{INVALID_UUID};
};
}; // namespace Service::Account

View File

@@ -7,7 +7,9 @@
#include "common/assert.h"
#include "common/file_util.h"
#include "core/core.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/sdmc_factory.h"
#include "core/file_sys/vfs.h"
@@ -256,15 +258,28 @@ ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
return RESULT_SUCCESS;
}
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id) {
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}", title_id);
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() {
LOG_TRACE(Service_FS, "Opening RomFS for current process");
if (romfs_factory == nullptr) {
// TODO(bunnei): Find a better error code for this
return ResultCode(-1);
}
return romfs_factory->Open(title_id);
return romfs_factory->OpenCurrentProcess();
}
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type) {
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}",
title_id, static_cast<u8>(storage_id), static_cast<u8>(type));
if (romfs_factory == nullptr) {
// TODO(bunnei): Find a better error code for this
return ResultCode(-1);
}
return romfs_factory->Open(title_id, storage_id, type);
}
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,

View File

@@ -6,14 +6,24 @@
#include <memory>
#include "common/common_types.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/directory.h"
#include "core/file_sys/mode.h"
#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/sdmc_factory.h"
#include "core/hle/result.h"
namespace FileSys {
class BISFactory;
class RegisteredCache;
class RomFSFactory;
class SaveDataFactory;
class SDMCFactory;
enum class ContentRecordType : u8;
enum class SaveDataSpaceId : u8;
enum class StorageId : u8;
struct SaveDataDescriptor;
} // namespace FileSys
namespace Service {
namespace SM {
@@ -27,7 +37,9 @@ ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory)
ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id);
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess();
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type);
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
FileSys::SaveDataDescriptor save_struct);
ResultVal<FileSys::VirtualDir> OpenSDMC();

View File

@@ -13,9 +13,11 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/file_sys/directory.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/vfs.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/filesystem/filesystem.h"
@@ -23,15 +25,6 @@
namespace Service::FileSystem {
enum class StorageId : u8 {
None = 0,
Host = 1,
GameCard = 2,
NandSystem = 3,
NandUser = 4,
SdCard = 5,
};
class IStorage final : public ServiceFramework<IStorage> {
public:
explicit IStorage(FileSys::VirtualFile backend_)
@@ -467,7 +460,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
{110, nullptr, "OpenContentStorageFileSystem"},
{200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"},
{201, nullptr, "OpenDataStorageByProgramId"},
{202, nullptr, "OpenDataStorageByDataId"},
{202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"},
{203, &FSP_SRV::OpenRomStorage, "OpenRomStorage"},
{400, nullptr, "OpenDeviceOperator"},
{500, nullptr, "OpenSdCardDetectionEventNotifier"},
@@ -580,7 +573,7 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
auto romfs = OpenRomFS(Core::System::GetInstance().CurrentProcess()->program_id);
auto romfs = OpenRomFSCurrentProcess();
if (romfs.Failed()) {
// TODO (bunnei): Find the right error code to use here
LOG_CRITICAL(Service_FS, "no file system interface available!");
@@ -596,10 +589,37 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IStorage>(std::move(storage));
}
void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage_id = rp.PopRaw<FileSys::StorageId>();
const auto unknown = rp.PopRaw<u32>();
const auto title_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
static_cast<u8>(storage_id), unknown, title_id);
auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
if (data.Failed()) {
// TODO(DarkLordZach): Find the right error code to use here
LOG_ERROR(Service_FS,
"could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
static_cast<u8>(storage_id));
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultCode(-1));
return;
}
IStorage storage(std::move(data.Unwrap()));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IStorage>(std::move(storage));
}
void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto storage_id = rp.PopRaw<StorageId>();
auto storage_id = rp.PopRaw<FileSys::StorageId>();
auto title_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}",

View File

@@ -25,6 +25,7 @@ private:
void MountSaveData(Kernel::HLERequestContext& ctx);
void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
void OpenRomStorage(Kernel::HLERequestContext& ctx);
FileSys::VirtualFile romfs;

View File

@@ -8,6 +8,7 @@
#include "common/logging/log.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/romfs_factory.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"

View File

@@ -7,6 +7,7 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/romfs_factory.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/deconstructed_rom_directory.h"

View File

@@ -19,8 +19,8 @@ static u64 GenerateTelemetryId() {
u64 GetTelemetryId() {
u64 telemetry_id{};
static const std::string& filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) +
"telemetry_id"};
const std::string filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) +
"telemetry_id"};
if (FileUtil::Exists(filename)) {
FileUtil::IOFile file(filename, "rb");
@@ -44,8 +44,8 @@ u64 GetTelemetryId() {
u64 RegenerateTelemetryId() {
const u64 new_telemetry_id{GenerateTelemetryId()};
static const std::string& filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) +
"telemetry_id"};
const std::string filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) +
"telemetry_id"};
FileUtil::IOFile file(filename, "wb");
if (!file.IsOpen()) {

View File

@@ -477,7 +477,9 @@ union Instruction {
if (texture_info >= 12 && texture_info <= 13)
return TextureType::TextureCube;
UNIMPLEMENTED();
LOG_CRITICAL(HW_GPU, "Unhandled texture_info: {}",
static_cast<u32>(texture_info.Value()));
UNREACHABLE();
}
bool IsArrayTexture() const {
@@ -523,7 +525,9 @@ union Instruction {
return TextureType::Texture3D;
}
UNIMPLEMENTED();
LOG_CRITICAL(HW_GPU, "Unhandled texture_info: {}",
static_cast<u32>(texture_info.Value()));
UNREACHABLE();
}
bool IsArrayTexture() const {

View File

@@ -8,8 +8,6 @@
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
struct ScreenInfo;
namespace VideoCore {
class RasterizerInterface {
@@ -55,7 +53,7 @@ public:
/// Attempt to use a faster method to display the framebuffer to screen
virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
u32 pixel_stride, ScreenInfo& screen_info) {
u32 pixel_stride) {
return false;
}

View File

@@ -2,7 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <memory>
#include "core/frontend/emu_window.h"
#include "core/settings.h"
#include "video_core/renderer_base.h"
@@ -17,18 +16,11 @@ RendererBase::RendererBase(Core::Frontend::EmuWindow& window) : render_window{wi
RendererBase::~RendererBase() = default;
void RendererBase::RefreshBaseSettings() {
RefreshRasterizerSetting();
UpdateCurrentFramebufferLayout();
renderer_settings.use_framelimiter = Settings::values.toggle_framelimit;
}
void RendererBase::RefreshRasterizerSetting() {
if (rasterizer == nullptr) {
rasterizer = std::make_unique<RasterizerOpenGL>(render_window);
}
}
void RendererBase::UpdateCurrentFramebufferLayout() {
const Layout::FramebufferLayout& layout = render_window.GetFramebufferLayout();

View File

@@ -58,9 +58,6 @@ public:
void RefreshBaseSettings();
protected:
/// 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

View File

@@ -36,8 +36,8 @@ 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(Core::Frontend::EmuWindow& window)
: emu_window{window}, stream_buffer(GL_ARRAY_BUFFER, STREAM_BUFFER_SIZE) {
RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info)
: emu_window{window}, screen_info{info}, stream_buffer(GL_ARRAY_BUFFER, STREAM_BUFFER_SIZE) {
// Create sampler objects
for (size_t i = 0; i < texture_samplers.size(); ++i) {
texture_samplers[i].Create();
@@ -304,7 +304,8 @@ bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
}
std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb,
bool using_depth_fb) {
bool using_depth_fb,
bool preserve_contents) {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
if (regs.rt[0].format == Tegra::RenderTargetFormat::NONE) {
@@ -327,7 +328,7 @@ 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);
res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, preserve_contents);
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
const MathUtil::Rectangle<u32> draw_rect{
@@ -390,7 +391,7 @@ void RasterizerOpenGL::Clear() {
ScopeAcquireGLContext acquire_context{emu_window};
auto [dirty_color_surface, dirty_depth_surface] =
ConfigureFramebuffers(use_color_fb, use_depth_fb);
ConfigureFramebuffers(use_color_fb, use_depth_fb, false);
// TODO(Subv): Support clearing only partial colors.
glClearColor(regs.clear_color[0], regs.clear_color[1], regs.clear_color[2],
@@ -445,7 +446,7 @@ void RasterizerOpenGL::DrawArrays() {
ScopeAcquireGLContext acquire_context{emu_window};
auto [dirty_color_surface, dirty_depth_surface] =
ConfigureFramebuffers(true, regs.zeta.Address() != 0 && regs.zeta_enable != 0);
ConfigureFramebuffers(true, regs.zeta.Address() != 0 && regs.zeta_enable != 0, true);
SyncDepthTestState();
SyncBlendState();
@@ -574,8 +575,7 @@ bool RasterizerOpenGL::AccelerateFill(const void* config) {
}
bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
VAddr framebuffer_addr, u32 pixel_stride,
ScreenInfo& screen_info) {
VAddr framebuffer_addr, u32 pixel_stride) {
if (!framebuffer_addr) {
return {};
}

View File

@@ -30,7 +30,7 @@ class EmuWindow;
class RasterizerOpenGL : public VideoCore::RasterizerInterface {
public:
explicit RasterizerOpenGL(Core::Frontend::EmuWindow& renderer);
explicit RasterizerOpenGL(Core::Frontend::EmuWindow& renderer, ScreenInfo& info);
~RasterizerOpenGL() override;
void DrawArrays() override;
@@ -43,8 +43,8 @@ public:
bool AccelerateDisplayTransfer(const void* config) override;
bool AccelerateTextureCopy(const void* config) override;
bool AccelerateFill(const void* config) override;
bool AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer, VAddr framebuffer_addr,
u32 pixel_stride, ScreenInfo& screen_info) override;
bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
u32 pixel_stride) override;
bool AccelerateDrawBatch(bool is_indexed) override;
/// OpenGL shader generated for a given Maxwell register state
@@ -87,7 +87,8 @@ private:
/// Configures the color and depth framebuffer states and returns the dirty <Color, Depth>
/// surfaces if writing was enabled.
std::pair<Surface, Surface> ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb);
std::pair<Surface, Surface> ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb,
bool preserve_contents);
/// Binds the framebuffer color and depth surface
void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface,
@@ -151,6 +152,8 @@ private:
Core::Frontend::EmuWindow& emu_window;
ScreenInfo& screen_info;
std::unique_ptr<GLShader::ProgramManager> shader_program_manager;
OGLVertexArray sw_vao;
OGLVertexArray hw_vao;

View File

@@ -686,7 +686,8 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu
}
SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(bool using_color_fb,
bool using_depth_fb) {
bool using_depth_fb,
bool preserve_contents) {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
// TODO(bunnei): This is hard corded to use just the first render buffer
@@ -708,7 +709,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(bool usin
MathUtil::Rectangle<u32> color_rect{};
Surface color_surface;
if (using_color_fb) {
color_surface = GetSurface(color_params);
color_surface = GetSurface(color_params, preserve_contents);
if (color_surface) {
color_rect = color_surface->GetSurfaceParams().GetRect();
}
@@ -717,7 +718,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(bool usin
MathUtil::Rectangle<u32> depth_rect{};
Surface depth_surface;
if (using_depth_fb) {
depth_surface = GetSurface(depth_params);
depth_surface = GetSurface(depth_params, preserve_contents);
if (depth_surface) {
depth_rect = depth_surface->GetSurfaceParams().GetRect();
}
@@ -752,7 +753,7 @@ void RasterizerCacheOpenGL::FlushSurface(const Surface& surface) {
surface->FlushGLBuffer();
}
Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params) {
Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool preserve_contents) {
if (params.addr == 0 || params.height * params.width == 0) {
return {};
}
@@ -774,9 +775,13 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params) {
} else if (surface->GetSurfaceParams().IsCompatibleSurface(params)) {
// Use the cached surface as-is
return surface;
} else {
// If surface parameters changed, recreate the surface from the old one
} else if (preserve_contents) {
// If surface parameters changed and we care about keeping the previous data, recreate
// the surface from the old one
return RecreateSurface(surface, params);
} else {
// Delete the old surface before creating a new one to prevent collisions.
UnregisterSurface(surface);
}
}
@@ -793,12 +798,58 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
// Verify surface is compatible for blitting
const auto& params{surface->GetSurfaceParams()};
ASSERT(params.type == new_params.type);
ASSERT_MSG(params.GetCompressionFactor(params.pixel_format) == 1,
"Compressed texture reinterpretation is not supported");
// Create a new surface with the new parameters, and blit the previous surface to it
Surface new_surface{std::make_shared<CachedSurface>(new_params)};
BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle,
new_surface->GetSurfaceParams().GetRect(), params.type, read_framebuffer.handle,
draw_framebuffer.handle);
auto source_format = GetFormatTuple(params.pixel_format, params.component_type);
auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type);
size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes());
// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one
// using the new format.
OGLBuffer pbo;
pbo.Create();
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle);
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
glGetTextureImage(surface->Texture().handle, 0, source_format.format, source_format.type,
params.SizeInBytes(), nullptr);
// If the new texture is bigger than the previous one, we need to fill in the rest with data
// from the CPU.
if (params.SizeInBytes() < new_params.SizeInBytes()) {
// Upload the rest of the memory.
if (new_params.is_tiled) {
// TODO(Subv): We might have to de-tile the subtexture and re-tile it with the rest of
// the data in this case. Games like Super Mario Odyssey seem to hit this case when
// drawing, it re-uses the memory of a previous texture as a bigger framebuffer but it
// doesn't clear it beforehand, the texture is already full of zeros.
LOG_CRITICAL(HW_GPU, "Trying to upload extra texture data from the CPU during "
"reinterpretation but the texture is tiled.");
}
size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes();
auto address = Core::System::GetInstance().GPU().memory_manager->GpuToCpuAddress(
new_params.addr + params.SizeInBytes());
std::vector<u8> data(remaining_size);
Memory::ReadBlock(*address, data.data(), data.size());
glBufferSubData(GL_PIXEL_PACK_BUFFER, params.SizeInBytes(), remaining_size, data.data());
}
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
const auto& dest_rect{new_params.GetRect()};
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle);
glTextureSubImage2D(
new_surface->Texture().handle, 0, 0, 0, static_cast<GLsizei>(dest_rect.GetWidth()),
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, dest_format.type, nullptr);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
pbo.Release();
// Update cache accordingly
UnregisterSurface(surface);

View File

@@ -722,7 +722,8 @@ 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);
SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb,
bool preserve_contents);
/// Flushes the surface to Switch memory
void FlushSurface(const Surface& surface);
@@ -738,7 +739,7 @@ public:
private:
void LoadSurface(const Surface& surface);
Surface GetSurface(const SurfaceParams& params);
Surface GetSurface(const SurfaceParams& params, bool preserve_contents = true);
/// Recreates a surface with new parameters
Surface RecreateSurface(const Surface& surface, const SurfaceParams& new_params);

View File

@@ -26,6 +26,7 @@ using Tegra::Shader::Sampler;
using Tegra::Shader::SubOp;
constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH;
constexpr u32 PROGRAM_HEADER_SIZE = 0x50;
class DecompileFail : public std::runtime_error {
public:
@@ -621,6 +622,23 @@ public:
}
private:
// Shader program header for a Fragment Shader.
struct FragmentHeader {
INSERT_PADDING_WORDS(5);
INSERT_PADDING_WORDS(13);
u32 enabled_color_outputs;
union {
BitField<0, 1, u32> writes_samplemask;
BitField<1, 1, u32> writes_depth;
};
bool IsColorComponentOutputEnabled(u32 render_target, u32 component) const {
u32 bit = render_target * 4 + component;
return enabled_color_outputs & (1 << bit);
}
};
static_assert(sizeof(FragmentHeader) == PROGRAM_HEADER_SIZE, "FragmentHeader size is wrong");
/// Gets the Subroutine object corresponding to the specified address.
const Subroutine& GetSubroutine(u32 begin, u32 end) const {
auto iter = subroutines.find(Subroutine{begin, end, suffix});
@@ -894,6 +912,36 @@ private:
shader.AddLine('}');
}
/// Writes the output values from a fragment shader to the corresponding GLSL output variables.
void EmitFragmentOutputsWrite() {
ASSERT(stage == Maxwell3D::Regs::ShaderStage::Fragment);
FragmentHeader header;
std::memcpy(&header, program_code.data(), PROGRAM_HEADER_SIZE);
ASSERT_MSG(header.writes_samplemask == 0, "Samplemask write is unimplemented");
// Write the color outputs using the data in the shader registers, disabled
// rendertargets/components are skipped in the register assignment.
u32 current_reg = 0;
for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets;
++render_target) {
// TODO(Subv): Figure out how dual-source blending is configured in the Switch.
for (u32 component = 0; component < 4; ++component) {
if (header.IsColorComponentOutputEnabled(render_target, component)) {
shader.AddLine(fmt::format("color[{}][{}] = {};", render_target, component,
regs.GetRegisterAsFloat(current_reg)));
++current_reg;
}
}
}
if (header.writes_depth) {
// The depth output is always 2 registers after the last color output, and current_reg
// already contains one past the last color register.
shader.AddLine("gl_FragDepth = " + regs.GetRegisterAsFloat(current_reg + 1) + ';');
}
}
/**
* Compiles a single instruction from Tegra to GLSL.
* @param offset the offset of the Tegra shader instruction.
@@ -1525,6 +1573,14 @@ private:
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
break;
}
case Tegra::Shader::TextureType::TextureCube: {
std::string x = regs.GetRegisterAsFloat(instr.gpr8);
std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
ASSERT(instr.gpr20.Value() == Register::ZeroIndex);
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
break;
}
default:
LOG_CRITICAL(HW_GPU, "Unhandled texture type {}",
static_cast<u32>(instr.tex.texture_type.Value()));
@@ -1570,6 +1626,13 @@ private:
}
break;
}
case Tegra::Shader::TextureType::Texture3D: {
std::string x = regs.GetRegisterAsFloat(instr.gpr8);
std::string y = regs.GetRegisterAsFloat(instr.gpr20);
std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
break;
}
case Tegra::Shader::TextureType::TextureCube: {
std::string x = regs.GetRegisterAsFloat(instr.gpr8);
std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
@@ -1969,12 +2032,8 @@ private:
default: {
switch (opcode->GetId()) {
case OpCode::Id::EXIT: {
// Final color output is currently hardcoded to GPR0-3 for fragment shaders
if (stage == Maxwell3D::Regs::ShaderStage::Fragment) {
shader.AddLine("color.r = " + regs.GetRegisterAsFloat(0) + ';');
shader.AddLine("color.g = " + regs.GetRegisterAsFloat(1) + ';');
shader.AddLine("color.b = " + regs.GetRegisterAsFloat(2) + ';');
shader.AddLine("color.a = " + regs.GetRegisterAsFloat(3) + ';');
EmitFragmentOutputsWrite();
}
switch (instr.flow.cond) {

View File

@@ -87,7 +87,7 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSCo
.get_value_or({});
out += R"(
in vec4 position;
out vec4 color;
layout(location = 0) out vec4 color[8];
layout (std140) uniform fs_config {
vec4 viewport_flip;

View File

@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <tuple>
#include <glad/glad.h>
#include "common/common_types.h"

View File

@@ -16,6 +16,7 @@
#include "core/memory.h"
#include "core/settings.h"
#include "core/tracer/recorder.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
#include "video_core/utils.h"
@@ -130,7 +131,7 @@ void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&
}
// Load the framebuffer from memory, draw it to the screen, and swap buffers
LoadFBToScreenInfo(*framebuffer, screen_info);
LoadFBToScreenInfo(*framebuffer);
DrawScreen();
render_window.SwapBuffers();
}
@@ -142,14 +143,12 @@ void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&
// Restore the rasterizer state
prev_state.Apply();
RefreshRasterizerSetting();
}
/**
* Loads framebuffer from emulated memory into the active OpenGL texture.
*/
void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer,
ScreenInfo& screen_info) {
void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) {
const u32 bytes_per_pixel{Tegra::FramebufferConfig::BytesPerPixel(framebuffer.pixel_format)};
const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel};
const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset};
@@ -162,8 +161,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
// only allows rows to have a memory alignement of 4.
ASSERT(framebuffer.stride % 4 == 0);
if (!rasterizer->AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride,
screen_info)) {
if (!rasterizer->AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride)) {
// Reset the screen info's display texture to its own permanent texture
screen_info.display_texture = screen_info.texture.resource.handle;
@@ -276,6 +274,14 @@ void RendererOpenGL::InitOpenGLObjects() {
LoadColorToActiveGLTexture(0, 0, 0, 0, screen_info.texture);
}
void RendererOpenGL::CreateRasterizer() {
if (rasterizer) {
return;
}
rasterizer = std::make_unique<RasterizerOpenGL>(render_window, screen_info);
}
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
const Tegra::FramebufferConfig& framebuffer) {
@@ -432,7 +438,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
case GL_DEBUG_SEVERITY_LOW:
LOG_TRACE(Render_OpenGL, format, str_source, str_type, id, message);
LOG_DEBUG(Render_OpenGL, format, str_source, str_type, id, message);
break;
}
}
@@ -463,8 +469,7 @@ bool RendererOpenGL::Init() {
}
InitOpenGLObjects();
RefreshRasterizerSetting();
CreateRasterizer();
return true;
}

View File

@@ -59,6 +59,8 @@ public:
private:
void InitOpenGLObjects();
void CreateRasterizer();
void ConfigureFramebufferTexture(TextureInfo& texture,
const Tegra::FramebufferConfig& framebuffer);
void DrawScreen();
@@ -66,7 +68,7 @@ private:
void UpdateFramerate();
// Loads framebuffer from emulated memory into the display information structure
void LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer, ScreenInfo& screen_info);
void LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer);
// Fills active OpenGL texture with the given RGBA color.
void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
const TextureInfo& texture);

View File

@@ -16,6 +16,7 @@
#include "common/string_util.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/vfs_real.h"
#include "core/loader/loader.h"

View File

@@ -6,12 +6,15 @@
#include <array>
#include <atomic>
#include <map>
#include <memory>
#include <utility>
#include <QImage>
#include <QRunnable>
#include <QStandardItem>
#include <QString>
#include "common/string_util.h"
#include "core/file_sys/content_archive.h"
#include "ui_settings.h"
#include "yuzu/util/util.h"

View File

@@ -27,7 +27,9 @@
#include "common/string_util.h"
#include "core/core.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/vfs_real.h"
#include "core/gdbstub/gdbstub.h"
#include "core/loader/loader.h"
@@ -88,9 +90,20 @@ void GMainWindow::ShowCallouts() {}
const int GMainWindow::max_recent_files_item;
static void InitializeLogging() {
Log::Filter log_filter;
log_filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(log_filter);
const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
FileUtil::CreateFullPath(log_dir);
Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
}
GMainWindow::GMainWindow()
: config(new Config()), emu_thread(nullptr),
vfs(std::make_shared<FileSys::RealVfsFilesystem>()) {
InitializeLogging();
debug_context = Tegra::DebugContext::Construct();
@@ -1095,16 +1108,6 @@ void GMainWindow::UpdateUITheme() {
#undef main
#endif
static void InitializeLogging() {
Log::Filter log_filter;
log_filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(log_filter);
const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
FileUtil::CreateFullPath(log_dir);
Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
}
int main(int argc, char* argv[]) {
MicroProfileOnThreadCreate("Frontend");
SCOPE_EXIT({ MicroProfileShutdown(); });
@@ -1122,7 +1125,6 @@ int main(int argc, char* argv[]) {
GMainWindow main_window;
// After settings have been loaded by GMainWindow, apply the filter
InitializeLogging();
main_window.show();
return app.exec();
}