Compare commits
97 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
973fdce79b | ||
|
|
1c7c1347d8 | ||
|
|
ff8754f921 | ||
|
|
89cc8c1617 | ||
|
|
552aac7e6c | ||
|
|
fe2498a650 | ||
|
|
3d938b8c60 | ||
|
|
d85cfc94e2 | ||
|
|
459e158340 | ||
|
|
3e0727df1b | ||
|
|
894b0de0f2 | ||
|
|
dd09439fee | ||
|
|
05231d8b08 | ||
|
|
966874e357 | ||
|
|
d84eb9dac6 | ||
|
|
8afc21f175 | ||
|
|
d4104c72aa | ||
|
|
d5bc9aef4e | ||
|
|
863579736c | ||
|
|
2b7d862366 | ||
|
|
3acd6fa086 | ||
|
|
48733744bb | ||
|
|
a8bb1eb39f | ||
|
|
a44475207c | ||
|
|
3268321f4b | ||
|
|
6279c2dcf4 | ||
|
|
474ec2ee5f | ||
|
|
f63ccbd936 | ||
|
|
7a1a860abe | ||
|
|
457d1b4490 | ||
|
|
dffd154d6d | ||
|
|
0a0b3c4b9f | ||
|
|
c1c9ab31e8 | ||
|
|
8346541901 | ||
|
|
29f49bd3c1 | ||
|
|
ffbd51e207 | ||
|
|
701c7cb85c | ||
|
|
fbc2bcd4a9 | ||
|
|
741cae1e1d | ||
|
|
a1805ceb0b | ||
|
|
86d1649b32 | ||
|
|
204d707ce7 | ||
|
|
9c7321fe6d | ||
|
|
6a9cd17227 | ||
|
|
0faa13baeb | ||
|
|
e6b3d3a9ea | ||
|
|
8874d0e657 | ||
|
|
0e9d58e82a | ||
|
|
f36affdbe3 | ||
|
|
ce66a188d0 | ||
|
|
40c9c5a55c | ||
|
|
c20cea118b | ||
|
|
8b08f82dc7 | ||
|
|
dbfe82773d | ||
|
|
bbd6429ecb | ||
|
|
364b950515 | ||
|
|
a25c5b982a | ||
|
|
f26866ff6a | ||
|
|
c2121cb059 | ||
|
|
1bdb67440b | ||
|
|
d3cfaf95c8 | ||
|
|
0b13ce1435 | ||
|
|
af08034c71 | ||
|
|
2aeb3355e4 | ||
|
|
c6352ffc58 | ||
|
|
ec468c990d | ||
|
|
f43d8ea523 | ||
|
|
2194308245 | ||
|
|
b5c77313de | ||
|
|
dd0446ff43 | ||
|
|
31413f0d2f | ||
|
|
05549e45c5 | ||
|
|
50e2777724 | ||
|
|
b102815f1f | ||
|
|
7244671137 | ||
|
|
ff500a7b68 | ||
|
|
eb9b55eafe | ||
|
|
78dd1cd441 | ||
|
|
df001e83b1 | ||
|
|
b879fb84a2 | ||
|
|
68c1ffdd1c | ||
|
|
7eace8f512 | ||
|
|
38b35e752b | ||
|
|
c945226973 | ||
|
|
e5c916a27c | ||
|
|
50d08beed2 | ||
|
|
9b22f856c2 | ||
|
|
c061c2bf3c | ||
|
|
f3daecafeb | ||
|
|
dc35c3f9d7 | ||
|
|
af2698dcea | ||
|
|
6c1ba02e0c | ||
|
|
3e9b79e088 | ||
|
|
f317080f40 | ||
|
|
910ad2e110 | ||
|
|
6be342118a | ||
|
|
d6e9b96e2f |
16
externals/glad/include/KHR/khrplatform.h
vendored
16
externals/glad/include/KHR/khrplatform.h
vendored
@@ -2,7 +2,7 @@
|
||||
#define __khrplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright (c) 2008-2009 The Khronos Group Inc.
|
||||
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
@@ -26,18 +26,16 @@
|
||||
|
||||
/* Khronos platform-specific types and definitions.
|
||||
*
|
||||
* $Revision: 32517 $ on $Date: 2016-03-11 02:41:19 -0800 (Fri, 11 Mar 2016) $
|
||||
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||
* The last semantic modification to khrplatform.h was at commit ID:
|
||||
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||
*
|
||||
* Adopters may modify this file to suit their platform. Adopters are
|
||||
* encouraged to submit platform specific modifications to the Khronos
|
||||
* group so that they can be included in future versions of this file.
|
||||
* Please submit changes by sending them to the public Khronos Bugzilla
|
||||
* (http://khronos.org/bugzilla) by filing a bug against product
|
||||
* "Khronos (general)" component "Registry".
|
||||
*
|
||||
* A predefined template which fills in some of the bug fields can be
|
||||
* reached using http://tinyurl.com/khrplatform-h-bugreport, but you
|
||||
* must create a Bugzilla login first.
|
||||
* Please submit changes by filing pull requests or issues on
|
||||
* the EGL Registry repository linked above.
|
||||
*
|
||||
*
|
||||
* See the Implementer's Guidelines for information about where this file
|
||||
|
||||
56
externals/glad/include/glad/glad.h
vendored
56
externals/glad/include/glad/glad.h
vendored
File diff suppressed because one or more lines are too long
1962
externals/glad/src/glad.c
vendored
1962
externals/glad/src/glad.c
vendored
File diff suppressed because one or more lines are too long
@@ -63,7 +63,6 @@ add_library(common STATIC
|
||||
string_util.cpp
|
||||
string_util.h
|
||||
swap.h
|
||||
synchronized_wrapper.h
|
||||
telemetry.cpp
|
||||
telemetry.h
|
||||
thread.cpp
|
||||
|
||||
@@ -3,19 +3,20 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <climits>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#ifdef _WIN32
|
||||
#include <share.h> // For _SH_DENYWR
|
||||
#else
|
||||
#define _SH_DENYWR 0
|
||||
#endif
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h" // snprintf compatibility define
|
||||
#include "common/logging/backend.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/logging/text_formatter.h"
|
||||
@@ -48,11 +49,11 @@ public:
|
||||
backends.push_back(std::move(backend));
|
||||
}
|
||||
|
||||
void RemoveBackend(const std::string& backend_name) {
|
||||
void RemoveBackend(std::string_view backend_name) {
|
||||
std::lock_guard<std::mutex> lock(writing_mutex);
|
||||
auto it = std::remove_if(backends.begin(), backends.end(), [&backend_name](const auto& i) {
|
||||
return !strcmp(i->GetName(), backend_name.c_str());
|
||||
});
|
||||
const auto it =
|
||||
std::remove_if(backends.begin(), backends.end(),
|
||||
[&backend_name](const auto& i) { return backend_name == i->GetName(); });
|
||||
backends.erase(it, backends.end());
|
||||
}
|
||||
|
||||
@@ -64,10 +65,10 @@ public:
|
||||
filter = f;
|
||||
}
|
||||
|
||||
Backend* GetBackend(const std::string& backend_name) {
|
||||
auto it = std::find_if(backends.begin(), backends.end(), [&backend_name](const auto& i) {
|
||||
return !strcmp(i->GetName(), backend_name.c_str());
|
||||
});
|
||||
Backend* GetBackend(std::string_view backend_name) {
|
||||
const auto it =
|
||||
std::find_if(backends.begin(), backends.end(),
|
||||
[&backend_name](const auto& i) { return backend_name == i->GetName(); });
|
||||
if (it == backends.end())
|
||||
return nullptr;
|
||||
return it->get();
|
||||
@@ -265,11 +266,11 @@ void AddBackend(std::unique_ptr<Backend> backend) {
|
||||
Impl::Instance().AddBackend(std::move(backend));
|
||||
}
|
||||
|
||||
void RemoveBackend(const std::string& backend_name) {
|
||||
void RemoveBackend(std::string_view backend_name) {
|
||||
Impl::Instance().RemoveBackend(backend_name);
|
||||
}
|
||||
|
||||
Backend* GetBackend(const std::string& backend_name) {
|
||||
Backend* GetBackend(std::string_view backend_name) {
|
||||
return Impl::Instance().GetBackend(backend_name);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdarg>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <string_view>
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/filter.h"
|
||||
#include "common/logging/log.h"
|
||||
@@ -106,9 +105,9 @@ private:
|
||||
|
||||
void AddBackend(std::unique_ptr<Backend> backend);
|
||||
|
||||
void RemoveBackend(const std::string& backend_name);
|
||||
void RemoveBackend(std::string_view backend_name);
|
||||
|
||||
Backend* GetBackend(const std::string& backend_name);
|
||||
Backend* GetBackend(std::string_view backend_name);
|
||||
|
||||
/**
|
||||
* Returns the name of the passed log class as a C-string. Subclasses are separated by periods
|
||||
|
||||
@@ -8,39 +8,9 @@
|
||||
#include "common/string_util.h"
|
||||
|
||||
namespace Log {
|
||||
|
||||
Filter::Filter(Level default_level) {
|
||||
ResetAll(default_level);
|
||||
}
|
||||
|
||||
void Filter::ResetAll(Level level) {
|
||||
class_levels.fill(level);
|
||||
}
|
||||
|
||||
void Filter::SetClassLevel(Class log_class, Level level) {
|
||||
class_levels[static_cast<size_t>(log_class)] = level;
|
||||
}
|
||||
|
||||
void Filter::ParseFilterString(const std::string& filter_str) {
|
||||
auto clause_begin = filter_str.cbegin();
|
||||
while (clause_begin != filter_str.cend()) {
|
||||
auto clause_end = std::find(clause_begin, filter_str.cend(), ' ');
|
||||
|
||||
// If clause isn't empty
|
||||
if (clause_end != clause_begin) {
|
||||
ParseFilterRule(clause_begin, clause_end);
|
||||
}
|
||||
|
||||
if (clause_end != filter_str.cend()) {
|
||||
// Skip over the whitespace
|
||||
++clause_end;
|
||||
}
|
||||
clause_begin = clause_end;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename It>
|
||||
static Level GetLevelByName(const It begin, const It end) {
|
||||
Level GetLevelByName(const It begin, const It end) {
|
||||
for (u8 i = 0; i < static_cast<u8>(Level::Count); ++i) {
|
||||
const char* level_name = GetLevelName(static_cast<Level>(i));
|
||||
if (Common::ComparePartialString(begin, end, level_name)) {
|
||||
@@ -51,7 +21,7 @@ static Level GetLevelByName(const It begin, const It end) {
|
||||
}
|
||||
|
||||
template <typename It>
|
||||
static Class GetClassByName(const It begin, const It end) {
|
||||
Class GetClassByName(const It begin, const It end) {
|
||||
for (ClassType i = 0; i < static_cast<ClassType>(Class::Count); ++i) {
|
||||
const char* level_name = GetLogClassName(static_cast<Class>(i));
|
||||
if (Common::ComparePartialString(begin, end, level_name)) {
|
||||
@@ -61,8 +31,8 @@ static Class GetClassByName(const It begin, const It end) {
|
||||
return Class::Count;
|
||||
}
|
||||
|
||||
bool Filter::ParseFilterRule(const std::string::const_iterator begin,
|
||||
const std::string::const_iterator end) {
|
||||
template <typename Iterator>
|
||||
bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
||||
auto level_separator = std::find(begin, end, ':');
|
||||
if (level_separator == end) {
|
||||
LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: {}",
|
||||
@@ -77,7 +47,7 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
|
||||
}
|
||||
|
||||
if (Common::ComparePartialString(begin, level_separator, "*")) {
|
||||
ResetAll(level);
|
||||
instance.ResetAll(level);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -87,9 +57,40 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
|
||||
return false;
|
||||
}
|
||||
|
||||
SetClassLevel(log_class, level);
|
||||
instance.SetClassLevel(log_class, level);
|
||||
return true;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
Filter::Filter(Level default_level) {
|
||||
ResetAll(default_level);
|
||||
}
|
||||
|
||||
void Filter::ResetAll(Level level) {
|
||||
class_levels.fill(level);
|
||||
}
|
||||
|
||||
void Filter::SetClassLevel(Class log_class, Level level) {
|
||||
class_levels[static_cast<size_t>(log_class)] = level;
|
||||
}
|
||||
|
||||
void Filter::ParseFilterString(std::string_view filter_view) {
|
||||
auto clause_begin = filter_view.cbegin();
|
||||
while (clause_begin != filter_view.cend()) {
|
||||
auto clause_end = std::find(clause_begin, filter_view.cend(), ' ');
|
||||
|
||||
// If clause isn't empty
|
||||
if (clause_end != clause_begin) {
|
||||
ParseFilterRule(*this, clause_begin, clause_end);
|
||||
}
|
||||
|
||||
if (clause_end != filter_view.cend()) {
|
||||
// Skip over the whitespace
|
||||
++clause_end;
|
||||
}
|
||||
clause_begin = clause_end;
|
||||
}
|
||||
}
|
||||
|
||||
bool Filter::CheckMessage(Class log_class, Level level) const {
|
||||
return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include "common/logging/log.h"
|
||||
|
||||
namespace Log {
|
||||
@@ -40,9 +40,7 @@ public:
|
||||
* - `Service:Info` -- Sets the level of Service to Info.
|
||||
* - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace.
|
||||
*/
|
||||
void ParseFilterString(const std::string& filter_str);
|
||||
bool ParseFilterRule(const std::string::const_iterator start,
|
||||
const std::string::const_iterator end);
|
||||
void ParseFilterString(std::string_view filter_view);
|
||||
|
||||
/// Matches class/level combination against the filter, returning true if it passed.
|
||||
bool CheckMessage(Class log_class, Level level) const;
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/param_package.h"
|
||||
#include "common/string_util.h"
|
||||
@@ -12,10 +14,11 @@ namespace Common {
|
||||
|
||||
constexpr char KEY_VALUE_SEPARATOR = ':';
|
||||
constexpr char PARAM_SEPARATOR = ',';
|
||||
|
||||
constexpr char ESCAPE_CHARACTER = '$';
|
||||
const std::string KEY_VALUE_SEPARATOR_ESCAPE{ESCAPE_CHARACTER, '0'};
|
||||
const std::string PARAM_SEPARATOR_ESCAPE{ESCAPE_CHARACTER, '1'};
|
||||
const std::string ESCAPE_CHARACTER_ESCAPE{ESCAPE_CHARACTER, '2'};
|
||||
constexpr char KEY_VALUE_SEPARATOR_ESCAPE[] = "$0";
|
||||
constexpr char PARAM_SEPARATOR_ESCAPE[] = "$1";
|
||||
constexpr char ESCAPE_CHARACTER_ESCAPE[] = "$2";
|
||||
|
||||
ParamPackage::ParamPackage(const std::string& serialized) {
|
||||
std::vector<std::string> pairs;
|
||||
@@ -35,7 +38,7 @@ ParamPackage::ParamPackage(const std::string& serialized) {
|
||||
part = Common::ReplaceAll(part, ESCAPE_CHARACTER_ESCAPE, {ESCAPE_CHARACTER});
|
||||
}
|
||||
|
||||
Set(key_value[0], key_value[1]);
|
||||
Set(key_value[0], std::move(key_value[1]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,16 +104,16 @@ float ParamPackage::Get(const std::string& key, float default_value) const {
|
||||
}
|
||||
}
|
||||
|
||||
void ParamPackage::Set(const std::string& key, const std::string& value) {
|
||||
data[key] = value;
|
||||
void ParamPackage::Set(const std::string& key, std::string value) {
|
||||
data.insert_or_assign(key, std::move(value));
|
||||
}
|
||||
|
||||
void ParamPackage::Set(const std::string& key, int value) {
|
||||
data[key] = std::to_string(value);
|
||||
data.insert_or_assign(key, std::to_string(value));
|
||||
}
|
||||
|
||||
void ParamPackage::Set(const std::string& key, float value) {
|
||||
data[key] = std::to_string(value);
|
||||
data.insert_or_assign(key, std::to_string(value));
|
||||
}
|
||||
|
||||
bool ParamPackage::Has(const std::string& key) const {
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
std::string Get(const std::string& key, const std::string& default_value) const;
|
||||
int Get(const std::string& key, int default_value) const;
|
||||
float Get(const std::string& key, float default_value) const;
|
||||
void Set(const std::string& key, const std::string& value);
|
||||
void Set(const std::string& key, std::string value);
|
||||
void Set(const std::string& key, int value);
|
||||
void Set(const std::string& key, float value);
|
||||
bool Has(const std::string& key) const;
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
// Copyright 2015 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
|
||||
namespace Common {
|
||||
|
||||
template <typename T>
|
||||
class SynchronizedWrapper;
|
||||
|
||||
/**
|
||||
* Synchronized reference, that keeps a SynchronizedWrapper's mutex locked during its lifetime. This
|
||||
* greatly reduces the chance that someone will access the wrapped resource without locking the
|
||||
* mutex.
|
||||
*/
|
||||
template <typename T>
|
||||
class SynchronizedRef {
|
||||
public:
|
||||
SynchronizedRef(SynchronizedWrapper<T>& wrapper) : wrapper(&wrapper) {
|
||||
wrapper.mutex.lock();
|
||||
}
|
||||
|
||||
SynchronizedRef(SynchronizedRef&) = delete;
|
||||
SynchronizedRef(SynchronizedRef&& o) : wrapper(o.wrapper) {
|
||||
o.wrapper = nullptr;
|
||||
}
|
||||
|
||||
~SynchronizedRef() {
|
||||
if (wrapper)
|
||||
wrapper->mutex.unlock();
|
||||
}
|
||||
|
||||
SynchronizedRef& operator=(SynchronizedRef&) = delete;
|
||||
SynchronizedRef& operator=(SynchronizedRef&& o) {
|
||||
std::swap(wrapper, o.wrapper);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& operator*() {
|
||||
return wrapper->data;
|
||||
}
|
||||
const T& operator*() const {
|
||||
return wrapper->data;
|
||||
}
|
||||
|
||||
T* operator->() {
|
||||
return &wrapper->data;
|
||||
}
|
||||
const T* operator->() const {
|
||||
return &wrapper->data;
|
||||
}
|
||||
|
||||
private:
|
||||
SynchronizedWrapper<T>* wrapper;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wraps an object, only allowing access to it via a locking reference wrapper. Good to ensure no
|
||||
* one forgets to lock a mutex before acessing an object. To access the wrapped object construct a
|
||||
* SyncronizedRef on this wrapper. Inspired by Rust's Mutex type
|
||||
* (http://doc.rust-lang.org/std/sync/struct.Mutex.html).
|
||||
*/
|
||||
template <typename T>
|
||||
class SynchronizedWrapper {
|
||||
public:
|
||||
template <typename... Args>
|
||||
SynchronizedWrapper(Args&&... args) : data(std::forward<Args>(args)...) {}
|
||||
|
||||
SynchronizedRef<T> Lock() {
|
||||
return {*this};
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename U>
|
||||
friend class SynchronizedRef;
|
||||
|
||||
std::mutex mutex;
|
||||
T data;
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
@@ -104,6 +104,10 @@ public:
|
||||
|
||||
virtual void SetTlsAddress(VAddr address) = 0;
|
||||
|
||||
virtual u64 GetTPIDR_EL0() const = 0;
|
||||
|
||||
virtual void SetTPIDR_EL0(u64 value) = 0;
|
||||
|
||||
/**
|
||||
* Saves the current CPU context
|
||||
* @param ctx Thread context to save
|
||||
|
||||
@@ -196,6 +196,14 @@ void ARM_Dynarmic::SetTlsAddress(u64 address) {
|
||||
cb->tpidrro_el0 = address;
|
||||
}
|
||||
|
||||
u64 ARM_Dynarmic::GetTPIDR_EL0() const {
|
||||
return cb->tpidr_el0;
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::SetTPIDR_EL0(u64 value) {
|
||||
cb->tpidr_el0 = value;
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
|
||||
ctx.cpu_registers = jit->GetRegisters();
|
||||
ctx.sp = jit->GetSP();
|
||||
|
||||
@@ -34,6 +34,8 @@ public:
|
||||
void SetCPSR(u32 cpsr) override;
|
||||
VAddr GetTlsAddress() const override;
|
||||
void SetTlsAddress(VAddr address) override;
|
||||
void SetTPIDR_EL0(u64 value) override;
|
||||
u64 GetTPIDR_EL0() const override;
|
||||
|
||||
void SaveContext(ThreadContext& ctx) override;
|
||||
void LoadContext(const ThreadContext& ctx) override;
|
||||
|
||||
@@ -169,6 +169,16 @@ void ARM_Unicorn::SetTlsAddress(VAddr base) {
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
|
||||
}
|
||||
|
||||
u64 ARM_Unicorn::GetTPIDR_EL0() const {
|
||||
u64 value{};
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDR_EL0, &value));
|
||||
return value;
|
||||
}
|
||||
|
||||
void ARM_Unicorn::SetTPIDR_EL0(u64 value) {
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value));
|
||||
}
|
||||
|
||||
void ARM_Unicorn::Run() {
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
ExecuteInstructions(std::max(4000000, 0));
|
||||
|
||||
@@ -28,6 +28,8 @@ public:
|
||||
void SetCPSR(u32 cpsr) override;
|
||||
VAddr GetTlsAddress() const override;
|
||||
void SetTlsAddress(VAddr address) override;
|
||||
void SetTPIDR_EL0(u64 value) override;
|
||||
u64 GetTPIDR_EL0() const override;
|
||||
void SaveContext(ThreadContext& ctx) override;
|
||||
void LoadContext(const ThreadContext& ctx) override;
|
||||
void PrepareReschedule() override;
|
||||
|
||||
@@ -20,13 +20,13 @@ enum {
|
||||
constexpr ResultCode ERROR_PATH_NOT_FOUND(ErrorModule::FS, ErrCodes::NotFound);
|
||||
|
||||
// TODO(bunnei): Replace these with correct errors for Switch OS
|
||||
constexpr ResultCode ERROR_INVALID_PATH(ResultCode(-1));
|
||||
constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ResultCode(-1));
|
||||
constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(ResultCode(-1));
|
||||
constexpr ResultCode ERROR_FILE_NOT_FOUND(ResultCode(-1));
|
||||
constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(ResultCode(-1));
|
||||
constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(ResultCode(-1));
|
||||
constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(ResultCode(-1));
|
||||
constexpr ResultCode ERROR_DIRECTORY_NOT_EMPTY(ResultCode(-1));
|
||||
constexpr ResultCode ERROR_INVALID_PATH(-1);
|
||||
constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(-1);
|
||||
constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(-1);
|
||||
constexpr ResultCode ERROR_FILE_NOT_FOUND(-1);
|
||||
constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(-1);
|
||||
constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(-1);
|
||||
constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(-1);
|
||||
constexpr ResultCode ERROR_DIRECTORY_NOT_EMPTY(-1);
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
@@ -76,7 +76,7 @@ std::vector<std::shared_ptr<VfsFile>> PartitionFilesystem::GetFiles() const {
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<VfsDirectory>> PartitionFilesystem::GetSubdirectories() const {
|
||||
return {};
|
||||
return pfs_dirs;
|
||||
}
|
||||
|
||||
std::string PartitionFilesystem::GetName() const {
|
||||
|
||||
@@ -42,7 +42,7 @@ bool VfsFile::WriteByte(u8 data, size_t offset) {
|
||||
return Write(&data, 1, offset) == 1;
|
||||
}
|
||||
|
||||
size_t VfsFile::WriteBytes(std::vector<u8> data, size_t offset) {
|
||||
size_t VfsFile::WriteBytes(const std::vector<u8>& data, size_t offset) {
|
||||
return Write(data.data(), data.size(), offset);
|
||||
}
|
||||
|
||||
|
||||
@@ -59,8 +59,7 @@ struct VfsFile : NonCopyable {
|
||||
// Returns the number of bytes (sizeof(T)*number_elements) read successfully.
|
||||
template <typename T>
|
||||
size_t ReadArray(T* data, size_t number_elements, size_t offset = 0) const {
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Data type must be trivially copyable.");
|
||||
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
||||
|
||||
return Read(reinterpret_cast<u8*>(data), number_elements * sizeof(T), offset);
|
||||
}
|
||||
@@ -69,8 +68,7 @@ struct VfsFile : NonCopyable {
|
||||
// Returns the number of bytes read successfully.
|
||||
template <typename T>
|
||||
size_t ReadBytes(T* data, size_t size, size_t offset = 0) const {
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Data type must be trivially copyable.");
|
||||
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
||||
return Read(reinterpret_cast<u8*>(data), size, offset);
|
||||
}
|
||||
|
||||
@@ -78,8 +76,7 @@ struct VfsFile : NonCopyable {
|
||||
// Returns the number of bytes read successfully (sizeof(T)).
|
||||
template <typename T>
|
||||
size_t ReadObject(T* data, size_t offset = 0) const {
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Data type must be trivially copyable.");
|
||||
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
||||
return Read(reinterpret_cast<u8*>(data), sizeof(T), offset);
|
||||
}
|
||||
|
||||
@@ -88,33 +85,29 @@ struct VfsFile : NonCopyable {
|
||||
virtual bool WriteByte(u8 data, size_t offset = 0);
|
||||
// Writes a vector of bytes to offset in file and returns the number of bytes successfully
|
||||
// written.
|
||||
virtual size_t WriteBytes(std::vector<u8> data, size_t offset = 0);
|
||||
virtual size_t WriteBytes(const std::vector<u8>& data, size_t offset = 0);
|
||||
|
||||
// Writes an array of type T, size number_elements to offset in file.
|
||||
// Returns the number of bytes (sizeof(T)*number_elements) written successfully.
|
||||
template <typename T>
|
||||
size_t WriteArray(T* data, size_t number_elements, size_t offset = 0) {
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Data type must be trivially copyable.");
|
||||
|
||||
size_t WriteArray(const T* data, size_t number_elements, size_t offset = 0) {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
||||
return Write(data, number_elements * sizeof(T), offset);
|
||||
}
|
||||
|
||||
// Writes size bytes starting at memory location data to offset in file.
|
||||
// Returns the number of bytes written successfully.
|
||||
template <typename T>
|
||||
size_t WriteBytes(T* data, size_t size, size_t offset = 0) {
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Data type must be trivially copyable.");
|
||||
return Write(reinterpret_cast<u8*>(data), size, offset);
|
||||
size_t WriteBytes(const T* data, size_t size, size_t offset = 0) {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
||||
return Write(reinterpret_cast<const u8*>(data), size, offset);
|
||||
}
|
||||
|
||||
// Writes one object of type T to offset in file.
|
||||
// Returns the number of bytes written successfully (sizeof(T)).
|
||||
template <typename T>
|
||||
size_t WriteObject(const T& data, size_t offset = 0) {
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Data type must be trivially copyable.");
|
||||
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
||||
return Write(&data, sizeof(T), offset);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,16 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "core/file_sys/vfs_offset.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, size_t size_, size_t offset_,
|
||||
const std::string& name_)
|
||||
: file(file_), offset(offset_), size(size_), name(name_) {}
|
||||
std::string name_)
|
||||
: file(std::move(file_)), offset(offset_), size(size_), name(std::move(name_)) {}
|
||||
|
||||
std::string OffsetVfsFile::GetName() const {
|
||||
return name.empty() ? file->GetName() : name;
|
||||
@@ -73,7 +76,7 @@ bool OffsetVfsFile::WriteByte(u8 data, size_t r_offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t OffsetVfsFile::WriteBytes(std::vector<u8> data, size_t r_offset) {
|
||||
size_t OffsetVfsFile::WriteBytes(const std::vector<u8>& data, size_t r_offset) {
|
||||
return file->Write(data.data(), TrimToFit(data.size(), r_offset), offset + r_offset);
|
||||
}
|
||||
|
||||
@@ -86,7 +89,7 @@ size_t OffsetVfsFile::GetOffset() const {
|
||||
}
|
||||
|
||||
size_t OffsetVfsFile::TrimToFit(size_t r_size, size_t r_offset) const {
|
||||
return std::max<size_t>(std::min<size_t>(size - r_offset, r_size), 0);
|
||||
return std::clamp(r_size, size_t{0}, size - r_offset);
|
||||
}
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace FileSys {
|
||||
// the size of this wrapper.
|
||||
struct OffsetVfsFile : public VfsFile {
|
||||
OffsetVfsFile(std::shared_ptr<VfsFile> file, size_t size, size_t offset = 0,
|
||||
const std::string& new_name = "");
|
||||
std::string new_name = "");
|
||||
|
||||
std::string GetName() const override;
|
||||
size_t GetSize() const override;
|
||||
@@ -28,7 +28,7 @@ struct OffsetVfsFile : public VfsFile {
|
||||
std::vector<u8> ReadBytes(size_t size, size_t offset) const override;
|
||||
std::vector<u8> ReadAllBytes() const override;
|
||||
bool WriteByte(u8 data, size_t offset) override;
|
||||
size_t WriteBytes(std::vector<u8> data, size_t offset) override;
|
||||
size_t WriteBytes(const std::vector<u8>& data, size_t offset) override;
|
||||
|
||||
bool Rename(const std::string& name) override;
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ static Kernel::Thread* FindThreadById(int id) {
|
||||
for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
|
||||
const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList();
|
||||
for (auto& thread : threads) {
|
||||
if (thread->GetThreadId() == id) {
|
||||
if (thread->GetThreadId() == static_cast<u32>(id)) {
|
||||
current_core = core;
|
||||
return thread.get();
|
||||
}
|
||||
@@ -214,7 +214,7 @@ static Kernel::Thread* FindThreadById(int id) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static u64 RegRead(int id, Kernel::Thread* thread = nullptr) {
|
||||
static u64 RegRead(std::size_t id, Kernel::Thread* thread = nullptr) {
|
||||
if (!thread) {
|
||||
return 0;
|
||||
}
|
||||
@@ -234,7 +234,7 @@ static u64 RegRead(int id, Kernel::Thread* thread = nullptr) {
|
||||
}
|
||||
}
|
||||
|
||||
static void RegWrite(int id, u64 val, Kernel::Thread* thread = nullptr) {
|
||||
static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr) {
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
@@ -744,7 +744,7 @@ static bool IsDataAvailable() {
|
||||
fd_set fd_socket;
|
||||
|
||||
FD_ZERO(&fd_socket);
|
||||
FD_SET(gdbserver_socket, &fd_socket);
|
||||
FD_SET(static_cast<u32>(gdbserver_socket), &fd_socket);
|
||||
|
||||
struct timeval t;
|
||||
t.tv_sec = 0;
|
||||
@@ -793,7 +793,7 @@ static void ReadRegisters() {
|
||||
|
||||
u8* bufptr = buffer;
|
||||
|
||||
for (int reg = 0; reg <= SP_REGISTER; reg++) {
|
||||
for (u32 reg = 0; reg <= SP_REGISTER; reg++) {
|
||||
LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread));
|
||||
}
|
||||
|
||||
@@ -807,7 +807,7 @@ static void ReadRegisters() {
|
||||
|
||||
bufptr += 8;
|
||||
|
||||
for (int reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) {
|
||||
for (u32 reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) {
|
||||
LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread));
|
||||
}
|
||||
|
||||
@@ -858,7 +858,7 @@ static void WriteRegisters() {
|
||||
if (command_buffer[0] != 'G')
|
||||
return SendReply("E01");
|
||||
|
||||
for (int i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) {
|
||||
for (u32 i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) {
|
||||
if (reg <= SP_REGISTER) {
|
||||
RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg == PC_REGISTER) {
|
||||
|
||||
@@ -174,6 +174,25 @@ public:
|
||||
template <typename First, typename... Other>
|
||||
void Push(const First& first_value, const Other&... other_values);
|
||||
|
||||
/**
|
||||
* Helper function for pushing strongly-typed enumeration values.
|
||||
*
|
||||
* @tparam Enum The enumeration type to be pushed
|
||||
*
|
||||
* @param value The value to push.
|
||||
*
|
||||
* @note The underlying size of the enumeration type is the size of the
|
||||
* data that gets pushed. e.g. "enum class SomeEnum : u16" will
|
||||
* push a u16-sized amount of data.
|
||||
*/
|
||||
template <typename Enum>
|
||||
void PushEnum(Enum value) {
|
||||
static_assert(std::is_enum_v<Enum>, "T must be an enum type within a PushEnum call.");
|
||||
static_assert(!std::is_convertible_v<Enum, int>,
|
||||
"enum type in PushEnum must be a strongly typed enum.");
|
||||
Push(static_cast<std::underlying_type_t<Enum>>(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copies the content of the given trivially copyable class to the buffer as a normal
|
||||
* param
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace AddressArbiter {
|
||||
static ResultCode WaitForAddress(VAddr address, s64 timeout) {
|
||||
SharedPtr<Thread> current_thread = GetCurrentThread();
|
||||
current_thread->arb_wait_address = address;
|
||||
current_thread->status = THREADSTATUS_WAIT_ARB;
|
||||
current_thread->status = ThreadStatus::WaitArb;
|
||||
current_thread->wakeup_callback = nullptr;
|
||||
|
||||
current_thread->WakeAfterDelay(timeout);
|
||||
@@ -65,7 +65,7 @@ static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num
|
||||
|
||||
// Signal the waiting threads.
|
||||
for (size_t i = 0; i < last; i++) {
|
||||
ASSERT(waiting_threads[i]->status == THREADSTATUS_WAIT_ARB);
|
||||
ASSERT(waiting_threads[i]->status == ThreadStatus::WaitArb);
|
||||
waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS);
|
||||
waiting_threads[i]->arb_wait_address = 0;
|
||||
waiting_threads[i]->ResumeFromWait();
|
||||
|
||||
@@ -38,7 +38,7 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
|
||||
thread->wakeup_callback =
|
||||
[context = *this, callback](ThreadWakeupReason reason, SharedPtr<Thread> thread,
|
||||
SharedPtr<WaitObject> object, size_t index) mutable -> bool {
|
||||
ASSERT(thread->status == THREADSTATUS_WAIT_HLE_EVENT);
|
||||
ASSERT(thread->status == ThreadStatus::WaitHLEEvent);
|
||||
callback(thread, context, reason);
|
||||
context.WriteToOutgoingCommandBuffer(*thread);
|
||||
return true;
|
||||
@@ -50,7 +50,7 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
|
||||
}
|
||||
|
||||
event->Clear();
|
||||
thread->status = THREADSTATUS_WAIT_HLE_EVENT;
|
||||
thread->status = ThreadStatus::WaitHLEEvent;
|
||||
thread->wait_objects = {event};
|
||||
event->AddWaitingThread(thread);
|
||||
|
||||
@@ -301,10 +301,6 @@ size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size, int buffe
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t HLERequestContext::WriteBuffer(const std::vector<u8>& buffer, int buffer_index) const {
|
||||
return WriteBuffer(buffer.data(), buffer.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()
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include "common/common_types.h"
|
||||
@@ -171,8 +173,25 @@ public:
|
||||
/// Helper function to write a buffer using the appropriate buffer descriptor
|
||||
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, int buffer_index = 0) const;
|
||||
/* Helper function to write a buffer using the appropriate buffer descriptor
|
||||
*
|
||||
* @tparam ContiguousContainer an arbitrary container that satisfies the
|
||||
* ContiguousContainer concept in the C++ standard library.
|
||||
*
|
||||
* @param container The container to write the data of into a buffer.
|
||||
* @param buffer_index The buffer in particular to write to.
|
||||
*/
|
||||
template <typename ContiguousContainer,
|
||||
typename = std::enable_if_t<!std::is_pointer_v<ContiguousContainer>>>
|
||||
size_t WriteBuffer(const ContiguousContainer& container, int buffer_index = 0) const {
|
||||
using ContiguousType = typename ContiguousContainer::value_type;
|
||||
|
||||
static_assert(std::is_trivially_copyable_v<ContiguousType>,
|
||||
"Container to WriteBuffer must contain trivially copyable objects");
|
||||
|
||||
return WriteBuffer(std::data(container), std::size(container) * sizeof(ContiguousType),
|
||||
buffer_index);
|
||||
}
|
||||
|
||||
/// Helper function to get the size of the input buffer
|
||||
size_t GetReadBufferSize(int buffer_index = 0) const;
|
||||
|
||||
@@ -28,7 +28,7 @@ static std::pair<SharedPtr<Thread>, u32> GetHighestPriorityMutexWaitingThread(
|
||||
if (thread->mutex_wait_address != mutex_addr)
|
||||
continue;
|
||||
|
||||
ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX);
|
||||
ASSERT(thread->status == ThreadStatus::WaitMutex);
|
||||
|
||||
++num_waiters;
|
||||
if (highest_priority_thread == nullptr ||
|
||||
@@ -83,7 +83,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
|
||||
GetCurrentThread()->mutex_wait_address = address;
|
||||
GetCurrentThread()->wait_handle = requesting_thread_handle;
|
||||
|
||||
GetCurrentThread()->status = THREADSTATUS_WAIT_MUTEX;
|
||||
GetCurrentThread()->status = ThreadStatus::WaitMutex;
|
||||
GetCurrentThread()->wakeup_callback = nullptr;
|
||||
|
||||
// Update the lock holder thread's priority to prevent priority inversion.
|
||||
@@ -121,7 +121,7 @@ ResultCode Mutex::Release(VAddr address) {
|
||||
// Grant the mutex to the next waiting thread and resume it.
|
||||
Memory::Write32(address, mutex_value);
|
||||
|
||||
ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX);
|
||||
ASSERT(thread->status == ThreadStatus::WaitMutex);
|
||||
thread->ResumeFromWait();
|
||||
|
||||
thread->lock_owner = nullptr;
|
||||
|
||||
@@ -34,7 +34,7 @@ Thread* Scheduler::PopNextReadyThread() {
|
||||
Thread* next = nullptr;
|
||||
Thread* thread = GetCurrentThread();
|
||||
|
||||
if (thread && thread->status == THREADSTATUS_RUNNING) {
|
||||
if (thread && thread->status == ThreadStatus::Running) {
|
||||
// We have to do better than the current thread.
|
||||
// This call returns null when that's not possible.
|
||||
next = ready_queue.pop_first_better(thread->current_priority);
|
||||
@@ -56,18 +56,20 @@ void Scheduler::SwitchContext(Thread* new_thread) {
|
||||
if (previous_thread) {
|
||||
previous_thread->last_running_ticks = CoreTiming::GetTicks();
|
||||
cpu_core->SaveContext(previous_thread->context);
|
||||
// Save the TPIDR_EL0 system register in case it was modified.
|
||||
previous_thread->tpidr_el0 = cpu_core->GetTPIDR_EL0();
|
||||
|
||||
if (previous_thread->status == THREADSTATUS_RUNNING) {
|
||||
if (previous_thread->status == ThreadStatus::Running) {
|
||||
// This is only the case when a reschedule is triggered without the current thread
|
||||
// yielding execution (i.e. an event triggered, system core time-sliced, etc)
|
||||
ready_queue.push_front(previous_thread->current_priority, previous_thread);
|
||||
previous_thread->status = THREADSTATUS_READY;
|
||||
previous_thread->status = ThreadStatus::Ready;
|
||||
}
|
||||
}
|
||||
|
||||
// Load context of new thread
|
||||
if (new_thread) {
|
||||
ASSERT_MSG(new_thread->status == THREADSTATUS_READY,
|
||||
ASSERT_MSG(new_thread->status == ThreadStatus::Ready,
|
||||
"Thread must be ready to become running.");
|
||||
|
||||
// Cancel any outstanding wakeup events for this thread
|
||||
@@ -78,7 +80,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
|
||||
current_thread = new_thread;
|
||||
|
||||
ready_queue.remove(new_thread->current_priority, new_thread);
|
||||
new_thread->status = THREADSTATUS_RUNNING;
|
||||
new_thread->status = ThreadStatus::Running;
|
||||
|
||||
if (previous_process != current_thread->owner_process) {
|
||||
Core::CurrentProcess() = current_thread->owner_process;
|
||||
@@ -87,6 +89,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
|
||||
|
||||
cpu_core->LoadContext(new_thread->context);
|
||||
cpu_core->SetTlsAddress(new_thread->GetTLSAddress());
|
||||
cpu_core->SetTPIDR_EL0(new_thread->GetTPIDR_EL0());
|
||||
cpu_core->ClearExclusiveState();
|
||||
} else {
|
||||
current_thread = nullptr;
|
||||
@@ -129,14 +132,14 @@ void Scheduler::RemoveThread(Thread* thread) {
|
||||
void Scheduler::ScheduleThread(Thread* thread, u32 priority) {
|
||||
std::lock_guard<std::mutex> lock(scheduler_mutex);
|
||||
|
||||
ASSERT(thread->status == THREADSTATUS_READY);
|
||||
ASSERT(thread->status == ThreadStatus::Ready);
|
||||
ready_queue.push_back(priority, thread);
|
||||
}
|
||||
|
||||
void Scheduler::UnscheduleThread(Thread* thread, u32 priority) {
|
||||
std::lock_guard<std::mutex> lock(scheduler_mutex);
|
||||
|
||||
ASSERT(thread->status == THREADSTATUS_READY);
|
||||
ASSERT(thread->status == ThreadStatus::Ready);
|
||||
ready_queue.remove(priority, thread);
|
||||
}
|
||||
|
||||
@@ -144,7 +147,7 @@ void Scheduler::SetThreadPriority(Thread* thread, u32 priority) {
|
||||
std::lock_guard<std::mutex> lock(scheduler_mutex);
|
||||
|
||||
// If thread was ready, adjust queues
|
||||
if (thread->status == THREADSTATUS_READY)
|
||||
if (thread->status == ThreadStatus::Ready)
|
||||
ready_queue.move(thread, thread->current_priority, priority);
|
||||
else
|
||||
ready_queue.prepare(priority);
|
||||
|
||||
@@ -110,10 +110,10 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
|
||||
result = hle_handler->HandleSyncRequest(context);
|
||||
}
|
||||
|
||||
if (thread->status == THREADSTATUS_RUNNING) {
|
||||
if (thread->status == ThreadStatus::Running) {
|
||||
// Put the thread to sleep until the server replies, it will be awoken in
|
||||
// svcReplyAndReceive for LLE servers.
|
||||
thread->status = THREADSTATUS_WAIT_IPC;
|
||||
thread->status = ThreadStatus::WaitIPC;
|
||||
|
||||
if (hle_handler != nullptr) {
|
||||
// For HLE services, we put the request threads to sleep for a short duration to
|
||||
|
||||
@@ -133,7 +133,7 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
|
||||
/// Default thread wakeup callback for WaitSynchronization
|
||||
static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread,
|
||||
SharedPtr<WaitObject> object, size_t index) {
|
||||
ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY);
|
||||
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
|
||||
|
||||
if (reason == ThreadWakeupReason::Timeout) {
|
||||
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
|
||||
@@ -197,7 +197,7 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
|
||||
object->AddWaitingThread(thread);
|
||||
|
||||
thread->wait_objects = std::move(objects);
|
||||
thread->status = THREADSTATUS_WAIT_SYNCH_ANY;
|
||||
thread->status = ThreadStatus::WaitSynchAny;
|
||||
|
||||
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
||||
thread->WakeAfterDelay(nano_seconds);
|
||||
@@ -217,7 +217,7 @@ static ResultCode CancelSynchronization(Handle thread_handle) {
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY);
|
||||
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
|
||||
thread->SetWaitSynchronizationResult(
|
||||
ResultCode(ErrorModule::Kernel, ErrCodes::SynchronizationCanceled));
|
||||
thread->ResumeFromWait();
|
||||
@@ -468,8 +468,8 @@ static void ExitProcess() {
|
||||
continue;
|
||||
|
||||
// TODO(Subv): When are the other running/ready threads terminated?
|
||||
ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
|
||||
thread->status == THREADSTATUS_WAIT_SYNCH_ALL,
|
||||
ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
|
||||
thread->status == ThreadStatus::WaitSynchAll,
|
||||
"Exiting processes with non-waiting threads is currently unimplemented");
|
||||
|
||||
thread->Stop();
|
||||
@@ -545,7 +545,7 @@ static ResultCode StartThread(Handle thread_handle) {
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
ASSERT(thread->status == THREADSTATUS_DORMANT);
|
||||
ASSERT(thread->status == ThreadStatus::Dormant);
|
||||
|
||||
thread->ResumeFromWait();
|
||||
Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
|
||||
@@ -596,7 +596,7 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
|
||||
current_thread->condvar_wait_address = condition_variable_addr;
|
||||
current_thread->mutex_wait_address = mutex_addr;
|
||||
current_thread->wait_handle = thread_handle;
|
||||
current_thread->status = THREADSTATUS_WAIT_MUTEX;
|
||||
current_thread->status = ThreadStatus::WaitMutex;
|
||||
current_thread->wakeup_callback = nullptr;
|
||||
|
||||
current_thread->WakeAfterDelay(nano_seconds);
|
||||
@@ -656,7 +656,7 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
|
||||
if (mutex_val == 0) {
|
||||
// We were able to acquire the mutex, resume this thread.
|
||||
Memory::Write32(thread->mutex_wait_address, thread->wait_handle);
|
||||
ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX);
|
||||
ASSERT(thread->status == ThreadStatus::WaitMutex);
|
||||
thread->ResumeFromWait();
|
||||
|
||||
auto lock_owner = thread->lock_owner;
|
||||
@@ -672,8 +672,8 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
|
||||
Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
|
||||
auto owner = g_handle_table.Get<Thread>(owner_handle);
|
||||
ASSERT(owner);
|
||||
ASSERT(thread->status != THREADSTATUS_RUNNING);
|
||||
thread->status = THREADSTATUS_WAIT_MUTEX;
|
||||
ASSERT(thread->status != ThreadStatus::Running);
|
||||
thread->status = ThreadStatus::WaitMutex;
|
||||
thread->wakeup_callback = nullptr;
|
||||
|
||||
// Signal that the mutex now has a waiting thread.
|
||||
@@ -795,8 +795,9 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (core == THREADPROCESSORID_DEFAULT) {
|
||||
ASSERT(thread->owner_process->ideal_processor != THREADPROCESSORID_DEFAULT);
|
||||
if (core == static_cast<u32>(THREADPROCESSORID_DEFAULT)) {
|
||||
ASSERT(thread->owner_process->ideal_processor !=
|
||||
static_cast<u8>(THREADPROCESSORID_DEFAULT));
|
||||
// Set the target CPU to the one specified in the process' exheader.
|
||||
core = thread->owner_process->ideal_processor;
|
||||
mask = 1ull << core;
|
||||
@@ -811,7 +812,7 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
|
||||
|
||||
if (core == OnlyChangeMask) {
|
||||
core = thread->ideal_core;
|
||||
} else if (core >= Core::NUM_CPU_CORES && core != -1) {
|
||||
} else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(-1)) {
|
||||
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Kernel {
|
||||
static CoreTiming::EventType* ThreadWakeupEventType = nullptr;
|
||||
|
||||
bool Thread::ShouldWait(Thread* thread) const {
|
||||
return status != THREADSTATUS_DEAD;
|
||||
return status != ThreadStatus::Dead;
|
||||
}
|
||||
|
||||
void Thread::Acquire(Thread* thread) {
|
||||
@@ -63,11 +63,11 @@ void Thread::Stop() {
|
||||
|
||||
// Clean up thread from ready queue
|
||||
// This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
|
||||
if (status == THREADSTATUS_READY) {
|
||||
if (status == ThreadStatus::Ready) {
|
||||
scheduler->UnscheduleThread(this, current_priority);
|
||||
}
|
||||
|
||||
status = THREADSTATUS_DEAD;
|
||||
status = ThreadStatus::Dead;
|
||||
|
||||
WakeupAllWaitingThreads();
|
||||
|
||||
@@ -86,7 +86,7 @@ void Thread::Stop() {
|
||||
|
||||
void WaitCurrentThread_Sleep() {
|
||||
Thread* thread = GetCurrentThread();
|
||||
thread->status = THREADSTATUS_WAIT_SLEEP;
|
||||
thread->status = ThreadStatus::WaitSleep;
|
||||
}
|
||||
|
||||
void ExitCurrentThread() {
|
||||
@@ -110,10 +110,9 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
|
||||
|
||||
bool resume = true;
|
||||
|
||||
if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
|
||||
thread->status == THREADSTATUS_WAIT_SYNCH_ALL ||
|
||||
thread->status == THREADSTATUS_WAIT_HLE_EVENT) {
|
||||
|
||||
if (thread->status == ThreadStatus::WaitSynchAny ||
|
||||
thread->status == ThreadStatus::WaitSynchAll ||
|
||||
thread->status == ThreadStatus::WaitHLEEvent) {
|
||||
// Remove the thread from each of its waiting objects' waitlists
|
||||
for (auto& object : thread->wait_objects)
|
||||
object->RemoveWaitingThread(thread.get());
|
||||
@@ -126,7 +125,7 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
|
||||
|
||||
if (thread->mutex_wait_address != 0 || thread->condvar_wait_address != 0 ||
|
||||
thread->wait_handle) {
|
||||
ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX);
|
||||
ASSERT(thread->status == ThreadStatus::WaitMutex);
|
||||
thread->mutex_wait_address = 0;
|
||||
thread->condvar_wait_address = 0;
|
||||
thread->wait_handle = 0;
|
||||
@@ -141,7 +140,7 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
|
||||
}
|
||||
|
||||
if (thread->arb_wait_address != 0) {
|
||||
ASSERT(thread->status == THREADSTATUS_WAIT_ARB);
|
||||
ASSERT(thread->status == ThreadStatus::WaitArb);
|
||||
thread->arb_wait_address = 0;
|
||||
}
|
||||
|
||||
@@ -178,28 +177,28 @@ void Thread::ResumeFromWait() {
|
||||
ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects");
|
||||
|
||||
switch (status) {
|
||||
case THREADSTATUS_WAIT_SYNCH_ALL:
|
||||
case THREADSTATUS_WAIT_SYNCH_ANY:
|
||||
case THREADSTATUS_WAIT_HLE_EVENT:
|
||||
case THREADSTATUS_WAIT_SLEEP:
|
||||
case THREADSTATUS_WAIT_IPC:
|
||||
case THREADSTATUS_WAIT_MUTEX:
|
||||
case THREADSTATUS_WAIT_ARB:
|
||||
case ThreadStatus::WaitSynchAll:
|
||||
case ThreadStatus::WaitSynchAny:
|
||||
case ThreadStatus::WaitHLEEvent:
|
||||
case ThreadStatus::WaitSleep:
|
||||
case ThreadStatus::WaitIPC:
|
||||
case ThreadStatus::WaitMutex:
|
||||
case ThreadStatus::WaitArb:
|
||||
break;
|
||||
|
||||
case THREADSTATUS_READY:
|
||||
case ThreadStatus::Ready:
|
||||
// The thread's wakeup callback must have already been cleared when the thread was first
|
||||
// awoken.
|
||||
ASSERT(wakeup_callback == nullptr);
|
||||
// If the thread is waiting on multiple wait objects, it might be awoken more than once
|
||||
// before actually resuming. We can ignore subsequent wakeups if the thread status has
|
||||
// already been set to THREADSTATUS_READY.
|
||||
// already been set to ThreadStatus::Ready.
|
||||
return;
|
||||
|
||||
case THREADSTATUS_RUNNING:
|
||||
case ThreadStatus::Running:
|
||||
DEBUG_ASSERT_MSG(false, "Thread with object id {} has already resumed.", GetObjectId());
|
||||
return;
|
||||
case THREADSTATUS_DEAD:
|
||||
case ThreadStatus::Dead:
|
||||
// This should never happen, as threads must complete before being stopped.
|
||||
DEBUG_ASSERT_MSG(false, "Thread with object id {} cannot be resumed because it's DEAD.",
|
||||
GetObjectId());
|
||||
@@ -208,7 +207,7 @@ void Thread::ResumeFromWait() {
|
||||
|
||||
wakeup_callback = nullptr;
|
||||
|
||||
status = THREADSTATUS_READY;
|
||||
status = ThreadStatus::Ready;
|
||||
|
||||
boost::optional<s32> new_processor_id = GetNextProcessorId(affinity_mask);
|
||||
if (!new_processor_id) {
|
||||
@@ -310,9 +309,10 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
|
||||
SharedPtr<Thread> thread(new Thread);
|
||||
|
||||
thread->thread_id = NewThreadId();
|
||||
thread->status = THREADSTATUS_DORMANT;
|
||||
thread->status = ThreadStatus::Dormant;
|
||||
thread->entry_point = entry_point;
|
||||
thread->stack_top = stack_top;
|
||||
thread->tpidr_el0 = 0;
|
||||
thread->nominal_priority = thread->current_priority = priority;
|
||||
thread->last_running_ticks = CoreTiming::GetTicks();
|
||||
thread->processor_id = processor_id;
|
||||
@@ -471,7 +471,7 @@ void Thread::ChangeCore(u32 core, u64 mask) {
|
||||
ideal_core = core;
|
||||
affinity_mask = mask;
|
||||
|
||||
if (status != THREADSTATUS_READY) {
|
||||
if (status != ThreadStatus::Ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,18 +36,18 @@ enum ThreadProcessorId : s32 {
|
||||
(1 << THREADPROCESSORID_2) | (1 << THREADPROCESSORID_3)
|
||||
};
|
||||
|
||||
enum ThreadStatus {
|
||||
THREADSTATUS_RUNNING, ///< Currently running
|
||||
THREADSTATUS_READY, ///< Ready to run
|
||||
THREADSTATUS_WAIT_HLE_EVENT, ///< Waiting for hle event to finish
|
||||
THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC
|
||||
THREADSTATUS_WAIT_IPC, ///< Waiting for the reply from an IPC request
|
||||
THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false
|
||||
THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true
|
||||
THREADSTATUS_WAIT_MUTEX, ///< Waiting due to an ArbitrateLock/WaitProcessWideKey svc
|
||||
THREADSTATUS_WAIT_ARB, ///< Waiting due to a SignalToAddress/WaitForAddress svc
|
||||
THREADSTATUS_DORMANT, ///< Created but not yet made ready
|
||||
THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated
|
||||
enum class ThreadStatus {
|
||||
Running, ///< Currently running
|
||||
Ready, ///< Ready to run
|
||||
WaitHLEEvent, ///< Waiting for hle event to finish
|
||||
WaitSleep, ///< Waiting due to a SleepThread SVC
|
||||
WaitIPC, ///< Waiting for the reply from an IPC request
|
||||
WaitSynchAny, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false
|
||||
WaitSynchAll, ///< Waiting due to WaitSynchronizationN with wait_all = true
|
||||
WaitMutex, ///< Waiting due to an ArbitrateLock/WaitProcessWideKey svc
|
||||
WaitArb, ///< Waiting due to a SignalToAddress/WaitForAddress svc
|
||||
Dormant, ///< Created but not yet made ready
|
||||
Dead ///< Run to completion, or forcefully terminated
|
||||
};
|
||||
|
||||
enum class ThreadWakeupReason {
|
||||
@@ -182,6 +182,14 @@ public:
|
||||
return tls_address;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the value of the TPIDR_EL0 Read/Write system register for this thread.
|
||||
* @returns The value of the TPIDR_EL0 register.
|
||||
*/
|
||||
u64 GetTPIDR_EL0() const {
|
||||
return tpidr_el0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the address of the current thread's command buffer, located in the TLS.
|
||||
* @returns VAddr of the thread's command buffer.
|
||||
@@ -194,14 +202,14 @@ public:
|
||||
* with wait_all = true.
|
||||
*/
|
||||
bool IsSleepingOnWaitAll() const {
|
||||
return status == THREADSTATUS_WAIT_SYNCH_ALL;
|
||||
return status == ThreadStatus::WaitSynchAll;
|
||||
}
|
||||
|
||||
ARM_Interface::ThreadContext context;
|
||||
|
||||
u32 thread_id;
|
||||
|
||||
u32 status;
|
||||
ThreadStatus status;
|
||||
VAddr entry_point;
|
||||
VAddr stack_top;
|
||||
|
||||
@@ -213,6 +221,7 @@ public:
|
||||
s32 processor_id;
|
||||
|
||||
VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread
|
||||
u64 tpidr_el0; ///< TPIDR_EL0 read/write system register.
|
||||
|
||||
SharedPtr<Process> owner_process; ///< Process that owns this thread
|
||||
|
||||
|
||||
@@ -38,9 +38,9 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
|
||||
|
||||
for (const auto& thread : waiting_threads) {
|
||||
// The list of waiting threads must not contain threads that are not waiting to be awakened.
|
||||
ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
|
||||
thread->status == THREADSTATUS_WAIT_SYNCH_ALL ||
|
||||
thread->status == THREADSTATUS_WAIT_HLE_EVENT,
|
||||
ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
|
||||
thread->status == ThreadStatus::WaitSynchAll ||
|
||||
thread->status == ThreadStatus::WaitHLEEvent,
|
||||
"Inconsistent thread statuses in waiting_threads");
|
||||
|
||||
if (thread->current_priority >= candidate_priority)
|
||||
@@ -49,10 +49,10 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
|
||||
if (ShouldWait(thread.get()))
|
||||
continue;
|
||||
|
||||
// A thread is ready to run if it's either in THREADSTATUS_WAIT_SYNCH_ANY or
|
||||
// in THREADSTATUS_WAIT_SYNCH_ALL and the rest of the objects it is waiting on are ready.
|
||||
// A thread is ready to run if it's either in ThreadStatus::WaitSynchAny or
|
||||
// in ThreadStatus::WaitSynchAll and the rest of the objects it is waiting on are ready.
|
||||
bool ready_to_run = true;
|
||||
if (thread->status == THREADSTATUS_WAIT_SYNCH_ALL) {
|
||||
if (thread->status == ThreadStatus::WaitSynchAll) {
|
||||
ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
|
||||
[&thread](const SharedPtr<WaitObject>& object) {
|
||||
return object->ShouldWait(thread.get());
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/acc/acc.h"
|
||||
@@ -24,18 +25,17 @@ struct UserData {
|
||||
static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size");
|
||||
|
||||
struct ProfileBase {
|
||||
u8 user_id[0x10];
|
||||
u128 user_id;
|
||||
u64 timestamp;
|
||||
u8 username[0x20];
|
||||
std::array<u8, 0x20> username;
|
||||
};
|
||||
static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase structure has incorrect size");
|
||||
|
||||
using Uid = std::array<u64, 2>;
|
||||
static constexpr Uid DEFAULT_USER_ID{0x10ull, 0x20ull};
|
||||
static constexpr u128 DEFAULT_USER_ID{1ull, 0ull};
|
||||
|
||||
class IProfile final : public ServiceFramework<IProfile> {
|
||||
public:
|
||||
IProfile() : ServiceFramework("IProfile") {
|
||||
IProfile(u128 user_id) : ServiceFramework("IProfile"), user_id(user_id) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Get"},
|
||||
{1, &IProfile::GetBase, "GetBase"},
|
||||
@@ -48,11 +48,18 @@ public:
|
||||
private:
|
||||
void GetBase(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
|
||||
// TODO(Subv): Retrieve this information from somewhere.
|
||||
ProfileBase profile_base{};
|
||||
profile_base.user_id = user_id;
|
||||
profile_base.username = {'y', 'u', 'z', 'u'};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 16};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw(profile_base);
|
||||
}
|
||||
|
||||
u128 user_id; ///< The user id this profile refers to.
|
||||
};
|
||||
|
||||
class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
|
||||
@@ -75,14 +82,16 @@ private:
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(true); // TODO: Check when this is supposed to return true and when not
|
||||
rb.Push(false); // TODO: Check when this is supposed to return true and when not
|
||||
}
|
||||
|
||||
void GetAccountId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(0x12345678ABCDEF);
|
||||
// TODO(Subv): Find out what this actually does and implement it. Stub it as an error for
|
||||
// now since we do not implement NNID. Returning a bogus id here will cause games to send
|
||||
// invalid IPC requests after ListOpenUsers is called.
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultCode(-1));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -95,25 +104,29 @@ void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID};
|
||||
ctx.WriteBuffer(user_ids.data(), user_ids.size());
|
||||
// TODO(Subv): There is only one user for now.
|
||||
const std::vector<u128> user_ids = {DEFAULT_USER_ID};
|
||||
ctx.WriteBuffer(user_ids);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Module::Interface::ListOpenUsers(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID};
|
||||
ctx.WriteBuffer(user_ids.data(), user_ids.size());
|
||||
// TODO(Subv): There is only one user for now.
|
||||
const std::vector<u128> user_ids = {DEFAULT_USER_ID};
|
||||
ctx.WriteBuffer(user_ids);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u128 user_id = rp.PopRaw<u128>();
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IProfile>();
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
rb.PushIpcInterface<IProfile>(user_id);
|
||||
LOG_DEBUG(Service_ACC, "called user_id=0x{:016X}{:016X}", user_id[1], user_id[0]);
|
||||
}
|
||||
|
||||
void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
@@ -12,7 +12,7 @@ class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
public:
|
||||
Interface(std::shared_ptr<Module> module, const char* name);
|
||||
explicit Interface(std::shared_ptr<Module> module, const char* name);
|
||||
|
||||
void GetUserExistence(Kernel::HLERequestContext& ctx);
|
||||
void ListAllUsers(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
|
||||
class ISelfController final : public ServiceFramework<ISelfController> {
|
||||
public:
|
||||
ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
|
||||
explicit ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
|
||||
|
||||
private:
|
||||
void SetFocusHandlingMode(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Service::AM {
|
||||
|
||||
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
|
||||
public:
|
||||
ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
|
||||
explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
|
||||
: ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace AM {
|
||||
|
||||
class AppletAE final : public ServiceFramework<AppletAE> {
|
||||
public:
|
||||
AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
|
||||
explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
|
||||
~AppletAE() = default;
|
||||
|
||||
private:
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Service::AM {
|
||||
|
||||
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
|
||||
public:
|
||||
IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
|
||||
explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
|
||||
: ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace AM {
|
||||
|
||||
class AppletOE final : public ServiceFramework<AppletOE> {
|
||||
public:
|
||||
AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
|
||||
explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
|
||||
~AppletOE() = default;
|
||||
|
||||
private:
|
||||
|
||||
@@ -20,6 +20,21 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
enum class PerformanceConfiguration : u32 {
|
||||
Config1 = 0x00010000,
|
||||
Config2 = 0x00010001,
|
||||
Config3 = 0x00010002,
|
||||
Config4 = 0x00020000,
|
||||
Config5 = 0x00020001,
|
||||
Config6 = 0x00020002,
|
||||
Config7 = 0x00020003,
|
||||
Config8 = 0x00020004,
|
||||
Config9 = 0x00020005,
|
||||
Config10 = 0x00020006,
|
||||
Config11 = 0x92220007,
|
||||
Config12 = 0x92220008,
|
||||
};
|
||||
|
||||
void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
@@ -40,7 +55,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(0); // Performance configuration
|
||||
rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1));
|
||||
|
||||
LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Service::APM {
|
||||
|
||||
class APM final : public ServiceFramework<APM> {
|
||||
public:
|
||||
APM(std::shared_ptr<Module> apm, const char* name);
|
||||
explicit APM(std::shared_ptr<Module> apm, const char* name);
|
||||
~APM() = default;
|
||||
|
||||
private:
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core_timing.h"
|
||||
@@ -167,8 +168,8 @@ void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const std::string audio_interface = "AudioInterface";
|
||||
ctx.WriteBuffer(audio_interface.c_str(), audio_interface.size());
|
||||
constexpr std::array<char, 15> audio_interface{{"AudioInterface"}};
|
||||
ctx.WriteBuffer(audio_interface);
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core_timing.h"
|
||||
@@ -17,7 +19,7 @@ constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 200)};
|
||||
|
||||
class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
|
||||
public:
|
||||
IAudioRenderer(AudioRendererParameter audren_params)
|
||||
explicit IAudioRenderer(AudioRendererParameter audren_params)
|
||||
: ServiceFramework("IAudioRenderer"), worker_params(audren_params) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetAudioRendererSampleRate"},
|
||||
@@ -176,7 +178,7 @@ private:
|
||||
struct UpdateDataHeader {
|
||||
UpdateDataHeader() {}
|
||||
|
||||
UpdateDataHeader(const AudioRendererParameter& config) {
|
||||
explicit UpdateDataHeader(const AudioRendererParameter& config) {
|
||||
revision = Common::MakeMagic('R', 'E', 'V', '4'); // 5.1.0 Revision
|
||||
behavior_size = 0xb0;
|
||||
memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10;
|
||||
@@ -298,8 +300,8 @@ private:
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const std::string audio_interface = "AudioInterface";
|
||||
ctx.WriteBuffer(audio_interface.c_str(), audio_interface.size());
|
||||
constexpr std::array<char, 15> audio_interface{{"AudioInterface"}};
|
||||
ctx.WriteBuffer(audio_interface);
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -323,8 +325,8 @@ private:
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const std::string audio_interface = "AudioDevice";
|
||||
ctx.WriteBuffer(audio_interface.c_str(), audio_interface.size());
|
||||
constexpr std::array<char, 12> audio_interface{{"AudioDevice"}};
|
||||
ctx.WriteBuffer(audio_interface);
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -12,7 +12,7 @@ class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
public:
|
||||
Interface(std::shared_ptr<Module> module, const char* name);
|
||||
explicit Interface(std::shared_ptr<Module> module, const char* name);
|
||||
|
||||
void CreateBcatService(Kernel::HLERequestContext& ctx);
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
public:
|
||||
Interface(std::shared_ptr<Module> module, const char* name);
|
||||
explicit Interface(std::shared_ptr<Module> module, const char* name);
|
||||
|
||||
void ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx);
|
||||
void ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -193,6 +193,10 @@ ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
|
||||
if (dir == nullptr)
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
auto filename = FileUtil::GetFilename(path);
|
||||
// TODO(Subv): Some games use the '/' path, find out what this means.
|
||||
if (filename.empty())
|
||||
return MakeResult(FileSys::EntryType::Directory);
|
||||
|
||||
if (dir->GetFile(filename) != nullptr)
|
||||
return MakeResult(FileSys::EntryType::File);
|
||||
if (dir->GetSubdirectory(filename) != nullptr)
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
@@ -26,7 +34,7 @@ enum class StorageId : u8 {
|
||||
|
||||
class IStorage final : public ServiceFramework<IStorage> {
|
||||
public:
|
||||
IStorage(FileSys::VirtualFile backend_)
|
||||
explicit IStorage(FileSys::VirtualFile backend_)
|
||||
: ServiceFramework("IStorage"), backend(std::move(backend_)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IStorage::Read, "Read"}, {1, nullptr, "Write"}, {2, nullptr, "Flush"},
|
||||
@@ -133,19 +141,19 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u8> data = ctx.ReadBuffer();
|
||||
std::vector<u8> actual_data(length);
|
||||
const std::vector<u8> data = ctx.ReadBuffer();
|
||||
|
||||
ASSERT_MSG(
|
||||
data.size() <= length,
|
||||
static_cast<s64>(data.size()) <= length,
|
||||
"Attempting to write more data than requested (requested={:016X}, actual={:016X}).",
|
||||
length, data.size());
|
||||
|
||||
std::copy(data.begin(), data.end(), actual_data.begin());
|
||||
// Write the data to the Storage backend
|
||||
auto written = backend->WriteBytes(data, offset);
|
||||
const auto write_size =
|
||||
static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length));
|
||||
const std::size_t written = backend->Write(data.data(), write_size, offset);
|
||||
|
||||
ASSERT_MSG(written == length,
|
||||
ASSERT_MSG(static_cast<s64>(written) == length,
|
||||
"Could not write all bytes to file (requested={:016X}, actual={:016X}).", length,
|
||||
written);
|
||||
|
||||
@@ -223,23 +231,20 @@ private:
|
||||
LOG_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);
|
||||
const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry);
|
||||
|
||||
// Cap at total number of entries.
|
||||
u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
|
||||
const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
|
||||
|
||||
// Read the data from the Directory backend
|
||||
std::vector<FileSys::Entry> entry_data(entries.begin() + next_entry_index,
|
||||
entries.begin() + next_entry_index + actual_entries);
|
||||
// Determine data start and end
|
||||
const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
|
||||
const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
|
||||
const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
|
||||
|
||||
next_entry_index += actual_entries;
|
||||
|
||||
// Convert the data into a byte array
|
||||
std::vector<u8> output(entry_data.size() * sizeof(FileSys::Entry));
|
||||
std::memcpy(output.data(), entry_data.data(), output.size());
|
||||
|
||||
// Write the data to memory
|
||||
ctx.WriteBuffer(output);
|
||||
ctx.WriteBuffer(begin, range_size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -12,7 +12,7 @@ class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
public:
|
||||
Interface(std::shared_ptr<Module> module, const char* name);
|
||||
explicit Interface(std::shared_ptr<Module> module, const char* name);
|
||||
|
||||
void CreateFriendService(Kernel::HLERequestContext& ctx);
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
public:
|
||||
Interface(std::shared_ptr<Module> module, const char* name);
|
||||
explicit Interface(std::shared_ptr<Module> module, const char* name);
|
||||
|
||||
void CreateUserInterface(Kernel::HLERequestContext& ctx);
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
public:
|
||||
Interface(std::shared_ptr<Module> module, const char* name);
|
||||
explicit Interface(std::shared_ptr<Module> module, const char* name);
|
||||
|
||||
void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx);
|
||||
void CreateGeneralService(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -119,7 +119,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
|
||||
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
|
||||
LOG_DEBUG(Service_NS, "called, language_code=%lx", language_code);
|
||||
LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code);
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
std::vector<u32> font_codes;
|
||||
std::vector<u32> font_offsets;
|
||||
@@ -132,9 +132,9 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
|
||||
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);
|
||||
ctx.WriteBuffer(font_codes, 0);
|
||||
ctx.WriteBuffer(font_offsets, 1);
|
||||
ctx.WriteBuffer(font_sizes, 2);
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u8>(static_cast<u8>(LoadState::Done)); // Fonts Loaded
|
||||
|
||||
@@ -17,7 +17,7 @@ class nvmap;
|
||||
|
||||
class nvdisp_disp0 final : public nvdevice {
|
||||
public:
|
||||
nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev) : nvdevice(), nvmap_dev(std::move(nvmap_dev)) {}
|
||||
explicit nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {}
|
||||
~nvdisp_disp0() = default;
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
|
||||
@@ -18,7 +18,7 @@ class nvmap;
|
||||
|
||||
class nvhost_as_gpu final : public nvdevice {
|
||||
public:
|
||||
nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {}
|
||||
explicit nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {}
|
||||
~nvhost_as_gpu() override = default;
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
|
||||
@@ -18,7 +18,7 @@ constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8);
|
||||
|
||||
class nvhost_gpu final : public nvdevice {
|
||||
public:
|
||||
nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {}
|
||||
explicit nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {}
|
||||
~nvhost_gpu() override = default;
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
|
||||
/// Returns a pointer to one of the available devices, identified by its name.
|
||||
template <typename T>
|
||||
std::shared_ptr<T> GetDevice(std::string name) {
|
||||
std::shared_ptr<T> GetDevice(const std::string& name) {
|
||||
auto itr = devices.find(name);
|
||||
if (itr == devices.end())
|
||||
return nullptr;
|
||||
|
||||
@@ -23,15 +23,10 @@ constexpr u64 frame_ticks = static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / SCREE
|
||||
|
||||
NVFlinger::NVFlinger() {
|
||||
// Add the different displays to the list of displays.
|
||||
Display default_{0, "Default"};
|
||||
Display external{1, "External"};
|
||||
Display edid{2, "Edid"};
|
||||
Display internal{3, "Internal"};
|
||||
|
||||
displays.emplace_back(default_);
|
||||
displays.emplace_back(external);
|
||||
displays.emplace_back(edid);
|
||||
displays.emplace_back(internal);
|
||||
displays.emplace_back(0, "Default");
|
||||
displays.emplace_back(1, "External");
|
||||
displays.emplace_back(2, "Edid");
|
||||
displays.emplace_back(3, "Internal");
|
||||
|
||||
// Schedule the screen composition events
|
||||
composition_event =
|
||||
|
||||
@@ -12,7 +12,7 @@ class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
public:
|
||||
Interface(std::shared_ptr<Module> module, const char* name);
|
||||
explicit Interface(std::shared_ptr<Module> module, const char* name);
|
||||
|
||||
void CreateService(Kernel::HLERequestContext& ctx);
|
||||
void CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -31,7 +31,7 @@ void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
|
||||
LanguageCode::ZH_HANS,
|
||||
LanguageCode::ZH_HANT,
|
||||
}};
|
||||
ctx.WriteBuffer(available_language_codes.data(), available_language_codes.size());
|
||||
ctx.WriteBuffer(available_language_codes);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Service::SM {
|
||||
/// Interface to "sm:" service
|
||||
class SM final : public ServiceFramework<SM> {
|
||||
public:
|
||||
SM(std::shared_ptr<ServiceManager> service_manager);
|
||||
explicit SM(std::shared_ptr<ServiceManager> service_manager);
|
||||
~SM() override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -12,7 +12,7 @@ class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
public:
|
||||
Interface(std::shared_ptr<Module> module, const char* name);
|
||||
explicit Interface(std::shared_ptr<Module> module, const char* name);
|
||||
|
||||
void GetRandomBytes(Kernel::HLERequestContext& ctx);
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
public:
|
||||
Interface(std::shared_ptr<Module> time, const char* name);
|
||||
explicit Interface(std::shared_ptr<Module> time, const char* name);
|
||||
|
||||
void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx);
|
||||
void GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -579,7 +579,7 @@ private:
|
||||
|
||||
class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
|
||||
public:
|
||||
ISystemDisplayService() : ServiceFramework("ISystemDisplayService") {
|
||||
explicit ISystemDisplayService() : ServiceFramework("ISystemDisplayService") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{1200, nullptr, "GetZOrderCountMin"},
|
||||
{1202, nullptr, "GetZOrderCountMax"},
|
||||
@@ -777,7 +777,7 @@ private:
|
||||
|
||||
class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
|
||||
public:
|
||||
IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
|
||||
explicit IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
|
||||
~IApplicationDisplayService() = default;
|
||||
|
||||
private:
|
||||
|
||||
@@ -24,8 +24,8 @@ class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
public:
|
||||
Interface(std::shared_ptr<Module> module, const char* name,
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
|
||||
explicit Interface(std::shared_ptr<Module> module, const char* name,
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
|
||||
|
||||
void GetDisplayService(Kernel::HLERequestContext& ctx);
|
||||
|
||||
|
||||
@@ -83,16 +83,13 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
|
||||
VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR};
|
||||
for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
|
||||
"subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
|
||||
const VAddr load_addr = next_load_addr;
|
||||
const FileSys::VirtualFile module_file = dir->GetFile(module);
|
||||
if (module_file != nullptr)
|
||||
if (module_file != nullptr) {
|
||||
const VAddr load_addr = next_load_addr;
|
||||
next_load_addr = AppLoader_NSO::LoadModule(module_file, load_addr);
|
||||
if (next_load_addr) {
|
||||
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
|
||||
// Register module with GDBStub
|
||||
GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
|
||||
} else {
|
||||
next_load_addr = load_addr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,8 +87,8 @@ const char* GetFileTypeString(FileType type) {
|
||||
* Get a loader for a file with a specific type
|
||||
* @param file The file to load
|
||||
* @param type The type of the file
|
||||
* @param filename the file name (without path)
|
||||
* @param filepath the file full path (with name)
|
||||
* @param file the file to retrieve the loader for
|
||||
* @param type the file type
|
||||
* @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type
|
||||
*/
|
||||
static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileType type) {
|
||||
|
||||
@@ -154,7 +154,7 @@ public:
|
||||
/**
|
||||
* Get the RomFS of the application
|
||||
* Since the RomFS can be huge, we return a file reference instead of copying to a buffer
|
||||
* @param file The file containing the RomFS
|
||||
* @param dir The directory containing the RomFS
|
||||
* @return ResultStatus result of function
|
||||
*/
|
||||
virtual ResultStatus ReadRomFS(FileSys::VirtualFile& dir) {
|
||||
@@ -193,8 +193,8 @@ extern const std::initializer_list<Kernel::AddressMapping> default_address_mappi
|
||||
|
||||
/**
|
||||
* Identifies a bootable file and return a suitable loader
|
||||
* @param filename String filename of bootable file
|
||||
* @return best loader for this file
|
||||
* @param file The bootable file
|
||||
* @return the best loader for this file
|
||||
*/
|
||||
std::unique_ptr<AppLoader> GetLoader(FileSys::VirtualFile file);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/file_util.h"
|
||||
@@ -21,7 +22,7 @@
|
||||
|
||||
namespace Loader {
|
||||
|
||||
AppLoader_NCA::AppLoader_NCA(FileSys::VirtualFile file) : AppLoader(file) {}
|
||||
AppLoader_NCA::AppLoader_NCA(FileSys::VirtualFile file) : AppLoader(std::move(file)) {}
|
||||
|
||||
FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& file) {
|
||||
// TODO(DarkLordZach): Assuming everything is decrypted. Add crypto support.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
@@ -48,7 +49,7 @@ struct ModHeader {
|
||||
};
|
||||
static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size.");
|
||||
|
||||
AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file) : AppLoader(file) {}
|
||||
AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file) : AppLoader(std::move(file)) {}
|
||||
|
||||
FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& file) {
|
||||
// Read NSO header
|
||||
|
||||
@@ -55,41 +55,32 @@ AppLoader_NSO::AppLoader_NSO(FileSys::VirtualFile file) : AppLoader(std::move(fi
|
||||
|
||||
FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& file) {
|
||||
u32 magic = 0;
|
||||
file->ReadObject(&magic);
|
||||
|
||||
if (Common::MakeMagic('N', 'S', 'O', '0') == magic) {
|
||||
return FileType::NSO;
|
||||
if (file->ReadObject(&magic) != sizeof(magic)) {
|
||||
return FileType::Error;
|
||||
}
|
||||
|
||||
return FileType::Error;
|
||||
if (Common::MakeMagic('N', 'S', 'O', '0') != magic) {
|
||||
return FileType::Error;
|
||||
}
|
||||
|
||||
return FileType::NSO;
|
||||
}
|
||||
|
||||
static std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data,
|
||||
const NsoSegmentHeader& header) {
|
||||
std::vector<u8> uncompressed_data(header.size);
|
||||
const int bytes_uncompressed = LZ4_decompress_safe(
|
||||
reinterpret_cast<const char*>(compressed_data.data()),
|
||||
reinterpret_cast<char*>(uncompressed_data.data()), compressed_data.size(), header.size);
|
||||
const int bytes_uncompressed =
|
||||
LZ4_decompress_safe(reinterpret_cast<const char*>(compressed_data.data()),
|
||||
reinterpret_cast<char*>(uncompressed_data.data()),
|
||||
static_cast<int>(compressed_data.size()), header.size);
|
||||
|
||||
ASSERT_MSG(bytes_uncompressed == header.size && bytes_uncompressed == uncompressed_data.size(),
|
||||
ASSERT_MSG(bytes_uncompressed == static_cast<int>(header.size) &&
|
||||
bytes_uncompressed == static_cast<int>(uncompressed_data.size()),
|
||||
"{} != {} != {}", bytes_uncompressed, header.size, uncompressed_data.size());
|
||||
|
||||
return uncompressed_data;
|
||||
}
|
||||
|
||||
static std::vector<u8> ReadSegment(FileUtil::IOFile& file, const NsoSegmentHeader& header,
|
||||
size_t compressed_size) {
|
||||
std::vector<u8> compressed_data(compressed_size);
|
||||
|
||||
file.Seek(header.offset, SEEK_SET);
|
||||
if (compressed_size != file.ReadBytes(compressed_data.data(), compressed_size)) {
|
||||
LOG_CRITICAL(Loader, "Failed to read {} NSO LZ4 compressed bytes", compressed_size);
|
||||
return {};
|
||||
}
|
||||
|
||||
return DecompressSegment(compressed_data, header);
|
||||
}
|
||||
|
||||
static constexpr u32 PageAlignSize(u32 size) {
|
||||
return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
namespace ArmTests {
|
||||
|
||||
static Memory::PageTable* page_table = nullptr;
|
||||
|
||||
TestEnvironment::TestEnvironment(bool mutable_memory_)
|
||||
: mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
|
||||
|
||||
@@ -67,10 +65,13 @@ boost::optional<bool> TestEnvironment::TestMemory::IsValidAddress(VAddr addr) {
|
||||
}
|
||||
|
||||
boost::optional<u8> TestEnvironment::TestMemory::Read8(VAddr addr) {
|
||||
auto iter = data.find(addr);
|
||||
const auto iter = data.find(addr);
|
||||
|
||||
if (iter == data.end()) {
|
||||
return addr; // Some arbitrary data
|
||||
// Some arbitrary data
|
||||
return static_cast<u8>(addr);
|
||||
}
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -9,6 +11,10 @@
|
||||
#include "common/common_types.h"
|
||||
#include "core/memory_hook.h"
|
||||
|
||||
namespace Memory {
|
||||
struct PageTable;
|
||||
}
|
||||
|
||||
namespace ArmTests {
|
||||
|
||||
struct WriteRecord {
|
||||
@@ -79,6 +85,7 @@ private:
|
||||
bool mutable_memory;
|
||||
std::shared_ptr<TestMemory> test_memory;
|
||||
std::vector<WriteRecord> write_records;
|
||||
Memory::PageTable* page_table = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ArmTests
|
||||
|
||||
@@ -317,8 +317,6 @@ std::vector<Texture::FullTextureInfo> Maxwell3D::GetStageTextures(Regs::ShaderSt
|
||||
auto& tex_info_buffer = fragment_shader.const_buffers[regs.tex_cb_index];
|
||||
ASSERT(tex_info_buffer.enabled && tex_info_buffer.address != 0);
|
||||
|
||||
GPUVAddr tic_base_address = regs.tic.TICAddress();
|
||||
|
||||
GPUVAddr tex_info_buffer_end = tex_info_buffer.address + tex_info_buffer.size;
|
||||
|
||||
// Offset into the texture constbuffer where the texture info begins.
|
||||
|
||||
@@ -20,7 +20,11 @@ GPU::GPU() {
|
||||
|
||||
GPU::~GPU() = default;
|
||||
|
||||
const Tegra::Engines::Maxwell3D& GPU::Get3DEngine() const {
|
||||
const Engines::Maxwell3D& GPU::Maxwell3D() const {
|
||||
return *maxwell_3d;
|
||||
}
|
||||
|
||||
Engines::Maxwell3D& GPU::Maxwell3D() {
|
||||
return *maxwell_3d;
|
||||
}
|
||||
|
||||
|
||||
@@ -93,15 +93,14 @@ public:
|
||||
/// Processes a command list stored at the specified address in GPU memory.
|
||||
void ProcessCommandList(GPUVAddr address, u32 size);
|
||||
|
||||
/// Returns a const reference to the Maxwell3D GPU engine.
|
||||
const Engines::Maxwell3D& Maxwell3D() const;
|
||||
|
||||
/// Returns a reference to the Maxwell3D GPU engine.
|
||||
const Engines::Maxwell3D& Get3DEngine() const;
|
||||
Engines::Maxwell3D& Maxwell3D();
|
||||
|
||||
std::unique_ptr<MemoryManager> memory_manager;
|
||||
|
||||
Engines::Maxwell3D& Maxwell3D() {
|
||||
return *maxwell_3d;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Writes a single register in the engine bound to the specified subchannel
|
||||
void WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params);
|
||||
|
||||
@@ -634,8 +634,8 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
|
||||
u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint program,
|
||||
u32 current_bindpoint,
|
||||
const std::vector<GLShader::ConstBufferEntry>& entries) {
|
||||
auto& gpu = Core::System::GetInstance().GPU();
|
||||
auto& maxwell3d = gpu.Get3DEngine();
|
||||
const auto& gpu = Core::System::GetInstance().GPU();
|
||||
const auto& maxwell3d = gpu.Maxwell3D();
|
||||
|
||||
// Reset all buffer draw state for this stage.
|
||||
for (auto& buffer : state.draw.const_buffers[static_cast<size_t>(stage)]) {
|
||||
@@ -644,7 +644,7 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr
|
||||
}
|
||||
|
||||
// Upload only the enabled buffers from the 16 constbuffers of each shader stage
|
||||
auto& shader_stage = maxwell3d.state.shader_stages[static_cast<size_t>(stage)];
|
||||
const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<size_t>(stage)];
|
||||
|
||||
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
|
||||
const auto& used_buffer = entries[bindpoint];
|
||||
@@ -700,8 +700,8 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr
|
||||
|
||||
u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program, u32 current_unit,
|
||||
const std::vector<GLShader::SamplerEntry>& entries) {
|
||||
auto& gpu = Core::System::GetInstance().GPU();
|
||||
auto& maxwell3d = gpu.Get3DEngine();
|
||||
const auto& gpu = Core::System::GetInstance().GPU();
|
||||
const auto& maxwell3d = gpu.Maxwell3D();
|
||||
|
||||
ASSERT_MSG(current_unit + entries.size() <= std::size(state.texture_units),
|
||||
"Exceeded the number of active textures.");
|
||||
|
||||
@@ -216,7 +216,7 @@ public:
|
||||
}
|
||||
|
||||
/// Returns a GLSL string representing the current state of the register
|
||||
const std::string GetActiveString() {
|
||||
std::string GetActiveString() {
|
||||
declr_type.insert(active_type);
|
||||
return GetPrefixString(active_type) + std::to_string(index) + '_' + suffix;
|
||||
}
|
||||
@@ -518,7 +518,7 @@ public:
|
||||
|
||||
private:
|
||||
/// Build GLSL conversion function, e.g. floatBitsToInt, intBitsToFloat, etc.
|
||||
const std::string GetGLSLConversionFunc(GLSLRegister::Type src, GLSLRegister::Type dest) 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]);
|
||||
@@ -1405,7 +1405,7 @@ private:
|
||||
|
||||
// TEXS has two destination registers. RG goes into gpr0+0 and gpr0+1, and BA
|
||||
// goes into gpr28+0 and gpr28+1
|
||||
size_t offset{};
|
||||
size_t texs_offset{};
|
||||
|
||||
for (const auto& dest : {instr.gpr0.Value(), instr.gpr28.Value()}) {
|
||||
for (unsigned elem = 0; elem < 2; ++elem) {
|
||||
@@ -1413,7 +1413,8 @@ private:
|
||||
// Skip disabled components
|
||||
continue;
|
||||
}
|
||||
regs.SetRegisterToFloat(dest, elem + offset, texture, 1, 4, false, elem);
|
||||
regs.SetRegisterToFloat(dest, elem + texs_offset, texture, 1, 4, false,
|
||||
elem);
|
||||
}
|
||||
|
||||
if (!instr.texs.HasTwoDestinations()) {
|
||||
@@ -1421,7 +1422,7 @@ private:
|
||||
break;
|
||||
}
|
||||
|
||||
offset += 2;
|
||||
texs_offset += 2;
|
||||
}
|
||||
--shader.scope;
|
||||
shader.AddLine("}");
|
||||
@@ -1463,7 +1464,6 @@ private:
|
||||
op_b = "abs(" + op_b + ')';
|
||||
}
|
||||
|
||||
using Tegra::Shader::Pred;
|
||||
// We can't use the constant predicate as destination.
|
||||
ASSERT(instr.fsetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
|
||||
|
||||
@@ -1500,7 +1500,6 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
using Tegra::Shader::Pred;
|
||||
// We can't use the constant predicate as destination.
|
||||
ASSERT(instr.isetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
|
||||
|
||||
@@ -1528,7 +1527,6 @@ private:
|
||||
std::string op_b =
|
||||
GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0);
|
||||
|
||||
using Tegra::Shader::Pred;
|
||||
// We can't use the constant predicate as destination.
|
||||
ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
|
||||
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
namespace GLShader {
|
||||
|
||||
namespace Impl {
|
||||
void SetShaderUniformBlockBinding(GLuint shader, const char* name,
|
||||
Maxwell3D::Regs::ShaderStage binding, size_t expected_size) {
|
||||
static void SetShaderUniformBlockBinding(GLuint shader, const char* name,
|
||||
Maxwell3D::Regs::ShaderStage binding,
|
||||
size_t expected_size) {
|
||||
GLuint ub_index = glGetUniformBlockIndex(shader, name);
|
||||
if (ub_index != GL_INVALID_INDEX) {
|
||||
GLint ub_size = 0;
|
||||
|
||||
@@ -21,7 +21,6 @@ using Tegra::Engines::Maxwell3D;
|
||||
|
||||
namespace Impl {
|
||||
void SetShaderUniformBlockBindings(GLuint shader);
|
||||
void SetShaderSamplerBindings(GLuint shader);
|
||||
} // namespace Impl
|
||||
|
||||
/// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned
|
||||
|
||||
@@ -181,30 +181,34 @@ void OpenGLState::Apply() const {
|
||||
}
|
||||
|
||||
// Textures
|
||||
for (int i = 0; i < std::size(texture_units); ++i) {
|
||||
if (texture_units[i].texture_2d != cur_state.texture_units[i].texture_2d) {
|
||||
glActiveTexture(TextureUnits::MaxwellTexture(i).Enum());
|
||||
glBindTexture(GL_TEXTURE_2D, texture_units[i].texture_2d);
|
||||
for (std::size_t i = 0; i < std::size(texture_units); ++i) {
|
||||
const auto& texture_unit = texture_units[i];
|
||||
const auto& cur_state_texture_unit = cur_state.texture_units[i];
|
||||
|
||||
if (texture_unit.texture_2d != cur_state_texture_unit.texture_2d) {
|
||||
glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum());
|
||||
glBindTexture(GL_TEXTURE_2D, texture_unit.texture_2d);
|
||||
}
|
||||
if (texture_units[i].sampler != cur_state.texture_units[i].sampler) {
|
||||
glBindSampler(static_cast<GLuint>(i), texture_units[i].sampler);
|
||||
if (texture_unit.sampler != cur_state_texture_unit.sampler) {
|
||||
glBindSampler(static_cast<GLuint>(i), texture_unit.sampler);
|
||||
}
|
||||
// Update the texture swizzle
|
||||
if (texture_units[i].swizzle.r != cur_state.texture_units[i].swizzle.r ||
|
||||
texture_units[i].swizzle.g != cur_state.texture_units[i].swizzle.g ||
|
||||
texture_units[i].swizzle.b != cur_state.texture_units[i].swizzle.b ||
|
||||
texture_units[i].swizzle.a != cur_state.texture_units[i].swizzle.a) {
|
||||
std::array<GLint, 4> mask = {texture_units[i].swizzle.r, texture_units[i].swizzle.g,
|
||||
texture_units[i].swizzle.b, texture_units[i].swizzle.a};
|
||||
if (texture_unit.swizzle.r != cur_state_texture_unit.swizzle.r ||
|
||||
texture_unit.swizzle.g != cur_state_texture_unit.swizzle.g ||
|
||||
texture_unit.swizzle.b != cur_state_texture_unit.swizzle.b ||
|
||||
texture_unit.swizzle.a != cur_state_texture_unit.swizzle.a) {
|
||||
std::array<GLint, 4> mask = {texture_unit.swizzle.r, texture_unit.swizzle.g,
|
||||
texture_unit.swizzle.b, texture_unit.swizzle.a};
|
||||
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask.data());
|
||||
}
|
||||
}
|
||||
|
||||
// Constbuffers
|
||||
for (u32 stage = 0; stage < draw.const_buffers.size(); ++stage) {
|
||||
for (u32 buffer_id = 0; buffer_id < draw.const_buffers[stage].size(); ++buffer_id) {
|
||||
auto& current = cur_state.draw.const_buffers[stage][buffer_id];
|
||||
auto& new_state = draw.const_buffers[stage][buffer_id];
|
||||
for (std::size_t stage = 0; stage < draw.const_buffers.size(); ++stage) {
|
||||
for (std::size_t buffer_id = 0; buffer_id < draw.const_buffers[stage].size(); ++buffer_id) {
|
||||
const auto& current = cur_state.draw.const_buffers[stage][buffer_id];
|
||||
const auto& new_state = draw.const_buffers[stage][buffer_id];
|
||||
|
||||
if (current.enabled != new_state.enabled || current.bindpoint != new_state.bindpoint ||
|
||||
current.ssbo != new_state.ssbo) {
|
||||
if (new_state.enabled) {
|
||||
|
||||
@@ -336,9 +336,9 @@ void GraphicsSurfaceWidget::OnUpdate() {
|
||||
// TODO: Store a reference to the registers in the debug context instead of accessing them
|
||||
// directly...
|
||||
|
||||
auto& registers = gpu.Get3DEngine().regs;
|
||||
auto& rt = registers.rt[static_cast<size_t>(surface_source) -
|
||||
static_cast<size_t>(Source::RenderTarget0)];
|
||||
const auto& registers = gpu.Maxwell3D().regs;
|
||||
const auto& rt = registers.rt[static_cast<size_t>(surface_source) -
|
||||
static_cast<size_t>(Source::RenderTarget0)];
|
||||
|
||||
surface_address = rt.Address();
|
||||
surface_width = rt.width;
|
||||
|
||||
@@ -194,32 +194,32 @@ QString WaitTreeThread::GetText() const {
|
||||
const auto& thread = static_cast<const Kernel::Thread&>(object);
|
||||
QString status;
|
||||
switch (thread.status) {
|
||||
case THREADSTATUS_RUNNING:
|
||||
case ThreadStatus::Running:
|
||||
status = tr("running");
|
||||
break;
|
||||
case THREADSTATUS_READY:
|
||||
case ThreadStatus::Ready:
|
||||
status = tr("ready");
|
||||
break;
|
||||
case THREADSTATUS_WAIT_HLE_EVENT:
|
||||
case ThreadStatus::WaitHLEEvent:
|
||||
status = tr("waiting for HLE return");
|
||||
break;
|
||||
case THREADSTATUS_WAIT_SLEEP:
|
||||
case ThreadStatus::WaitSleep:
|
||||
status = tr("sleeping");
|
||||
break;
|
||||
case THREADSTATUS_WAIT_SYNCH_ALL:
|
||||
case THREADSTATUS_WAIT_SYNCH_ANY:
|
||||
case ThreadStatus::WaitSynchAll:
|
||||
case ThreadStatus::WaitSynchAny:
|
||||
status = tr("waiting for objects");
|
||||
break;
|
||||
case THREADSTATUS_WAIT_MUTEX:
|
||||
case ThreadStatus::WaitMutex:
|
||||
status = tr("waiting for mutex");
|
||||
break;
|
||||
case THREADSTATUS_WAIT_ARB:
|
||||
case ThreadStatus::WaitArb:
|
||||
status = tr("waiting for address arbiter");
|
||||
break;
|
||||
case THREADSTATUS_DORMANT:
|
||||
case ThreadStatus::Dormant:
|
||||
status = tr("dormant");
|
||||
break;
|
||||
case THREADSTATUS_DEAD:
|
||||
case ThreadStatus::Dead:
|
||||
status = tr("dead");
|
||||
break;
|
||||
}
|
||||
@@ -232,22 +232,22 @@ QString WaitTreeThread::GetText() const {
|
||||
QColor WaitTreeThread::GetColor() const {
|
||||
const auto& thread = static_cast<const Kernel::Thread&>(object);
|
||||
switch (thread.status) {
|
||||
case THREADSTATUS_RUNNING:
|
||||
case ThreadStatus::Running:
|
||||
return QColor(Qt::GlobalColor::darkGreen);
|
||||
case THREADSTATUS_READY:
|
||||
case ThreadStatus::Ready:
|
||||
return QColor(Qt::GlobalColor::darkBlue);
|
||||
case THREADSTATUS_WAIT_HLE_EVENT:
|
||||
case ThreadStatus::WaitHLEEvent:
|
||||
return QColor(Qt::GlobalColor::darkRed);
|
||||
case THREADSTATUS_WAIT_SLEEP:
|
||||
case ThreadStatus::WaitSleep:
|
||||
return QColor(Qt::GlobalColor::darkYellow);
|
||||
case THREADSTATUS_WAIT_SYNCH_ALL:
|
||||
case THREADSTATUS_WAIT_SYNCH_ANY:
|
||||
case THREADSTATUS_WAIT_MUTEX:
|
||||
case THREADSTATUS_WAIT_ARB:
|
||||
case ThreadStatus::WaitSynchAll:
|
||||
case ThreadStatus::WaitSynchAny:
|
||||
case ThreadStatus::WaitMutex:
|
||||
case ThreadStatus::WaitArb:
|
||||
return QColor(Qt::GlobalColor::red);
|
||||
case THREADSTATUS_DORMANT:
|
||||
case ThreadStatus::Dormant:
|
||||
return QColor(Qt::GlobalColor::darkCyan);
|
||||
case THREADSTATUS_DEAD:
|
||||
case ThreadStatus::Dead:
|
||||
return QColor(Qt::GlobalColor::gray);
|
||||
default:
|
||||
return WaitTreeItem::GetColor();
|
||||
@@ -291,8 +291,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
|
||||
else
|
||||
list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex")));
|
||||
|
||||
if (thread.status == THREADSTATUS_WAIT_SYNCH_ANY ||
|
||||
thread.status == THREADSTATUS_WAIT_SYNCH_ALL) {
|
||||
if (thread.status == ThreadStatus::WaitSynchAny ||
|
||||
thread.status == ThreadStatus::WaitSynchAll) {
|
||||
list.push_back(std::make_unique<WaitTreeObjectList>(thread.wait_objects,
|
||||
thread.IsSleepingOnWaitAll()));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user