Compare commits

...

80 Commits

Author SHA1 Message Date
David Marcec
e7b0e8a3cc More accurate GetTPCMasks impl 2018-05-10 21:01:39 -07:00
Hexagon12
5e9c547952 Stubs for QLaunch (#428)
* Stubs for QLaunch

* Wiped unrelated stuff

* Addressed comment

* Dropped GetPopFromGeneralChannelEvent
2018-05-07 11:27:30 -04:00
Max Thomas
266703b50e hid: Tweaks, Analog Sticks (#435)
* hid: Update mouse/keyboard state

* hid: Working analog sticks

* hid: Nits

* hid: Nits

* hid: Update mystery sections

* hid: Tweaks
2018-05-07 11:06:02 -04:00
bunnei
9eccb5de9d Merge pull request #434 from lioncash/vdtor
memory_hook: Default virtual destructor in the cpp file
2018-05-03 15:09:14 -04:00
bunnei
8c665d6752 Merge pull request #433 from lioncash/logging
core_timing: Don't include the log header in core timing's header
2018-05-03 15:08:43 -04:00
Lioncash
732a77d0e8 memory_hook: Default virtual destructor in the cpp file
Prevents creating multiple copies of the vtable in every translation unit that uses the class.
Also silences a -Wweak-vtables warning
2018-05-03 08:12:16 -04:00
Lioncash
9f3641755e core_timing: Don't include the log header in core timing's header
Avoids propagating logging macros and facilities to files that may not need them.
This also allows hiding an internal constant.
2018-05-03 08:00:15 -04:00
bunnei
1147db9dd1 Merge pull request #431 from lioncash/fmt
general: Make formatting of logged hex values more straightforward
2018-05-02 15:24:41 -04:00
bunnei
b1a8e5914b Merge pull request #430 from lioncash/vec
vector_math: Ensure members are always initialized
2018-05-02 09:55:32 -04:00
bunnei
902182f80c Merge pull request #427 from bunnei/domain-inputs
ipc: Add support for PopIpcInterface() method.
2018-05-02 09:55:14 -04:00
Lioncash
7c9644646f general: Make formatting of logged hex values more straightforward
This makes the formatting expectations more obvious (e.g. any zero padding specified
is padding that's entirely dedicated to the value being printed, not any pretty-printing
that also gets tacked on).
2018-05-02 09:49:36 -04:00
bunnei
fadab1d5f3 ipc: Add support for PopIpcInterface() method.
- This can be used for domain objects as inputs to service functions.
2018-05-01 21:57:44 -04:00
Lioncash
acc10c7ee2 vector_math: Ensure members are always initialized
Ensures that values are always in a well-defined state.
2018-05-01 21:25:25 -04:00
bunnei
8262aeeac8 Merge pull request #429 from Subv/ioctl_corruption
GPU: Don't write to invalid memory locations when handling ioctls that don't have an output.
2018-05-01 16:28:54 -04:00
David
ff2f0d980a GetSharedFontInOrderOfPriority (#381)
* GetSharedFontInOrderOfPriority

* Update pl_u.cpp

* Ability to use ReadBuffer and WriteBuffer with different buffer indexes, fixed up GetSharedFontInOrderOfPriority

* switched to NGLOG

* Update pl_u.cpp

* Update pl_u.cpp

* language_code is actually language code and not index

* u32->u64

* final cleanups
2018-05-01 16:28:36 -04:00
Subv
0c8b7c00e8 GPU: Don't write to invalid memory locations when handling ioctls that don't have an output. 2018-05-01 14:54:15 -05:00
bunnei
f362cf46ee Merge pull request #425 from lioncash/namespace
core_timing: Namespace all functions and constants in core_timing's header
2018-04-30 10:15:27 -04:00
Lioncash
0197e28cc9 core_timing: Namespace all functions and constants in core_timing's header
All of these variables and functions are related to timings and should be within the namespace.
2018-04-30 03:32:59 -04:00
bunnei
81a0082f6b Merge pull request #424 from lioncash/string
string_util: Remove StringFromFormat() and related functions
2018-04-29 21:49:13 -04:00
bunnei
225ff1130f Merge pull request #422 from bunnei/shader-mov
Shader instructions MOV_C, MOV_R, and several minor GPU things
2018-04-29 21:47:42 -04:00
bunnei
b3962e7d1e Merge pull request #423 from lioncash/file
file_util: Minor changes to IOFile
2018-04-29 21:47:28 -04:00
Lioncash
3abba08080 string_util: Remove StringFromFormat() and related functions
Given we utilize fmt, we don't need to provide our own functions for formatting anymore
2018-04-29 18:52:33 -04:00
Lioncash
e8bbafb746 file_util: Make move constructor/assignment operator and related functions noexcept
Without this, it's possible to get compilation failures in the (rare) scenario where
a container is used to store a bunch of live IOFile instances, as they may be using
std::move_if_noexcept under the hood. Given these definitely don't throw exceptions
this is also not incorrect to add either.
2018-04-29 18:34:09 -04:00
Lioncash
40d2dcabd7 file_util: Add static assertions to ReadBytes() and WriteBytes()
Ensure that the actual types being passed in are trivially copyable. The internal
call to ReadArray() and WriteArray() will always succeed, since they're passed a pointer to char*
which is always trivially copyable.
2018-04-29 18:24:12 -04:00
bunnei
f41eb95e13 maxwell_3d: Reset vertex counts after drawing. 2018-04-29 16:23:31 -04:00
bunnei
08b8fcbe6d gl_shader_decompiler: Implement MOV_R. 2018-04-29 16:05:18 -04:00
bunnei
316327f487 maxwell_to_gl: Implement type SignedNorm, Size_8_8_8_8. 2018-04-29 16:05:17 -04:00
bunnei
c7ce472eeb shader_bytecode: Add decoding for FMNMX instruction. 2018-04-29 16:05:17 -04:00
bunnei
869075867b Merge pull request #421 from Subv/sh_pred3
Shaders: Implemented predicate condition 3 (LessEqual) in the fset and fsetp instructions.
2018-04-29 15:59:33 -04:00
Subv
da32c648bf Shaders: Implemented predicate condition 3 (LessEqual) in the fset and fsetp instructions. 2018-04-29 12:49:41 -05:00
bunnei
a71346cd7c gl_shader_decompiler: Implement MOV_C. 2018-04-29 13:13:13 -04:00
bunnei
6c464a2a4a Merge pull request #416 from bunnei/shader-ints-p3
gl_shader_decompiler: Implement MOV32I, partially implement I2I, I2F
2018-04-29 12:56:16 -04:00
bunnei
49d92aa661 Merge pull request #417 from bunnei/lang-codes
set/am: Fix code for getting language codes
2018-04-29 12:55:43 -04:00
bunnei
334e859ab1 am: Fix GetDesiredLanguage implementation. 2018-04-29 11:07:07 -04:00
bunnei
17b16cf6f6 set: Fix GetAvailableLanguageCodes implementation. 2018-04-29 11:07:06 -04:00
Sebastian Valle
faa431b274 Merge pull request #418 from bunnei/copy-block-height
fermi_2d: Fix surface copy block height.
2018-04-29 09:49:33 -05:00
bunnei
f87ea8fa8b fermi_2d: Fix surface copy block height. 2018-04-28 20:40:03 -04:00
bunnei
0c01c34eff gl_shader_decompiler: Partially implement I2I_R, and I2F_R. 2018-04-28 20:03:19 -04:00
bunnei
e73927cfc2 gl_shader_decompiler: More cleanups, etc. with how we handle register types. 2018-04-28 20:03:19 -04:00
bunnei
c691fa4074 GLSLRegister: Simplify register declarations, etc. 2018-04-28 20:03:19 -04:00
bunnei
f2dcb39049 shader_bytecode: Add decodings for i2i instructions. 2018-04-28 20:03:18 -04:00
bunnei
a7b5ab4d9a gl_shader_decompiler: Implement MOV32_IMM instruction. 2018-04-28 20:03:18 -04:00
bunnei
3d9126ba87 Merge pull request #414 from lioncash/cruft
file_util: Remove compiler version checks around is_trivially_copyable
2018-04-28 17:06:49 -04:00
bunnei
7fd54fed92 Merge pull request #413 from lioncash/dynarmic
externals: Update dynarmic
2018-04-28 17:06:17 -04:00
Lioncash
5d9ee12b1a file_util: Remove compiler version checks around is_trivially_copyable()
The minimum clang/GCC versions we support already support this. We can also
remove is_standard_layout(), as fread and fwrite only require the type to be
trivially copyable.
2018-04-28 15:31:23 -04:00
bunnei
bad00085ca Merge pull request #412 from lioncash/log
log: Remove old logging macros and functions
2018-04-28 15:04:24 -04:00
Lioncash
e56e2a1528 externals: Update dynarmic
Just a basic update to keep it in sync
2018-04-28 14:31:37 -04:00
Mat M
99ac33de20 Merge pull request #411 from lioncash/travis
travis: Use Xcode 9.3 instead of 9.2
2018-04-27 22:12:00 -04:00
Lioncash
d43c49264f log: Remove old logging macros and functions
Now that the old macros are no longer used, we can remove all functionality related to them.
2018-04-27 16:18:34 -04:00
bunnei
6b365f7703 Merge pull request #408 from bunnei/shader-ints-p2
gl_shader_decompiler: Add GLSLRegisterManager class to track register state.
2018-04-27 16:06:09 -04:00
bunnei
41dde2394b Merge pull request #410 from lioncash/generic
core/renderer_opengl: Replace usages of LOG_GENERIC with fmt-capable equivalents
2018-04-27 15:59:12 -04:00
Lioncash
5a579f66a0 travis: Use Xcode 9.3 instead of 9.2
Keeps the toolchains up to date.
2018-04-27 12:17:01 -04:00
Lioncash
16198f979e renderer_opengl: Replace usages of LOG_GENERIC with fmt-capable equivalents 2018-04-27 12:09:35 -04:00
Lioncash
843dd62c81 core: Replace usages of LOG_GENERIC with new fmt-capable equivalents 2018-04-27 11:57:52 -04:00
bunnei
e6242ab5e6 gl_shader_decompiler: Add GLSLRegisterManager class to track register state. 2018-04-27 11:49:26 -04:00
bunnei
acede1f1d3 Merge pull request #409 from lioncash/assert
general: Convert assertion macros over to be fmt-compatible
2018-04-27 11:09:56 -04:00
Lioncash
8475496630 general: Convert assertion macros over to be fmt-compatible 2018-04-27 10:04:02 -04:00
bunnei
3c40496409 Merge pull request #380 from ogniK5377/service-impl
Implemented some useful interfaces needed for games.
2018-04-27 00:49:40 -04:00
David Marcec
abc23416e8 Switched to NGLOG_WARNING 2018-04-26 20:03:12 -07:00
bunnei
4f120a9ec0 Merge pull request #406 from lioncash/frontend
frontends: Move logging macros over to new fmt-capable ones
2018-04-26 22:53:42 -04:00
bunnei
18f8012233 Merge pull request #407 from lioncash/common
common: Move logging macros over to new fmt-capable macros where applicable
2018-04-26 22:53:14 -04:00
bunnei
3e0ec3dbd7 Merge pull request #405 from lioncash/input
input_common: Move old logging macros over to fmt-capable ones
2018-04-26 21:54:51 -04:00
Lioncash
3cfe77ae75 common: Move logging macros over to new fmt-capable macros where applicable 2018-04-26 20:09:58 -04:00
Lioncash
3062eb52f4 frontends: Move logging macros over to new fmt-capable ones 2018-04-26 19:14:48 -04:00
Lioncash
376f6397c6 input_common: Move old logging macros over to fmt-capable ones 2018-04-26 19:09:25 -04:00
bunnei
6a3d59fdc1 Merge pull request #402 from lioncash/core
core: Replace remaining old non-generic logger usages with fmt-capable equivalents
2018-04-26 18:45:10 -04:00
bunnei
bc43946140 Merge pull request #399 from bunnei/shader-ints
Shader decompiler prep for integer instructions
2018-04-26 18:43:51 -04:00
David Marcec
7391741a20 Merge branch 'master' of https://github.com/yuzu-emu/yuzu into service-impl 2018-04-26 14:28:54 -07:00
David Marcec
f1f7f2cba9 Added PREPO to logging backend, Removed comments from SaveReportWithUser 2018-04-26 14:19:34 -07:00
bunnei
4ac9b47dca Merge pull request #403 from lioncash/common
common: Remove chunk_file.h and linear_disk_cache.h
2018-04-26 16:45:41 -04:00
Lioncash
c33755e2b9 core: Replace remaining old non-generic logger usages with fmt-capable equivalents
LOG_GENERIC usages will be amended in a follow-up to keep API changes separate from
interface changes, as it will require removing a parameter from the relevant function
in the VMManager class.
2018-04-26 15:37:16 -04:00
Lioncash
87a92ef062 common: Remove chunk_file.h and linear_disk_cache.h
These are unused (and given chunk_file references Dolphin's >SVN< I doubt they were going to be used).
2018-04-26 14:59:32 -04:00
bunnei
c9d7abe9c9 gl_shader_decompiler: Boilerplate for handling integer instructions. 2018-04-26 14:38:42 -04:00
bunnei
37fa9a15cd gl_shader_decompiler: Move color output to EXIT instruction. 2018-04-26 14:38:41 -04:00
bunnei
3dd3cdeafd Merge pull request #401 from lioncash/gdbstub
core/gdbstub: Move logging macros to new fmt-compatible ones
2018-04-26 14:25:57 -04:00
Lioncash
623d772476 core/gdbstub: Move logging macros to new fmt-compatible ones 2018-04-26 12:04:50 -04:00
bunnei
4f281b3829 Merge pull request #400 from lioncash/hw
core/hw: Move logging macros over to fmt-capable ones
2018-04-26 10:35:36 -04:00
David Marcec
27650499bc GetIUserInterface->CreateUserInterface, Added todos and stub logs. Playreport->PlayReport. 2018-04-22 19:02:18 -07:00
David
df669bc540 lioncash proposed changes 2018-04-22 00:07:55 -07:00
David Marcec
f3137d3bc1 Implemented GetIUserInterface properly, Playreport and SSL::SetInterfaceVersion. Fixed ipc issues with IAudioDevice(wrong ids) 2018-04-21 22:04:24 -07:00
102 changed files with 1644 additions and 1607 deletions

View File

@@ -23,7 +23,7 @@ matrix:
- os: osx
env: NAME="macos build"
sudo: false
osx_image: xcode9.2
osx_image: xcode9.3
install: "./.travis/macos/deps.sh"
script: "./.travis/macos/build.sh"
after_success: "./.travis/macos/upload.sh"

View File

@@ -31,7 +31,6 @@ add_library(common STATIC
bit_set.h
break_points.cpp
break_points.h
chunk_file.h
cityhash.cpp
cityhash.h
color.h
@@ -41,7 +40,6 @@ add_library(common STATIC
file_util.cpp
file_util.h
hash.h
linear_disk_cache.h
logging/backend.cpp
logging/backend.h
logging/filter.cpp

View File

@@ -30,14 +30,15 @@ __declspec(noinline, noreturn)
#define ASSERT(_a_) \
do \
if (!(_a_)) { \
assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); }); \
assert_noinline_call([] { NGLOG_CRITICAL(Debug, "Assertion Failed!"); }); \
} \
while (0)
#define ASSERT_MSG(_a_, ...) \
do \
if (!(_a_)) { \
assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \
assert_noinline_call( \
[&] { NGLOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \
} \
while (0)

View File

@@ -1,623 +0,0 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
// Extremely simple serialization framework.
// (mis)-features:
// + Super fast
// + Very simple
// + Same code is used for serialization and deserializaition (in most cases)
// - Zero backwards/forwards compatibility
// - Serialization code for anything complex has to be manually written.
#include <cstring>
#include <deque>
#include <list>
#include <map>
#include <set>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
template <class T>
struct LinkedListItem : public T {
LinkedListItem<T>* next;
};
class PointerWrap;
class PointerWrapSection {
public:
PointerWrapSection(PointerWrap& p, int ver, const char* title)
: p_(p), ver_(ver), title_(title) {}
~PointerWrapSection();
bool operator==(const int& v) const {
return ver_ == v;
}
bool operator!=(const int& v) const {
return ver_ != v;
}
bool operator<=(const int& v) const {
return ver_ <= v;
}
bool operator>=(const int& v) const {
return ver_ >= v;
}
bool operator<(const int& v) const {
return ver_ < v;
}
bool operator>(const int& v) const {
return ver_ > v;
}
operator bool() const {
return ver_ > 0;
}
private:
PointerWrap& p_;
int ver_;
const char* title_;
};
// Wrapper class
class PointerWrap {
// This makes it a compile error if you forget to define DoState() on non-POD.
// Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason...
#ifdef _MSC_VER
template <typename T, bool isPOD = std::is_pod<T>::value,
bool isPointer = std::is_pointer<T>::value>
#else
template <typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value>
#endif
struct DoHelper {
static void DoArray(PointerWrap* p, T* x, int count) {
for (int i = 0; i < count; ++i)
p->Do(x[i]);
}
static void Do(PointerWrap* p, T& x) {
p->DoClass(x);
}
};
template <typename T>
struct DoHelper<T, true, false> {
static void DoArray(PointerWrap* p, T* x, int count) {
p->DoVoid((void*)x, sizeof(T) * count);
}
static void Do(PointerWrap* p, T& x) {
p->DoVoid((void*)&x, sizeof(x));
}
};
public:
enum Mode {
MODE_READ = 1, // load
MODE_WRITE, // save
MODE_MEASURE, // calculate size
MODE_VERIFY, // compare
};
enum Error {
ERROR_NONE = 0,
ERROR_WARNING = 1,
ERROR_FAILURE = 2,
};
u8** ptr;
Mode mode;
Error error;
public:
PointerWrap(u8** ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {}
PointerWrap(unsigned char** ptr_, int mode_)
: ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {}
PointerWrapSection Section(const char* title, int ver) {
return Section(title, ver, ver);
}
// The returned object can be compared against the version that was loaded.
// This can be used to support versions as old as minVer.
// Version = 0 means the section was not found.
PointerWrapSection Section(const char* title, int minVer, int ver) {
char marker[16] = {0};
int foundVersion = ver;
strncpy(marker, title, sizeof(marker));
if (!ExpectVoid(marker, sizeof(marker))) {
// Might be before we added name markers for safety.
if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion)))
DoMarker(title);
// Wasn't found, but maybe we can still load the state.
else
foundVersion = 0;
} else
Do(foundVersion);
if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) {
LOG_ERROR(Common, "Savestate failure: wrong version %d found for %s", foundVersion,
title);
SetError(ERROR_FAILURE);
return PointerWrapSection(*this, -1, title);
}
return PointerWrapSection(*this, foundVersion, title);
}
void SetMode(Mode mode_) {
mode = mode_;
}
Mode GetMode() const {
return mode;
}
u8** GetPPtr() {
return ptr;
}
void SetError(Error error_) {
if (error < error_)
error = error_;
if (error > ERROR_WARNING)
mode = PointerWrap::MODE_MEASURE;
}
bool ExpectVoid(void* data, int size) {
switch (mode) {
case MODE_READ:
if (memcmp(data, *ptr, size) != 0)
return false;
break;
case MODE_WRITE:
memcpy(*ptr, data, size);
break;
case MODE_MEASURE:
break; // MODE_MEASURE - don't need to do anything
case MODE_VERIFY:
for (int i = 0; i < size; i++) {
DEBUG_ASSERT_MSG(
((u8*)data)[i] == (*ptr)[i],
"Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n",
((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i],
&(*ptr)[i]);
}
break;
default:
break; // throw an error?
}
(*ptr) += size;
return true;
}
void DoVoid(void* data, int size) {
switch (mode) {
case MODE_READ:
memcpy(data, *ptr, size);
break;
case MODE_WRITE:
memcpy(*ptr, data, size);
break;
case MODE_MEASURE:
break; // MODE_MEASURE - don't need to do anything
case MODE_VERIFY:
for (int i = 0; i < size; i++) {
DEBUG_ASSERT_MSG(
((u8*)data)[i] == (*ptr)[i],
"Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n",
((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i],
&(*ptr)[i]);
}
break;
default:
break; // throw an error?
}
(*ptr) += size;
}
template <class K, class T>
void Do(std::map<K, T*>& x) {
if (mode == MODE_READ) {
for (auto it = x.begin(), end = x.end(); it != end; ++it) {
if (it->second != nullptr)
delete it->second;
}
}
T* dv = nullptr;
DoMap(x, dv);
}
template <class K, class T>
void Do(std::map<K, T>& x) {
T dv = T();
DoMap(x, dv);
}
template <class K, class T>
void DoMap(std::map<K, T>& x, T& default_val) {
unsigned int number = (unsigned int)x.size();
Do(number);
switch (mode) {
case MODE_READ: {
x.clear();
while (number > 0) {
K first = K();
Do(first);
T second = default_val;
Do(second);
x[first] = second;
--number;
}
} break;
case MODE_WRITE:
case MODE_MEASURE:
case MODE_VERIFY: {
typename std::map<K, T>::iterator itr = x.begin();
while (number > 0) {
K first = itr->first;
Do(first);
Do(itr->second);
--number;
++itr;
}
} break;
}
}
template <class K, class T>
void Do(std::multimap<K, T*>& x) {
if (mode == MODE_READ) {
for (auto it = x.begin(), end = x.end(); it != end; ++it) {
if (it->second != nullptr)
delete it->second;
}
}
T* dv = nullptr;
DoMultimap(x, dv);
}
template <class K, class T>
void Do(std::multimap<K, T>& x) {
T dv = T();
DoMultimap(x, dv);
}
template <class K, class T>
void DoMultimap(std::multimap<K, T>& x, T& default_val) {
unsigned int number = (unsigned int)x.size();
Do(number);
switch (mode) {
case MODE_READ: {
x.clear();
while (number > 0) {
K first = K();
Do(first);
T second = default_val;
Do(second);
x.insert(std::make_pair(first, second));
--number;
}
} break;
case MODE_WRITE:
case MODE_MEASURE:
case MODE_VERIFY: {
typename std::multimap<K, T>::iterator itr = x.begin();
while (number > 0) {
Do(itr->first);
Do(itr->second);
--number;
++itr;
}
} break;
}
}
// Store vectors.
template <class T>
void Do(std::vector<T*>& x) {
T* dv = nullptr;
DoVector(x, dv);
}
template <class T>
void Do(std::vector<T>& x) {
T dv = T();
DoVector(x, dv);
}
template <class T>
void DoPOD(std::vector<T>& x) {
T dv = T();
DoVectorPOD(x, dv);
}
template <class T>
void Do(std::vector<T>& x, T& default_val) {
DoVector(x, default_val);
}
template <class T>
void DoVector(std::vector<T>& x, T& default_val) {
u32 vec_size = (u32)x.size();
Do(vec_size);
x.resize(vec_size, default_val);
if (vec_size > 0)
DoArray(&x[0], vec_size);
}
template <class T>
void DoVectorPOD(std::vector<T>& x, T& default_val) {
u32 vec_size = (u32)x.size();
Do(vec_size);
x.resize(vec_size, default_val);
if (vec_size > 0)
DoArray(&x[0], vec_size);
}
// Store deques.
template <class T>
void Do(std::deque<T*>& x) {
T* dv = nullptr;
DoDeque(x, dv);
}
template <class T>
void Do(std::deque<T>& x) {
T dv = T();
DoDeque(x, dv);
}
template <class T>
void DoDeque(std::deque<T>& x, T& default_val) {
u32 deq_size = (u32)x.size();
Do(deq_size);
x.resize(deq_size, default_val);
u32 i;
for (i = 0; i < deq_size; i++)
Do(x[i]);
}
// Store STL lists.
template <class T>
void Do(std::list<T*>& x) {
T* dv = nullptr;
Do(x, dv);
}
template <class T>
void Do(std::list<T>& x) {
T dv = T();
DoList(x, dv);
}
template <class T>
void Do(std::list<T>& x, T& default_val) {
DoList(x, default_val);
}
template <class T>
void DoList(std::list<T>& x, T& default_val) {
u32 list_size = (u32)x.size();
Do(list_size);
x.resize(list_size, default_val);
typename std::list<T>::iterator itr, end;
for (itr = x.begin(), end = x.end(); itr != end; ++itr)
Do(*itr);
}
// Store STL sets.
template <class T>
void Do(std::set<T*>& x) {
if (mode == MODE_READ) {
for (auto it = x.begin(), end = x.end(); it != end; ++it) {
if (*it != nullptr)
delete *it;
}
}
DoSet(x);
}
template <class T>
void Do(std::set<T>& x) {
DoSet(x);
}
template <class T>
void DoSet(std::set<T>& x) {
unsigned int number = (unsigned int)x.size();
Do(number);
switch (mode) {
case MODE_READ: {
x.clear();
while (number-- > 0) {
T it = T();
Do(it);
x.insert(it);
}
} break;
case MODE_WRITE:
case MODE_MEASURE:
case MODE_VERIFY: {
typename std::set<T>::iterator itr = x.begin();
while (number-- > 0)
Do(*itr++);
} break;
default:
LOG_ERROR(Common, "Savestate error: invalid mode %d.", mode);
}
}
// Store strings.
void Do(std::string& x) {
int stringLen = (int)x.length() + 1;
Do(stringLen);
switch (mode) {
case MODE_READ:
x = (char*)*ptr;
break;
case MODE_WRITE:
memcpy(*ptr, x.c_str(), stringLen);
break;
case MODE_MEASURE:
break;
case MODE_VERIFY:
DEBUG_ASSERT_MSG((x == (char*)*ptr),
"Savestate verification failure: \"%s\" != \"%s\" (at %p).\n",
x.c_str(), (char*)*ptr, ptr);
break;
}
(*ptr) += stringLen;
}
void Do(std::wstring& x) {
int stringLen = sizeof(wchar_t) * ((int)x.length() + 1);
Do(stringLen);
switch (mode) {
case MODE_READ:
x = (wchar_t*)*ptr;
break;
case MODE_WRITE:
memcpy(*ptr, x.c_str(), stringLen);
break;
case MODE_MEASURE:
break;
case MODE_VERIFY:
DEBUG_ASSERT_MSG((x == (wchar_t*)*ptr),
"Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n",
x.c_str(), (wchar_t*)*ptr, ptr);
break;
}
(*ptr) += stringLen;
}
template <class T>
void DoClass(T& x) {
x.DoState(*this);
}
template <class T>
void DoClass(T*& x) {
if (mode == MODE_READ) {
if (x != nullptr)
delete x;
x = new T();
}
x->DoState(*this);
}
template <class T>
void DoArray(T* x, int count) {
DoHelper<T>::DoArray(this, x, count);
}
template <class T>
void Do(T& x) {
DoHelper<T>::Do(this, x);
}
template <class T>
void DoPOD(T& x) {
DoHelper<T>::Do(this, x);
}
template <class T>
void DoPointer(T*& x, T* const base) {
// pointers can be more than 2^31 apart, but you're using this function wrong if you need
// that much range
s32 offset = x - base;
Do(offset);
if (mode == MODE_READ)
x = base + offset;
}
template <class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*),
void (*TDo)(PointerWrap&, T*)>
void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end = nullptr) {
LinkedListItem<T>* list_cur = list_start;
LinkedListItem<T>* prev = nullptr;
while (true) {
u8 shouldExist = (list_cur ? 1 : 0);
Do(shouldExist);
if (shouldExist == 1) {
LinkedListItem<T>* cur = list_cur ? list_cur : TNew();
TDo(*this, (T*)cur);
if (!list_cur) {
if (mode == MODE_READ) {
cur->next = nullptr;
list_cur = cur;
if (prev)
prev->next = cur;
else
list_start = cur;
} else {
TFree(cur);
continue;
}
}
} else {
if (mode == MODE_READ) {
if (prev)
prev->next = nullptr;
if (list_end)
*list_end = prev;
if (list_cur) {
if (list_start == list_cur)
list_start = nullptr;
do {
LinkedListItem<T>* next = list_cur->next;
TFree(list_cur);
list_cur = next;
} while (list_cur);
}
}
break;
}
prev = list_cur;
list_cur = list_cur->next;
}
}
void DoMarker(const char* prevName, u32 arbitraryNumber = 0x42) {
u32 cookie = arbitraryNumber;
Do(cookie);
if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) {
LOG_ERROR(Common,
"After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). "
"Aborting savestate load...",
prevName, cookie, cookie, arbitraryNumber, arbitraryNumber);
SetError(ERROR_FAILURE);
}
}
};
inline PointerWrapSection::~PointerWrapSection() {
if (ver_ > 0) {
p_.DoMarker(title_);
}
}

View File

@@ -118,7 +118,7 @@ bool IsDirectory(const std::string& filename) {
#endif
if (result < 0) {
LOG_DEBUG(Common_Filesystem, "stat failed on %s: %s", filename.c_str(), GetLastErrorMsg());
NGLOG_DEBUG(Common_Filesystem, "stat failed on {}: {}", filename, GetLastErrorMsg());
return false;
}
@@ -128,31 +128,29 @@ bool IsDirectory(const std::string& filename) {
// Deletes a given filename, return true on success
// Doesn't supports deleting a directory
bool Delete(const std::string& filename) {
LOG_TRACE(Common_Filesystem, "file %s", filename.c_str());
NGLOG_TRACE(Common_Filesystem, "file {}", filename);
// Return true because we care about the file no
// being there, not the actual delete.
if (!Exists(filename)) {
LOG_DEBUG(Common_Filesystem, "%s does not exist", filename.c_str());
NGLOG_DEBUG(Common_Filesystem, "{} does not exist", filename);
return true;
}
// We can't delete a directory
if (IsDirectory(filename)) {
LOG_ERROR(Common_Filesystem, "Failed: %s is a directory", filename.c_str());
NGLOG_ERROR(Common_Filesystem, "Failed: {} is a directory", filename);
return false;
}
#ifdef _WIN32
if (!DeleteFileW(Common::UTF8ToUTF16W(filename).c_str())) {
LOG_ERROR(Common_Filesystem, "DeleteFile failed on %s: %s", filename.c_str(),
GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "DeleteFile failed on {}: {}", filename, GetLastErrorMsg());
return false;
}
#else
if (unlink(filename.c_str()) == -1) {
LOG_ERROR(Common_Filesystem, "unlink failed on %s: %s", filename.c_str(),
GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "unlink failed on {}: {}", filename, GetLastErrorMsg());
return false;
}
#endif
@@ -162,16 +160,16 @@ bool Delete(const std::string& filename) {
// Returns true if successful, or path already exists.
bool CreateDir(const std::string& path) {
LOG_TRACE(Common_Filesystem, "directory %s", path.c_str());
NGLOG_TRACE(Common_Filesystem, "directory {}", path);
#ifdef _WIN32
if (::CreateDirectoryW(Common::UTF8ToUTF16W(path).c_str(), nullptr))
return true;
DWORD error = GetLastError();
if (error == ERROR_ALREADY_EXISTS) {
LOG_DEBUG(Common_Filesystem, "CreateDirectory failed on %s: already exists", path.c_str());
NGLOG_DEBUG(Common_Filesystem, "CreateDirectory failed on {}: already exists", path);
return true;
}
LOG_ERROR(Common_Filesystem, "CreateDirectory failed on %s: %i", path.c_str(), error);
NGLOG_ERROR(Common_Filesystem, "CreateDirectory failed on {}: {}", path, error);
return false;
#else
if (mkdir(path.c_str(), 0755) == 0)
@@ -180,11 +178,11 @@ bool CreateDir(const std::string& path) {
int err = errno;
if (err == EEXIST) {
LOG_DEBUG(Common_Filesystem, "mkdir failed on %s: already exists", path.c_str());
NGLOG_DEBUG(Common_Filesystem, "mkdir failed on {}: already exists", path);
return true;
}
LOG_ERROR(Common_Filesystem, "mkdir failed on %s: %s", path.c_str(), strerror(err));
NGLOG_ERROR(Common_Filesystem, "mkdir failed on {}: {}", path, strerror(err));
return false;
#endif
}
@@ -192,10 +190,10 @@ bool CreateDir(const std::string& path) {
// Creates the full path of fullPath returns true on success
bool CreateFullPath(const std::string& fullPath) {
int panicCounter = 100;
LOG_TRACE(Common_Filesystem, "path %s", fullPath.c_str());
NGLOG_TRACE(Common_Filesystem, "path {}", fullPath);
if (FileUtil::Exists(fullPath)) {
LOG_DEBUG(Common_Filesystem, "path exists %s", fullPath.c_str());
NGLOG_DEBUG(Common_Filesystem, "path exists {}", fullPath);
return true;
}
@@ -211,14 +209,14 @@ bool CreateFullPath(const std::string& fullPath) {
// Include the '/' so the first call is CreateDir("/") rather than CreateDir("")
std::string const subPath(fullPath.substr(0, position + 1));
if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) {
LOG_ERROR(Common, "CreateFullPath: directory creation failed");
NGLOG_ERROR(Common, "CreateFullPath: directory creation failed");
return false;
}
// A safety check
panicCounter--;
if (panicCounter <= 0) {
LOG_ERROR(Common, "CreateFullPath: directory structure is too deep");
NGLOG_ERROR(Common, "CreateFullPath: directory structure is too deep");
return false;
}
position++;
@@ -227,11 +225,11 @@ bool CreateFullPath(const std::string& fullPath) {
// Deletes a directory filename, returns true on success
bool DeleteDir(const std::string& filename) {
LOG_TRACE(Common_Filesystem, "directory %s", filename.c_str());
NGLOG_TRACE(Common_Filesystem, "directory {}", filename);
// check if a directory
if (!FileUtil::IsDirectory(filename)) {
LOG_ERROR(Common_Filesystem, "Not a directory %s", filename.c_str());
NGLOG_ERROR(Common_Filesystem, "Not a directory {}", filename);
return false;
}
@@ -242,14 +240,14 @@ bool DeleteDir(const std::string& filename) {
if (rmdir(filename.c_str()) == 0)
return true;
#endif
LOG_ERROR(Common_Filesystem, "failed %s: %s", filename.c_str(), GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg());
return false;
}
// renames file srcFilename to destFilename, returns true on success
bool Rename(const std::string& srcFilename, const std::string& destFilename) {
LOG_TRACE(Common_Filesystem, "%s --> %s", srcFilename.c_str(), destFilename.c_str());
NGLOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename);
#ifdef _WIN32
if (_wrename(Common::UTF8ToUTF16W(srcFilename).c_str(),
Common::UTF8ToUTF16W(destFilename).c_str()) == 0)
@@ -258,21 +256,21 @@ bool Rename(const std::string& srcFilename, const std::string& destFilename) {
if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
return true;
#endif
LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(),
GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "failed {} --> {}: {}", srcFilename, destFilename,
GetLastErrorMsg());
return false;
}
// copies file srcFilename to destFilename, returns true on success
bool Copy(const std::string& srcFilename, const std::string& destFilename) {
LOG_TRACE(Common_Filesystem, "%s --> %s", srcFilename.c_str(), destFilename.c_str());
NGLOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename);
#ifdef _WIN32
if (CopyFileW(Common::UTF8ToUTF16W(srcFilename).c_str(),
Common::UTF8ToUTF16W(destFilename).c_str(), FALSE))
return true;
LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(),
GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "failed {} --> {}: {}", srcFilename, destFilename,
GetLastErrorMsg());
return false;
#else
@@ -284,8 +282,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
// Open input file
FILE* input = fopen(srcFilename.c_str(), "rb");
if (!input) {
LOG_ERROR(Common_Filesystem, "opening input failed %s --> %s: %s", srcFilename.c_str(),
destFilename.c_str(), GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "opening input failed {} --> {}: {}", srcFilename,
destFilename, GetLastErrorMsg());
return false;
}
@@ -293,8 +291,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
FILE* output = fopen(destFilename.c_str(), "wb");
if (!output) {
fclose(input);
LOG_ERROR(Common_Filesystem, "opening output failed %s --> %s: %s", srcFilename.c_str(),
destFilename.c_str(), GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "opening output failed {} --> {}: {}", srcFilename,
destFilename, GetLastErrorMsg());
return false;
}
@@ -304,8 +302,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
size_t rnum = fread(buffer, sizeof(char), BSIZE, input);
if (rnum != BSIZE) {
if (ferror(input) != 0) {
LOG_ERROR(Common_Filesystem, "failed reading from source, %s --> %s: %s",
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "failed reading from source, {} --> {}: {}",
srcFilename, destFilename, GetLastErrorMsg());
goto bail;
}
}
@@ -313,8 +311,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
// write output
size_t wnum = fwrite(buffer, sizeof(char), rnum, output);
if (wnum != rnum) {
LOG_ERROR(Common_Filesystem, "failed writing to output, %s --> %s: %s",
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "failed writing to output, {} --> {}: {}", srcFilename,
destFilename, GetLastErrorMsg());
goto bail;
}
}
@@ -334,12 +332,12 @@ bail:
// Returns the size of filename (64bit)
u64 GetSize(const std::string& filename) {
if (!Exists(filename)) {
LOG_ERROR(Common_Filesystem, "failed %s: No such file", filename.c_str());
NGLOG_ERROR(Common_Filesystem, "failed {}: No such file", filename);
return 0;
}
if (IsDirectory(filename)) {
LOG_ERROR(Common_Filesystem, "failed %s: is a directory", filename.c_str());
NGLOG_ERROR(Common_Filesystem, "failed {}: is a directory", filename);
return 0;
}
@@ -350,11 +348,11 @@ u64 GetSize(const std::string& filename) {
if (stat(filename.c_str(), &buf) == 0)
#endif
{
LOG_TRACE(Common_Filesystem, "%s: %lld", filename.c_str(), (long long)buf.st_size);
NGLOG_TRACE(Common_Filesystem, "{}: {}", filename, buf.st_size);
return buf.st_size;
}
LOG_ERROR(Common_Filesystem, "Stat failed %s: %s", filename.c_str(), GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "Stat failed {}: {}", filename, GetLastErrorMsg());
return 0;
}
@@ -362,7 +360,7 @@ u64 GetSize(const std::string& filename) {
u64 GetSize(const int fd) {
struct stat buf;
if (fstat(fd, &buf) != 0) {
LOG_ERROR(Common_Filesystem, "GetSize: stat failed %i: %s", fd, GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "GetSize: stat failed {}: {}", fd, GetLastErrorMsg());
return 0;
}
return buf.st_size;
@@ -373,12 +371,14 @@ u64 GetSize(FILE* f) {
// can't use off_t here because it can be 32-bit
u64 pos = ftello(f);
if (fseeko(f, 0, SEEK_END) != 0) {
LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s", f, GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "GetSize: seek failed {}: {}", fmt::ptr(f),
GetLastErrorMsg());
return 0;
}
u64 size = ftello(f);
if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) {
LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s", f, GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "GetSize: seek failed {}: {}", fmt::ptr(f),
GetLastErrorMsg());
return 0;
}
return size;
@@ -386,10 +386,10 @@ u64 GetSize(FILE* f) {
// creates an empty file filename, returns true on success
bool CreateEmptyFile(const std::string& filename) {
LOG_TRACE(Common_Filesystem, "%s", filename.c_str());
NGLOG_TRACE(Common_Filesystem, "{}", filename);
if (!FileUtil::IOFile(filename, "wb")) {
LOG_ERROR(Common_Filesystem, "failed %s: %s", filename.c_str(), GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg());
return false;
}
@@ -398,7 +398,7 @@ bool CreateEmptyFile(const std::string& filename) {
bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string& directory,
DirectoryEntryCallable callback) {
LOG_TRACE(Common_Filesystem, "directory %s", directory.c_str());
NGLOG_TRACE(Common_Filesystem, "directory {}", directory);
// How many files + directories we found
unsigned found_entries = 0;
@@ -556,7 +556,7 @@ std::string GetCurrentDir() {
char* dir;
if (!(dir = getcwd(nullptr, 0))) {
#endif
LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: %s", GetLastErrorMsg());
NGLOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: {}", GetLastErrorMsg());
return nullptr;
}
#ifdef _WIN32
@@ -653,12 +653,12 @@ static const std::string GetUserDirectory(const std::string& envvar) {
else if (envvar == "XDG_CACHE_HOME")
subdirectory = DIR_SEP ".cache";
else
ASSERT_MSG(false, "Unknown XDG variable %s.", envvar.c_str());
ASSERT_MSG(false, "Unknown XDG variable {}.", envvar);
user_dir = GetHomeDirectory() + subdirectory;
}
ASSERT_MSG(!user_dir.empty(), "User directory %s musnt be empty.", envvar.c_str());
ASSERT_MSG(user_dir[0] == '/', "User directory %s must be absolute.", envvar.c_str());
ASSERT_MSG(!user_dir.empty(), "User directory {} mustnt be empty.", envvar);
ASSERT_MSG(user_dir[0] == '/', "User directory {} must be absolute.", envvar);
return user_dir;
}
@@ -676,7 +676,7 @@ std::string GetSysDirectory() {
#endif
sysDir += DIR_SEP;
LOG_DEBUG(Common_Filesystem, "Setting to %s:", sysDir.c_str());
NGLOG_DEBUG(Common_Filesystem, "Setting to {}:", sysDir);
return sysDir;
}
@@ -692,7 +692,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string& new
if (!FileUtil::IsDirectory(paths[D_USER_IDX])) {
paths[D_USER_IDX] = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP;
} else {
LOG_INFO(Common_Filesystem, "Using the local user directory");
NGLOG_INFO(Common_Filesystem, "Using the local user directory");
}
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
@@ -719,7 +719,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string& new
if (!newPath.empty()) {
if (!FileUtil::IsDirectory(newPath)) {
LOG_ERROR(Common_Filesystem, "Invalid path specified %s", newPath.c_str());
NGLOG_ERROR(Common_Filesystem, "Invalid path specified {}", newPath);
return paths[DirIDX];
} else {
paths[DirIDX] = newPath;
@@ -809,16 +809,16 @@ IOFile::~IOFile() {
Close();
}
IOFile::IOFile(IOFile&& other) {
IOFile::IOFile(IOFile&& other) noexcept {
Swap(other);
}
IOFile& IOFile::operator=(IOFile&& other) {
IOFile& IOFile::operator=(IOFile&& other) noexcept {
Swap(other);
return *this;
}
void IOFile::Swap(IOFile& other) {
void IOFile::Swap(IOFile& other) noexcept {
std::swap(m_file, other.m_file);
std::swap(m_good, other.m_good);
}

View File

@@ -160,22 +160,18 @@ public:
~IOFile();
IOFile(IOFile&& other);
IOFile& operator=(IOFile&& other);
IOFile(IOFile&& other) noexcept;
IOFile& operator=(IOFile&& other) noexcept;
void Swap(IOFile& other);
void Swap(IOFile& other) noexcept;
bool Open(const std::string& filename, const char openmode[]);
bool Close();
template <typename T>
size_t ReadArray(T* data, size_t length) {
static_assert(std::is_standard_layout<T>(),
"Given array does not consist of standard layout objects");
#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
static_assert(std::is_trivially_copyable<T>(),
"Given array does not consist of trivially copyable objects");
#endif
if (!IsOpen()) {
m_good = false;
@@ -191,12 +187,8 @@ public:
template <typename T>
size_t WriteArray(const T* data, size_t length) {
static_assert(std::is_standard_layout<T>(),
"Given array does not consist of standard layout objects");
#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
static_assert(std::is_trivially_copyable<T>(),
"Given array does not consist of trivially copyable objects");
#endif
if (!IsOpen()) {
m_good = false;
@@ -210,11 +202,15 @@ public:
return items_written;
}
size_t ReadBytes(void* data, size_t length) {
template <typename T>
size_t ReadBytes(T* data, size_t length) {
static_assert(std::is_trivially_copyable<T>(), "T must be trivially copyable");
return ReadArray(reinterpret_cast<char*>(data), length);
}
size_t WriteBytes(const void* data, size_t length) {
template <typename T>
size_t WriteBytes(const T* data, size_t length) {
static_assert(std::is_trivially_copyable<T>(), "T must be trivially copyable");
return WriteArray(reinterpret_cast<const char*>(data), length);
}

View File

@@ -1,167 +0,0 @@
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <fstream>
#include "common/common_types.h"
// defined in Version.cpp
extern const char* scm_rev_git_str;
// On disk format:
// header{
// u32 'DCAC';
// u32 version; // svn_rev
// u16 sizeof(key_type);
// u16 sizeof(value_type);
//}
// key_value_pair{
// u32 value_size;
// key_type key;
// value_type[value_size] value;
//}
template <typename K, typename V>
class LinearDiskCacheReader {
public:
virtual void Read(const K& key, const V* value, u32 value_size) = 0;
};
// Dead simple unsorted key-value store with append functionality.
// No random read functionality, all reading is done in OpenAndRead.
// Keys and values can contain any characters, including \0.
//
// Suitable for caching generated shader bytecode between executions.
// Not tuned for extreme performance but should be reasonably fast.
// Does not support keys or values larger than 2GB, which should be reasonable.
// Keys must have non-zero length; values can have zero length.
// K and V are some POD type
// K : the key type
// V : value array type
template <typename K, typename V>
class LinearDiskCache {
public:
// return number of read entries
u32 OpenAndRead(const char* filename, LinearDiskCacheReader<K, V>& reader) {
using std::ios_base;
// close any currently opened file
Close();
m_num_entries = 0;
// try opening for reading/writing
OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary);
m_file.seekg(0, std::ios::end);
std::fstream::pos_type end_pos = m_file.tellg();
m_file.seekg(0, std::ios::beg);
std::fstream::pos_type start_pos = m_file.tellg();
std::streamoff file_size = end_pos - start_pos;
if (m_file.is_open() && ValidateHeader()) {
// good header, read some key/value pairs
K key;
V* value = nullptr;
u32 value_size;
u32 entry_number;
std::fstream::pos_type last_pos = m_file.tellg();
while (Read(&value_size)) {
std::streamoff next_extent =
(last_pos - start_pos) + sizeof(value_size) + value_size;
if (next_extent > file_size)
break;
delete[] value;
value = new V[value_size];
// read key/value and pass to reader
if (Read(&key) && Read(value, value_size) && Read(&entry_number) &&
entry_number == m_num_entries + 1) {
reader.Read(key, value, value_size);
} else {
break;
}
m_num_entries++;
last_pos = m_file.tellg();
}
m_file.seekp(last_pos);
m_file.clear();
delete[] value;
return m_num_entries;
}
// failed to open file for reading or bad header
// close and recreate file
Close();
m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary);
WriteHeader();
return 0;
}
void Sync() {
m_file.flush();
}
void Close() {
if (m_file.is_open())
m_file.close();
// clear any error flags
m_file.clear();
}
// Appends a key-value pair to the store.
void Append(const K& key, const V* value, u32 value_size) {
// TODO: Should do a check that we don't already have "key"? (I think each caller does that
// already.)
Write(&value_size);
Write(&key);
Write(value, value_size);
m_num_entries++;
Write(&m_num_entries);
}
private:
void WriteHeader() {
Write(&m_header);
}
bool ValidateHeader() {
char file_header[sizeof(Header)];
return (Read(file_header, sizeof(Header)) &&
!memcmp((const char*)&m_header, file_header, sizeof(Header)));
}
template <typename D>
bool Write(const D* data, u32 count = 1) {
return m_file.write((const char*)data, count * sizeof(D)).good();
}
template <typename D>
bool Read(const D* data, u32 count = 1) {
return m_file.read((char*)data, count * sizeof(D)).good();
}
struct Header {
Header() : id(*(u32*)"DCAC"), key_t_size(sizeof(K)), value_t_size(sizeof(V)) {
memcpy(ver, scm_rev_git_str, 40);
}
const u32 id;
const u16 key_t_size, value_t_size;
char ver[40];
} m_header;
std::fstream m_file;
u32 m_num_entries;
};

View File

@@ -2,11 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <cstdio>
#include <utility>
#include "common/assert.h"
#include "common/common_funcs.h" // snprintf compatibility define
#include "common/logging/backend.h"
#include "common/logging/filter.h"
#include "common/logging/log.h"
@@ -48,6 +45,7 @@ namespace Log {
SUB(Service, NS) \
SUB(Service, NVDRV) \
SUB(Service, PCTL) \
SUB(Service, PREPO) \
SUB(Service, SET) \
SUB(Service, SM) \
SUB(Service, SPL) \
@@ -131,21 +129,6 @@ void SetFilter(Filter* new_filter) {
filter = new_filter;
}
void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_num,
const char* function, const char* format, ...) {
if (filter && !filter->CheckMessage(log_class, log_level))
return;
std::array<char, 4 * 1024> formatting_buffer;
va_list args;
va_start(args, format);
vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args);
va_end(args);
Entry entry = CreateEntry(log_class, log_level, filename, line_num, function,
std::string(formatting_buffer.data()));
PrintColoredMessage(entry);
}
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
unsigned int line_num, const char* function, const char* format,
const fmt::format_args& args) {

View File

@@ -65,6 +65,7 @@ enum class Class : ClassType {
Service_NS, ///< The NS services
Service_NVDRV, ///< The NVDRV (Nvidia driver) service
Service_PCTL, ///< The PCTL (Parental control) service
Service_PREPO, ///< The PREPO (Play report) service
Service_SET, ///< The SET (Settings) service
Service_SM, ///< The SM (Service manager) service
Service_SPL, ///< The SPL service
@@ -91,19 +92,6 @@ enum class Class : ClassType {
Count ///< Total number of logging classes
};
/// Logs a message to the global logger.
void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_num,
const char* function,
#ifdef _MSC_VER
_Printf_format_string_
#endif
const char* format,
...)
#ifdef __GNUC__
__attribute__((format(printf, 6, 7)))
#endif
;
/// Logs a message to the global logger, using fmt
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
unsigned int line_num, const char* function, const char* format,
@@ -118,28 +106,6 @@ void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsig
} // namespace Log
#define LOG_GENERIC(log_class, log_level, ...) \
::Log::LogMessage(log_class, log_level, __FILE__, __LINE__, __func__, __VA_ARGS__)
#ifdef _DEBUG
#define LOG_TRACE(log_class, ...) \
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Trace, __VA_ARGS__)
#else
#define LOG_TRACE(log_class, ...) (void(0))
#endif
#define LOG_DEBUG(log_class, ...) \
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Debug, __VA_ARGS__)
#define LOG_INFO(log_class, ...) \
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Info, __VA_ARGS__)
#define LOG_WARNING(log_class, ...) \
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Warning, __VA_ARGS__)
#define LOG_ERROR(log_class, ...) \
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Error, __VA_ARGS__)
#define LOG_CRITICAL(log_class, ...) \
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Critical, __VA_ARGS__)
// Define the fmt lib macros
#ifdef _DEBUG
#define NGLOG_TRACE(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Trace, __FILE__, __LINE__, \

View File

@@ -55,7 +55,7 @@ void* AllocateExecutableMemory(size_t size, bool low) {
if (ptr == MAP_FAILED) {
ptr = nullptr;
#endif
LOG_ERROR(Common_Memory, "Failed to allocate executable memory");
NGLOG_ERROR(Common_Memory, "Failed to allocate executable memory");
}
#if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT)
else {
@@ -68,7 +68,7 @@ void* AllocateExecutableMemory(size_t size, bool low) {
#if EMU_ARCH_BITS == 64
if ((u64)ptr >= 0x80000000 && low == true)
LOG_ERROR(Common_Memory, "Executable memory ended up above 2GB!");
NGLOG_ERROR(Common_Memory, "Executable memory ended up above 2GB!");
#endif
return ptr;
@@ -85,7 +85,7 @@ void* AllocateMemoryPages(size_t size) {
#endif
if (ptr == nullptr)
LOG_ERROR(Common_Memory, "Failed to allocate raw memory");
NGLOG_ERROR(Common_Memory, "Failed to allocate raw memory");
return ptr;
}
@@ -99,12 +99,12 @@ void* AllocateAlignedMemory(size_t size, size_t alignment) {
ptr = memalign(alignment, size);
#else
if (posix_memalign(&ptr, alignment, size) != 0)
LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
NGLOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
#endif
#endif
if (ptr == nullptr)
LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
NGLOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
return ptr;
}
@@ -113,7 +113,7 @@ void FreeMemoryPages(void* ptr, size_t size) {
if (ptr) {
#ifdef _WIN32
if (!VirtualFree(ptr, 0, MEM_RELEASE))
LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n%s", GetLastErrorMsg());
NGLOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n{}", GetLastErrorMsg());
#else
munmap(ptr, size);
#endif
@@ -134,7 +134,7 @@ void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
#ifdef _WIN32
DWORD oldValue;
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
LOG_ERROR(Common_Memory, "WriteProtectMemory failed!\n%s", GetLastErrorMsg());
NGLOG_ERROR(Common_Memory, "WriteProtectMemory failed!\n{}", GetLastErrorMsg());
#else
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
#endif
@@ -145,7 +145,7 @@ void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
DWORD oldValue;
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE,
&oldValue))
LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n%s", GetLastErrorMsg());
NGLOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n{}", GetLastErrorMsg());
#else
mprotect(ptr, size,
allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
@@ -167,8 +167,7 @@ std::string MemUsage() {
return "MemUsage Error";
if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
Ret = Common::StringFromFormat(
"%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
Ret = fmt::format("{} K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7));
CloseHandle(hProcess);
return Ret;

View File

@@ -25,7 +25,7 @@ ParamPackage::ParamPackage(const std::string& serialized) {
std::vector<std::string> key_value;
Common::SplitString(pair, KEY_VALUE_SEPARATOR, key_value);
if (key_value.size() != 2) {
LOG_ERROR(Common, "invalid key pair %s", pair.c_str());
NGLOG_ERROR(Common, "invalid key pair {}", pair);
continue;
}
@@ -64,7 +64,7 @@ std::string ParamPackage::Serialize() const {
std::string ParamPackage::Get(const std::string& key, const std::string& default_value) const {
auto pair = data.find(key);
if (pair == data.end()) {
LOG_DEBUG(Common, "key %s not found", key.c_str());
NGLOG_DEBUG(Common, "key '{}' not found", key);
return default_value;
}
@@ -74,14 +74,14 @@ std::string ParamPackage::Get(const std::string& key, const std::string& default
int ParamPackage::Get(const std::string& key, int default_value) const {
auto pair = data.find(key);
if (pair == data.end()) {
LOG_DEBUG(Common, "key %s not found", key.c_str());
NGLOG_DEBUG(Common, "key '{}' not found", key);
return default_value;
}
try {
return std::stoi(pair->second);
} catch (const std::logic_error&) {
LOG_ERROR(Common, "failed to convert %s to int", pair->second.c_str());
NGLOG_ERROR(Common, "failed to convert {} to int", pair->second);
return default_value;
}
}
@@ -89,14 +89,14 @@ int ParamPackage::Get(const std::string& key, int default_value) const {
float ParamPackage::Get(const std::string& key, float default_value) const {
auto pair = data.find(key);
if (pair == data.end()) {
LOG_DEBUG(Common, "key %s not found", key.c_str());
NGLOG_DEBUG(Common, "key {} not found", key);
return default_value;
}
try {
return std::stof(pair->second);
} catch (const std::logic_error&) {
LOG_ERROR(Common, "failed to convert %s to float", pair->second.c_str());
NGLOG_ERROR(Common, "failed to convert {} to float", pair->second);
return default_value;
}
}

View File

@@ -46,76 +46,6 @@ bool AsciiToHex(const char* _szValue, u32& result) {
return true;
}
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) {
int writtenCount;
#ifdef _MSC_VER
// You would think *printf are simple, right? Iterate on each character,
// if it's a format specifier handle it properly, etc.
//
// Nooooo. Not according to the C standard.
//
// According to the C99 standard (7.19.6.1 "The fprintf function")
// The format shall be a multibyte character sequence
//
// Because some character encodings might have '%' signs in the middle of
// a multibyte sequence (SJIS for example only specifies that the first
// byte of a 2 byte sequence is "high", the second byte can be anything),
// printf functions have to decode the multibyte sequences and try their
// best to not screw up.
//
// Unfortunately, on Windows, the locale for most languages is not UTF-8
// as we would need. Notably, for zh_TW, Windows chooses EUC-CN as the
// locale, and completely fails when trying to decode UTF-8 as EUC-CN.
//
// On the other hand, the fix is simple: because we use UTF-8, no such
// multibyte handling is required as we can simply assume that no '%' char
// will be present in the middle of a multibyte sequence.
//
// This is why we lookup an ANSI (cp1252) locale here and use _vsnprintf_l.
static locale_t c_locale = nullptr;
if (!c_locale)
c_locale = _create_locale(LC_ALL, ".1252");
writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args);
#else
writtenCount = vsnprintf(out, outsize, format, args);
#endif
if (writtenCount > 0 && writtenCount < outsize) {
out[writtenCount] = '\0';
return true;
} else {
out[outsize - 1] = '\0';
return false;
}
}
std::string StringFromFormat(const char* format, ...) {
va_list args;
char* buf = nullptr;
#ifdef _WIN32
int required = 0;
va_start(args, format);
required = _vscprintf(format, args);
buf = new char[required + 1];
CharArrayFromFormatV(buf, required + 1, format, args);
va_end(args);
std::string temp = buf;
delete[] buf;
#else
va_start(args, format);
if (vasprintf(&buf, format, args) < 0)
LOG_ERROR(Common, "Unable to allocate memory for string");
va_end(args);
std::string temp = buf;
free(buf);
#endif
return temp;
}
// For Debugging. Read out an u8 array.
std::string ArrayToString(const u8* data, size_t size, int line_len, bool spaces) {
std::ostringstream oss;
@@ -347,7 +277,7 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
iconv_t const conv_desc = iconv_open("UTF-8", fromcode);
if ((iconv_t)(-1) == conv_desc) {
LOG_ERROR(Common, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno));
NGLOG_ERROR(Common, "Iconv initialization failure [{}]: {}", fromcode, strerror(errno));
iconv_close(conv_desc);
return {};
}
@@ -376,7 +306,7 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
++src_buffer;
}
} else {
LOG_ERROR(Common, "iconv failure [%s]: %s", fromcode, strerror(errno));
NGLOG_ERROR(Common, "iconv failure [{}]: {}", fromcode, strerror(errno));
break;
}
}
@@ -395,7 +325,7 @@ std::u16string UTF8ToUTF16(const std::string& input) {
iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8");
if ((iconv_t)(-1) == conv_desc) {
LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: %s", strerror(errno));
NGLOG_ERROR(Common, "Iconv initialization failure [UTF-8]: {}", strerror(errno));
iconv_close(conv_desc);
return {};
}
@@ -424,7 +354,7 @@ std::u16string UTF8ToUTF16(const std::string& input) {
++src_buffer;
}
} else {
LOG_ERROR(Common, "iconv failure [UTF-8]: %s", strerror(errno));
NGLOG_ERROR(Common, "iconv failure [UTF-8]: {}", strerror(errno));
break;
}
}

View File

@@ -4,7 +4,6 @@
#pragma once
#include <cstdarg>
#include <cstddef>
#include <iomanip>
#include <sstream>
@@ -20,19 +19,6 @@ std::string ToLower(std::string str);
/// Make a string uppercase
std::string ToUpper(std::string str);
std::string StringFromFormat(const char* format, ...);
// Cheap!
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args);
template <size_t Count>
inline void CharArrayFromFormat(char (&out)[Count], const char* format, ...) {
va_list args;
va_start(args, format);
CharArrayFromFormatV(out, Count, format, args);
va_end(args);
}
// Good
std::string ArrayToString(const u8* data, size_t size, int line_len = 20, bool spaces = true);
std::string StripSpaces(const std::string& s);

View File

@@ -2,7 +2,10 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <time.h>
#include <ctime>
#include <fmt/format.h>
#ifdef _WIN32
#include <windows.h>
// windows.h needs to be included before other windows headers
@@ -104,8 +107,8 @@ std::string Timer::GetTimeElapsedFormatted() const {
// Hours
u32 Hours = Minutes / 60;
std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i", Hours, Minutes % 60, Seconds % 60,
Milliseconds % 1000);
std::string TmpStr = fmt::format("{:02}:{:02}:{:02}:{:03}", Hours, Minutes % 60, Seconds % 60,
Milliseconds % 1000);
return TmpStr;
}
@@ -165,11 +168,11 @@ std::string Timer::GetTimeFormatted() {
#ifdef _WIN32
struct timeb tp;
(void)::ftime(&tp);
return StringFromFormat("%s:%03i", tmp, tp.millitm);
return fmt::format("{}:{:03}", tmp, tp.millitm);
#else
struct timeval t;
(void)gettimeofday(&t, nullptr);
return StringFromFormat("%s:%03d", tmp, (int)(t.tv_usec / 1000));
return fmt::format("{}:{:03}", tmp, static_cast<int>(t.tv_usec / 1000));
#endif
}

View File

@@ -52,8 +52,8 @@ static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w);
template <typename T>
class Vec2 {
public:
T x;
T y;
T x{};
T y{};
Vec2() = default;
Vec2(const T& _x, const T& _y) : x(_x), y(_y) {}
@@ -192,9 +192,9 @@ inline float Vec2<float>::Normalize() {
template <typename T>
class Vec3 {
public:
T x;
T y;
T z;
T x{};
T y{};
T z{};
Vec3() = default;
Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {}
@@ -392,10 +392,10 @@ typedef Vec3<float> Vec3f;
template <typename T>
class Vec4 {
public:
T x;
T y;
T z;
T w;
T x{};
T y{};
T z{};
T w{};
Vec4() = default;
Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {}

View File

@@ -185,6 +185,8 @@ add_library(core STATIC
hle/service/pctl/module.h
hle/service/pctl/pctl.cpp
hle/service/pctl/pctl.h
hle/service/prepo/prepo.cpp
hle/service/prepo/prepo.h
hle/service/service.cpp
hle/service/service.h
hle/service/set/set.cpp
@@ -251,6 +253,7 @@ add_library(core STATIC
loader/nso.h
memory.cpp
memory.h
memory_hook.cpp
memory_hook.h
memory_setup.h
perf_stats.cpp

View File

@@ -55,8 +55,8 @@ public:
}
void InterpreterFallback(u64 pc, size_t num_instructions) override {
LOG_INFO(Core_ARM, "Unicorn fallback @ 0x%" PRIx64 " for %zu instructions (instr = %08x)",
pc, num_instructions, MemoryReadCode(pc));
NGLOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc,
num_instructions, MemoryReadCode(pc));
ARM_Interface::ThreadContext ctx;
parent.SaveContext(ctx);
@@ -76,7 +76,7 @@ public:
case Dynarmic::A64::Exception::Yield:
return;
default:
ASSERT_MSG(false, "ExceptionRaised(exception = %zu, pc = %" PRIx64 ")",
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:X})",
static_cast<size_t>(exception), pc);
}
}

View File

@@ -30,7 +30,7 @@ LoadDll LoadDll::g_load_dll;
#define CHECKED(expr) \
do { \
if (auto _cerr = (expr)) { \
ASSERT_MSG(false, "Call " #expr " failed with error: %u (%s)\n", _cerr, \
ASSERT_MSG(false, "Call " #expr " failed with error: {} ({})\n", _cerr, \
uc_strerror(_cerr)); \
} \
} while (0)
@@ -53,7 +53,7 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si
void* user_data) {
ARM_Interface::ThreadContext ctx{};
Core::CPU().SaveContext(ctx);
ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x%lx, pc=0x%lx, lr=0x%lx", addr,
ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x{:X}, pc=0x{:X}, lr=0x{:X}", addr,
ctx.pc, ctx.cpu_registers[30]);
return {};
}

View File

@@ -55,7 +55,7 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
// If we don't have a currently active thread then don't execute instructions,
// instead advance to the next event and try to yield to the next thread
if (Kernel::GetCurrentThread() == nullptr) {
LOG_TRACE(Core_ARM, "Idling");
NGLOG_TRACE(Core_ARM, "Idling");
CoreTiming::Idle();
CoreTiming::Advance();
PrepareReschedule();
@@ -82,15 +82,15 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
app_loader = Loader::GetLoader(filepath);
if (!app_loader) {
LOG_CRITICAL(Core, "Failed to obtain loader for %s!", filepath.c_str());
NGLOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
return ResultStatus::ErrorGetLoader;
}
std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode =
app_loader->LoadKernelSystemMode();
if (system_mode.second != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to determine system mode (Error %i)!",
static_cast<int>(system_mode.second));
NGLOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
static_cast<int>(system_mode.second));
switch (system_mode.second) {
case Loader::ResultStatus::ErrorEncrypted:
@@ -106,15 +106,15 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
ResultStatus init_result{Init(emu_window, system_mode.first.get())};
if (init_result != ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error %i)!",
static_cast<int>(init_result));
NGLOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
System::Shutdown();
return init_result;
}
const Loader::ResultStatus load_result{app_loader->Load(current_process)};
if (Loader::ResultStatus::Success != load_result) {
LOG_CRITICAL(Core, "Failed to load ROM (Error %i)!", static_cast<int>(load_result));
NGLOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
System::Shutdown();
switch (load_result) {
@@ -151,7 +151,7 @@ void System::Reschedule() {
}
System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
LOG_DEBUG(HW_Memory, "initialized OK");
NGLOG_DEBUG(HW_Memory, "initialized OK");
CoreTiming::Init();
@@ -162,7 +162,7 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
cpu_core = std::make_shared<ARM_Dynarmic>();
#else
cpu_core = std::make_shared<ARM_Unicorn>();
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
NGLOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif
} else {
cpu_core = std::make_shared<ARM_Unicorn>();
@@ -184,7 +184,7 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
return ResultStatus::ErrorVideoCore;
}
LOG_DEBUG(Core, "Initialized OK");
NGLOG_DEBUG(Core, "Initialized OK");
// Reset counters and set time origin to current frame
GetAndResetPerfStats();
@@ -218,7 +218,7 @@ void System::Shutdown() {
app_loader.reset();
LOG_DEBUG(Core, "Shutdown OK");
NGLOG_DEBUG(Core, "Shutdown OK");
}
Service::SM::ServiceManager& System::ServiceManager() {

View File

@@ -6,6 +6,7 @@
#include <algorithm>
#include <cinttypes>
#include <limits>
#include <mutex>
#include <string>
#include <tuple>
@@ -57,7 +58,8 @@ static u64 event_fifo_id;
// to the event_queue by the emu thread
static Common::MPSCQueue<Event, false> ts_queue;
static constexpr int MAX_SLICE_LENGTH = 20000;
constexpr int MAX_SLICE_LENGTH = 20000;
constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE;
static s64 idled_cycles;
@@ -70,11 +72,59 @@ static EventType* ev_lost = nullptr;
static void EmptyTimedCallback(u64 userdata, s64 cyclesLate) {}
s64 usToCycles(s64 us) {
if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) {
NGLOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (us > MAX_VALUE_TO_MULTIPLY) {
NGLOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * (us / 1000000);
}
return (BASE_CLOCK_RATE * us) / 1000000;
}
s64 usToCycles(u64 us) {
if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) {
NGLOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (us > MAX_VALUE_TO_MULTIPLY) {
NGLOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * static_cast<s64>(us / 1000000);
}
return (BASE_CLOCK_RATE * static_cast<s64>(us)) / 1000000;
}
s64 nsToCycles(s64 ns) {
if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) {
NGLOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (ns > MAX_VALUE_TO_MULTIPLY) {
NGLOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * (ns / 1000000000);
}
return (BASE_CLOCK_RATE * ns) / 1000000000;
}
s64 nsToCycles(u64 ns) {
if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) {
NGLOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (ns > MAX_VALUE_TO_MULTIPLY) {
NGLOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * (static_cast<s64>(ns) / 1000000000);
}
return (BASE_CLOCK_RATE * static_cast<s64>(ns)) / 1000000000;
}
EventType* RegisterEvent(const std::string& name, TimedCallback callback) {
// check for existing type with same name.
// we want event type names to remain unique so that we can use them for serialization.
ASSERT_MSG(event_types.find(name) == event_types.end(),
"CoreTiming Event \"%s\" is already registered. Events should only be registered "
"CoreTiming Event \"{}\" is already registered. Events should only be registered "
"during Init to avoid breaking save states.",
name.c_str());

View File

@@ -18,15 +18,14 @@
*/
#include <functional>
#include <limits>
#include <string>
#include "common/common_types.h"
#include "common/logging/log.h"
namespace CoreTiming {
// The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz
// The exact value used is of course unverified.
constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch clock speed is 1020MHz un/docked
constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE;
inline s64 msToCycles(int ms) {
// since ms is int there is no way to overflow
@@ -49,29 +48,9 @@ inline s64 usToCycles(int us) {
return (BASE_CLOCK_RATE * static_cast<s64>(us) / 1000000);
}
inline s64 usToCycles(s64 us) {
if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) {
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (us > MAX_VALUE_TO_MULTIPLY) {
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * (us / 1000000);
}
return (BASE_CLOCK_RATE * us) / 1000000;
}
s64 usToCycles(s64 us);
inline s64 usToCycles(u64 us) {
if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) {
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (us > MAX_VALUE_TO_MULTIPLY) {
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * static_cast<s64>(us / 1000000);
}
return (BASE_CLOCK_RATE * static_cast<s64>(us)) / 1000000;
}
s64 usToCycles(u64 us);
inline s64 nsToCycles(float ns) {
return static_cast<s64>(BASE_CLOCK_RATE * (0.000000001f) * ns);
@@ -81,29 +60,9 @@ inline s64 nsToCycles(int ns) {
return BASE_CLOCK_RATE * static_cast<s64>(ns) / 1000000000;
}
inline s64 nsToCycles(s64 ns) {
if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) {
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (ns > MAX_VALUE_TO_MULTIPLY) {
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * (ns / 1000000000);
}
return (BASE_CLOCK_RATE * ns) / 1000000000;
}
s64 nsToCycles(s64 ns);
inline s64 nsToCycles(u64 ns) {
if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) {
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
return std::numeric_limits<s64>::max();
}
if (ns > MAX_VALUE_TO_MULTIPLY) {
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
return BASE_CLOCK_RATE * (static_cast<s64>(ns) / 1000000000);
}
return (BASE_CLOCK_RATE * static_cast<s64>(ns)) / 1000000000;
}
s64 nsToCycles(u64 ns);
inline u64 cyclesToNs(s64 cycles) {
return cycles * 1000000000 / BASE_CLOCK_RATE;
@@ -117,8 +76,6 @@ inline u64 cyclesToMs(s64 cycles) {
return cycles * 1000 / BASE_CLOCK_RATE;
}
namespace CoreTiming {
/**
* CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
* required to end slice -1 and start slice 0 before the first cycle of code is executed.

View File

@@ -77,11 +77,11 @@ u64 ProgramMetadata::GetFilesystemPermissions() const {
void ProgramMetadata::Print() const {
NGLOG_DEBUG(Service_FS, "Magic: {:.4}", npdm_header.magic.data());
NGLOG_DEBUG(Service_FS, "Main thread priority: {:#04X}", npdm_header.main_thread_priority);
NGLOG_DEBUG(Service_FS, "Main thread priority: 0x{:02X}", npdm_header.main_thread_priority);
NGLOG_DEBUG(Service_FS, "Main thread core: {}", npdm_header.main_thread_cpu);
NGLOG_DEBUG(Service_FS, "Main thread stack size: {:#X} bytes", npdm_header.main_stack_size);
NGLOG_DEBUG(Service_FS, "Main thread stack size: 0x{:X} bytes", npdm_header.main_stack_size);
NGLOG_DEBUG(Service_FS, "Process category: {}", npdm_header.process_category);
NGLOG_DEBUG(Service_FS, "Flags: {:02X}", npdm_header.flags);
NGLOG_DEBUG(Service_FS, "Flags: 0x{:02X}", npdm_header.flags);
NGLOG_DEBUG(Service_FS, " > 64-bit instructions: {}",
npdm_header.has_64_bit_instructions ? "YES" : "NO");
@@ -99,15 +99,15 @@ void ProgramMetadata::Print() const {
// Begin ACID printing (potential perms, signed)
NGLOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data());
NGLOG_DEBUG(Service_FS, "Flags: {:02X}", acid_header.flags);
NGLOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags);
NGLOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO");
NGLOG_DEBUG(Service_FS, "Title ID Min: {:016X}", acid_header.title_id_min);
NGLOG_DEBUG(Service_FS, "Title ID Max: {:016X}", acid_header.title_id_max);
NGLOG_DEBUG(Service_FS, "Filesystem Access: {:016X}\n", acid_file_access.permissions);
NGLOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min);
NGLOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max);
NGLOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions);
// Begin ACI0 printing (actual perms, unsigned)
NGLOG_DEBUG(Service_FS, "Magic: {:.4}", aci_header.magic.data());
NGLOG_DEBUG(Service_FS, "Title ID: {:016X}", aci_header.title_id);
NGLOG_DEBUG(Service_FS, "Filesystem Access: {:016X}\n", aci_file_access.permissions);
NGLOG_DEBUG(Service_FS, "Title ID: 0x{:016X}", aci_header.title_id);
NGLOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", aci_file_access.permissions);
}
} // namespace FileSys

View File

@@ -59,7 +59,7 @@ template <typename InputDeviceType>
void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) {
auto pair = std::make_pair(name, std::move(factory));
if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) {
LOG_ERROR(Input, "Factory %s already registered", name.c_str());
NGLOG_ERROR(Input, "Factory '{}' already registered", name);
}
}
@@ -71,7 +71,7 @@ void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDevic
template <typename InputDeviceType>
void UnregisterFactory(const std::string& name) {
if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) {
LOG_ERROR(Input, "Factory %s not registered", name.c_str());
NGLOG_ERROR(Input, "Factory '{}' not registered", name);
}
}
@@ -88,7 +88,7 @@ std::unique_ptr<InputDeviceType> CreateDevice(const std::string& params) {
const auto pair = factory_list.find(engine);
if (pair == factory_list.end()) {
if (engine != "null") {
LOG_ERROR(Input, "Unknown engine name: %s", engine.c_str());
NGLOG_ERROR(Input, "Unknown engine name: {}", engine);
}
return std::make_unique<InputDeviceType>();
}

View File

@@ -6,7 +6,6 @@
#include <algorithm>
#include <atomic>
#include <cinttypes>
#include <climits>
#include <csignal>
#include <cstdarg>
@@ -180,7 +179,7 @@ static u8 HexCharToValue(u8 hex) {
return hex - 'A' + 0xA;
}
LOG_ERROR(Debug_GDBStub, "Invalid nibble: %c (%02x)\n", hex, hex);
NGLOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex);
return 0;
}
@@ -320,7 +319,7 @@ static u8 ReadByte() {
u8 c;
size_t received_size = recv(gdbserver_socket, reinterpret_cast<char*>(&c), 1, MSG_WAITALL);
if (received_size != 1) {
LOG_ERROR(Debug_GDBStub, "recv failed : %ld", received_size);
NGLOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size);
Shutdown();
}
@@ -361,9 +360,8 @@ static void RemoveBreakpoint(BreakpointType type, PAddr addr) {
auto bp = p.find(static_cast<u64>(addr));
if (bp != p.end()) {
LOG_DEBUG(Debug_GDBStub,
"gdb: removed a breakpoint: %016" PRIx64 " bytes at %016" PRIx64 " of type %d\n",
bp->second.len, bp->second.addr, static_cast<int>(type));
NGLOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}",
bp->second.len, bp->second.addr, static_cast<int>(type));
p.erase(static_cast<u64>(addr));
}
}
@@ -408,10 +406,10 @@ bool CheckBreakpoint(PAddr addr, BreakpointType type) {
}
if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) {
LOG_DEBUG(Debug_GDBStub,
"Found breakpoint type %d @ %016" PRIx64 ", range: %016" PRIx64
" - %016" PRIx64 " (%" PRIx64 " bytes)\n",
static_cast<int>(type), addr, bp->second.addr, bp->second.addr + len, len);
NGLOG_DEBUG(Debug_GDBStub,
"Found breakpoint type {} @ {:016X}, range: {:016X}"
" - {:016X} ({:X} bytes)",
static_cast<int>(type), addr, bp->second.addr, bp->second.addr + len, len);
return true;
}
}
@@ -427,7 +425,7 @@ bool CheckBreakpoint(PAddr addr, BreakpointType type) {
static void SendPacket(const char packet) {
size_t sent_size = send(gdbserver_socket, &packet, 1, 0);
if (sent_size != 1) {
LOG_ERROR(Debug_GDBStub, "send failed");
NGLOG_ERROR(Debug_GDBStub, "send failed");
}
}
@@ -445,7 +443,7 @@ static void SendReply(const char* reply) {
command_length = static_cast<u32>(strlen(reply));
if (command_length + 4 > sizeof(command_buffer)) {
LOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply");
NGLOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply");
return;
}
@@ -462,7 +460,7 @@ static void SendReply(const char* reply) {
while (left > 0) {
int sent_size = send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0);
if (sent_size < 0) {
LOG_ERROR(Debug_GDBStub, "gdb: send failed");
NGLOG_ERROR(Debug_GDBStub, "gdb: send failed");
return Shutdown();
}
@@ -473,7 +471,7 @@ static void SendReply(const char* reply) {
/// Handle query command from gdb client.
static void HandleQuery() {
LOG_DEBUG(Debug_GDBStub, "gdb: query '%s'\n", command_buffer + 1);
NGLOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1);
const char* query = reinterpret_cast<const char*>(command_buffer + 1);
@@ -512,8 +510,8 @@ static void SendSignal(u32 signal) {
latest_signal = signal;
std::string buffer = Common::StringFromFormat("T%02x", latest_signal);
LOG_DEBUG(Debug_GDBStub, "Response: %s", buffer.c_str());
std::string buffer = fmt::format("T{:02x}", latest_signal);
NGLOG_DEBUG(Debug_GDBStub, "Response: {}", buffer);
SendReply(buffer.c_str());
}
@@ -527,18 +525,18 @@ static void ReadCommand() {
// ignore ack
return;
} else if (c == 0x03) {
LOG_INFO(Debug_GDBStub, "gdb: found break command\n");
NGLOG_INFO(Debug_GDBStub, "gdb: found break command");
halt_loop = true;
SendSignal(SIGTRAP);
return;
} else if (c != GDB_STUB_START) {
LOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte %02x\n", c);
NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c);
return;
}
while ((c = ReadByte()) != GDB_STUB_END) {
if (command_length >= sizeof(command_buffer)) {
LOG_ERROR(Debug_GDBStub, "gdb: command_buffer overflow\n");
NGLOG_ERROR(Debug_GDBStub, "gdb: command_buffer overflow");
SendPacket(GDB_STUB_NACK);
return;
}
@@ -551,9 +549,10 @@ static void ReadCommand() {
u8 checksum_calculated = CalculateChecksum(command_buffer, command_length);
if (checksum_received != checksum_calculated) {
LOG_ERROR(Debug_GDBStub,
"gdb: invalid checksum: calculated %02x and read %02x for $%s# (length: %d)\n",
checksum_calculated, checksum_received, command_buffer, command_length);
NGLOG_ERROR(
Debug_GDBStub,
"gdb: invalid checksum: calculated {:02X} and read {:02X} for ${}# (length: {})",
checksum_calculated, checksum_received, command_buffer, command_length);
command_length = 0;
@@ -580,7 +579,7 @@ static bool IsDataAvailable() {
t.tv_usec = 0;
if (select(gdbserver_socket + 1, &fd_socket, nullptr, nullptr, &t) < 0) {
LOG_ERROR(Debug_GDBStub, "select failed");
NGLOG_ERROR(Debug_GDBStub, "select failed");
return false;
}
@@ -693,7 +692,7 @@ static void ReadMemory() {
u64 len =
HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset));
LOG_DEBUG(Debug_GDBStub, "gdb: addr: %016lx len: %016lx\n", addr, len);
NGLOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len);
if (len * 2 > sizeof(reply)) {
SendReply("E01");
@@ -781,8 +780,8 @@ static bool CommitBreakpoint(BreakpointType type, PAddr addr, u64 len) {
breakpoint.len = len;
p.insert({addr, breakpoint});
LOG_DEBUG(Debug_GDBStub, "gdb: added %d breakpoint: %016" PRIx64 " bytes at %016" PRIx64 "\n",
static_cast<int>(type), breakpoint.len, breakpoint.addr);
NGLOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}",
static_cast<int>(type), breakpoint.len, breakpoint.addr);
return true;
}
@@ -889,7 +888,7 @@ void HandlePacket() {
return;
}
LOG_DEBUG(Debug_GDBStub, "Packet: %s", command_buffer);
NGLOG_DEBUG(Debug_GDBStub, "Packet: {}", command_buffer);
switch (command_buffer[0]) {
case 'q':
@@ -903,7 +902,7 @@ void HandlePacket() {
break;
case 'k':
Shutdown();
LOG_INFO(Debug_GDBStub, "killed by gdb");
NGLOG_INFO(Debug_GDBStub, "killed by gdb");
return;
case 'g':
ReadRegisters();
@@ -982,7 +981,7 @@ static void Init(u16 port) {
breakpoints_write.clear();
// Start gdb server
LOG_INFO(Debug_GDBStub, "Starting GDB server on port %d...", port);
NGLOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port);
sockaddr_in saddr_server = {};
saddr_server.sin_family = AF_INET;
@@ -995,28 +994,28 @@ static void Init(u16 port) {
int tmpsock = static_cast<int>(socket(PF_INET, SOCK_STREAM, 0));
if (tmpsock == -1) {
LOG_ERROR(Debug_GDBStub, "Failed to create gdb socket");
NGLOG_ERROR(Debug_GDBStub, "Failed to create gdb socket");
}
// Set socket to SO_REUSEADDR so it can always bind on the same port
int reuse_enabled = 1;
if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_enabled,
sizeof(reuse_enabled)) < 0) {
LOG_ERROR(Debug_GDBStub, "Failed to set gdb socket option");
NGLOG_ERROR(Debug_GDBStub, "Failed to set gdb socket option");
}
const sockaddr* server_addr = reinterpret_cast<const sockaddr*>(&saddr_server);
socklen_t server_addrlen = sizeof(saddr_server);
if (bind(tmpsock, server_addr, server_addrlen) < 0) {
LOG_ERROR(Debug_GDBStub, "Failed to bind gdb socket");
NGLOG_ERROR(Debug_GDBStub, "Failed to bind gdb socket");
}
if (listen(tmpsock, 1) < 0) {
LOG_ERROR(Debug_GDBStub, "Failed to listen to gdb socket");
NGLOG_ERROR(Debug_GDBStub, "Failed to listen to gdb socket");
}
// Wait for gdb to connect
LOG_INFO(Debug_GDBStub, "Waiting for gdb to connect...\n");
NGLOG_INFO(Debug_GDBStub, "Waiting for gdb to connect...");
sockaddr_in saddr_client;
sockaddr* client_addr = reinterpret_cast<sockaddr*>(&saddr_client);
socklen_t client_addrlen = sizeof(saddr_client);
@@ -1027,9 +1026,9 @@ static void Init(u16 port) {
halt_loop = false;
step_loop = false;
LOG_ERROR(Debug_GDBStub, "Failed to accept gdb client");
NGLOG_ERROR(Debug_GDBStub, "Failed to accept gdb client");
} else {
LOG_INFO(Debug_GDBStub, "Client connected.\n");
NGLOG_INFO(Debug_GDBStub, "Client connected.");
saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr);
}
@@ -1048,7 +1047,7 @@ void Shutdown() {
return;
}
LOG_INFO(Debug_GDBStub, "Stopping GDB ...");
NGLOG_INFO(Debug_GDBStub, "Stopping GDB ...");
if (gdbserver_socket != -1) {
shutdown(gdbserver_socket, SHUT_RDWR);
gdbserver_socket = -1;
@@ -1058,7 +1057,7 @@ void Shutdown() {
WSACleanup();
#endif
LOG_INFO(Debug_GDBStub, "GDB stopped.");
NGLOG_INFO(Debug_GDBStub, "GDB stopped.");
}
bool IsServerEnabled() {

View File

@@ -167,6 +167,7 @@ struct DomainMessageHeader {
struct {
union {
BitField<0, 8, CommandType> command;
BitField<8, 8, u32_le> input_object_count;
BitField<16, 16, u32_le> size;
};
u32_le object_id;

View File

@@ -298,6 +298,13 @@ public:
template <typename T>
Kernel::SharedPtr<T> GetCopyObject(size_t index);
template <class T>
std::shared_ptr<T> PopIpcInterface() {
ASSERT(context->Session()->IsDomain());
ASSERT(context->GetDomainMessageHeader()->input_object_count > 0);
return context->GetDomainRequestHandler<T>(Pop<u32>() - 1);
}
};
/// Pop ///

View File

@@ -251,24 +251,26 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
return RESULT_SUCCESS;
}
std::vector<u8> HLERequestContext::ReadBuffer() const {
std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const {
std::vector<u8> buffer;
const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[0].Size()};
const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()};
if (is_buffer_a) {
buffer.resize(BufferDescriptorA()[0].Size());
Memory::ReadBlock(BufferDescriptorA()[0].Address(), buffer.data(), buffer.size());
buffer.resize(BufferDescriptorA()[buffer_index].Size());
Memory::ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(),
buffer.size());
} else {
buffer.resize(BufferDescriptorX()[0].Size());
Memory::ReadBlock(BufferDescriptorX()[0].Address(), buffer.data(), buffer.size());
buffer.resize(BufferDescriptorX()[buffer_index].Size());
Memory::ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(),
buffer.size());
}
return buffer;
}
size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size) const {
const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[0].Size()};
const size_t buffer_size{GetWriteBufferSize()};
size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size, int buffer_index) const {
const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()};
const size_t buffer_size{GetWriteBufferSize(buffer_index)};
if (size > buffer_size) {
NGLOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size,
buffer_size);
@@ -276,26 +278,28 @@ size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size) const {
}
if (is_buffer_b) {
Memory::WriteBlock(BufferDescriptorB()[0].Address(), buffer, size);
Memory::WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
} else {
Memory::WriteBlock(BufferDescriptorC()[0].Address(), buffer, size);
Memory::WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
}
return size;
}
size_t HLERequestContext::WriteBuffer(const std::vector<u8>& buffer) const {
size_t HLERequestContext::WriteBuffer(const std::vector<u8>& buffer, int buffer_index) const {
return WriteBuffer(buffer.data(), buffer.size());
}
size_t HLERequestContext::GetReadBufferSize() const {
const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[0].Size()};
return is_buffer_a ? BufferDescriptorA()[0].Size() : BufferDescriptorX()[0].Size();
size_t HLERequestContext::GetReadBufferSize(int buffer_index) const {
const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()};
return is_buffer_a ? BufferDescriptorA()[buffer_index].Size()
: BufferDescriptorX()[buffer_index].Size();
}
size_t HLERequestContext::GetWriteBufferSize() const {
const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[0].Size()};
return is_buffer_b ? BufferDescriptorB()[0].Size() : BufferDescriptorC()[0].Size();
size_t HLERequestContext::GetWriteBufferSize(int buffer_index) const {
const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()};
return is_buffer_b ? BufferDescriptorB()[buffer_index].Size()
: BufferDescriptorC()[buffer_index].Size();
}
std::string HLERequestContext::Description() const {

View File

@@ -164,19 +164,19 @@ public:
}
/// Helper function to read a buffer using the appropriate buffer descriptor
std::vector<u8> ReadBuffer() const;
std::vector<u8> ReadBuffer(int buffer_index = 0) const;
/// Helper function to write a buffer using the appropriate buffer descriptor
size_t WriteBuffer(const void* buffer, size_t size) const;
size_t WriteBuffer(const void* buffer, size_t size, int buffer_index = 0) const;
/// Helper function to write a buffer using the appropriate buffer descriptor
size_t WriteBuffer(const std::vector<u8>& buffer) const;
size_t WriteBuffer(const std::vector<u8>& buffer, int buffer_index = 0) const;
/// Helper function to get the size of the input buffer
size_t GetReadBufferSize() const;
size_t GetReadBufferSize(int buffer_index = 0) const;
/// Helper function to get the size of the output buffer
size_t GetWriteBufferSize() const;
size_t GetWriteBufferSize(int buffer_index = 0) const;
template <typename T>
SharedPtr<T> GetCopyObject(size_t index) {
@@ -202,6 +202,16 @@ public:
domain_objects.emplace_back(std::move(object));
}
template <typename T>
std::shared_ptr<T> GetDomainRequestHandler(size_t index) const {
return std::static_pointer_cast<T>(domain_request_handlers[index]);
}
void SetDomainRequestHandlers(
const std::vector<std::shared_ptr<SessionRequestHandler>>& handlers) {
domain_request_handlers = handlers;
}
/// Clears the list of objects so that no lingering objects are written accidentally to the
/// response buffer.
void ClearIncomingObjects() {
@@ -245,6 +255,8 @@ private:
unsigned data_payload_offset{};
unsigned buffer_c_offset{};
u32_le command{};
std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
};
} // namespace Kernel

View File

@@ -10,12 +10,12 @@ namespace Kernel {
ObjectAddressTable g_object_address_table;
void ObjectAddressTable::Insert(VAddr addr, SharedPtr<Object> obj) {
ASSERT_MSG(objects.find(addr) == objects.end(), "Object already exists with addr=0x%lx", addr);
ASSERT_MSG(objects.find(addr) == objects.end(), "Object already exists with addr=0x{:X}", addr);
objects[addr] = obj;
}
void ObjectAddressTable::Close(VAddr addr) {
ASSERT_MSG(objects.find(addr) != objects.end(), "Object does not exist with addr=0x%lx", addr);
ASSERT_MSG(objects.find(addr) != objects.end(), "Object does not exist with addr=0x{:X}", addr);
objects.erase(addr);
}

View File

@@ -111,7 +111,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
int major = (kernel_version >> 8) & 0xFF;
NGLOG_INFO(Loader, "ExHeader kernel version: {}.{}", major, minor);
} else {
NGLOG_ERROR(Loader, "Unhandled kernel caps descriptor: {:#010X}", descriptor);
NGLOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x{:08X}", descriptor);
}
}
}
@@ -134,7 +134,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
HandleSpecialMapping(vm_manager, mapping);
}
vm_manager.LogLayout(Log::Level::Debug);
vm_manager.LogLayout();
status = ProcessStatus::Running;
Kernel::SetupMainThread(entry_point, main_thread_priority, this);

View File

@@ -61,6 +61,9 @@ void ServerSession::Acquire(Thread* thread) {
ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
auto& domain_message_header = context.GetDomainMessageHeader();
if (domain_message_header) {
// Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs
context.SetDomainRequestHandlers(domain_request_handlers);
// If there is a DomainMessageHeader, then this is CommandType "Request"
const u32 object_id{context.GetDomainMessageHeader()->object_id};
switch (domain_message_header->command) {
@@ -68,7 +71,7 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
NGLOG_DEBUG(IPC, "CloseVirtualHandle, object_id={:#010X}", object_id);
NGLOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id);
domain_request_handlers[object_id - 1] = nullptr;

View File

@@ -107,7 +107,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
// Error out if the requested permissions don't match what the creator process allows.
if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) {
NGLOG_ERROR(Kernel, "cannot map id={}, address={:#X} name={}, permissions don't match",
NGLOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match",
GetObjectId(), address, name);
return ERR_INVALID_COMBINATION;
}
@@ -115,7 +115,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
// Error out if the provided permissions are not compatible with what the creator process needs.
if (other_permissions != MemoryPermission::DontCare &&
static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) {
NGLOG_ERROR(Kernel, "cannot map id={}, address={:#X} name={}, permissions don't match",
NGLOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match",
GetObjectId(), address, name);
return ERR_WRONG_PERMISSION;
}
@@ -133,7 +133,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
if (result.Failed()) {
NGLOG_ERROR(
Kernel,
"cannot map id={}, target_address={:#X} name={}, error mapping to virtual memory",
"cannot map id={}, target_address=0x{:X} name={}, error mapping to virtual memory",
GetObjectId(), target_address, name);
return result.Code();
}

View File

@@ -31,7 +31,7 @@ namespace Kernel {
/// Set the process heap to a given Size. It can both extend and shrink the heap.
static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
NGLOG_TRACE(Kernel_SVC, "called, heap_size={:#X}", heap_size);
NGLOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size);
auto& process = *Core::CurrentProcess();
CASCADE_RESULT(*heap_addr,
process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite));
@@ -39,20 +39,20 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
}
static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) {
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, addr={:#X}", addr);
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, addr=0x{:X}", addr);
return RESULT_SUCCESS;
}
/// Maps a memory range into a different range.
static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
NGLOG_TRACE(Kernel_SVC, "called, dst_addr={:#X}, src_addr={:#X}, size={:#X}", dst_addr,
NGLOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
src_addr, size);
return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size);
}
/// Unmaps a region that was previously mapped with svcMapMemory
static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
NGLOG_TRACE(Kernel_SVC, "called, dst_addr={:#X}, src_addr={:#X}, size={:#X}", dst_addr,
NGLOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
src_addr, size);
return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size);
}
@@ -90,11 +90,11 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
static ResultCode SendSyncRequest(Handle handle) {
SharedPtr<ClientSession> session = g_handle_table.Get<ClientSession>(handle);
if (!session) {
NGLOG_ERROR(Kernel_SVC, "called with invalid handle={:#010X}", handle);
NGLOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
return ERR_INVALID_HANDLE;
}
NGLOG_TRACE(Kernel_SVC, "called handle={:#010X}({})", handle, session->GetName());
NGLOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
Core::System::GetInstance().PrepareReschedule();
@@ -105,7 +105,7 @@ static ResultCode SendSyncRequest(Handle handle) {
/// Get the ID for the specified thread.
static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
NGLOG_TRACE(Kernel_SVC, "called thread={:#010X}", thread_handle);
NGLOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
if (!thread) {
@@ -118,7 +118,7 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
/// Get the ID of the specified process
static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
NGLOG_TRACE(Kernel_SVC, "called process={:#010X}", process_handle);
NGLOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle);
const SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle);
if (!process) {
@@ -178,7 +178,7 @@ static ResultCode WaitSynchronization1(
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 handle_count,
s64 nano_seconds) {
NGLOG_TRACE(Kernel_SVC, "called handles_address={:#X}, handle_count={}, nano_seconds={}",
NGLOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
handles_address, handle_count, nano_seconds);
if (!Memory::IsValidVirtualAddress(handles_address))
@@ -239,7 +239,7 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
/// Resumes a thread waiting on WaitSynchronization
static ResultCode CancelSynchronization(Handle thread_handle) {
NGLOG_TRACE(Kernel_SVC, "called thread={:#X}", thread_handle);
NGLOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
if (!thread) {
@@ -257,8 +257,8 @@ static ResultCode CancelSynchronization(Handle thread_handle) {
static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
Handle requesting_thread_handle) {
NGLOG_TRACE(Kernel_SVC,
"called holding_thread_handle={:#010X}, mutex_addr={:#X}, "
"requesting_current_thread_handle={:#010X}",
"called holding_thread_handle=0x{:08X}, mutex_addr=0x{:X}, "
"requesting_current_thread_handle=0x{:08X}",
holding_thread_handle, mutex_addr, requesting_thread_handle);
return Mutex::TryAcquire(mutex_addr, holding_thread_handle, requesting_thread_handle);
@@ -266,7 +266,7 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
/// Unlock a mutex
static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
NGLOG_TRACE(Kernel_SVC, "called mutex_addr={:#X}", mutex_addr);
NGLOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr);
return Mutex::Release(mutex_addr);
}
@@ -286,7 +286,7 @@ static void OutputDebugString(VAddr address, s32 len) {
/// Gets system/memory information for the current process
static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) {
NGLOG_TRACE(Kernel_SVC, "called info_id={:#X}, info_sub_id={:#X}, handle={:#010X}", info_id,
NGLOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
info_sub_id, handle);
auto& vm_manager = Core::CurrentProcess()->vm_manager;
@@ -355,14 +355,14 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
/// Sets the thread activity
static ResultCode SetThreadActivity(Handle handle, u32 unknown) {
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle={:#010X}, unknown={:#010X}", handle,
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, unknown=0x{:08X}", handle,
unknown);
return RESULT_SUCCESS;
}
/// Gets the thread context
static ResultCode GetThreadContext(Handle handle, VAddr addr) {
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle={:#010X}, addr={:#X}", handle, addr);
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, addr=0x{:X}", handle, addr);
return RESULT_SUCCESS;
}
@@ -407,9 +407,10 @@ static u32 GetCurrentProcessorNumber() {
static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size,
u32 permissions) {
NGLOG_TRACE(Kernel_SVC,
"called, shared_memory_handle={:#X}, addr={:#X}, size={:#X}, permissions={:#010X}",
shared_memory_handle, addr, size, permissions);
NGLOG_TRACE(
Kernel_SVC,
"called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
shared_memory_handle, addr, size, permissions);
SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle);
if (!shared_memory) {
@@ -429,14 +430,14 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type,
MemoryPermission::DontCare);
default:
NGLOG_ERROR(Kernel_SVC, "unknown permissions={:#010X}", permissions);
NGLOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions);
}
return RESULT_SUCCESS;
}
static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) {
NGLOG_WARNING(Kernel_SVC, "called, shared_memory_handle={:#010X}, addr={:#X}, size={:#X}",
NGLOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}",
shared_memory_handle, addr, size);
SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle);
@@ -465,7 +466,7 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i
memory_info->type = static_cast<u32>(vma->second.meminfo_state);
}
NGLOG_TRACE(Kernel_SVC, "called process={:#010X} addr={:X}", process_handle, addr);
NGLOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr);
return RESULT_SUCCESS;
}
@@ -510,7 +511,7 @@ static void ExitProcess() {
/// Creates a new thread
static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top,
u32 priority, s32 processor_id) {
std::string name = Common::StringFromFormat("unknown-%llx", entry_point);
std::string name = fmt::format("unknown-{:X}", entry_point);
if (priority > THREADPRIO_LOWEST) {
return ERR_OUT_OF_RANGE;
@@ -539,7 +540,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
processor_id);
break;
default:
ASSERT_MSG(false, "Unsupported thread processor ID: %d", processor_id);
ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id);
break;
}
@@ -552,8 +553,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
Core::System::GetInstance().PrepareReschedule();
NGLOG_TRACE(Kernel_SVC,
"called entrypoint={:#010X} ({}), arg={:#010X}, stacktop={:#010X}, "
"threadpriority={:#010X}, processorid={:#010X} : created handle={:#010X}",
"called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, "
"threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
entry_point, name, arg, stack_top, priority, processor_id, *out_handle);
return RESULT_SUCCESS;
@@ -561,7 +562,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
/// Starts the thread for the provided handle
static ResultCode StartThread(Handle thread_handle) {
NGLOG_TRACE(Kernel_SVC, "called thread={:#010X}", thread_handle);
NGLOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
if (!thread) {
@@ -575,7 +576,7 @@ static ResultCode StartThread(Handle thread_handle) {
/// Called when a thread exits
static void ExitThread() {
NGLOG_TRACE(Kernel_SVC, "called, pc={:#010X}", Core::CPU().GetPC());
NGLOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CPU().GetPC());
ExitCurrentThread();
Core::System::GetInstance().PrepareReschedule();
@@ -604,7 +605,7 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
Handle thread_handle, s64 nano_seconds) {
NGLOG_TRACE(
Kernel_SVC,
"called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle={:#010X}, timeout={}",
"called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}",
mutex_addr, condition_variable_addr, thread_handle, nano_seconds);
SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
@@ -629,7 +630,7 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
/// Signal process wide key
static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target) {
NGLOG_TRACE(Kernel_SVC, "called, condition_variable_addr={:#X}, target={:#010X}",
NGLOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}",
condition_variable_addr, target);
u32 processed = 0;
@@ -696,13 +697,13 @@ static u64 GetSystemTick() {
/// Close a handle
static ResultCode CloseHandle(Handle handle) {
NGLOG_TRACE(Kernel_SVC, "Closing handle {:#010X}", handle);
NGLOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
return g_handle_table.Close(handle);
}
/// Reset an event
static ResultCode ResetSignal(Handle handle) {
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called handle {:#010X}", handle);
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle);
auto event = g_handle_table.Get<Event>(handle);
ASSERT(event != nullptr);
event->Clear();
@@ -711,28 +712,28 @@ static ResultCode ResetSignal(Handle handle) {
/// Creates a TransferMemory object
static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) {
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called addr={:#X}, size={:#X}, perms={:010X}", addr, size,
permissions);
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr,
size, permissions);
*handle = 0;
return RESULT_SUCCESS;
}
static ResultCode GetThreadCoreMask(Handle handle, u32* mask, u64* unknown) {
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle={:010X}", handle);
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}", handle);
*mask = 0x0;
*unknown = 0xf;
return RESULT_SUCCESS;
}
static ResultCode SetThreadCoreMask(Handle handle, u32 mask, u64 unknown) {
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle={:#010X}, mask={:#010X}, unknown={:#X}",
NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, mask=0x{:08X}, unknown=0x{:X}",
handle, mask, unknown);
return RESULT_SUCCESS;
}
static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permissions,
u32 remote_permissions) {
NGLOG_TRACE(Kernel_SVC, "called, size={:#X}, localPerms={:#010X}, remotePerms={:#010X}", size,
NGLOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size,
local_permissions, remote_permissions);
auto sharedMemHandle =
SharedMemory::Create(g_handle_table.Get<Process>(KernelHandle::CurrentProcess), size,
@@ -744,7 +745,7 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
}
static ResultCode ClearEvent(Handle handle) {
NGLOG_TRACE(Kernel_SVC, "called, event={:010X}", handle);
NGLOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
SharedPtr<Event> evt = g_handle_table.Get<Event>(handle);
if (evt == nullptr)
@@ -896,7 +897,7 @@ static const FunctionDef SVC_Table[] = {
static const FunctionDef* GetSVCInfo(u32 func_num) {
if (func_num >= std::size(SVC_Table)) {
NGLOG_ERROR(Kernel_SVC, "Unknown svc={:#04X}", func_num);
NGLOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num);
return nullptr;
}
return &SVC_Table[func_num];
@@ -918,7 +919,7 @@ void CallSVC(u32 immediate) {
NGLOG_CRITICAL(Kernel_SVC, "Unimplemented SVC function {}(..)", info->name);
}
} else {
NGLOG_CRITICAL(Kernel_SVC, "Unknown SVC function {:#X}", immediate);
NGLOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate);
}
}

View File

@@ -146,7 +146,8 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
if (nanoseconds == -1)
return;
CoreTiming::ScheduleEvent(nsToCycles(nanoseconds), ThreadWakeupEventType, callback_handle);
CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(nanoseconds), ThreadWakeupEventType,
callback_handle);
}
void Thread::CancelWakeupTimer() {
@@ -175,11 +176,11 @@ void Thread::ResumeFromWait() {
return;
case THREADSTATUS_RUNNING:
DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId());
DEBUG_ASSERT_MSG(false, "Thread with object id {} has already resumed.", GetObjectId());
return;
case THREADSTATUS_DEAD:
// This should never happen, as threads must complete before being stopped.
DEBUG_ASSERT_MSG(false, "Thread with object id %u cannot be resumed because it's DEAD.",
DEBUG_ASSERT_MSG(false, "Thread with object id {} cannot be resumed because it's DEAD.",
GetObjectId());
return;
}

View File

@@ -57,7 +57,8 @@ void Timer::Set(s64 initial, s64 interval) {
// Immediately invoke the callback
Signal(0);
} else {
CoreTiming::ScheduleEvent(nsToCycles(initial), timer_callback_event_type, callback_handle);
CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(initial), timer_callback_event_type,
callback_handle);
}
}
@@ -86,7 +87,7 @@ void Timer::Signal(int cycles_late) {
if (interval_delay != 0) {
// Reschedule the timer with the interval delay
CoreTiming::ScheduleEvent(nsToCycles(interval_delay) - cycles_late,
CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(interval_delay) - cycles_late,
timer_callback_event_type, callback_handle);
}
}

View File

@@ -2,7 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cinttypes>
#include <iterator>
#include "common/assert.h"
#include "common/logging/log.h"
@@ -225,11 +224,10 @@ void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) {
}
}
void VMManager::LogLayout(Log::Level log_level) const {
void VMManager::LogLayout() const {
for (const auto& p : vma_map) {
const VirtualMemoryArea& vma = p.second;
LOG_GENERIC(Log::Class::Kernel, log_level,
"%016" PRIx64 " - %016" PRIx64 " size: %16" PRIx64 " %c%c%c %s", vma.base,
NGLOG_DEBUG(Kernel, "{:016X} - {:016X} size: {:016X} {}{}{} {}", vma.base,
vma.base + vma.size, vma.size,
(u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-',
(u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-',
@@ -245,8 +243,8 @@ VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle& iter) {
}
ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u64 size) {
ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x%16" PRIx64, size);
ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x%016" PRIx64, base);
ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x{:016X}", size);
ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x{:016X}", base);
VMAIter vma_handle = StripIterConstness(FindVMA(base));
if (vma_handle == vma_map.end()) {
@@ -281,8 +279,8 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u64 size) {
}
ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u64 size) {
ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x%16" PRIx64, size);
ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x%016" PRIx64, target);
ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x{:016X}", size);
ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x{:016X}", target);
VAddr target_end = target + size;
ASSERT(target_end >= target);

View File

@@ -187,7 +187,7 @@ public:
void RefreshMemoryBlockMappings(const std::vector<u8>* block);
/// Dumps the address space layout to the log, for debugging
void LogLayout(Log::Level log_level) const;
void LogLayout() const;
/// Gets the total memory usage, used by svcGetInfo
u64 GetTotalMemoryUsage();

View File

@@ -12,6 +12,7 @@
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/nvflinger/nvflinger.h"
#include "core/hle/service/set/set.h"
#include "core/settings.h"
namespace Service::AM {
@@ -102,7 +103,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
{40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
{41, nullptr, "IsSystemBufferSharingEnabled"},
{42, nullptr, "GetSystemSharedLayerHandle"},
{50, nullptr, "SetHandlesRequestToDisplay"},
{50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
{51, nullptr, "ApproveToDisplay"},
{60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
{61, nullptr, "SetMediaPlaybackState"},
@@ -228,6 +229,13 @@ void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx)
NGLOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
}
ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") {
static const FunctionInfo functions[] = {
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
@@ -444,7 +452,8 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
{10, nullptr, "CreateApplicationAndPushAndRequestToStart"},
{11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
{12, nullptr, "CreateApplicationAndRequestToStart"},
{13, nullptr, "CreateApplicationAndRequestToStartForQuest"},
{13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest,
"CreateApplicationAndRequestToStartForQuest"},
{20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"},
{21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"},
{22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
@@ -501,6 +510,13 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
NGLOG_DEBUG(Service_AM, "called");
}
void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(
Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u128 uid = rp.PopRaw<u128>();
@@ -533,14 +549,15 @@ void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called, result={:#010}", result);
NGLOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
}
void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
// TODO(bunnei): This should be configurable
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(SystemLanguage::English);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
rb.Push(static_cast<u64>(Service::Set::LanguageCode::EN_US));
NGLOG_DEBUG(Service_AM, "called");
}
void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) {
@@ -570,4 +587,64 @@ void InstallInterfaces(SM::ServiceManager& service_manager,
std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager);
}
IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions") {
static const FunctionInfo functions[] = {
{10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"},
{11, nullptr, "LockForeground"},
{12, nullptr, "UnlockForeground"},
{20, nullptr, "PopFromGeneralChannel"},
{21, nullptr, "GetPopFromGeneralChannelEvent"},
{30, nullptr, "GetHomeButtonWriterLockAccessor"},
{31, nullptr, "GetWriterLockAccessorEx"},
};
RegisterHandlers(functions);
}
void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_AM, "(STUBBED) called");
}
IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") {
static const FunctionInfo functions[] = {
{0, nullptr, "RequestToEnterSleep"},
{1, nullptr, "EnterSleep"},
{2, nullptr, "StartSleepSequence"},
{3, nullptr, "StartShutdownSequence"},
{4, nullptr, "StartRebootSequence"},
{10, nullptr, "LoadAndApplyIdlePolicySettings"},
{11, nullptr, "NotifyCecSettingsChanged"},
{12, nullptr, "SetDefaultHomeButtonLongPressTime"},
{13, nullptr, "UpdateDefaultDisplayResolution"},
{14, nullptr, "ShouldSleepOnBoot"},
{15, nullptr, "GetHdcpAuthenticationFailedEvent"},
};
RegisterHandlers(functions);
}
IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreator") {
static const FunctionInfo functions[] = {
{0, nullptr, "CreateApplication"},
{1, nullptr, "PopLaunchRequestedApplication"},
{10, nullptr, "CreateSystemApplication"},
{100, nullptr, "PopFloatingApplicationForDevelopment"},
};
RegisterHandlers(functions);
}
IProcessWindingController::IProcessWindingController()
: ServiceFramework("IProcessWindingController") {
static const FunctionInfo functions[] = {
{0, nullptr, "GetLaunchReason"},
{11, nullptr, "OpenCallingLibraryApplet"},
{21, nullptr, "PushContext"},
{22, nullptr, "PopContext"},
{23, nullptr, "CancelWindingReservation"},
{30, nullptr, "WindAndDoReserved"},
{40, nullptr, "ReserveToStartAndWaitAndUnwindThis"},
{41, nullptr, "ReserveToStartAndWait"},
};
RegisterHandlers(functions);
}
} // namespace Service::AM

View File

@@ -70,6 +70,7 @@ private:
void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx);
void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx);
void SetScreenShotPermission(Kernel::HLERequestContext& ctx);
void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx);
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
Kernel::SharedPtr<Kernel::Event> launchable_event;
@@ -113,6 +114,7 @@ public:
private:
void PopLaunchParameter(Kernel::HLERequestContext& ctx);
void CreateApplicationAndRequestToStartForQuest(Kernel::HLERequestContext& ctx);
void EnsureSaveData(Kernel::HLERequestContext& ctx);
void SetTerminateResult(Kernel::HLERequestContext& ctx);
void GetDesiredLanguage(Kernel::HLERequestContext& ctx);
@@ -121,6 +123,29 @@ private:
void NotifyRunning(Kernel::HLERequestContext& ctx);
};
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
public:
IHomeMenuFunctions();
private:
void RequestToGetForeground(Kernel::HLERequestContext& ctx);
};
class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
public:
IGlobalStateController();
};
class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
public:
IApplicationCreator();
};
class IProcessWindingController final : public ServiceFramework<IProcessWindingController> {
public:
IProcessWindingController();
};
/// Registers all AM services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger);

View File

@@ -20,7 +20,7 @@ public:
{2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"},
{3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"},
{4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"},
{10, nullptr, "GetProcessWindingController"},
{10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"},
{11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
{20, &ILibraryAppletProxy::GetApplicationFunctions, "GetApplicationFunctions"},
{1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
@@ -28,6 +28,93 @@ public:
RegisterHandlers(functions);
}
private:
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ICommonStateGetter>();
NGLOG_DEBUG(Service_AM, "called");
}
void GetSelfController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISelfController>(nvflinger);
NGLOG_DEBUG(Service_AM, "called");
}
void GetWindowController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IWindowController>();
NGLOG_DEBUG(Service_AM, "called");
}
void GetAudioController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IAudioController>();
NGLOG_DEBUG(Service_AM, "called");
}
void GetDisplayController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDisplayController>();
NGLOG_DEBUG(Service_AM, "called");
}
void GetProcessWindingController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IProcessWindingController>();
NGLOG_DEBUG(Service_AM, "called");
}
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDebugFunctions>();
NGLOG_DEBUG(Service_AM, "called");
}
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>();
NGLOG_DEBUG(Service_AM, "called");
}
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationFunctions>();
NGLOG_DEBUG(Service_AM, "called");
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
};
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
public:
explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
: ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)) {
static const FunctionInfo functions[] = {
{0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
{1, &ISystemAppletProxy::GetSelfController, "GetSelfController"},
{2, &ISystemAppletProxy::GetWindowController, "GetWindowController"},
{3, &ISystemAppletProxy::GetAudioController, "GetAudioController"},
{4, &ISystemAppletProxy::GetDisplayController, "GetDisplayController"},
{10, nullptr, "GetProcessWindingController"},
{11, &ISystemAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
{20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
{21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
{22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"},
{1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
};
RegisterHandlers(functions);
}
private:
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -78,16 +165,43 @@ private:
NGLOG_DEBUG(Service_AM, "called");
}
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationFunctions>();
rb.PushIpcInterface<IHomeMenuFunctions>();
NGLOG_DEBUG(Service_AM, "called");
}
void GetGlobalStateController(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IGlobalStateController>();
NGLOG_DEBUG(Service_AM, "called");
}
void GetApplicationCreator(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationCreator>();
NGLOG_DEBUG(Service_AM, "called");
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
};
void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemAppletProxy>(nvflinger);
NGLOG_DEBUG(Service_AM, "called");
}
void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger);
NGLOG_DEBUG(Service_AM, "called");
}
void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -98,9 +212,9 @@ void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
: ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)) {
static const FunctionInfo functions[] = {
{100, nullptr, "OpenSystemAppletProxy"},
{100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
{200, &AppletAE::OpenLibraryAppletProxyOld, "OpenLibraryAppletProxyOld"},
{201, nullptr, "OpenLibraryAppletProxy"},
{201, &AppletAE::OpenLibraryAppletProxy, "OpenLibraryAppletProxy"},
{300, nullptr, "OpenOverlayAppletProxy"},
{350, nullptr, "OpenSystemApplicationProxy"},
{400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"},

View File

@@ -21,6 +21,8 @@ public:
~AppletAE() = default;
private:
void OpenSystemAppletProxy(Kernel::HLERequestContext& ctx);
void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx);
void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx);
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;

View File

@@ -18,7 +18,7 @@ constexpr u32 sample_rate{48000};
/// to more audio channels (probably when Docked I guess)
constexpr u32 audio_channels{2};
/// TODO(st4rk): find a proper value for the audio_ticks
constexpr u64 audio_ticks{static_cast<u64>(BASE_CLOCK_RATE / 500)};
constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 500)};
class IAudioOut final : public ServiceFramework<IAudioOut> {
public:

View File

@@ -12,7 +12,7 @@
namespace Service::Audio {
/// TODO(bunnei): Find a proper value for the audio_ticks
constexpr u64 audio_ticks{static_cast<u64>(BASE_CLOCK_RATE / 200)};
constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 200)};
class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
public:
@@ -162,12 +162,13 @@ public:
{0x3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},
{0x4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
{0x5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
{0x6, nullptr, "ListAudioDeviceNameAuto"},
{0x7, nullptr, "SetAudioDeviceOutputVolumeAuto"},
{0x6, &IAudioDevice::ListAudioDeviceName,
"ListAudioDeviceNameAuto"}, // TODO(ogniK): Confirm if autos are identical to non auto
{0x7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"},
{0x8, nullptr, "GetAudioDeviceOutputVolumeAuto"},
{0x10, nullptr, "GetActiveAudioDeviceNameAuto"},
{0x11, nullptr, "QueryAudioDeviceInputEvent"},
{0x12, nullptr, "QueryAudioDeviceOutputEvent"}};
{0xa, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},
{0xb, nullptr, "QueryAudioDeviceInputEvent"},
{0xc, nullptr, "QueryAudioDeviceOutputEvent"}};
RegisterHandlers(functions);
buffer_event =
@@ -257,7 +258,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0x400);
rb.Push<u64>(0x4000);
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
}

View File

@@ -16,7 +16,7 @@ Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
void Module::Interface::FatalSimple(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
u32 error_code = rp.Pop<u32>();
NGLOG_WARNING(Service_Fatal, "(STUBBED) called, error_code={:#X}", error_code);
NGLOG_WARNING(Service_Fatal, "(STUBBED) called, error_code=0x{:X}", error_code);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}

View File

@@ -25,7 +25,7 @@ ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& fact
ASSERT_MSG(inserted, "Tried to register more than one system with same id code");
auto& filesystem = result.first->second;
NGLOG_DEBUG(Service_FS, "Registered file system {} with id code {:#010X}",
NGLOG_DEBUG(Service_FS, "Registered file system {} with id code 0x{:08X}",
filesystem->GetName(), static_cast<u32>(type));
return RESULT_SUCCESS;
}

View File

@@ -35,7 +35,7 @@ private:
const s64 offset = rp.Pop<s64>();
const s64 length = rp.Pop<s64>();
NGLOG_DEBUG(Service_FS, "called, offset={:#X}, length={}", offset, length);
NGLOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
// Error checking
if (length < 0) {
@@ -87,7 +87,7 @@ private:
const s64 offset = rp.Pop<s64>();
const s64 length = rp.Pop<s64>();
NGLOG_DEBUG(Service_FS, "called, offset={:#X}, length={}", offset, length);
NGLOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
// Error checking
if (length < 0) {
@@ -124,7 +124,7 @@ private:
const s64 offset = rp.Pop<s64>();
const s64 length = rp.Pop<s64>();
NGLOG_DEBUG(Service_FS, "called, offset={:#X}, length={}", offset, length);
NGLOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
// Error checking
if (length < 0) {
@@ -197,7 +197,7 @@ private:
IPC::RequestParser rp{ctx};
const u64 unk = rp.Pop<u64>();
NGLOG_DEBUG(Service_FS, "called, unk={:#X}", unk);
NGLOG_DEBUG(Service_FS, "called, unk=0x{:X}", unk);
// Calculate how many entries we can fit in the output buffer
u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry);
@@ -265,7 +265,7 @@ public:
u64 mode = rp.Pop<u64>();
u32 size = rp.Pop<u32>();
NGLOG_DEBUG(Service_FS, "called file {} mode {:#X} size {:#010X}", name, mode, size);
NGLOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend->CreateFile(name, size));

View File

@@ -18,9 +18,9 @@ namespace Service::HID {
// Updating period for each HID device.
// TODO(shinyquagsire23): These need better values.
constexpr u64 pad_update_ticks = BASE_CLOCK_RATE / 10000;
constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE / 10000;
constexpr u64 gyroscope_update_ticks = BASE_CLOCK_RATE / 10000;
constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000;
constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000;
constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000;
class IAppletResource final : public ServiceFramework<IAppletResource> {
public:
@@ -60,7 +60,10 @@ private:
std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
// TODO(shinyquagsire23): sticks, gyro, touch, mouse, keyboard
std::transform(Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
sticks.begin(), Input::CreateDevice<Input::AnalogDevice>);
// TODO(shinyquagsire23): gyro, touch, mouse, keyboard
}
void UpdatePadCallback(u64 userdata, int cycles_late) {
@@ -79,61 +82,70 @@ private:
controller_header.left_color_body = JOYCON_BODY_NEON_BLUE;
controller_header.left_color_buttons = JOYCON_BUTTONS_NEON_BLUE;
for (int index = 0; index < HID_NUM_LAYOUTS; index++) {
ControllerLayout& layout = mem.controllers[Controller_Handheld].layouts[index];
layout.header.num_entries = HID_NUM_ENTRIES;
layout.header.max_entry_index = HID_NUM_ENTRIES - 1;
for (size_t controller = 0; controller < mem.controllers.size(); controller++) {
for (int index = 0; index < HID_NUM_LAYOUTS; index++) {
ControllerLayout& layout = mem.controllers[controller].layouts[index];
layout.header.num_entries = HID_NUM_ENTRIES;
layout.header.max_entry_index = HID_NUM_ENTRIES - 1;
// HID shared memory stores the state of the past 17 samples in a circlular buffer,
// each with a timestamp in number of samples since boot.
layout.header.timestamp_ticks = CoreTiming::GetTicks();
layout.header.latest_entry = (layout.header.latest_entry + 1) % HID_NUM_ENTRIES;
// HID shared memory stores the state of the past 17 samples in a circlular buffer,
// each with a timestamp in number of samples since boot.
layout.header.timestamp_ticks = CoreTiming::GetTicks();
layout.header.latest_entry = (layout.header.latest_entry + 1) % HID_NUM_ENTRIES;
ControllerInputEntry& entry = layout.entries[layout.header.latest_entry];
entry.connection_state = ConnectionState_Connected | ConnectionState_Wired;
entry.timestamp++;
entry.timestamp_2++; // TODO(shinyquagsire23): Is this always identical to timestamp?
ControllerInputEntry& entry = layout.entries[layout.header.latest_entry];
entry.connection_state = ConnectionState_Connected | ConnectionState_Wired;
entry.timestamp++;
// TODO(shinyquagsire23): Is this always identical to timestamp?
entry.timestamp_2++;
// TODO(shinyquagsire23): Set up some LUTs for each layout mapping in the future?
// For now everything is just the default handheld layout, but split Joy-Con will
// rotate the face buttons and directions for certain layouts.
ControllerPadState& state = entry.buttons;
using namespace Settings::NativeButton;
state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
state.lstick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus());
state.rstick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus());
state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
// TODO(shinyquagsire23): More than just handheld input
if (controller != Controller_Handheld)
continue;
state.dleft.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
state.dup.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
state.dright.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
state.ddown.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
// TODO(shinyquagsire23): Set up some LUTs for each layout mapping in the future?
// For now everything is just the default handheld layout, but split Joy-Con will
// rotate the face buttons and directions for certain layouts.
ControllerPadState& state = entry.buttons;
using namespace Settings::NativeButton;
state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
state.lstick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus());
state.rstick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus());
state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
state.lstick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
state.lstick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
state.lstick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
state.lstick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
state.dleft.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
state.dup.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
state.dright.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
state.ddown.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
state.rstick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
state.rstick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
state.rstick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
state.rstick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
state.lstick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
state.lstick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
state.lstick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
state.lstick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus());
state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus());
state.rstick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
state.rstick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
state.rstick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
state.rstick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
// TODO(shinyquagsire23): Analog stick vals
state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus());
state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus());
// TODO(shinyquagsire23): Update pad info proper, (circular buffers, timestamps,
// layouts)
const auto [stick_l_x_f, stick_l_y_f] = sticks[Joystick_Left]->GetStatus();
const auto [stick_r_x_f, stick_r_y_f] = sticks[Joystick_Right]->GetStatus();
entry.joystick_left_x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
entry.joystick_left_y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
entry.joystick_right_x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
entry.joystick_right_y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
}
}
// TODO(bunnei): Properly implement the touch screen, the below will just write empty data
@@ -151,6 +163,71 @@ private:
touchscreen.entries[curr_entry].header.timestamp = sample_counter;
touchscreen.entries[curr_entry].header.num_touches = 0;
// TODO(shinyquagsire23): Properly implement mouse
Mouse& mouse = mem.mouse;
const u64 last_mouse_entry = mouse.header.latest_entry;
const u64 curr_mouse_entry = (mouse.header.latest_entry + 1) % mouse.entries.size();
const u64 mouse_sample_counter = mouse.entries[last_mouse_entry].timestamp + 1;
mouse.header.timestamp_ticks = timestamp;
mouse.header.num_entries = mouse.entries.size();
mouse.header.max_entry_index = mouse.entries.size();
mouse.header.latest_entry = curr_mouse_entry;
mouse.entries[curr_mouse_entry].timestamp = mouse_sample_counter;
mouse.entries[curr_mouse_entry].timestamp_2 = mouse_sample_counter;
// TODO(shinyquagsire23): Properly implement keyboard
Keyboard& keyboard = mem.keyboard;
const u64 last_keyboard_entry = keyboard.header.latest_entry;
const u64 curr_keyboard_entry =
(keyboard.header.latest_entry + 1) % keyboard.entries.size();
const u64 keyboard_sample_counter = keyboard.entries[last_keyboard_entry].timestamp + 1;
keyboard.header.timestamp_ticks = timestamp;
keyboard.header.num_entries = keyboard.entries.size();
keyboard.header.latest_entry = last_keyboard_entry;
keyboard.header.max_entry_index = keyboard.entries.size();
keyboard.entries[curr_keyboard_entry].timestamp = keyboard_sample_counter;
keyboard.entries[curr_keyboard_entry].timestamp_2 = keyboard_sample_counter;
// TODO(shinyquagsire23): Figure out what any of these are
for (size_t i = 0; i < mem.unk_input_1.size(); i++) {
UnkInput1& input = mem.unk_input_1[i];
const u64 last_input_entry = input.header.latest_entry;
const u64 curr_input_entry = (input.header.latest_entry + 1) % input.entries.size();
const u64 input_sample_counter = input.entries[last_input_entry].timestamp + 1;
input.header.timestamp_ticks = timestamp;
input.header.num_entries = input.entries.size();
input.header.latest_entry = last_input_entry;
input.header.max_entry_index = input.entries.size();
input.entries[curr_input_entry].timestamp = input_sample_counter;
input.entries[curr_input_entry].timestamp_2 = input_sample_counter;
}
for (size_t i = 0; i < mem.unk_input_2.size(); i++) {
UnkInput2& input = mem.unk_input_2[i];
input.header.timestamp_ticks = timestamp;
input.header.num_entries = 17;
input.header.latest_entry = 0;
input.header.max_entry_index = 0;
}
UnkInput3& input = mem.unk_input_3;
const u64 last_input_entry = input.header.latest_entry;
const u64 curr_input_entry = (input.header.latest_entry + 1) % input.entries.size();
const u64 input_sample_counter = input.entries[last_input_entry].timestamp + 1;
input.header.timestamp_ticks = timestamp;
input.header.num_entries = input.entries.size();
input.header.latest_entry = last_input_entry;
input.header.max_entry_index = input.entries.size();
input.entries[curr_input_entry].timestamp = input_sample_counter;
input.entries[curr_input_entry].timestamp_2 = input_sample_counter;
// TODO(shinyquagsire23): Signal events
std::memcpy(shared_mem->GetPointer(), &mem, sizeof(SharedMemory));
@@ -169,6 +246,7 @@ private:
std::atomic<bool> is_device_reload_pending{true};
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
buttons;
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks;
};
class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {

View File

@@ -48,6 +48,11 @@ enum ControllerConnectionState {
ConnectionState_Wired = 1 << 1,
};
enum ControllerJoystick {
Joystick_Left = 0,
Joystick_Right = 1,
};
enum ControllerID {
Controller_Player1 = 0,
Controller_Player2 = 1,
@@ -63,6 +68,34 @@ enum ControllerID {
// End enums and output structs
// Begin UnkInput3
struct UnkInput3Header {
u64 timestamp_ticks;
u64 num_entries;
u64 latest_entry;
u64 max_entry_index;
};
static_assert(sizeof(UnkInput3Header) == 0x20, "HID UnkInput3 header structure has incorrect size");
struct UnkInput3Entry {
u64 timestamp;
u64 timestamp_2;
u64 unk_8;
u64 unk_10;
u64 unk_18;
};
static_assert(sizeof(UnkInput3Entry) == 0x28, "HID UnkInput3 entry structure has incorrect size");
struct UnkInput3 {
UnkInput3Header header;
std::array<UnkInput3Entry, 17> entries;
std::array<u8, 0x138> padding;
};
static_assert(sizeof(UnkInput3) == 0x400, "HID UnkInput3 structure has incorrect size");
// End UnkInput3
// Begin TouchScreen
struct TouchScreenHeader {
@@ -204,6 +237,52 @@ static_assert(sizeof(Keyboard) == 0x400, "HID keyboard structure has incorrect s
// End Keyboard
// Begin UnkInput1
struct UnkInput1Header {
u64 timestamp_ticks;
u64 num_entries;
u64 latest_entry;
u64 max_entry_index;
};
static_assert(sizeof(UnkInput1Header) == 0x20, "HID UnkInput1 header structure has incorrect size");
struct UnkInput1Entry {
u64 timestamp;
u64 timestamp_2;
u64 unk_8;
u64 unk_10;
u64 unk_18;
};
static_assert(sizeof(UnkInput1Entry) == 0x28, "HID UnkInput1 entry structure has incorrect size");
struct UnkInput1 {
UnkInput1Header header;
std::array<UnkInput1Entry, 17> entries;
std::array<u8, 0x138> padding;
};
static_assert(sizeof(UnkInput1) == 0x400, "HID UnkInput1 structure has incorrect size");
// End UnkInput1
// Begin UnkInput2
struct UnkInput2Header {
u64 timestamp_ticks;
u64 num_entries;
u64 latest_entry;
u64 max_entry_index;
};
static_assert(sizeof(UnkInput2Header) == 0x20, "HID UnkInput2 header structure has incorrect size");
struct UnkInput2 {
UnkInput2Header header;
std::array<u8, 0x1E0> padding;
};
static_assert(sizeof(UnkInput2) == 0x200, "HID UnkInput2 structure has incorrect size");
// End UnkInput2
// Begin Controller
struct ControllerMAC {
@@ -283,10 +362,10 @@ struct ControllerInputEntry {
u64 timestamp;
u64 timestamp_2;
ControllerPadState buttons;
u32 joystick_left_x;
u32 joystick_left_y;
u32 joystick_right_x;
u32 joystick_right_y;
s32 joystick_left_x;
s32 joystick_left_y;
s32 joystick_right_x;
s32 joystick_right_y;
u64 connection_state;
};
static_assert(sizeof(ControllerInputEntry) == 0x30,
@@ -312,17 +391,12 @@ static_assert(sizeof(Controller) == 0x5000, "HID controller structure has incorr
// End Controller
struct SharedMemory {
std::array<u8, 0x400> header;
UnkInput3 unk_input_3;
TouchScreen touchscreen;
Mouse mouse;
Keyboard keyboard;
std::array<u8, 0x400> unk_section_1;
std::array<u8, 0x400> unk_section_2;
std::array<u8, 0x400> unk_section_3;
std::array<u8, 0x400> unk_section_4;
std::array<u8, 0x200> unk_section_5;
std::array<u8, 0x200> unk_section_6;
std::array<u8, 0x200> unk_section_7;
std::array<UnkInput1, 4> unk_input_1;
std::array<UnkInput2, 3> unk_input_2;
std::array<u8, 0x800> unk_section_8;
std::array<u8, 0x4000> controller_serials;
std::array<Controller, 10> controllers;

View File

@@ -12,10 +12,52 @@ namespace Service::NFP {
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
: ServiceFramework(name), module(std::move(module)) {}
void Module::Interface::Unknown(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_NFP, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
class IUser final : public ServiceFramework<IUser> {
public:
IUser() : ServiceFramework("IUser") {
static const FunctionInfo functions[] = {
{0, &IUser::Initialize, "Initialize"},
{1, nullptr, "Unknown1"},
{2, nullptr, "Unknown2"},
{3, nullptr, "Unknown3"},
{4, nullptr, "Unknown4"},
{5, nullptr, "Unknown5"},
{6, nullptr, "Unknown6"},
{7, nullptr, "Unknown7"},
{8, nullptr, "Unknown8"},
{9, nullptr, "Unknown9"},
{10, nullptr, "Unknown10"},
{11, nullptr, "Unknown11"},
{12, nullptr, "Unknown12"},
{13, nullptr, "Unknown13"},
{14, nullptr, "Unknown14"},
{15, nullptr, "Unknown15"},
{16, nullptr, "Unknown16"},
{17, nullptr, "Unknown17"},
{18, nullptr, "Unknown18"},
{19, nullptr, "Unknown19"},
{20, nullptr, "Unknown20"},
{21, nullptr, "Unknown21"},
{22, nullptr, "Unknown22"},
{23, nullptr, "Unknown23"},
{24, nullptr, "Unknown24"},
};
RegisterHandlers(functions);
}
private:
void Initialize(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_NFP, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
};
void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
NGLOG_DEBUG(Service_NFP, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IUser>();
}
void InstallInterfaces(SM::ServiceManager& service_manager) {

View File

@@ -14,7 +14,7 @@ public:
public:
Interface(std::shared_ptr<Module> module, const char* name);
void Unknown(Kernel::HLERequestContext& ctx);
void CreateUserInterface(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> module;

View File

@@ -9,7 +9,7 @@ namespace Service::NFP {
NFP_User::NFP_User(std::shared_ptr<Module> module)
: Module::Interface(std::move(module), "nfp:user") {
static const FunctionInfo functions[] = {
{0, &NFP_User::Unknown, "Unknown"},
{0, &NFP_User::CreateUserInterface, "CreateUserInterface"},
};
RegisterHandlers(functions);
}

View File

@@ -37,7 +37,7 @@ PL_U::PL_U() : ServiceFramework("pl:u") {
{2, &PL_U::GetSize, "GetSize"},
{3, &PL_U::GetSharedMemoryAddressOffset, "GetSharedMemoryAddressOffset"},
{4, &PL_U::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
{5, nullptr, "GetSharedFontInOrderOfPriority"},
{5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"},
};
RegisterHandlers(functions);
@@ -116,4 +116,29 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(shared_font_mem);
}
void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for
NGLOG_DEBUG(Service_NS, "called, language_code=%lx", language_code);
IPC::ResponseBuilder rb{ctx, 4};
std::vector<u32> font_codes;
std::vector<u32> font_offsets;
std::vector<u32> font_sizes;
// TODO(ogniK): Have actual priority order
for (size_t i = 0; i < SHARED_FONT_REGIONS.size(); i++) {
font_codes.push_back(static_cast<u32>(i));
font_offsets.push_back(SHARED_FONT_REGIONS[i].offset);
font_sizes.push_back(SHARED_FONT_REGIONS[i].size);
}
ctx.WriteBuffer(font_codes.data(), font_codes.size(), 0);
ctx.WriteBuffer(font_offsets.data(), font_offsets.size(), 1);
ctx.WriteBuffer(font_sizes.data(), font_sizes.size(), 2);
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(static_cast<u8>(LoadState::Done)); // Fonts Loaded
rb.Push<u32>(static_cast<u32>(font_codes.size()));
}
} // namespace Service::NS

View File

@@ -21,6 +21,7 @@ private:
void GetSize(Kernel::HLERequestContext& ctx);
void GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx);
void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx);
void GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx);
/// Handle to shared memory region designated for a shared font
Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;

View File

@@ -12,7 +12,7 @@
namespace Service::Nvidia::Devices {
u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
NGLOG_DEBUG(Service_NVDRV, "called, command={:#010X}, input_size={:#X}, output_size={:#X}",
NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
command.raw, input.size(), output.size());
switch (static_cast<IoctlCommand>(command.raw)) {
@@ -38,8 +38,7 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vecto
u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlInitalizeEx params{};
std::memcpy(&params, input.data(), input.size());
NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size={:#X}", params.big_page_size);
std::memcpy(output.data(), &params, output.size());
NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
return 0;
}
@@ -135,7 +134,6 @@ u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& ou
std::memcpy(&params, input.data(), input.size());
NGLOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
channel = params.fd;
std::memcpy(output.data(), &params, output.size());
return 0;
}

View File

@@ -9,7 +9,7 @@
namespace Service::Nvidia::Devices {
u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
NGLOG_DEBUG(Service_NVDRV, "called, command={:#010X}, input_size={:#X}, output_size={:#X}",
NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
command.raw, input.size(), output.size());
switch (static_cast<IoctlCommand>(command.raw)) {

View File

@@ -10,7 +10,7 @@
namespace Service::Nvidia::Devices {
u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
NGLOG_DEBUG(Service_NVDRV, "called, command={:#010X}, input_size={:#X}, output_size={:#X}",
NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
command.raw, input.size(), output.size());
switch (static_cast<IoctlCommand>(command.raw)) {
@@ -77,8 +77,13 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto
u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlGpuGetTpcMasksArgs params{};
std::memcpy(&params, input.data(), input.size());
NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, mask={:#X}, mask_buf_addr={:#X}",
params.mask_buf_size, params.mask_buf_addr);
NGLOG_INFO(Service_NVDRV, "called, mask=0x{:X}, mask_buf_addr=0x{:X}", params.mask_buf_size,
params.mask_buf_addr);
// TODO(ogniK): Confirm value on hardware
if (params.mask_buf_size)
params.tpc_mask_size = 4 * 1; // 4 * num_gpc
else
params.tpc_mask_size = 0;
std::memcpy(output.data(), &params, sizeof(params));
return 0;
}

View File

@@ -86,7 +86,7 @@ private:
/// [in] pointer to TPC mask buffer. It will receive one 32-bit TPC mask per GPC or 0 if
/// GPC is not enabled or not present. This parameter is ignored if mask_buf_size is 0.
u64_le mask_buf_addr;
u64_le unk; // Nintendo add this?
u64_le tpc_mask_size; // Nintendo add this?
};
static_assert(sizeof(IoctlGpuGetTpcMasksArgs) == 24,
"IoctlGpuGetTpcMasksArgs is incorrect size");

View File

@@ -12,7 +12,7 @@
namespace Service::Nvidia::Devices {
u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
NGLOG_DEBUG(Service_NVDRV, "called, command={:#010X}, input_size={:#X}, output_size={:#X}",
NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
command.raw, input.size(), output.size());
switch (static_cast<IoctlCommand>(command.raw)) {
@@ -49,7 +49,6 @@ u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output
std::memcpy(&params, input.data(), input.size());
NGLOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
nvmap_fd = params.nvmap_fd;
std::memcpy(output.data(), &params, output.size());
return 0;
}
@@ -58,7 +57,6 @@ u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& out
IoctlClientData params{};
std::memcpy(&params, input.data(), input.size());
user_data = params.data;
std::memcpy(output.data(), &params, output.size());
return 0;
}
@@ -91,7 +89,6 @@ u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>&
u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {
std::memcpy(&channel_priority, input.data(), input.size());
NGLOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
std::memcpy(output.data(), &channel_priority, output.size());
return 0;
}

View File

@@ -49,7 +49,7 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
u32 handle = next_handle++;
handles[handle] = std::move(object);
NGLOG_DEBUG(Service_NVDRV, "size={:#010X}", params.size);
NGLOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
params.handle = handle;

View File

@@ -75,7 +75,7 @@ void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
pid = rp.Pop<u64>();
NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, pid={:#X}", pid);
NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0);

View File

@@ -39,8 +39,8 @@ Module::Module() {
}
u32 Module::Open(std::string device_name) {
ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device %s",
device_name.c_str());
ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}",
device_name);
auto device = devices[device_name];
u32 fd = next_fd++;

View File

@@ -19,7 +19,7 @@
namespace Service::NVFlinger {
constexpr size_t SCREEN_REFRESH_RATE = 60;
constexpr u64 frame_ticks = static_cast<u64>(BASE_CLOCK_RATE / SCREEN_REFRESH_RATE);
constexpr u64 frame_ticks = static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE);
NVFlinger::NVFlinger() {
// Add the different displays to the list of displays.

View File

@@ -0,0 +1,43 @@
#include <cinttypes>
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/prepo/prepo.h"
namespace Service::PlayReport {
PlayReport::PlayReport(const char* name) : ServiceFramework(name) {
static const FunctionInfo functions[] = {
{10100, nullptr, "SaveReport"},
{10101, &PlayReport::SaveReportWithUser, "SaveReportWithUser"},
{10200, nullptr, "RequestImmediateTransmission"},
{10300, nullptr, "GetTransmissionStatus"},
{20100, nullptr, "SaveSystemReport"},
{20200, nullptr, "SetOperationMode"},
{20101, nullptr, "SaveSystemReportWithUser"},
{30100, nullptr, "ClearStorage"},
{40100, nullptr, "IsUserAgreementCheckEnabled"},
{40101, nullptr, "SetUserAgreementCheckEnabled"},
{90100, nullptr, "GetStorageUsage"},
{90200, nullptr, "GetStatistics"},
{90201, nullptr, "GetThroughputHistory"},
{90300, nullptr, "GetLastUploadError"},
};
RegisterHandlers(functions);
};
void PlayReport::SaveReportWithUser(Kernel::HLERequestContext& ctx) {
// TODO(ogniK): Do we want to add play report?
NGLOG_WARNING(Service_PREPO, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
};
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<PlayReport>("prepo:a")->InstallAsService(service_manager);
std::make_shared<PlayReport>("prepo:m")->InstallAsService(service_manager);
std::make_shared<PlayReport>("prepo:s")->InstallAsService(service_manager);
std::make_shared<PlayReport>("prepo:u")->InstallAsService(service_manager);
}
} // namespace Service::PlayReport

View File

@@ -0,0 +1,23 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <memory>
#include <string>
#include "core/hle/kernel/event.h"
#include "core/hle/service/service.h"
namespace Service::PlayReport {
class PlayReport final : public ServiceFramework<PlayReport> {
public:
explicit PlayReport(const char* name);
~PlayReport() = default;
private:
void SaveReportWithUser(Kernel::HLERequestContext& ctx);
};
void InstallInterfaces(SM::ServiceManager& service_manager);
} // namespace Service::PlayReport

View File

@@ -29,7 +29,8 @@
#include "core/hle/service/nifm/nifm.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/pctl/module.h"
#include "core/hle/service/pctl/pctl.h"
#include "core/hle/service/prepo/prepo.h"
#include "core/hle/service/service.h"
#include "core/hle/service/set/settings.h"
#include "core/hle/service/sm/controller.h"
@@ -57,10 +58,9 @@ static std::string MakeFunctionString(const char* name, const char* port_name,
// Number of params == bits 0-5 + bits 6-11
int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
std::string function_string =
Common::StringFromFormat("function '%s': port=%s", name, port_name);
std::string function_string = fmt::format("function '{}': port={}", name, port_name);
for (int i = 1; i <= num_params; ++i) {
function_string += Common::StringFromFormat(", cmd_buff[%i]=0x%X", i, cmd_buff[i]);
function_string += fmt::format(", cmd_buff[{}]=0x{:X}", i, cmd_buff[i]);
}
return function_string;
}
@@ -113,10 +113,10 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
std::string function_name = info == nullptr ? fmt::format("{}", ctx.GetCommand()) : info->name;
fmt::memory_buffer buf;
fmt::format_to(buf, "function '{}': port='{}' cmd_buf={{[0]={:#x}", function_name, service_name,
cmd_buf[0]);
fmt::format_to(buf, "function '{}': port='{}' cmd_buf={{[0]=0x{:X}", function_name,
service_name, cmd_buf[0]);
for (int i = 1; i <= 8; ++i) {
fmt::format_to(buf, ", [{}]={:#x}", i, cmd_buf[i]);
fmt::format_to(buf, ", [{}]=0x{:X}", i, cmd_buf[i]);
}
buf.push_back('}');
@@ -153,7 +153,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
break;
}
default:
UNIMPLEMENTED_MSG("command_type=%d", static_cast<int>(context.GetCommandType()));
UNIMPLEMENTED_MSG("command_type={}", static_cast<int>(context.GetCommandType()));
}
context.WriteToOutgoingCommandBuffer(*Kernel::GetCurrentThread());
@@ -192,6 +192,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) {
NS::InstallInterfaces(*sm);
Nvidia::InstallInterfaces(*sm);
PCTL::InstallInterfaces(*sm);
PlayReport::InstallInterfaces(*sm);
Sockets::InstallInterfaces(*sm);
SPL::InstallInterfaces(*sm);
SSL::InstallInterfaces(*sm);

View File

@@ -14,15 +14,33 @@ namespace Service::Set {
void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u32 id = rp.Pop<u32>();
constexpr std::array<u8, 13> lang_codes{};
ctx.WriteBuffer(lang_codes.data(), lang_codes.size());
IPC::ResponseBuilder rb{ctx, 2};
static constexpr std::array<LanguageCode, 17> available_language_codes = {{
LanguageCode::JA,
LanguageCode::EN_US,
LanguageCode::FR,
LanguageCode::DE,
LanguageCode::IT,
LanguageCode::ES,
LanguageCode::ZH_CN,
LanguageCode::KO,
LanguageCode::NL,
LanguageCode::PT,
LanguageCode::RU,
LanguageCode::ZH_TW,
LanguageCode::EN_GB,
LanguageCode::FR_CA,
LanguageCode::ES_419,
LanguageCode::ZH_HANS,
LanguageCode::ZH_HANT,
}};
ctx.WriteBuffer(available_language_codes.data(), available_language_codes.size());
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u64>(available_language_codes.size()));
NGLOG_WARNING(Service_SET, "(STUBBED) called");
NGLOG_DEBUG(Service_SET, "called");
}
SET::SET() : ServiceFramework("set") {

View File

@@ -8,6 +8,27 @@
namespace Service::Set {
/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64.
enum class LanguageCode : u64 {
JA = 0x000000000000616A,
EN_US = 0x00000053552D6E65,
FR = 0x0000000000007266,
DE = 0x0000000000006564,
IT = 0x0000000000007469,
ES = 0x0000000000007365,
ZH_CN = 0x0000004E432D687A,
KO = 0x0000000000006F6B,
NL = 0x0000000000006C6E,
PT = 0x0000000000007470,
RU = 0x0000000000007572,
ZH_TW = 0x00000057542D687A,
EN_GB = 0x00000042472D6E65,
FR_CA = 0x00000041432D7266,
ES_419 = 0x00003931342D7365,
ZH_HANS = 0x00736E61482D687A,
ZH_HANT = 0x00746E61482D687A,
};
class SET final : public ServiceFramework<SET> {
public:
explicit SET();

View File

@@ -102,7 +102,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
if (client_port.Failed()) {
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
rb.Push(client_port.Code());
NGLOG_ERROR(Service_SM, "called service={} -> error {:#010X}", name,
NGLOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name,
client_port.Code().raw);
if (name.length() == 0)
return; // LibNX Fix

View File

@@ -96,12 +96,22 @@ SSL::SSL() : ServiceFramework("ssl") {
{2, nullptr, "GetCertificates"},
{3, nullptr, "GetCertificateBufSize"},
{4, nullptr, "DebugIoctl"},
{5, nullptr, "SetInterfaceVersion"},
{5, &SSL::SetInterfaceVersion, "SetInterfaceVersion"},
{6, nullptr, "FlushSessionCache"},
};
RegisterHandlers(functions);
}
void SSL::SetInterfaceVersion(Kernel::HLERequestContext& ctx) {
NGLOG_WARNING(Service_SSL, "(STUBBED) called");
IPC::RequestParser rp{ctx};
u32 unk1 = rp.Pop<u32>(); // Probably minor/major?
u32 unk2 = rp.Pop<u32>(); // TODO(ogniK): Figure out what this does
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<SSL>()->InstallAsService(service_manager);
}

View File

@@ -15,6 +15,7 @@ public:
private:
void CreateContext(Kernel::HLERequestContext& ctx);
void SetInterfaceVersion(Kernel::HLERequestContext& ctx);
};
/// Registers all SSL services with the specified service manager.

View File

@@ -59,7 +59,8 @@ public:
private:
void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
NGLOG_DEBUG(Service_Time, "called");
SteadyClockTimePoint steady_clock_time_point{cyclesToMs(CoreTiming::GetTicks()) / 1000};
SteadyClockTimePoint steady_clock_time_point{
CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000};
IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(steady_clock_time_point);
@@ -110,7 +111,7 @@ private:
IPC::RequestParser rp{ctx};
u64 posix_time = rp.Pop<u64>();
NGLOG_WARNING(Service_Time, "(STUBBED) called, posix_time={:#018X}", posix_time);
NGLOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
CalendarAdditionalInfo additional_info{};

View File

@@ -640,7 +640,7 @@ private:
bool visibility = rp.Pop<bool>();
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_VI, "(STUBBED) called, layer_id={:#010X}, visibility={}", layer_id,
NGLOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id,
visibility);
}
};
@@ -762,7 +762,7 @@ private:
bool visibility = rp.Pop<bool>();
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
rb.Push(RESULT_SUCCESS);
NGLOG_WARNING(Service_VI, "(STUBBED) called, layer_id={:#X}, visibility={}", layer_id,
NGLOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id,
visibility);
}

View File

@@ -56,13 +56,14 @@ static void UpdateTimeCallback(u64 userdata, int cycles_late) {
date_time.date_time = GetSystemTime();
date_time.update_tick = CoreTiming::GetTicks();
date_time.tick_to_second_coefficient = BASE_CLOCK_RATE;
date_time.tick_to_second_coefficient = CoreTiming::BASE_CLOCK_RATE;
date_time.tick_offset = 0;
++shared_page.date_time_counter;
// system time is updated hourly
CoreTiming::ScheduleEvent(msToCycles(60 * 60 * 1000) - cycles_late, update_time_event);
CoreTiming::ScheduleEvent(CoreTiming::msToCycles(60 * 60 * 1000) - cycles_late,
update_time_event);
}
void Init() {

View File

@@ -33,7 +33,7 @@ inline void Read(T& var, const u32 addr) {
LCD::Read(var, addr);
break;
default:
NGLOG_ERROR(HW_Memory, "Unknown Read{} @ {:#010X}", sizeof(var) * 8, addr);
NGLOG_ERROR(HW_Memory, "Unknown Read{} @ 0x{:08X}", sizeof(var) * 8, addr);
break;
}
}
@@ -62,7 +62,7 @@ inline void Write(u32 addr, const T data) {
LCD::Write(addr, data);
break;
default:
NGLOG_ERROR(HW_Memory, "Unknown Write{} {:#010X} @ {:#010X}", sizeof(data) * 8, data, addr);
NGLOG_ERROR(HW_Memory, "Unknown Write{} 0x{:08X} @ 0x{:08X}", sizeof(data) * 8, data, addr);
break;
}
}

View File

@@ -20,7 +20,7 @@ inline void Read(T& var, const u32 raw_addr) {
// Reads other than u32 are untested, so I'd rather have them abort than silently fail
if (index >= 0x400 || !std::is_same<T, u32>::value) {
NGLOG_ERROR(HW_LCD, "Unknown Read{} @ {:#010X}", sizeof(var) * 8, addr);
NGLOG_ERROR(HW_LCD, "Unknown Read{} @ 0x{:08X}", sizeof(var) * 8, addr);
return;
}
@@ -34,7 +34,7 @@ inline void Write(u32 addr, const T data) {
// Writes other than u32 are untested, so I'd rather have them abort than silently fail
if (index >= 0x400 || !std::is_same<T, u32>::value) {
NGLOG_ERROR(HW_LCD, "Unknown Write{} {:#010X} @ {:#010X}", sizeof(data) * 8, data, addr);
NGLOG_ERROR(HW_LCD, "Unknown Write{} 0x{:08X} @ 0x{:08X}", sizeof(data) * 8, data, addr);
return;
}

View File

@@ -132,7 +132,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
const VAddr load_addr = next_load_addr;
next_load_addr = AppLoader_NSO::LoadModule(path, load_addr);
if (next_load_addr) {
NGLOG_DEBUG(Loader, "loaded module {} @ {:#X}", module, load_addr);
NGLOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
} else {
next_load_addr = load_addr;
}
@@ -176,8 +176,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(
offset = 0;
size = romfs_file->GetSize();
NGLOG_DEBUG(Loader, "RomFS offset: {:#018X}", offset);
NGLOG_DEBUG(Loader, "RomFS size: {:#018X}", size);
NGLOG_DEBUG(Loader, "RomFS offset: 0x{:016X}", offset);
NGLOG_DEBUG(Loader, "RomFS size: 0x{:016X}", size);
// Reset read pointer
file.Seek(0, SEEK_SET);

View File

@@ -84,7 +84,7 @@ static std::vector<u8> ReadSegment(FileUtil::IOFile& file, const NsoSegmentHeade
reinterpret_cast<char*>(uncompressed_data.data()), compressed_size, header.size);
ASSERT_MSG(bytes_uncompressed == header.size && bytes_uncompressed == uncompressed_data.size(),
"%d != %u != %zu", bytes_uncompressed, header.size, uncompressed_data.size());
"{} != {} != {}", bytes_uncompressed, header.size, uncompressed_data.size());
return uncompressed_data;
}
@@ -158,7 +158,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
// Load module
LoadModule(filepath, Memory::PROCESS_IMAGE_VADDR);
NGLOG_DEBUG(Loader, "loaded module {} @ {:#X}", filepath, Memory::PROCESS_IMAGE_VADDR);
NGLOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", filepath, Memory::PROCESS_IMAGE_VADDR);
process->svc_access_mask.set();
process->address_mappings = default_address_mappings;

View File

@@ -4,7 +4,6 @@
#include <algorithm>
#include <array>
#include <cinttypes>
#include <cstring>
#include <boost/optional.hpp>
#include "common/assert.h"
@@ -47,7 +46,7 @@ static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, Pa
VAddr end = base + size;
while (base != end) {
ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %016" PRIX64, base);
ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at {:016X}", base);
page_table.attributes[base] = type;
page_table.pointers[base] = memory;
@@ -59,14 +58,14 @@ static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, Pa
}
void MapMemoryRegion(PageTable& page_table, VAddr base, u64 size, u8* target) {
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %016" PRIX64, size);
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %016" PRIX64, base);
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory);
}
void MapIoRegion(PageTable& page_table, VAddr base, u64 size, MemoryHookPointer mmio_handler) {
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %016" PRIX64, size);
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %016" PRIX64, base);
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special);
auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
@@ -75,8 +74,8 @@ void MapIoRegion(PageTable& page_table, VAddr base, u64 size, MemoryHookPointer
}
void UnmapRegion(PageTable& page_table, VAddr base, u64 size) {
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %016" PRIX64, size);
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %016" PRIX64, base);
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped);
auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
@@ -169,10 +168,10 @@ T Read(const VAddr vaddr) {
PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
switch (type) {
case PageType::Unmapped:
NGLOG_ERROR(HW_Memory, "Unmapped Read{} @ {:#010X}", sizeof(T) * 8, vaddr);
NGLOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
return 0;
case PageType::Memory:
ASSERT_MSG(false, "Mapped memory page without a pointer @ %016" PRIX64, vaddr);
ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
break;
case PageType::RasterizerCachedMemory: {
RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Flush);
@@ -201,11 +200,11 @@ void Write(const VAddr vaddr, const T data) {
PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
switch (type) {
case PageType::Unmapped:
NGLOG_ERROR(HW_Memory, "Unmapped Write{} {:#010X} @ {:#018X}", sizeof(data) * 8, (u32)data,
vaddr);
NGLOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
static_cast<u32>(data), vaddr);
return;
case PageType::Memory:
ASSERT_MSG(false, "Mapped memory page without a pointer @ %016" PRIX64, vaddr);
ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
break;
case PageType::RasterizerCachedMemory: {
RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Invalidate);
@@ -251,7 +250,7 @@ u8* GetPointer(const VAddr vaddr) {
return GetPointerFromVMA(vaddr);
}
NGLOG_ERROR(HW_Memory, "Unknown GetPointer @ {:#018X}", vaddr);
NGLOG_ERROR(HW_Memory, "Unknown GetPointer @ 0x{:016X}", vaddr);
return nullptr;
}
@@ -288,12 +287,12 @@ u8* GetPhysicalPointer(PAddr address) {
});
if (area == std::end(memory_areas)) {
NGLOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ {:#018X}", address);
NGLOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ 0x{:016X}", address);
return nullptr;
}
if (area->paddr_base == IO_AREA_PADDR) {
NGLOG_ERROR(HW_Memory, "MMIO mappings are not supported yet. phys_addr={:018X}", address);
NGLOG_ERROR(HW_Memory, "MMIO mappings are not supported yet. phys_addr={:016X}", address);
return nullptr;
}
@@ -477,7 +476,7 @@ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_
switch (page_table.attributes[page_index]) {
case PageType::Unmapped: {
NGLOG_ERROR(HW_Memory,
"Unmapped ReadBlock @ {:#018X} (start address = {:#018X}, size = {})",
"Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
current_vaddr, src_addr, size);
std::memset(dest_buffer, 0, copy_amount);
break;
@@ -541,7 +540,7 @@ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const voi
switch (page_table.attributes[page_index]) {
case PageType::Unmapped: {
NGLOG_ERROR(HW_Memory,
"Unmapped WriteBlock @ {:#018X} (start address = {:#018X}, size = {})",
"Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
current_vaddr, dest_addr, size);
break;
}
@@ -589,7 +588,7 @@ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const size
switch (page_table.attributes[page_index]) {
case PageType::Unmapped: {
NGLOG_ERROR(HW_Memory,
"Unmapped ZeroBlock @ {:#018X} (start address = {#:018X}, size = {})",
"Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
current_vaddr, dest_addr, size);
break;
}
@@ -630,7 +629,7 @@ void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
switch (page_table.attributes[page_index]) {
case PageType::Unmapped: {
NGLOG_ERROR(HW_Memory,
"Unmapped CopyBlock @ {:#018X} (start address = {:#018X}, size = {})",
"Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
current_vaddr, src_addr, size);
ZeroBlock(process, dest_addr, copy_amount);
break;
@@ -684,7 +683,7 @@ boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) {
PAddr VirtualToPhysicalAddress(const VAddr addr) {
auto paddr = TryVirtualToPhysicalAddress(addr);
if (!paddr) {
NGLOG_ERROR(HW_Memory, "Unknown virtual address @ {:#018X}", addr);
NGLOG_ERROR(HW_Memory, "Unknown virtual address @ 0x{:016X}", addr);
// To help with debugging, set bit on address so that it's obviously invalid.
return addr | 0x80000000;
}

11
src/core/memory_hook.cpp Normal file
View File

@@ -0,0 +1,11 @@
// Copyright 2018 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/memory_hook.h"
namespace Memory {
MemoryHook::~MemoryHook() = default;
} // namespace Memory

View File

@@ -23,7 +23,7 @@ namespace Memory {
*/
class MemoryHook {
public:
virtual ~MemoryHook() = default;
virtual ~MemoryHook();
virtual boost::optional<bool> IsValidAddress(VAddr addr) = 0;

View File

@@ -99,6 +99,10 @@ enum Values {
NumAnalogs,
};
constexpr int STICK_HID_BEGIN = LStick;
constexpr int STICK_HID_END = NumAnalogs;
constexpr int NUM_STICKS_HID = NumAnalogs;
static const std::array<const char*, NumAnalogs> mapping = {{
"lstick",
"rstick",

View File

@@ -42,14 +42,14 @@ u64 GetTelemetryId() {
if (FileUtil::Exists(filename)) {
FileUtil::IOFile file(filename, "rb");
if (!file.IsOpen()) {
LOG_ERROR(Core, "failed to open telemetry_id: %s", filename.c_str());
NGLOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
return {};
}
file.ReadBytes(&telemetry_id, sizeof(u64));
} else {
FileUtil::IOFile file(filename, "wb");
if (!file.IsOpen()) {
LOG_ERROR(Core, "failed to open telemetry_id: %s", filename.c_str());
NGLOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
return {};
}
telemetry_id = GenerateTelemetryId();
@@ -65,7 +65,7 @@ u64 RegenerateTelemetryId() {
FileUtil::IOFile file(filename, "wb");
if (!file.IsOpen()) {
LOG_ERROR(Core, "failed to open telemetry_id: %s", filename.c_str());
NGLOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
return {};
}
file.WriteBytes(&new_telemetry_id, sizeof(u64));

View File

@@ -159,7 +159,7 @@ void Recorder::Finish(const std::string& filename) {
throw "Failed to write stream element";
}
} catch (const char* str) {
LOG_ERROR(HW_GPU, "Writing CiTrace file failed: %s", str);
NGLOG_ERROR(HW_GPU, "Writing CiTrace file failed: {}", str);
}
}

View File

@@ -32,7 +32,7 @@ public:
explicit SDLJoystick(int joystick_index)
: joystick{SDL_JoystickOpen(joystick_index), SDL_JoystickClose} {
if (!joystick) {
LOG_ERROR(Input, "failed to open joystick %d", joystick_index);
NGLOG_ERROR(Input, "failed to open joystick {}", joystick_index);
}
}
@@ -204,7 +204,7 @@ public:
trigger_if_greater = false;
} else {
trigger_if_greater = true;
LOG_ERROR(Input, "Unknown direction %s", direction_name.c_str());
NGLOG_ERROR(Input, "Unknown direction '{}'", direction_name);
}
return std::make_unique<SDLAxisButton>(GetJoystick(joystick_index), axis, threshold,
trigger_if_greater);
@@ -235,7 +235,7 @@ public:
void Init() {
if (SDL_Init(SDL_INIT_JOYSTICK) < 0) {
LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: %s", SDL_GetError());
NGLOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
} else {
using namespace Input;
RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>());

View File

@@ -59,12 +59,12 @@ void Fermi2D::HandleSurfaceCopy() {
// If the input is tiled and the output is linear, deswizzle the input and copy it over.
Texture::CopySwizzledData(regs.src.width, regs.src.height, src_bytes_per_pixel,
dst_bytes_per_pixel, src_buffer, dst_buffer, true,
regs.src.block_height);
regs.src.BlockHeight());
} else {
// If the input is linear and the output is tiled, swizzle the input and copy it over.
Texture::CopySwizzledData(regs.src.width, regs.src.height, src_bytes_per_pixel,
dst_bytes_per_pixel, dst_buffer, src_buffer, false,
regs.dst.block_height);
regs.dst.BlockHeight());
}
}

View File

@@ -49,6 +49,11 @@ public:
return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) |
address_low);
}
u32 BlockHeight() const {
// The block height is stored in log2 format.
return 1 << block_height;
}
};
static_assert(sizeof(Surface) == 0x28, "Surface has incorrect size");

View File

@@ -168,7 +168,7 @@ void Maxwell3D::ProcessQueryGet() {
result = 0;
break;
default:
UNIMPLEMENTED_MSG("Unimplemented query select type %u",
UNIMPLEMENTED_MSG("Unimplemented query select type {}",
static_cast<u32>(regs.query.query_get.select.Value()));
}
@@ -186,7 +186,7 @@ void Maxwell3D::ProcessQueryGet() {
break;
}
default:
UNIMPLEMENTED_MSG("Query mode %u not implemented",
UNIMPLEMENTED_MSG("Query mode {} not implemented",
static_cast<u32>(regs.query.query_get.mode.Value()));
}
}
@@ -208,6 +208,16 @@ void Maxwell3D::DrawArrays() {
const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count};
VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(is_indexed);
// TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
// the game is trying to draw indexed or direct mode. This needs to be verified on HW still -
// it's possible that it is incorrect and that there is some other register used to specify the
// drawing mode.
if (is_indexed) {
regs.index_array.count = 0;
} else {
regs.vertex_buffer.count = 0;
}
}
void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) {

View File

@@ -19,9 +19,19 @@ namespace Tegra {
namespace Shader {
struct Register {
// Register 255 is special cased to always be 0
/// Number of registers
static constexpr size_t NumRegisters = 256;
/// Register 255 is special cased to always be 0
static constexpr size_t ZeroIndex = 255;
enum class Size : u64 {
Byte = 0,
Short = 1,
Word = 2,
Long = 3,
};
constexpr Register() = default;
constexpr Register(u64 value) : value(value) {}
@@ -48,6 +58,11 @@ struct Register {
return ~value;
}
u64 GetSwizzledIndex(u64 elem) const {
elem = (value + elem) & 3;
return (value & ~3) + elem;
}
private:
u64 value{};
};
@@ -228,6 +243,15 @@ union Instruction {
BitField<56, 1, u64> neg_imm;
} fset;
union {
BitField<10, 2, Register::Size> size;
BitField<13, 1, u64> is_signed;
BitField<41, 2, u64> selector;
BitField<45, 1, u64> negate_a;
BitField<49, 1, u64> abs_a;
BitField<50, 1, u64> saturate_a;
} conversion;
BitField<61, 1, u64> is_b_imm;
BitField<60, 1, u64> is_b_gpr;
BitField<59, 1, u64> is_c_gpr;
@@ -282,10 +306,11 @@ public:
MOV_C,
MOV_R,
MOV_IMM,
MOV32I,
MOV32_IMM,
SHR_C,
SHR_R,
SHR_IMM,
FMNMX,
FSETP_C, // Set Predicate
FSETP_R,
FSETP_IMM,
@@ -306,6 +331,7 @@ public:
FloatSet,
FloatSetPredicate,
IntegerSetPredicate,
Conversion,
Unknown,
};
@@ -427,20 +453,21 @@ private:
INST("0100110010110---", Id::F2I_C, Type::Arithmetic, "F2I_C"),
INST("0101110010110---", Id::F2I_R, Type::Arithmetic, "F2I_R"),
INST("0011100-10110---", Id::F2I_IMM, Type::Arithmetic, "F2I_IMM"),
INST("0100110010111---", Id::I2F_C, Type::Arithmetic, "I2F_C"),
INST("0101110010111---", Id::I2F_R, Type::Arithmetic, "I2F_R"),
INST("0011100-10111---", Id::I2F_IMM, Type::Arithmetic, "I2F_IMM"),
INST("0100110011100---", Id::I2I_C, Type::Arithmetic, "I2I_C"),
INST("0101110011100---", Id::I2I_R, Type::Arithmetic, "I2I_R"),
INST("01110001-1000---", Id::I2I_IMM, Type::Arithmetic, "I2I_IMM"),
INST("000001----------", Id::LOP32I, Type::Arithmetic, "LOP32I"),
INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"),
INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"),
INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"),
INST("000000010000----", Id::MOV32I, Type::Arithmetic, "MOV32I"),
INST("000000010000----", Id::MOV32_IMM, Type::Arithmetic, "MOV32_IMM"),
INST("0100110000101---", Id::SHR_C, Type::Arithmetic, "SHR_C"),
INST("0101110000101---", Id::SHR_R, Type::Arithmetic, "SHR_R"),
INST("0011100-00101---", Id::SHR_IMM, Type::Arithmetic, "SHR_IMM"),
INST("0101110001100---", Id::FMNMX, Type::Arithmetic, "FMNMX"),
INST("0100110011100---", Id::I2I_C, Type::Conversion, "I2I_C"),
INST("0101110011100---", Id::I2I_R, Type::Conversion, "I2I_R"),
INST("01110001-1000---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"),
INST("0100110010111---", Id::I2F_C, Type::Conversion, "I2F_C"),
INST("0101110010111---", Id::I2F_R, Type::Conversion, "I2F_R"),
INST("0011100-10111---", Id::I2F_IMM, Type::Conversion, "I2F_IMM"),
INST("01011000--------", Id::FSET_R, Type::FloatSet, "FSET_R"),
INST("0100100---------", Id::FSET_C, Type::FloatSet, "FSET_C"),
INST("0011000---------", Id::FSET_IMM, Type::FloatSet, "FSET_IMM"),

View File

@@ -30,7 +30,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) {
case RenderTargetFormat::RGB10_A2_UNORM:
return 4;
default:
UNIMPLEMENTED_MSG("Unimplemented render target format %u", static_cast<u32>(format));
UNIMPLEMENTED_MSG("Unimplemented render target format {}", static_cast<u32>(format));
}
}

View File

@@ -113,7 +113,7 @@ bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) {
break;
}
default:
UNIMPLEMENTED_MSG("Unimplemented macro operation %u",
UNIMPLEMENTED_MSG("Unimplemented macro operation {}",
static_cast<u32>(opcode.operation.Value()));
}
@@ -154,7 +154,7 @@ u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b)
return ~(src_a & src_b);
default:
UNIMPLEMENTED_MSG("Unimplemented ALU operation %u", static_cast<u32>(operation));
UNIMPLEMENTED_MSG("Unimplemented ALU operation {}", static_cast<u32>(operation));
}
}
@@ -201,7 +201,7 @@ void MacroInterpreter::ProcessResult(ResultOperation operation, u32 reg, u32 res
Send((result >> 12) & 0b111111);
break;
default:
UNIMPLEMENTED_MSG("Unimplemented result operation %u", static_cast<u32>(operation));
UNIMPLEMENTED_MSG("Unimplemented result operation {}", static_cast<u32>(operation));
}
}

View File

@@ -252,7 +252,7 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
break;
}
default:
NGLOG_CRITICAL(HW_GPU, "Unimplemented shader index={}, enable={}, offset={:#010X}",
NGLOG_CRITICAL(HW_GPU, "Unimplemented shader index={}, enable={}, offset=0x{:08X}",
index, shader_config.enable.Value(), shader_config.offset);
UNREACHABLE();
}

View File

@@ -41,7 +41,7 @@ enum class ExitMethod {
struct Subroutine {
/// Generates a name suitable for GLSL source code.
std::string GetName() const {
return "sub_" + std::to_string(begin) + "_" + std::to_string(end);
return "sub_" + std::to_string(begin) + '_' + std::to_string(end);
}
u32 begin; ///< Entry point of the subroutine.
@@ -146,31 +146,304 @@ private:
std::string shader_source;
};
class GLSLGenerator {
/**
* Represents an emulated shader register, used to track the state of that register for emulation
* with GLSL. At this time, a register can be used as a float or an integer. This class is used for
* bookkeeping within the GLSL program.
*/
class GLSLRegister {
public:
GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
u32 main_offset, Maxwell3D::Regs::ShaderStage stage)
: subroutines(subroutines), program_code(program_code), main_offset(main_offset),
stage(stage) {
enum class Type {
Float,
Integer,
UnsignedInteger,
};
Generate();
GLSLRegister(size_t index, ShaderWriter& shader) : index{index}, shader{shader} {}
/// Gets the GLSL type string for a register
static std::string GetTypeString(Type type) {
switch (type) {
case Type::Float:
return "float";
case Type::Integer:
return "int";
case Type::UnsignedInteger:
return "uint";
}
UNREACHABLE();
return {};
}
std::string GetShaderCode() {
return declarations.GetResult() + shader.GetResult();
/// Gets the GLSL register prefix string, used for declarations and referencing
static std::string GetPrefixString(Type type) {
return "reg_" + GetTypeString(type) + '_';
}
/// Returns entries in the shader that are useful for external functions
ShaderEntries GetEntries() const {
return {GetConstBuffersDeclarations()};
/// Returns a GLSL string representing the current state of the register
const std::string GetActiveString() {
declr_type.insert(active_type);
return GetPrefixString(active_type) + std::to_string(index);
}
/// Returns true if the active type is a float
bool IsFloat() const {
return active_type == Type::Float;
}
/// Returns true if the active type is an integer
bool IsInteger() const {
return active_type == Type::Integer;
}
/// Returns the index of the register
size_t GetIndex() const {
return index;
}
/// Returns a set of the declared types of the register
const std::set<Type>& DeclaredTypes() const {
return declr_type;
}
private:
/// Gets the Subroutine object corresponding to the specified address.
const Subroutine& GetSubroutine(u32 begin, u32 end) const {
auto iter = subroutines.find(Subroutine{begin, end});
ASSERT(iter != subroutines.end());
return *iter;
const size_t index;
const std::string float_str;
const std::string integer_str;
ShaderWriter& shader;
Type active_type{Type::Float};
std::set<Type> declr_type;
};
/**
* Used to manage shader registers that are emulated with GLSL. This class keeps track of the state
* of all registers (e.g. whether they are currently being used as Floats or Integers), and
* generates the necessary GLSL code to perform conversions as needed. This class is used for
* bookkeeping within the GLSL program.
*/
class GLSLRegisterManager {
public:
GLSLRegisterManager(ShaderWriter& shader, ShaderWriter& declarations,
const Maxwell3D::Regs::ShaderStage& stage)
: shader{shader}, declarations{declarations}, stage{stage} {
BuildRegisterList();
}
/**
* Gets a register as an float.
* @param reg The register to get.
* @param elem The element to use for the operation.
* @returns GLSL string corresponding to the register as a float.
*/
std::string GetRegisterAsFloat(const Register& reg, unsigned elem = 0) {
ASSERT(regs[reg].IsFloat());
return GetRegister(reg, elem);
}
/**
* Gets a register as an integer.
* @param reg The register to get.
* @param elem The element to use for the operation.
* @param is_signed Whether to get the register as a signed (or unsigned) integer.
* @returns GLSL string corresponding to the register as an integer.
*/
std::string GetRegisterAsInteger(const Register& reg, unsigned elem = 0,
bool is_signed = true) {
const std::string func = GetGLSLConversionFunc(
GLSLRegister::Type::Float,
is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger);
return func + '(' + GetRegister(reg, elem) + ')';
}
/**
* Writes code that does a register assignment to float value operation.
* @param reg The destination register to use.
* @param elem The element to use for the operation.
* @param value The code representing the value to assign.
* @param dest_num_components Number of components in the destination.
* @param value_num_components Number of components in the value.
* @param is_abs Optional, when True, applies absolute value to output.
* @param dest_elem Optional, the destination element to use for the operation.
*/
void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value,
u64 dest_num_components, u64 value_num_components, bool is_abs = false,
u64 dest_elem = 0) {
SetRegister(reg, elem, value, dest_num_components, value_num_components, is_abs, dest_elem);
}
/**
* Writes code that does a register assignment to integer value operation.
* @param reg The destination register to use.
* @param elem The element to use for the operation.
* @param value The code representing the value to assign.
* @param dest_num_components Number of components in the destination.
* @param value_num_components Number of components in the value.
* @param is_abs Optional, when True, applies absolute value to output.
* @param dest_elem Optional, the destination element to use for the operation.
*/
void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem,
const std::string& value, u64 dest_num_components,
u64 value_num_components, bool is_abs = false, u64 dest_elem = 0) {
const std::string func = GetGLSLConversionFunc(
is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger,
GLSLRegister::Type::Float);
SetRegister(reg, elem, func + '(' + value + ')', dest_num_components, value_num_components,
is_abs, dest_elem);
}
/**
* Writes code that does a register assignment to input attribute operation. Input attributes
* are stored as floats, so this may require conversion.
* @param reg The destination register to use.
* @param elem The element to use for the operation.
* @param attribute The input attibute to use as the source value.
*/
void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute) {
std::string dest = GetRegisterAsFloat(reg);
std::string src = GetInputAttribute(attribute) + GetSwizzle(elem);
if (regs[reg].IsFloat()) {
shader.AddLine(dest + " = " + src + ';');
} else if (regs[reg].IsInteger()) {
shader.AddLine(dest + " = floatBitsToInt(" + src + ");");
} else {
UNREACHABLE();
}
}
/**
* Writes code that does a output attribute assignment to register operation. Output attributes
* are stored as floats, so this may require conversion.
* @param attribute The destination output attribute.
* @param elem The element to use for the operation.
* @param reg The register to use as the source value.
*/
void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) {
std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem);
std::string src = GetRegisterAsFloat(reg);
ASSERT_MSG(regs[reg].IsFloat(), "Output attributes must be set to a float");
shader.AddLine(dest + " = " + src + ';');
}
/// Generates code representing a uniform (C buffer) register.
std::string GetUniform(const Uniform& uniform, const Register& dest_reg) {
declr_const_buffers[uniform.index].MarkAsUsed(static_cast<unsigned>(uniform.index),
static_cast<unsigned>(uniform.offset), stage);
std::string value =
'c' + std::to_string(uniform.index) + '[' + std::to_string(uniform.offset) + ']';
if (regs[dest_reg].IsFloat()) {
return value;
} else if (regs[dest_reg].IsInteger()) {
return "floatBitsToInt(" + value + ')';
} else {
UNREACHABLE();
}
}
/// Add declarations for registers
void GenerateDeclarations() {
for (const auto& reg : regs) {
for (const auto& type : reg.DeclaredTypes()) {
declarations.AddLine(GLSLRegister::GetTypeString(type) + ' ' +
GLSLRegister::GetPrefixString(type) +
std::to_string(reg.GetIndex()) + " = 0;");
}
}
declarations.AddNewLine();
for (const auto& index : declr_input_attribute) {
// TODO(bunnei): Use proper number of elements for these
declarations.AddLine("layout(location = " +
std::to_string(static_cast<u32>(index) -
static_cast<u32>(Attribute::Index::Attribute_0)) +
") in vec4 " + GetInputAttribute(index) + ';');
}
declarations.AddNewLine();
for (const auto& index : declr_output_attribute) {
// TODO(bunnei): Use proper number of elements for these
declarations.AddLine("layout(location = " +
std::to_string(static_cast<u32>(index) -
static_cast<u32>(Attribute::Index::Attribute_0)) +
") out vec4 " + GetOutputAttribute(index) + ';');
}
declarations.AddNewLine();
unsigned const_buffer_layout = 0;
for (const auto& entry : GetConstBuffersDeclarations()) {
declarations.AddLine("layout(std430) buffer " + entry.GetName());
declarations.AddLine('{');
declarations.AddLine(" float c" + std::to_string(entry.GetIndex()) + "[];");
declarations.AddLine("};");
declarations.AddNewLine();
++const_buffer_layout;
}
declarations.AddNewLine();
}
/// Returns a list of constant buffer declarations
std::vector<ConstBufferEntry> GetConstBuffersDeclarations() const {
std::vector<ConstBufferEntry> result;
std::copy_if(declr_const_buffers.begin(), declr_const_buffers.end(),
std::back_inserter(result), [](const auto& entry) { return entry.IsUsed(); });
return result;
}
private:
/// Build GLSL conversion function, e.g. floatBitsToInt, intBitsToFloat, etc.
const std::string GetGLSLConversionFunc(GLSLRegister::Type src, GLSLRegister::Type dest) const {
const std::string src_type = GLSLRegister::GetTypeString(src);
std::string dest_type = GLSLRegister::GetTypeString(dest);
dest_type[0] = toupper(dest_type[0]);
return src_type + "BitsTo" + dest_type;
}
/// Generates code representing a temporary (GPR) register.
std::string GetRegister(const Register& reg, unsigned elem) {
if (reg == Register::ZeroIndex) {
return "0";
}
return regs[reg.GetSwizzledIndex(elem)].GetActiveString();
}
/**
* Writes code that does a register assignment to value operation.
* @param reg The destination register to use.
* @param elem The element to use for the operation.
* @param value The code representing the value to assign.
* @param dest_num_components Number of components in the destination.
* @param value_num_components Number of components in the value.
* @param is_abs Optional, when True, applies absolute value to output.
* @param dest_elem Optional, the destination element to use for the operation.
*/
void SetRegister(const Register& reg, u64 elem, const std::string& value,
u64 dest_num_components, u64 value_num_components, bool is_abs,
u64 dest_elem) {
std::string dest = GetRegister(reg, dest_elem);
if (dest_num_components > 1) {
dest += GetSwizzle(elem);
}
std::string src = '(' + value + ')';
if (value_num_components > 1) {
src += GetSwizzle(elem);
}
src = is_abs ? "abs(" + src + ')' : src;
shader.AddLine(dest + " = " + src + ';');
}
/// Build the GLSL register list.
void BuildRegisterList() {
for (size_t index = 0; index < Register::NumRegisters; ++index) {
regs.emplace_back(index, shader);
}
}
/// Generates code representing an input attribute register.
@@ -209,6 +482,50 @@ private:
}
}
/// Generates code to use for a swizzle operation.
static std::string GetSwizzle(u64 elem) {
ASSERT(elem <= 3);
std::string swizzle = ".";
swizzle += "xyzw"[elem];
return swizzle;
}
ShaderWriter& shader;
ShaderWriter& declarations;
std::vector<GLSLRegister> regs;
std::set<Attribute::Index> declr_input_attribute;
std::set<Attribute::Index> declr_output_attribute;
std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers;
const Maxwell3D::Regs::ShaderStage& stage;
};
class GLSLGenerator {
public:
GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
u32 main_offset, Maxwell3D::Regs::ShaderStage stage)
: subroutines(subroutines), program_code(program_code), main_offset(main_offset),
stage(stage) {
Generate();
}
std::string GetShaderCode() {
return declarations.GetResult() + shader.GetResult();
}
/// Returns entries in the shader that are useful for external functions
ShaderEntries GetEntries() const {
return {regs.GetConstBuffersDeclarations()};
}
private:
/// Gets the Subroutine object corresponding to the specified address.
const Subroutine& GetSubroutine(u32 begin, u32 end) const {
auto iter = subroutines.find(Subroutine{begin, end});
ASSERT(iter != subroutines.end());
return *iter;
}
/// Generates code representing a 19-bit immediate value
static std::string GetImmediate19(const Instruction& instr) {
return std::to_string(instr.alu.GetImm20_19());
@@ -219,32 +536,13 @@ private:
return std::to_string(instr.alu.GetImm20_32());
}
/// Generates code representing a temporary (GPR) register.
std::string GetRegister(const Register& reg, unsigned elem = 0) {
if (reg == Register::ZeroIndex)
return "0";
if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) {
// GPRs 0-3 are output color for the fragment shader
return std::string{"color."} + "rgba"[(reg + elem) & 3];
}
return *declr_register.insert("register_" + std::to_string(reg + elem)).first;
}
/// Generates code representing a uniform (C buffer) register.
std::string GetUniform(const Uniform& reg) {
declr_const_buffers[reg.index].MarkAsUsed(static_cast<unsigned>(reg.index),
static_cast<unsigned>(reg.offset), stage);
return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']';
}
/// Generates code representing a texture sampler.
std::string GetSampler(const Sampler& sampler) const {
// TODO(Subv): Support more than just texture sampler 0
ASSERT_MSG(sampler.index == Sampler::Index::Sampler_0, "unsupported");
const unsigned index{static_cast<unsigned>(sampler.index.Value()) -
static_cast<unsigned>(Sampler::Index::Sampler_0)};
return "tex[" + std::to_string(index) + "]";
return "tex[" + std::to_string(index) + ']';
}
/**
@@ -262,23 +560,6 @@ private:
}
}
/**
* Writes code that does an assignment operation.
* @param reg the destination register code.
* @param value the code representing the value to assign.
*/
void SetDest(u64 elem, const std::string& reg, const std::string& value,
u64 dest_num_components, u64 value_num_components, bool is_abs = false) {
std::string swizzle = ".";
swizzle += "xyzw"[elem];
std::string dest = reg + (dest_num_components != 1 ? swizzle : "");
std::string src = "(" + value + ")" + (value_num_components != 1 ? swizzle : "");
src = is_abs ? "abs(" + src + ")" : src;
shader.AddLine(dest + " = " + src + ";");
}
/*
* Writes code that assigns a predicate boolean variable.
* @param pred The id of the predicate to write to.
@@ -360,11 +641,10 @@ private:
switch (opcode->GetType()) {
case OpCode::Type::Arithmetic: {
std::string dest = GetRegister(instr.gpr0);
std::string op_a = instr.alu.negate_a ? "-" : "";
op_a += GetRegister(instr.gpr8);
op_a += regs.GetRegisterAsFloat(instr.gpr8);
if (instr.alu.abs_a) {
op_a = "abs(" + op_a + ")";
op_a = "abs(" + op_a + ')';
}
std::string op_b = instr.alu.negate_b ? "-" : "";
@@ -373,56 +653,75 @@ private:
op_b += GetImmediate19(instr);
} else {
if (instr.is_b_gpr) {
op_b += GetRegister(instr.gpr20);
op_b += regs.GetRegisterAsFloat(instr.gpr20);
} else {
op_b += GetUniform(instr.uniform);
op_b += regs.GetUniform(instr.uniform, instr.gpr0);
}
}
if (instr.alu.abs_b) {
op_b = "abs(" + op_b + ")";
op_b = "abs(" + op_b + ')';
}
switch (opcode->GetId()) {
case OpCode::Id::MOV_C:
case OpCode::Id::MOV_R: {
regs.SetRegisterToFloat(instr.gpr0, 0, op_b, 1, 1);
break;
}
case OpCode::Id::MOV32_IMM: {
// mov32i doesn't have abs or neg bits.
regs.SetRegisterToFloat(instr.gpr0, 0, GetImmediate32(instr), 1, 1);
break;
}
case OpCode::Id::FMUL_C:
case OpCode::Id::FMUL_R:
case OpCode::Id::FMUL_IMM: {
SetDest(0, dest, op_a + " * " + op_b, 1, 1, instr.alu.abs_d);
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, instr.alu.abs_d);
break;
}
case OpCode::Id::FMUL32_IMM: {
// fmul32i doesn't have abs or neg bits.
SetDest(0, dest, GetRegister(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1);
regs.SetRegisterToFloat(
instr.gpr0, 0,
regs.GetRegisterAsFloat(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1);
break;
}
case OpCode::Id::FADD_C:
case OpCode::Id::FADD_R:
case OpCode::Id::FADD_IMM: {
SetDest(0, dest, op_a + " + " + op_b, 1, 1, instr.alu.abs_d);
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, instr.alu.abs_d);
break;
}
case OpCode::Id::MUFU: {
switch (instr.sub_op) {
case SubOp::Cos:
SetDest(0, dest, "cos(" + op_a + ")", 1, 1, instr.alu.abs_d);
regs.SetRegisterToFloat(instr.gpr0, 0, "cos(" + op_a + ')', 1, 1,
instr.alu.abs_d);
break;
case SubOp::Sin:
SetDest(0, dest, "sin(" + op_a + ")", 1, 1, instr.alu.abs_d);
regs.SetRegisterToFloat(instr.gpr0, 0, "sin(" + op_a + ')', 1, 1,
instr.alu.abs_d);
break;
case SubOp::Ex2:
SetDest(0, dest, "exp2(" + op_a + ")", 1, 1, instr.alu.abs_d);
regs.SetRegisterToFloat(instr.gpr0, 0, "exp2(" + op_a + ')', 1, 1,
instr.alu.abs_d);
break;
case SubOp::Lg2:
SetDest(0, dest, "log2(" + op_a + ")", 1, 1, instr.alu.abs_d);
regs.SetRegisterToFloat(instr.gpr0, 0, "log2(" + op_a + ')', 1, 1,
instr.alu.abs_d);
break;
case SubOp::Rcp:
SetDest(0, dest, "1.0 / " + op_a, 1, 1, instr.alu.abs_d);
regs.SetRegisterToFloat(instr.gpr0, 0, "1.0 / " + op_a, 1, 1, instr.alu.abs_d);
break;
case SubOp::Rsq:
SetDest(0, dest, "inversesqrt(" + op_a + ")", 1, 1, instr.alu.abs_d);
regs.SetRegisterToFloat(instr.gpr0, 0, "inversesqrt(" + op_a + ')', 1, 1,
instr.alu.abs_d);
break;
case SubOp::Min:
SetDest(0, dest, "min(" + op_a + "," + op_b + ")", 1, 1, instr.alu.abs_d);
regs.SetRegisterToFloat(instr.gpr0, 0, "min(" + op_a + "," + op_b + ')', 1, 1,
instr.alu.abs_d);
break;
default:
NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {0:x}",
@@ -443,30 +742,29 @@ private:
break;
}
case OpCode::Type::Ffma: {
std::string dest = GetRegister(instr.gpr0);
std::string op_a = GetRegister(instr.gpr8);
std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
std::string op_b = instr.ffma.negate_b ? "-" : "";
std::string op_c = instr.ffma.negate_c ? "-" : "";
switch (opcode->GetId()) {
case OpCode::Id::FFMA_CR: {
op_b += GetUniform(instr.uniform);
op_c += GetRegister(instr.gpr39);
op_b += regs.GetUniform(instr.uniform, instr.gpr0);
op_c += regs.GetRegisterAsFloat(instr.gpr39);
break;
}
case OpCode::Id::FFMA_RR: {
op_b += GetRegister(instr.gpr20);
op_c += GetRegister(instr.gpr39);
op_b += regs.GetRegisterAsFloat(instr.gpr20);
op_c += regs.GetRegisterAsFloat(instr.gpr39);
break;
}
case OpCode::Id::FFMA_RC: {
op_b += GetRegister(instr.gpr39);
op_c += GetUniform(instr.uniform);
op_b += regs.GetRegisterAsFloat(instr.gpr39);
op_c += regs.GetUniform(instr.uniform, instr.gpr0);
break;
}
case OpCode::Id::FFMA_IMM: {
op_b += GetImmediate19(instr);
op_c += GetRegister(instr.gpr39);
op_c += regs.GetRegisterAsFloat(instr.gpr39);
break;
}
default: {
@@ -475,28 +773,55 @@ private:
}
}
SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1);
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1);
break;
}
case OpCode::Type::Conversion: {
ASSERT_MSG(instr.conversion.size == Register::Size::Word, "Unimplemented");
ASSERT_MSG(!instr.conversion.selector, "Unimplemented");
ASSERT_MSG(!instr.conversion.negate_a, "Unimplemented");
ASSERT_MSG(!instr.conversion.saturate_a, "Unimplemented");
switch (opcode->GetId()) {
case OpCode::Id::I2I_R:
case OpCode::Id::I2F_R: {
std::string op_a =
regs.GetRegisterAsInteger(instr.gpr20, 0, instr.conversion.is_signed);
if (instr.conversion.abs_a) {
op_a = "abs(" + op_a + ')';
}
regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_signed, 0, op_a, 1, 1);
break;
}
default: {
NGLOG_CRITICAL(HW_GPU, "Unhandled conversion instruction: {}", opcode->GetName());
UNREACHABLE();
}
}
break;
}
case OpCode::Type::Memory: {
std::string gpr0 = GetRegister(instr.gpr0);
const Attribute::Index attribute = instr.attribute.fmt20.index;
switch (opcode->GetId()) {
case OpCode::Id::LD_A: {
ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4);
regs.SetRegisterToInputAttibute(instr.gpr0, instr.attribute.fmt20.element,
attribute);
break;
}
case OpCode::Id::ST_A: {
ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
SetDest(instr.attribute.fmt20.element, GetOutputAttribute(attribute), gpr0, 4, 1);
regs.SetOutputAttributeToRegister(attribute, instr.attribute.fmt20.element,
instr.gpr0);
break;
}
case OpCode::Id::TEXS: {
ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
const std::string op_a = GetRegister(instr.gpr8);
const std::string op_b = GetRegister(instr.gpr20);
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
const std::string sampler = GetSampler(instr.sampler);
const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
// Add an extra scope and declare the texture coords inside to prevent overwriting
@@ -506,7 +831,7 @@ private:
shader.AddLine(coord);
const std::string texture = "texture(" + sampler + ", coords)";
for (unsigned elem = 0; elem < instr.attribute.fmt20.size; ++elem) {
SetDest(elem, GetRegister(instr.gpr0, elem), texture, 1, 4);
regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, elem);
}
--shader.scope;
shader.AddLine("}");
@@ -521,7 +846,7 @@ private:
}
case OpCode::Type::FloatSetPredicate: {
std::string op_a = instr.fsetp.neg_a ? "-" : "";
op_a += GetRegister(instr.gpr8);
op_a += regs.GetRegisterAsFloat(instr.gpr8);
if (instr.fsetp.abs_a) {
op_a = "abs(" + op_a + ')';
@@ -537,9 +862,9 @@ private:
op_b += '(' + GetImmediate19(instr) + ')';
} else {
if (instr.is_b_gpr) {
op_b += GetRegister(instr.gpr20);
op_b += regs.GetRegisterAsFloat(instr.gpr20);
} else {
op_b += GetUniform(instr.uniform);
op_b += regs.GetUniform(instr.uniform, instr.gpr0);
}
}
@@ -563,6 +888,9 @@ private:
case PredCondition::Equal:
SetPredicate(instr.fsetp.pred3, '(' + op_a + ") == (" + op_b + ')');
break;
case PredCondition::LessEqual:
SetPredicate(instr.fsetp.pred3, '(' + op_a + ") <= (" + op_b + ')');
break;
default:
NGLOG_CRITICAL(HW_GPU, "Unhandled predicate condition: {} (a: {}, b: {})",
static_cast<unsigned>(instr.fsetp.cond.Value()), op_a, op_b);
@@ -571,9 +899,8 @@ private:
break;
}
case OpCode::Type::FloatSet: {
std::string dest = GetRegister(instr.gpr0);
std::string op_a = instr.fset.neg_a ? "-" : "";
op_a += GetRegister(instr.gpr8);
op_a += regs.GetRegisterAsFloat(instr.gpr8);
if (instr.fset.abs_a) {
op_a = "abs(" + op_a + ')';
@@ -589,14 +916,14 @@ private:
op_b += imm;
} else {
if (instr.is_b_gpr) {
op_b += GetRegister(instr.gpr20);
op_b += regs.GetRegisterAsFloat(instr.gpr20);
} else {
op_b += GetUniform(instr.uniform);
op_b += regs.GetUniform(instr.uniform, instr.gpr0);
}
}
if (instr.fset.abs_b) {
op_b = "abs(" + op_b + ")";
op_b = "abs(" + op_b + ')';
}
using Tegra::Shader::Pred;
@@ -608,13 +935,20 @@ private:
using Tegra::Shader::PredCondition;
switch (instr.fset.cond) {
case PredCondition::LessThan:
SetDest(0, dest, "((" + op_a + ") < (" + op_b + ")) ? 1.0 : 0", 1, 1);
regs.SetRegisterToFloat(instr.gpr0, 0,
"((" + op_a + ") < (" + op_b + ")) ? 1.0 : 0", 1, 1);
break;
case PredCondition::Equal:
SetDest(0, dest, "((" + op_a + ") == (" + op_b + ")) ? 1.0 : 0", 1, 1);
regs.SetRegisterToFloat(instr.gpr0, 0,
"((" + op_a + ") == (" + op_b + ")) ? 1.0 : 0", 1, 1);
break;
case PredCondition::LessEqual:
regs.SetRegisterToFloat(instr.gpr0, 0,
"((" + op_a + ") <= (" + op_b + ")) ? 1.0 : 0", 1, 1);
break;
case PredCondition::GreaterThan:
SetDest(0, dest, "((" + op_a + ") > (" + op_b + ")) ? 1.0 : 0", 1, 1);
regs.SetRegisterToFloat(instr.gpr0, 0,
"((" + op_a + ") > (" + op_b + ")) ? 1.0 : 0", 1, 1);
break;
default:
NGLOG_CRITICAL(HW_GPU, "Unhandled predicate condition: {} (a: {}, b: {})",
@@ -628,6 +962,15 @@ private:
case OpCode::Id::EXIT: {
ASSERT_MSG(instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex),
"Predicated exits not implemented");
// 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) + ';');
}
shader.AddLine("return true;");
offset = PROGRAM_END - 1;
break;
@@ -638,8 +981,7 @@ private:
}
case OpCode::Id::IPA: {
const auto& attribute = instr.attribute.fmt28;
std::string dest = GetRegister(instr.gpr0);
SetDest(attribute.element, dest, GetInputAttribute(attribute.index), 1, 4);
regs.SetRegisterToInputAttibute(instr.gpr0, attribute.element, attribute.index);
break;
}
default: {
@@ -745,50 +1087,10 @@ private:
GenerateDeclarations();
}
/// Returns a list of constant buffer declarations
std::vector<ConstBufferEntry> GetConstBuffersDeclarations() const {
std::vector<ConstBufferEntry> result;
std::copy_if(declr_const_buffers.begin(), declr_const_buffers.end(),
std::back_inserter(result), [](const auto& entry) { return entry.IsUsed(); });
return result;
}
/// Add declarations for registers
void GenerateDeclarations() {
for (const auto& reg : declr_register) {
declarations.AddLine("float " + reg + " = 0.0;");
}
declarations.AddNewLine();
regs.GenerateDeclarations();
for (const auto& index : declr_input_attribute) {
// TODO(bunnei): Use proper number of elements for these
declarations.AddLine("layout(location = " +
std::to_string(static_cast<u32>(index) -
static_cast<u32>(Attribute::Index::Attribute_0)) +
") in vec4 " + GetInputAttribute(index) + ";");
}
declarations.AddNewLine();
for (const auto& index : declr_output_attribute) {
// TODO(bunnei): Use proper number of elements for these
declarations.AddLine("layout(location = " +
std::to_string(static_cast<u32>(index) -
static_cast<u32>(Attribute::Index::Attribute_0)) +
") out vec4 " + GetOutputAttribute(index) + ";");
}
declarations.AddNewLine();
unsigned const_buffer_layout = 0;
for (const auto& entry : GetConstBuffersDeclarations()) {
declarations.AddLine("layout(std430) buffer " + entry.GetName());
declarations.AddLine('{');
declarations.AddLine(" float c" + std::to_string(entry.GetIndex()) + "[];");
declarations.AddLine("};");
declarations.AddNewLine();
++const_buffer_layout;
}
declarations.AddNewLine();
for (const auto& pred : declr_predicates) {
declarations.AddLine("bool " + pred + " = false;");
}
@@ -803,13 +1105,10 @@ private:
ShaderWriter shader;
ShaderWriter declarations;
GLSLRegisterManager regs{shader, declarations, stage};
// Declarations
std::set<std::string> declr_register;
std::set<std::string> declr_predicates;
std::set<Attribute::Index> declr_input_attribute;
std::set<Attribute::Index> declr_output_attribute;
std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers;
}; // namespace Decompiler
std::string GetCommonDeclarations() {

View File

@@ -17,7 +17,7 @@ void SetShaderUniformBlockBinding(GLuint shader, const char* name,
GLint ub_size = 0;
glGetActiveUniformBlockiv(shader, ub_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ub_size);
ASSERT_MSG(ub_size == expected_size,
"Uniform block size did not match! Got %d, expected %zu",
"Uniform block size did not match! Got {}, expected {}",
static_cast<int>(ub_size), expected_size);
glUniformBlockBinding(shader, ub_index, static_cast<GLuint>(binding));
}

View File

@@ -36,6 +36,18 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
return {};
}
case Maxwell::VertexAttribute::Type::SignedNorm: {
switch (attrib.size) {
case Maxwell::VertexAttribute::Size::Size_8_8_8_8:
return GL_BYTE;
}
NGLOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
UNREACHABLE();
return {};
}
case Maxwell::VertexAttribute::Type::Float:
return GL_FLOAT;
}

View File

@@ -398,21 +398,22 @@ static const char* GetType(GLenum type) {
static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity,
GLsizei length, const GLchar* message, const void* user_param) {
Log::Level level;
const char format[] = "{} {} {}: {}";
const char* const str_source = GetSource(source);
const char* const str_type = GetType(type);
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH:
level = Log::Level::Error;
NGLOG_ERROR(Render_OpenGL, format, str_source, str_type, id, message);
break;
case GL_DEBUG_SEVERITY_MEDIUM:
level = Log::Level::Warning;
NGLOG_WARNING(Render_OpenGL, format, str_source, str_type, id, message);
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
case GL_DEBUG_SEVERITY_LOW:
level = Log::Level::Debug;
NGLOG_DEBUG(Render_OpenGL, format, str_source, str_type, id, message);
break;
}
LOG_GENERIC(Log::Class::Render_OpenGL, level, "%s %s %d: %s", GetSource(source), GetType(type),
id, message);
}
/// Initialize the renderer

View File

@@ -4,6 +4,8 @@
#include <QScreen>
#include <QWindow>
#include <fmt/format.h>
#include "common/microprofile.h"
#include "common/scm_rev.h"
#include "common/string_util.h"
@@ -102,8 +104,8 @@ private:
GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread)
: QWidget(parent), child(nullptr), emu_thread(emu_thread) {
std::string window_title = Common::StringFromFormat("yuzu %s| %s-%s", Common::g_build_name,
Common::g_scm_branch, Common::g_scm_desc);
std::string window_title = fmt::format("yuzu {} | {}-{}", Common::g_build_name,
Common::g_scm_branch, Common::g_scm_desc);
setWindowTitle(QString::fromStdString(window_title));
InputCommon::Init();

View File

@@ -315,7 +315,8 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) {
if (!FileUtil::Exists(dir_path.toStdString()) ||
!FileUtil::IsDirectory(dir_path.toStdString())) {
LOG_ERROR(Frontend, "Could not find game list folder at %s", dir_path.toLocal8Bit().data());
NGLOG_ERROR(Frontend, "Could not find game list folder at {}",
dir_path.toLocal8Bit().data());
search_field->setFilterResult(0, 0);
return;
}
@@ -364,7 +365,7 @@ static bool HasSupportedFileExtension(const std::string& file_name) {
void GameList::RefreshGameDirectory() {
if (!UISettings::values.gamedir.isEmpty() && current_worker != nullptr) {
LOG_INFO(Frontend, "Change detected in the games directory. Reloading game list.");
NGLOG_INFO(Frontend, "Change detected in the games directory. Reloading game list.");
search_field->clear();
PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan);
}

View File

@@ -359,19 +359,17 @@ bool GMainWindow::LoadROM(const QString& filename) {
if (result != Core::System::ResultStatus::Success) {
switch (result) {
case Core::System::ResultStatus::ErrorGetLoader:
LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!",
filename.toStdString().c_str());
NGLOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filename.toStdString());
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().c_str());
NGLOG_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!");
NGLOG_CRITICAL(Frontend, "Failed to load ROM!");
QMessageBox::critical(this, tr("Error while loading ROM!"),
tr("Could not determine the system mode."));
break;
@@ -859,7 +857,7 @@ void GMainWindow::UpdateUITheme() {
QString theme_uri(":" + UISettings::values.theme + "/style.qss");
QFile f(theme_uri);
if (!f.exists()) {
LOG_ERROR(Frontend, "Unable to set style, stylesheet file not found");
NGLOG_ERROR(Frontend, "Unable to set style, stylesheet file not found");
} else {
f.open(QFile::ReadOnly | QFile::Text);
QTextStream ts(&f);

View File

@@ -27,17 +27,17 @@ bool Config::LoadINI(const std::string& default_contents, bool retry) {
const char* location = this->sdl2_config_loc.c_str();
if (sdl2_config->ParseError() < 0) {
if (retry) {
LOG_WARNING(Config, "Failed to load %s. Creating file from defaults...", location);
NGLOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", location);
FileUtil::CreateFullPath(location);
FileUtil::WriteStringToFile(true, default_contents, location);
sdl2_config = std::make_unique<INIReader>(location); // Reopen file
return LoadINI(default_contents, false);
}
LOG_ERROR(Config, "Failed.");
NGLOG_ERROR(Config, "Failed.");
return false;
}
LOG_INFO(Config, "Successfully loaded %s", location);
NGLOG_INFO(Config, "Successfully loaded {}", location);
return true;
}

Some files were not shown because too many files have changed in this diff Show More